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 import tempfile
00012 import shutil
00013 import subprocess
00014 import re
00015 from rosgraph.names import load_mappings
00016 from xacro import set_substitution_args_context
00017 
00018 # regex to match whitespace
00019 whitespace = re.compile(r'\s+')
00020 
00021 def all_attributes_match(a, b):
00022     if len(a.attributes) != len(b.attributes):
00023         print("Different number of attributes")
00024         return False
00025     a_atts = [(a.attributes.item(i).name, a.attributes.item(i).value) for i in range(len(a.attributes))]
00026     b_atts = [(b.attributes.item(i).name, b.attributes.item(i).value) for i in range(len(b.attributes))]
00027     a_atts.sort()
00028     b_atts.sort()
00029 
00030     for i in range(len(a_atts)):
00031         if a_atts[i][0] != b_atts[i][0]:
00032             print("Different attribute names: %s and %s" % (a_atts[i][0], b_atts[i][0]))
00033             return False
00034         try:
00035             if abs(float(a_atts[i][1]) - float(b_atts[i][1])) > 1.0e-9:
00036                 print("Different attribute values: %s and %s" % (a_atts[i][1], b_atts[i][1]))
00037                 return False
00038         except ValueError:  # Attribute values aren't numeric
00039             if a_atts[i][1] != b_atts[i][1]:
00040                 print("Different attribute values: %s and %s" % (a_atts[i][1], b_atts[i][1]))
00041                 return False
00042 
00043     return True
00044 
00045 def text_matches(a, b):
00046     a_norm = whitespace.sub(' ', a)
00047     b_norm = whitespace.sub(' ', b)
00048     if a_norm.strip() == b_norm.strip(): return True
00049     print("Different text values: '%s' and '%s'" % (a, b))
00050     return False
00051 
00052 def nodes_match(a, b):
00053     ignore = [] # list of node type to ignore
00054     if not a and not b:
00055         return True
00056     if not a or not b:
00057         return False
00058 
00059     if a.nodeType != b.nodeType:
00060         print("Different node types: %s and %s" % (a, b))
00061         return False
00062 
00063     # compare text-valued nodes
00064     if a.nodeType in [xml.dom.Node.TEXT_NODE,
00065                       xml.dom.Node.CDATA_SECTION_NODE,
00066                       xml.dom.Node.COMMENT_NODE]:
00067         return text_matches(a.data, b.data)
00068 
00069     # ignore all other nodes except ELEMENTs
00070     if a.nodeType != xml.dom.Node.ELEMENT_NODE:
00071         return True
00072 
00073     # compare ELEMENT nodes
00074     if a.nodeName != b.nodeName:
00075         print("Different element names: %s and %s" % (a.nodeName, b.nodeName))
00076         return False
00077 
00078     if not all_attributes_match(a, b):
00079         return False
00080 
00081     a = a.firstChild
00082     b = b.firstChild
00083     while a or b:
00084         # ignore whitespace-only text nodes
00085         # we could have several text nodes in a row, due to replacements
00086         while (a and
00087                ((a.nodeType in ignore) or
00088                 (a.nodeType == xml.dom.Node.TEXT_NODE and whitespace.sub('', a.data) == ""))):
00089             a = a.nextSibling
00090         while (b and
00091                ((b.nodeType in ignore) or
00092                 (b.nodeType == xml.dom.Node.TEXT_NODE and whitespace.sub('', b.data) == ""))):
00093             b = b.nextSibling
00094 
00095         if not nodes_match(a, b):
00096             return False
00097 
00098         if a: a = a.nextSibling
00099         if b: b = b.nextSibling
00100 
00101     return True
00102 
00103 
00104 def xml_matches(a, b):
00105     if isinstance(a, str):
00106         return xml_matches(parseString(a).documentElement, b)
00107     if isinstance(b, str):
00108         return xml_matches(a, parseString(b).documentElement)
00109     if a.nodeType == xml.dom.Node.DOCUMENT_NODE:
00110         return xml_matches(a.documentElement, b)
00111     if b.nodeType == xml.dom.Node.DOCUMENT_NODE:
00112         return xml_matches(a, b.documentElement)
00113 
00114     if not nodes_match(a, b):
00115         print("Match failed:")
00116         a.writexml(sys.stdout)
00117         print()
00118         print('=' * 78)
00119         b.writexml(sys.stdout)
00120         print()
00121         return False
00122     return True
00123 
00124 
00125 def quick_xacro(xml):
00126     if isinstance(xml, str):
00127         doc = parseString(xml)
00128         return quick_xacro(doc)
00129     xacro.eval_self_contained(xml)
00130     return xml
00131 
00132 
00133 class TestMatchXML(unittest.TestCase):
00134     def test_normalize_whitespace_text(self):
00135         self.assertTrue(text_matches("", " \t\n\r"))
00136     def test_normalize_whitespace_trim(self):
00137         self.assertTrue(text_matches(" foo bar ", "foo \t\n\r bar"))
00138 
00139     def test_empty_node_vs_whitespace(self):
00140         self.assertTrue(xml_matches('''<foo/>''', '''<foo> \t\n\r </foo>'''))
00141     def test_whitespace_vs_empty_node(self):
00142         self.assertTrue(xml_matches('''<foo> \t\n\r </foo>''', '''<foo/>'''))
00143     def test_normalize_whitespace_nested(self):
00144         self.assertTrue(xml_matches('''<a><b/></a>''', '''<a>\n<b> </b> </a>'''))
00145 
00146 class TestXacro(unittest.TestCase):
00147 
00148     def test_DEPRECATED_should_replace_before_macroexpand(self):
00149         self.assertTrue(
00150             xml_matches(
00151                 quick_xacro('''<a>
00152 <macro name="inner" params="*the_block">
00153   <in_the_inner><insert_block name="the_block" /></in_the_inner>
00154 </macro>
00155 <macro name="outer" params="*the_block">
00156   <in_the_outer><inner><insert_block name="the_block" /></inner></in_the_outer>
00157 </macro>
00158 <outer><woot /></outer></a>'''),
00159                 '''<a>
00160 <in_the_outer><in_the_inner><woot /></in_the_inner></in_the_outer></a>'''))
00161 
00162     def test_should_replace_before_macroexpand(self):
00163         self.assertTrue(
00164             xml_matches(
00165                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00166 <xacro:macro name="inner" params="*the_block">
00167   <in_the_inner><xacro:insert_block name="the_block" /></in_the_inner>
00168 </xacro:macro>
00169 <xacro:macro name="outer" params="*the_block">
00170   <in_the_outer><xacro:inner><insert_block name="the_block" /></xacro:inner></in_the_outer>
00171 </xacro:macro>
00172 <xacro:outer><woot /></xacro:outer></a>'''),
00173                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00174 <in_the_outer><in_the_inner><woot /></in_the_inner></in_the_outer></a>'''))
00175 
00176     def test_property_replacement(self):
00177         self.assertTrue(
00178             xml_matches(
00179                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00180   <xacro:property name="foo" value="42" />
00181   <the_foo result="${foo}" />
00182 </a>'''),
00183                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00184   <the_foo result="42" />
00185 </a>'''))
00186 
00187     def test_math_ignores_spaces(self):
00188         self.assertTrue(
00189             xml_matches(
00190                 quick_xacro('''<a><f v="${0.9 / 2 - 0.2}" /></a>'''),
00191                 '''<a><f v="0.25" /></a>'''))
00192 
00193     def test_substitution_args_find(self):
00194         self.assertTrue(
00195             xml_matches(
00196                 quick_xacro('''<a><f v="$(find xacro)/test/test_xacro.py" /></a>'''),
00197                 '''<a><f v="''' + os.path.abspath((__file__).replace(".pyc",".py")) + '''" /></a>'''))
00198 
00199     def test_substitution_args_arg(self):
00200         set_substitution_args_context(load_mappings(['sub_arg:=my_arg']))
00201         self.assertTrue(
00202             xml_matches(
00203                 quick_xacro('''<a><f v="$(arg sub_arg)" /></a>'''),
00204                 '''<a><f v="my_arg" /></a>'''))
00205         set_substitution_args_context({})
00206 
00207     def test_escaping_dollar_braces(self):
00208         self.assertTrue(
00209             xml_matches(
00210                 quick_xacro('''<a b="$${foo}" c="$$${foo}" />'''),
00211                 '''<a b="${foo}" c="$${foo}" />'''))
00212 
00213     def test_just_a_dollar_sign(self):
00214         self.assertTrue(
00215             xml_matches(
00216                 quick_xacro('''<a b="$" />'''),
00217                 '''<a b="$" />'''))
00218 
00219     def test_multiple_insert_blocks(self):
00220         self.assertTrue(
00221             xml_matches(
00222                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00223 <xacro:macro name="foo" params="*block">
00224   <xacro:insert_block name="block" />
00225   <xacro:insert_block name="block" />
00226 </xacro:macro>
00227 <xacro:foo>
00228   <a_block />
00229 </xacro:foo>
00230 </a>'''),
00231                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00232   <a_block />
00233   <a_block />
00234 </a>'''))
00235 
00236     def test_multiple_blocks(self):
00237         self.assertTrue(
00238             xml_matches(
00239                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00240 <xacro:macro name="foo" params="*block1 *block2">
00241   <xacro:insert_block name="block2" />
00242   <first>
00243     <xacro:insert_block name="block1" />
00244   </first>
00245 </xacro:macro>
00246 <xacro:foo>
00247   <first_block />
00248   <second_block />
00249 </xacro:foo>
00250 </a>'''),
00251                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00252   <second_block />
00253   <first>
00254     <first_block />
00255   </first>
00256 </a>'''))
00257 
00258     def test_integer_stays_integer(self):
00259         self.assertTrue(
00260             xml_matches(
00261                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00262 <xacro:macro name="m" params="num">
00263   <test number="${num}" />
00264 </xacro:macro>
00265 <xacro:m num="100" />
00266 </a>'''),
00267                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00268   <test number="100" />
00269 </a>'''))
00270 
00271     def test_insert_block_property(self):
00272         self.assertTrue(
00273             xml_matches(
00274                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00275 <xacro:property name="some_block">
00276   <some_block />
00277 </xacro:property>
00278 <foo>
00279   <xacro:insert_block name="some_block" />
00280 </foo>
00281 </a>'''),
00282                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00283 <foo><some_block /></foo>
00284 </a>'''))
00285 
00286     def test_include(self):
00287         doc = parseString('''<a xmlns:xacro="http://www.ros.org/xacro">
00288                              <xacro:include filename="include1.xml" /></a>''')
00289         xacro.process_includes(doc, os.path.dirname(os.path.realpath(__file__)))
00290         self.assertTrue(
00291             xml_matches(doc, '''<a xmlns:xacro="http://www.ros.org/xacro"><foo /><bar /></a>'''))
00292 
00293     def test_include_glob(self):
00294         doc = parseString('''<a xmlns:xacro="http://www.ros.org/xacro">
00295                              <xacro:include filename="include*.xml" /></a>''')
00296         xacro.process_includes(doc, os.path.dirname(os.path.realpath(__file__)))
00297         self.assertTrue(
00298             xml_matches(doc, '<a xmlns:xacro="http://www.ros.org/xacro"><foo /><bar /><baz /></a>'))
00299 
00300     def test_include_nonexistent(self):
00301         doc = parseString('''<a xmlns:xacro="http://www.ros.org/xacro">
00302                              <xacro:include filename="include-nada.xml" /></a>''')
00303         self.assertRaises(xacro.XacroException,
00304                           xacro.process_includes, doc, os.path.dirname(os.path.realpath(__file__)))
00305 
00306     def test_boolean_if_statement(self):
00307         self.assertTrue(
00308             xml_matches(
00309                 quick_xacro('''\
00310 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00311   <xacro:if value="false">
00312     <a />
00313   </xacro:if>
00314   <xacro:if value="true">
00315     <b />
00316   </xacro:if>
00317 </robot>'''),
00318                 '''\
00319 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00320     <b />
00321 </robot>'''))
00322 
00323     def test_integer_if_statement(self):
00324         self.assertTrue(
00325             xml_matches(
00326                 quick_xacro('''\
00327 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00328   <xacro:if value="${0*42}">
00329     <a />
00330   </xacro:if>
00331   <xacro:if value="0">
00332     <b />
00333   </xacro:if>
00334   <xacro:if value="${0}">
00335     <c />
00336   </xacro:if>
00337   <xacro:if value="${1*2+3}">
00338     <d />
00339   </xacro:if>
00340 </robot>'''),
00341                 '''\
00342 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00343     <d />
00344 </robot>'''))
00345 
00346     def test_float_if_statement(self):
00347         self.assertTrue(
00348             xml_matches(
00349                 quick_xacro('''\
00350 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00351   <xacro:if value="${3*0.0}">
00352     <a />
00353   </xacro:if>
00354   <xacro:if value="${3*0.1}">
00355     <b />
00356   </xacro:if>
00357 </robot>'''),
00358                 '''\
00359 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00360     <b />
00361 </robot>'''))
00362 
00363     def test_consecutive_if(self):
00364         self.assertTrue(
00365             xml_matches(quick_xacro('''
00366 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
00367   <xacro:if value="1"><xacro:if value="0"><a>bar</a></xacro:if></xacro:if>
00368 </a>'''),
00369 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"/>'''))
00370 
00371     def test_consider_non_elements_if(self):
00372         self.assertTrue(
00373             xml_matches(quick_xacro('''
00374 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
00375   <xacro:if value="1"><!-- comment --> text <b>bar</b></xacro:if>
00376 </a>'''),
00377 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00378 <!-- comment --> text <b>bar</b></a>'''))
00379 
00380     def test_consider_non_elements_block(self):
00381         self.assertTrue(
00382             xml_matches(
00383                 quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00384 <xacro:macro name="foo" params="*block">
00385   <!-- comment -->
00386   foo
00387   <xacro:insert_block name="block" />
00388 </xacro:macro>
00389 <xacro:foo>
00390   <!-- ignored comment -->
00391   ignored text
00392   <a_block />
00393 </xacro:foo>
00394 </a>'''),
00395                 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
00396   <!-- comment -->
00397   foo
00398   <a_block />
00399 </a>'''))
00400 
00401     def test_recursive_evaluation(self):
00402         self.assertTrue(
00403             xml_matches(
00404                 quick_xacro('''\
00405 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00406   <xacro:property name="a" value="42"/>
00407   <xacro:property name="a2" value="${2*a}"/>
00408   <a doubled="${a2}"/>
00409 </robot>'''),
00410                 '''\
00411 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00412   <a doubled="84"/>
00413 </robot>'''))
00414 
00415     def test_recursive_definition(self):
00416         self.assertRaises(xacro.XacroException,
00417                           quick_xacro, '''\
00418 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00419   <xacro:property name="a" value="${a2}"/>
00420   <xacro:property name="a2" value="${2*a}"/>
00421   <a doubled="${a2}"/>
00422 </robot>''')
00423 
00424     def test_multiple_recursive_evaluation(self):
00425         self.assertTrue(
00426             xml_matches(
00427                 quick_xacro('''\
00428 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00429   <xacro:property name="a" value="1"/>
00430   <xacro:property name="b" value="2"/>
00431   <xacro:property name="c" value="3"/>
00432   <xacro:property name="product" value="${a*b*c}"/>
00433   <answer product="${product}"/>
00434 </robot>'''),
00435                 '''\
00436 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00437   <answer product="6"/>
00438 </robot>'''))
00439 
00440     def test_transitive_evaluation(self):
00441         self.assertTrue(
00442             xml_matches(
00443                 quick_xacro('''\
00444 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00445   <xacro:property name="a" value="42"/>
00446   <xacro:property name="b" value="${a}"/>
00447   <xacro:property name="c" value="${b}"/>
00448   <xacro:property name="d" value="${c}"/>
00449   <answer d="${d}"/>
00450 </robot>'''),
00451                 '''\
00452 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00453   <answer d="42"/>
00454 </robot>'''))
00455 
00456     def test_multi_tree_evaluation(self):
00457         self.assertTrue(
00458             xml_matches(
00459                 quick_xacro('''\
00460 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00461   <xacro:property name="a" value="42"/>
00462   <xacro:property name="b" value="2.1"/>
00463   <xacro:property name="c" value="${a}"/>
00464   <xacro:property name="d" value="${b}"/>
00465   <xacro:property name="e" value="${c*d}"/>
00466   <answer e="${e}"/>
00467 </robot>'''),
00468                 '''\
00469 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00470   <answer e="88.2"/>
00471 </robot>'''))
00472 
00473     def test_from_issue(self):
00474         self.assertTrue(
00475             xml_matches(
00476                 quick_xacro('''\
00477 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00478   <xacro:property name="x" value="42"/>
00479   <xacro:property name="wheel_width" value="${x}"/>
00480   <link name="my_link">
00481     <origin xyz="0 0 ${wheel_width/2}"/>
00482   </link>
00483 </robot>'''),
00484                 '''\
00485 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00486   <link name="my_link">
00487     <origin xyz="0 0 21.0"/>
00488   </link>
00489 </robot>'''))
00490 
00491     def test_recursive_bad_math(self):
00492         self.assertRaises(ZeroDivisionError,
00493             quick_xacro, '''\
00494 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00495   <xacro:property name="x" value="0"/>
00496   <tag badness="${1/x}"/>
00497 </robot>''')
00498 
00499     def test_pr2(self):
00500         # run xacro on the pr2 tree snapshot
00501         test_dir= os.path.abspath(os.path.dirname(__file__))
00502         xacro_path = os.path.join(test_dir, '..', 'xacro.py')
00503         pr2_xacro_path = os.path.join(test_dir, 'robots', 'pr2',
00504                                       'pr2.urdf.xacro')
00505         proc = subprocess.Popen([xacro_path, pr2_xacro_path],
00506                                 stdout=subprocess.PIPE)
00507         output, errcode = proc.communicate()
00508         if errcode:
00509             raise Exception("xacro couldn't process the pr2 snapshot test case")
00510         pr2_golden_parse_path = os.path.join(test_dir, 'robots', 'pr2',
00511                                              'pr2_1.11.4.xml')
00512         self.assertTrue(
00513             xml_matches(
00514                 xml.dom.minidom.parse(pr2_golden_parse_path),
00515                 quick_xacro(output)))
00516 
00517     def test_default_param(self):
00518         self.assertTrue(
00519             xml_matches(
00520                 quick_xacro('''\
00521 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00522   <xacro:macro name="fixed_link" params="parent_link:=base_link child_link *joint_pose">
00523     <link name="${child_link}"/>
00524     <joint name="${child_link}_joint" type="fixed">
00525       <xacro:insert_block name="joint_pose" />
00526       <parent link="${parent_link}"/>
00527       <child link="${child_link}" />
00528     </joint>
00529   </xacro:macro>
00530   <xacro:fixed_link child_link="foo">
00531     <origin xyz="0 0 0" rpy="0 0 0" />
00532   </xacro:fixed_link >
00533 </robot>'''),
00534                 '''\
00535 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00536   <link name="foo"/>
00537   <joint name="foo_joint" type="fixed">
00538     <origin rpy="0 0 0" xyz="0 0 0"/>
00539     <parent link="base_link"/>
00540     <child link="foo"/>
00541   </joint>
00542 </robot>'''))
00543 
00544     def test_default_param_override(self):
00545         self.assertTrue(
00546             xml_matches(
00547                 quick_xacro('''\
00548 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00549   <xacro:macro name="fixed_link" params="parent_link:=base_link child_link *joint_pose">
00550     <link name="${child_link}"/>
00551     <joint name="${child_link}_joint" type="fixed">
00552       <xacro:insert_block name="joint_pose" />
00553       <parent link="${parent_link}"/>
00554       <child link="${child_link}" />
00555     </joint>
00556   </xacro:macro>
00557   <xacro:fixed_link child_link="foo" parent_link="bar">
00558     <origin xyz="0 0 0" rpy="0 0 0" />
00559   </xacro:fixed_link >
00560 </robot>'''),
00561                 '''\
00562 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00563   <link name="foo"/>
00564   <joint name="foo_joint" type="fixed">
00565     <origin rpy="0 0 0" xyz="0 0 0"/>
00566     <parent link="bar"/>
00567     <child link="foo"/>
00568   </joint>
00569 </robot>'''))
00570 
00571     def test_param_missing(self):
00572         self.assertRaises(xacro.XacroException,
00573                           quick_xacro, '''\
00574 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00575   <xacro:macro name="fixed_link" params="parent_link child_link *joint_pose">
00576     <link name="${child_link}"/>
00577     <joint name="${child_link}_joint" type="fixed">
00578       <xacro:insert_block name="joint_pose" />
00579       <parent link="${parent_link}"/>
00580       <child link="${child_link}" />
00581     </joint>
00582   </xacro:macro>
00583   <xacro:fixed_link child_link="foo">
00584     <origin xyz="0 0 0" rpy="0 0 0" />
00585   </xacro:fixed_link >
00586 </robot>''')
00587 
00588     def test_default_arg(self):
00589         set_substitution_args_context({})
00590         self.assertTrue(
00591             xml_matches(
00592                 quick_xacro('''\
00593 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00594   <xacro:arg name="foo" default="2"/>
00595   <link name="my_link">
00596     <origin xyz="0 0 $(arg foo)"/>
00597   </link>
00598 </robot>
00599 '''),'''\
00600 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00601   <link name="my_link">
00602     <origin xyz="0 0 2"/>
00603   </link>
00604 </robot>'''))
00605         set_substitution_args_context({})
00606 
00607     def test_default_arg_override(self):
00608         set_substitution_args_context(load_mappings(['foo:=4']))
00609         self.assertTrue(
00610             xml_matches(
00611                 quick_xacro('''\
00612 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00613   <xacro:arg name="foo" default="2"/>
00614   <link name="my_link">
00615     <origin xyz="0 0 $(arg foo)"/>
00616   </link>
00617 </robot>
00618 '''),'''\
00619 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00620   <link name="my_link">
00621     <origin xyz="0 0 4"/>
00622   </link>
00623 </robot>'''))
00624         set_substitution_args_context({})
00625 
00626     def test_default_arg_missing(self):
00627         set_substitution_args_context({})
00628         self.assertRaises(Exception,
00629             quick_xacro, '''\
00630 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00631   <link name="my_link">
00632     <origin xyz="0 0 $(arg foo)"/>
00633   </link>
00634 </robot>
00635 ''')
00636         set_substitution_args_context({})
00637 
00638     def test_broken_input_doesnt_create_empty_output_file(self):
00639         # run xacro on broken input file to make sure we don't create an
00640         # empty output file
00641         tmp_dir_name = tempfile.mkdtemp() # create directory we can trash
00642         test_dir = os.path.abspath(os.path.dirname(__file__))
00643         output_path = os.path.join(tmp_dir_name, "should_not_exist")
00644         xacro_path = os.path.join(test_dir, '..', 'xacro.py')
00645         broken_file_path = os.path.join(test_dir, 'broken.xacro')
00646         errcode = subprocess.call([xacro_path, broken_file_path,
00647                                    '-o', output_path])
00648         output_file_created = os.path.isfile(output_path)
00649         shutil.rmtree(tmp_dir_name) # clean up after ourselves
00650         self.assertFalse(output_file_created)
00651 
00652     def test_ros_arg_param(self):
00653         self.assertTrue(
00654             xml_matches(
00655                 quick_xacro('''\
00656 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00657   <xacro:macro name="fixed_link" params="parent_link:=base_link child_link *joint_pose">
00658     <link name="${child_link}"/>
00659     <joint name="${child_link}_joint" type="fixed">
00660       <xacro:insert_block name="joint_pose" />
00661       <parent link="${parent_link}"/>
00662       <child link="${child_link}" />
00663       <arg name="${parent_link}" value="${child_link}"/>
00664     </joint>
00665   </xacro:macro>
00666   <xacro:fixed_link child_link="foo">
00667     <origin xyz="0 0 0" rpy="0 0 0" />
00668   </xacro:fixed_link >
00669 </robot>'''),
00670                 '''\
00671 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
00672   <link name="foo"/>
00673   <joint name="foo_joint" type="fixed">
00674     <origin rpy="0 0 0" xyz="0 0 0"/>
00675     <parent link="base_link"/>
00676     <child link="foo"/>
00677     <arg name="base_link" value="foo"/>
00678   </joint>
00679 </robot>'''))
00680 


xacro
Author(s): Stuart Glaser, William Woodall
autogenerated on Sat Jun 8 2019 18:50:42