changeset 832:7ad34db77566

Cleaned up XPath tests, added tests from #185.
author cmlenz
date Tue, 17 Mar 2009 14:25:22 +0000
parents 398c1b07f832
children b5c9b92b0bd6
files genshi/tests/path.py
diffstat 1 files changed, 425 insertions(+), 343 deletions(-) [+]
line wrap: on
line diff
--- a/genshi/tests/path.py
+++ b/genshi/tests/path.py
@@ -25,45 +25,10 @@
     def test(self, ignore_context = False):
         return self.strategy.test(ignore_context)
 
+
 class PathTestCase(unittest.TestCase):
 
     strategies = [GenericStrategy, SingleStepStrategy, SimplePathStrategy]
-    def _create_path(self, expression, expected):
-        return path
-
-    def _test_strategies(self, stream, path, render,
-                             namespaces=None, variables=None):
-        for strategy in self.strategies:
-            if not strategy.supports(path):
-                continue
-            s = strategy(path)
-            rendered = FakePath(s).select(stream,namespaces=namespaces,
-                                            variables=variables).render()
-            msg = "Bad render using %s strategy"%str(strategy)
-            msg += "\nExpected:\t'%s'"%render
-            msg += "\nRendered:\t'%s'"%rendered
-            self.assertEqual(render, rendered, msg)
-
-    def _test_expression(self, text, expected, stream=None, render="",
-                            namespaces=None, variables=None):
-        path = Path(text)
-        if expected is not None:
-            self.assertEqual(expected, repr(path))
-
-        if stream is None:
-            return
-
-        rendered = path.select(stream, namespaces=namespaces,
-                                    variables=variables).render()
-        msg = "Bad render using whole path"
-        msg += "\nExpected:\t'%s'"%render
-        msg += "\nRendered:\t'%s'"%rendered
-        self.assertEqual(render, rendered, msg)
-
-        if len(path.paths) == 1:
-            self._test_strategies(stream, path.paths[0], render,
-                                namespaces=namespaces, variables=variables)
-
 
     def test_error_no_absolute_path(self):
         self.assertRaises(PathSyntaxError, Path, '/root')
@@ -74,442 +39,520 @@
 
     def test_1step(self):
         xml = XML('<root><elem/></root>')
-
-        self._test_expression(  'elem',
-                                '<Path "child::elem">',
-                                xml,
-                                '<elem/>')
-
-        self._test_expression(  'elem',
-                                '<Path "child::elem">',
-                                xml,
-                                '<elem/>')
-
-        self._test_expression(  'child::elem',
-                                '<Path "child::elem">',
-                                xml,
-                                '<elem/>')
-
-        self._test_expression(  '//elem',
-                                '<Path "descendant-or-self::elem">',
-                                xml,
-                                '<elem/>')
-
-        self._test_expression(  'descendant::elem',
-                                '<Path "descendant::elem">',
-                                xml,
-                                '<elem/>')
+        self._test_eval(
+            path = 'elem',
+            equiv = '<Path "child::elem">',
+            input = xml,
+            output = '<elem/>'
+        )
+        self._test_eval(
+            path = 'elem',
+            equiv = '<Path "child::elem">',
+            input = xml,
+            output = '<elem/>'
+        )
+        self._test_eval(
+            path = 'child::elem',
+            equiv = '<Path "child::elem">',
+            input = xml,
+            output = '<elem/>'
+        )
+        self._test_eval(
+            path = '//elem',
+            equiv = '<Path "descendant-or-self::elem">',
+            input = xml,
+            output = '<elem/>'
+        )
+        self._test_eval(
+            path = 'descendant::elem',
+            equiv = '<Path "descendant::elem">',
+            input = xml,
+            output = '<elem/>'
+        )
 
     def test_1step_self(self):
         xml = XML('<root><elem/></root>')
-
-        self._test_expression(  '.',
-                                '<Path "self::node()">',
-                                xml,
-                                '<root><elem/></root>')
-
-        self._test_expression(  'self::node()',
-                                '<Path "self::node()">',
-                                xml,
-                                '<root><elem/></root>')
+        self._test_eval(
+            path = '.',
+            equiv = '<Path "self::node()">',
+            input = xml,
+            output = '<root><elem/></root>'
+        )
+        self._test_eval(
+            path = 'self::node()',
+            equiv = '<Path "self::node()">',
+            input = xml,
+            output = '<root><elem/></root>'
+        )
 
     def test_1step_wildcard(self):
         xml = XML('<root><elem/></root>')
