test_xacro.py
Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 
00003 from __future__ import print_function
00004 
00005 import sys
00006 import unittest
00007 import xacro
00008 from xml.dom.minidom import parseString
00009 import xml.dom
00010 import os.path
00011 from rosgraph.names import load_mappings
00012 from xacro import set_substitution_args_context
00013 
00014 
00015 def all_attributes_match(a, b):
00016     if len(a.attributes) != len(b.attributes):
00017         print("Different number of attributes")
00018         return False
00019     a_atts = [(a.attributes.item(i).name, a.attributes.item(i).value) for i in range(len(a.attributes))]
00020     b_atts = [(b.attributes.item(i).name, b.attributes.item(i).value) for i in range(len(b.attributes))]
00021     a_atts.sort()
00022     b_atts.sort()
00023 
00024     for i in range(len(a_atts)):
00025         if a_atts[i][0] != b_atts[i][0]:
00026             print("Different attribute names: %s and %s" % (a_atts[i][0], b_atts[i][0]))
00027             return False
00028         try:
00029             if abs(float(a_atts[i][1]) - float(b_atts[i][1])) > 1.0e-9:
00030                 print("Different attribute values: %s and %s" % (a_atts[i][1], b_atts[i][1]))
00031                 return False
00032         except ValueError:  # Attribute values aren't numeric
00033             if a_atts[i][1] != b_atts[i][1]:
00034                 print("Different attribute values: %s and %s" % (a_atts[i][1], b_atts[i][1]))
00035                 return False
00036 
00037     return True
00038 
00039 
00040 def elements_match(a, b):
00041     if not a and not b:
00042         return True
00043     if not a or not b:
00044         return False
00045 
00046     if a.nodeType != b.nodeType:
00047         print("Different node types: %d and %d" % (a.nodeType, b.nodeType))
00048         return False
00049     if a.nodeName != b.nodeName:
00050         print("Different element names: %s and %s" % (a.nodeName, b.nodeName))
00051         return False
00052 
00053     if not all_attributes_match(a, b):
00054         return False
00055 
00056     if not elements_match(xacro.first_child_element(a), xacro.first_child_element(b)):
00057         return False
00058     if not elements_match(xacro.next_sibling_element(a), xacro.next_sibling_element(b)):
00059         return False
00060     return True
00061 
00062 
00063 def xml_matches(a, b):
00064     if isinstance(a, str):
00065         return xml_matches(parseString(a).documentElement, b)
00066     if isinstance(b, str):
00067         return xml_matches(a, parseString(b).documentElement)
00068     if a.nodeType == xml.dom.Node.DOCUMENT_NODE:
00069         return xml_matches(a.documentElement, b)
00070     if b.nodeType == xml.dom.Node.DOCUMENT_NODE:
00071         return xml_matches(a, b.documentElement)
00072 
00073     if not elements_match(a, b):
00074         print("Match failed:")
00075         a.writexml(sys.stdout)
00076         print
00077         print('=' * 78)
00078         b.writexml(sys.stdout)
00079         return False
00080     return True
00081 
00082 
00083 def quick_xacro(xml):
00084     if isinstance(xml, str):
00085         doc = parseString(xml)
00086         return quick_xacro(doc)
00087     xacro.eval_self_contained(xml)
00088     return xml
00089 
00090 
00091 class TestXacro(unittest.TestCase):
00092 
00093     def test_DEPRECATED_should_replace_before_macroexpand(self):
00094         self.assertTrue(
00095             xml_matches(
00096                 quick_xacro('''<a>
00097 <macro name="inner" params="*the_block">
00098   <in_the_inner><insert_block name="the_block" /></in_the_inner>
00099 </macro>
00100 <macro name="outer" params="*the_block">
00101   <in_the_outer><inner><insert_block name="the_block" /></inner></in_the_outer>
00102 </macro>
00103 <outer><woot /></outer></a>'''),
00104                 '''<a>
00105 <in_the_outer><in_the_inner><woot /></in_the_inner></in_the_outer></a>'''))
00106 
00107     def test_should_replace_before_macroexpand(self):
00108         self.assertTrue(
00109             xml_matches(
00110                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00111 <xacro:macro name="inner" params="*the_block">
00112   <in_the_inner><xacro:insert_block name="the_block" /></in_the_inner>
00113 </xacro:macro>
00114 <xacro:macro name="outer" params="*the_block">
00115   <in_the_outer><xacro:inner><insert_block name="the_block" /></xacro:inner></in_the_outer>
00116 </xacro:macro>
00117 <xacro:outer><woot /></xacro:outer></a>'''),
00118                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00119 <in_the_outer><in_the_inner><woot /></in_the_inner></in_the_outer></a>'''))
00120 
00121     def test_property_replacement(self):
00122         self.assertTrue(
00123             xml_matches(
00124                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00125   <xacro:property name="foo" value="42" />
00126   <the_foo result="${foo}" />
00127 </a>'''),
00128                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00129   <the_foo result="42" />
00130 </a>'''))
00131 
00132     def test_math_ignores_spaces(self):
00133         self.assertTrue(
00134             xml_matches(
00135                 quick_xacro('''<a><f v="${0.9 / 2 - 0.2}" /></a>'''),
00136                 '''<a><f v="0.25" /></a>'''))
00137 
00138     def test_substitution_args_find(self):
00139         self.assertTrue(
00140             xml_matches(
00141                 quick_xacro('''<a><f v="$(find xacro)/test/test_xacro.py" /></a>'''),
00142                 '''<a><f v="''' + os.path.abspath(__file__) + '''" /></a>'''))
00143 
00144     def test_substitution_args_arg(self):
00145         set_substitution_args_context(load_mappings(['sub_arg:=my_arg']))
00146         self.assertTrue(
00147             xml_matches(
00148                 quick_xacro('''<a><f v="$(arg sub_arg)" /></a>'''),
00149                 '''<a><f v="my_arg" /></a>'''))
00150         set_substitution_args_context({})
00151 
00152     def test_escaping_dollar_braces(self):
00153         self.assertTrue(
00154             xml_matches(
00155                 quick_xacro('''<a b="$${foo}" c="$$${foo}" />'''),
00156                 '''<a b="${foo}" c="$${foo}" />'''))
00157 
00158     def test_just_a_dollar_sign(self):
00159         self.assertTrue(
00160             xml_matches(
00161                 quick_xacro('''<a b="$" />'''),
00162                 '''<a b="$" />'''))
00163 
00164     def test_multiple_insert_blocks(self):
00165         self.assertTrue(
00166             xml_matches(
00167                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00168 <xacro:macro name="foo" params="*block">
00169   <xacro:insert_block name="block" />
00170   <xacro:insert_block name="block" />
00171 </xacro:macro>
00172 <xacro:foo>
00173   <a_block />
00174 </xacro:foo>
00175 </a>'''),
00176                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00177   <a_block />
00178   <a_block />
00179 </a>'''))
00180 
00181     def test_multiple_blocks(self):
00182         self.assertTrue(
00183             xml_matches(
00184                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00185 <xacro:macro name="foo" params="*block1 *block2">
00186   <xacro:insert_block name="block2" />
00187   <first>
00188     <xacro:insert_block name="block1" />
00189   </first>
00190 </xacro:macro>
00191 <xacro:foo>
00192   <first_block />
00193   <second_block />
00194 </xacro:foo>
00195 </a>'''),
00196                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00197   <second_block />
00198   <first>
00199     <first_block />
00200   </first>
00201 </a>'''))
00202 
00203     def test_integer_stays_integer(self):
00204         self.assertTrue(
00205             xml_matches(
00206                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00207 <xacro:macro name="m" params="num">
00208   <test number="${num}" />
00209 </xacro:macro>
00210 <xacro:m num="100" />
00211 </a>'''),
00212                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00213   <test number="100" />
00214 </a>'''))
00215 
00216     def test_insert_block_property(self):
00217         self.assertTrue(
00218             xml_matches(
00219                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00220 <xacro:property name="some_block">
00221   <some_block />
00222 </xacro:property>
00223 <foo>
00224   <xacro:insert_block name="some_block" />
00225 </foo>
00226 </a>'''),
00227                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00228 <foo><some_block /></foo>
00229 </a>'''))
00230 
00231     def test_include(self):
00232         doc = parseString('''<a xmlns:xacro="http://www.ros.org/xacro">
00233                              <xacro:include filename="include1.xml" /></a>''')
00234         xacro.process_includes(doc, os.path.dirname(os.path.realpath(__file__)))
00235         self.assertTrue(
00236             xml_matches(doc, '''<a xmlns:xacro="http://www.ros.org/xacro"><foo /><bar /></a>'''))
00237 
00238     def test_include_glob(self):
00239         doc = parseString('''<a xmlns:xacro="http://www.ros.org/xacro">
00240                              <xacro:include filename="include*.xml" /></a>''')
00241         xacro.process_includes(doc, os.path.dirname(os.path.realpath(__file__)))
00242         self.assertTrue(
00243             xml_matches(doc, '<a xmlns:xacro="http://www.ros.org/xacro"><foo /><bar /><baz /></a>'))
00244 
00245     def test_include_nonexistent(self):
00246         doc = parseString('''<a xmlns:xacro="http://www.ros.org/xacro">
00247                              <xacro:include filename="include-nada.xml" /></a>''')
00248         self.assertRaises(xacro.XacroException,
00249                           xacro.process_includes, doc, os.path.dirname(os.path.realpath(__file__)))
00250 
00251     def test_numeric_if_statement(self):
00252         doc = parseString('''\
00253 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00254   <xacro:if value="${3*0}"/>
00255   <xacro:if value="0"/>
00256   <xacro:if value="1"/>
00257 </robot>''')
00258         quick_xacro(doc)
00259         self.assertTrue(
00260             xml_matches(
00261                 quick_xacro('''\
00262 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00263   <xacro:if value="${3*0}">
00264     <a />
00265   </xacro:if>
00266   <xacro:if value="0">
00267     <b />
00268   </xacro:if>
00269   <xacro:if value="1">
00270     <c />
00271   </xacro:if>
00272 </robot>'''),
00273                 '''\
00274 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00275     <c />
00276 </robot>'''))


xacro
Author(s): Stuart Glaser
autogenerated on Thu Aug 27 2015 15:44:55