test_xacro.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 from __future__ import print_function
4 
5 import sys
6 import unittest
7 import xacro
8 from xml.dom.minidom import parseString
9 import xml.dom
10 import os.path
11 import tempfile
12 import shutil
13 import subprocess
14 import re
15 from cStringIO import StringIO
16 from contextlib import contextmanager
17 
18 
19 # regex to match whitespace
20 whitespace = re.compile(r'\s+')
21 
23  if len(a.attributes) != len(b.attributes):
24  print("Different number of attributes")
25  return False
26  a_atts = [(a.attributes.item(i).name, a.attributes.item(i).value) for i in range(len(a.attributes))]
27  b_atts = [(b.attributes.item(i).name, b.attributes.item(i).value) for i in range(len(b.attributes))]
28  a_atts.sort()
29  b_atts.sort()
30 
31  for i in range(len(a_atts)):
32  if a_atts[i][0] != b_atts[i][0]:
33  print("Different attribute names: %s and %s" % (a_atts[i][0], b_atts[i][0]))
34  return False
35  try:
36  if abs(float(a_atts[i][1]) - float(b_atts[i][1])) > 1.0e-9:
37  print("Different attribute values: %s and %s" % (a_atts[i][1], b_atts[i][1]))
38  return False
39  except ValueError: # Attribute values aren't numeric
40  if a_atts[i][1] != b_atts[i][1]:
41  print("Different attribute values: %s and %s" % (a_atts[i][1], b_atts[i][1]))
42  return False
43 
44  return True
45 
46 def text_matches(a, b):
47  a_norm = whitespace.sub(' ', a)
48  b_norm = whitespace.sub(' ', b)
49  if a_norm.strip() == b_norm.strip(): return True
50  print("Different text values: '%s' and '%s'" % (a, b))
51  return False
52 
53 def nodes_match(a, b, ignore_nodes):
54  if not a and not b:
55  return True
56  if not a or not b:
57  return False
58 
59  if a.nodeType != b.nodeType:
60  print("Different node types: %s and %s" % (a, b))
61  return False
62 
63  # compare text-valued nodes
64  if a.nodeType in [xml.dom.Node.TEXT_NODE,
65  xml.dom.Node.CDATA_SECTION_NODE,
66  xml.dom.Node.COMMENT_NODE]:
67  return text_matches(a.data, b.data)
68 
69  # ignore all other nodes except ELEMENTs
70  if a.nodeType != xml.dom.Node.ELEMENT_NODE:
71  return True
72 
73  # compare ELEMENT nodes
74  if a.nodeName != b.nodeName:
75  print("Different element names: %s and %s" % (a.nodeName, b.nodeName))
76  return False
77 
78  if not all_attributes_match(a, b):
79  return False
80 
81  a = a.firstChild
82  b = b.firstChild
83  while a or b:
84  # ignore whitespace-only text nodes
85  # we could have several text nodes in a row, due to replacements
86  while (a and
87  ((a.nodeType in ignore_nodes) or
88  (a.nodeType == xml.dom.Node.TEXT_NODE and whitespace.sub('', a.data) == ""))):
89  a = a.nextSibling
90  while (b and
91  ((b.nodeType in ignore_nodes) or
92  (b.nodeType == xml.dom.Node.TEXT_NODE and whitespace.sub('', b.data) == ""))):
93  b = b.nextSibling
94 
95  if not nodes_match(a, b, ignore_nodes):
96  return False
97 
98  if a: a = a.nextSibling
99  if b: b = b.nextSibling
100 
101  return True
102 
103 
104 def xml_matches(a, b, ignore_nodes=[]):
105  if isinstance(a, str):
106  return xml_matches(parseString(a).documentElement, b, ignore_nodes)
107  if isinstance(b, str):
108  return xml_matches(a, parseString(b).documentElement, ignore_nodes)
109  if a.nodeType == xml.dom.Node.DOCUMENT_NODE:
110  return xml_matches(a.documentElement, b, ignore_nodes)
111  if b.nodeType == xml.dom.Node.DOCUMENT_NODE:
112  return xml_matches(a, b.documentElement, ignore_nodes)
113 
114  if not nodes_match(a, b, ignore_nodes):
115  print("Match failed:")
116  a.writexml(sys.stdout)
117  print()
118  print('=' * 78)
119  b.writexml(sys.stdout)
120  print()
121  return False
122  return True
123 
124 
125 # capture output going to file=sys.stdout | sys.stderr
126 @contextmanager
127 def capture_stderr(function, *args, **kwargs):
128  old, sys.stderr = sys.stderr, StringIO() # temporarily replace sys.stderr with StringIO()
129  result = function(*args, **kwargs)
130  sys.stderr.seek(0)
131  yield (result, sys.stderr.read())
132  sys.stderr = old # restore sys.stderr
133 
134 
135 class TestMatchXML(unittest.TestCase):
137  self.assertTrue(text_matches("", " \t\n\r"))
139  self.assertTrue(text_matches(" foo bar ", "foo \t\n\r bar"))
140 
142  self.assertTrue(xml_matches('''<foo/>''', '''<foo> \t\n\r </foo>'''))
144  self.assertTrue(xml_matches('''<foo> \t\n\r </foo>''', '''<foo/>'''))
146  self.assertTrue(xml_matches('''<a><b/></a>''', '''<a>\n<b> </b> </a>'''))
147 
149  self.assertTrue(xml_matches('''<a><b/><!-- foo --> <!-- bar --></a>''',
150  '''<a><b/></a>''', [xml.dom.Node.COMMENT_NODE]))
151 
152 
153 class TestXacroFunctions(unittest.TestCase):
155  self.assertTrue(xacro.is_valid_name("_valid_name_123"))
156  self.assertFalse(xacro.is_valid_name('pass')) # syntactically correct keyword
157  self.assertFalse(xacro.is_valid_name('foo ')) # trailing whitespace
158  self.assertFalse(xacro.is_valid_name(' foo')) # leading whitespace
159  self.assertFalse(xacro.is_valid_name('1234')) # number
160  self.assertFalse(xacro.is_valid_name('1234abc')) # number and letters
161  self.assertFalse(xacro.is_valid_name('')) # empty string
162  self.assertFalse(xacro.is_valid_name(' ')) # whitespace only
163  self.assertFalse(xacro.is_valid_name('foo bar')) # several tokens
164  self.assertFalse(xacro.is_valid_name('no-dashed-names-for-you'))
165  self.assertFalse(xacro.is_valid_name('invalid.too')) # dot separates fields
166 
168  # define three nested macro dicts with the same macro names (keys)
169  content = {'xacro:simple': 'simple'}
170  ns2 = dict({k: v+'2' for k,v in content.iteritems()})
171  ns1 = dict({k: v+'1' for k,v in content.iteritems()})
172  ns1.update(ns2=ns2)
173  macros = dict(content)
174  macros.update(ns1=ns1)
175 
176  self.assertEqual(xacro.resolve_macro('simple', macros), 'simple')
177  self.assertEqual(xacro.resolve_macro('ns1.simple', macros), 'simple1')
178  self.assertEqual(xacro.resolve_macro('ns1.ns2.simple', macros), 'simple2')
179 
180  self.assertEqual(xacro.resolve_macro('xacro:simple', macros), 'simple')
181  self.assertEqual(xacro.resolve_macro('xacro:ns1.simple', macros), 'simple1')
182  self.assertEqual(xacro.resolve_macro('xacro:ns1.ns2.simple', macros), 'simple2')
183 
184  def check_macro_arg(self, s, param, forward, default, rest):
185  p, v, r = xacro.parse_macro_arg(s)
186  self.assertEqual(p, param, msg="'{0}' != '{1}' parsing {2}".format(p, param, s))
187  if forward or default:
188  self.assertTrue(v is not None)
189  self.assertEqual(v[0], forward, msg="'{0}' != '{1}' parsing {2}".format(v[0], forward, s))
190  self.assertEqual(v[1], default, msg="'{0}' != '{1}' parsing {2}".format(v[1], default, s))
191  else:
192  self.assertTrue(v is None)
193  self.assertEqual(r, rest, msg="'{0}' != '{1}' parsing {2}".format(r, rest, s))
194 
196  for forward in ['', '^', '^|']:
197  defaults = ['', "f('some string','some other')", "f('a b')"]
198  if forward == '^': defaults = ['']
199  for default in defaults:
200  seps = ['=', ':='] if forward or default else ['']
201  for sep in seps:
202  for rest in ['', ' ', ' bar', ' bar=42']:
203  s = 'foo{0}{1}{2}{3}'.format(sep, forward, default, rest)
204  self.check_macro_arg(s, 'foo', 'foo' if forward else None,
205  default if default else None,
206  rest.lstrip())
208  for ws in [' ', ' \t ', ' \n ']:
209  self.check_macro_arg(ws + 'foo' + ws + 'bar=42' + ws, 'foo', None, None, 'bar=42' + ws)
210 
211 # base class providing some convenience functions
212 class TestXacroBase(unittest.TestCase):
213  def __init__(self, *args, **kwargs):
214  super(TestXacroBase, self).__init__(*args, **kwargs)
215  self.in_order = False
216  self.ignore_nodes = []
217 
218  def assert_matches(self, a, b):
219  self.assertTrue(xml_matches(a, b, self.ignore_nodes))
220 
221  def quick_xacro(self, xml, cli=None, **kwargs):
222  args = {}
223  if cli:
224  opts, _ = xacro.cli.process_args(cli, require_input=False)
225  args.update(vars(opts)) # initialize with cli args
226  args.update(dict(in_order = self.in_order)) # set in_order option from test class
227  args.update(kwargs) # explicit function args have highest priority
228 
229  doc = xacro.parse(xml)
230  xacro.process_doc(doc, **args)
231  return doc
232 
233  def run_xacro(self, input_path, *args):
234  args = list(args)
235  if self.in_order:
236  args.append('--inorder')
237  test_dir = os.path.abspath(os.path.dirname(__file__))
238  xacro_path = os.path.join(test_dir, '..', 'scripts', 'xacro')
239  subprocess.call([xacro_path, input_path] + args)
240 
241 
242 # class to match XML docs while ignoring any comments
244  def __init__(self, *args, **kwargs):
245  super(TestXacroCommentsIgnored, self).__init__(*args, **kwargs)
246  self.ignore_nodes = [xml.dom.Node.COMMENT_NODE]
247 
248  def test_pr2(self):
249  # run xacro on the pr2 tree snapshot
250  test_dir= os.path.abspath(os.path.dirname(__file__))
251  pr2_xacro_path = os.path.join(test_dir, 'robots', 'pr2', 'pr2.urdf.xacro')
252  pr2_golden_parse_path = os.path.join(test_dir, 'robots', 'pr2', 'pr2_1.11.4.xml')
253  self.assert_matches(
254  xml.dom.minidom.parse(pr2_golden_parse_path),
255  self.quick_xacro(open(pr2_xacro_path)))
256 
257 
258 # standard test class (including the test from TestXacroCommentsIgnored)
260  def __init__(self, *args, **kwargs):
261  super(TestXacroCommentsIgnored, self).__init__(*args, **kwargs)
262  self.ignore_nodes = []
263 
265  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
266  <xacro:property name="invalid.name"/></a>'''
267  self.assertRaises(xacro.XacroException, self.quick_xacro, src)
268 
270  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
271  <xacro:macro name="foo"><a>foo</a></xacro:macro>
272  <xacro:macro name="bar"><b>bar</b></xacro:macro>
273  <xacro:property name="var" value="%s"/>
274  <xacro:call macro="${var}"/></a>'''
275  res = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">%s</a>'''
276  self.assert_matches(self.quick_xacro(src % "foo"), res % "<a>foo</a>")
277  self.assert_matches(self.quick_xacro(src % "bar"), res % "<b>bar</b>")
278 
280  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
281  <xacro:macro name="foo"><a name="foo"/></xacro:macro>
282  <xacro:macro name="call"><a name="bar"/></xacro:macro>
283  <xacro:call/></a>'''
284  # for now we only issue a deprecated warning and expect the old behaviour
285  # resolving macro "call"
286  res = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><a name="bar"/></a>'''
287  # new behaviour would be to resolve to foo of course
288  # res = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><a name="foo"/></a>'''
289  with capture_stderr(self.quick_xacro, src) as (result, output):
290  self.assert_matches(result, res)
291  self.assertTrue("deprecated use of macro name 'call'" in output)
292 
294  self.assertRaises(xacro.XacroException,
295  self.quick_xacro,
296  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
297  <xacro:call macro="foo"/></a>''')
298 
300  self.assertRaises(xacro.XacroException,
301  self.quick_xacro,
302  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
303  <xacro:undefined><foo/><bar/></xacro:undefined></a>''')
304 
306  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
307  <xacro:macro name="foo" params="name"><xacro:element xacro:name="${name}"/></xacro:macro>
308  <xacro:foo name="A"/>
309  <xacro:foo name="B"/>
310 </a>'''
311  res = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><A/><B/></a>'''
312  self.assert_matches(self.quick_xacro(src), res)
313 
315  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
316  <xacro:macro name="foo" params="name value">
317  <tag><xacro:attribute name="${name}" value="${value}"/></tag>
318  </xacro:macro>
319  <xacro:foo name="A" value="foo"/>
320  <xacro:foo name="B" value="bar"/>
321 </a>'''
322  res = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><tag A="foo"/><tag B="bar"/></a>'''
323  self.assert_matches(self.quick_xacro(src), res)
324 
326  src = '''<xml xmlns:xacro="http://www.ros.org/wiki/xacro">
327  <xacro:property name="foo" value="1.0"/>
328  <xacro:macro name="m" params="foo"><a foo="${foo}"/></xacro:macro>
329  <xacro:m foo="1 ${foo}"/>
330  <!-- now redefining the property and macro -->
331  <xacro:property name="foo" value="2.0"/>
332  <xacro:macro name="m" params="foo"><b bar="${foo}"/></xacro:macro>
333  <xacro:m foo="2 ${foo}"/>
334 </xml>'''
335  oldOrder = '''
336 <xml xmlns:xacro="http://www.ros.org/wiki/xacro">
337  <b bar="1 2.0"/>
338  <b bar="2 2.0"/>
339 </xml>
340 '''
341  inOrder = '''
342 <xml xmlns:xacro="http://www.ros.org/wiki/xacro">
343  <a foo="1 1.0"/>
344  <b bar="2 2.0"/>
345 </xml>
346 '''
347  self.assert_matches(self.quick_xacro(src), inOrder if self.in_order else oldOrder)
348 
350  self.assert_matches(
351  self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
352 <xacro:macro name="inner" params="*the_block">
353  <in_the_inner><xacro:insert_block name="the_block" /></in_the_inner>
354 </xacro:macro>
355 <xacro:macro name="outer" params="*the_block">
356  <in_the_outer><xacro:inner><xacro:insert_block name="the_block" /></xacro:inner></in_the_outer>
357 </xacro:macro>
358 <xacro:outer><woot /></xacro:outer></a>'''),
359  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
360 <in_the_outer><in_the_inner><woot /></in_the_inner></in_the_outer></a>''')
361 
363  self.assert_matches(self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
364  <xacro:macro name="foo" params="lst">${lst[-1]}</xacro:macro>
365  <foo lst="${[1,2,3]}"/></a>'''),
366  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">3</a>''')
367 
369  self.assert_matches(
370  self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
371  <xacro:property name="foo" value="42" />
372  <the_foo result="${foo}" />
373 </a>'''),
374  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
375  <the_foo result="42" />
376 </a>''')
377 
379  self.assert_matches(self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
380  <xacro:macro name="foo" params="factor">
381  <xacro:property name="foo" value="${21*factor}" scope="parent"/>
382  </xacro:macro>
383  <xacro:foo factor="2"/><a foo="${foo}"/></a>'''),
384  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><a foo="42"/></a>''')
385 
387  self.assert_matches(self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
388  <xacro:macro name="foo" params="factor">
389  <xacro:macro name="bar">
390  <xacro:property name="foo" value="${21*factor}" scope="global"/>
391  </xacro:macro>
392  <xacro:bar/>
393  </xacro:macro>
394  <xacro:foo factor="2"/><a foo="${foo}"/></a>'''),
395  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><a foo="42"/></a>''')
396 
398  self.assert_matches(
399  self.quick_xacro('''<a><f v="${0.9 / 2 - 0.2}" /></a>'''),
400  '''<a><f v="0.25" /></a>''')
401 
403  self.assert_matches(
404  self.quick_xacro('''<a><f v="$(find xacro)/test/test_xacro.py" /></a>'''),
405  '''<a><f v="''' + os.path.abspath((__file__).replace(".pyc",".py") + '''" /></a>'''))
406 
408  self.assert_matches(
409  self.quick_xacro('''<a><f v="$(arg sub_arg)" /></a>''', cli=['sub_arg:=my_arg']),
410  '''<a><f v="my_arg" /></a>''')
411 
413  self.assert_matches(
414  self.quick_xacro('''<a b="$${foo}" c="$$${foo}" />'''),
415  '''<a b="${foo}" c="$${foo}" />''')
416 
418  self.assert_matches(
419  self.quick_xacro('''<a b="$" />'''),
420  '''<a b="$" />''')
421 
423  self.assert_matches(
424  self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
425 <xacro:macro name="foo" params="*block">
426  <xacro:insert_block name="block" />
427  <xacro:insert_block name="block" />
428 </xacro:macro>
429 <xacro:foo>
430  <a_block />
431 </xacro:foo>
432 </a>'''),
433  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
434  <a_block />
435  <a_block />
436 </a>''')
437 
439  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
440 <xacro:macro name="foo" params="*block{A} *block{B}">
441  <xacro:insert_block name="block1" />
442  <xacro:insert_block name="block2" />
443 </xacro:macro>
444 <xacro:foo>
445  <block1/>
446  <block2/>
447 </xacro:foo>
448 </a>'''
449  res = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
450 <block{A}/>
451 <block{B}/>
452 </a>'''
453  # test both, reversal and non-reversal of block order
454  for d in [dict(A='1', B='2'), dict(A='2', B='1')]:
455  self.assert_matches(self.quick_xacro(src.format(**d)), res.format(**d))
456 
458  self.assert_matches(
459  self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
460 <xacro:macro name="m" params="num">
461  <test number="${num}" />
462 </xacro:macro>
463 <xacro:m num="100" />
464 </a>'''),
465  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
466  <test number="100" />
467 </a>''')
468 
470  self.assert_matches(
471  self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
472 <xacro:macro name="bar">bar</xacro:macro>
473 <xacro:property name="val" value="2" />
474 <xacro:property name="some_block">
475  <some_block attr="${val}"><xacro:bar/></some_block>
476 </xacro:property>
477 <foo>
478  <xacro:insert_block name="some_block" />
479 </foo>
480 </a>'''),
481  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
482 <foo><some_block attr="2">bar</some_block></foo>
483 </a>''')
484 
485  def test_include(self):
486  self.assert_matches(self.quick_xacro('''\
487 <a xmlns:xacro="http://www.ros.org/xacro">
488  <xacro:include filename="include1.xml" /></a>'''),
489  '''<a xmlns:xacro="http://www.ros.org/xacro"><inc1/></a>''')
490 
491  def test_include_glob(self):
492  input = '''<a xmlns:xacro="http://www.ros.org/xacro">
493  <xacro:include filename="include{glob}.xml"/></a>'''
494  result = '<a xmlns:xacro="http://www.ros.org/xacro"><inc1/><inc2/></a>'
495  for pattern in ['*', '?', '[1-2]']:
496  self.assert_matches(self.quick_xacro(input.format(glob=pattern)), result)
497 
499  self.assertRaises(xacro.XacroException,
500  self.quick_xacro, '''<a xmlns:xacro="http://www.ros.org/xacro">
501  <xacro:include filename="include-nada.xml" /></a>''')
502 
504  # <include> tags with some non-trivial content should not issue the deprecation warning
505  src = '''<a><include filename="nada"><tag/></include></a>'''
506  with capture_stderr(self.quick_xacro, src) as (result, output):
507  self.assert_matches(result, src)
508  self.assertEqual(output, '')
509 
511  doc = '''<a xmlns:xacro="http://www.ros.org/xacro">
512  <xacro:property name="file" value="include1.xml"/>
513  <xacro:include filename="${file}" /></a>'''
514  if self.in_order:
515  self.assert_matches(self.quick_xacro(doc),
516  '''<a xmlns:xacro="http://www.ros.org/xacro"><inc1/></a>''')
517  else:
518  self.assertRaises(xacro.XacroException, self.quick_xacro, doc)
519 
521  self.assert_matches(self.quick_xacro('''\
522 <a xmlns:xacro="http://www.ros.org/xacro">
523  <xacro:include filename="include1.xml"/>
524  <xacro:include filename="./include1.xml"/>
525  <xacro:include filename="subdir/include-recursive.xacro"/>
526 </a>'''),
527 '''<a xmlns:xacro="http://www.ros.org/xacro">
528 <inc1/><inc1/>
529 <subdir_inc1/><subdir_inc1/><inc1/></a>''')
530 
532  doc = '''
533 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
534  <xacro:property name="var" value="main"/>
535  <xacro:include filename="include1.xacro" ns="A"/>
536  <xacro:include filename="include2.xacro" ns="B"/>
537  <A.foo/><B.foo/>
538  <main var="${var}" A="${2*A.var}" B="${B.var+1}"/>
539 </a>'''
540  result = '''
541 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
542  <inc1/><inc2/><main var="main" A="2" B="3"/>
543 </a>'''
544 
545  if self.in_order:
546  self.assert_matches(self.quick_xacro(doc), result)
547  else:
548  self.assertRaises(xacro.XacroException, self.quick_xacro, doc)
549 
551  self.assert_matches(
552  self.quick_xacro('''\
553 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
554  <xacro:if value="false">
555  <a />
556  </xacro:if>
557  <xacro:if value="true">
558  <b />
559  </xacro:if>
560 </robot>'''),
561  '''\
562 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
563  <b />
564 </robot>''')
565 
567  self.assertRaises(xacro.XacroException,
568  self.quick_xacro,
569  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
570  <xacro:if value="nonsense"><foo/></xacro:if></a>''')
571 
573  self.assert_matches(
574  self.quick_xacro('''\
575 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
576  <xacro:if value="${0*42}">
577  <a />
578  </xacro:if>
579  <xacro:if value="0">
580  <b />
581  </xacro:if>
582  <xacro:if value="${0}">
583  <c />
584  </xacro:if>
585  <xacro:if value="${1*2+3}">
586  <d />
587  </xacro:if>
588 </robot>'''),
589  '''\
590 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
591  <d />
592 </robot>''')
593 
595  self.assert_matches(
596  self.quick_xacro('''\
597 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
598  <xacro:if value="${3*0.0}">
599  <a />
600  </xacro:if>
601  <xacro:if value="${3*0.1}">
602  <b />
603  </xacro:if>
604 </robot>'''),
605  '''\
606 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
607  <b />
608 </robot>''')
609 
611  self.assert_matches(
612  self.quick_xacro('''\
613 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
614  <xacro:property name="condT" value="${True}"/>
615  <xacro:property name="condF" value="${False}"/>
616  <xacro:if value="${condF}"><a /></xacro:if>
617  <xacro:if value="${condT}"><b /></xacro:if>
618  <xacro:if value="${True}"><c /></xacro:if>
619 </robot>'''),
620  '''\
621 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
622  <b /><c />
623 </robot>''')
624 
626  self.assert_matches(self.quick_xacro('''
627 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
628  <xacro:if value="1"><xacro:if value="0"><a>bar</a></xacro:if></xacro:if>
629 </a>'''),
630 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"/>''')
631 
633  self.assert_matches(self.quick_xacro('''
634 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
635  <xacro:property name="var" value="useit"/>
636  <xacro:if value="${var == 'useit'}"><foo>bar</foo></xacro:if>
637  <xacro:if value="${'use' in var}"><bar>foo</bar></xacro:if>
638 </a>'''),
639 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
640 <foo>bar</foo>
641 <bar>foo</bar>
642 </a>''')
643 
645  self.assert_matches(self.quick_xacro('''
646 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
647  <xacro:property name="xyz" value="5 -2"/>
648  <foo>${xyz}</foo>
649 </a>'''),
650 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
651  <foo>5 -2</foo>
652 </a>''')
653 
655  self.assert_matches(self.quick_xacro('''
656 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
657  <foo function="${1. + sin(pi)}"/>
658 </a>'''),
659 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
660  <foo function="1.0"/>
661 </a>''')
662 
664  self.assert_matches(self.quick_xacro('''
665 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
666  <xacro:if value="1"><!-- comment --> text <b>bar</b></xacro:if>
667 </a>'''),
668 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
669 <!-- comment --> text <b>bar</b></a>''')
670 
672  self.assert_matches(
673  self.quick_xacro('''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
674 <xacro:macro name="foo" params="*block">
675  <!-- comment -->
676  foo
677  <xacro:insert_block name="block" />
678 </xacro:macro>
679 <xacro:foo>
680  <!-- ignored comment -->
681  ignored text
682  <a_block />
683 </xacro:foo>
684 </a>'''),
685  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
686  <!-- comment -->
687  foo
688  <a_block />
689 </a>''')
690 
692  self.assert_matches(self.quick_xacro('''
693 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
694  <!-- A -->
695 
696  <!-- ignore multiline comments before any xacro tag -->
697  <!-- ignored -->
698  <xacro:property name="foo" value="1"/>
699  <!-- ignored -->
700  <xacro:if value="1"><!-- B --></xacro:if>
701  <!-- ignored -->
702  <xacro:macro name="foo"><!-- C --></xacro:macro>
703  <!-- ignored -->
704  <xacro:foo/>
705 </a>'''),
706 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
707 <!-- A --><!-- B --><!-- C --></a>''')
708 
710  self.assert_matches(
711  self.quick_xacro('''\
712 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
713  <xacro:property name="a" value=" 42 "/>
714  <xacro:property name="a2" value="${ 2 * a }"/>
715  <a doubled="${a2}"/>
716 </robot>'''),
717  '''\
718 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
719  <a doubled="84"/>
720 </robot>''')
721 
723  self.assert_matches(
724  self.quick_xacro('''\
725 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
726  <xacro:property name="a2" value="${2*a}"/>
727  <xacro:property name="a" value="42"/>
728  <a doubled="${a2}"/>
729 </robot>'''),
730  '''\
731 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
732  <a doubled="84"/>
733 </robot>''')
734 
736  self.assertRaises(xacro.XacroException,
737  self.quick_xacro, '''\
738 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
739  <xacro:property name="a" value="${a2}"/>
740  <xacro:property name="a2" value="${2*a}"/>
741  <a doubled="${a2}"/>
742 </robot>''')
743 
745  self.assert_matches(
746  self.quick_xacro('''\
747 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
748  <xacro:property name="a" value="1"/>
749  <xacro:property name="b" value="2"/>
750  <xacro:property name="c" value="3"/>
751  <xacro:property name="product" value="${a*b*c}"/>
752  <answer product="${product}"/>
753 </robot>'''),
754  '''\
755 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
756  <answer product="6"/>
757 </robot>''')
758 
760  self.assert_matches(
761  self.quick_xacro('''\
762 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
763  <xacro:property name="a" value="42"/>
764  <xacro:property name="b" value="${a}"/>
765  <xacro:property name="b" value="${-a}"/>
766  <xacro:property name="b" value="${a}"/>
767  <answer b="${b} ${b} ${b}"/>
768 </robot>'''),
769  '''\
770 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
771  <answer b="42 42 42"/>
772 </robot>''')
773 
775  self.assert_matches(
776  self.quick_xacro('''\
777 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
778  <xacro:property name="a" value="42"/>
779  <xacro:property name="b" value="${a}"/>
780  <xacro:property name="c" value="${b}"/>
781  <xacro:property name="d" value="${c}"/>
782  <answer d="${d}"/>
783 </robot>'''),
784  '''\
785 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
786  <answer d="42"/>
787 </robot>''')
788 
790  self.assert_matches(
791  self.quick_xacro('''\
792 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
793  <xacro:property name="a" value="42"/>
794  <xacro:property name="b" value="2.1"/>
795  <xacro:property name="c" value="${a}"/>
796  <xacro:property name="d" value="${b}"/>
797  <xacro:property name="f" value="${c*d}"/>
798  <answer f="${f}"/>
799 </robot>'''),
800  '''\
801 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
802  <answer f="88.2"/>
803 </robot>''')
804 
805  def test_from_issue(self):
806  self.assert_matches(
807  self.quick_xacro('''\
808 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
809  <xacro:property name="x" value="42"/>
810  <xacro:property name="wheel_width" value="${x}"/>
811  <link name="my_link">
812  <origin xyz="0 0 ${wheel_width/2}"/>
813  </link>
814 </robot>'''),
815  '''\
816 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
817  <link name="my_link">
818  <origin xyz="0 0 21.0"/>
819  </link>
820 </robot>''')
821 
823  self.assertRaises(xacro.XacroException,
824  self.quick_xacro, '''\
825 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
826  <xacro:property name="x" value="0"/>
827  <tag badness="${1/x}"/>
828 </robot>''')
829 
831  self.assert_matches(
832  self.quick_xacro('''\
833 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
834  <xacro:macro name="fixed_link" params="parent_link:=base_link child_link *joint_pose">
835  <link name="${child_link}"/>
836  <joint name="${child_link}_joint" type="fixed">
837  <xacro:insert_block name="joint_pose" />
838  <parent link="${parent_link}"/>
839  <child link="${child_link}" />
840  </joint>
841  </xacro:macro>
842  <xacro:fixed_link child_link="foo">
843  <origin xyz="0 0 0" rpy="0 0 0" />
844  </xacro:fixed_link >
845 </robot>'''),
846  '''\
847 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
848  <link name="foo"/>
849  <joint name="foo_joint" type="fixed">
850  <origin rpy="0 0 0" xyz="0 0 0"/>
851  <parent link="base_link"/>
852  <child link="foo"/>
853  </joint>
854 </robot>''')
855 
857  self.assert_matches(
858  self.quick_xacro('''\
859 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
860  <xacro:macro name="fixed_link" params="parent_link:=base_link child_link *joint_pose">
861  <link name="${child_link}"/>
862  <joint name="${child_link}_joint" type="fixed">
863  <xacro:insert_block name="joint_pose" />
864  <parent link="${parent_link}"/>
865  <child link="${child_link}" />
866  </joint>
867  </xacro:macro>
868  <xacro:fixed_link child_link="foo" parent_link="bar">
869  <origin xyz="0 0 0" rpy="0 0 0" />
870  </xacro:fixed_link >
871 </robot>'''),
872  '''\
873 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
874  <link name="foo"/>
875  <joint name="foo_joint" type="fixed">
876  <origin rpy="0 0 0" xyz="0 0 0"/>
877  <parent link="bar"/>
878  <child link="foo"/>
879  </joint>
880 </robot>''')
881 
883  self.assertRaises(xacro.XacroException,
884  self.quick_xacro, '''\
885 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
886  <xacro:macro name="fixed_link" params="parent_link child_link *joint_pose">
887  <link name="${child_link}"/>
888  <joint name="${child_link}_joint" type="fixed">
889  <xacro:insert_block name="joint_pose" />
890  <parent link="${parent_link}"/>
891  <child link="${child_link}" />
892  </joint>
893  </xacro:macro>
894  <xacro:fixed_link child_link="foo">
895  <origin xyz="0 0 0" rpy="0 0 0" />
896  </xacro:fixed_link >
897 </robot>''')
898 
899  def test_default_arg(self):
900  self.assert_matches(
901  self.quick_xacro('''\
902 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
903  <xacro:arg name="foo" default="2"/>
904  <link name="my_link">
905  <origin xyz="0 0 $(arg foo)"/>
906  </link>
907 </robot>
908 '''),'''\
909 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
910  <link name="my_link">
911  <origin xyz="0 0 2"/>
912  </link>
913 </robot>''')
914 
916  self.assert_matches(
917  self.quick_xacro('''\
918 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
919  <xacro:arg name="foo" default="2"/>
920  <link name="my_link">
921  <origin xyz="0 0 $(arg foo)"/>
922  </link>
923 </robot>
924 ''', ['foo:=4']),'''\
925 <robot xmlns:xacro="http://www.ros.org/wiki/xacro">
926  <link name="my_link">
927  <origin xyz="0 0 4"/>
928  </link>
929 </robot>''')
930 
932  self.assertRaises(Exception,
933  self.quick_xacro, '''\
934 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
935  <a arg="$(arg foo)"/>
936 </a>
937 ''')
938 
940  self.assert_matches(self.quick_xacro('''
941 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
942 <xacro:arg name="foo" default=""/>$(arg foo)</a>'''),
943  '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"/>''')
944 
946  # run xacro on broken input file to make sure we don't create an
947  # empty output file
948  tmp_dir_name = tempfile.mkdtemp() # create directory we can trash
949  output_path = os.path.join(tmp_dir_name, "should_not_exist")
950  self.run_xacro('broken.xacro', '-o', output_path)
951 
952  output_file_created = os.path.isfile(output_path)
953  shutil.rmtree(tmp_dir_name) # clean up after ourselves
954 
955  self.assertFalse(output_file_created)
956 
958  # run xacro to create output file in non-existent directory
959  # to make sure this directory will be created by xacro
960  tmp_dir_name = tempfile.mkdtemp() # create directory we can trash
961  shutil.rmtree(tmp_dir_name) # ensure directory is removed
962  output_path = os.path.join(tmp_dir_name, "out")
963  self.run_xacro('include1.xml', '-o', output_path)
964 
965  output_file_created = os.path.isfile(output_path)
966  shutil.rmtree(tmp_dir_name) # clean up after ourselves
967 
968  self.assertTrue(output_file_created)
969 
971  self.assert_matches(
972  self.quick_xacro('''\
973 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
974  <xacro:property name="list" value="[0, 1+1, 2]"/>
975  <xacro:property name="tuple" value="(0,1+1,2)"/>
976  <xacro:property name="dict" value="{'a':0, 'b':1+1, 'c':2}"/>
977  <a list="${list}" tuple="${tuple}" dict="${dict}"/>
978 </a>'''),
979 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
980  <a list="[0, 1+1, 2]" tuple="(0,1+1,2)" dict="{'a':0, 'b':1+1, 'c':2}"/>
981 </a>''')
982 
984  self.assert_matches(
985  self.quick_xacro('''\
986 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
987  <xacro:property name="list" value="${[0, 1+1, 2]}"/>
988  <xacro:property name="tuple" value="${(0,1+1,2)}"/>
989  <xacro:property name="dic" value="${dict(a=0, b=1+1, c=2)}"/>
990  <a list="${list}" tuple="${tuple}" dict="${dic}"/>
991 </a>'''),
992 '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
993  <a list="[0, 2, 2]" tuple="(0, 2, 2)" dict="{'a': 0, 'c': 2, 'b': 2}"/>
994 </a>''')
995 
997  self.assert_matches(
998  self.quick_xacro('''\
999 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1000  <arg name="foo" value="bar"/>
1001  <include filename="foo"/>
1002 </a>''', xacro_ns=False),
1003 '''\
1004 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1005  <arg name="foo" value="bar"/>
1006  <include filename="foo"/>
1007 </a>''')
1008 
1010  # If a property is assigned from a substitution arg, then this properties' value was
1011  # no longer converted to a python type, so that e.g. 0.5 remained u'0.5'.
1012  # If this property is then used in a numerical expression an exception is thrown.
1013  self.assert_matches(
1014  self.quick_xacro('''\
1015 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1016  <xacro:arg name="foo" default="0.5"/>
1017  <xacro:property name="prop" value="$(arg foo)" />
1018  <a prop="${prop-0.3}"/>
1019 </a>
1020 '''),'''\
1021 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1022  <a prop="0.2"/>
1023 </a>''')
1024 
1026  self.assert_matches(
1027  self.quick_xacro('''\
1028 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1029  <xacro:arg name="foo" default="0.5"/>
1030  <xacro:arg name="bar" default="$(arg foo)"/>
1031  <xacro:property name="prop" value="$(arg bar)" />
1032  <a prop="${prop-0.3}"/>
1033 </a>
1034 '''),'''\
1035 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1036  <a prop="0.2"/>
1037 </a>''')
1038 
1040  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1041  <xacro:macro name="xacro:my_macro"><foo/></xacro:macro>
1042  <xacro:my_macro/>
1043  </a>'''
1044  res = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><foo/></a>'''
1045  self.assert_matches(self.quick_xacro(src), res)
1046 
1048  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1049  <xacro:property name="pi" value="3.14"/></a>'''
1050  with capture_stderr(self.quick_xacro, src) as (result, output):
1051  self.assert_matches(result, '<a xmlns:xacro="http://www.ros.org/wiki/xacro"/>')
1052  self.assertTrue(output)
1053 
1055  src = '''
1056 <a xmlns:xacro="http://www.ros.org/xacro">
1057  <xacro:macro name="foo" params="a b:=${a} c:=$${a}"> a=${a} b=${b} c=${c} </xacro:macro>
1058  <xacro:property name="a" value="1"/>
1059  <xacro:property name="d" value="$${a}"/>
1060  <d d="${d}"><foo a="2"/></d>
1061 </a>'''
1062  res = '''<a xmlns:xacro="http://www.ros.org/xacro"><d d="${a}"> a=2 b=1 c=${a} </d></a>'''
1063  self.assert_matches(self.quick_xacro(src), res)
1064 
1066  src='''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1067  <xacro:property name="arg" value="42"/>
1068  <xacro:macro name="foo" params="arg:=^%s">${arg}</xacro:macro>
1069  <xacro:foo/>
1070  </a>'''
1071  res='''<a xmlns:xacro="http://www.ros.org/wiki/xacro">%s</a>'''
1072  self.assert_matches(self.quick_xacro(src % ''), res % '42')
1073  self.assert_matches(self.quick_xacro(src % '|'), res % '42')
1074  self.assert_matches(self.quick_xacro(src % '|6'), res % '42')
1075 
1077  src='''<a xmlns:xacro="http://www.ros.org/wiki/xacro">${2*'$(arg var)'}</a>'''
1078  res='''<a xmlns:xacro="http://www.ros.org/wiki/xacro">%s</a>'''
1079  self.assert_matches(self.quick_xacro(src, ['var:=xacro']), res % (2*'xacro'))
1080 
1082  src='''<a xmlns:xacro="http://www.ros.org/wiki/xacro">$(arg ${'v'+'ar'})</a>'''
1083  res='''<a xmlns:xacro="http://www.ros.org/wiki/xacro">%s</a>'''
1084  self.assert_matches(self.quick_xacro(src, ['var:=xacro']), res % 'xacro')
1085 
1086 # test class for in-order processing
1088  def __init__(self, *args, **kwargs):
1089  super(TestXacroInorder, self).__init__(*args, **kwargs)
1090  self.in_order = True
1091 
1093  doc = ('''<a xmlns:xacro="http://www.ros.org/xacro">
1094  <xacro:if value="false"><xacro:include filename="non-existent"/></xacro:if></a>''')
1095  self.assert_matches(self.quick_xacro(doc),
1096  '''<a xmlns:xacro="http://www.ros.org/xacro"/>''')
1097 
1099  self.assert_matches(
1100  self.quick_xacro('''\
1101 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1102  <xacro:arg name="has_stuff" default="false"/>
1103  <xacro:if value="$(arg has_stuff)">
1104  <xacro:include file="$(find nonexistent_package)/stuff.urdf" />
1105  </xacro:if>
1106 </a>'''),
1107 '<a xmlns:xacro="http://www.ros.org/wiki/xacro"/>')
1108 
1110  src = '''
1111 <a xmlns:xacro="http://www.ros.org/wiki/xacro">
1112  <xacro:property name="settings" value="${load_yaml('settings.yaml')}"/>
1113  <xacro:property name="type" value="$(arg type)"/>
1114  <xacro:include filename="${settings['arms'][type]['file']}"/>
1115  <xacro:call macro="${settings['arms'][type]['macro']}"/>
1116 </a>'''
1117  res = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro"><{tag}/></a>'''
1118  for i in ['inc1', 'inc2']:
1119  self.assert_matches(self.quick_xacro(src, cli=['type:=%s' % i]),
1120  res.format(tag=i))
1121 
1123  src='''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1124 <xacro:macro name="foo" params="arg:=${2*foo}">
1125  <xacro:property name="foo" value="-"/>
1126  <f val="${arg}"/>
1127 </xacro:macro>
1128 <xacro:property name="foo" value="${3*7}"/>
1129 <xacro:foo/>
1130 <xacro:property name="foo" value="*"/>
1131 <xacro:foo/>
1132 </a>'''
1133  res='''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1134 <f val="42"/><f val="**"/></a>'''
1135  self.assert_matches(self.quick_xacro(src), res)
1136 
1138  src = '''<a xmlns:xacro="http://www.ros.org/wiki/xacro">
1139 <xacro:property name="bar" value="unused"/>
1140 <xacro:property name="foo" value="unused"/>
1141 <xacro:macro name="foo" params="arg:=${foo}">
1142  <a val="${arg}"/>
1143 </xacro:macro>
1144 <xacro:foo/>
1145 <xacro:property name="bar" value="dummy"/>
1146 <xacro:property name="foo" value="21"/></a>'''
1147  with capture_stderr(self.quick_xacro, src, do_check_order=True) as (result, output):
1148  self.assertTrue("Document is incompatible to --inorder processing." in output)
1149  self.assertTrue("foo" in output) # foo should be reported
1150  self.assertTrue("bar" not in output) # bar shouldn't be reported
1151 
1153  src = '''
1154  <a xmlns:xacro="http://www.ros.org/xacro">
1155  <xacro:property name="prop" default="false"/>
1156  <xacro:unless value="${prop}">
1157  <foo/>
1158  <xacro:property name="prop" value="true"/>
1159  </xacro:unless>
1160 
1161  <!-- second foo should be ignored -->
1162  <xacro:unless value="${prop}">
1163  <foo/>
1164  <xacro:property name="prop" value="true"/>
1165  </xacro:unless>
1166  </a>'''
1167  res = '''<a xmlns:xacro="http://www.ros.org/xacro"><foo/></a>'''
1168  self.assert_matches(self.quick_xacro(src), res)
1169 
1170 
1171 if __name__ == '__main__':
1172  unittest.main()
def parse(inp, filename=None)
def text_matches(a, b)
Definition: test_xacro.py:46
def test_multiple_blocks(self)
Definition: test_xacro.py:438
def test_extension_in_expression(self)
Definition: test_xacro.py:1076
def test_normalize_whitespace_nested(self)
Definition: test_xacro.py:145
def test_default_arg_empty(self)
Definition: test_xacro.py:939
def test_xacro_attribute(self)
Definition: test_xacro.py:314
def test_include_from_variable(self)
Definition: test_xacro.py:510
def test_recursive_bad_math(self)
Definition: test_xacro.py:822
def test_whitespace_vs_empty_node(self)
Definition: test_xacro.py:143
def __init__(self, args, kwargs)
Definition: test_xacro.py:260
def assert_matches(self, a, b)
Definition: test_xacro.py:218
def test_property_scope_global(self)
Definition: test_xacro.py:386
def test_include_deprecated(self)
Definition: test_xacro.py:503
def __init__(self, args, kwargs)
Definition: test_xacro.py:244
def test_equality_expression_in_if_statement(self)
Definition: test_xacro.py:632
def test_default_param_override(self)
Definition: test_xacro.py:856
def test_multiple_definition_and_evaluation(self)
Definition: test_xacro.py:759
def process_doc(doc, in_order=False, just_deps=False, just_includes=False, mappings=None, xacro_ns=True, kwargs)
def test_evaluate_macro_params_before_body(self)
Definition: test_xacro.py:362
def test_broken_input_doesnt_create_empty_output_file(self)
Definition: test_xacro.py:945
def test_math_ignores_spaces(self)
Definition: test_xacro.py:397
def test_include_recursive(self)
Definition: test_xacro.py:520
def test_multiple_insert_blocks(self)
Definition: test_xacro.py:422
def test_math_expressions(self)
Definition: test_xacro.py:654
def test_boolean_if_statement(self)
Definition: test_xacro.py:550
def test_consider_non_elements_block(self)
Definition: test_xacro.py:671
def test_recursive_evaluation_wrong_order(self)
Definition: test_xacro.py:722
def test_integer_if_statement(self)
Definition: test_xacro.py:572
def __init__(self, args, kwargs)
Definition: test_xacro.py:213
def test_overwrite_globals(self)
Definition: test_xacro.py:1047
def capture_stderr(function, args, kwargs)
Definition: test_xacro.py:127
def resolve_macro(fullname, macros)
def test_issue_63_fixed_with_inorder_processing(self)
Definition: test_xacro.py:1098
def test_recursive_definition(self)
Definition: test_xacro.py:735
def test_macro_name_with_colon(self)
Definition: test_xacro.py:1039
def test_property_forwarding(self)
Definition: test_xacro.py:1065
def test_invalid_property_name(self)
Definition: test_xacro.py:264
def test_transitive_evaluation(self)
Definition: test_xacro.py:774
def is_valid_name(name)
def run_xacro(self, input_path, args)
Definition: test_xacro.py:233
def test_multi_tree_evaluation(self)
Definition: test_xacro.py:789
def test_include_nonexistent(self)
Definition: test_xacro.py:498
def test_float_if_statement(self)
Definition: test_xacro.py:594
def xml_matches(a, b, ignore_nodes=[])
Definition: test_xacro.py:104
def test_substitution_args_arg(self)
Definition: test_xacro.py:407
def test_default_arg_override(self)
Definition: test_xacro.py:915
def test_iterable_literals_eval(self)
Definition: test_xacro.py:983
def test_macro_default_param_evaluation_order(self)
Definition: test_xacro.py:1122
def test_consider_non_elements_if(self)
Definition: test_xacro.py:663
def test_integer_stays_integer(self)
Definition: test_xacro.py:457
def test_macro_undefined(self)
Definition: test_xacro.py:299
def test_multiple_recursive_evaluation(self)
Definition: test_xacro.py:744
def all_attributes_match(a, b)
Definition: test_xacro.py:22
def test_dynamic_macro_name_clash(self)
Definition: test_xacro.py:279
def test_substitution_args_find(self)
Definition: test_xacro.py:402
def test_insert_block_property(self)
Definition: test_xacro.py:469
def test_include_with_namespace(self)
Definition: test_xacro.py:531
def test_recursive_evaluation(self)
Definition: test_xacro.py:709
def test_property_scope_parent(self)
Definition: test_xacro.py:378
def test_no_double_evaluation(self)
Definition: test_xacro.py:1054
def test_normalize_whitespace_text(self)
Definition: test_xacro.py:136
def test_expression_in_extension(self)
Definition: test_xacro.py:1081
def process_args(argv, require_input=True)
Definition: cli.py:62
def test_transitive_arg_evaluation(self)
Definition: test_xacro.py:1025
def test_property_replacement(self)
Definition: test_xacro.py:368
def test_enforce_xacro_ns(self)
Definition: test_xacro.py:996
def parse_macro_arg(s)
def test_ignore_xacro_comments(self)
Definition: test_xacro.py:691
def test_dynamic_macro_names(self)
Definition: test_xacro.py:269
def test_inorder_processing(self)
Definition: test_xacro.py:325
def test_issue_68_numeric_arg(self)
Definition: test_xacro.py:1009
def test_invalid_if_statement(self)
Definition: test_xacro.py:566
def test_just_a_dollar_sign(self)
Definition: test_xacro.py:417
def test_should_replace_before_macroexpand(self)
Definition: test_xacro.py:349
def test_normalize_whitespace_trim(self)
Definition: test_xacro.py:138
def test_empty_node_vs_whitespace(self)
Definition: test_xacro.py:141
def test_escaping_dollar_braces(self)
Definition: test_xacro.py:412
def quick_xacro(self, xml, cli=None, kwargs)
Definition: test_xacro.py:221
def check_macro_arg(self, s, param, forward, default, rest)
Definition: test_xacro.py:184
def test_dynamic_macro_undefined(self)
Definition: test_xacro.py:293
def __init__(self, args, kwargs)
Definition: test_xacro.py:1088
def test_default_arg_missing(self)
Definition: test_xacro.py:931
def test_iterable_literals_plain(self)
Definition: test_xacro.py:970
def nodes_match(a, b, ignore_nodes)
Definition: test_xacro.py:53


xacro
Author(s): Stuart Glaser, William Woodall, Robert Haschke
autogenerated on Mon Jun 10 2019 15:46:01