-
-        self._test_expression(  '*',
-                                '<Path "child::*">',
-                                xml,
-                                '<elem/>')
-
-        self._test_expression(  'child::*',
-                                '<Path "child::*">',
-                                xml,
-                                '<elem/>')
-
-        self._test_expression(  'child::node()',
-                                '<Path "child::node()">',
-                                xml,
-                                '<elem/>')
-
-        self._test_expression(  '//*',
-                                '<Path "descendant-or-self::*">',
-                                xml,
-                                '<root><elem/></root>')
+        self._test_eval(
+            path = '*',
+            equiv = '<Path "child::*">',
+            input = xml,
+            output = '<elem/>'
+        )
+        self._test_eval(
+            path = 'child::*',
+            equiv = '<Path "child::*">',
+            input = xml,
+            output = '<elem/>'
+        )
+        self._test_eval(
+            path = 'child::node()',
+            equiv = '<Path "child::node()">',
+            input = xml,
+            output = '<elem/>'
+        )
+        self._test_eval(
+            path = '//*',
+            equiv = '<Path "descendant-or-self::*">',
+            input = xml,
+            output = '<root><elem/></root>'
+        )
 
     def test_1step_attribute(self):
-        self._test_expression(  '@foo',
-                                '<Path "attribute::foo">',
-                                XML('<root/>'),
-                                '')
-
+        self._test_eval(
+            path = '@foo',
+            equiv = '<Path "attribute::foo">',
+            input = XML('<root/>'),
+            output = ''
+        )
         xml = XML('<root foo="bar"/>')
-
-        self._test_expression(  '@foo',
-                                '<Path "attribute::foo">',
-                                xml,
-                                'bar')
-
-        self._test_expression(  './@foo',
-                                '<Path "self::node()/attribute::foo">',
-                                xml,
-                                'bar')
+        self._test_eval(
+            path = '@foo',
+            equiv = '<Path "attribute::foo">',
+            input = xml,
+            output = 'bar'
+        )
+        self._test_eval(
+            path = './@foo',
+            equiv = '<Path "self::node()/attribute::foo">',
+            input = xml,
+            output = 'bar'
+        )
 
     def test_1step_text(self):
         xml = XML('<root>Hey</root>')
-
-        self._test_expression(  'text()',
-                                '<Path "child::text()">',
-                                xml,
-                                'Hey')
-
-        self._test_expression(  './text()',
-                                '<Path "self::node()/child::text()">',
-                                xml,
-                                'Hey')
-
-        self._test_expression(  '//text()',
-                                '<Path "descendant-or-self::text()">',
-                                xml,
-                                'Hey')
-
-        self._test_expression(  './/text()',
-            '<Path "self::node()/descendant-or-self::node()/child::text()">',
-                                xml,
-                                'Hey')
+        self._test_eval(
+            path = 'text()',
+            equiv = '<Path "child::text()">',
+            input = xml,
+            output = 'Hey'
+        )
+        self._test_eval(
+            path = './text()',
+            equiv = '<Path "self::node()/child::text()">',
+            input = xml,
+            output = 'Hey'
+        )
+        self._test_eval(
+            path = '//text()',
+            equiv = '<Path "descendant-or-self::text()">',
+            input = xml,
+            output = 'Hey'
+        )
+        self._test_eval(
+            path = './/text()',
+            equiv = '<Path "self::node()/descendant-or-self::node()/child::text()">',
+            input = xml,
+            output = 'Hey'
+        )
 
     def test_2step(self):
         xml = XML('<root><foo/><bar/></root>')
-        self._test_expression('*', None, xml, '<foo/><bar/>')
-        self._test_expression('bar', None, xml, '<bar/>')
-        self._test_expression('baz', None, xml, '')
+        self._test_eval('*', input=xml, output='<foo/><bar/>')
+        self._test_eval('bar', input=xml, output='<bar/>')
+        self._test_eval('baz', input=xml, output='')
 
     def test_2step_attribute(self):
         xml = XML('<elem class="x"><span id="joe">Hey Joe</span></elem>')
-        self._test_expression('@*', None, xml, 'x')
-        self._test_expression('./@*', None, xml, 'x')
-        self._test_expression('.//@*', None, xml, 'xjoe')
-        self._test_expression('*/@*', None, xml, 'joe')
+        self._test_eval('@*', input=xml, output='x')
+        self._test_eval('./@*', input=xml, output='x')
+        self._test_eval('.//@*', input=xml, output='xjoe')
+        self._test_eval('*/@*', input=xml, output='joe')
 
         xml = XML('<elem><foo id="1"/><foo id="2"/></elem>')
-        self._test_expression('@*', None, xml, '')
-        self._test_expression('foo/@*', None, xml, '12')
+        self._test_eval('@*', input=xml, output='')
+        self._test_eval('foo/@*', input=xml, output='12')
 
     def test_2step_complex(self):
         xml = XML('<root><foo><bar/></foo></root>')
