示例#1
0
 def __post_init__(self):
     self.processors: List[HandlerInterface] = [
         AttributeGroupHandler(self),
         ClassExtensionHandler(self),
         ClassEnumerationHandler(self),
         AttributeSubstitutionHandler(self),
         AttributeTypeHandler(self),
         AttributeMergeHandler(),
         AttributeMixedContentHandler(),
         AttributeSanitizerHandler(self),
     ]
示例#2
0
    def __init__(self, data: Dict[QName, List[Class]] = None) -> None:
        """
        Initialize container structure and the list of process handlers.

        :params data: class map indexed by their source qualified name.
        """
        super().__init__(data)

        self.processors = [
            AttributeGroupHandler(self),
            ClassExtensionHandler(self),
            AttributeEnumUnionHandler(self),
            AttributeTypeHandler(self),
            AttributeSubstitutionHandler(self),
            AttributeMergeHandler(),
            AttributeImpliedHandler(),
            AttributeMismatchHandler(),
        ]
示例#3
0
    def setUp(self):
        super().setUp()

        container = ClassContainer()
        self.processor = AttributeTypeHandler(container=container)
示例#4
0
class AttributeTypeHandlerTests(FactoryTestCase):
    def setUp(self):
        super().setUp()

        container = ClassContainer()
        self.processor = AttributeTypeHandler(container=container)

    @mock.patch.object(AttributeTypeHandler, "filter_types")
    @mock.patch.object(AttributeTypeHandler, "process_type")
    def test_process(self, mock_process_type, mock_filter_types):
        xs_int = AttrTypeFactory.native(DataType.INT)
        xs_bool = AttrTypeFactory.native(DataType.BOOLEAN)
        xs_string = AttrTypeFactory.native(DataType.STRING)
        mock_filter_types.side_effect = lambda x: x

        target = ClassFactory.create(attrs=[
            AttrFactory.create(types=[xs_int, xs_bool]),
            AttrFactory.create(types=[xs_string, xs_string]),
        ])

        self.processor.process(target)
        self.assertEqual(2, len(target.attrs[0].types))
        self.assertEqual(2, len(target.attrs[1].types))

        mock_filter_types.assert_has_calls([
            mock.call(target.attrs[0].types),
            mock.call(target.attrs[1].types),
        ])

        mock_process_type.assert_has_calls([
            mock.call(target, target.attrs[0], xs_int),
            mock.call(target, target.attrs[0], xs_bool),
            mock.call(target, target.attrs[1], xs_string),
            mock.call(target, target.attrs[1], xs_string),
        ])

    @mock.patch.object(AttributeTypeHandler, "process_dependency_type")
    @mock.patch.object(AttributeTypeHandler, "process_native_type")
    def test_process_type_with_native_type(self, mock_process_native_type,
                                           mock_process_dependency_type):
        attr = AttrFactory.create()
        target = ClassFactory.create()
        xs_int = AttrTypeFactory.native(DataType.INT)

        self.processor.process_type(target, attr, xs_int)
        self.assertEqual(0, mock_process_dependency_type.call_count)
        mock_process_native_type.assert_called_once_with(attr, xs_int)

    @mock.patch.object(AttributeTypeHandler, "process_dependency_type")
    @mock.patch.object(AttributeTypeHandler, "process_native_type")
    def test_process_type_with_dependency_type(self, mock_process_native_type,
                                               mock_process_dependency_type):
        attr = AttrFactory.create()
        target = ClassFactory.create()
        attr_type = AttrTypeFactory.create()

        self.processor.process_type(target, attr, attr_type)
        self.assertEqual(0, mock_process_native_type.call_count)
        mock_process_dependency_type.assert_called_once_with(
            target, attr, attr_type)

    @mock.patch.object(AttributeTypeHandler, "process_inner_type")
    def test_process_type_with_forward_reference(self,
                                                 mock_process_inner_type):
        attr = AttrFactory.create()
        target = ClassFactory.create()
        attr_type = AttrTypeFactory.create(forward=True)

        self.processor.process_type(target, attr, attr_type)
        mock_process_inner_type.assert_called_once_with(
            target, attr, attr_type)

    def test_process_native_type(self):
        attr = AttrFactory.native(DataType.INT)
        nm_tokens_type = AttrTypeFactory.native(DataType.NMTOKENS)

        self.processor.process_native_type(attr, attr.types[0])
        self.assertEqual(str(DataType.INT), attr.types[0].qname)

        attr.restrictions.pattern = "[a-z]"
        self.processor.process_native_type(attr, attr.types[0])
        self.assertEqual(str(DataType.STRING), attr.types[0].qname)

        self.processor.process_native_type(attr, nm_tokens_type)
        self.assertTrue(attr.restrictions.tokens)

    @mock.patch.object(AttributeTypeHandler, "reset_attribute_type")
    @mock.patch.object(AttributeTypeHandler, "find_dependency")
    def test_process_dependency_type_with_absent_type(
            self, mock_find_dependency, mock_reset_attribute_type):
        mock_find_dependency.return_value = None
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]

        self.processor.process_dependency_type(target, attr, attr_type)
        mock_reset_attribute_type.assert_called_once_with(attr_type, True)

    @mock.patch.object(AttributeTypeHandler, "reset_attribute_type")
    @mock.patch.object(AttributeTypeHandler, "find_dependency")
    def test_process_dependency_type_with_dummy_type(
            self, mock_find_dependency, mock_reset_attribute_type):
        mock_find_dependency.return_value = ClassFactory.create(
            tag=Tag.ELEMENT)
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]

        self.processor.process_dependency_type(target, attr, attr_type)
        mock_reset_attribute_type.assert_called_once_with(attr_type, False)

    @mock.patch.object(AttributeTypeHandler, "copy_attribute_properties")
    @mock.patch.object(AttributeTypeHandler, "find_dependency")
    def test_process_dependency_type_with_simple_type(
            self, mock_find_dependency, mock_copy_attribute_properties):
        simple = ClassFactory.simple_type()
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]
        mock_find_dependency.return_value = simple

        self.processor.process_dependency_type(target, attr, attr_type)
        mock_copy_attribute_properties.assert_called_once_with(
            simple, target, attr, attr_type)

    @mock.patch.object(AttributeTypeHandler, "find_dependency")
    def test_process_dependency_type_with_enumeration_type(
            self, mock_find_dependency):
        enumeration = ClassFactory.enumeration(2)
        enumeration.attrs[1].restrictions.format = "base16"
        mock_find_dependency.return_value = enumeration

        target = ClassFactory.simple_type()
        attr = target.attrs[0]
        attr.types[0] = AttrTypeFactory.create(qname=enumeration.qname)

        self.processor.process_dependency_type(target, attr, attr.types[0])
        self.assertEqual("base16", attr.restrictions.format)

    @mock.patch.object(AttributeTypeHandler, "set_circular_flag")
    @mock.patch.object(AttributeTypeHandler, "find_dependency")
    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)

    @mock.patch.object(AttributeTypeHandler, "update_restrictions")
    @mock.patch.object(AttributeTypeHandler, "copy_attribute_properties")
    def test_process_inner_type_with_simple_type(
            self, mock_copy_attribute_properties, mock_update_restrictions):
        attr = AttrFactory.create(
            types=[AttrTypeFactory.create(qname="{bar}a")])
        inner = ClassFactory.simple_type(qname="{bar}a",
                                         status=Status.PROCESSED)
        target = ClassFactory.create(inner=[inner])

        self.processor.process_inner_type(target, attr, attr.types[0])
        self.assertNotIn(inner, target.inner)

        self.assertEqual(0, mock_update_restrictions.call_count)
        mock_copy_attribute_properties.assert_called_once_with(
            inner, target, attr, attr.types[0])

    @mock.patch.object(AttributeTypeHandler, "update_restrictions")
    @mock.patch.object(AttributeTypeHandler, "copy_attribute_properties")
    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)

    @mock.patch.object(AttributeTypeHandler, "update_restrictions")
    @mock.patch.object(AttributeTypeHandler, "copy_attribute_properties")
    def test_process_inner_type_with_circular_reference(
            self, mock_copy_attribute_properties, mock_update_restrictions):
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = AttrTypeFactory.create(circular=True)

        self.processor.process_inner_type(target, attr, attr_type)
        self.assertEqual(0, mock_copy_attribute_properties.call_count)
        self.assertEqual(0, mock_update_restrictions.call_count)

    @mock.patch.object(ClassUtils, "copy_inner_class")
    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_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)

    @mock.patch.object(AttributeTypeHandler, "is_circular_dependency")
    def test_set_circular_flag(self, mock_is_circular_dependency):
        source = ClassFactory.create()
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]

        mock_is_circular_dependency.return_value = True

        self.processor.set_circular_flag(source, target, attr_type)
        self.assertTrue(attr_type.circular)

        mock_is_circular_dependency.assert_called_once_with(
            source, target, set())

    @mock.patch.object(ClassContainer, "find")
    @mock.patch.object(Class, "dependencies")
    def test_is_circular_dependency(self, mock_dependencies,
                                    mock_container_find):
        source = ClassFactory.create()
        target = ClassFactory.create()
        another = ClassFactory.create()
        processing = ClassFactory.create(status=Status.PROCESSING)

        find_classes = {"a": another, "b": target}

        mock_container_find.side_effect = lambda x: find_classes.get(x)
        mock_dependencies.side_effect = [
            list("ccde"),
            list("abc"),
            list("xy"),
        ]

        self.assertTrue(
            self.processor.is_circular_dependency(processing, target, set()))

        self.processor.dependencies.clear()
        self.assertFalse(
            self.processor.is_circular_dependency(source, target, set()))

        self.processor.dependencies.clear()
        self.assertTrue(
            self.processor.is_circular_dependency(source, target, set()))

        self.processor.dependencies.clear()
        self.assertTrue(
            self.processor.is_circular_dependency(source, source, set()))

        mock_container_find.assert_has_calls([
            mock.call("c"),
            mock.call("d"),
            mock.call("e"),
            mock.call("a"),
            mock.call("x"),
            mock.call("y"),
            mock.call("b"),
        ])

    def test_find_dependency(self):
        attr_type = AttrTypeFactory.create(qname="a")

        self.assertIsNone(
            self.processor.find_dependency(attr_type, Tag.ELEMENT))

        abstract = ClassFactory.create(qname="a",
                                       tag=Tag.COMPLEX_TYPE,
                                       abstract=True)
        self.processor.container.add(abstract)
        self.assertEqual(
            abstract, self.processor.find_dependency(attr_type, Tag.ELEMENT))

        element = ClassFactory.create(qname="a", tag=Tag.ELEMENT)
        self.processor.container.add(element)
        self.assertEqual(
            element, self.processor.find_dependency(attr_type,
                                                    Tag.SIMPLE_TYPE))

        simple = ClassFactory.create(qname="a", tag=Tag.SIMPLE_TYPE)
        self.processor.container.add(simple)
        self.assertEqual(
            simple, self.processor.find_dependency(attr_type, Tag.SIMPLE_TYPE))

    @mock.patch.object(Class, "dependencies")
    def test_cached_dependencies(self, mock_class_dependencies):
        mock_class_dependencies.return_value = ["a", "b"]

        source = ClassFactory.create()
        self.processor.dependencies[id(source)] = ("a", )

        actual = self.processor.cached_dependencies(source)
        self.assertEqual(("a", ), actual)

        self.processor.dependencies.clear()
        actual = self.processor.cached_dependencies(source)
        self.assertEqual(("a", "b"), actual)
        mock_class_dependencies.assert_called_once_with()

    def test_update_restrictions(self):
        attr = AttrFactory.create()
        self.processor.update_restrictions(attr, DataType.NMTOKENS)
        self.assertTrue(attr.restrictions.tokens)

        attr = AttrFactory.create()
        self.processor.update_restrictions(attr, DataType.IDREFS)
        self.assertTrue(attr.restrictions.tokens)

        attr = AttrFactory.create()
        self.processor.update_restrictions(attr, DataType.BASE64_BINARY)
        self.assertEqual("base64", attr.restrictions.format)

        attr = AttrFactory.create()
        self.processor.update_restrictions(attr, DataType.HEX_BINARY)
        self.assertEqual("base16", attr.restrictions.format)

    def test_filter_types(self):
        xs_string = AttrTypeFactory.native(DataType.STRING)
        xs_error = AttrTypeFactory.native(DataType.ERROR)
        xs_any = AttrTypeFactory.native(DataType.ANY_TYPE)

        types = [
            xs_string.clone(),
            xs_string.clone(),
            xs_string.clone(),
            xs_error.clone(),
        ]

        actual = self.processor.filter_types(types)

        self.assertEqual(1, len(actual))

        types.append(xs_any)
        actual = self.processor.filter_types(types)
        self.assertEqual(1, len(actual))
        self.assertEqual(xs_string, actual[0])

        actual = self.processor.filter_types([])
        self.assertEqual(xs_string, actual[0])

        types = [xs_any]
        actual = self.processor.filter_types(types)
        self.assertEqual(1, len(actual))
