def test_process_class( self, mock_process_attribute_default, mock_process_attribute_restrictions, mock_process_attribute_sequence, mock_process_duplicate_attribute_names, ): target = ClassFactory.elements(2) inner = ClassFactory.elements(1) target.inner.append(inner) self.sanitizer.process_class(target) calls_with_target = [ mock.call(target.inner[0], target.inner[0].attrs[0]), mock.call(target, target.attrs[0]), mock.call(target, target.attrs[1]), ] calls_without_target = [ mock.call(target.inner[0].attrs[0]), mock.call(target.attrs[0]), mock.call(target.attrs[1]), ] mock_process_attribute_default.assert_has_calls(calls_with_target) mock_process_attribute_restrictions.assert_has_calls( calls_without_target) mock_process_attribute_sequence.assert_has_calls(calls_with_target) mock_process_duplicate_attribute_names.assert_has_calls( [mock.call(target.inner[0].attrs), mock.call(target.attrs)])
def test_copy_attribute_properties_from_nillable_source(self): source = ClassFactory.elements(1, nillable=True) target = ClassFactory.elements(1) attr = target.attrs[0] self.processor.copy_attribute_properties(source, target, attr, attr.types[0]) self.assertTrue(attr.restrictions.nillable)
def test_render(self): classes = [ ClassFactory.elements(2, package="foo"), ClassFactory.elements(3, package="foo"), ] iterator = self.generator.render(classes) actual = [(out.path, out.title, out.source) for out in iterator] self.assertEqual(1, len(actual)) self.assertEqual(3, len(actual[0])) self.assertIsInstance(actual[0][0], Path) self.assertTrue(actual[0][0].is_absolute()) self.assertEqual("foo.tests", actual[0][1]) self.assertEqual( str(Path("foo/tests.pu")), str(actual[0][0].relative_to(Path.cwd())) ) output = ( "@startuml\n" "\n" "class class_B {\n" " +attr_B : string\n" " +attr_C : string\n" "}\n" "class class_C {\n" " +attr_D : string\n" " +attr_E : string\n" " +attr_F : string\n" "}\n" "\n" "@enduml" "\n" ) self.assertEqual(output, actual[0][2])
def test_copy_attribute_properties(self, mock_copy_inner_class): source = ClassFactory.elements(1, qname="Foobar") source.attrs[0].restrictions.max_length = 100 source.attrs[0].restrictions.min_length = 1 source.attrs[0].help = "foo" source.attrs[0].types = [ AttrTypeFactory.create(qname="first"), AttrTypeFactory.create(qname="second"), ] target = ClassFactory.elements(1) attr = target.attrs[0] attr.restrictions.min_length = 2 attr.types.clear() attr.types.append(AttrTypeFactory.create(qname=source.name)) self.assertEqual("Foobar", attr.types[0].name) self.processor.copy_attribute_properties(source, target, attr, attr.types[0]) self.assertEqual("first", attr.types[0].name) self.assertEqual("second", attr.types[1].name) self.assertEqual("foo", attr.help) self.assertEqual(Restrictions(min_length=2, max_length=100), attr.restrictions) mock_copy_inner_class.assert_has_calls([ mock.call(source, target, attr, source.attrs[0].types[0]), mock.call(source, target, attr, source.attrs[0].types[1]), ])
def test_copy_group_attributes(self, mock_clone_attribute, mock_copy_inner_classes): mock_clone_attribute.side_effect = lambda x, y: x.clone() source = ClassFactory.elements(2) source.inner.append(ClassFactory.create()) target = ClassFactory.elements(3) attrs = list(target.attrs) attrs[1].name = "bar" ClassUtils.copy_group_attributes(source, target, target.attrs[1]) self.assertEqual(4, len(target.attrs)) self.assertEqual(source.attrs[0], target.attrs[1]) self.assertEqual(source.attrs[1], target.attrs[2]) mock_copy_inner_classes.assert_has_calls( [ mock.call(source, target, source.attrs[0]), mock.call(source, target, source.attrs[1]), ] ) mock_clone_attribute.assert_has_calls( [ mock.call(source.attrs[0], attrs[1].restrictions), mock.call(source.attrs[1], attrs[1].restrictions), ] )
def test_process_simple_extension_when_source_and_target_are_not_enumerations( self, mock_copy_attributes): source = ClassFactory.elements(2) target = ClassFactory.elements(1) extension = ExtensionFactory.create() self.processor.process_simple_extension(source, target, extension) mock_copy_attributes.assert_called_once_with(source, target, extension)
def test_should_flatten_extension(self): source = ClassFactory.create() target = ClassFactory.create() self.assertFalse(self.processor.should_flatten_extension(source, target)) # Source has suffix attr and target has its own attrs source = ClassFactory.elements(1) source.attrs[0].index = sys.maxsize target.attrs.append(AttrFactory.create()) self.assertTrue(self.processor.should_flatten_extension(source, target)) # Target has suffix attr source = ClassFactory.create() target = ClassFactory.elements(1) target.attrs[0].index = sys.maxsize self.assertTrue(self.processor.should_flatten_extension(source, target)) # Source is a simple type source = ClassFactory.create(attrs=[AttrFactory.create(tag=Tag.SIMPLE_TYPE)]) target = ClassFactory.elements(1) self.assertTrue(self.processor.should_flatten_extension(source, target)) # Sequential violation source = ClassFactory.elements(3) target = source.clone() self.assertFalse(self.processor.should_flatten_extension(source, target)) for attr in target.attrs: attr.restrictions.sequential = True self.assertFalse(self.processor.should_flatten_extension(source, target)) target.attrs = [target.attrs[1], target.attrs[0], target.attrs[2]] self.assertTrue(self.processor.should_flatten_extension(source, target)) # Types violation target = source.clone() target.attrs[1].types = [ AttrTypeFactory.native(DataType.INT), AttrTypeFactory.native(DataType.FLOAT), ] source.attrs[1].types = [ AttrTypeFactory.native(DataType.INT), AttrTypeFactory.native(DataType.FLOAT), AttrTypeFactory.native(DataType.DECIMAL), ] self.assertFalse(self.processor.should_flatten_extension(source, target)) target.attrs[1].types.append(AttrTypeFactory.native(DataType.QNAME)) self.assertTrue(self.processor.should_flatten_extension(source, target))
def test_process_complex_extension_removes_extension( self, mock_should_remove_extension, mock_copy_attributes): mock_should_remove_extension.return_value = True extension = ExtensionFactory.create() target = ClassFactory.elements(1, extensions=[extension]) source = ClassFactory.elements(5) self.processor.process_complex_extension(source, target, extension) self.assertEqual(0, len(target.extensions)) self.assertEqual(1, len(target.attrs)) mock_should_remove_extension.assert_called_once_with(source, target) self.assertEqual(0, mock_copy_attributes.call_count)
def test_remove_inherited_fields_with_lists_type(self): target = ClassFactory.elements(2) target.attrs[0].restrictions.min_occurs = 1 target.attrs[0].restrictions.max_occurs = 3 source = target.clone() source.qname = "BaseClass" target.attrs[0].restrictions.min_occurs = 0 target.attrs[1].restrictions.max_occurs = 10 target.extensions.append(ExtensionFactory.reference(source.qname)) self.processor.container.add(source) self.processor.process(target) self.assertEqual(2, len(target.attrs)) # min/max occurs didn't match self.processor.container.config.output.compound_fields = True self.processor.process(target) self.assertEqual(2, len( target.attrs)) # The are not part of a choice group target.attrs[0].restrictions.choice = "123" target.attrs[1].restrictions.choice = "123" source.attrs[0].restrictions.choice = "456" source.attrs[1].restrictions.choice = "456" self.processor.process(target) self.assertEqual(0, len(target.attrs))
def test_add_default_attribute(self): xs_string = AttrTypeFactory.native(DataType.STRING) extension = ExtensionFactory.create(xs_string, Restrictions(required=True)) item = ClassFactory.elements(1, extensions=[extension]) ClassExtensionHandler.add_default_attribute(item, extension) expected = AttrFactory.create(name="@value", default=None, types=[xs_string], tag=Tag.EXTENSION) self.assertEqual(2, len(item.attrs)) self.assertEqual(0, len(item.extensions)) self.assertEqual(expected, item.attrs[0]) xs_int = AttrTypeFactory.native(DataType.INT) extension = ExtensionFactory.create(xs_int, Restrictions(tokens=True)) item.extensions.append(extension) ClassExtensionHandler.add_default_attribute(item, extension) expected.types.append(xs_int) expected_restrictions = Restrictions(tokens=True, required=True, min_occurs=1, max_occurs=1) self.assertEqual(2, len(item.attrs)) self.assertEqual(0, len(item.extensions)) self.assertEqual(expected, item.attrs[0]) self.assertEqual(expected_restrictions, item.attrs[0].restrictions)
def test_render_module(self): classes = [ ClassFactory.enumeration(2, help="\n\nI am enum "), ClassFactory.elements(2), ClassFactory.service(2), ] classes[0].attrs[0].help = "I am a member" classes[1].attrs[0].help = "I am a field" resolver = DependenciesResolver() actual = self.generator.render_module(resolver, classes) expected = ("from dataclasses import dataclass, field\n" "from enum import Enum\n" "from typing import Optional\n" "\n" '__NAMESPACE__ = "xsdata"\n' "\n" "\n" "class ClassB(Enum):\n" ' """\n' " I am enum.\n" "\n" " :cvar ATTR_B: I am a member\n" " :cvar ATTR_C:\n" ' """\n' " ATTR_B = None\n" " ATTR_C = None\n" "\n" "\n" "@dataclass\n" "class ClassC:\n" ' """\n' " :ivar attr_d: I am a field\n" " :ivar attr_e:\n" ' """\n' " class Meta:\n" ' name = "class_C"\n' "\n" " attr_d: Optional[str] = field(\n" " default=None,\n" " metadata={\n" ' "name": "attr_D",\n' ' "type": "Element",\n' " }\n" " )\n" " attr_e: Optional[str] = field(\n" " default=None,\n" " metadata={\n" ' "name": "attr_E",\n' ' "type": "Element",\n' " }\n" " )\n" "\n" "\n" "class ClassD:\n" ' attr_f = "None"\n' ' attr_g = "None"\n') self.assertEqual(expected, actual)
def test_process(self): item = ClassFactory.create() self.processor.process(item) self.assertEqual(0, len(item.attrs)) item = ClassFactory.elements(2, mixed=True) self.processor.process(item) expected = AttrFactory.create( name="content", types=[AttrTypeFactory.native(DataType.ANY_TYPE)], tag=Tag.ANY, namespace="##any", ) # Wildcard is not defined self.assertEqual(expected, item.attrs[0]) self.assertTrue(item.attrs[0].is_list) self.assertEqual(3, len(item.attrs)) self.assertTrue(item.attrs[0].mixed) # Wildcard is defined and is list item.attrs[0].restrictions.max_occurs = 3 item.attrs[0].mixed = False self.processor.process(item) self.assertEqual(3, len(item.attrs)) self.assertTrue(item.attrs[0].mixed) self.assertEqual(3, item.attrs[0].restrictions.max_occurs) # Wildcard is defined but not list item.attrs[0].restrictions.max_occurs = 1 self.processor.process(item) self.assertTrue(item.attrs[0].is_list) self.assertEqual(sys.maxsize, item.attrs[0].restrictions.max_occurs)
def test_promote(self): target = ClassFactory.elements(2) inner = ClassFactory.enumeration(3) target.inner.append(inner) target.inner.append(ClassFactory.simple_type()) # Irrelevant attr_type = AttrTypeFactory.create(qname=inner.qname, forward=True) target.attrs[0].types.append(attr_type.clone()) target.attrs[1].types.append(attr_type.clone()) self.container.add(target) self.assertEqual(3, len(self.container.data)) self.processor.process(target) new_qname = build_qname(inner.target_namespace, f"{target.name}_{inner.name}") self.assertEqual(4, len(self.container.data)) new_inner = self.container.find(new_qname) self.assertEqual(1, len(target.inner)) self.assertNotEqual(new_inner.qname, inner.qname) self.assertEqual(new_inner.attrs, inner.attrs) self.assertEqual(new_inner.qname, target.attrs[0].types[1].qname) self.assertEqual(new_inner.qname, target.attrs[1].types[1].qname) self.assertFalse(target.attrs[0].types[1].forward) self.assertFalse(target.attrs[1].types[1].forward)
def test_process_simple_extension_when_source_is_enumeration_and_target_is_not( self, mock_add_default_attribute): source = ClassFactory.enumeration(2) target = ClassFactory.elements(1) extension = ExtensionFactory.create() self.processor.process_simple_extension(source, target, extension) mock_add_default_attribute.assert_called_once_with(target, extension)
def test_process_extension_with_native_type(self, mock_flatten_extension_native): extension = ExtensionFactory.native(DataType.STRING) target = ClassFactory.elements(1, extensions=[extension]) self.processor.process_extension(target, extension) mock_flatten_extension_native.assert_called_once_with( target, extension)
def test_process_extension_with_dependency_type( self, mock_process_dependency_extension): extension = ExtensionFactory.create(AttrTypeFactory.create("foo")) target = ClassFactory.elements(1, extensions=[extension]) self.processor.process_extension(target, extension) mock_process_dependency_extension.assert_called_once_with( target, extension)
def test_validate_references(self): first = ClassFactory.elements(2) second = ClassFactory.create(attrs=first.attrs) ClassAnalyzer.validate_references([first]) with self.assertRaises(AnalyzerValueError) as cm: ClassAnalyzer.validate_references([first, second]) self.assertEqual("Cross references detected!", str(cm.exception))
def test_process_enum_extension_raises_exception(self): source = ClassFactory.elements(2) target = ClassFactory.enumeration(2) extension = ExtensionFactory.reference(source.qname) target.extensions.append(extension) self.processor.container.add(source) self.processor.container.add(target) with self.assertRaises(CodeGenerationError): self.processor.process_dependency_extension(target, extension)
def test_filter(self): target = ClassFactory.elements(2) self.processor.process(target) self.assertEqual(2, len(target.attrs)) target.attrs.append(AttrFactory.enumeration()) self.processor.process(target) self.assertEqual(1, len(target.attrs)) self.assertTrue(target.attrs[0].is_enumeration)
def test_process_simple_extension_when_target_is_enumeration_and_source_is_not( self, mock_add_default_attribute, mock_copy_attributes): extension = ExtensionFactory.create() source = ClassFactory.elements(2) target = ClassFactory.enumeration(1, extensions=[extension]) self.processor.process_simple_extension(source, target, extension) self.assertEqual(0, mock_add_default_attribute.call_count) self.assertEqual(0, mock_copy_attributes.call_count) self.assertEqual(0, len(target.extensions))
def test_process_inner_type_with_complex_type( self, mock_copy_attribute_properties, mock_update_restrictions): target = ClassFactory.create() inner = ClassFactory.elements(2, qname="a", status=Status.PROCESSED) attr = AttrFactory.create(types=[AttrTypeFactory.create(qname="a")]) target.inner.append(inner) self.processor.process_inner_type(target, attr, attr.types[0]) self.assertIn(inner, target.inner) self.assertEqual(0, mock_copy_attribute_properties.call_count) self.assertEqual(0, mock_update_restrictions.call_count)
def test_replace_attributes_type(self): extension = ExtensionFactory.create() target = ClassFactory.elements(2) target.extensions.append(extension) ClassExtensionHandler.replace_attributes_type(target, extension) self.assertEqual(1, len(target.attrs[0].types)) self.assertEqual(1, len(target.attrs[1].types)) self.assertEqual(extension.type, target.attrs[0].types[0]) self.assertEqual(extension.type, target.attrs[1].types[0]) self.assertEqual(0, len(target.extensions))
def test_create_substitution(self): item = ClassFactory.elements(1, qname=build_qname("foo", "bar")) actual = self.processor.create_substitution(item) expected = AttrFactory.create( name=item.name, default=None, types=[AttrType(qname=build_qname("foo", "bar"))], tag=item.tag, ) self.assertEqual(expected, actual)
def test_process_dependency_type_with_complex_type( self, mock_find_dependency, mock_set_circular_flag ): complex_type = ClassFactory.elements(1) mock_find_dependency.return_value = complex_type target = ClassFactory.create() attr = AttrFactory.create() attr_type = attr.types[0] self.processor.process_dependency_type(target, attr, attr_type) mock_set_circular_flag.assert_called_once_with(complex_type, target, attr_type)
def test_is_simple_type(self): obj = ClassFactory.elements(2) self.assertFalse(obj.is_simple_type) obj.attrs.pop() self.assertFalse(obj.is_simple_type) for tag in SIMPLE_TYPES: obj.attrs[0].tag = tag self.assertTrue(obj.is_simple_type) obj.extensions.append(ExtensionFactory.create()) self.assertFalse(obj.is_simple_type)
def test_reduce(self, mock_merge_attributes): first = ClassFactory.elements(2) second = first.clone() second.attrs.append(AttrFactory.create()) third = second.clone() third.attrs.append(AttrFactory.create()) fourth = ClassFactory.create() actual = ClassUtils.reduce([first, second, third, fourth]) self.assertEqual([third, fourth], list(actual)) mock_merge_attributes.assert_has_calls( [ mock.call(third, first), mock.call(third, second), ] )
def test_class_references(self): target = ClassFactory.elements( 2, inner=ClassFactory.list(2, attrs=AttrFactory.list(1)), extensions=ExtensionFactory.list(1), ) actual = ClassAnalyzer.class_references(target) # +1 target # +2 attrs # +2 attr types # +1 extension # +1 extension type # +2 inner classes # +2 inner classes attrs # +2 inner classes attr types self.assertEqual(13, len(actual)) self.assertEqual(id(target), actual[0])
def test_process(self, mock_process_attribute, mock_is_group): mock_is_group.side_effect = [ True, False, True, True, False, False, ] target = ClassFactory.elements(2) self.processor.process(target) self.assertEqual(6, mock_is_group.call_count) mock_process_attribute.assert_has_calls([ mock.call(target, target.attrs[0]), mock.call(target, target.attrs[0]), mock.call(target, target.attrs[1]), ])
def test_group_compound_fields(self, mock_group_fields): target = ClassFactory.elements(8) # First group repeating target.attrs[0].restrictions.choice = "1" target.attrs[1].restrictions.choice = "1" target.attrs[1].restrictions.max_occurs = 2 # Second group repeating target.attrs[2].restrictions.choice = "2" target.attrs[3].restrictions.choice = "2" target.attrs[3].restrictions.max_occurs = 2 # Third group optional target.attrs[4].restrictions.choice = "3" target.attrs[5].restrictions.choice = "3" self.sanitizer.group_compound_fields(target) mock_group_fields.assert_has_calls([ mock.call(target, target.attrs[0:2]), mock.call(target, target.attrs[2:4]), ])
def test_add_attribute(self): target = ClassFactory.elements(2) attr = target.attrs[0].clone() attr.index += 1 ElementMapper.add_attribute(target, attr) self.assertEqual(2, len(target.attrs)) self.assertEqual(sys.maxsize, target.attrs[0].restrictions.max_occurs) self.assertEqual(2, len(target.attrs[0].types)) self.assertFalse(target.attrs[0].restrictions.sequential) attr = target.attrs[1].clone() attr.restrictions.sequential = True ElementMapper.add_attribute(target, attr) self.assertTrue(target.attrs[1].restrictions.sequential) attr = AttrFactory.create() ElementMapper.add_attribute(target, attr) self.assertEqual(3, len(target.attrs))