00001
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
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:
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 = []
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
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
00070 if a.nodeType != xml.dom.Node.ELEMENT_NODE:
00071 return True
00072
00073
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
00085
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
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
00640
00641 tmp_dir_name = tempfile.mkdtemp()
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)
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