-
-        self._test_expression(  'foo/bar',
-                                '<Path "child::foo/child::bar">',
-                                xml,
-                                '<bar/>')
-
-        self._test_expression(  './bar',
-                                '<Path "self::node()/child::bar">',
-                                xml,
-                                '')
-
-        self._test_expression(  'foo/*',
-                                '<Path "child::foo/child::*">',
-                                xml,
-                                '<bar/>')
-
+        self._test_eval(
+            path = 'foo/bar',
+            equiv = '<Path "child::foo/child::bar">',
+            input = xml,
+            output = '<bar/>'
+        )
+        self._test_eval(
+            path = './bar',
+            equiv = '<Path "self::node()/child::bar">',
+            input = xml,
+            output = ''
+        )
+        self._test_eval(
+            path = 'foo/*',
+            equiv = '<Path "child::foo/child::*">',
+            input = xml,
+            output = '<bar/>'
+        )
         xml = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>')
-        self._test_expression(  './bar',
-                                '<Path "self::node()/child::bar">',
-                                xml,
-                                '<bar id="2"/>')
+        self._test_eval(
+            path = './bar',
+            equiv = '<Path "self::node()/child::bar">',
+            input = xml,
+            output = '<bar id="2"/>'
+        )
 
     def test_2step_text(self):
         xml = XML('<root><item>Foo</item></root>')
-
-        self._test_expression(  'item/text()',
-                                '<Path "child::item/child::text()">',
-                                xml,
-                                'Foo')
-
-        self._test_expression(  '*/text()',
-                                '<Path "child::*/child::text()">',
-                                xml,
-                                'Foo')
-
-        self._test_expression(  '//text()',
-                                '<Path "descendant-or-self::text()">',
-                                xml,
-                                'Foo')
-
-        self._test_expression(  './text()',
-                                '<Path "self::node()/child::text()">',
-                                xml,
-                                '')
-
+        self._test_eval(
+            path = 'item/text()',
+            equiv = '<Path "child::item/child::text()">',
+            input = xml,
+            output = 'Foo'
+        )
+        self._test_eval(
+            path = '*/text()',
+            equiv = '<Path "child::*/child::text()">',
+            input = xml,
+            output = 'Foo'
+        )
+        self._test_eval(
+            path = '//text()',
+            equiv = '<Path "descendant-or-self::text()">',
+            input = xml,
+            output = 'Foo'
+        )
+        self._test_eval(
+            path = './text()',
+            equiv = '<Path "self::node()/child::text()">',
+            input = xml,
+            output = ''
+        )
         xml = XML('<root><item>Foo</item><item>Bar</item></root>')
-        self._test_expression(  'item/text()',
-                                '<Path "child::item/child::text()">',
-                                xml,
-                                'FooBar')
+        self._test_eval(
+            path = 'item/text()',
+            equiv = '<Path "child::item/child::text()">',
+            input = xml,
+            output = 'FooBar'
+        )
+        xml = XML('<root><item><name>Foo</name><sub><name>Bar</name></sub></item></root>') 
+        self._test_eval(
+            path = 'item/name/text()',
+            equiv = '<Path "child::item/child::name/child::text()">',
+            input = xml,
+            output = 'Foo'
+        )
 
     def test_3step(self):
         xml = XML('<root><foo><bar/></foo></root>')
-        self._test_expression(  'foo/*',
-                                '<Path "child::foo/child::*">',
-                                xml,
-                                '<bar/>')
+        self._test_eval(
+            path = 'foo/*',
+            equiv = '<Path "child::foo/child::*">',
+            input = xml,
+            output = '<bar/>'
+        )
 
     def test_3step_complex(self):
-        xml = XML('<root><foo><bar/></foo></root>')
-        self._test_expression(  '*/bar',
-                                '<Path "child::*/child::bar">',
-                                xml,
-                                '<bar/>')
+        self._test_eval(
+            path = '*/bar',
+            equiv = '<Path "child::*/child::bar">',
+            input = XML('<root><foo><bar/></foo></root>'),
+            output = '<bar/>'
+        )
+        self._test_eval(
+            path = '//bar',
+            equiv = '<Path "descendant-or-self::bar">',
+            input = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>'),
+            output = '<bar id="1"/><bar id="2"/>'
+        )
 
