Split and rename test_helpers module
- Unify XPathToken unit tests into class XPathTokenTest
This commit is contained in:
parent
526e9baa9f
commit
9c4b942700
|
@ -15,7 +15,7 @@ import decimal
|
|||
from .compat import PY3, string_base_type
|
||||
from .exceptions import ElementPathSyntaxError, ElementPathNameError, MissingContextError
|
||||
from .datatypes import UntypedAtomic, DayTimeDuration, YearMonthDuration, \
|
||||
NumericTypeProxy, ArithmeticTypeProxy, XSD_BUILTIN_TYPES
|
||||
NumericTypeProxy, ArithmeticTypeProxy
|
||||
from .xpath_context import XPathSchemaContext
|
||||
from .tdop_parser import Parser, MultiLabel
|
||||
from .namespaces import XML_ID, XML_LANG, XPATH_1_DEFAULT_NAMESPACES, \
|
||||
|
@ -252,19 +252,9 @@ def select(self, context=None):
|
|||
if name[0] != '{' and self.parser.default_namespace:
|
||||
name = '{%s}%s' % (self.parser.default_namespace, name)
|
||||
|
||||
for item in context.iter_children_or_self():
|
||||
xsd_type = self.match_xsd_type(item, name)
|
||||
if xsd_type is not None:
|
||||
primitive_type = self.parser.schema.get_primitive_type(xsd_type)
|
||||
try:
|
||||
value = XSD_BUILTIN_TYPES[primitive_type.local_name or 'anyType'].value
|
||||
except KeyError:
|
||||
value = XSD_BUILTIN_TYPES['anyType'].value
|
||||
|
||||
if isinstance(item, AttributeNode):
|
||||
yield TypedAttribute(item, value)
|
||||
else:
|
||||
yield TypedElement(item, value)
|
||||
for schema_item in context.iter_children_or_self():
|
||||
if self.match_xsd_type(schema_item, name) is not None:
|
||||
yield self.get_typed_node(context, schema_item)
|
||||
return
|
||||
|
||||
if name[0] != '{' and self.parser.default_namespace:
|
||||
|
@ -288,53 +278,22 @@ def select(self, context=None):
|
|||
|
||||
# Try to match the type using the path
|
||||
for item in context.iter_children_or_self():
|
||||
try:
|
||||
if is_attribute_node(item, name):
|
||||
path = context.get_path(item)
|
||||
xsd_attribute = self.parser.schema.find(path, self.parser.namespaces)
|
||||
if is_attribute_node(item, name) or is_element_node(item, tag):
|
||||
path = context.get_path(item)
|
||||
xsd_component = self.parser.schema.find(path, self.parser.namespaces)
|
||||
|
||||
if xsd_attribute is not None:
|
||||
self.xsd_type = xsd_attribute.type
|
||||
yield TypedAttribute(item, self.xsd_type.decode(item[1]))
|
||||
else:
|
||||
self.xsd_type = self.parser.schema
|
||||
yield item
|
||||
elif is_element_node(item, tag):
|
||||
path = context.get_path(item)
|
||||
xsd_element = self.parser.schema.find(path, self.parser.namespaces)
|
||||
|
||||
if xsd_element is not None:
|
||||
self.xsd_type = xsd_element.type
|
||||
if isinstance(item, TypedElement):
|
||||
yield item
|
||||
elif self.xsd_type.is_simple() or self.xsd_type.has_simple_content():
|
||||
yield TypedElement(item, self.xsd_type.decode(item.text))
|
||||
else:
|
||||
yield item
|
||||
else:
|
||||
self.xsd_type = self.parser.schema
|
||||
yield item
|
||||
|
||||
except (TypeError, ValueError):
|
||||
msg = "Type {!r} does not match sequence type of {!r}"
|
||||
self.wrong_sequence_type(msg.format(self.xsd_type, item))
|
||||
# print(path, xsd_component)
|
||||
|
||||
if xsd_component is not None:
|
||||
self.xsd_type = xsd_component.type
|
||||
else:
|
||||
self.xsd_type = self.parser.schema
|
||||
yield self.get_typed_node(context, item)
|
||||
else:
|
||||
# XSD typed selection
|
||||
for item in context.iter_children_or_self():
|
||||
try:
|
||||
if is_attribute_node(item, name):
|
||||
yield TypedAttribute(item, self.xsd_type.decode(item[1]))
|
||||
elif is_element_node(item, tag):
|
||||
if isinstance(item, TypedElement):
|
||||
yield item
|
||||
elif self.xsd_type.is_simple() or self.xsd_type.has_simple_content():
|
||||
yield TypedElement(item, self.xsd_type.decode(item.text))
|
||||
else:
|
||||
yield item
|
||||
except (TypeError, ValueError):
|
||||
msg = "Type {!r} does not match sequence type of {!r}"
|
||||
self.wrong_sequence_type(msg.format(self.xsd_type, item))
|
||||
if is_attribute_node(item, name) or is_element_node(item, tag):
|
||||
yield self.get_typed_node(context, item)
|
||||
|
||||
|
||||
###
|
||||
|
@ -411,13 +370,37 @@ def select(self, context=None):
|
|||
else:
|
||||
value = '{%s}%s' % (namespace, self[1].value)
|
||||
|
||||
if context is not None:
|
||||
if context is None:
|
||||
return
|
||||
elif isinstance(context, XPathSchemaContext):
|
||||
for schema_item in context.iter_children_or_self():
|
||||
if self.match_xsd_type(schema_item, value) is not None:
|
||||
yield self.get_typed_node(context, schema_item)
|
||||
|
||||
elif self.xsd_type is self.parser.schema:
|
||||
for item in context.iter_children_or_self():
|
||||
if is_attribute_node(item, value):
|
||||
yield item
|
||||
elif is_element_node(item, value):
|
||||
yield item
|
||||
|
||||
elif self.xsd_type is None or isinstance(self.xsd_type, AbstractSchemaProxy):
|
||||
for item in context.iter_children_or_self():
|
||||
if is_attribute_node(item, value) or is_element_node(item, value):
|
||||
path = context.get_path(item)
|
||||
xsd_component = self.parser.schema.find(path, self.parser.namespaces)
|
||||
if xsd_component is not None:
|
||||
self.xsd_type = xsd_component.type
|
||||
else:
|
||||
self.xsd_type = self.parser.schema
|
||||
yield self.get_typed_node(context, item)
|
||||
|
||||
else:
|
||||
# XSD typed selection
|
||||
for item in context.iter_children_or_self():
|
||||
if is_attribute_node(item, value) or is_element_node(item, value):
|
||||
yield self.get_typed_node(context, item)
|
||||
|
||||
|
||||
###
|
||||
# Namespace URI as in ElementPath
|
||||
|
@ -725,7 +708,7 @@ def select(self, context=None):
|
|||
yield result
|
||||
else:
|
||||
items = []
|
||||
left_results = list(self[0].select(context))
|
||||
left_results = [x for x in self[0].select(context)]
|
||||
context.size = len(left_results)
|
||||
for context.position, context.item in enumerate(left_results):
|
||||
if not is_xpath_node(context.item):
|
||||
|
@ -747,26 +730,6 @@ def select(self, context=None):
|
|||
yield result
|
||||
|
||||
|
||||
@method('/')
|
||||
def evaluate(self, context=None):
|
||||
"""
|
||||
General evaluation method for path operators, that may returns the a single value or None.
|
||||
"""
|
||||
if context is not None:
|
||||
selector = iter(self.select(context))
|
||||
try:
|
||||
value = next(selector)
|
||||
except StopIteration:
|
||||
return
|
||||
else:
|
||||
try:
|
||||
next(selector)
|
||||
except StopIteration:
|
||||
return self.data_value(value)
|
||||
else:
|
||||
self.wrong_context_type("atomized operand is a sequence of length greater than one")
|
||||
|
||||
|
||||
@method('//')
|
||||
def select(self, context=None):
|
||||
if context is None:
|
||||
|
@ -799,7 +762,7 @@ def led(self, left):
|
|||
def select(self, context=None):
|
||||
if context is not None:
|
||||
for position, item in enumerate(self[0].select(context), start=1):
|
||||
predicate = list(self[1].select(context.copy()))
|
||||
predicate = [x for x in self[1].select(context.copy())]
|
||||
if len(predicate) == 1 and isinstance(predicate[0], NumericTypeProxy):
|
||||
if position == predicate[0]:
|
||||
yield item
|
||||
|
@ -968,7 +931,7 @@ def select(self, context=None):
|
|||
def select(self, context=None):
|
||||
if context is not None:
|
||||
item = context.item
|
||||
for elem in reversed(list(context.iter_ancestors(axis=self.symbol))):
|
||||
for elem in reversed([x for x in context.iter_ancestors(axis=self.symbol)]):
|
||||
context.item = elem
|
||||
yield elem
|
||||
yield item
|
||||
|
@ -1042,7 +1005,7 @@ def evaluate(self, context=None):
|
|||
|
||||
@method(function('count', nargs=1))
|
||||
def evaluate(self, context=None):
|
||||
return len(list(self[0].select(context)))
|
||||
return len([x for x in self[0].select(context)])
|
||||
|
||||
|
||||
@method(function('id', nargs=1))
|
||||
|
|
|
@ -324,7 +324,7 @@ def evaluate(self, context=None):
|
|||
# Aggregate functions
|
||||
@method(function('avg', nargs=1))
|
||||
def evaluate(self, context=None):
|
||||
result = list(self[0].select(context))
|
||||
result = [x for x in self[0].select(context)]
|
||||
if not result:
|
||||
return result
|
||||
elif isinstance(result[0], Duration):
|
||||
|
@ -436,7 +436,7 @@ def select(self, context=None):
|
|||
|
||||
@method(function('reverse', nargs=1))
|
||||
def select(self, context=None):
|
||||
for result in reversed(list(self[0].select(context))):
|
||||
for result in reversed([x for x in self[0].select(context)]):
|
||||
yield result
|
||||
|
||||
|
||||
|
@ -451,7 +451,7 @@ def select(self, context=None):
|
|||
|
||||
@method(function('unordered', nargs=1))
|
||||
def select(self, context=None):
|
||||
for result in sorted(list(self[0].select(context)), key=lambda x: self.string_value(x)):
|
||||
for result in sorted([x for x in self[0].select(context)], key=lambda x: self.string_value(x)):
|
||||
yield result
|
||||
|
||||
|
||||
|
|
|
@ -425,7 +425,7 @@ def evaluate(self, context=None):
|
|||
|
||||
@method('if')
|
||||
def select(self, context=None):
|
||||
if self.boolean_value(list(self[0].select(context))):
|
||||
if self.boolean_value([x for x in self[0].select(context)]):
|
||||
for result in self[1].select(context):
|
||||
yield result
|
||||
else:
|
||||
|
@ -745,13 +745,13 @@ def evaluate(self, context=None):
|
|||
def evaluate(self, context=None):
|
||||
symbol = self.symbol
|
||||
|
||||
left = list(self[0].select(context))
|
||||
left = [x for x in self[0].select(context)]
|
||||
if not left:
|
||||
return
|
||||
elif len(left) > 1 or not is_xpath_node(left[0]):
|
||||
self[0].wrong_type("left operand of %r must be a single node" % symbol)
|
||||
|
||||
right = list(self[1].select(context))
|
||||
right = [x for x in self[1].select(context)]
|
||||
if not right:
|
||||
return
|
||||
elif len(right) > 1 or not is_xpath_node(right[0]):
|
||||
|
@ -783,7 +783,7 @@ def evaluate(self, context=None):
|
|||
self.wrong_type(str(err))
|
||||
return
|
||||
else:
|
||||
return list(range(start, stop))
|
||||
return [x for x in range(start, stop)]
|
||||
|
||||
|
||||
@method('to')
|
||||
|
|
|
@ -103,15 +103,13 @@ class XPathContext(object):
|
|||
except KeyError:
|
||||
return
|
||||
|
||||
@lru_cache(maxsize=1024)
|
||||
def get_path(self, item):
|
||||
"""Cached path resolver for elements and attributes. Returns absolute paths."""
|
||||
path = []
|
||||
|
||||
if isinstance(item, (AttributeNode, TypedAttribute)):
|
||||
path.append('@%s' % item[0])
|
||||
item = self._elem
|
||||
elif isinstance(item, TypedElement):
|
||||
if isinstance(item, TypedElement):
|
||||
item = item[0]
|
||||
|
||||
while True:
|
||||
|
|
|
@ -27,12 +27,14 @@ from decimal import Decimal
|
|||
from .compat import string_base_type, unicode_type
|
||||
from .exceptions import xpath_error
|
||||
from .namespaces import XQT_ERRORS_NAMESPACE
|
||||
from .xpath_nodes import AttributeNode, NamespaceNode, TypedElement, is_etree_element, \
|
||||
is_attribute_node, elem_iter_strings, is_text_node, is_namespace_node, \
|
||||
is_comment_node, is_processing_instruction_node, is_element_node, \
|
||||
is_document_node, is_xpath_node, is_schema_node
|
||||
from .xpath_nodes import AttributeNode, NamespaceNode, TypedAttribute, TypedElement, \
|
||||
is_etree_element, is_attribute_node, elem_iter_strings, is_text_node, \
|
||||
is_namespace_node, is_comment_node, is_processing_instruction_node, \
|
||||
is_element_node, is_document_node, is_xpath_node, is_schema_node
|
||||
from .datatypes import UntypedAtomic, Timezone, DayTimeDuration, XSD_BUILTIN_TYPES
|
||||
from .schema_proxy import AbstractSchemaProxy
|
||||
from .tdop_parser import Token
|
||||
from .xpath_context import XPathSchemaContext
|
||||
|
||||
|
||||
def ordinal(n):
|
||||
|
@ -61,7 +63,7 @@ class XPathToken(Token):
|
|||
|
||||
:param context: The XPath dynamic context.
|
||||
"""
|
||||
return list(self.select(context))
|
||||
return [x for x in self.select(context)]
|
||||
|
||||
def select(self, context=None):
|
||||
"""
|
||||
|
@ -207,7 +209,7 @@ class XPathToken(Token):
|
|||
for item in self.select(context):
|
||||
value = self.data_value(item)
|
||||
if value is None:
|
||||
raise self.error('FOTY0012', "argument node does not have a typed value: {}".format(item))
|
||||
raise self.error('FOTY0012', "argument node {!r} does not have a typed value".format(item))
|
||||
else:
|
||||
yield value
|
||||
|
||||
|
@ -229,6 +231,8 @@ class XPathToken(Token):
|
|||
except StopIteration:
|
||||
if isinstance(value, UntypedAtomic):
|
||||
value = str(value)
|
||||
if isinstance(context, XPathSchemaContext):
|
||||
return value
|
||||
if self.xsd_type is not None and isinstance(value, string_base_type):
|
||||
try:
|
||||
value = self.xsd_type.decode(value)
|
||||
|
@ -250,10 +254,11 @@ class XPathToken(Token):
|
|||
:returns: a list of data couples.
|
||||
"""
|
||||
if context is None:
|
||||
operand1, operand2 = list(self[0].select()), list(self[1].select())
|
||||
operand1 = [x for x in self[0].select()]
|
||||
operand2 = [x for x in self[1].select()]
|
||||
else:
|
||||
operand1 = list(self[0].select(context.copy()))
|
||||
operand2 = list(self[1].select(context.copy()))
|
||||
operand1 = [x for x in self[0].select(context.copy())]
|
||||
operand2 = [x for x in self[1].select(context.copy())]
|
||||
|
||||
if self.parser.compatibility_mode:
|
||||
# Boolean comparison if one of the results is a single boolean value (1.)
|
||||
|
@ -284,11 +289,9 @@ class XPathToken(Token):
|
|||
:param context: the XPath dynamic context.
|
||||
"""
|
||||
for result in self.select(context):
|
||||
if not isinstance(result, tuple):
|
||||
yield result # not a namedtuple-wrapped result
|
||||
elif hasattr(result[0], 'type'):
|
||||
yield result[0] # an XSD schema attribute/element
|
||||
elif not isinstance(result, NamespaceNode):
|
||||
if isinstance(result, TypedElement):
|
||||
yield result[0]
|
||||
elif isinstance(result, (AttributeNode, TypedAttribute)):
|
||||
yield result[1]
|
||||
else:
|
||||
yield result
|
||||
|
@ -419,6 +422,39 @@ class XPathToken(Token):
|
|||
self.wrong_context_type("Multiple XSD type matching during static analysis")
|
||||
return xsd_type
|
||||
|
||||
def get_typed_node(self, context, item):
|
||||
"""
|
||||
Returns a typed node if the token is bound to an XSD type.
|
||||
|
||||
:param context: the XPath dynamic context.
|
||||
:param item: an untyped XPath attribute ot element.
|
||||
"""
|
||||
if isinstance(self.xsd_type, (type(None), AbstractSchemaProxy)):
|
||||
return item
|
||||
|
||||
if isinstance(context, XPathSchemaContext):
|
||||
primitive_type = self.parser.schema.get_primitive_type(self.xsd_type)
|
||||
try:
|
||||
value = XSD_BUILTIN_TYPES[primitive_type.local_name or 'anyType'].value
|
||||
except KeyError:
|
||||
value = XSD_BUILTIN_TYPES['anyType'].value
|
||||
|
||||
if isinstance(item, AttributeNode):
|
||||
return TypedAttribute(item, value)
|
||||
else:
|
||||
return TypedElement(item, value)
|
||||
else:
|
||||
try:
|
||||
if isinstance(item, AttributeNode):
|
||||
return TypedAttribute(item, self.xsd_type.decode(item[1]))
|
||||
elif self.xsd_type.is_simple() or self.xsd_type.has_simple_content():
|
||||
return TypedElement(item, self.xsd_type.decode(item.text))
|
||||
else:
|
||||
return item
|
||||
except (TypeError, ValueError):
|
||||
msg = "Type {!r} does not match sequence type of {!r}"
|
||||
self.wrong_sequence_type(msg.format(self.xsd_type, item))
|
||||
|
||||
@contextlib.contextmanager
|
||||
def use_locale(self, collation):
|
||||
"""A context manager for setting a specific collation for a code block."""
|
||||
|
|
|
@ -24,8 +24,11 @@ import unittest
|
|||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
from tests.test_helpers import ExceptionHelpersTest, NamespaceHelpersTest, NodeHelpersTest
|
||||
from tests.test_exceptions import ExceptionsTest
|
||||
from tests.test_namespaces import NamespacesTest
|
||||
from tests.test_datatypes import UntypedAtomicTest, DateTimeTypesTest, DurationTypesTest, TimezoneTypeTest
|
||||
from tests.test_xpath_nodes import XPathNodesTest
|
||||
from tests.test_xpath_token import XPathTokenTest
|
||||
from tests.test_xpath_context import XPathContextTest
|
||||
from tests.test_xpath1_parser import XPath1ParserTest, LxmlXPath1ParserTest
|
||||
from tests.test_xpath2_parser import XPath2ParserTest, LxmlXPath2ParserTest
|
||||
|
@ -34,8 +37,11 @@ if __name__ == '__main__':
|
|||
from tests.test_package import PackageTest
|
||||
except ImportError:
|
||||
# Python 2 fallback
|
||||
from test_helpers import ExceptionHelpersTest, NamespaceHelpersTest, NodeHelpersTest
|
||||
from test_exceptions import ExceptionsTest
|
||||
from test_namespaces import NamespacessTest
|
||||
from test_datatypes import UntypedAtomicTest, DateTimeTypesTest, DurationTypesTest, TimezoneTypeTest
|
||||
from test_xpath_nodes import XPathNodesTest
|
||||
from test_xpath_token import XPathTokenTest
|
||||
from test_xpath_context import XPathContextTest
|
||||
from test_xpath1_parser import XPath1ParserTest, LxmlXPath1ParserTest
|
||||
from test_xpath2_parser import XPath2ParserTest, LxmlXPath2ParserTest
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c), 2018-2019, SISSA (International School for Advanced Studies).
|
||||
# All rights reserved.
|
||||
# This file is distributed under the terms of the MIT License.
|
||||
# See the file 'LICENSE' in the root directory of the present
|
||||
# distribution, or http://opensource.org/licenses/MIT.
|
||||
#
|
||||
# @author Davide Brunato <brunato@sissa.it>
|
||||
#
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
from elementpath.exceptions import ElementPathError, xpath_error
|
||||
from elementpath.namespaces import XSD_NAMESPACE
|
||||
from elementpath.xpath1_parser import XPath1Parser
|
||||
|
||||
|
||||
class ExceptionsTest(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.parser = XPath1Parser(namespaces={'xs': XSD_NAMESPACE, 'tst': "http://xpath.test/ns"})
|
||||
|
||||
def test_exception_repr(self):
|
||||
err = ElementPathError("unknown error")
|
||||
self.assertEqual(str(err), 'unknown error')
|
||||
err = ElementPathError("unknown error", code='XPST0001')
|
||||
self.assertEqual(str(err), '[XPST0001] unknown error.')
|
||||
token = self.parser.symbol_table['true'](self.parser)
|
||||
err = ElementPathError("unknown error", code='XPST0001', token=token)
|
||||
self.assertEqual(str(err), "'true' function: [XPST0001] unknown error.")
|
||||
|
||||
def test_xpath_error(self):
|
||||
self.assertEqual(str(xpath_error('XPST0001')), '[err:XPST0001] Parser not bound to a schema.')
|
||||
self.assertEqual(str(xpath_error('err:XPDY0002', "test message")), '[err:XPDY0002] test message.')
|
||||
self.assertRaises(ValueError, xpath_error, '')
|
||||
self.assertRaises(ValueError, xpath_error, 'error:XPDY0002')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -0,0 +1,53 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c), 2018-2019, SISSA (International School for Advanced Studies).
|
||||
# All rights reserved.
|
||||
# This file is distributed under the terms of the MIT License.
|
||||
# See the file 'LICENSE' in the root directory of the present
|
||||
# distribution, or http://opensource.org/licenses/MIT.
|
||||
#
|
||||
# @author Davide Brunato <brunato@sissa.it>
|
||||
#
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
from elementpath.namespaces import XSD_NAMESPACE, get_namespace, qname_to_prefixed, \
|
||||
prefixed_to_qname
|
||||
|
||||
|
||||
class NamespacesTest(unittest.TestCase):
|
||||
namespaces = {
|
||||
'xs': XSD_NAMESPACE,
|
||||
'tst': "http://xpath.test/ns"
|
||||
}
|
||||
|
||||
# namespaces.py module
|
||||
def test_get_namespace_function(self):
|
||||
self.assertEqual(get_namespace('A'), '')
|
||||
self.assertEqual(get_namespace('{ns}foo'), 'ns')
|
||||
self.assertEqual(get_namespace('{}foo'), '')
|
||||
self.assertEqual(get_namespace('{A}B{C}'), 'A')
|
||||
|
||||
def test_qname_to_prefixed_function(self):
|
||||
self.assertEqual(qname_to_prefixed('{ns}foo', {'bar': 'ns'}), 'bar:foo')
|
||||
self.assertEqual(qname_to_prefixed('{ns}foo', {'': 'ns'}), 'foo')
|
||||
self.assertEqual(qname_to_prefixed('foo', {'': 'ns'}), 'foo')
|
||||
|
||||
def test_prefixed_to_qname_function(self):
|
||||
self.assertEqual(prefixed_to_qname('{ns}foo', {'bar': 'ns'}), '{ns}foo')
|
||||
self.assertEqual(prefixed_to_qname('bar:foo', {'bar': 'ns'}), '{ns}foo')
|
||||
self.assertEqual(prefixed_to_qname('foo', {'': 'ns'}), '{ns}foo')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
prefixed_to_qname('bar:foo', self.namespaces)
|
||||
with self.assertRaises(ValueError):
|
||||
prefixed_to_qname('bar:foo:bar', {'bar': 'ns'})
|
||||
with self.assertRaises(ValueError):
|
||||
prefixed_to_qname(':foo', {'': 'ns'})
|
||||
with self.assertRaises(ValueError):
|
||||
prefixed_to_qname('foo:', {'': 'ns'})
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -211,52 +211,6 @@ class XPath1ParserTest(unittest.TestCase):
|
|||
else:
|
||||
self.assertTrue(expected(results))
|
||||
|
||||
def test_boolean_value_function(self):
|
||||
token = self.parser.parse('true()')
|
||||
elem = ElementTree.Element('A')
|
||||
with self.assertRaises(TypeError):
|
||||
token.boolean_value(elem)
|
||||
|
||||
self.assertFalse(token.boolean_value([]))
|
||||
self.assertTrue(token.boolean_value([elem]))
|
||||
self.assertFalse(token.boolean_value([0]))
|
||||
self.assertTrue(token.boolean_value([1]))
|
||||
with self.assertRaises(TypeError):
|
||||
token.boolean_value([1, 1])
|
||||
with self.assertRaises(TypeError):
|
||||
token.boolean_value(elem)
|
||||
self.assertFalse(token.boolean_value(0))
|
||||
self.assertTrue(token.boolean_value(1))
|
||||
|
||||
def test_data_value_function(self):
|
||||
token = self.parser.parse('true()')
|
||||
self.assertIsNone(token.data_value(None))
|
||||
|
||||
def test_string_value_function(self):
|
||||
token = self.parser.parse('true()')
|
||||
|
||||
document = ElementTree.parse(io.StringIO(u'<A>123<B1>456</B1><B2>789</B2></A>'))
|
||||
element = ElementTree.Element('schema')
|
||||
attribute = AttributeNode('id', '0212349350')
|
||||
namespace = NamespaceNode('xs', 'http://www.w3.org/2001/XMLSchema')
|
||||
comment = ElementTree.Comment('nothing important')
|
||||
pi = ElementTree.ProcessingInstruction('action', 'nothing to do')
|
||||
text = u'betelgeuse'
|
||||
self.assertEqual(token.string_value(document), '123456789')
|
||||
self.assertEqual(token.string_value(element), '')
|
||||
self.assertEqual(token.string_value(attribute), '0212349350')
|
||||
self.assertEqual(token.string_value(namespace), 'http://www.w3.org/2001/XMLSchema')
|
||||
self.assertEqual(token.string_value(comment), 'nothing important')
|
||||
self.assertEqual(token.string_value(pi), 'action nothing to do')
|
||||
self.assertEqual(token.string_value(text), 'betelgeuse')
|
||||
self.assertEqual(token.string_value(None), '')
|
||||
self.assertEqual(token.string_value(10), '10')
|
||||
|
||||
def test_number_value_function(self):
|
||||
token = self.parser.parse('true()')
|
||||
self.assertEqual(token.number_value("19"), 19)
|
||||
self.assertTrue(math.isnan(token.number_value("not a number")))
|
||||
|
||||
# Wrong XPath expression checker shortcuts
|
||||
def wrong_syntax(self, path):
|
||||
self.assertRaises(SyntaxError, self.parser.parse, path)
|
||||
|
|
|
@ -14,74 +14,14 @@ import unittest
|
|||
import io
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
|
||||
from elementpath.exceptions import ElementPathError, xpath_error
|
||||
from elementpath.namespaces import XSD_NAMESPACE, get_namespace, qname_to_prefixed, \
|
||||
prefixed_to_qname
|
||||
from elementpath.xpath_nodes import AttributeNode, NamespaceNode, is_etree_element, \
|
||||
is_element_node, is_attribute_node, is_comment_node, is_document_node, \
|
||||
is_namespace_node, is_processing_instruction_node, is_text_node, node_attributes, \
|
||||
node_base_uri, node_document_uri, node_children, node_is_id, node_is_idrefs, \
|
||||
node_nilled, node_kind, node_name
|
||||
from elementpath.xpath_token import ordinal
|
||||
from elementpath.xpath1_parser import XPath1Parser
|
||||
|
||||
|
||||
class ExceptionHelpersTest(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.parser = XPath1Parser(namespaces={'xs': XSD_NAMESPACE, 'tst': "http://xpath.test/ns"})
|
||||
|
||||
def test_exception_repr(self):
|
||||
err = ElementPathError("unknown error")
|
||||
self.assertEqual(str(err), 'unknown error')
|
||||
err = ElementPathError("unknown error", code='XPST0001')
|
||||
self.assertEqual(str(err), '[XPST0001] unknown error.')
|
||||
token = self.parser.symbol_table['true'](self.parser)
|
||||
err = ElementPathError("unknown error", code='XPST0001', token=token)
|
||||
self.assertEqual(str(err), "'true' function: [XPST0001] unknown error.")
|
||||
|
||||
def test_xpath_error(self):
|
||||
self.assertEqual(str(xpath_error('XPST0001')), '[err:XPST0001] Parser not bound to a schema.')
|
||||
self.assertEqual(str(xpath_error('err:XPDY0002', "test message")), '[err:XPDY0002] test message.')
|
||||
self.assertRaises(ValueError, xpath_error, '')
|
||||
self.assertRaises(ValueError, xpath_error, 'error:XPDY0002')
|
||||
|
||||
|
||||
class NamespaceHelpersTest(unittest.TestCase):
|
||||
namespaces = {
|
||||
'xs': XSD_NAMESPACE,
|
||||
'tst': "http://xpath.test/ns"
|
||||
}
|
||||
|
||||
# namespaces.py module
|
||||
def test_get_namespace_function(self):
|
||||
self.assertEqual(get_namespace('A'), '')
|
||||
self.assertEqual(get_namespace('{ns}foo'), 'ns')
|
||||
self.assertEqual(get_namespace('{}foo'), '')
|
||||
self.assertEqual(get_namespace('{A}B{C}'), 'A')
|
||||
|
||||
def test_qname_to_prefixed_function(self):
|
||||
self.assertEqual(qname_to_prefixed('{ns}foo', {'bar': 'ns'}), 'bar:foo')
|
||||
self.assertEqual(qname_to_prefixed('{ns}foo', {'': 'ns'}), 'foo')
|
||||
self.assertEqual(qname_to_prefixed('foo', {'': 'ns'}), 'foo')
|
||||
|
||||
def test_prefixed_to_qname_function(self):
|
||||
self.assertEqual(prefixed_to_qname('{ns}foo', {'bar': 'ns'}), '{ns}foo')
|
||||
self.assertEqual(prefixed_to_qname('bar:foo', {'bar': 'ns'}), '{ns}foo')
|
||||
self.assertEqual(prefixed_to_qname('foo', {'': 'ns'}), '{ns}foo')
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
prefixed_to_qname('bar:foo', self.namespaces)
|
||||
with self.assertRaises(ValueError):
|
||||
prefixed_to_qname('bar:foo:bar', {'bar': 'ns'})
|
||||
with self.assertRaises(ValueError):
|
||||
prefixed_to_qname(':foo', {'': 'ns'})
|
||||
with self.assertRaises(ValueError):
|
||||
prefixed_to_qname('foo:', {'': 'ns'})
|
||||
|
||||
|
||||
class NodeHelpersTest(unittest.TestCase):
|
||||
class XPathNodesTest(unittest.TestCase):
|
||||
elem = ElementTree.XML('<node a1="10"/>')
|
||||
|
||||
def test_is_etree_element_function(self):
|
||||
|
@ -231,28 +171,5 @@ class NodeHelpersTest(unittest.TestCase):
|
|||
self.assertEqual(node_name(namespace), 'xs')
|
||||
|
||||
|
||||
class XPathTokenHelpersTest(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.parser = XPath1Parser(namespaces={'xs': XSD_NAMESPACE, 'tst': "http://xpath.test/ns"})
|
||||
|
||||
def test_ordinal_function(self):
|
||||
self.assertEqual(ordinal(1), '1st')
|
||||
self.assertEqual(ordinal(2), '2nd')
|
||||
self.assertEqual(ordinal(3), '3rd')
|
||||
self.assertEqual(ordinal(4), '4th')
|
||||
self.assertEqual(ordinal(11), '11th')
|
||||
self.assertEqual(ordinal(23), '23rd')
|
||||
self.assertEqual(ordinal(34), '34th')
|
||||
|
||||
def test_get_argument_method(self):
|
||||
token = self.parser.symbol_table['true'](self.parser)
|
||||
|
||||
self.assertIsNone(token.get_argument(2))
|
||||
with self.assertRaises(TypeError):
|
||||
token.get_argument(1, required=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (c), 2018-2019, SISSA (International School for Advanced Studies).
|
||||
# All rights reserved.
|
||||
# This file is distributed under the terms of the MIT License.
|
||||
# See the file 'LICENSE' in the root directory of the present
|
||||
# distribution, or http://opensource.org/licenses/MIT.
|
||||
#
|
||||
# @author Davide Brunato <brunato@sissa.it>
|
||||
#
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
import io
|
||||
import math
|
||||
import xml.etree.ElementTree as ElementTree
|
||||
|
||||
from elementpath.namespaces import XSD_NAMESPACE
|
||||
from elementpath.xpath_nodes import AttributeNode, TypedAttribute, TypedElement, NamespaceNode
|
||||
from elementpath.xpath_token import ordinal
|
||||
from elementpath.xpath_context import XPathContext
|
||||
from elementpath.xpath1_parser import XPath1Parser
|
||||
|
||||
|
||||
class XPathTokenTest(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.parser = XPath1Parser(namespaces={'xs': XSD_NAMESPACE, 'tst': "http://xpath.test/ns"})
|
||||
|
||||
def test_ordinal_function(self):
|
||||
self.assertEqual(ordinal(1), '1st')
|
||||
self.assertEqual(ordinal(2), '2nd')
|
||||
self.assertEqual(ordinal(3), '3rd')
|
||||
self.assertEqual(ordinal(4), '4th')
|
||||
self.assertEqual(ordinal(11), '11th')
|
||||
self.assertEqual(ordinal(23), '23rd')
|
||||
self.assertEqual(ordinal(34), '34th')
|
||||
|
||||
def test_get_argument_method(self):
|
||||
token = self.parser.symbol_table['true'](self.parser)
|
||||
|
||||
self.assertIsNone(token.get_argument(2))
|
||||
with self.assertRaises(TypeError):
|
||||
token.get_argument(1, required=True)
|
||||
|
||||
def test_select_results(self):
|
||||
token = self.parser.parse('.')
|
||||
elem = ElementTree.Element('A', attrib={'max': '30'})
|
||||
elem.text = '10'
|
||||
|
||||
context = XPathContext(elem)
|
||||
self.assertListEqual(list(token.select_results(context)), [elem])
|
||||
|
||||
context = XPathContext(elem, item=TypedElement(elem, 10))
|
||||
self.assertListEqual(list(token.select_results(context)), [elem])
|
||||
|
||||
context = XPathContext(elem, item=AttributeNode('max', '30'))
|
||||
self.assertListEqual(list(token.select_results(context)), ['30'])
|
||||
|
||||
context = XPathContext(elem, item=TypedAttribute(AttributeNode('max', '30'), 30))
|
||||
self.assertListEqual(list(token.select_results(context)), [30])
|
||||
|
||||
context = XPathContext(elem, item=10)
|
||||
self.assertListEqual(list(token.select_results(context)), [10])
|
||||
|
||||
context = XPathContext(elem, item='10')
|
||||
self.assertListEqual(list(token.select_results(context)), ['10'])
|
||||
|
||||
def test_boolean_value_function(self):
|
||||
token = self.parser.parse('true()')
|
||||
elem = ElementTree.Element('A')
|
||||
with self.assertRaises(TypeError):
|
||||
token.boolean_value(elem)
|
||||
|
||||
self.assertFalse(token.boolean_value([]))
|
||||
self.assertTrue(token.boolean_value([elem]))
|
||||
self.assertFalse(token.boolean_value([0]))
|
||||
self.assertTrue(token.boolean_value([1]))
|
||||
with self.assertRaises(TypeError):
|
||||
token.boolean_value([1, 1])
|
||||
with self.assertRaises(TypeError):
|
||||
token.boolean_value(elem)
|
||||
self.assertFalse(token.boolean_value(0))
|
||||
self.assertTrue(token.boolean_value(1))
|
||||
|
||||
def test_data_value_function(self):
|
||||
token = self.parser.parse('true()')
|
||||
self.assertIsNone(token.data_value(None))
|
||||
|
||||
def test_string_value_function(self):
|
||||
token = self.parser.parse('true()')
|
||||
|
||||
document = ElementTree.parse(io.StringIO(u'<A>123<B1>456</B1><B2>789</B2></A>'))
|
||||
element = ElementTree.Element('schema')
|
||||
attribute = AttributeNode('id', '0212349350')
|
||||
namespace = NamespaceNode('xs', 'http://www.w3.org/2001/XMLSchema')
|
||||
comment = ElementTree.Comment('nothing important')
|
||||
pi = ElementTree.ProcessingInstruction('action', 'nothing to do')
|
||||
text = u'betelgeuse'
|
||||
self.assertEqual(token.string_value(document), '123456789')
|
||||
self.assertEqual(token.string_value(element), '')
|
||||
self.assertEqual(token.string_value(attribute), '0212349350')
|
||||
self.assertEqual(token.string_value(namespace), 'http://www.w3.org/2001/XMLSchema')
|
||||
self.assertEqual(token.string_value(comment), 'nothing important')
|
||||
self.assertEqual(token.string_value(pi), 'action nothing to do')
|
||||
self.assertEqual(token.string_value(text), 'betelgeuse')
|
||||
self.assertEqual(token.string_value(None), '')
|
||||
self.assertEqual(token.string_value(10), '10')
|
||||
|
||||
def test_number_value_function(self):
|
||||
token = self.parser.parse('true()')
|
||||
self.assertEqual(token.number_value("19"), 19)
|
||||
self.assertTrue(math.isnan(token.number_value("not a number")))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
Loading…
Reference in New Issue