def test_render(self): classes = [ ClassFactory.elements(2), ClassFactory.elements(3), ] iterator = PlantUmlGenerator().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("foo/tests.pu", str(actual[0][0].relative_to(Path.cwd()))) output = """@startuml class class_B { +attr_B : string +attr_C : string } class class_C { +attr_D : string +attr_E : string +attr_F : string } @enduml""" self.assertEqual(output, actual[0][2])
def test_process_class( self, mock_process_attribute_default, mock_process_attribute_restrictions, mock_process_attribute_name, 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_name.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_flatten_extension_simple_when_source_and_target_are_not_enumerations( self, mock_copy_attributes): source = ClassFactory.elements(2) target = ClassFactory.elements(1) extension = ExtensionFactory.create() self.analyzer.flatten_extension_simple(source, target, extension) mock_copy_attributes.assert_called_once_with(source, target, extension)
def test_find_simple_class(self): a = ClassFactory.enumeration(1, name="a") b = ClassFactory.create(name="b", type=SimpleType) c = ClassFactory.elements(1, name="c", abstract=True) d = ClassFactory.elements(1, name="d") self.analyzer.create_class_index([a, b, c, d]) self.assertEqual(a, self.analyzer.find_simple_class(a.source_qname())) self.assertEqual(b, self.analyzer.find_simple_class(b.source_qname())) self.assertEqual(c, self.analyzer.find_simple_class(c.source_qname())) self.assertIsNone(self.analyzer.find_simple_class(d.source_qname()))
def test_process_attribute(self, mock_find): target = ClassFactory.elements(2) mock_find.side_effect = [-1, 2] first_attr = target.attrs[0] second_attr = target.attrs[1] first_attr.restrictions.max_occurs = 2 attr_name = first_attr.name attr_qname = target.source_qname(attr_name) reference_attrs = AttrFactory.list(2) self.processor.create_substitutions() self.processor.substitutions[attr_qname] = reference_attrs self.processor.process_attribute(target, first_attr) self.assertEqual(4, len(target.attrs)) self.assertEqual(reference_attrs[0], target.attrs[0]) self.assertIsNot(reference_attrs[0], target.attrs[0]) self.assertEqual(reference_attrs[1], target.attrs[3]) self.assertIsNot(reference_attrs[1], target.attrs[3]) self.assertEqual(2, target.attrs[0].restrictions.max_occurs) self.assertEqual(2, target.attrs[3].restrictions.max_occurs) self.processor.process_attribute(target, second_attr) self.assertEqual(4, len(target.attrs))
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_extension_native(self, mock_create_default_attribute): extension = ExtensionFactory.create() target = ClassFactory.elements(1) self.processor.process_native_extension(target, extension) mock_create_default_attribute.assert_called_once_with( target, extension)
def test_add_substitution_attrs(self, mock_find_attribute): target = ClassFactory.elements(2) mock_find_attribute.side_effect = [-1, 2] first_attr = target.attrs[0] second_attr = target.attrs[1] first_attr.restrictions.max_occurs = 2 attr_name = first_attr.name attr_qname = target.source_qname(attr_name) reference_attrs = AttrFactory.list(2) self.analyzer.substitutions_index[attr_qname] = reference_attrs self.analyzer.add_substitution_attrs(target, first_attr) self.assertEqual(4, len(target.attrs)) self.assertEqual(reference_attrs[0], target.attrs[0]) self.assertIsNot(reference_attrs[0], target.attrs[0]) self.assertEqual(reference_attrs[1], target.attrs[3]) self.assertIsNot(reference_attrs[1], target.attrs[3]) self.assertEqual(2, target.attrs[0].restrictions.max_occurs) self.assertEqual(2, target.attrs[3].restrictions.max_occurs) second_attr.wildcard = True self.analyzer.add_substitution_attrs(target, second_attr) self.assertEqual(4, len(target.attrs)) self.analyzer.add_substitution_attrs(target, AttrFactory.enumeration()) self.assertEqual(4, len(target.attrs))
def test_flatten_extension_with_native_type_and_target_not_enumeration( self, mock_create_default_attribute ): extension = ExtensionFactory.create(type=AttrTypeFactory.xs_string()) target = ClassFactory.elements(1, extensions=[extension]) self.analyzer.flatten_extension(target, extension) mock_create_default_attribute.assert_called_once_with(target, extension)
def test_find_repeat_on_condition_and_not_processed( self, mock_process_class): first = ClassFactory.elements(2, qname="a") second = ClassFactory.elements(2, qname="a") self.container.extend([first, second]) def process_class(x: Class): x.status = Status.PROCESSED if x is first: first.attrs.clear() mock_process_class.side_effect = process_class self.assertEqual( second, self.container.find(first.qname, lambda x: len(x.attrs) == 2), )
def test_flatten_extension_native_and_target_no_enumeration( self, mock_create_default_attribute): extension = ExtensionFactory.create() target = ClassFactory.elements(1) self.analyzer.flatten_extension_native(target, extension) mock_create_default_attribute.assert_called_once_with( target, extension)
def test_flatten_extension_with_native_type(self, mock_flatten_extension_native): extension = ExtensionFactory.create(type=AttrTypeFactory.xs_string()) target = ClassFactory.elements(1, extensions=[extension]) self.analyzer.flatten_extension(target, extension) mock_flatten_extension_native.assert_called_once_with( target, extension)
def test_find_attr_simple_type(self): a = ClassFactory.enumeration(1, name="a") b = ClassFactory.elements(1, name="b", abstract=True) c = ClassFactory.elements(1, name="c") type_a = AttrTypeFactory.create(name="a") type_b = AttrTypeFactory.create(name="b") type_c = AttrTypeFactory.create(name="c") self.analyzer.create_class_index([a, b, c]) self.assertIsNone(self.analyzer.find_attr_simple_type( a, type_a)) # Enumeration self.assertIsNone(self.analyzer.find_attr_simple_type( a, type_c)) # Complex self.assertIsNone(self.analyzer.find_attr_simple_type( b, type_b)) # Source is target self.assertEqual(b, self.analyzer.find_attr_simple_type(a, type_b))
def test_process_extension_with_dependency_type( self, mock_process_dependency_extension): extension = ExtensionFactory.create(type=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_process_simple_dependency_no_source_attributes(self): source = ClassFactory.create() target = ClassFactory.elements(1) attr = target.attrs[0] self.processor.process_simple_dependency(source, target, attr, attr.types[0]) self.assertEqual("string", attr.types[0].name)
def test_flatten_extension_simple_when_source_is_enumeration_and_target_is_not( self, mock_create_default_attribute ): source = ClassFactory.enumeration(2) target = ClassFactory.elements(1) extension = ExtensionFactory.create() self.analyzer.flatten_extension_simple(source, target, extension) mock_create_default_attribute.assert_called_once_with(target, extension)
def test_class_docstring_with_class_help(self): target = ClassFactory.elements(2, help="Help Me!") expected = '''"""Help Me! :ivar attr_b: :ivar attr_c: """''' self.assertEqual(expected, class_docstring(target))
def test_copy_group_attributes(self, mock_clone_attribute, mock_copy_inner_classes): mock_clone_attribute.side_effect = lambda x, y, z: x.clone() source = ClassFactory.elements(2) source.inner.append(ClassFactory.create()) target = ClassFactory.elements(3) attrs = list(target.attrs) attrs[1].name = "foo: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_called_once_with(source, target) mock_clone_attribute.assert_has_calls([ mock.call(source.attrs[0], attrs[1].restrictions, "foo"), mock.call(source.attrs[1], attrs[1].restrictions, "foo"), ])
def test_copy_extension_type(self): extension = ExtensionFactory.create() target = ClassFactory.elements(2) target.extensions.append(extension) ClassExtensionHandler.copy_extension_type(target, extension) self.assertEqual(extension.type, target.attrs[0].types[1]) self.assertEqual(extension.type, target.attrs[1].types[1]) self.assertEqual(0, len(target.extensions))
def test_flatten_extension_simple_when_target_is_enumeration_and_source_is_not( self, mock_create_default_attribute, mock_copy_attributes): extension = ExtensionFactory.create() source = ClassFactory.elements(2) target = ClassFactory.enumeration(1, extensions=[extension]) self.analyzer.flatten_extension_simple(source, target, extension) self.assertEqual(0, mock_create_default_attribute.call_count) self.assertEqual(0, mock_copy_attributes.call_count) self.assertEqual(0, len(target.extensions))
def test_process_simple_dependency(self, mock_copy_inner_classes): source = ClassFactory.elements(1, qname="Foobar") source.attrs[0].restrictions.max_length = 100 source.attrs[0].restrictions.min_length = 1 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.process_simple_dependency(source, target, attr, attr.types[0]) self.assertEqual("string", attr.types[0].name) self.assertEqual(Restrictions(min_length=2, max_length=100), attr.restrictions) mock_copy_inner_classes.assert_called_once_with(source, target)
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(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_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)
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.type.__name__, ) self.assertEqual(expected, actual)
def test_sanitize_attributes( self, mock_sanitize_attribute, mock_sanitize_restrictions, mock_sanitize_attribute_sequence, mock_sanitize_attribute_name, ): target = ClassFactory.elements(3) inner = ClassFactory.elements(2) target.inner.append(inner) ClassUtils.sanitize_attributes(target) ClassUtils.sanitize_attributes(ClassFactory.create()) self.assertEqual(5, mock_sanitize_attribute.call_count) mock_sanitize_attribute.assert_has_calls([ mock.call(target.attrs[0]), mock.call(target.attrs[1]), mock.call(target.attrs[2]), mock.call(target.inner[0].attrs[0]), mock.call(target.inner[0].attrs[1]), ]) mock_sanitize_restrictions.assert_has_calls([ mock.call(target.attrs[0].restrictions), mock.call(target.attrs[1].restrictions), mock.call(target.attrs[2].restrictions), mock.call(target.inner[0].attrs[0].restrictions), mock.call(target.inner[0].attrs[1].restrictions), ]) expected_second = [ mock.call(target.attrs, 0), mock.call(target.attrs, 1), mock.call(target.attrs, 2), mock.call(target.inner[0].attrs, 0), mock.call(target.inner[0].attrs, 1), ] mock_sanitize_attribute_sequence.assert_has_calls(expected_second) mock_sanitize_attribute_name.assert_has_calls(expected_second)
def test_process_simple_dependency_with_more_than_one_attribute(self): source = ClassFactory.create(type=SimpleType, attrs=AttrFactory.list(2)) target = ClassFactory.elements(1) attr = target.attrs[0] attr_type = attr.types[0] with self.assertRaises(AnalyzerValueError) as cm: self.processor.process_simple_dependency(source, target, attr, attr_type) self.assertEqual("SimpleType with more than one attribute: `class_B`", str(cm.exception))
def test_process_attributes_with_exploit_names( self, mock_process_attribute, mock_has_duplicate_attrs, mock_sanitize_attribute_names, mock_hash_attributes_names, mock_unset_attributes_local_names, ): obj = ClassFactory.elements(3) mock_has_duplicate_attrs.return_value = True generator.process_attributes(obj, ["a", "b"]) mock_process_attribute.assert_has_calls( [mock.call(obj, attr, ["a", "b"]) for attr in obj.attrs]) mock_sanitize_attribute_names.assert_called_once_with(obj) mock_unset_attributes_local_names.assert_called_once_with(obj) mock_hash_attributes_names.assert_called_once_with(obj)
def test_process_attributes_with_duplicate_names( self, mock_process_attribute, mock_has_duplicate_attrs, mock_sanitize_attribute_names, mock_hash_attributes_names, mock_unset_attributes_local_names, ): obj = ClassFactory.elements(3) mock_has_duplicate_attrs.side_effect = [True, False] generator.process_attributes(obj, ["a", "b"]) mock_process_attribute.assert_has_calls( [mock.call(obj, attr, ["a", "b"]) for attr in obj.attrs]) mock_sanitize_attribute_names.assert_called_once_with(obj) mock_unset_attributes_local_names.assert_called_once_with(obj) self.assertEqual(0, mock_hash_attributes_names.call_count)
def test_flatten_class( self, mock_flatten_enumeration_unions, mock_expand_attribute_group, mock_flatten_extension, mock_flatten_attribute_types, mock_add_substitution_attrs, mock_create_mixed_attribute, mock_merge_duplicate_attributes, ): inner = ClassFactory.list(2) extensions = ExtensionFactory.list(2) target = ClassFactory.elements(2, inner=inner, extensions=extensions) self.analyzer.flatten_class(target) mock_flatten_enumeration_unions.assert_has_calls( [mock.call(target), mock.call(inner[0]), mock.call(inner[1])] ) mock_expand_attribute_group.assert_has_calls( [mock.call(target, target.attrs[0]), mock.call(target, target.attrs[1])] ) mock_flatten_extension.assert_has_calls( [ mock.call(target, target.extensions[1]), mock.call(target, target.extensions[0]), ] ) mock_flatten_attribute_types.assert_has_calls( [mock.call(target, target.attrs[0]), mock.call(target, target.attrs[1])] ) mock_add_substitution_attrs.assert_has_calls( [mock.call(target, target.attrs[0]), mock.call(target, target.attrs[1])] ) mock_create_mixed_attribute.assert_has_calls( [mock.call(target), mock.call(inner[0]), mock.call(inner[1])] ) mock_merge_duplicate_attributes.assert_has_calls( [mock.call(target), mock.call(inner[0]), mock.call(inner[1])] )