debian-xmlschema/xmlschema/tests/test_models.py

806 lines
33 KiB
Python

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c), 2016-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>
#
"""
This module runs tests concerning model groups validation.
"""
import unittest
from xmlschema import XMLSchema10, XMLSchema11
from xmlschema.validators import ModelVisitor
from xmlschema.compat import ordered_dict_class
from xmlschema.tests import casepath, XsdValidatorTestCase
class TestModelValidation(XsdValidatorTestCase):
# --- Test helper functions ---
def check_advance_true(self, model, expected=None):
"""
Advances a model with a match condition and checks the expected error list or exception.
:param model: an ModelGroupVisitor instance.
:param expected: can be an exception class or a list. Leaving `None` means that an empty \
list is expected.
"""
if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected, lambda x: list(model.advance(x)), True)
else:
self.assertEqual([e for e in model.advance(True)], expected or [])
def check_advance_false(self, model, expected=None):
"""
Advances a model with a no-match condition and checks the expected error list or or exception.
:param model: an ModelGroupVisitor instance.
:param expected: can be an exception class or a list. Leaving `None` means that an empty \
list is expected.
"""
if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected, lambda x: list(model.advance(x)), False)
else:
self.assertEqual([e for e in model.advance(False)], expected or [])
def check_advance(self, model, match, expected=None):
"""
Advances a model with an argument match condition and checks the expected error list.
:param model: an ModelGroupVisitor instance.
:param match: the matching boolean condition.
:param expected: can be an exception class or a list. Leaving `None` means that an empty \
list is expected.
"""
if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected, lambda x: list(model.advance(x)), match)
else:
self.assertEqual([e for e in model.advance(match)], expected or [])
def check_stop(self, model, expected=None):
"""
Stops a model and checks the expected errors list.
:param model: an ModelGroupVisitor instance.
:param expected: can be an exception class or a list. Leaving `None` means that an empty \
list is expected.
"""
if isinstance(expected, type) and issubclass(expected, Exception):
self.assertRaises(expected, lambda: list(model.stop()))
else:
self.assertEqual([e for e in model.stop()], expected or [])
# --- Vehicles schema ---
def test_vehicles_model(self):
# Sequence with two not-emptiable single-occurs elements
group = self.vh_schema.elements['vehicles'].type.content_type
model = ModelVisitor(group)
self.check_advance_true(model) # <cars>
self.check_advance_true(model) # <bikes>
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_true(model) # <cars>
self.check_advance_true(model) # <bikes>
self.check_advance_true(model, ValueError) # <bikes>
self.assertIsNone(model.element)
def test_cars_model(self):
# Emptiable 1:1 sequence with one emptiable and unlimited element.
group = self.vh_schema.elements['cars'].type.content_type
model = ModelVisitor(group)
self.check_advance_true(model) # <car>
self.check_advance_true(model) # <car>
self.check_advance_true(model) # <car>
self.check_advance_false(model) # (end)
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_false(model) # <not-a-car>
self.assertIsNone(model.element)
# --- Collection schema ---
def test_collection_model(self):
# Sequence with one not-emptiable and unlimited element.
group = self.col_schema.elements['collection'].type.content_type
model = ModelVisitor(group)
self.check_advance_true(model) # <car>
self.check_advance_true(model) # <car>
self.check_advance_true(model) # <car>
self.check_advance_true(model) # <car>
self.check_advance_false(model) # (end)
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_false(model, [(group[0], 0, [group[0]])]) # <not-a-car>
self.assertIsNone(model.element)
def test_person_type_model(self):
# Sequence with four single elements, last two are also emptiable.
group = self.col_schema.types['personType'].content_type
model = ModelVisitor(group)
self.check_advance_true(model) # <name>
self.check_advance_true(model) # <born>
self.check_advance_true(model) # <dead>
self.check_advance_true(model) # <qualification>
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_true(model) # <name>
self.check_advance_true(model) # <born>
self.check_stop(model)
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_true(model) # <name> match
self.check_advance_false(model, [(group[1], 0, [group[1]])]) # <born> missing!
self.check_advance_true(model) # <dead> match
self.check_stop(model) # <qualification> is optional
self.assertIsNone(model.element)
# --- XSD 1.0/1.1 meta-schema models ---
def test_meta_simple_derivation_model(self):
"""
<xs:group name="simpleDerivation">
<xs:choice>
<xs:element ref="xs:restriction"/>
<xs:element ref="xs:list"/>
<xs:element ref="xs:union"/>
</xs:choice>
</xs:group>
"""
group = XMLSchema10.meta_schema.groups['simpleDerivation']
model = ModelVisitor(group)
self.check_advance_true(model) # <restriction> match
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_false(model) # <list> not match with <restriction>
self.check_advance_true(model) # <list> match
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_false(model) # <union> not match with <restriction>
self.check_advance_false(model) # <union> not match with <list>
self.check_advance_true(model) # <union> match
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_false(model) # <other> not match with <restriction>
self.check_advance_false(model) # <other> not match with <list>
self.check_advance_false(model, [(group, 0, group[:])]) # <other> not match with <union>
self.assertIsNone(model.element)
def test_meta_simple_restriction_model(self):
"""
<!-- XSD 1.0 -->
<xs:group name="facets">
<xs:choice>
<xs:element ref="xs:minExclusive"/>
<xs:element ref="xs:minInclusive"/>
<xs:element ref="xs:maxExclusive"/>
<xs:element ref="xs:maxInclusive"/>
<xs:element ref="xs:totalDigits"/>
<xs:element ref="xs:fractionDigits"/>
<xs:element ref="xs:length"/>
<xs:element ref="xs:minLength"/>
<xs:element ref="xs:maxLength"/>
<xs:element ref="xs:enumeration"/>
<xs:element ref="xs:whiteSpace"/>
<xs:element ref="xs:pattern"/>
</xs:choice>
</xs:group>
<xs:group name="simpleRestrictionModel">
<xs:sequence>
<xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/>
<xs:group ref="xs:facets" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:group>
<!-- XSD 1.1 -->
<xs:group name="simpleRestrictionModel">
<xs:sequence>
<xs:element name="simpleType" type="xs:localSimpleType" minOccurs="0"/>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="xs:facet"/> <!-- Use a substitution group -->
<xs:any processContents="lax" namespace="##other"/>
</xs:choice>
</xs:sequence>
</xs:group>
"""
# Sequence with an optional single element and an optional unlimited choice.
group = self.schema_class.meta_schema.groups['simpleRestrictionModel']
model = ModelVisitor(group)
if self.schema_class.XSD_VERSION == '1.0':
self.assertEqual(model.element, group[0])
self.check_advance_true(model) # <simpleType> match
self.assertEqual(model.element, group[1][0][0])
self.check_advance_false(model) # <maxExclusive> do not match
self.assertEqual(model.element, group[1][0][1])
self.check_advance_false(model) # <maxExclusive> do not match
self.assertEqual(model.element, group[1][0][2])
self.check_advance_true(model) # <maxExclusive> match
self.assertEqual(model.element, group[1][0][0])
for _ in range(12):
self.check_advance_false(model) # no match for all the inner choice group "xs:facets"
self.assertIsNone(model.element)
def test_meta_schema_top_model(self):
"""
<xs:group name="schemaTop">
<xs:choice>
<xs:group ref="xs:redefinable"/>
<xs:element ref="xs:element"/>
<xs:element ref="xs:attribute"/>
<xs:element ref="xs:notation"/>
</xs:choice>
</xs:group>
<xs:group name="redefinable">
<xs:choice>
<xs:element ref="xs:simpleType"/>
<xs:element ref="xs:complexType"/>
<xs:element ref="xs:group"/>
<xs:element ref="xs:attributeGroup"/>
</xs:choice>
</xs:group>
"""
group = self.schema_class.meta_schema.groups['schemaTop']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0][0][0])
self.check_advance_false(model) # <simpleType> don't match
self.assertEqual(model.element, group[0][0][1])
self.check_advance_true(model) # <complexType> match
self.assertIsNone(model.element)
model.restart()
self.assertEqual(model.element, group[0][0][0])
self.check_advance_false(model) # <simpleType> don't match
self.assertEqual(model.element, group[0][0][1])
self.check_advance_false(model) # <complexType> don't match
self.assertEqual(model.element, group[0][0][2])
self.check_advance_false(model) # <group> don't match
self.assertEqual(model.element, group[0][0][3])
self.check_advance_false(model) # <attributeGroup> don't match
self.assertEqual(model.element, group[1])
self.check_advance_false(model) # <element> don't match
self.assertEqual(model.element, group[2])
self.check_advance_false(model) # <attribute> don't match
self.assertEqual(model.element, group[3])
self.check_advance_false(model, [(group, 0, group[0][0][:] + group[1:])]) # <notation> don't match
model.restart()
self.assertEqual(model.element, group[0][0][0])
self.check_advance_false(model) # <simpleType> don't match
self.assertEqual(model.element, group[0][0][1])
self.check_advance_false(model) # <complexType> don't match
self.assertEqual(model.element, group[0][0][2])
self.check_advance_false(model) # <group> don't match
self.assertEqual(model.element, group[0][0][3])
self.check_advance_false(model) # <attributeGroup> don't match
self.assertEqual(model.element, group[1])
self.check_advance_false(model) # <element> don't match
self.assertEqual(model.element, group[2])
self.check_advance_true(model) # <attribute> match
self.assertIsNone(model.element)
def test_meta_attr_declarations_group(self):
"""
<xs:group name="attrDecls">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="attribute" type="xs:attribute"/>
<xs:element name="attributeGroup" type="xs:attributeGroupRef"/>
</xs:choice>
<xs:element ref="xs:anyAttribute" minOccurs="0"/>
</xs:sequence>
</xs:group>
"""
group = self.schema_class.meta_schema.groups['attrDecls']
model = ModelVisitor(group)
for match in [False, False, True]:
self.check_advance(model, match)
self.assertIsNone(model.element)
model = ModelVisitor(group)
self.check_advance_false(model)
self.check_advance_true(model)
self.assertEqual(model.element, group[0][0])
model = ModelVisitor(group)
for match in [False, True, False, False]:
self.check_advance(model, match)
self.assertEqual(model.element, group[1])
model = ModelVisitor(group)
for match in [False, True, True, False, True, False, False]:
self.check_advance(model, match)
self.assertEqual(model.element, group[1])
def test_meta_complex_type_model(self):
"""
<xs:group name="complexTypeModel">
<xs:choice>
<xs:element ref="xs:simpleContent"/>
<xs:element ref="xs:complexContent"/>
<xs:sequence>
<xs:group ref="xs:typeDefParticle" minOccurs="0"/>
<xs:group ref="xs:attrDecls"/>
</xs:sequence>
</xs:choice>
</xs:group>
<xs:group name="typeDefParticle">
<xs:choice>
<xs:element name="group" type="xs:groupRef"/>
<xs:element ref="xs:all"/>
<xs:element ref="xs:choice"/>
<xs:element ref="xs:sequence"/>
</xs:choice>
</xs:group>
<xs:group name="complexTypeModel">
<xs:choice>
<xs:element ref="xs:simpleContent"/>
<xs:element ref="xs:complexContent"/>
<xs:sequence>
<xs:element ref="xs:openContent" minOccurs="0"/>
<xs:group ref="xs:typeDefParticle" minOccurs="0"/>
<xs:group ref="xs:attrDecls"/>
<xs:group ref="xs:assertions"/>
</xs:sequence>
</xs:choice>
</xs:group>
"""
group = self.schema_class.meta_schema.groups['complexTypeModel']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0])
self.check_advance_true(model) # <simpleContent> match
self.assertIsNone(model.element)
model.restart()
self.assertEqual(model.element, group[0])
self.check_advance_false(model)
self.check_advance_true(model) # <complexContent> match
self.assertIsNone(model.element)
if self.schema_class.XSD_VERSION == '1.0':
model.restart()
self.assertEqual(model.element, group[0])
for match in [False, False, False, False, True]:
self.check_advance(model, match) # <all> match
self.check_stop(model)
self.assertIsNone(model.element)
model.restart()
self.assertEqual(model.element, group[0])
for match in [False, False, False, False, True, False, True, False, False, False]:
self.check_advance(model, match) # <all> match, <attributeGroup> match
self.assertIsNone(model.element)
def test_meta_schema_document_model(self):
group = self.schema_class.meta_schema.elements['schema'].type.content_type
# A schema model with a wrong tag
model = ModelVisitor(group)
if self.schema_class.XSD_VERSION == '1.0':
self.assertEqual(model.element, group[0][0])
self.check_advance_false(model) # eg. anyAttribute
self.check_stop(model)
else:
self.assertEqual(model.element, group[0][0][0])
#
# Tests on schema test_cases/features/models/models.xsd
def test_model_group1(self):
group = self.models_schema.groups['group1']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0])
self.check_stop(model)
model.restart()
self.assertEqual(model.element, group[0])
for _ in range(3):
self.check_advance_false(model)
self.assertIsNone(model.element)
model.restart()
for match in [False, True, False]:
self.check_advance(model, match)
self.assertIsNone(model.element)
def test_model_group2(self):
group = self.models_schema.groups['group2']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0])
for _ in range(3):
self.check_advance_false(model) # group1 do not match
self.assertEqual(model.element, group[1][0][0][2]) # <elem3> of group1
for _ in range(8):
self.check_advance_false(model)
self.assertEqual(model.element, group[2]) # <elem12>
self.check_advance_false(model)
self.assertEqual(model.element, group[3]) # <elem13>
self.check_advance_false(model)
self.assertIsNone(model.element)
def test_model_group3(self):
group = self.models_schema.groups['group3']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0])
for match in [True, False, True]:
self.check_advance(model, match)
self.check_stop(model)
def test_model_group4(self):
group = self.models_schema.groups['group4']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0])
for match in [True, False, True]:
self.check_advance(model, match)
self.check_stop(model)
def test_model_group5(self):
group = self.models_schema.groups['group5']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0][0])
for _ in range(5): # match [<elem1> .. <elem5>]
self.check_advance_true(model)
self.assertEqual(model.element.name, 'elem6')
self.check_advance_true(model) # match choice with <elem6>
self.check_stop(model)
def test_model_group6(self):
group = self.models_schema.groups['group6']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0][0])
self.check_advance_true(model) # match choice with <elem1>
self.check_advance_true(model) # match choice with <elem2>
self.assertIsNone(model.element)
def test_model_group7(self):
group = self.models_schema.types['complexType7'].content_type
model = ModelVisitor(group)
self.assertEqual(model.element, group[0][0])
self.check_stop(model, [(group[0][0], 0, [group[0][0]])])
group = self.models_schema.types['complexType7_emptiable'].content_type
model = ModelVisitor(group)
self.assertEqual(model.element, group[0][0])
self.check_stop(model)
def test_model_group8(self):
group = self.models_schema.groups['group8']
model = ModelVisitor(group)
self.assertEqual(model.element, group[0][0])
self.check_advance_true(model) # match choice with <elem1>
self.check_advance_false(model)
self.assertEqual(model.element, group[0][1])
self.check_advance_true(model) # match choice with <elem2>
self.assertEqual(model.element, group[0][2])
self.check_advance_true(model) # match choice with <elem3>
self.assertEqual(model.element, group[0][3])
self.check_advance_true(model) # match choice with <elem4>
self.assertIsNone(model.element)
#
# Tests on issues
def test_issue_086(self):
issue_086_xsd = casepath('issues/issue_086/issue_086.xsd')
schema = self.schema_class(issue_086_xsd)
group = schema.types['Foo'].content_type
# issue_086-1.xml sequence simulation
model = ModelVisitor(group)
self.assertEqual(model.element, group[0])
self.check_advance_true(model) # <header> matching
self.assertEqual(model.element, group[1][0][0]) # 'a' element
self.check_advance_true(model) # <a> matching
self.assertEqual(model.element, group[1][0][0]) # 'a' element
self.check_advance_true(model) # <a> matching
self.assertEqual(model.element, group[1][0][0]) # 'a' element
self.check_advance_false(model)
self.assertEqual(model.element, group[1][0][0]) # 'a' element
self.check_advance_false(model)
self.assertEqual(model.element, group[1][1][0]) # 'b' element
self.check_advance_true(model) # <b> matching
self.assertEqual(model.element, group[1][1][0]) # 'b' element
self.check_advance_true(model) # <b> matching
self.check_advance_false(model)
self.assertEqual(model.element, group[1][0][0]) # 'a' element (choice group restarted)
self.check_advance_false(model)
self.check_advance_false(model)
self.assertEqual(model.element, group[1][2][0]) # 'c' element
self.check_advance_true(model) # <c> matching
self.assertEqual(model.element, group[1][2][0]) # 'c' element
self.check_advance_true(model) # <c> matching
self.check_stop(model)
# issue_086-2.xml sequence simulation
model = ModelVisitor(group)
self.check_advance_true(model) # <header> matching
self.assertEqual(model.element, group[1][0][0]) # 'a' element
self.check_advance_false(model)
self.assertEqual(model.element, group[1][1][0]) # 'b' element
self.check_advance_true(model) # <b> matching
self.assertEqual(model.element, group[1][1][0]) # 'b' element
self.check_advance_true(model) # <b> matching
self.check_advance_false(model)
self.assertEqual(model.element, group[1][0][0]) # 'a' element (choice group restarted)
self.check_advance_false(model)
self.check_advance_false(model)
self.assertEqual(model.element, group[1][2][0]) # 'c' element
self.check_advance_true(model) # <c> matching
self.assertEqual(model.element, group[1][2][0]) # 'c' element
self.check_advance_true(model) # <c> matching
self.check_advance_false(model)
self.assertEqual(model.element, group[1][0][0]) # 'a' element
self.check_advance_true(model) # <a> matching
self.assertEqual(model.element, group[1][0][0]) # 'a' element
self.check_advance_true(model) # <a> matching
self.assertEqual(model.element, group[1][0][0]) # 'a' element
self.check_stop(model)
class TestModelValidation11(TestModelValidation):
schema_class = XMLSchema11
class TestModelBasedSorting(XsdValidatorTestCase):
def test_sort_content(self):
# test of ModelVisitor's sort_content/iter_unordered_content
schema = self.get_schema("""
<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>
""")
model = ModelVisitor(schema.types['A_type'].content_type)
self.assertListEqual(
model.sort_content([('B2', 10), ('B1', 'abc'), ('B3', True)]),
[('B1', 'abc'), ('B2', 10), ('B3', True)]
)
self.assertListEqual(
model.sort_content([('B3', True), ('B2', 10), ('B1', 'abc')]),
[('B1', 'abc'), ('B2', 10), ('B3', True)]
)
self.assertListEqual(
model.sort_content([('B2', 10), ('B4', None), ('B1', 'abc'), ('B3', True)]),
[('B1', 'abc'), ('B2', 10), ('B3', True), ('B4', None)]
)
content = [('B2', 10), ('B4', None), ('B1', 'abc'), (1, 'hello'), ('B3', True)]
self.assertListEqual(
model.sort_content(content),
[(1, 'hello'), ('B1', 'abc'), ('B2', 10), ('B3', True), ('B4', None)]
)
content = [(2, 'world!'), ('B2', 10), ('B4', None), ('B1', 'abc'), (1, 'hello'), ('B3', True)]
self.assertListEqual(
model.sort_content(content),
[(1, 'hello'), ('B1', 'abc'), (2, 'world!'), ('B2', 10), ('B3', True), ('B4', None)]
)
# With a dict-type argument
content = ordered_dict_class([('B2', [10]), ('B1', ['abc']), ('B3', [True])])
self.assertListEqual(
model.sort_content(content), [('B1', 'abc'), ('B2', 10), ('B3', True)]
)
content = ordered_dict_class([('B2', [10]), ('B1', ['abc']), ('B3', [True]), (1, 'hello')])
self.assertListEqual(
model.sort_content(content), [(1, 'hello'), ('B1', 'abc'), ('B2', 10), ('B3', True)]
)
# With partial content
self.assertListEqual(model.sort_content([]), [])
self.assertListEqual(model.sort_content([('B1', 'abc')]), [('B1', 'abc')])
self.assertListEqual(model.sort_content([('B2', 10)]), [('B2', 10)])
self.assertListEqual(model.sort_content([('B3', True)]), [('B3', True)])
self.assertListEqual(
model.sort_content([('B3', True), ('B1', 'abc')]), [('B1', 'abc'), ('B3', True)]
)
self.assertListEqual(
model.sort_content([('B2', 10), ('B1', 'abc')]), [('B1', 'abc'), ('B2', 10)]
)
self.assertListEqual(
model.sort_content([('B3', True), ('B2', 10)]), [('B2', 10), ('B3', True)]
)
def test_iter_collapsed_content_with_optional_elements(self):
schema = self.get_schema("""
<xs:element name="A" type="A_type" />
<xs:complexType name="A_type">
<xs:sequence>
<xs:element name="B1" minOccurs="0" />
<xs:element name="B2" minOccurs="0" />
<xs:element name="B3" />
<xs:element name="B4" />
<xs:element name="B5" />
<xs:element name="B6" minOccurs="0" />
<xs:element name="B7" />
</xs:sequence>
</xs:complexType>
""")
model = ModelVisitor(schema.types['A_type'].content_type)
content = [('B3', 10), ('B4', None), ('B5', True), ('B6', 'alpha'), ('B7', 20)]
model.restart()
self.assertListEqual(
list(model.iter_collapsed_content(content)), content
)
content = [('B3', 10), ('B5', True), ('B6', 'alpha'), ('B7', 20)] # Missing B4
model.restart()
self.assertListEqual(
list(model.iter_collapsed_content(content)), content
)
def test_iter_collapsed_content_with_repeated_elements(self):
schema = self.get_schema("""
<xs:element name="A" type="A_type" />
<xs:complexType name="A_type">
<xs:sequence>
<xs:element name="B1" minOccurs="0" />
<xs:element name="B2" minOccurs="0" maxOccurs="unbounded" />
<xs:element name="B3" maxOccurs="unbounded" />
<xs:element name="B4" />
<xs:element name="B5" maxOccurs="unbounded" />
<xs:element name="B6" minOccurs="0" />
<xs:element name="B7" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
""")
model = ModelVisitor(schema.types['A_type'].content_type)
content = [
('B3', 10), ('B4', None), ('B5', True), ('B5', False), ('B6', 'alpha'), ('B7', 20)
]
self.assertListEqual(
list(model.iter_collapsed_content(content)), content
)
content = [('B3', 10), ('B3', 11), ('B3', 12), ('B4', None), ('B5', True),
('B5', False), ('B6', 'alpha'), ('B7', 20), ('B7', 30)]
model.restart()
self.assertListEqual(
list(model.iter_collapsed_content(content)), content
)
content = [('B3', 10), ('B3', 11), ('B3', 12), ('B4', None), ('B5', True), ('B5', False)]
model.restart()
self.assertListEqual(
list(model.iter_collapsed_content(content)), content
)
def test_iter_collapsed_content_with_repeated_groups(self):
schema = self.get_schema("""
<xs:element name="A" type="A_type" />
<xs:complexType name="A_type">
<xs:sequence minOccurs="1" maxOccurs="2">
<xs:element name="B1" minOccurs="0" />
<xs:element name="B2" minOccurs="0" />
</xs:sequence>
</xs:complexType>
""")
model = ModelVisitor(schema.types['A_type'].content_type)
content = [('B1', 1), ('B1', 2), ('B2', 3), ('B2', 4)]
self.assertListEqual(
list(model.iter_collapsed_content(content)),
[('B1', 1), ('B2', 3), ('B1', 2), ('B2', 4)]
)
# Model broken by unknown element at start
content = [('X', None), ('B1', 1), ('B1', 2), ('B2', 3), ('B2', 4)]
model.restart()
self.assertListEqual(list(model.iter_collapsed_content(content)), content)
content = [('B1', 1), ('X', None), ('B1', 2), ('B2', 3), ('B2', 4)]
model.restart()
self.assertListEqual(list(model.iter_collapsed_content(content)), content)
content = [('B1', 1), ('B1', 2), ('X', None), ('B2', 3), ('B2', 4)]
model.restart()
self.assertListEqual(list(model.iter_collapsed_content(content)), content)
content = [('B1', 1), ('B1', 2), ('B2', 3), ('X', None), ('B2', 4)]
model.restart()
self.assertListEqual(
list(model.iter_collapsed_content(content)),
[('B1', 1), ('B2', 3), ('B1', 2), ('X', None), ('B2', 4)]
)
content = [('B1', 1), ('B1', 2), ('B2', 3), ('B2', 4), ('X', None)]
model.restart()
self.assertListEqual(
list(model.iter_collapsed_content(content)),
[('B1', 1), ('B2', 3), ('B1', 2), ('B2', 4), ('X', None)]
)
def test_iter_collapsed_content_with_single_elements(self):
schema = self.get_schema("""
<xs:element name="A" type="A_type" />
<xs:complexType name="A_type">
<xs:sequence>
<xs:element name="B1" />
<xs:element name="B2" />
<xs:element name="B3" />
</xs:sequence>
</xs:complexType>
""")
model = ModelVisitor(schema.types['A_type'].content_type)
content = [('B1', 'abc'), ('B2', 10), ('B3', False)]
model.restart()
self.assertListEqual(list(model.iter_collapsed_content(content)), content)
content = [('B3', False), ('B1', 'abc'), ('B2', 10)]
model.restart()
self.assertListEqual(list(model.iter_collapsed_content(content)), content)
content = [('B1', 'abc'), ('B3', False), ('B2', 10)]
model.restart()
self.assertListEqual(list(model.iter_collapsed_content(content)), content)
content = [('B1', 'abc'), ('B1', 'def'), ('B2', 10), ('B3', False)]
model.restart()
self.assertListEqual(
list(model.iter_collapsed_content(content)),
[('B1', 'abc'), ('B2', 10), ('B3', False), ('B1', 'def')]
)
content = [('B1', 'abc'), ('B2', 10), ('X', None)]
model.restart()
self.assertListEqual(list(model.iter_collapsed_content(content)), content)
content = [('X', None), ('B1', 'abc'), ('B2', 10), ('B3', False)]
model.restart()
self.assertListEqual(list(model.iter_collapsed_content(content)), content)
if __name__ == '__main__':
from xmlschema.tests import print_test_header
print_test_header()
unittest.main()