-        xml = XML('<root><foo><bar id="1"/></foo><bar id="2"/></root>')
-        self._test_expression(  '//bar',
-                                '<Path "descendant-or-self::bar">',
-                                xml,
-                                '<bar id="1"/><bar id="2"/>')
+    def test_3step_complex_text(self):
+        xml = XML('<root><item><bar>Some text </bar><baz><bar>in here.</bar></baz></item></root>')
+        self._test_eval(
+            path = 'item/bar/text()',
+            equiv = '<Path "child::item/child::bar/child::text()">',
+            input = xml,
+            output = 'Some text '
+        )
+        self._test_eval(
+            path = 'item//bar/text()',
+            equiv = '<Path "child::item/descendant-or-self::node()/child::bar/child::text()">',
+            input = xml,
+            output = 'Some text in here.'
+        )
 
     def test_node_type_comment(self):
         xml = XML('<root><!-- commented --></root>')
-        self._test_expression(  'comment()',
-                                '<Path "child::comment()">',
-                                xml,
-                                '<!-- commented -->')
+        self._test_eval(
+            path = 'comment()',
+            equiv = '<Path "child::comment()">',
+            input = xml,
+            output = '<!-- commented -->'
+        )
 
     def test_node_type_text(self):
         xml = XML('<root>Some text <br/>in here.</root>')
-        self._test_expression(  'text()',
-                                '<Path "child::text()">',
-                                xml,
-                                'Some text in here.')
+        self._test_eval(
+            path = 'text()',
+            equiv = '<Path "child::text()">',
+            input = xml,
+            output = 'Some text in here.'
+        )
 
     def test_node_type_node(self):
         xml = XML('<root>Some text <br/>in here.</root>')
-        self._test_expression(  'node()',
-                                '<Path "child::node()">',
-                                xml,
-                                'Some text <br/>in here.',)
+        self._test_eval(
+            path = 'node()',
+            equiv = '<Path "child::node()">',
+            input = xml,
+            output = 'Some text <br/>in here.'
+        )
 
     def test_node_type_processing_instruction(self):
         xml = XML('<?python x = 2 * 3 ?><root><?php echo("x") ?></root>')
-
-        self._test_expression(  '//processing-instruction()',
-                        '<Path "descendant-or-self::processing-instruction()">',
-                                xml,
-                                '<?python x = 2 * 3 ?><?php echo("x") ?>')
-
-        self._test_expression(  'processing-instruction()',
-                                '<Path "child::processing-instruction()">',
-                                xml,
-                                '<?php echo("x") ?>')
-
-        self._test_expression(  'processing-instruction("php")',
-                        '<Path "child::processing-instruction(\"php\")">',
-                                xml,
-                                '<?php echo("x") ?>')
+        self._test_eval(
+            path = '//processing-instruction()',
+            equiv = '<Path "descendant-or-self::processing-instruction()">',
+            input = xml,
+            output = '<?python x = 2 * 3 ?><?php echo("x") ?>'
+        )
+        self._test_eval(
+            path = 'processing-instruction()',
+            equiv = '<Path "child::processing-instruction()">',
+            input = xml,
+            output = '<?php echo("x") ?>'
+        )
+        self._test_eval(
+            path = 'processing-instruction("php")',
+            equiv = '<Path "child::processing-instruction(\"php\")">',
+            input = xml,
+            output = '<?php echo("x") ?>'
+        )
 
     def test_simple_union(self):
         xml = XML("""<body>1<br />2<br />3<br /></body>""")
-        self._test_expression(  '*|text()',
-                                '<Path "child::*|child::text()">',
-                                xml,
-                                '1<br/>2<br/>3<br/>')
+        self._test_eval(
+            path = '*|text()',
+            equiv = '<Path "child::*|child::text()">',
+            input = xml,
+            output = '1<br/>2<br/>3<br/>'
+        )
 
     def test_predicate_name(self):
         xml = XML('<root><foo/><bar/></root>')
-        self._test_expression('*[name()="foo"]', None, xml, '<foo/>')
+        self._test_eval('*[name()="foo"]', input=xml, output='<foo/>')
 
     def test_predicate_localname(self):
         xml = XML('<root><foo xmlns="NS"/><bar/></root>')
-        self._test_expression('*[local-name()="foo"]', None, xml,
-                                '<foo xmlns="NS"/>')
+        self._test_eval('*[local-name()="foo"]', input=xml,
+                              output='<foo xmlns="NS"/>')
 
     def test_predicate_namespace(self):
         xml = XML('<root><foo xmlns="NS"/><bar/></root>')
-        self._test_expression('*[namespace-uri()="NS"]', None, xml,
-                                '<foo xmlns="NS"/>')
+        self._test_eval('*[namespace-uri()="NS"]', input=xml,
+                                output='<foo xmlns="NS"/>')
 
     def test_predicate_not_name(self):
         xml = XML('<root><foo/><bar/></root>')
