Skip to content

Commit

Permalink
Add test module for schema context and fix Float10 hash
Browse files Browse the repository at this point in the history
  • Loading branch information
brunato committed Jan 20, 2021
1 parent 6b7d678 commit bbb4eed
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 3 deletions.
3 changes: 3 additions & 0 deletions elementpath/datatypes/numeric.py
Expand Up @@ -33,6 +33,9 @@ def __new__(cls, value):
return super().__new__(cls, 0.0)
return value

def __hash__(self):
return super(Float10, self).__hash__()

def __eq__(self, other):
if isinstance(other, self.__class__):
if super(Float10, self).__eq__(other):
Expand Down
3 changes: 1 addition & 2 deletions elementpath/xpath1/xpath1_parser.py
Expand Up @@ -609,8 +609,7 @@ def nud(self):
def evaluate(self, context=None):
if self[1].label.endswith('function'):
return self[1].evaluate(context)
else:
return '{%s}%s' % (self[0].value, self[1].value)
return [x for x in self.select(context)]


@method('{')
Expand Down
10 changes: 10 additions & 0 deletions tests/test_datatypes.py
Expand Up @@ -107,6 +107,9 @@ def test_init(self):
with self.assertRaises(ValueError):
Float10('inf')

def test_hash(self):
self.assertEqual(hash(Float10(892.1)), hash(892.1))

def test_equivalence(self):
self.assertEqual(Float10('10.1'), Float10('10.1'))
self.assertEqual(Float10('10.1'), Float('10.1'))
Expand Down Expand Up @@ -1268,7 +1271,14 @@ def test_hash_value(self):
self.assertEqual(hash(HexBinary(b'F859')), hash(b'F859'))

def test_equality(self):
self.assertEqual(HexBinary(b'8A7F'), HexBinary(b'8A7F'))
self.assertEqual(HexBinary(b'8a7f'), HexBinary(b'8a7f'))
self.assertEqual(HexBinary(b'8a7f'), HexBinary(b'8A7F'))
self.assertEqual(HexBinary(b'8A7F'), HexBinary(b'8a7f'))

self.assertEqual(Base64Binary(b'YWxwaGE='), Base64Binary(b'YWxwaGE='))
self.assertNotEqual(Base64Binary(b'YWxwaGE='), Base64Binary(b'ywxwaGE='))

self.assertNotEqual(HexBinary(b'F859'), Base64Binary(b'YWxwaGE='))
self.assertNotEqual(HexBinary(b'F859'), UntypedAtomic(HexBinary(b'F859')))

Expand Down
158 changes: 158 additions & 0 deletions tests/test_schema_context.py
@@ -0,0 +1,158 @@
#!/usr/bin/env python
#
# Copyright (c), 2021, 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>
#
import unittest
from textwrap import dedent

from elementpath import TypedElement, XPath2Parser
from elementpath.datatypes import UntypedAtomic

try:
# noinspection PyPackageRequirements
import xmlschema
from xmlschema.xpath import XMLSchemaContext
except (ImportError, AttributeError):
xmlschema = None


@unittest.skipIf(xmlschema is None, "xmlschema library required.")
class XMLSchemaProxyTest(unittest.TestCase):

@classmethod
def setUpClass(cls):
cls.schema1 = xmlschema.XMLSchema(dedent('''
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://xpath.test/ns" targetNamespace="http://xpath.test/ns">
<xs:element name="a">
<xs:complexType>
<xs:sequence>
<xs:element name="b1" type="xs:string" />
<xs:element name="b2" type="xs:int" />
<xs:element ref="b3"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="b3" type="xs:float"/>
</xs:schema>'''))

def test_name_token(self):
parser = XPath2Parser(default_namespace="http://xpath.test/ns")
context = XMLSchemaContext(self.schema1)

elem_a = self.schema1.elements['a']
token = parser.parse('a')
self.assertIsNone(token.xsd_types)

