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


xacro
Author(s): Stuart Glaser
autogenerated on Mon Oct 6 2014 09:05:11