# -*- 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__)