-        self._test_expression('*[not(name()="foo")]', None, xml, '<bar/>')
+        self._test_eval('*[not(name()="foo")]', input=xml,
+                              output='<bar/>')
 
     def test_predicate_attr(self):
         xml = XML('<root><item/><item important="very"/></root>')
-        self._test_expression('item[@important]', None, xml,
-                                '<item important="very"/>')
-        self._test_expression('item[@important="very"]', None, xml,
-                                '<item important="very"/>')
+        self._test_eval('item[@important]', input=xml,
+                              output='<item important="very"/>')
+        self._test_eval('item[@important="very"]', input=xml,
+                              output='<item important="very"/>')
 
     def test_predicate_attr_equality(self):
         xml = XML('<root><item/><item important="notso"/></root>')
-        self._test_expression('item[@important="very"]', None, xml, '')
-        self._test_expression('item[@important!="very"]', None, xml,
-                                '<item/><item important="notso"/>')
+        self._test_eval('item[@important="very"]', input=xml, output='')
+        self._test_eval('item[@important!="very"]', input=xml,
+                              output='<item/><item important="notso"/>')
 
     def test_predicate_attr_greater_than(self):
         xml = XML('<root><item priority="3"/></root>')
-        self._test_expression('item[@priority>3]', None, xml, '')
-        self._test_expression('item[@priority>2]', None, xml,
-                                '<item priority="3"/>')
+        self._test_eval('item[@priority>3]', input=xml, output='')
+        self._test_eval('item[@priority>2]', input=xml,
+                              output='<item priority="3"/>')
 
     def test_predicate_attr_less_than(self):
         xml = XML('<root><item priority="3"/></root>')
-        self._test_expression('item[@priority<3]', None, xml, '')
-        self._test_expression('item[@priority<4]', None, xml,
-                                '<item priority="3"/>')
+        self._test_eval('item[@priority<3]', input=xml, output='')
+        self._test_eval('item[@priority<4]', input=xml,
+                              output='<item priority="3"/>')
 
     def test_predicate_attr_and(self):
         xml = XML('<root><item/><item important="very"/></root>')
-        self._test_expression('item[@important and @important="very"]',
-                                None, xml, '<item important="very"/>')
-        self._test_expression('item[@important and @important="notso"]',
-                                None, xml, '')
+        self._test_eval('item[@important and @important="very"]',
+                                input=xml, output='<item important="very"/>')
+        self._test_eval('item[@important and @important="notso"]',
+                                input=xml, output='')
 
     def test_predicate_attr_or(self):
         xml = XML('<root><item/><item important="very"/></root>')
-        self._test_expression('item[@urgent or @important]', None, xml,
-                                '<item important="very"/>')
-        self._test_expression('item[@urgent or @notso]', None, xml, '')
+        self._test_eval('item[@urgent or @important]', input=xml,
+                              output='<item important="very"/>')
+        self._test_eval('item[@urgent or @notso]', input=xml, output='')
 
     def test_predicate_boolean_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[boolean("")]', None, xml, '')
-        self._test_expression('*[boolean("yo")]', None, xml, '<foo>bar</foo>')
-        self._test_expression('*[boolean(0)]', None, xml, '')
-        self._test_expression('*[boolean(42)]', None, xml, '<foo>bar</foo>')
-        self._test_expression('*[boolean(false())]', None, xml, '')
-        self._test_expression('*[boolean(true())]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[boolean("")]', input=xml, output='')
+        self._test_eval('*[boolean("yo")]', input=xml,
+                              output='<foo>bar</foo>')
+        self._test_eval('*[boolean(0)]', input=xml, output='')
+        self._test_eval('*[boolean(42)]', input=xml,
+                              output='<foo>bar</foo>')
+        self._test_eval('*[boolean(false())]', input=xml, output='')
+        self._test_eval('*[boolean(true())]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_ceil_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[ceiling("4.5")=5]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[ceiling("4.5")=5]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_concat_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[name()=concat("f", "oo")]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[name()=concat("f", "oo")]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_contains_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[contains(name(), "oo")]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[contains(name(), "oo")]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_matches_function(self):
         xml = XML('<root><foo>bar</foo><bar>foo</bar></root>')
-        self._test_expression('*[matches(name(), "foo|bar")]', None, xml,
-                                '<foo>bar</foo><bar>foo</bar>')
+        self._test_eval('*[matches(name(), "foo|bar")]', input=xml,
+                              output='<foo>bar</foo><bar>foo</bar>')
 
     def test_predicate_false_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[false()]', None, xml, '')
+        self._test_eval('*[false()]', input=xml, output='')
 
     def test_predicate_floor_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[floor("4.5")=4]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[floor("4.5")=4]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_normalize_space_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[normalize-space(" foo   bar  ")="foo bar"]',
-                                None, xml, '<foo>bar</foo>')
+        self._test_eval('*[normalize-space(" foo   bar  ")="foo bar"]',
+                                input=xml, output='<foo>bar</foo>')
 
     def test_predicate_number_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[number("3.0")=3]', None, xml,