result = token.evaluate(context.copy())
self.assertEqual(token.xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
self.assertListEqual(result, [TypedElement(elem_a, elem_a.type, UntypedAtomic('1'))])

elem_b1 = elem_a.type.content[0]
token = parser.parse('a/b1')
self.assertIsNone(token[0].xsd_types)
self.assertIsNone(token[1].xsd_types)

result = token.evaluate(context.copy())
self.assertEqual(token[0].xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
self.assertEqual(token[1].xsd_types, {"b1": elem_b1.type})
self.assertListEqual(result, [TypedElement(elem_b1, elem_b1.type, ' alpha\t')])

def test_colon_token(self):
parser = XPath2Parser(namespaces={'tst': "http://xpath.test/ns"})
context = XMLSchemaContext(self.schema1)

elem_a = self.schema1.elements['a']
token = parser.parse('tst:a')
self.assertEqual(token.symbol, ':')
self.assertIsNone(token.xsd_types)

result = token.evaluate(context.copy())
self.assertEqual(token.xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
self.assertListEqual(result, [TypedElement(elem_a, elem_a.type, UntypedAtomic('1'))])

elem_b1 = elem_a.type.content[0]
token = parser.parse('tst:a/b1')
self.assertEqual(token.symbol, '/')
self.assertEqual(token[0].symbol, ':')
self.assertIsNone(token[0].xsd_types)
self.assertIsNone(token[1].xsd_types)

result = token.evaluate(context.copy())
self.assertListEqual(result, [TypedElement(elem_b1, elem_b1.type, ' alpha\t')])
self.assertEqual(token[0].xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
self.assertEqual(token[1].xsd_types, {"b1": elem_b1.type})

token = parser.parse('tst:a/tst:b1')
result = token.evaluate(context.copy())
self.assertListEqual(result, [])
self.assertEqual(token[0].xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
self.assertIsNone(token[1].xsd_types)

elem_b3 = elem_a.type.content[2]
token = parser.parse('tst:a/tst:b3')
self.assertEqual(token.symbol, '/')
self.assertEqual(token[0].symbol, ':')
self.assertIsNone(token[0].xsd_types)
self.assertIsNone(token[1].xsd_types)

result = token.evaluate(context.copy())
self.assertListEqual(result, [TypedElement(elem_b3, elem_b3.type, 1.0)])
self.assertEqual(token[0].xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
self.assertEqual(token[1].xsd_types, {"{http://xpath.test/ns}b3": elem_b3.type})

def test_extended_name_token(self):
parser = XPath2Parser(strict=False)
context = XMLSchemaContext(self.schema1)

elem_a = self.schema1.elements['a']
token = parser.parse('{http://xpath.test/ns}a')
self.assertEqual(token.symbol, '{')
self.assertIsNone(token.xsd_types)
self.assertEqual(token[0].symbol, '(string)')
self.assertEqual(token[1].symbol, '(name)')
self.assertEqual(token[1].value, 'a')

result = token.evaluate(context)
self.assertListEqual(result, [TypedElement(elem_a, elem_a.type, UntypedAtomic('1'))])
self.assertEqual(token.xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
self.assertIsNone(token[0].xsd_types)
self.assertIsNone(token[1].xsd_types)

def test_wildcard_token(self):
parser = XPath2Parser(default_namespace="http://xpath.test/ns")
context = XMLSchemaContext(self.schema1)

elem_a = self.schema1.elements['a']
elem_b3 = self.schema1.elements['b3']
token = parser.parse('*')
self.assertEqual(token.symbol, '*')
self.assertIsNone(token.xsd_types)

result = token.evaluate(context)
self.assertListEqual(result, [elem_a, elem_b3])
self.assertEqual(token.xsd_types, {"{http://xpath.test/ns}a": elem_a.type,
"{http://xpath.test/ns}b3": elem_b3.type})

token = parser.parse('a/*')
self.assertEqual(token.symbol, '/')
self.assertEqual(token[0].symbol, '(name)')
self.assertEqual(token[1].symbol, '*')

result = token.evaluate(context)
self.assertListEqual(result, elem_a.type.content[:])
self.assertIsNone(token.xsd_types)
self.assertEqual(token[0].xsd_types, {"{http://xpath.test/ns}a": elem_a.type})
self.assertEqual(token[1].xsd_types, {'b1': elem_a.type.content[0].type,
'b2': elem_a.type.content[1].type,
'{http://xpath.test/ns}b3': elem_b3.type})


if __name__ == '__main__':
unittest.main()
3 changes: 2 additions & 1 deletion tests/test_xpath1_parser.py
Expand Up @@ -383,8 +383,9 @@ def test_qname_uri_references(self):
self.check_value("{%s}true()" % XPATH_FUNCTIONS_NAMESPACE, True)
self.check_value("string({%s}true())" % XPATH_FUNCTIONS_NAMESPACE, 'true')

context = XPathContext(root)
name = '{%s}alpha' % XPATH_FUNCTIONS_NAMESPACE
self.check_value(name, name) # it's not an error to use 'fn' namespace for a name
self.check_value(name, [], context) # it's not an error to use 'fn' namespace for a name

self.parser.strict = True
self.wrong_syntax('{%s}string' % XSD_NAMESPACE)
Expand Down

0 comments on commit bbb4eed

Please sign in to comment.