-
-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Break sanitizer down to handler processors
- Loading branch information
Showing
21 changed files
with
1,094 additions
and
1,064 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
from unittest import mock | ||
|
||
from xsdata.codegen.container import ClassContainer | ||
from xsdata.codegen.handlers import AttributeDefaultValueHandler | ||
from xsdata.models.enums import Namespace | ||
from xsdata.utils.testing import AttrFactory | ||
from xsdata.utils.testing import AttrTypeFactory | ||
from xsdata.utils.testing import ClassFactory | ||
from xsdata.utils.testing import FactoryTestCase | ||
|
||
|
||
class AttributeDefaultValueHandlerTests(FactoryTestCase): | ||
def setUp(self): | ||
super().setUp() | ||
|
||
container = ClassContainer() | ||
self.processor = AttributeDefaultValueHandler(container=container) | ||
|
||
def test_process_attribute_with_enumeration(self): | ||
target = ClassFactory.create() | ||
attr = AttrFactory.enumeration() | ||
attr.restrictions.max_occurs = 2 | ||
attr.fixed = True | ||
|
||
self.processor.process_attribute(target, attr) | ||
self.assertTrue(attr.fixed) | ||
|
||
def test_process_attribute_with_optional_field(self): | ||
target = ClassFactory.create() | ||
attr = AttrFactory.create(fixed=True, default=2) | ||
attr.restrictions.min_occurs = 0 | ||
self.processor.process_attribute(target, attr) | ||
self.assertFalse(attr.fixed) | ||
self.assertIsNone(attr.default) | ||
|
||
def test_process_attribute_with_xsi_type(self): | ||
target = ClassFactory.create() | ||
attr = AttrFactory.create( | ||
fixed=True, default=2, name="type", namespace=Namespace.XSI.uri | ||
) | ||
self.processor.process_attribute(target, attr) | ||
self.assertFalse(attr.fixed) | ||
self.assertIsNone(attr.default) | ||
|
||
def test_process_attribute_with_valid_case(self): | ||
target = ClassFactory.create() | ||
attr = AttrFactory.create(fixed=True, default=2) | ||
self.processor.process_attribute(target, attr) | ||
self.assertTrue(attr.fixed) | ||
self.assertEqual(2, attr.default) | ||
|
||
@mock.patch("xsdata.codegen.handlers.attribute_default_value.logger.warning") | ||
@mock.patch.object(AttributeDefaultValueHandler, "find_enum") | ||
def test_process_attribute_enum(self, mock_find_enum, mock_logger_warning): | ||
enum_one = ClassFactory.enumeration(1, qname="{a}root") | ||
enum_one.attrs[0].default = "1" | ||
enum_one.attrs[0].name = "one" | ||
enum_two = ClassFactory.enumeration(1, qname="inner") | ||
enum_two.attrs[0].default = "2" | ||
enum_two.attrs[0].name = "two" | ||
enum_three = ClassFactory.enumeration(2, qname="missing_member") | ||
enum_three.attrs[0].default = "4" | ||
enum_three.attrs[0].name = "four" | ||
enum_three.attrs[1].default = "5" | ||
enum_three.attrs[1].name = "five" | ||
|
||
mock_find_enum.side_effect = [ | ||
None, | ||
enum_one, | ||
None, | ||
enum_two, | ||
enum_three, | ||
enum_three, | ||
] | ||
|
||
target = ClassFactory.create( | ||
qname="target", | ||
attrs=[ | ||
AttrFactory.create( | ||
types=[ | ||
AttrTypeFactory.create(), | ||
AttrTypeFactory.create(qname="foo"), | ||
], | ||
default="1", | ||
), | ||
AttrFactory.create( | ||
types=[ | ||
AttrTypeFactory.create(), | ||
AttrTypeFactory.create(qname="bar", forward=True), | ||
], | ||
default="2", | ||
), | ||
AttrFactory.create(default="3"), | ||
AttrFactory.create(default=" 4 5"), | ||
], | ||
) | ||
|
||
actual = [] | ||
for attr in target.attrs: | ||
self.processor.process_attribute(target, attr) | ||
actual.append(attr.default) | ||
|
||
self.assertEqual( | ||
[ | ||
"@enum@{a}root::one", | ||
"@enum@inner::two", | ||
None, | ||
"@enum@missing_member::four@five", | ||
], | ||
actual, | ||
) | ||
mock_logger_warning.assert_called_once_with( | ||
"No enumeration member matched %s.%s default value `%s`", | ||
target.name, | ||
target.attrs[2].local_name, | ||
"3", | ||
) | ||
|
||
def test_find_enum(self): | ||
native_type = AttrTypeFactory.create() | ||
matching_external = AttrTypeFactory.create("foo") | ||
missing_external = AttrTypeFactory.create("bar") | ||
enumeration = ClassFactory.enumeration(1, qname="foo") | ||
inner = ClassFactory.enumeration(1, qname="foobar") | ||
|
||
target = ClassFactory.create( | ||
attrs=[ | ||
AttrFactory.create( | ||
types=[ | ||
native_type, | ||
matching_external, | ||
missing_external, | ||
] | ||
) | ||
], | ||
inner=[inner], | ||
) | ||
self.processor.container.extend([target, enumeration]) | ||
|
||
actual = self.processor.find_enum(native_type) | ||
self.assertIsNone(actual) | ||
|
||
actual = self.processor.find_enum(matching_external) | ||
self.assertEqual(enumeration, actual) | ||
|
||
actual = self.processor.find_enum(missing_external) | ||
self.assertIsNone(actual) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
from xsdata.codegen.handlers import AttributeNameConflictHandler | ||
from xsdata.models.enums import Tag | ||
from xsdata.utils.testing import AttrFactory | ||
from xsdata.utils.testing import ClassFactory | ||
from xsdata.utils.testing import FactoryTestCase | ||
|
||
|
||
class AttributeNameConflictHandlerTests(FactoryTestCase): | ||
def setUp(self): | ||
super().setUp() | ||
|
||
self.processor = AttributeNameConflictHandler() | ||
|
||
def test_process(self): | ||
attrs = [ | ||
AttrFactory.create(name="a", tag=Tag.ELEMENT), | ||
AttrFactory.create(name="a", tag=Tag.ATTRIBUTE), | ||
AttrFactory.create(name="b", tag=Tag.ATTRIBUTE), | ||
AttrFactory.create(name="c", tag=Tag.ATTRIBUTE), | ||
AttrFactory.create(name="c", tag=Tag.ELEMENT), | ||
AttrFactory.create(name="d", tag=Tag.ELEMENT), | ||
AttrFactory.create(name="d", tag=Tag.ELEMENT), | ||
AttrFactory.create(name="e", tag=Tag.ELEMENT, namespace="b"), | ||
AttrFactory.create(name="e", tag=Tag.ELEMENT), | ||
AttrFactory.create(name="f", tag=Tag.ELEMENT), | ||
AttrFactory.create(name="f", tag=Tag.ELEMENT, namespace="a"), | ||
AttrFactory.create(name="gA", tag=Tag.ENUMERATION), | ||
AttrFactory.create(name="g[A]", tag=Tag.ENUMERATION), | ||
AttrFactory.create(name="g_a", tag=Tag.ENUMERATION), | ||
AttrFactory.create(name="g_a_1", tag=Tag.ENUMERATION), | ||
] | ||
target = ClassFactory.create(attrs=attrs) | ||
|
||
self.processor.process(target) | ||
expected = [ | ||
"a", | ||
"a_Attribute", | ||
"b", | ||
"c_Attribute", | ||
"c", | ||
"d_Element", | ||
"d", | ||
"b_e", | ||
"e", | ||
"f", | ||
"a_f", | ||
"gA", | ||
"g[A]_2", | ||
"g_a_3", | ||
"g_a_1", | ||
] | ||
self.assertEqual(expected, [x.name for x in attrs]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
from xsdata.codegen.handlers import AttributeRestrictionsHandler | ||
from xsdata.codegen.models import Class | ||
from xsdata.codegen.models import Restrictions | ||
from xsdata.models.enums import Tag | ||
from xsdata.utils.testing import AttrFactory | ||
from xsdata.utils.testing import ClassFactory | ||
from xsdata.utils.testing import FactoryTestCase | ||
|
||
|
||
class AttributeRestrictionsHandlerTests(FactoryTestCase): | ||
def setUp(self): | ||
super().setUp() | ||
|
||
self.processor = AttributeRestrictionsHandler() | ||
|
||
def test_reset_occurrences(self): | ||
required = Restrictions(min_occurs=1, max_occurs=1) | ||
attr = AttrFactory.attribute(restrictions=required.clone()) | ||
self.processor.reset_occurrences(attr) | ||
self.assertIsNone(attr.restrictions.min_occurs) | ||
self.assertIsNone(attr.restrictions.max_occurs) | ||
|
||
tokens = Restrictions(required=True, tokens=True, min_occurs=1, max_occurs=1) | ||
attr = AttrFactory.element(restrictions=tokens.clone()) | ||
self.processor.reset_occurrences(attr) | ||
self.assertFalse(attr.restrictions.required) | ||
self.assertIsNone(attr.restrictions.min_occurs) | ||
self.assertIsNone(attr.restrictions.max_occurs) | ||
|
||
attr = AttrFactory.element(restrictions=tokens.clone()) | ||
attr.restrictions.max_occurs = 2 | ||
self.processor.reset_occurrences(attr) | ||
self.assertFalse(attr.restrictions.required) | ||
self.assertIsNotNone(attr.restrictions.min_occurs) | ||
self.assertIsNotNone(attr.restrictions.max_occurs) | ||
|
||
multiple = Restrictions(min_occurs=0, max_occurs=2) | ||
attr = AttrFactory.create(tag=Tag.EXTENSION, restrictions=multiple) | ||
self.processor.reset_occurrences(attr) | ||
self.assertTrue(attr.restrictions.required) | ||
self.assertIsNone(attr.restrictions.min_occurs) | ||
self.assertIsNone(attr.restrictions.max_occurs) | ||
|
||
multiple = Restrictions(max_occurs=2, required=True) | ||
attr = AttrFactory.element(restrictions=multiple, fixed=True) | ||
self.processor.reset_occurrences(attr) | ||
self.assertIsNone(attr.restrictions.required) | ||
self.assertEqual(0, attr.restrictions.min_occurs) | ||
self.assertFalse(attr.fixed) | ||
|
||
attr = AttrFactory.element(restrictions=required.clone()) | ||
self.processor.reset_occurrences(attr) | ||
self.assertTrue(attr.restrictions.required) | ||
self.assertIsNone(attr.restrictions.min_occurs) | ||
self.assertIsNone(attr.restrictions.max_occurs) | ||
|
||
restrictions = Restrictions(required=True, min_occurs=0, max_occurs=1) | ||
attr = AttrFactory.element(restrictions=restrictions, default="A", fixed=True) | ||
self.processor.reset_occurrences(attr) | ||
self.assertIsNone(attr.restrictions.required) | ||
self.assertIsNone(attr.restrictions.min_occurs) | ||
self.assertIsNone(attr.restrictions.max_occurs) | ||
self.assertIsNone(attr.default) | ||
self.assertFalse(attr.fixed) | ||
|
||
attr = AttrFactory.element(restrictions=required.clone(), default="A") | ||
self.processor.reset_occurrences(attr) | ||
self.assertIsNone(attr.restrictions.required) | ||
|
||
attr = AttrFactory.element(restrictions=required.clone(), fixed=True) | ||
self.processor.reset_occurrences(attr) | ||
self.assertIsNone(attr.restrictions.required) | ||
|
||
attr = AttrFactory.element(restrictions=required.clone()) | ||
attr.restrictions.nillable = True | ||
self.processor.reset_occurrences(attr) | ||
self.assertIsNone(attr.restrictions.required) | ||
|
||
def test_reset_sequential(self): | ||
def len_sequential(target: Class): | ||
return len([attr for attr in target.attrs if attr.restrictions.sequential]) | ||
|
||
restrictions = Restrictions(max_occurs=2, sequential=True) | ||
target = ClassFactory.create( | ||
attrs=[ | ||
AttrFactory.create(restrictions=restrictions.clone()), | ||
AttrFactory.create(restrictions=restrictions.clone()), | ||
] | ||
) | ||
|
||
attrs_clone = [attr.clone() for attr in target.attrs] | ||
|
||
self.processor.reset_sequential(target, 0) | ||
self.assertEqual(2, len_sequential(target)) | ||
|
||
target.attrs[0].restrictions.sequential = False | ||
self.processor.reset_sequential(target, 0) | ||
self.assertEqual(1, len_sequential(target)) | ||
|
||
self.processor.reset_sequential(target, 1) | ||
self.assertEqual(0, len_sequential(target)) | ||
|
||
target.attrs = attrs_clone | ||
target.attrs[1].restrictions.sequential = False | ||
self.processor.reset_sequential(target, 0) | ||
self.assertEqual(0, len_sequential(target)) | ||
|
||
target.attrs[0].restrictions.sequential = True | ||
target.attrs[0].restrictions.max_occurs = 0 | ||
target.attrs[1].restrictions.sequential = True | ||
self.processor.reset_sequential(target, 0) | ||
self.assertEqual(1, len_sequential(target)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.