Code refactoring for tests

- Rename XMLSchemaTestCase to XsdValidatorTestCase
  - Add casepath() helper
  - Modify TestResources: derive from TestCase and use casepath()
  - Split test_package.py into 3 modules (added test_etree.py and
    test_memory.py)
  - Update .tox with new environments 'package' and 'memory'
  - Replace test_package with test_etree into test_all.py script
  - Modify XsdValidatorTestCase.check_schema() to use xs prefix for
    XSD namespace and no namespace as targetNamespace for a fast
    reuse of common and user sample cases
This commit is contained in:
Davide Brunato 2019-06-20 07:31:00 +02:00
parent 81849f2368
commit 6994da5173
16 changed files with 730 additions and 661 deletions

3
.gitignore vendored
View File

@ -6,7 +6,8 @@
*.json
.idea/
.tox/
.coverage
.coverage*
!.coveragerc
.ipynb_checkpoints/
doc/_*/
dist/

View File

@ -62,7 +62,7 @@ author = 'Davide Brunato'
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0.13'
release = '1.0.14'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View File

@ -38,8 +38,8 @@ class InstallCommand(install):
setup(
name='xmlschema',
version='1.0.13',
install_requires=['elementpath~=1.1.7'],
version='1.0.14',
install_requires=['elementpath~=1.1.8'],
packages=['xmlschema'],
include_package_data=True,
cmdclass={

19
tox.ini
View File

@ -4,7 +4,7 @@
# and then run "tox" from this directory.
[tox]
envlist = py27, py35, py36, py37, py38, docs, flake8, coverage
envlist = package, py27, py35, py36, py37, py38, memory, docs, flake8, coverage
skip_missing_interpreters = true
toxworkdir = {homedir}/.tox/xmlschema
@ -12,24 +12,21 @@ toxworkdir = {homedir}/.tox/xmlschema
deps =
lxml
elementpath~=1.1.7
py37: memory_profiler
py27: pathlib2
memory: memory_profiler
docs: Sphinx
docs: sphinx_rtd_theme
flake8: flake8
coverage: coverage
coverage: memory_profiler
commands = python xmlschema/tests/test_all.py {posargs}
whitelist_externals = make
[testenv:py27]
deps =
lxml
elementpath~=1.1.7
pathlib2
commands = python xmlschema/tests/test_all.py {posargs}
[testenv:package]
commands = python xmlschema/tests/test_package.py
[testenv:py38]
deps = elementpath~=1.1.7
commands = python xmlschema/tests/test_all.py {posargs}
[testenv:memory]
commands = python xmlschema/tests/test_memory.py
[testenv:docs]
commands =

View File

@ -26,7 +26,7 @@ from .validators import (
XMLSchemaBase, XMLSchema, XMLSchema10
)
__version__ = '1.0.13'
__version__ = '1.0.14'
__author__ = "Davide Brunato"
__contact__ = "brunato@sissa.it"
__copyright__ = "Copyright 2016-2019, SISSA"

View File

@ -45,29 +45,37 @@ def has_network_access(*locations):
SKIP_REMOTE_TESTS = not has_network_access('http://www.sissa.it', 'http://www.w3.org/', 'http://dublincore.org/')
PROTECTED_PREFIX_PATTERN = re.compile(r'ns\d:')
TEST_CASES_DIR = os.path.join(os.path.dirname(__file__), 'test_cases/')
SCHEMA_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="{0}">
{1}
</xs:schema>"""
def casepath(relative_path):
"""
Returns the absolute path from a relative path specified from the `xmlschema/tests/test_cases/` dir.
"""
return os.path.join(TEST_CASES_DIR, relative_path)
def print_test_header():
"""Print an header thar displays Python version and platform used for test session."""
header1 = "Test %r" % xmlschema
header2 = "with Python {} on platform {}".format(platform.python_version(), platform.platform())
print('{0}\n{1}\n{2}\n{0}'.format("*" * max(len(header1), len(header2)), header1, header2))
class XMLSchemaTestCase(unittest.TestCase):
class XsdValidatorTestCase(unittest.TestCase):
"""
XMLSchema TestCase class.
TestCase class for XSD validators.
"""
@classmethod
def casepath(cls, relative_path):
return casepath(relative_path)
Setup tests common environment. The tests parts have to use empty prefix for
XSD namespace names and 'ns' prefix for XMLSchema test namespace names.
"""
test_cases_dir = os.path.join(os.path.dirname(__file__), 'test_cases/')
etree_register_namespace(prefix='', uri=XSD_NAMESPACE)
etree_register_namespace(prefix='xs', uri=XSD_NAMESPACE)
etree_register_namespace(prefix='ns', uri="ns")
SCHEMA_TEMPLATE = """<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns:ns="ns" xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="ns" elementFormDefault="unqualified" version="{0}">
{1}
</schema>"""
schema_class = XMLSchema
@ -83,36 +91,27 @@ class XMLSchemaTestCase(unittest.TestCase):
'ns': 'ns',
}
cls.vh_dir = cls.casepath('examples/vehicles')
cls.vh_xsd_file = cls.casepath('examples/vehicles/vehicles.xsd')
cls.vh_xml_file = cls.casepath('examples/vehicles/vehicles.xml')
cls.vh_json_file = cls.casepath('examples/vehicles/vehicles.json')
cls.vh_dir = casepath('examples/vehicles')
cls.vh_xsd_file = casepath('examples/vehicles/vehicles.xsd')
cls.vh_xml_file = casepath('examples/vehicles/vehicles.xml')
cls.vh_json_file = casepath('examples/vehicles/vehicles.json')
cls.vh_schema = cls.schema_class(cls.vh_xsd_file)
cls.vh_namespaces = fetch_namespaces(cls.vh_xml_file)
cls.col_dir = cls.casepath('examples/collection')
cls.col_xsd_file = cls.casepath('examples/collection/collection.xsd')
cls.col_xml_file = cls.casepath('examples/collection/collection.xml')
cls.col_json_file = cls.casepath('examples/collection/collection.json')
cls.col_dir = casepath('examples/collection')
cls.col_xsd_file = casepath('examples/collection/collection.xsd')
cls.col_xml_file = casepath('examples/collection/collection.xml')
cls.col_json_file = casepath('examples/collection/collection.json')
cls.col_schema = cls.schema_class(cls.col_xsd_file)
cls.col_namespaces = fetch_namespaces(cls.col_xml_file)
cls.st_xsd_file = cls.casepath('features/decoder/simple-types.xsd')
cls.st_xsd_file = casepath('features/decoder/simple-types.xsd')
cls.st_schema = cls.schema_class(cls.st_xsd_file)
cls.models_xsd_file = cls.casepath('features/models/models.xsd')
cls.models_xsd_file = casepath('features/models/models.xsd')
cls.models_schema = cls.schema_class(cls.models_xsd_file)
@classmethod
def casepath(cls, path):
"""
Returns the absolute path of a test case file.
:param path: the relative path of the case file from base dir ``xmlschema/tests/test_cases/``.
"""
return os.path.join(cls.test_cases_dir, path)
def retrieve_schema_source(self, source):
def get_schema_source(self, source):
"""
Returns a schema source that can be used to create an XMLSchema instance.
@ -129,9 +128,7 @@ class XMLSchemaTestCase(unittest.TestCase):
raise XMLSchemaValueError("% is not an XSD global definition/declaration." % source)
root = etree_element('schema', attrib={
'xmlns:ns': "ns",
'xmlns': "http://www.w3.org/2001/XMLSchema",
'targetNamespace': "ns",
'xmlns:xs': "http://www.w3.org/2001/XMLSchema",
'elementFormDefault': "qualified",
'version': self.schema_class.XSD_VERSION,
})
@ -140,19 +137,11 @@ class XMLSchemaTestCase(unittest.TestCase):
else:
source = source.strip()
if not source.startswith('<'):
return self.casepath(source)
return casepath(source)
elif source.startswith('<?xml ') or source.startswith('<xs:schema '):
return source
else:
return self.SCHEMA_TEMPLATE.format(self.schema_class.XSD_VERSION, source)
def get_schema(self, source):
return self.schema_class(self.retrieve_schema_source(source))
def get_element(self, name, **attrib):
source = '<element name="{}" {}/>'.format(
name, ' '.join('%s="%s"' % (k, v) for k, v in attrib.items())
)
schema = self.schema_class(self.retrieve_schema_source(source))
return schema.elements[name]
return SCHEMA_TEMPLATE.format(self.schema_class.XSD_VERSION, source)
def check_etree_elements(self, elem, other):
"""Checks if two ElementTree elements are equal."""
@ -168,6 +157,16 @@ class XMLSchemaTestCase(unittest.TestCase):
msg = "Protected prefix {!r} found:\n {}".format(match.group(0), s)
self.assertIsNone(match, msg)
def get_schema(self, source):
return self.schema_class(self.get_schema_source(source))
def get_element(self, name, **attrib):
source = '<xs:element name="{}" {}/>'.format(
name, ' '.join('%s="%s"' % (k, v) for k, v in attrib.items())
)
schema = self.schema_class(self.get_schema_source(source))
return schema.elements[name]
def check_errors(self, path, expected):
"""
Checks schema or validation errors, checking information completeness of the

View File

@ -10,6 +10,8 @@
# @author Davide Brunato <brunato@sissa.it>
#
if __name__ == '__main__':
from xmlschema.tests import print_test_header
from xmlschema.tests.test_etree import *
from xmlschema.tests.test_helpers import *
from xmlschema.tests.test_meta import *
from xmlschema.tests.test_regex import *
@ -18,8 +20,6 @@ if __name__ == '__main__':
from xmlschema.tests.test_models import *
from xmlschema.tests.test_schemas import *
from xmlschema.tests.test_validators import *
from xmlschema.tests.test_package import *
from xmlschema.tests import print_test_header
print_test_header()
unittest.main()

View File

@ -0,0 +1,97 @@
#!/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>
#
import unittest
import os
import importlib
import sys
import subprocess
@unittest.skipIf(sys.version_info < (3,), "In Python 2 ElementTree is not overwritten by cElementTree")
class TestElementTree(unittest.TestCase):
def test_element_string_serialization(self):
ElementTree = importlib.import_module('xml.etree.ElementTree')
xmlschema_etree = importlib.import_module('xmlschema.etree')
elem = ElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
elem = xmlschema_etree.ElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
elem = xmlschema_etree.PyElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
def test_import_element_tree_before(self):
ElementTree = importlib.import_module('xml.etree.ElementTree')
xmlschema_etree = importlib.import_module('xmlschema.etree')
self.assertIsNot(ElementTree.Element, ElementTree._Element_Py, msg="cElementTree not available!")
elem = xmlschema_etree.PyElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
self.assertIs(importlib.import_module('xml.etree.ElementTree'), ElementTree)
self.assertIs(xmlschema_etree.ElementTree, ElementTree)
def test_import_element_tree_after(self):
xmlschema_etree = importlib.import_module('xmlschema.etree')
ElementTree = importlib.import_module('xml.etree.ElementTree')
self.assertIsNot(ElementTree.Element, ElementTree._Element_Py, msg="cElementTree not available!")
elem = xmlschema_etree.PyElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
self.assertIs(importlib.import_module('xml.etree.ElementTree'), ElementTree)
self.assertIs(xmlschema_etree.ElementTree, ElementTree)
def test_element_tree_import_script(self):
test_dir = os.path.dirname(__file__) or '.'
cmd = [os.path.join(test_dir, 'check_etree_import.py')]
process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = process.stdout.decode('utf-8')
self.assertTrue("\nTest OK:" in output, msg="Wrong import of ElementTree after xmlschema")
cmd.append('--before')
process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = process.stdout.decode('utf-8')
self.assertTrue("\nTest OK:" in output, msg="Wrong import of ElementTree before xmlschema")
def test_safe_xml_parser(self):
test_dir = os.path.dirname(__file__) or '.'
xmlschema_etree = importlib.import_module('xmlschema.etree')
parser = xmlschema_etree.SafeXMLParser(target=xmlschema_etree.PyElementTree.TreeBuilder())
PyElementTree = xmlschema_etree.PyElementTree
xml_file = os.path.join(test_dir, 'test_cases/resources/with_entity.xml')
elem = xmlschema_etree.ElementTree.parse(xml_file).getroot()
self.assertEqual(elem.text, 'abc')
self.assertRaises(
PyElementTree.ParseError, xmlschema_etree.ElementTree.parse, xml_file, parser=parser
)
xml_file = os.path.join(test_dir, 'test_cases/resources/unused_external_entity.xml')
elem = xmlschema_etree.ElementTree.parse(xml_file).getroot()
self.assertEqual(elem.text, 'abc')
self.assertRaises(
PyElementTree.ParseError, xmlschema_etree.ElementTree.parse, xml_file, parser=parser
)
xml_file = os.path.join(test_dir, 'test_cases/resources/external_entity.xml')
self.assertRaises(xmlschema_etree.ParseError, xmlschema_etree.ElementTree.parse, xml_file)
self.assertRaises(
PyElementTree.ParseError, xmlschema_etree.ElementTree.parse, xml_file, parser=parser
)
if __name__ == '__main__':
from xmlschema.tests import print_test_header
print_test_header()
unittest.main()

View File

@ -22,10 +22,9 @@ from xmlschema.helpers import get_xsd_annotation, iter_xsd_components, get_names
local_name, qname_to_prefixed, has_xsd_components, get_xsd_component, \
get_xml_bool_attribute, get_xsd_derivation_attribute
from xmlschema.qnames import XSI_TYPE, XSD_SCHEMA, XSD_ELEMENT, XSD_SIMPLE_TYPE, XSD_ANNOTATION
from xmlschema.tests import XMLSchemaTestCase
class TestHelpers(XMLSchemaTestCase):
class TestHelpers(unittest.TestCase):
def test_get_namespace_function(self):
self.assertEqual(get_namespace(XSD_SIMPLE_TYPE), XSD_NAMESPACE)

View File

@ -0,0 +1,107 @@
#!/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>
#
import unittest
import os
import decimal
import subprocess
class TestMemoryUsage(unittest.TestCase):
@staticmethod
def check_memory_profile(output):
"""Check the output of a memory memory profile run on a function."""
mem_usage = []
func_num = 0
for line in output.split('\n'):
parts = line.split()
if 'def' in parts:
func_num += 1
if not parts or not parts[0].isdigit() or len(parts) == 1 \
or not parts[1].replace('.', '').isdigit():
continue
mem_usage.append(decimal.Decimal(parts[1]))
if func_num > 1:
raise ValueError("Cannot the a memory profile output of more than one function!")
return max(v - mem_usage[0] for v in mem_usage[1:])
@unittest.skip
def test_package_memory_usage(self):
test_dir = os.path.dirname(__file__) or '.'
cmd = [os.path.join(test_dir, 'check_memory.py'), '1']
output = subprocess.check_output(cmd, universal_newlines=True)
package_mem = self.check_memory_profile(output)
self.assertLess(package_mem, 20)
def test_element_tree_memory_usage(self):
test_dir = os.path.dirname(__file__) or '.'
xsd10_schema_file = os.path.join(
os.path.dirname(os.path.abspath(test_dir)), 'validators/schemas/XSD_1.0/XMLSchema.xsd'
)
cmd = [os.path.join(test_dir, 'check_memory.py'), '2', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
parse_mem = self.check_memory_profile(output)
cmd = [os.path.join(test_dir, 'check_memory.py'), '3', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
iterparse_mem = self.check_memory_profile(output)
cmd = [os.path.join(test_dir, 'check_memory.py'), '4', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
lazy_iterparse_mem = self.check_memory_profile(output)
self.assertLess(parse_mem, 2)
self.assertLessEqual(lazy_iterparse_mem, parse_mem / 2)
self.assertLessEqual(lazy_iterparse_mem, iterparse_mem)
def test_decode_memory_usage(self):
test_dir = os.path.dirname(__file__) or '.'
xsd10_schema_file = os.path.join(
os.path.dirname(os.path.abspath(test_dir)), 'validators/schemas/XSD_1.0/XMLSchema.xsd'
)
cmd = [os.path.join(test_dir, 'check_memory.py'), '5', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
decode_mem = self.check_memory_profile(output)
cmd = [os.path.join(test_dir, 'check_memory.py'), '6', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
lazy_decode_mem = self.check_memory_profile(output)
self.assertLess(decode_mem, 2)
self.assertLessEqual(lazy_decode_mem, decode_mem / decimal.Decimal(1.4))
def test_validate_memory_usage(self):
test_dir = os.path.dirname(__file__) or '.'
xsd10_schema_file = os.path.join(
os.path.dirname(os.path.abspath(test_dir)), 'validators/schemas/XSD_1.0/XMLSchema.xsd'
)
cmd = [os.path.join(test_dir, 'check_memory.py'), '7', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
validate_mem = self.check_memory_profile(output)
cmd = [os.path.join(test_dir, 'check_memory.py'), '8', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
lazy_validate_mem = self.check_memory_profile(output)
self.assertLess(validate_mem, 2)
self.assertLessEqual(lazy_validate_mem, validate_mem / 2)
if __name__ == '__main__':
from xmlschema.tests import print_test_header
print_test_header()
unittest.main()

View File

@ -15,10 +15,10 @@ This module runs tests concerning model groups validation.
import unittest
from xmlschema.validators import ModelVisitor
from xmlschema.tests import XMLSchemaTestCase
from xmlschema.tests import casepath, XsdValidatorTestCase
class TestModelValidation(XMLSchemaTestCase):
class TestModelValidation(XsdValidatorTestCase):
# --- Test helper functions ---
@ -468,7 +468,7 @@ class TestModelValidation(XMLSchemaTestCase):
#
# Tests on issues
def test_issue_086(self):
issue_086_xsd = self.casepath('issues/issue_086/issue_086.xsd')
issue_086_xsd = casepath('issues/issue_086/issue_086.xsd')
schema = self.schema_class(issue_086_xsd)
group = schema.types['Foo'].content_type

View File

@ -17,177 +17,8 @@ import os
import re
import importlib
import platform
import sys
import decimal
import subprocess
try:
import memory_profiler
except ImportError:
memory_profiler = None
@unittest.skipIf(sys.version_info < (3,), "In Python 2 ElementTree is not overwritten by cElementTree")
class TestElementTree(unittest.TestCase):
def test_element_string_serialization(self):
ElementTree = importlib.import_module('xml.etree.ElementTree')
xmlschema_etree = importlib.import_module('xmlschema.etree')
elem = ElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
elem = xmlschema_etree.ElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
elem = xmlschema_etree.PyElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
def test_import_element_tree_before(self):
ElementTree = importlib.import_module('xml.etree.ElementTree')
xmlschema_etree = importlib.import_module('xmlschema.etree')
self.assertIsNot(ElementTree.Element, ElementTree._Element_Py, msg="cElementTree not available!")
elem = xmlschema_etree.PyElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
self.assertIs(importlib.import_module('xml.etree.ElementTree'), ElementTree)
self.assertIs(xmlschema_etree.ElementTree, ElementTree)
def test_import_element_tree_after(self):
xmlschema_etree = importlib.import_module('xmlschema.etree')
ElementTree = importlib.import_module('xml.etree.ElementTree')
self.assertIsNot(ElementTree.Element, ElementTree._Element_Py, msg="cElementTree not available!")
elem = xmlschema_etree.PyElementTree.Element('element')
self.assertEqual(xmlschema_etree.etree_tostring(elem), '<element />')
self.assertIs(importlib.import_module('xml.etree.ElementTree'), ElementTree)
self.assertIs(xmlschema_etree.ElementTree, ElementTree)
def test_element_tree_import_script(self):
test_dir = os.path.dirname(__file__) or '.'
cmd = [os.path.join(test_dir, 'check_etree_import.py')]
process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = process.stdout.decode('utf-8')
self.assertTrue("\nTest OK:" in output, msg="Wrong import of ElementTree after xmlschema")
cmd.append('--before')
process = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = process.stdout.decode('utf-8')
self.assertTrue("\nTest OK:" in output, msg="Wrong import of ElementTree before xmlschema")
def test_safe_xml_parser(self):
test_dir = os.path.dirname(__file__) or '.'
xmlschema_etree = importlib.import_module('xmlschema.etree')
parser = xmlschema_etree.SafeXMLParser(target=xmlschema_etree.PyElementTree.TreeBuilder())
PyElementTree = xmlschema_etree.PyElementTree
xml_file = os.path.join(test_dir, 'test_cases/resources/with_entity.xml')
elem = xmlschema_etree.ElementTree.parse(xml_file).getroot()
self.assertEqual(elem.text, 'abc')
self.assertRaises(
PyElementTree.ParseError, xmlschema_etree.ElementTree.parse, xml_file, parser=parser
)
xml_file = os.path.join(test_dir, 'test_cases/resources/unused_external_entity.xml')
elem = xmlschema_etree.ElementTree.parse(xml_file).getroot()
self.assertEqual(elem.text, 'abc')
self.assertRaises(
PyElementTree.ParseError, xmlschema_etree.ElementTree.parse, xml_file, parser=parser
)
xml_file = os.path.join(test_dir, 'test_cases/resources/external_entity.xml')
self.assertRaises(xmlschema_etree.ParseError, xmlschema_etree.ElementTree.parse, xml_file)
self.assertRaises(
PyElementTree.ParseError, xmlschema_etree.ElementTree.parse, xml_file, parser=parser
)
@unittest.skipIf(memory_profiler is None or sys.version_info[:2] != (3, 7), "Test only with Python 3.7")
class TestMemoryUsage(unittest.TestCase):
@staticmethod
def check_memory_profile(output):
"""Check the output of a memory memory profile run on a function."""
mem_usage = []
func_num = 0
for line in output.split('\n'):
parts = line.split()
if 'def' in parts:
func_num += 1
if not parts or not parts[0].isdigit() or len(parts) == 1 \
or not parts[1].replace('.', '').isdigit():
continue
mem_usage.append(decimal.Decimal(parts[1]))
if func_num > 1:
raise ValueError("Cannot the a memory profile output of more than one function!")
return max(v - mem_usage[0] for v in mem_usage[1:])
@unittest.skip
def test_package_memory_usage(self):
test_dir = os.path.dirname(__file__) or '.'
cmd = [os.path.join(test_dir, 'check_memory.py'), '1']
output = subprocess.check_output(cmd, universal_newlines=True)
package_mem = self.check_memory_profile(output)
self.assertLess(package_mem, 20)
def test_element_tree_memory_usage(self):
test_dir = os.path.dirname(__file__) or '.'
xsd10_schema_file = os.path.join(
os.path.dirname(os.path.abspath(test_dir)), 'validators/schemas/XSD_1.0/XMLSchema.xsd'
)
cmd = [os.path.join(test_dir, 'check_memory.py'), '2', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
parse_mem = self.check_memory_profile(output)
cmd = [os.path.join(test_dir, 'check_memory.py'), '3', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
iterparse_mem = self.check_memory_profile(output)
cmd = [os.path.join(test_dir, 'check_memory.py'), '4', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
lazy_iterparse_mem = self.check_memory_profile(output)
self.assertLess(parse_mem, 2)
self.assertLessEqual(lazy_iterparse_mem, parse_mem / 2)
self.assertLessEqual(lazy_iterparse_mem, iterparse_mem)
def test_decode_memory_usage(self):
test_dir = os.path.dirname(__file__) or '.'
xsd10_schema_file = os.path.join(
os.path.dirname(os.path.abspath(test_dir)), 'validators/schemas/XSD_1.0/XMLSchema.xsd'
)
cmd = [os.path.join(test_dir, 'check_memory.py'), '5', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
decode_mem = self.check_memory_profile(output)
cmd = [os.path.join(test_dir, 'check_memory.py'), '6', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
lazy_decode_mem = self.check_memory_profile(output)
self.assertLess(decode_mem, 2)
self.assertLessEqual(lazy_decode_mem, decode_mem / decimal.Decimal(1.5))
def test_validate_memory_usage(self):
test_dir = os.path.dirname(__file__) or '.'
xsd10_schema_file = os.path.join(
os.path.dirname(os.path.abspath(test_dir)), 'validators/schemas/XSD_1.0/XMLSchema.xsd'
)
cmd = [os.path.join(test_dir, 'check_memory.py'), '7', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
validate_mem = self.check_memory_profile(output)
cmd = [os.path.join(test_dir, 'check_memory.py'), '8', xsd10_schema_file]
output = subprocess.check_output(cmd, universal_newlines=True)
lazy_validate_mem = self.check_memory_profile(output)
self.assertLess(validate_mem, 2)
self.assertLessEqual(lazy_validate_mem, validate_mem / 2)
@unittest.skipIf(platform.system() == 'Windows', "Skip packaging test on Windows platform.")
class TestPackaging(unittest.TestCase):
@classmethod

View File

@ -14,7 +14,6 @@ This module runs tests concerning resources.
"""
import unittest
import os
import platform
try:
from pathlib import PureWindowsPath, PurePath
@ -25,9 +24,10 @@ from xmlschema import (
fetch_namespaces, fetch_resource, normalize_url, fetch_schema, fetch_schema_locations,
load_xml_resource, XMLResource, XMLSchemaURLError
)
from xmlschema.tests import XMLSchemaTestCase, SKIP_REMOTE_TESTS
from xmlschema.tests import casepath
from xmlschema.compat import urlopen, urlsplit, uses_relative, StringIO
from xmlschema.etree import ElementTree, PyElementTree, lxml_etree, is_etree_element, etree_element, py_etree_element
from xmlschema.etree import ElementTree, PyElementTree, lxml_etree, is_etree_element, \
etree_element, py_etree_element
def is_windows_path(path):
@ -39,7 +39,17 @@ def add_leading_slash(path):
return '/' + path if path and path[0] not in ('/', '\\') else path
class TestResources(XMLSchemaTestCase):
class TestResources(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.vh_dir = casepath('examples/vehicles')
cls.vh_xsd_file = casepath('examples/vehicles/vehicles.xsd')
cls.vh_xml_file = casepath('examples/vehicles/vehicles.xml')
cls.col_dir = casepath('examples/collection')
cls.col_xsd_file = casepath('examples/collection/collection.xsd')
cls.col_xml_file = casepath('examples/collection/collection.xml')
def check_url(self, url, expected):
url_parts = urlsplit(url)
@ -108,13 +118,13 @@ class TestResources(XMLSchemaTestCase):
self.assertEqual(normalize_url('dir2/schema.xsd', '////root/dir1'), 'file:///root/dir1/dir2/schema.xsd')
def test_fetch_resource(self):
wrong_path = self.casepath('resources/dummy_file.txt')
wrong_path = casepath('resources/dummy_file.txt')
self.assertRaises(XMLSchemaURLError, fetch_resource, wrong_path)
right_path = self.casepath('resources/dummy file.txt')
right_path = casepath('resources/dummy file.txt')
self.assertTrue(fetch_resource(right_path).endswith('dummy file.txt'))
def test_fetch_namespaces(self):
self.assertFalse(fetch_namespaces(self.casepath('resources/malformed.xml')))
self.assertFalse(fetch_namespaces(casepath('resources/malformed.xml')))
def test_fetch_schema_locations(self):
locations = fetch_schema_locations(self.col_xml_file)
@ -282,15 +292,15 @@ class TestResources(XMLSchemaTestCase):
resource = XMLResource(self.vh_xml_file, defuse='always')
self.assertIsInstance(resource.root, py_etree_element)
xml_file = self.casepath('resources/with_entity.xml')
xml_file = casepath('resources/with_entity.xml')
self.assertIsInstance(XMLResource(xml_file), XMLResource)
self.assertRaises(PyElementTree.ParseError, XMLResource, xml_file, defuse='always')
xml_file = self.casepath('resources/unused_external_entity.xml')
xml_file = casepath('resources/unused_external_entity.xml')
self.assertIsInstance(XMLResource(xml_file), XMLResource)
self.assertRaises(PyElementTree.ParseError, XMLResource, xml_file, defuse='always')
xml_file = self.casepath('resources/external_entity.xml')
xml_file = casepath('resources/external_entity.xml')
self.assertIsInstance(XMLResource(xml_file), XMLResource)
self.assertRaises(PyElementTree.ParseError, XMLResource, xml_file, defuse='always')
@ -367,22 +377,6 @@ class TestResources(XMLSchemaTestCase):
self.assertEqual(len(locations), 2)
self.check_url(locations[0][1], os.path.join(self.col_dir, 'other.xsd'))
@unittest.skipIf(SKIP_REMOTE_TESTS or platform.system() == 'Windows',
"Remote networks are not accessible or avoid SSL verification error on Windows.")
def test_remote_schemas_loading(self):
col_schema = self.schema_class("https://raw.githubusercontent.com/brunato/xmlschema/master/"
"xmlschema/tests/test_cases/examples/collection/collection.xsd")
self.assertTrue(isinstance(col_schema, self.schema_class))
vh_schema = self.schema_class("https://raw.githubusercontent.com/brunato/xmlschema/master/"
"xmlschema/tests/test_cases/examples/vehicles/vehicles.xsd")
self.assertTrue(isinstance(vh_schema, self.schema_class))
def test_schema_defuse(self):
vh_schema = self.schema_class(self.vh_xsd_file, defuse='always')
self.assertIsInstance(vh_schema.root, etree_element)
for schema in vh_schema.maps.iter_schemas():
self.assertIsInstance(schema.root, etree_element)
if __name__ == '__main__':
from xmlschema.tests import print_test_header

View File

@ -17,6 +17,7 @@ import unittest
import pdb
import os
import pickle
import platform
import time
import warnings
@ -26,12 +27,12 @@ from xmlschema import XMLSchemaBase, XMLSchemaParseError, XMLSchemaModelError, \
from xmlschema.compat import PY3, unicode_type
from xmlschema.etree import lxml_etree, etree_element, py_etree_element
from xmlschema.qnames import XSD_LIST, XSD_UNION, XSD_ELEMENT, XSI_TYPE
from xmlschema.tests import tests_factory, SchemaObserver, XMLSchemaTestCase
from xmlschema.tests import SKIP_REMOTE_TESTS, tests_factory, SchemaObserver, XsdValidatorTestCase
from xmlschema.validators import XsdValidator, XMLSchema11
from xmlschema.xpath import ElementPathContext
class TestXMLSchema10(XMLSchemaTestCase):
class TestXMLSchema10(XsdValidatorTestCase):
def check_schema(self, source, expected=None, **kwargs):
"""
@ -43,9 +44,9 @@ class TestXMLSchema10(XMLSchemaTestCase):
a substring test if it's not `None` (maybe a string). Then returns the schema instance.
"""
if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected, self.schema_class, self.retrieve_schema_source(source), **kwargs)
self.assertRaises(expected, self.schema_class, self.get_schema_source(source), **kwargs)
else:
schema = self.schema_class(self.retrieve_schema_source(source), **kwargs)
schema = self.schema_class(self.get_schema_source(source), **kwargs)
if callable(expected):
self.assertTrue(expected(schema))
return schema
@ -53,16 +54,16 @@ class TestXMLSchema10(XMLSchemaTestCase):
def check_complex_restriction(self, base, restriction, expected=None, **kwargs):
content = 'complex' if self.content_pattern.search(base) else 'simple'
source = """
<complexType name="targetType">
<xs:complexType name="targetType">
{0}
</complexType>
<complexType name="restrictedType">
<{1}Content>
<restriction base="ns:targetType">
</xs:complexType>
<xs:complexType name="restrictedType">
<xs:{1}Content>
<xs:restriction base="targetType">
{2}
</restriction>
</{1}Content>
</complexType>
</xs:restriction>
</xs:{1}Content>
</xs:complexType>
""".format(base.strip(), content, restriction.strip())
self.check_schema(source, expected, **kwargs)
@ -91,14 +92,14 @@ class TestXMLSchema10(XMLSchemaTestCase):
def test_simple_types(self):
# Issue #54: set list or union schema element.
xs = self.check_schema("""
<simpleType name="test_list">
<annotation/>
<list itemType="string"/>
</simpleType>
<simpleType name="test_union">
<annotation/>
<union memberTypes="string integer boolean"/>
</simpleType>
<xs:simpleType name="test_list">
<xs:annotation/>
<xs:list itemType="xs:string"/>
</xs:simpleType>
<xs:simpleType name="test_union">
<xs:annotation/>
<xs:union memberTypes="xs:string xs:integer xs:boolean"/>
</xs:simpleType>
""")
xs.types['test_list'].elem = xs.root[0] # elem.tag == 'simpleType'
self.assertEqual(xs.types['test_list'].elem.tag, XSD_LIST)
@ -110,12 +111,14 @@ class TestXMLSchema10(XMLSchemaTestCase):
with warnings.catch_warnings(record=True) as context:
warnings.simplefilter("always")
self.check_schema("""
<include schemaLocation="example.xsd" />
<import schemaLocation="example.xsd" />
<redefine schemaLocation="example.xsd"/>
<import namespace="http://missing.example.test/" />
<import/>
""")
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="ns">
<xs:include schemaLocation="example.xsd" />
<xs:import schemaLocation="example.xsd" />
<xs:redefine schemaLocation="example.xsd"/>
<xs:import namespace="http://missing.example.test/" />
<xs:import/>
</xs:schema>
""")
self.assertEqual(len(context), 3, "Wrong number of include/import warnings")
self.assertEqual(context[0].category, XMLSchemaIncludeWarning)
self.assertEqual(context[1].category, XMLSchemaIncludeWarning)
@ -127,293 +130,333 @@ class TestXMLSchema10(XMLSchemaTestCase):
def test_wrong_references(self):
# Wrong namespace for element type's reference
self.check_schema("""
<element name="dimension" type="dimensionType"/>
<simpleType name="dimensionType">
<restriction base="short"/>
</simpleType>
""", XMLSchemaParseError)
<xs:element name="dimension" type="xs:dimensionType"/>
<xs:simpleType name="dimensionType">
<xs:restriction base="xs:short"/>
</xs:simpleType>
""", XMLSchemaParseError)
def test_restriction_has_annotation(self):
# Wrong namespace for element type's reference
schema = self.check_schema("""
<simpleType name='Magic'>
<annotation>
<documentation> stuff </documentation>
</annotation>
<restriction base='string'>
<enumeration value='A'/>
</restriction>
</simpleType>""")
<xs:simpleType name='Magic'>
<xs:annotation>
<xs:documentation> stuff </xs:documentation>
</xs:annotation>
<xs:restriction base='xs:string'>
<xs:enumeration value='A'/>
</xs:restriction>
</xs:simpleType>""")
self.assertIsNotNone(schema.types["Magic"].annotation)
def test_facets(self):
# Issue #55 and a near error (derivation from xs:integer)
self.check_schema("""
<simpleType name="dtype">
<restriction base="decimal">
<fractionDigits value="3" />
<totalDigits value="20" />
</restriction>
</simpleType>
<simpleType name="ntype">
<restriction base="ns:dtype">
<totalDigits value="3" />
<fractionDigits value="1" />
</restriction>
</simpleType>
""")
<xs:simpleType name="dtype">
<xs:restriction base="xs:decimal">
<xs:fractionDigits value="3" />
<xs:totalDigits value="20" />
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ntype">
<xs:restriction base="dtype">
<xs:totalDigits value="3" />
<xs:fractionDigits value="1" />
</xs:restriction>
</xs:simpleType>
""")
self.check_schema("""
<simpleType name="dtype">
<restriction base="integer">
<fractionDigits value="3" /> <!-- <<< value must be 0 -->
<totalDigits value="20" />
</restriction>
</simpleType>
""", xmlschema.XMLSchemaParseError)
<xs:simpleType name="dtype">
<xs:restriction base="xs:integer">
<xs:fractionDigits value="3" /> <!-- <<< value must be 0 -->
<xs:totalDigits value="20" />
</xs:restriction>
</xs:simpleType>
""", xmlschema.XMLSchemaParseError)
# Issue #56
self.check_schema("""
<simpleType name="mlengthparent">
<restriction base="string">
<maxLength value="200"/>
</restriction>
</simpleType>
<simpleType name="mlengthchild">
<restriction base="ns:mlengthparent">
<maxLength value="20"/>
</restriction>
</simpleType>
""")
<xs:simpleType name="mlengthparent">
<xs:restriction base="xs:string">
<xs:maxLength value="200"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="mlengthchild">
<xs:restriction base="mlengthparent">
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
""")
def test_element_restrictions(self):
base = """
<sequence>
<element name="A" maxOccurs="7"/>
<element name="B" type="string"/>
<element name="C" fixed="5"/>
</sequence>
<xs:sequence>
<xs:element name="A" maxOccurs="7"/>
<xs:element name="B" type="xs:string"/>
<xs:element name="C" fixed="5"/>
</xs:sequence>
"""
self.check_complex_restriction(
base, restriction="""
<sequence>
<element name="A" maxOccurs="6"/>
<element name="B" type="NCName"/>
<element name="C" fixed="5"/>
</sequence>
""")
<xs:sequence>
<xs:element name="A" maxOccurs="6"/>
<xs:element name="B" type="xs:NCName"/>
<xs:element name="C" fixed="5"/>
</xs:sequence>
"""
)
self.check_complex_restriction(
base, restriction="""
<sequence>
<element name="A" maxOccurs="8"/> <!-- <<< More occurrences -->
<element name="B" type="NCName"/>
<element name="C" fixed="5"/>
</sequence>
""", expected=XMLSchemaParseError)
<xs:sequence>
<xs:element name="A" maxOccurs="8"/> <!-- <<< More occurrences -->
<xs:element name="B" type="xs:NCName"/>
<xs:element name="C" fixed="5"/>
</xs:sequence>
""", expected=XMLSchemaParseError
)
self.check_complex_restriction(
base, restriction="""
<sequence>
<element name="A" maxOccurs="6"/>
<element name="B" type="float"/> <!-- <<< Not a derived type -->
<element name="C" fixed="5"/>
</sequence>
""", expected=XMLSchemaParseError)
<xs:sequence>
<xs:element name="A" maxOccurs="6"/>
<xs:element name="B" type="float"/> <!-- <<< Not a derived type -->
<xs:element name="C" fixed="5"/>
</xs:sequence>
""", expected=XMLSchemaParseError
)
self.check_complex_restriction(
base, restriction="""
<sequence>
<element name="A" maxOccurs="6"/>
<element name="B" type="NCName"/>
<element name="C" fixed="3"/> <!-- <<< Different fixed value -->
</sequence>
""", expected=XMLSchemaParseError)
<xs:sequence>
<xs:element name="A" maxOccurs="6"/>
<xs:element name="B" type="xs:NCName"/>
<xs:element name="C" fixed="3"/> <!-- <<< Different fixed value -->
</xs:sequence>
""", expected=XMLSchemaParseError
)
self.check_complex_restriction(
base, restriction="""
<sequence>
<element name="A" maxOccurs="6" nillable="true"/> <!-- <<< nillable is True -->
<element name="B" type="NCName"/>
<element name="C" fixed="5"/>
</sequence>
""", expected=XMLSchemaParseError)
<xs:sequence>
<xs:element name="A" maxOccurs="6" nillable="true"/> <!-- <<< nillable is True -->
<xs:element name="B" type="xs:NCName"/>
<xs:element name="C" fixed="5"/>
</xs:sequence>
""", expected=XMLSchemaParseError
)
def test_sequence_group_restriction(self):
# Meaningless sequence group
base = """
<sequence>
<sequence>
<element name="A"/>
<element name="B"/>
</sequence>
</sequence>
<xs:sequence>
<xs:sequence>
<xs:element name="A"/>
<xs:element name="B"/>
</xs:sequence>
</xs:sequence>
"""
self.check_complex_restriction(
base, '<sequence><element name="A"/><element name="B"/></sequence>'
base, restriction="""
<xs:sequence>
<xs:element name="A"/>
<xs:element name="B"/>
</xs:sequence>
"""
)
self.check_complex_restriction(
base, '<sequence><element name="A"/><element name="C"/></sequence>', XMLSchemaParseError
base, restriction="""
<xs:sequence>
<xs:element name="A"/>
<xs:element name="C"/>
</xs:sequence>
""", expected=XMLSchemaParseError
)
base = """
<sequence>
<element name="A"/>
<element name="B" minOccurs="0"/>
</sequence>
<xs:sequence>
<xs:element name="A"/>
<xs:element name="B" minOccurs="0"/>
</xs:sequence>
"""
self.check_complex_restriction(base, '<sequence><element name="A"/></sequence>')
self.check_complex_restriction(base, '<sequence><element name="B"/></sequence>', XMLSchemaParseError)
self.check_complex_restriction(base, '<sequence><element name="C"/></sequence>', XMLSchemaParseError)
self.check_complex_restriction(base, '<xs:sequence><xs:element name="A"/></xs:sequence>')
self.check_complex_restriction(
base, '<sequence><element name="A"/><element name="B"/></sequence>'
base, '<xs:sequence><xs:element name="B"/></xs:sequence>', XMLSchemaParseError
)
self.check_complex_restriction(
base, '<sequence><element name="A"/><element name="C"/></sequence>', XMLSchemaParseError
base, '<xs:sequence><xs:element name="C"/></xs:sequence>', XMLSchemaParseError
)
self.check_complex_restriction(
base, '<sequence><element name="A" minOccurs="0"/><element name="B"/></sequence>',
base, '<xs:sequence><xs:element name="A"/><xs:element name="B"/></xs:sequence>'
)
self.check_complex_restriction(
base, '<xs:sequence><xs:element name="A"/><xs:element name="C"/></xs:sequence>', XMLSchemaParseError
)
self.check_complex_restriction(
base, '<xs:sequence><xs:element name="A" minOccurs="0"/><xs:element name="B"/></xs:sequence>',
XMLSchemaParseError
)
self.check_complex_restriction(
base, '<sequence><element name="B" minOccurs="0"/><element name="A"/></sequence>',
base, '<xs:sequence><xs:element name="B" minOccurs="0"/><xs:element name="A"/></xs:sequence>',
XMLSchemaParseError
)
def test_all_group_restriction(self):
base = """
<all>
<element name="A"/>
<element name="B" minOccurs="0"/>
<element name="C" minOccurs="0"/>
</all>
<xs:all>
<xs:element name="A"/>
<xs:element name="B" minOccurs="0"/>
<xs:element name="C" minOccurs="0"/>
</xs:all>
"""
self.check_complex_restriction(base, '<all><element name="A"/><element name="C"/></all>')
self.check_complex_restriction(
base, '<all><element name="C" minOccurs="0"/><element name="A"/></all>', XMLSchemaParseError
base, restriction="""
<xs:all>
<xs:element name="A"/>
<xs:element name="C"/>
</xs:all>
""")
self.check_complex_restriction(
base, restriction="""
<xs:all>
<xs:element name="C" minOccurs="0"/>
<xs:element name="A"/>
</xs:all>
""", expected=XMLSchemaParseError
)
self.check_complex_restriction(
base, '<sequence><element name="A"/><element name="C"/></sequence>'
base, restriction="""
<xs:sequence>
<xs:element name="A"/>
<xs:element name="C"/>
</xs:sequence>
""")
self.check_complex_restriction(
base, '<xs:sequence><xs:element name="C" minOccurs="0"/><xs:element name="A"/></xs:sequence>',
)
self.check_complex_restriction(
base, '<sequence><element name="C" minOccurs="0"/><element name="A"/></sequence>',
base, restriction="""
<xs:sequence>
<xs:element name="C" minOccurs="0"/>
<xs:element name="A" minOccurs="0"/>
</xs:sequence>
""", expected=XMLSchemaParseError
)
self.check_complex_restriction(
base, '<sequence><element name="C" minOccurs="0"/><element name="A" minOccurs="0"/></sequence>',
XMLSchemaParseError
)
self.check_complex_restriction(
base, '<sequence><element name="A"/><element name="X"/></sequence>', XMLSchemaParseError
base, restriction="""
<xs:sequence>
<xs:element name="A"/>
<xs:element name="X"/>
</xs:sequence>
""", expected=XMLSchemaParseError
)
base = """
<all>
<element name="A" minOccurs="0" maxOccurs="0"/>
</all>
<xs:all>
<xs:element name="A" minOccurs="0" maxOccurs="0"/>
</xs:all>
"""
self.check_complex_restriction(base, '<all><element name="A"/></all>', XMLSchemaParseError)
self.check_complex_restriction(base, '<xs:all><xs:element name="A"/></xs:all>', XMLSchemaParseError)
def test_choice_group_restriction(self):
base = """
<choice maxOccurs="2">
<element name="A"/>
<element name="B"/>
<element name="C"/>
</choice>
<xs:choice maxOccurs="2">
<xs:element name="A"/>
<xs:element name="B"/>
<xs:element name="C"/>
</xs:choice>
"""
self.check_complex_restriction(base, '<choice><element name="A"/><element name="C"/></choice>')
self.check_complex_restriction(base, '<xs:choice><xs:element name="A"/><xs:element name="C"/></xs:choice>')
self.check_complex_restriction(
base, '<choice maxOccurs="2"><element name="C"/><element name="A"/></choice>',
base, '<xs:choice maxOccurs="2"><xs:element name="C"/><xs:element name="A"/></xs:choice>',
XMLSchemaParseError
)
self.check_complex_restriction(
base, '<choice maxOccurs="2"><element name="A"/><element name="C"/></choice>',
base, '<xs:choice maxOccurs="2"><xs:element name="A"/><xs:element name="C"/></xs:choice>',
)
def test_occurs_restriction(self):
base = """
<sequence minOccurs="3" maxOccurs="10">
<element name="A"/>
</sequence>
<xs:sequence minOccurs="3" maxOccurs="10">
<xs:element name="A"/>
</xs:sequence>
"""
self.check_complex_restriction(
base, '<sequence minOccurs="3" maxOccurs="7"><element name="A"/></sequence>')
base, '<xs:sequence minOccurs="3" maxOccurs="7"><xs:element name="A"/></xs:sequence>')
self.check_complex_restriction(
base, '<sequence minOccurs="4" maxOccurs="10"><element name="A"/></sequence>')
base, '<xs:sequence minOccurs="4" maxOccurs="10"><xs:element name="A"/></xs:sequence>')
self.check_complex_restriction(
base, '<sequence minOccurs="3" maxOccurs="11"><element name="A"/></sequence>',
base, '<xs:sequence minOccurs="3" maxOccurs="11"><xs:element name="A"/></xs:sequence>',
XMLSchemaParseError
)
self.check_complex_restriction(
base, '<sequence minOccurs="2" maxOccurs="10"><element name="A"/></sequence>',
base, '<xs:sequence minOccurs="2" maxOccurs="10"><xs:element name="A"/></xs:sequence>',
XMLSchemaParseError
)
def test_union_restrictions(self):
# Wrong union restriction (not admitted facets, see issue #67)
self.check_schema(r"""
<simpleType name="Percentage">
<restriction base="ns:Integer">
<minInclusive value="0"/>
<maxInclusive value="100"/>
</restriction>
</simpleType>
<simpleType name="Integer">
<union memberTypes="int ns:IntegerString"/>
</simpleType>
<simpleType name="IntegerString">
<restriction base="string">
<pattern value="-?[0-9]+(\.[0-9]+)?%"/>
</restriction>
</simpleType>
""", XMLSchemaParseError)
<xs:simpleType name="Percentage">
<xs:restriction base="Integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="Integer">
<xs:union memberTypes="xs:int IntegerString"/>
</xs:simpleType>
<xs:simpleType name="IntegerString">
<xs:restriction base="xs:string">
<xs:pattern value="-?[0-9]+(\.[0-9]+)?%"/>
</xs:restriction>
</xs:simpleType>
""", XMLSchemaParseError)
def test_final_attribute(self):
self.check_schema("""
<simpleType name="aType" final="list restriction">
<restriction base="string"/>
</simpleType>
""")
<xs:simpleType name="aType" final="list restriction">
<xs:restriction base="xs:string"/>
</xs:simpleType>
""")
def test_wrong_attribute(self):
self.check_schema("""
<attributeGroup name="alpha">
<attribute name="name" type="string"/>
<attribute ref="phone"/> <!-- Missing "phone" attribute -->
</attributeGroup>
""", XMLSchemaParseError)
<xs:attributeGroup name="alpha">
<xs:attribute name="name" type="xs:string"/>
<xs:attribute ref="phone"/> <!-- Missing "phone" attribute -->
</xs:attributeGroup>
""", XMLSchemaParseError)
def test_wrong_attribute_group(self):
self.check_schema("""
<attributeGroup name="alpha">
<attribute name="name" type="string"/>
<attributeGroup ref="beta"/> <!-- Missing "beta" attribute group -->
</attributeGroup>
""", XMLSchemaParseError)
<xs:attributeGroup name="alpha">
<xs:attribute name="name" type="xs:string"/>
<xs:attributeGroup ref="beta"/> <!-- Missing "beta" attribute group -->
</xs:attributeGroup>
""", XMLSchemaParseError)
schema = self.check_schema("""
<attributeGroup name="alpha">
<attribute name="name" type="string"/>
<attributeGroup name="beta"/> <!-- attribute "name" instead of "ref" -->
</attributeGroup>
<xs:attributeGroup name="alpha">
<xs:attribute name="name" type="xs:string"/>
<xs:attributeGroup name="beta"/> <!-- attribute "name" instead of "ref" -->
</xs:attributeGroup>
""", validation='lax')
self.assertTrue(isinstance(schema.all_errors[1], XMLSchemaParseError))
def test_date_time_facets(self):
self.check_schema("""
<simpleType name="restricted_date">
<restriction base="date">
<minInclusive value="1900-01-01"/>
<maxInclusive value="2030-12-31"/>
</restriction>
</simpleType>""")
<xs:simpleType name="restricted_date">
<xs:restriction base="xs:date">
<xs:minInclusive value="1900-01-01"/>
<xs:maxInclusive value="2030-12-31"/>
</xs:restriction>
</xs:simpleType>""")
self.check_schema("""
<simpleType name="restricted_year">
<restriction base="gYear">
<minInclusive value="1900"/>
<maxInclusive value="2030"/>
</restriction>
</simpleType>""")
<xs:simpleType name="restricted_year">
<xs:restriction base="xs:gYear">
<xs:minInclusive value="1900"/>
<xs:maxInclusive value="2030"/>
</xs:restriction>
</xs:simpleType>""")
def test_base_schemas(self):
from xmlschema.validators.schema import XML_SCHEMA_FILE
@ -433,26 +476,26 @@ class TestXMLSchema10(XMLSchemaTestCase):
def test_upa_violations(self):
self.check_schema("""
<complexType name="typeA">
<sequence>
<sequence minOccurs="0" maxOccurs="unbounded">
<element name="A"/>
<element name="B"/>
</sequence>
<element name="A" minOccurs="0"/>
</sequence>
</complexType>""", XMLSchemaModelError)
<xs:complexType name="typeA">
<xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="A"/>
<xs:element name="B"/>
</xs:sequence>
<xs:element name="A" minOccurs="0"/>
</xs:sequence>
</xs:complexType>""", XMLSchemaModelError)
self.check_schema("""
<complexType name="typeA">
<sequence>
<sequence minOccurs="0" maxOccurs="unbounded">
<element name="B"/>
<element name="A"/>
</sequence>
<element name="A" minOccurs="0"/>
</sequence>
</complexType>""")
<xs:complexType name="typeA">
<xs:sequence>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="B"/>
<xs:element name="A"/>
</xs:sequence>
<xs:element name="A" minOccurs="0"/>
</xs:sequence>
</xs:complexType>""")
def test_root_elements(self):
# Test issue #107 fix
@ -471,10 +514,26 @@ class TestXMLSchema10(XMLSchemaTestCase):
def test_is_restriction_method(self):
# Test issue #111 fix
schema = self.schema_class(source=os.path.join(self.test_cases_dir, 'issues/issue_111/issue_111.xsd'))
schema = self.schema_class(source=self.casepath('issues/issue_111/issue_111.xsd'))
extended_header_def = schema.types['extendedHeaderDef']
self.assertTrue(extended_header_def.is_derived(schema.types['blockDef']))
@unittest.skipIf(SKIP_REMOTE_TESTS or platform.system() == 'Windows',
"Remote networks are not accessible or avoid SSL verification error on Windows.")
def test_remote_schemas_loading(self):
col_schema = self.schema_class("https://raw.githubusercontent.com/brunato/xmlschema/master/"
"xmlschema/tests/test_cases/examples/collection/collection.xsd")
self.assertTrue(isinstance(col_schema, self.schema_class))
vh_schema = self.schema_class("https://raw.githubusercontent.com/brunato/xmlschema/master/"
"xmlschema/tests/test_cases/examples/vehicles/vehicles.xsd")
self.assertTrue(isinstance(vh_schema, self.schema_class))
def test_schema_defuse(self):
vh_schema = self.schema_class(self.vh_xsd_file, defuse='always')
self.assertIsInstance(vh_schema.root, etree_element)
for schema in vh_schema.maps.iter_schemas():
self.assertIsInstance(schema.root, etree_element)
class TestXMLSchema11(TestXMLSchema10):
@ -482,21 +541,21 @@ class TestXMLSchema11(TestXMLSchema10):
def test_explicit_timezone_facet(self):
schema = self.check_schema("""
<simpleType name='opt-tz-date'>
<restriction base='date'>
<explicitTimezone value='optional'/>
</restriction>
</simpleType>
<simpleType name='req-tz-date'>
<restriction base='date'>
<explicitTimezone value='required'/>
</restriction>
</simpleType>
<simpleType name='no-tz-date'>
<restriction base='date'>
<explicitTimezone value='prohibited'/>
</restriction>
</simpleType>
<xs:simpleType name='opt-tz-date'>
<xs:restriction base='xs:date'>
<xs:explicitTimezone value='optional'/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='req-tz-date'>
<xs:restriction base='xs:date'>
<xs:explicitTimezone value='required'/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name='no-tz-date'>
<xs:restriction base='xs:date'>
<xs:explicitTimezone value='prohibited'/>
</xs:restriction>
</xs:simpleType>
""")
self.assertTrue(schema.types['req-tz-date'].is_valid('2002-10-10-05:00'))
self.assertTrue(schema.types['req-tz-date'].is_valid('2002-10-10Z'))
@ -504,42 +563,43 @@ class TestXMLSchema11(TestXMLSchema10):
def test_assertion_facet(self):
self.check_schema("""
<simpleType name='DimensionType'>
<restriction base='integer'>
<assertion test='string-length($value) &lt; 2'/>
</restriction>
</simpleType>""", XMLSchemaParseError)
<xs:simpleType name='DimensionType'>
<xs:restriction base='xs:integer'>
<xs:assertion test='string-length($value) &lt; 2'/>
</xs:restriction>
</xs:simpleType>""", XMLSchemaParseError)
schema = self.check_schema("""
<simpleType name='MeasureType'>
<restriction base='integer'>
<assertion test='$value &gt; 0'/>
</restriction>
</simpleType>""")
<xs:simpleType name='MeasureType'>
<xs:restriction base='xs:integer'>
<xs:assertion test='$value &gt; 0'/>
</xs:restriction>
</xs:simpleType>""")
self.assertTrue(schema.types['MeasureType'].is_valid('10'))
self.assertFalse(schema.types['MeasureType'].is_valid('-1.5'))
self.check_schema("""
<simpleType name='RestrictedDateTimeType'>
<restriction base='dateTime'>
<assertion test="$value > '1999-12-31T23:59:59'"/>
</restriction>
</simpleType>""", XMLSchemaParseError)
<xs:simpleType name='RestrictedDateTimeType'>
<xs:restriction base='xs:dateTime'>
<xs:assertion test="$value > '1999-12-31T23:59:59'"/>
</xs:restriction>
</xs:simpleType>""", XMLSchemaParseError)
schema = self.check_schema("""
<simpleType name='RestrictedDateTimeType'>
<restriction base='dateTime'>
<assertion test="$value > xs:dateTime('1999-12-31T23:59:59')"/>
</restriction>
</simpleType>""")
<xs:simpleType name='RestrictedDateTimeType'>
<xs:restriction base='xs:dateTime'>
<xs:assertion test="$value > xs:dateTime('1999-12-31T23:59:59')"/>
</xs:restriction>
</xs:simpleType>""")
self.assertTrue(schema.types['RestrictedDateTimeType'].is_valid('2000-01-01T12:00:00'))
schema = self.check_schema("""<simpleType name="Percentage">
<restriction base="integer">
<assertion test="$value >= 0"/>
<assertion test="$value &lt;= 100"/>
</restriction>
</simpleType>""")
schema = self.check_schema("""
<xs:simpleType name="Percentage">
<xs:restriction base="xs:integer">
<xs:assertion test="$value >= 0"/>
<xs:assertion test="$value &lt;= 100"/>
</xs:restriction>
</xs:simpleType>""")
self.assertTrue(schema.types['Percentage'].is_valid('10'))
self.assertTrue(schema.types['Percentage'].is_valid('100'))
self.assertTrue(schema.types['Percentage'].is_valid('0'))
@ -549,11 +609,11 @@ class TestXMLSchema11(TestXMLSchema10):
def test_complex_type_assertion(self):
schema = self.check_schema("""
<complexType name="intRange">
<attribute name="min" type="int"/>
<attribute name="max" type="int"/>
<assert test="@min le @max"/>
</complexType>""")
<xs:complexType name="intRange">
<xs:attribute name="min" type="xs:int"/>
<xs:attribute name="max" type="xs:int"/>
<xs:assert test="@min le @max"/>
</xs:complexType>""")
xsd_type = schema.types['intRange']
xsd_type.decode(etree_element('a', attrib={'min': '10', 'max': '19'}))
@ -564,20 +624,20 @@ class TestXMLSchema11(TestXMLSchema10):
def test_open_content(self):
self.check_schema("""
<element name="Book">
<complexType>
<openContent mode="interleave">
<any />
</openContent>
<sequence>
<element name="Title" type="string"/>
<element name="Author" type="string" />
<element name="Date" type="gYear"/>
<element name="ISBN" type="string"/>
<element name="Publisher" type="string"/>
</sequence>
</complexType>
</element>""")
<xs:element name="Book">
<xs:complexType>
<xs:openContent mode="interleave">
<xs:any />
</xs:openContent>
<xs:sequence>
<xs:element name="Title" type="xs:string"/>
<xs:element name="Author" type="xs:string" />
<xs:element name="Date" type="xs:gYear"/>
<xs:element name="ISBN" type="xs:string"/>
<xs:element name="Publisher" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>""")
def make_schema_test_class(test_file, test_args, test_num, schema_class, check_with_lxml):
@ -601,7 +661,7 @@ def make_schema_test_class(test_file, test_args, test_num, schema_class, check_w
defuse = test_args.defuse
debug_mode = test_args.debug
class TestSchema(XMLSchemaTestCase):
class TestSchema(XsdValidatorTestCase):
@classmethod
def setUpClass(cls):

View File

@ -33,7 +33,7 @@ from xmlschema.etree import etree_element, etree_tostring, is_etree_element, Ele
from xmlschema.helpers import local_name
from xmlschema.qnames import XSI_TYPE
from xmlschema.resources import fetch_namespaces
from xmlschema.tests import XMLSchemaTestCase, tests_factory
from xmlschema.tests import XsdValidatorTestCase, tests_factory
from xmlschema.validators import XMLSchema11
_VEHICLES_DICT = {
@ -305,7 +305,7 @@ def make_validator_test_class(test_file, test_args, test_num, schema_class, chec
skip_strict = test_args.skip
debug_mode = test_args.debug
class TestValidator(XMLSchemaTestCase):
class TestValidator(XsdValidatorTestCase):
@classmethod
def setUpClass(cls):
@ -567,7 +567,7 @@ def make_validator_test_class(test_file, test_args, test_num, schema_class, chec
return TestValidator
class TestValidation(XMLSchemaTestCase):
class TestValidation(XsdValidatorTestCase):
def check_validity(self, xsd_component, data, expected, use_defaults=True):
if isinstance(expected, type) and issubclass(expected, Exception):
@ -641,7 +641,7 @@ class TestValidation11(TestValidation):
"</tree>"))
class TestDecoding(XMLSchemaTestCase):
class TestDecoding(XsdValidatorTestCase):
def check_decode(self, xsd_component, data, expected, **kwargs):
if isinstance(expected, type) and issubclass(expected, Exception):
@ -751,20 +751,20 @@ class TestDecoding(XMLSchemaTestCase):
self.assertEqual(xd, _DATA_DICT)
def test_datetime_types(self):
xs = self.get_schema('<element name="dt" type="dateTime"/>')
self.assertEqual(xs.decode('<ns:dt xmlns:ns="ns">2019-01-01T13:40:00</ns:dt>'), '2019-01-01T13:40:00')
self.assertEqual(xs.decode('<ns:dt xmlns:ns="ns">2019-01-01T13:40:00</ns:dt>', datetime_types=True),
xs = self.get_schema('<xs:element name="dt" type="xs:dateTime"/>')
self.assertEqual(xs.decode('<dt>2019-01-01T13:40:00</dt>'), '2019-01-01T13:40:00')
self.assertEqual(xs.decode('<dt>2019-01-01T13:40:00</dt>', datetime_types=True),
datatypes.DateTime10.fromstring('2019-01-01T13:40:00'))
xs = self.get_schema('<element name="dt" type="date"/>')
self.assertEqual(xs.decode('<ns:dt xmlns:ns="ns">2001-04-15</ns:dt>'), '2001-04-15')
self.assertEqual(xs.decode('<ns:dt xmlns:ns="ns">2001-04-15</ns:dt>', datetime_types=True),
xs = self.get_schema('<xs:element name="dt" type="xs:date"/>')
self.assertEqual(xs.decode('<dt>2001-04-15</dt>'), '2001-04-15')
self.assertEqual(xs.decode('<dt>2001-04-15</dt>', datetime_types=True),
datatypes.Date10.fromstring('2001-04-15'))
def test_duration_type(self):
xs = self.get_schema('<element name="td" type="duration"/>')
self.assertEqual(xs.decode('<ns:td xmlns:ns="ns">P5Y3MT60H30.001S</ns:td>'), 'P5Y3MT60H30.001S')
self.assertEqual(xs.decode('<ns:td xmlns:ns="ns">P5Y3MT60H30.001S</ns:td>', datetime_types=True),
xs = self.get_schema('<xs:element name="td" type="xs:duration"/>')
self.assertEqual(xs.decode('<td>P5Y3MT60H30.001S</td>'), 'P5Y3MT60H30.001S')
self.assertEqual(xs.decode('<td>P5Y3MT60H30.001S</td>', datetime_types=True),
datatypes.Duration.fromstring('P5Y3M2DT12H30.001S'))
def test_default_converter(self):
@ -874,20 +874,20 @@ class TestDecoding(XMLSchemaTestCase):
def test_decimal_type(self):
schema = self.get_schema("""
<element name="A" type="ns:A_type" />
<simpleType name="A_type">
<restriction base="decimal">
<minInclusive value="100.50"/>
</restriction>
</simpleType>
<xs:element name="A" type="A_type" />
<xs:simpleType name="A_type">
<xs:restriction base="xs:decimal">
<xs:minInclusive value="100.50"/>
</xs:restriction>
</xs:simpleType>
""")
self.check_decode(schema, '<A xmlns="ns">120.48</A>', Decimal('120.48'))
self.check_decode(schema, '<A xmlns="ns">100.50</A>', Decimal('100.50'), process_namespaces=False)
self.check_decode(schema, '<A xmlns="ns">100.49</A>', XMLSchemaValidationError)
self.check_decode(schema, '<A xmlns="ns">120.48</A>', 120.48, decimal_type=float)
self.check_decode(schema, '<A>120.48</A>', Decimal('120.48'))
self.check_decode(schema, '<A>100.50</A>', Decimal('100.50'), process_namespaces=False)
self.check_decode(schema, '<A>100.49</A>', XMLSchemaValidationError)
self.check_decode(schema, '<A>120.48</A>', 120.48, decimal_type=float)
# Issue #66
self.check_decode(schema, '<A xmlns="ns">120.48</A>', '120.48', decimal_type=str)
self.check_decode(schema, '<A>120.48</A>', '120.48', decimal_type=str)
def test_nillable(self):
# Issue #76
@ -1002,7 +1002,7 @@ class TestDecoding(XMLSchemaTestCase):
{'@int_attr': 'wrong', '$': 20})
def test_error_message(self):
schema = self.schema_class(os.path.join(self.test_cases_dir, 'issues/issue_115/Rotation.xsd'))
schema = self.schema_class(self.casepath('issues/issue_115/Rotation.xsd'))
rotation_data = '<tns:rotation xmlns:tns="http://www.example.org/Rotation/" ' \
'pitch="0.0" roll="0.0" yaw="-1.0" />'
@ -1022,26 +1022,26 @@ class TestDecoding11(TestDecoding):
schema_class = XMLSchema11
def test_datetime_types(self):
xs = self.get_schema('<element name="dt" type="dateTime"/>')
self.assertEqual(xs.decode('<ns:dt xmlns:ns="ns">2019-01-01T13:40:00</ns:dt>'), '2019-01-01T13:40:00')
self.assertEqual(xs.decode('<ns:dt xmlns:ns="ns">2019-01-01T13:40:00</ns:dt>', datetime_types=True),
xs = self.get_schema('<xs:element name="dt" type="xs:dateTime"/>')
self.assertEqual(xs.decode('<dt>2019-01-01T13:40:00</dt>'), '2019-01-01T13:40:00')
self.assertEqual(xs.decode('<dt>2019-01-01T13:40:00</dt>', datetime_types=True),
datatypes.DateTime.fromstring('2019-01-01T13:40:00'))
xs = self.get_schema('<element name="dt" type="date"/>')
self.assertEqual(xs.decode('<ns:dt xmlns:ns="ns">2001-04-15</ns:dt>'), '2001-04-15')
self.assertEqual(xs.decode('<ns:dt xmlns:ns="ns">2001-04-15</ns:dt>', datetime_types=True),
xs = self.get_schema('<xs:element name="dt" type="xs:date"/>')
self.assertEqual(xs.decode('<dt>2001-04-15</dt>'), '2001-04-15')
self.assertEqual(xs.decode('<dt>2001-04-15</dt>', datetime_types=True),
datatypes.Date.fromstring('2001-04-15'))
def test_derived_duration_types(self):
xs = self.get_schema('<element name="td" type="yearMonthDuration"/>')
self.assertEqual(xs.decode('<ns:td xmlns:ns="ns">P0Y4M</ns:td>'), 'P0Y4M')
self.assertEqual(xs.decode('<ns:td xmlns:ns="ns">P2Y10M</ns:td>', datetime_types=True),
xs = self.get_schema('<xs:element name="td" type="xs:yearMonthDuration"/>')
self.assertEqual(xs.decode('<td>P0Y4M</td>'), 'P0Y4M')
self.assertEqual(xs.decode('<td>P2Y10M</td>', datetime_types=True),
datatypes.Duration.fromstring('P2Y10M'))
xs = self.get_schema('<element name="td" type="dayTimeDuration"/>')
self.assertEqual(xs.decode('<ns:td xmlns:ns="ns">P2DT6H30M30.001S</ns:td>'), 'P2DT6H30M30.001S')
self.assertEqual(xs.decode('<ns:td xmlns:ns="ns">P2DT26H</ns:td>'), 'P2DT26H')
self.assertEqual(xs.decode('<ns:td xmlns:ns="ns">P2DT6H30M30.001S</ns:td>', datetime_types=True),
xs = self.get_schema('<xs:element name="td" type="xs:dayTimeDuration"/>')
self.assertEqual(xs.decode('<td>P2DT6H30M30.001S</td>'), 'P2DT6H30M30.001S')
self.assertEqual(xs.decode('<td>P2DT26H</td>'), 'P2DT26H')
self.assertEqual(xs.decode('<td>P2DT6H30M30.001S</td>', datetime_types=True),
datatypes.Duration.fromstring('P2DT6H30M30.001S'))
def test_type_alternatives(self):
@ -1064,7 +1064,7 @@ class TestDecoding11(TestDecoding):
self.assertTrue(xs.is_valid('<ns:value xmlns:ns="ns" choice="bool">true</ns:value>'))
class TestEncoding(XMLSchemaTestCase):
class TestEncoding(XsdValidatorTestCase):
def check_encode(self, xsd_component, data, expected, **kwargs):
if isinstance(expected, type) and issubclass(expected, Exception):
@ -1191,77 +1191,77 @@ class TestEncoding(XMLSchemaTestCase):
self.check_encode(boolean_or_integer_or_string, "Venice ", u'Venice ')
def test_simple_elements(self):
elem = etree_element('{ns}A')
elem = etree_element('A')
elem.text = '89'
self.check_encode(self.get_element('A', type='string'), '89', elem)
self.check_encode(self.get_element('A', type='integer'), 89, elem)
self.check_encode(self.get_element('A', type='xs:string'), '89', elem)
self.check_encode(self.get_element('A', type='xs:integer'), 89, elem)
elem.text = '-10.4'
self.check_encode(self.get_element('A', type='float'), -10.4, elem)
self.check_encode(self.get_element('A', type='xs:float'), -10.4, elem)
elem.text = 'false'
self.check_encode(self.get_element('A', type='boolean'), False, elem)
self.check_encode(self.get_element('A', type='xs:boolean'), False, elem)
elem.text = 'true'
self.check_encode(self.get_element('A', type='boolean'), True, elem)
self.check_encode(self.get_element('A', type='xs:boolean'), True, elem)
self.check_encode(self.get_element('A', type='short'), 128000, XMLSchemaValidationError)
self.check_encode(self.get_element('A', type='xs:short'), 128000, XMLSchemaValidationError)
elem.text = '0'
self.check_encode(self.get_element('A', type='nonNegativeInteger'), 0, elem)
self.check_encode(self.get_element('A', type='nonNegativeInteger'), '0', XMLSchemaValidationError)
self.check_encode(self.get_element('A', type='positiveInteger'), 0, XMLSchemaValidationError)
self.check_encode(self.get_element('A', type='xs:nonNegativeInteger'), 0, elem)
self.check_encode(self.get_element('A', type='xs:nonNegativeInteger'), '0', XMLSchemaValidationError)
self.check_encode(self.get_element('A', type='xs:positiveInteger'), 0, XMLSchemaValidationError)
elem.text = '-1'
self.check_encode(self.get_element('A', type='negativeInteger'), -1, elem)
self.check_encode(self.get_element('A', type='nonNegativeInteger'), -1, XMLSchemaValidationError)
self.check_encode(self.get_element('A', type='xs:negativeInteger'), -1, elem)
self.check_encode(self.get_element('A', type='xs:nonNegativeInteger'), -1, XMLSchemaValidationError)
def test_complex_elements(self):
schema = self.get_schema("""
<element name="A" type="ns:A_type" />
<complexType name="A_type" mixed="true">
<simpleContent>
<extension base="string">
<attribute name="a1" type="short" use="required"/>
<attribute name="a2" type="negativeInteger"/>
</extension>
</simpleContent>
</complexType>
<xs:element name="A" type="A_type" />
<xs:complexType name="A_type" mixed="true">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="a1" type="xs:short" use="required"/>
<xs:attribute name="a2" type="xs:negativeInteger"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
""")
self.check_encode(
schema.elements['A'], data={'@a1': 10, '@a2': -1, '$': 'simple '},
expected='<ns:A xmlns:ns="ns" a1="10" a2="-1">simple </ns:A>',
expected='<A a1="10" a2="-1">simple </A>',
)
self.check_encode(
schema.elements['A'], {'@a1': 10, '@a2': -1, '$': 'simple '},
ElementTree.fromstring('<A xmlns="ns" a1="10" a2="-1">simple </A>'),
ElementTree.fromstring('<A a1="10" a2="-1">simple </A>'),
)
self.check_encode(
schema.elements['A'], {'@a1': 10, '@a2': -1},
ElementTree.fromstring('<A xmlns="ns" a1="10" a2="-1"/>')
ElementTree.fromstring('<A a1="10" a2="-1"/>')
)
self.check_encode(
schema.elements['A'], {'@a1': 10, '$': 'simple '},
ElementTree.fromstring('<A xmlns="ns" a1="10">simple </A>')
ElementTree.fromstring('<A a1="10">simple </A>')
)
self.check_encode(schema.elements['A'], {'@a2': -1, '$': 'simple '}, XMLSchemaValidationError)
schema = self.get_schema("""
<element name="A" type="ns:A_type" />
<complexType name="A_type">
<sequence>
<element name="B1" type="string"/>
<element name="B2" type="integer"/>
<element name="B3" type="boolean"/>
</sequence>
</complexType>
<xs:element name="A" type="A_type" />
<xs:complexType name="A_type">
<xs:sequence>
<xs:element name="B1" type="xs:string"/>
<xs:element name="B2" type="xs:integer"/>
<xs:element name="B3" type="xs:boolean"/>
</xs:sequence>
</xs:complexType>
""")
self.check_encode(
xsd_component=schema.elements['A'],
data=ordered_dict_class([('B1', 'abc'), ('B2', 10), ('B3', False)]),
expected=u'<ns:A xmlns:ns="ns">\n<B1>abc</B1>\n<B2>10</B2>\n<B3>false</B3>\n</ns:A>',
expected=u'<A>\n<B1>abc</B1>\n<B2>10</B2>\n<B3>false</B3>\n</A>',
indent=0,
)
self.check_encode(schema.elements['A'], {'B1': 'abc', 'B2': 10, 'B4': False}, XMLSchemaValidationError)
self.check_encode(
xsd_component=schema.elements['A'],
data=ordered_dict_class([('B1', 'abc'), ('B2', 10), ('#1', 'hello'), ('B3', True)]),
expected=u'<ns:A xmlns:ns="ns">\n<B1>abc</B1>\n<B2>10</B2>\nhello\n<B3>true</B3>\n</ns:A>',
expected=u'<A>\n<B1>abc</B1>\n<B2>10</B2>\nhello\n<B3>true</B3>\n</A>',
indent=0, cdata_prefix='#'
)
self.check_encode(
@ -1271,48 +1271,32 @@ class TestEncoding(XMLSchemaTestCase):
)
def test_encode_datetime(self):
xs = self.get_schema('<element name="dt" type="dateTime"/>')
dt = xs.decode('<ns:dt xmlns:ns="ns">2019-01-01T13:40:00</ns:dt>', datetime_types=True)
self.assertEqual(
etree_tostring(xs.encode(dt)),
'<ns:dt xmlns:ns="ns">2019-01-01T13:40:00</ns:dt>'
)
xs = self.get_schema('<xs:element name="dt" type="xs:dateTime"/>')
dt = xs.decode('<dt>2019-01-01T13:40:00</dt>', datetime_types=True)
self.assertEqual(etree_tostring(xs.encode(dt)), '<dt>2019-01-01T13:40:00</dt>')
def test_encode_date(self):
xs = self.get_schema('<element name="dt" type="date"/>')
date = xs.decode('<ns:dt xmlns:ns="ns">2001-04-15</ns:dt>', datetime_types=True)
self.assertEqual(
etree_tostring(xs.encode(date)),
'<ns:dt xmlns:ns="ns">2001-04-15</ns:dt>'
)
xs = self.get_schema('<xs:element name="dt" type="xs:date"/>')
date = xs.decode('<dt>2001-04-15</dt>', datetime_types=True)
self.assertEqual(etree_tostring(xs.encode(date)), '<dt>2001-04-15</dt>')
def test_duration(self):
xs = self.get_schema('<element name="td" type="duration"/>')
duration = xs.decode('<ns:td xmlns:ns="ns">P5Y3MT60H30.001S</ns:td>', datetime_types=True)
self.assertEqual(
etree_tostring(xs.encode(duration)),
'<ns:td xmlns:ns="ns">P5Y3M2DT12H30.001S</ns:td>'
)
xs = self.get_schema('<xs:element name="td" type="xs:duration"/>')
duration = xs.decode('<td>P5Y3MT60H30.001S</td>', datetime_types=True)
self.assertEqual(etree_tostring(xs.encode(duration)), '<td>P5Y3M2DT12H30.001S</td>')
def test_gregorian_year(self):
xs = self.get_schema('<element name="td" type="gYear"/>')
gyear = xs.decode('<ns:td xmlns:ns="ns">2000</ns:td>', datetime_types=True)
self.assertEqual(
etree_tostring(xs.encode(gyear)),
'<ns:td xmlns:ns="ns">2000</ns:td>'
)
xs = self.get_schema('<xs:element name="td" type="xs:gYear"/>')
gyear = xs.decode('<td>2000</td>', datetime_types=True)
self.assertEqual(etree_tostring(xs.encode(gyear)), '<td>2000</td>')
def test_gregorian_yearmonth(self):
xs = self.get_schema('<element name="td" type="gYearMonth"/>')
gyear_month = xs.decode('<ns:td xmlns:ns="ns">2000-12</ns:td>', datetime_types=True)
self.assertEqual(
etree_tostring(xs.encode(gyear_month)),
'<ns:td xmlns:ns="ns">2000-12</ns:td>'
)
xs = self.get_schema('<xs:element name="td" type="xs:gYearMonth"/>')
gyear_month = xs.decode('<td>2000-12</td>', datetime_types=True)
self.assertEqual(etree_tostring(xs.encode(gyear_month)), '<td>2000-12</td>')
def test_error_message(self):
schema = self.schema_class(os.path.join(self.test_cases_dir, 'issues/issue_115/Rotation.xsd'))
schema = self.schema_class(self.casepath('issues/issue_115/Rotation.xsd'))
rotation_data = {
"@roll": 0.0,
"@pitch": 0.0,

View File

@ -18,15 +18,15 @@ import xml.etree.ElementTree as ElementTree
from elementpath import XPath1Parser, Selector, ElementPathSyntaxError
from xmlschema import XMLSchema
from xmlschema.tests import XMLSchemaTestCase
from xmlschema.tests import casepath
class XsdXPathTest(XMLSchemaTestCase):
class XsdXPathTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.xs1 = XMLSchema(cls.casepath("examples/vehicles/vehicles.xsd"))
cls.xs2 = XMLSchema(cls.casepath("examples/collection/collection.xsd"))
cls.xs1 = XMLSchema(casepath("examples/vehicles/vehicles.xsd"))
cls.xs2 = XMLSchema(casepath("examples/collection/collection.xsd"))
cls.cars = cls.xs1.elements['vehicles'].type.content_type[0]
cls.bikes = cls.xs1.elements['vehicles'].type.content_type[1]