示例#5
0
class AttributeTypeHandlerTests(FactoryTestCase):
    def setUp(self):
        super().setUp()

        container = ClassContainer()
        self.processor = AttributeTypeHandler(container=container)

    @mock.patch.object(AttributeTypeHandler, "process_type")
    def test_process(self, mock_process_type):
        xs_int = AttrTypeFactory.xs_int()
        xs_bool = AttrTypeFactory.xs_bool()
        xs_string = AttrTypeFactory.xs_string()

        target = ClassFactory.create(attrs=[
            AttrFactory.create(types=[xs_int, xs_bool]),
            AttrFactory.create(types=[xs_string, xs_string]),
        ])

        self.processor.process(target)
        self.assertEqual(2, len(target.attrs[0].types))
        self.assertEqual(1, len(target.attrs[1].types))  # remove duplicate

        mock_process_type.assert_has_calls([
            mock.call(target, target.attrs[0], xs_int),
            mock.call(target, target.attrs[0], xs_bool),
            mock.call(target, target.attrs[1], xs_string),
            mock.call(target, target.attrs[1], xs_string),
        ])

    @mock.patch.object(AttributeTypeHandler, "process_dependency_type")
    @mock.patch.object(AttributeTypeHandler, "process_native_type")
    def test_process_type_with_native_type(self, mock_process_native_type,
                                           mock_process_dependency_type):
        attr = AttrFactory.create()
        target = ClassFactory.create()
        xs_int = AttrTypeFactory.xs_int()

        self.processor.process_type(target, attr, xs_int)
        self.assertEqual(0, mock_process_dependency_type.call_count)
        mock_process_native_type.assert_called_once_with(attr, xs_int)

    @mock.patch.object(AttributeTypeHandler, "process_dependency_type")
    @mock.patch.object(AttributeTypeHandler, "process_native_type")
    def test_process_type_with_dependency_type(self, mock_process_native_type,
                                               mock_process_dependency_type):
        attr = AttrFactory.create()
        target = ClassFactory.create()
        attr_type = AttrTypeFactory.create()

        self.processor.process_type(target, attr, attr_type)
        self.assertEqual(0, mock_process_native_type.call_count)
        mock_process_dependency_type.assert_called_once_with(
            target, attr, attr_type)

    @mock.patch.object(AttributeTypeHandler, "process_dependency_type")
    @mock.patch.object(AttributeTypeHandler, "process_native_type")
    def test_process_type_with_inner_type(self, mock_process_native_type,
                                          mock_process_dependency_type):
        attr = AttrFactory.create()
        target = ClassFactory.create()
        attr_type = AttrTypeFactory.create(forward=True)

        self.processor.process_type(target, attr, attr_type)
        self.assertEqual(0, mock_process_native_type.call_count)
        self.assertEqual(0, mock_process_dependency_type.call_count)

    def test_process_native_type(self):
        attr = AttrFactory.create()
        xs_int = AttrTypeFactory.xs_int()
        xs_int_clone = xs_int.clone()

        self.processor.process_native_type(attr, xs_int)
        self.assertEqual(xs_int_clone, xs_int)

        attr.restrictions.pattern = "[a-z]"
        self.processor.process_native_type(attr, xs_int)
        self.assertEqual(AttrTypeFactory.xs_string(), xs_int)

    @mock.patch.object(AttributeTypeHandler, "reset_attribute_type")
    @mock.patch.object(AttributeTypeHandler, "find_dependency")
    def test_process_dependency_type_with_absent_type(
        self,
        mock_find_dependency,
        mock_reset_attribute_type,
    ):
        mock_find_dependency.return_value = None
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]

        self.processor.process_dependency_type(target, attr, attr_type)
        mock_reset_attribute_type.assert_called_once_with(attr_type)

    @mock.patch.object(AttributeTypeHandler, "process_simple_dependency")
    @mock.patch.object(AttributeTypeHandler, "find_dependency")
    def test_process_dependency_type_with_simple_type(
        self,
        mock_find_dependency,
        mock_process_simple_dependency,
    ):
        simple = ClassFactory.create(type=SimpleType)

        mock_find_dependency.return_value = simple

        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]

        self.processor.process_dependency_type(target, attr, attr_type)
        mock_process_simple_dependency.assert_called_once_with(
            simple, target, attr, attr_type)

    @mock.patch.object(AttributeTypeHandler, "process_complex_dependency")
    @mock.patch.object(AttributeTypeHandler, "find_dependency")
    def test_process_dependency_type_with_complex_type(
        self,
        mock_find_dependency,
        mock_process_complex_dependency,
    ):
        complex = ClassFactory.create(type=ComplexType)
        element = ClassFactory.create(type=Element)

        mock_find_dependency.side_effect = [complex, element]

        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]

        self.processor.process_dependency_type(target, attr, attr_type)
        self.processor.process_dependency_type(target, attr, attr_type)

        mock_process_complex_dependency.assert_has_calls([
            mock.call(complex, target, attr_type),
            mock.call(element, target, attr_type),
        ])

    @mock.patch.object(ClassUtils, "copy_inner_classes")
    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_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_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_simple_dependency_with_enumeration(self):
        source = ClassFactory.enumeration(2)
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]
        expected = attr_type.clone()

        self.processor.process_simple_dependency(source, target, attr,
                                                 attr_type)
        self.assertEqual(expected, attr_type)

    @mock.patch.object(AttributeTypeHandler, "is_circular_dependency")
    def test_process_complex_dependency(self, mock_is_circular_dependency):
        source = ClassFactory.create()
        target = ClassFactory.create()
        attr = AttrFactory.create()
        attr_type = attr.types[0]

        mock_is_circular_dependency.return_value = True

        self.processor.process_complex_dependency(source, target, attr_type)
        self.assertTrue(attr_type.circular)

        mock_is_circular_dependency.assert_called_once_with(
            source, target, set())

    @mock.patch.object(ClassContainer, "find")
    @mock.patch.object(Class, "dependencies")
    def test_is_circular_dependency(self, mock_dependencies,
                                    mock_container_find):
        source = ClassFactory.create()
        target = ClassFactory.create()
        another = ClassFactory.create()
        processing = ClassFactory.create(status=Status.PROCESSING)

        find_classes = {QName("a"): another, QName("b"): target}

        mock_container_find.side_effect = lambda x: find_classes.get(x)
        mock_dependencies.side_effect = [
            [QName(x) for x in "ccde"],
            [QName(x) for x in "abc"],
            [QName(x) for x in "xy"],
        ]

        self.assertTrue(
            self.processor.is_circular_dependency(processing, target, set()))

        self.processor.dependencies.clear()
        self.assertFalse(
            self.processor.is_circular_dependency(source, target, set()))

        self.processor.dependencies.clear()
        self.assertTrue(
            self.processor.is_circular_dependency(source, target, set()))

        self.processor.dependencies.clear()
        self.assertTrue(
            self.processor.is_circular_dependency(source, source, set()))

        mock_container_find.assert_has_calls([
            mock.call(QName("c")),
            mock.call(QName("d")),
            mock.call(QName("e")),
            mock.call(QName("a")),
            mock.call(QName("x")),
            mock.call(QName("y")),
            mock.call(QName("b")),
        ])

    def test_find_dependency(self):
        attr_type = AttrTypeFactory.create(qname="a")

        self.assertIsNone(self.processor.find_dependency(attr_type))

        abstract = ClassFactory.create(qname="a",
                                       type=ComplexType,
                                       abstract=True)
        self.processor.container.add(abstract)
        self.assertEqual(abstract, self.processor.find_dependency(attr_type))

        element = ClassFactory.create(qname="a", type=Element)
        self.processor.container.add(element)
        self.assertEqual(element, self.processor.find_dependency(attr_type))

        simple = ClassFactory.create(qname="a", type=SimpleType)
        self.processor.container.add(simple)
        self.assertEqual(simple, self.processor.find_dependency(attr_type))

    @mock.patch.object(Class, "dependencies")
    def test_cached_dependencies(self, mock_class_dependencies):
        a_qname = QName("a")
        b_qname = QName("b")

        mock_class_dependencies.return_value = [a_qname, b_qname]

        source = ClassFactory.create()
        self.processor.dependencies[id(source)] = (a_qname, )

        actual = self.processor.cached_dependencies(source)
        self.assertEqual((a_qname, ), actual)

        self.processor.dependencies.clear()
        actual = self.processor.cached_dependencies(source)
        self.assertEqual((a_qname, b_qname), actual)
        mock_class_dependencies.assert_called_once_with()