# -*- coding: utf-8 -*-
"""
Test cases related to XML Schema parsing and validation
"""
from __future__ import absolute_import
import unittest
from .common_imports import etree, BytesIO, HelperTestCase, fileInTestDir, make_doctest, SimpleFSPath
class ETreeXMLSchemaTestCase(HelperTestCase):
def test_xmlschema(self):
tree_valid = self.parse('')
tree_invalid = self.parse('')
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
self.assertTrue(schema.validate(tree_valid))
self.assertFalse(schema.validate(tree_invalid))
self.assertTrue(schema.validate(tree_valid)) # retry valid
self.assertFalse(schema.validate(tree_invalid)) # retry invalid
def test_xmlschema_error_log(self):
tree_valid = self.parse('')
tree_invalid = self.parse('')
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
self.assertTrue(schema.validate(tree_valid))
self.assertFalse(schema.error_log.filter_from_errors())
self.assertFalse(schema.validate(tree_invalid))
self.assertTrue(schema.error_log.filter_from_errors())
self.assertTrue(schema.error_log.filter_types(
etree.ErrorTypes.SCHEMAV_ELEMENT_CONTENT))
self.assertTrue(schema.validate(tree_valid))
self.assertFalse(schema.error_log.filter_from_errors())
self.assertFalse(schema.validate(tree_invalid))
self.assertTrue(schema.error_log.filter_from_errors())
self.assertTrue(schema.error_log.filter_types(
etree.ErrorTypes.SCHEMAV_ELEMENT_CONTENT))
def test_xmlschema_error_log_path(self):
"""We don't have a guarantee that there will always be a path
for a _LogEntry object (or even a node for which to determine
a path), but at least when this test was created schema validation
errors always got a node and an XPath value. If that ever changes,
we can modify this test to something like::
self.assertTrue(error_path is None or tree_path == error_path)
That way, we can at least verify that if we did get a path value
it wasn't bogus.
"""
tree = self.parse('42dada')
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
schema.validate(tree)
tree_path = tree.getpath(tree.findall('b')[1])
error_path = schema.error_log[0].path
self.assertTrue(tree_path == error_path)
def test_xmlschema_default_attributes(self):
schema = self.parse('''
''')
schema = etree.XMLSchema(schema, attribute_defaults=True)
tree = self.parse('')
root = tree.getroot()
self.assertEqual('ho', root[0].get('hardy'))
self.assertEqual(None, root[1].get('hardy'))
self.assertEqual('ho', root[2].get('hardy'))
self.assertEqual(None, root[3].get('hardy'))
self.assertTrue(schema(tree))
root = tree.getroot()
self.assertEqual('ho', root[0].get('hardy'))
self.assertEqual('hey', root[1].get('hardy'))
self.assertEqual('ho', root[2].get('hardy'))
self.assertEqual('hey', root[3].get('hardy'))
def test_xmlschema_parse(self):
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
parser = etree.XMLParser(schema=schema)
tree_valid = self.parse('', parser=parser)
self.assertEqual('a', tree_valid.getroot().tag)
self.assertRaises(etree.XMLSyntaxError,
self.parse, '', parser=parser)
def test_xmlschema_parse_default_attributes(self):
# does not work as of libxml2 2.7.3
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
parser = etree.XMLParser(schema=schema, attribute_defaults=True)
tree_valid = self.parse('',
parser=parser)
root = tree_valid.getroot()
self.assertEqual('ho', root[0].get('hardy'))
self.assertEqual('hey', root[1].get('hardy'))
self.assertEqual('ho', root[2].get('hardy'))
self.assertEqual('hey', root[3].get('hardy'))
def test_xmlschema_parse_default_attributes_schema_config(self):
# does not work as of libxml2 2.7.3
schema = self.parse('''
''')
schema = etree.XMLSchema(schema, attribute_defaults=True)
parser = etree.XMLParser(schema=schema)
tree_valid = self.parse('',
parser=parser)
root = tree_valid.getroot()
self.assertEqual('ho', root[0].get('hardy'))
self.assertEqual('hey', root[1].get('hardy'))
self.assertEqual('ho', root[2].get('hardy'))
self.assertEqual('hey', root[3].get('hardy'))
def test_xmlschema_parse_fixed_attributes(self):
# does not work as of libxml2 2.7.3
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
parser = etree.XMLParser(schema=schema, attribute_defaults=True)
tree_valid = self.parse('',
parser=parser)
root = tree_valid.getroot()
self.assertEqual('hey', root[0].get('hardy'))
self.assertEqual('hey', root[1].get('hardy'))
self.assertEqual('hey', root[2].get('hardy'))
def test_xmlschema_stringio(self):
schema_file = BytesIO('''
''')
schema = etree.XMLSchema(file=schema_file)
parser = etree.XMLParser(schema=schema)
tree_valid = self.parse('', parser=parser)
self.assertEqual('a', tree_valid.getroot().tag)
self.assertRaises(etree.XMLSyntaxError,
self.parse, '', parser=parser)
def test_xmlschema_iterparse(self):
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
xml = BytesIO('')
events = [ (event, el.tag)
for (event, el) in etree.iterparse(xml, schema=schema) ]
self.assertEqual([('end', 'b'), ('end', 'a')],
events)
def test_xmlschema_iterparse_incomplete(self):
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
xml = BytesIO('')
event, element = next(iter(etree.iterparse(xml, schema=schema)))
self.assertEqual('end', event)
self.assertEqual('b', element.tag)
def test_xmlschema_iterparse_fail(self):
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
self.assertRaises(
etree.XMLSyntaxError,
list, etree.iterparse(BytesIO(''), schema=schema))
def test_xmlschema_elementtree_error(self):
self.assertRaises(ValueError, etree.XMLSchema, etree.ElementTree())
def test_xmlschema_comment_error(self):
self.assertRaises(ValueError, etree.XMLSchema, etree.Comment('TEST'))
def test_xmlschema_illegal_validation_error(self):
schema = self.parse('''
''')
schema = etree.XMLSchema(schema)
root = etree.Element('a')
root.text = 'TEST'
self.assertTrue(schema(root))
self.assertRaises(ValueError, schema, etree.Comment('TEST'))
self.assertRaises(ValueError, schema, etree.PI('a', 'text'))
self.assertRaises(ValueError, schema, etree.Entity('text'))
def test_xmlschema_invalid_schema1(self):
schema = self.parse('''\
''')
self.assertRaises(etree.XMLSchemaParseError,
etree.XMLSchema, schema)
def test_xmlschema_invalid_schema2(self):
schema = self.parse('')
self.assertRaises(etree.XMLSchemaParseError,
etree.XMLSchema, schema)
def test_xmlschema_file(self):
# this will only work if we access the file through path or
# file object..
f = open(fileInTestDir('test.xsd'), 'rb')
try:
schema = etree.XMLSchema(file=f)
finally:
f.close()
tree_valid = self.parse('')
self.assertTrue(schema.validate(tree_valid))
def test_xmlschema_import_file(self):
# this will only work if we access the file through path or
# file object..
schema = etree.XMLSchema(file=fileInTestDir('test_import.xsd'))
tree_valid = self.parse(
'')
self.assertTrue(schema.validate(tree_valid))
def test_xmlschema_shortcut(self):
tree_valid = self.parse('')
tree_invalid = self.parse('')
schema = self.parse('''\
''')
self.assertTrue(tree_valid.xmlschema(schema))
self.assertFalse(tree_invalid.xmlschema(schema))
def test_create_from_partial_doc(self):
# this used to crash because the schema part was not properly copied out
wsdl = self.parse('''\
''')
schema_element = wsdl.find(
"{http://schemas.xmlsoap.org/wsdl/}types/"
"{http://www.w3.org/2001/XMLSchema}schema"
)
etree.XMLSchema(schema_element)
etree.XMLSchema(schema_element)
etree.XMLSchema(schema_element)
def test_xmlschema_pathlike(self):
schema = etree.XMLSchema(file=SimpleFSPath(fileInTestDir('test.xsd')))
tree_valid = self.parse('')
self.assertTrue(schema.validate(tree_valid))
class ETreeXMLSchemaResolversTestCase(HelperTestCase):
resolver_schema_int = BytesIO("""\
""")
resolver_schema_int2 = BytesIO("""\
""")
resolver_schema_ext = """\
"""
class simple_resolver(etree.Resolver):
def __init__(self, schema):
self.schema = schema
def resolve(self, url, id, context):
assert url == 'XXX.xsd'
return self.resolve_string(self.schema, context)
# tests:
def test_xmlschema_resolvers(self):
# test that resolvers work with schema.
parser = etree.XMLParser()
parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
schema = etree.XMLSchema(schema_doc)
def test_xmlschema_resolvers_root(self):
# test that the default resolver will get called if there's no
# specific parser resolver.
root_resolver = self.simple_resolver(self.resolver_schema_ext)
etree.get_default_parser().resolvers.add(root_resolver)
schema_doc = etree.parse(self.resolver_schema_int)
schema = etree.XMLSchema(schema_doc)
etree.get_default_parser().resolvers.remove(root_resolver)
def test_xmlschema_resolvers_noroot(self):
# test that the default resolver will not get called when a
# more specific resolver is registered.
class res_root(etree.Resolver):
def resolve(self, url, id, context):
assert False
return None
root_resolver = res_root()
etree.get_default_parser().resolvers.add(root_resolver)
parser = etree.XMLParser()
parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
schema = etree.XMLSchema(schema_doc)
etree.get_default_parser().resolvers.remove(root_resolver)
def test_xmlschema_nested_resolvers(self):
# test that resolvers work in a nested fashion.
resolver_schema = self.resolver_schema_ext
class res_nested(etree.Resolver):
def __init__(self, ext_schema):
self.ext_schema = ext_schema
def resolve(self, url, id, context):
assert url == 'YYY.xsd'
return self.resolve_string(self.ext_schema, context)
class res(etree.Resolver):
def __init__(self, ext_schema_1, ext_schema_2):
self.ext_schema_1 = ext_schema_1
self.ext_schema_2 = ext_schema_2
def resolve(self, url, id, context):
assert url == 'XXX.xsd'
new_parser = etree.XMLParser()
new_parser.resolvers.add(res_nested(self.ext_schema_2))
new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser)
new_schema = etree.XMLSchema(new_schema_doc)
return self.resolve_string(resolver_schema, context)
parser = etree.XMLParser()
parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext))
schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
schema = etree.XMLSchema(schema_doc)
def test_suite():
suite = unittest.TestSuite()
suite.addTests([unittest.makeSuite(ETreeXMLSchemaTestCase)])
suite.addTests([unittest.makeSuite(ETreeXMLSchemaResolversTestCase)])
suite.addTests(
[make_doctest('../../../doc/validation.txt')])
return suite
if __name__ == '__main__':
print('to test use test.py %s' % __file__)