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