-                                 '<foo>bar</foo>')
-        self._test_expression('*[number("3.0")=3.0]', None, xml,
-                                '<foo>bar</foo>')
-        self._test_expression('*[number("0.1")=.1]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[number("3.0")=3]', input=xml,
+                              output='<foo>bar</foo>')
+        self._test_eval('*[number("3.0")=3.0]', input=xml,
+                              output='<foo>bar</foo>')
+        self._test_eval('*[number("0.1")=.1]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_round_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[round("4.4")=4]', None, xml,
-                                '<foo>bar</foo>')
-        self._test_expression('*[round("4.6")=5]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[round("4.4")=4]', input=xml,
+                              output='<foo>bar</foo>')
+        self._test_eval('*[round("4.6")=5]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_starts_with_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[starts-with(name(), "f")]', None, xml,
-                                '<foo>bar</foo>')
-        self._test_expression('*[starts-with(name(), "b")]', None, xml, '')
+        self._test_eval('*[starts-with(name(), "f")]', input=xml,
+                              output='<foo>bar</foo>')
+        self._test_eval('*[starts-with(name(), "b")]', input=xml,
+                              output='')
 
     def test_predicate_string_length_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[string-length(name())=3]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[string-length(name())=3]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_substring_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[substring(name(), 1)="oo"]', None, xml,
-                                '<foo>bar</foo>')
-        self._test_expression('*[substring(name(), 1, 1)="o"]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[substring(name(), 1)="oo"]', input=xml,
+                              output='<foo>bar</foo>')
+        self._test_eval('*[substring(name(), 1, 1)="o"]', input=xml,
+                              output='<foo>bar</foo>')
 
     def test_predicate_substring_after_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[substring-after(name(), "f")="oo"]', None, xml,
-                                '<foo>bar</foo>')
+        self._test_eval('*[substring-after(name(), "f")="oo"]', input=xml,
+                                output='<foo>bar</foo>')
 
     def test_predicate_substring_before_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[substring-before(name(), "oo")="f"]',
-                                None, xml, '<foo>bar</foo>')
+        self._test_eval('*[substring-before(name(), "oo")="f"]',
+                                input=xml, output='<foo>bar</foo>')
 
     def test_predicate_translate_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[translate(name(), "fo", "ba")="baa"]',
-                                None, xml, '<foo>bar</foo>')
+        self._test_eval('*[translate(name(), "fo", "ba")="baa"]',
+                                input=xml, output='<foo>bar</foo>')
 
     def test_predicate_true_function(self):
         xml = XML('<root><foo>bar</foo></root>')
-        self._test_expression('*[true()]', None, xml, '<foo>bar</foo>')
+        self._test_eval('*[true()]', input=xml, output='<foo>bar</foo>')
 
     def test_predicate_variable(self):
         xml = XML('<root><foo>bar</foo></root>')
-        variables = {'bar': 'foo'}
-        self._test_expression('*[name()=$bar]', None, xml, '<foo>bar</foo>',
-                                variables = variables)
+        self._test_eval(
+            path = '*[name()=$bar]',
+            input = xml,
+            output = '<foo>bar</foo>',
+            variables = {'bar': 'foo'}
+        )
 
     def test_predicate_position(self):
         xml = XML('<root><foo id="a1"/><foo id="a2"/><foo id="a3"/></root>')
-        self._test_expression('*[2]', None, xml, '<foo id="a2"/>')
+        self._test_eval('*[2]', input=xml, output='<foo id="a2"/>')
 
     def test_predicate_attr_and_position(self):
         xml = XML('<root><foo/><foo id="a1"/><foo id="a2"/></root>')
-        self._test_expression('*[@id][2]', None, xml, '<foo id="a2"/>')
+        self._test_eval('*[@id][2]', input=xml, output='<foo id="a2"/>')
 
     def test_predicate_position_and_attr(self):
         xml = XML('<root><foo/><foo id="a1"/><foo id="a2"/></root>')
-        self._test_expression('*[1][@id]', None, xml, '')
-        self._test_expression('*[2][@id]', None, xml, '<foo id="a1"/>')
+        self._test_eval('*[1][@id]', input=xml, output='')
+        self._test_eval('*[2][@id]', input=xml, output='<foo id="a1"/>')
 
     def test_predicate_advanced_position(self):
         xml = XML('<root><a><b><c><d><e/></d></c></b></a></root>')
-        self._test_expression(   'descendant-or-self::*/'
+        self._test_eval(   'descendant-or-self::*/'
                                 'descendant-or-self::*/'
                                 'descendant-or-self::*[2]/'
-                                'self::*/descendant::*[3]', None, xml,
-                                '<d><e/></d>')
+                                'self::*/descendant::*[3]', input=xml,
+                                output='<d><e/></d>')
 
     def test_predicate_child_position(self):
         xml = XML('\
 <root><a><b>1</b><b>2</b><b>3</b></a><a><b>4</b><b>5</b></a></root>')
-        self._test_expression('//a/b[2]', None, xml, '<b>2</b><b>5</b>')
-        self._test_expression('//a/b[3]', None, xml, '<b>3</b>')
+        self._test_eval('//a/b[2]', input=xml, output='<b>2</b><b>5</b>')
+        self._test_eval('//a/b[3]', input=xml, output='<b>3</b>')
 
     def test_name_with_namespace(self):
         xml = XML('<root xmlns:f="FOO"><f:foo>bar</f:foo></root>')
-        self._test_expression('f:foo', '<Path "child::f:foo">', xml,
-                                '<foo xmlns="FOO">bar</foo>',
-                                namespaces = {'f': 'FOO'})
+        self._test_eval(
+            path = 'f:foo',
+            equiv = '<Path "child::f:foo">',
+            input = xml,
+            output = '<foo xmlns="FOO">bar</foo>',
+            namespaces = {'f': 'FOO'}
+        )
 
     def test_wildcard_with_namespace(self):
         xml = XML('<root xmlns:f="FOO"><f:foo>bar</f:foo></root>')
-        self._test_expression('f:*', '<Path "child::f:*">', xml,
-                                '<foo xmlns="FOO">bar</foo>',
-                                namespaces = {'f': 'FOO'})
+        self._test_eval(
+            path = 'f:*',
+            equiv = '<Path "child::f:*">',
+            input = xml,
+            output = '<foo xmlns="FOO">bar</foo>',
+            namespaces = {'f': 'FOO'}
+        )
 
     def test_predicate_termination(self):
         """
@@ -517,54 +560,58 @@
         cause an infinite loop. See <http://genshi.edgewall.org/ticket/82>.
         """
         xml = XML('<ul flag="1"><li>a</li><li>b</li></ul>')
-        self._test_expression('.[@flag="1"]/*', None, xml,
-                                '<li>a</li><li>b</li>')
+        self._test_eval('.[@flag="1"]/*', input=xml,
+                              output='<li>a</li><li>b</li>')
 
         xml = XML('<ul flag="1"><li>a</li><li>b</li></ul>')
-        self._test_expression('.[@flag="0"]/*', None, xml, '')
+        self._test_eval('.[@flag="0"]/*', input=xml, output='')
 
     def test_attrname_with_namespace(self):
         xml = XML('<root xmlns:f="FOO"><foo f:bar="baz"/></root>')
-        self._test_expression('foo[@f:bar]', None, xml,
-                                '<foo xmlns:ns1="FOO" ns1:bar="baz"/>',
-                                namespaces={'f': 'FOO'})
+        self._test_eval('foo[@f:bar]', input=xml,
+                              output='<foo xmlns:ns1="FOO" ns1:bar="baz"/>',
+                              namespaces={'f': 'FOO'})
 
     def test_attrwildcard_with_namespace(self):
         xml = XML('<root xmlns:f="FOO"><foo f:bar="baz"/></root>')
-        self._test_expression('foo[@f:*]', None, xml,
-                                '<foo xmlns:ns1="FOO" ns1:bar="baz"/>',
-                                namespaces={'f': 'FOO'})
+        self._test_eval('foo[@f:*]', input=xml,
+                              output='<foo xmlns:ns1="FOO" ns1:bar="baz"/>',
+                              namespaces={'f': 'FOO'})
+
     def test_self_and_descendant(self):
         xml = XML('<root><foo/></root>')
-        self._test_expression('self::root', None, xml, '<root><foo/></root>')
-        self._test_expression('self::foo', None, xml, '')
-        self._test_expression('descendant::root', None, xml, '')
-        self._test_expression('descendant::foo', None, xml, '<foo/>')
-        self._test_expression('descendant-or-self::root', None, xml, 
-                                '<root><foo/></root>')
-        self._test_expression('descendant-or-self::foo', None, xml, '<foo/>')
+        self._test_eval('self::root', input=xml, output='<root><foo/></root>')
+        self._test_eval('self::foo', input=xml, output='')
+        self._test_eval('descendant::root', input=xml, output='')
+        self._test_eval('descendant::foo', input=xml, output='<foo/>')
+        self._test_eval('descendant-or-self::root', input=xml, 
+                                output='<root><foo/></root>')
+        self._test_eval('descendant-or-self::foo', input=xml, output='<foo/>')
 
     def test_long_simple_paths(self):
         xml = XML('<root><a><b><a><d><a><b><a><b><a><b><a><c>!'
                     '</c></a></b></a></b></a></b></a></d></a></b></a></root>')
-        self._test_expression('//a/b/a/b/a/c', None, xml, '<c>!</c>')
-        self._test_expression('//a/b/a/c', None, xml, '<c>!</c>')
-        self._test_expression('//a/c', None, xml, '<c>!</c>')
-        self._test_expression('//c', None, xml, '<c>!</c>')
+        self._test_eval('//a/b/a/b/a/c', input=xml, output='<c>!</c>')
+        self._test_eval('//a/b/a/c', input=xml, output='<c>!</c>')
+        self._test_eval('//a/c', input=xml, output='<c>!</c>')
+        self._test_eval('//c', input=xml, output='<c>!</c>')
         # Please note that a//b is NOT the same as a/descendant::b 
         # it is a/descendant-or-self::node()/b, which SimplePathStrategy
         # does NOT support
-        self._test_expression('a/b/descendant::a/c', None, xml, '<c>!</c>')
-        self._test_expression('a/b/descendant::a/d/descendant::a/c',
-                                None, xml, '<c>!</c>')
-        self._test_expression('a/b/descendant::a/d/a/c', None, xml, '')
-        self._test_expression('//d/descendant::b/descendant::b/descendant::b'
-                                '/descendant::c', None, xml, '<c>!</c>')
-        self._test_expression('//d/descendant::b/descendant::b/descendant::b'
-                                '/descendant::b/descendant::c', None, xml, '')
+        self._test_eval('a/b/descendant::a/c', input=xml, output='<c>!</c>')
+        self._test_eval('a/b/descendant::a/d/descendant::a/c',
+                              input=xml, output='<c>!</c>')
+        self._test_eval('a/b/descendant::a/d/a/c', input=xml, output='')
+        self._test_eval('//d/descendant::b/descendant::b/descendant::b'
+                              '/descendant::c', input=xml, output='<c>!</c>')
+        self._test_eval('//d/descendant::b/descendant::b/descendant::b'
+                              '/descendant::b/descendant::c', input=xml,
+                              output='')
+
     def _test_support(self, strategy_class, text):
         path = PathParser(text, None, -1).parse()[0]
         return strategy_class.supports(path)
+
     def test_simple_strategy_support(self):
         self.assert_(self._test_support(SimplePathStrategy, 'a/b'))
         self.assert_(self._test_support(SimplePathStrategy, 'self::a/b'))
@@ -582,11 +629,46 @@
         self.assert_(not self._test_support(SimplePathStrategy, 'foo:bar'))
         self.assert_(not self._test_support(SimplePathStrategy, 'a/@foo:bar'))
 
+    def _test_strategies(self, input, path, output,
+                         namespaces=None, variables=None):
+        for strategy in self.strategies:
+            if not strategy.supports(path):
+                continue
+            s = strategy(path)
+            rendered = FakePath(s).select(input, namespaces=namespaces,
+                                          variables=variables).render()
+            msg = 'Bad render using %s strategy' % str(strategy)
+            msg += '\nExpected:\t%r' % output
+            msg += '\nRendered:\t%r' % rendered
+            self.assertEqual(output, rendered, msg)
+
+    def _test_eval(self, path, equiv=None, input=None, output='',
+                         namespaces=None, variables=None):
+        path = Path(path)
+        if equiv is not None:
+            self.assertEqual(equiv, repr(path))
+
+        if input is None:
+            return
+
+        rendered = path.select(input, namespaces=namespaces,
+                               variables=variables).render()
+        msg = 'Bad output using whole path'
+        msg += '\nExpected:\t%r' % output
+        msg += '\nRendered:\t%r' % rendered
+        self.assertEqual(output, rendered, msg)
+
+        if len(path.paths) == 1:
+            self._test_strategies(input, path.paths[0], output,
+                                  namespaces=namespaces, variables=variables)
+
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(doctest.DocTestSuite(Path.__module__))
     suite.addTest(unittest.makeSuite(PathTestCase, 'test'))
     return suite
 
+
 if __name__ == '__main__':
     unittest.main(defaultTest='suite')
Copyright (C) 2012-2017 Edgewall Software