def test_link_association_has_a_compatible_superclass(self):
        code = CMetaclass("Code")

        source = CMetaclass("Source")
        code.association(source, "[contained_code] * -> [source] *")

        code_a = CMetaclass("Code A", superclasses=code)
        code_b = CMetaclass("Code B", superclasses=code)
        a_b_association = code_a.association(code_b, "a_b: [code_a] * -> [code_b] *")

        source_1 = CClass(source, "source_1")

        code_a1 = CClass(code_a, "code_a1")
        code_b1 = CClass(code_b, "code_b1")
        code_b2 = CClass(code_b, "code_b2")
        links = add_links({code_a1: [code_b1, code_b2]}, association=a_b_association)

        try:
            add_links({source_1: [code_a1, code_b2, code_b1, links[0], links[1]]},
                      role_name="contained_code")
            exception_expected_()
        except CException as e:
            eq_("the metaclass link's association is missing a compatible classifier", e.value)

        a_b_association.superclasses = self.mcl
        try:
            add_links({source_1: [code_a1, code_b2, code_b1, links[0], links[1]]},
                      role_name="contained_code")
            exception_expected_()
        except CException as e:
            eq_("no common metaclass for classes or links found", e.value)

        a_b_association.superclasses = code_b
        add_links({source_1: [code_a1, code_b2, code_b1, links[0], links[1]]},
                  role_name="contained_code")
    def test_check_derived_association_is_metaclass_association(self):
        m1 = CMetaclass("MC1")
        m2 = CMetaclass("MC2")

        try:
            m1.association(m2, "* -> 1", derived_from=self.a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "association 'derived_from' is called on is not a class-level association")
 def test_association_to_association_not_possible(self):
     clx = CMetaclass("X")
     cla = CMetaclass("A")
     clb = CMetaclass("B")
     a_b_association = cla.association(clb, "a_b: [a] * -> [b] *")
     try:
         clx.association(a_b_association, "[x] * -> [a_b_association] *")
         exception_expected_()
     except CException as e:
         eq_("metaclass 'X' is not compatible with association target 'a_b'", e.value)
    def test_links_as_attribute_values(self):
        code = CMetaclass("Code")
        source = CMetaclass("Source")
        code.association(source, "[contained_code] * -> [source] *")
        code_a = CMetaclass("Code A", superclasses=code)
        code_b = CMetaclass("Code B", superclasses=code)
        a_b_association = code_a.association(code_b, "a_b: [code_a] * -> [code_b] *", superclasses=code)
        CClass(source, "source_1")
        code_a1 = CClass(code_a, "code_a1")
        code_b1 = CClass(code_b, "code_b1")
        code_b2 = CClass(code_b, "code_b2")
        a_b_links = add_links({code_a1: [code_b1, code_b2]}, association=a_b_association)

        links_list = [code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1]]

        collection_type = CMetaclass("Collection Type", attributes={
            "primary_code": code,
            "default_value_code": a_b_links[0],
            "codes": list,
            "default_values_list": links_list
        })
        collection = CClass(collection_type)

        eq_(collection.get_value("primary_code"), None)
        eq_(collection.get_value("default_value_code"), a_b_links[0])
        eq_(collection.get_value("codes"), None)
        eq_(collection.get_value("default_values_list"), links_list)

        collection.set_value("primary_code", a_b_links[1])
        collection.set_value("default_value_code", a_b_links[1])
        collection.set_value("codes", [code_a1, a_b_links[0]])
        collection.set_value("default_values_list", [a_b_links[0], a_b_links[1]])

        eq_(collection.get_value("primary_code"), a_b_links[1])
        eq_(collection.get_value("default_value_code"), a_b_links[1])
        eq_(collection.get_value("codes"), [code_a1, a_b_links[0]])
        eq_(collection.get_value("default_values_list"), [a_b_links[0], a_b_links[1]])

        collection.values = {'default_values_list': [a_b_links[0]], "codes": []}

        eq_(collection.values, {'default_value_code': a_b_links[1],
                                'default_values_list': [a_b_links[0]],
                                'codes': [],
                                'primary_code': a_b_links[1]})

        collection.delete_value("primary_code")
        collection.delete_value("default_value_code")
        collection.delete_value("codes")
        collection.delete_value("default_values_list")

        eq_(collection.get_value("primary_code"), None)
        eq_(collection.get_value("default_value_code"), None)
        eq_(collection.get_value("codes"), None)
        eq_(collection.get_value("default_values_list"), None)
    def test_link_to_link(self):
        collection1 = CMetaclass("Collection1")
        collection2 = CMetaclass("Collection2")
        collections_association = collection1.association(collection2,
                                                          "element references: [references] * -> [referenced] *")
        type_a = CMetaclass("Type A", superclasses=collection1)
        type_b = CMetaclass("Type B", superclasses=collection1)
        a_b_association = type_a.association(type_b, "a_b: [type_a] * -> [type_b] *", superclasses=collection1)
        type_c = CMetaclass("Type C", superclasses=collection2)
        type_d = CMetaclass("Type D", superclasses=[collection1, collection2])
        c_d_association = type_c.association(type_d, "c_d: [type_c] * -> [type_d] *", superclasses=collection2)
        a_d_association = type_a.association(type_d, "a_d: [type_a] * -> [type_d] *",
                                             superclasses=[collection1, collection2])

        a1 = CClass(type_a, "a1")
        b1 = CClass(type_b, "b1")
        b2 = CClass(type_b, "b2")
        c1 = CClass(type_c, "c1")
        c2 = CClass(type_c, "c2")
        d1 = CClass(type_d, "d1")

        a_b_links = add_links({a1: [b1, b2]}, association=a_b_association)
        c_d_links = add_links({d1: [c1, c2]}, association=c_d_association)
        a_d_links = add_links({a1: [d1]}, association=a_d_association)

        references_links = add_links({a_b_links[0]: c_d_links[0],
                                      a_b_links[1]: [c1, c2, d1, c_d_links[1], c_d_links[0]],
                                      a_d_links[0]: [a_d_links[0], c_d_links[1], c1, d1]}, role_name="referenced")

        eq_(set(a_b_links[0].get_linked(role_name="referenced")),
            {c_d_links[0]})
        eq_(set(a_b_links[0].linked), {c_d_links[0]})
        eq_(set(a_b_links[0].links), {references_links[0]})
        eq_(set(a_b_links[0].get_links_for_association(collections_association)), {references_links[0]})
        eq_(set(get_links([a_b_links[0]])), {references_links[0]})

        eq_(set(a_b_links[1].get_linked(role_name="referenced")),
            {c1, c2, d1, c_d_links[1], c_d_links[0]})
        eq_(set(a_b_links[1].linked), {c1, c2, d1, c_d_links[1], c_d_links[0]})
        correct_links_set = {references_links[1], references_links[2], references_links[3], references_links[4],
                             references_links[5]}
        eq_(set(a_b_links[1].links), correct_links_set)
        eq_(set(a_b_links[1].get_links_for_association(collections_association)), correct_links_set)
        eq_(set(get_links([a_b_links[1]])), correct_links_set)

        eq_(set(a_d_links[0].get_linked(role_name="referenced")),
            {a_d_links[0], c_d_links[1], c1, d1})
        eq_(set(a_d_links[0].linked), {a_d_links[0], c_d_links[1], c1, d1})
        correct_links_set = {references_links[6], references_links[7], references_links[8], references_links[9]}
        eq_(set(a_d_links[0].links), correct_links_set)
        eq_(set(a_d_links[0].get_links_for_association(collections_association)), correct_links_set)
        eq_(set(get_links([a_d_links[0]])), correct_links_set)
示例#6
0
    def test_add_links_with_inherited_common_classifiers(self):
        super_a = CMetaclass("SuperA")
        super_b = CMetaclass("SuperB")
        super_a.association(super_b, "[a] 1 -> [b] *")

        sub_b1 = CMetaclass("SubB1", superclasses=[super_b])
        sub_b2 = CMetaclass("SubB2", superclasses=[super_b])
        sub_a = CMetaclass("SubA", superclasses=[super_a])

        cl_a = CClass(sub_a, "a")
        cl_b1 = CClass(sub_b1, "b1")
        cl_b2 = CClass(sub_b2, "b2")

        add_links({cl_a: [cl_b1, cl_b2]}, role_name="b")
        eq_(set(cl_a.get_linked(role_name="b")), {cl_b1, cl_b2})
class TestStereotypeInstancesOnDerivedAssociations:
    def setup(self):
        self.m1 = CMetaclass("M1")
        self.m2 = CMetaclass("M2")
        self.m3 = CMetaclass("M3")
        self.a = self.m1.association(self.m2, name="a", multiplicity="*", role_name="m2",
                                     source_multiplicity="1..*", source_role_name="m1")

    def test_stereotype_instances_on_derived_association(self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", extended=self.a)
        s3 = CStereotype("S3", extended=self.a)

        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)

        eq_(a1.stereotype_instances, [])
        eq_(s1.extended_instances, [])
        a1.stereotype_instances = [s1]
        eq_(s1.extended_instances, [a1])
        eq_(a1.stereotype_instances, [s1])
        a1.stereotype_instances = [s1, s2, s3]
        eq_(s1.extended_instances, [a1])
        eq_(s2.extended_instances, [a1])
        eq_(s3.extended_instances, [a1])
        eq_(set(a1.stereotype_instances), {s1, s2, s3})
        a1.stereotype_instances = s2
        eq_(a1.stereotype_instances, [s2])
        eq_(s1.extended_instances, [])
        eq_(s2.extended_instances, [a1])
        eq_(s3.extended_instances, [])

        eq_(c1.associations, [a1])
        eq_(c2.associations, [a1])

    def test_stereotype_instances_on_derived_association_and_links_in_combination(self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", extended=self.a)
        s3 = CStereotype("S3", extended=self.a)

        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m2, "C3")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)
        links = set_links({c1: [c2, c3]})
        l1 = links[0]

        a1.stereotype_instances = [s1]
        l1.stereotype_instances = [s1]
        eq_(set(s1.extended_instances), {a1, l1})
        eq_(a1.stereotype_instances, [s1])
        eq_(l1.stereotype_instances, [s1])
        a1.stereotype_instances = [s1, s2, s3]
        eq_(set(s1.extended_instances), {a1, l1})
        eq_(s2.extended_instances, [a1])
        eq_(s3.extended_instances, [a1])
        eq_(set(a1.stereotype_instances), {s1, s2, s3})
        eq_(set(l1.stereotype_instances), {s1})
        l1.stereotype_instances = [s1, s2, s3]
        eq_(set(s1.extended_instances), {a1, l1})
        eq_(set(s2.extended_instances), {a1, l1})
        eq_(set(s3.extended_instances), {a1, l1})
        eq_(set(a1.stereotype_instances), {s1, s2, s3})
        eq_(set(l1.stereotype_instances), {s1, s2, s3})
        a1.stereotype_instances = s2
        eq_(a1.stereotype_instances, [s2])
        eq_(set(l1.stereotype_instances), {s1, s2, s3})
        eq_(s1.extended_instances, [l1])
        eq_(set(s2.extended_instances), {a1, l1})
        eq_(s3.extended_instances, [l1])
        l1.stereotype_instances = s3
        eq_(a1.stereotype_instances, [s2])
        eq_(l1.stereotype_instances, [s3])
        eq_(s1.extended_instances, [])
        eq_(s2.extended_instances, [a1])
        eq_(s3.extended_instances, [l1])

    def test_stereotype_instances_double_assignment(self):
        s1 = CStereotype("S1", extended=self.a)

        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)

        try:
            a1.stereotype_instances = [s1, s1]
            exception_expected_()
        except CException as e:
            eq_(e.value, "'S1' is already a stereotype instance on association from 'C1' to 'C2'")
        eq_(a1.stereotype_instances, [s1])

    def test_stereotype_instances_none_assignment(self):
        CStereotype("S1", extended=self.a)

        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)

        try:
            a1.stereotype_instances = [None]
            exception_expected_()
        except CException as e:
            eq_(e.value, "'None' is not a stereotype")
        eq_(a1.stereotype_instances, [])

    def test_stereotype_instances_wrong_type_in_assignment(self):
        CStereotype("S1", extended=self.a)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)

        try:
            a1.stereotype_instances = self.a
            exception_expected_()
        except CException as e:
            eq_(e.value, "a list or a stereotype is required as input")
        eq_(a1.stereotype_instances, [])

    def test_multiple_extended_instances(self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", extended=self.a)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m2, "C3")

        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)
        a2 = c1.association(c3, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)
        a3 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)

        a1.stereotype_instances = [s1]
        eq_(s1.extended_instances, [a1])
        a2.stereotype_instances = [s1]
        eq_(set(s1.extended_instances), {a1, a2})
        a3.stereotype_instances = [s1, s2]
        eq_(set(s1.extended_instances), {a1, a2, a3})
        eq_(set(s2.extended_instances), {a3})

    def test_delete_stereotype_of_extended_instances(self):
        s1 = CStereotype("S1", extended=self.a)
        s1.delete()
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)
        try:
            a1.stereotype_instances = [s1]
            exception_expected_()
        except CException as e:
            eq_(e.value, "cannot access named element that has been deleted")

    def test_delete_stereotyped_element_instance(self):
        s1 = CStereotype("S1", extended=self.a)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a,
                            stereotype_instances=[s1])
        eq_(s1.extended_instances, [a1])
        eq_(a1.stereotype_instances, [s1])
        a1.delete()
        eq_(s1.extended_instances, [])
        eq_(a1.stereotype_instances, [])

    def test_add_stereotype_instance_wrong_association(self):
        other_association = self.m1.association(self.m2, name="b", multiplicity="*", role_name="m1",
                                                source_multiplicity="1", source_role_name="m2")
        s1 = CStereotype("S1", extended=self.a)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=other_association)
        try:
            a1.stereotype_instances = [s1]
            exception_expected_()
        except CException as e:
            eq_(e.value,
                "stereotype 'S1' cannot be added to association from 'C1' to 'C2': " +
                "no extension by this stereotype found")

    def test_add_stereotype_of_inherited_metaclass(self):
        sub1 = CMetaclass("Sub1", superclasses=self.m1)
        sub2 = CMetaclass("Sub2", superclasses=self.m2)
        s = CStereotype("S1", extended=self.a)
        c1 = CClass(sub1, "C1")
        c2 = CClass(sub2, "C2")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a,
                            stereotype_instances=s)
        eq_(s.extended_instances, [a1])
        eq_(a1.stereotype_instances, [s])

    def test_add_stereotype_instance_correct_by_inheritance_of_stereotype(self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", superclasses=s1)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a,
                            stereotype_instances=s2)
        eq_(s2.extended_instances, [a1])
        eq_(a1.stereotype_instances, [s2])

    def test_all_extended_instances(self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", superclasses=s1)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m2, "C3")
        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)
        a2 = c1.association(c3, name="a", multiplicity="*", role_name="c3",
                            source_multiplicity="1", source_role_name="c1", derived_from=self.a)
        a1.stereotype_instances = s1
        a2.stereotype_instances = s2
        eq_(s1.extended_instances, [a1])
        eq_(s2.extended_instances, [a2])
        eq_(s1.all_extended_instances, [a1, a2])
        eq_(s2.all_extended_instances, [a2])

    def test_adding_stereotype_before_derived_from_is_used(self):
        sub1 = CMetaclass("Sub1", superclasses=self.m1)
        sub2 = CMetaclass("Sub2", superclasses=self.m2)
        s = CStereotype("S1", extended=self.a)
        c1 = CClass(sub1, "C1")
        c2 = CClass(sub2, "C2")
        try:
            a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                                source_multiplicity="1", source_role_name="c1", stereotype_instances=s,
                                derived_from=self.a)
            exception_expected_()
        except CException as e:
            eq_(e.value,
                "stereotype 'S1' cannot be added to association from 'C1' to 'C2': " +
                "no extension by this stereotype found")

    def test_derived_from_wrong_type(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        try:
            c1.association(c2, name="a", multiplicity="*", role_name="c2",
                           source_multiplicity="*", source_role_name="c1",
                           derived_from=self.m2)
            exception_expected_()
        except CException as e:
            eq_(e.value, "'M2' is not an association")

    def test_derived_from_getters(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a1 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1")
        eq_(a1.derived_from, None)
        eq_(self.a.derived_associations, [])

        a2 = c1.association(c2, name="a", multiplicity="*", role_name="c2",
                            source_multiplicity="1", source_role_name="c1",
                            derived_from=self.a)
        eq_(a2.derived_from, self.a)
        eq_(set(self.a.derived_associations), {a2})

        a1.derived_from = self.a
        eq_(a1.derived_from, self.a)
        eq_(set(self.a.derived_associations), {a1, a2})

    def test_source_multiplicities_derived_from_metaclass(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")
        try:
            c1.association(c2, name="a", multiplicity="*", role_name="c2",
                           source_multiplicity="*", source_role_name="c1",
                           derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "source lower multiplicity '0' smaller than metaclass' source lower " +
                "multiplicity '1' this association is derived from")
        try:
            c1.association(c2, name="a", multiplicity="*", role_name="c2",
                           source_multiplicity="1..*", source_role_name="c1",
                           derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "source upper multiplicity '*' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' source upper " +
                "multiplicity '1' this association is derived from")

        b = self.m1.association(self.m2, "a: [m1] 2..4 -> [m2] *")

        c1.association(c2, "a: [c1] 2..3 -> [c2] *", derived_from=b)

        try:
            c1.association(c2, "a: [c1] 1..* -> [c2] *", derived_from=b)
            exception_expected_()
        except CException as e:
            eq_(e.value, "source lower multiplicity '1' smaller than metaclass' source lower " +
                "multiplicity '2' this association is derived from")
        try:
            c1.association(c2, "a: [c1] 2..* -> [c2] *", derived_from=b)
            exception_expected_()
        except CException as e:
            eq_(e.value, "source upper multiplicity '*' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' source upper " +
                "multiplicity '4' this association is derived from")

    def test_target_multiplicities_derived_from_metaclass(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a = self.m1.association(self.m2, "* -> 1")
        try:
            c1.association(c2, name="a", multiplicity="*", role_name="c2",
                           source_multiplicity="*", source_role_name="c1",
                           derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "lower multiplicity '0' smaller than metaclass' lower " +
                "multiplicity '1' this association is derived from")
        try:
            c1.association(c2, name="a", multiplicity="1..*", role_name="c2",
                           source_multiplicity="*", source_role_name="c1",
                           derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "upper multiplicity '*' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' upper " +
                "multiplicity '1' this association is derived from")

        b = self.m1.association(self.m2, "a: * -> 2..4")

        c1.association(c2, "* -> 2..3", derived_from=b)

        try:
            c1.association(c2, name="a", multiplicity="1..*", role_name="c2",
                           source_multiplicity="*", source_role_name="c1",
                           derived_from=b)
            exception_expected_()
        except CException as e:
            eq_(e.value, "lower multiplicity '1' smaller than metaclass' lower " +
                "multiplicity '2' this association is derived from")
        try:
            c1.association(c2, "* -> 2..*", derived_from=b)
            exception_expected_()
        except CException as e:
            eq_(e.value, "upper multiplicity '*' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' upper " +
                "multiplicity '4' this association is derived from")

    def test_derived_from_source_multiplicities_on_multiple_associations(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")
        try:
            c1.association(c2, "a1: [c1] 1 -> [c2] *", derived_from=a)
            c1.association(c2, "a1: [c1] 1 -> [c2] *", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "source upper multiplicity '2' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' source upper " +
                "multiplicity '1' this association is derived from")

    def test_derived_from_source_multiplicities_multiple_associations_from_different_sources_and_targets(self):
        c1a = CClass(self.m1, "C1A")
        c1b = CClass(self.m1, "C1B")
        c1c = CClass(self.m1, "C1C")
        c2a = CClass(self.m2, "C2A")
        c2b = CClass(self.m2, "C2B")
        c2c = CClass(self.m2, "C2B")

        a = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")

        # testing to check this does not raise an exception, as association sources/targets are different
        c1a.association(c2a, "a1: [c1a] 1 -> [c2a] *", derived_from=a)
        c1b.association(c2a, "a2: [c1b] 1 -> [c2a] *", derived_from=a)
        c1c.association(c2a, "a3: [c1c] 1 -> [c2a] *", derived_from=a)
        c1a.association(c2b, "a4: [c1a] 1 -> [c2b] *", derived_from=a)
        c1a.association(c2c, "a5: [c1a] 1 -> [c2c] *", derived_from=a)

    def test_derived_from_source_multiplicities_on_multiple_associations_inheritance1(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m1, "C3", superclasses=c1)
        c4 = CClass(self.m2, "C4", superclasses=c2)
        c5 = CClass(self.m3, "C5")

        a = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")
        b = self.m1.association(self.m3, "b: [m1] 1 -> [m3] *")

        try:
            c1.association(c5, "b1: 1 -> *", derived_from=b)
            c3.association(c4, "a-c3-c4: [c3] 1 -> [c4] *", derived_from=a)
            c1.association(c2, "a-c1-c2: [c1] 1 -> [c2] *", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "source upper multiplicity '2' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' source upper " +
                "multiplicity '1' this association is derived from")

    def test_derived_from_source_multiplicities_on_multiple_associations_inheritance2(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m1, "C3", superclasses=c1)

        a = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")

        try:
            c3.association(c2, "a1: [c3] 1 -> [c2] *", derived_from=a)
            c1.association(c2, "a2: [c1] 1..* -> [c2] *", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "source upper multiplicity '*' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' source upper " +
                "multiplicity '1' this association is derived from")

    def test_derived_from_source_multiplicities_on_multiple_associations_inheritance3(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m1, "C3", superclasses=c1)
        c4 = CClass(self.m2, "C4", superclasses=c2)

        a = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")

        c1_c2 = c1.association(c2, "a2: [c1] 1 -> [c2] *", derived_from=a)
        try:
            c3.association(c4, "a1: [c3] 1 -> [c4] *", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "source upper multiplicity '2' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' source upper " +
                "multiplicity '1' this association is derived from")
        eq_(set(a.derived_associations), {c1_c2})

    def test_derived_from_source_multiplicities_on_multiple_associations_other_derived_association(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c5 = CClass(self.m3, "C5")

        a = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")
        b = self.m1.association(self.m3, "b: [m1] 1 -> [m3] *")

        c1.association(c5, "b1: 1 -> *", derived_from=b)
        # testing to check this does not raise an exception, as other derived association is not
        # counted in source upper multiplicity count
        c1.association(c2, "a: [c1] 1 -> [c2] *", derived_from=a)

    def test_derived_from_target_multiplicities_on_multiple_associations(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a = self.m1.association(self.m2, "a: [m1] * -> [m2] 1")
        try:
            c1.association(c2, "a1: [c1] * -> [c2] 1", derived_from=a)
            c1.association(c2, "a1: [c1] * -> [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "upper multiplicity '2' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' upper " +
                "multiplicity '1' this association is derived from")

    def test_derived_from_target_multiplicities_multiple_associations_from_different_sources(self):
        c1a = CClass(self.m1, "C1A")
        c1b = CClass(self.m1, "C1B")
        c1c = CClass(self.m1, "C1C")
        c2a = CClass(self.m2, "C2A")
        c2b = CClass(self.m2, "C2B")
        c2c = CClass(self.m2, "C2B")

        a = self.m1.association(self.m2, "a: [m1] * -> [m2] 1")

        # testing to check this does not raise an exception, as association sources/targets are different
        c1a.association(c2a, "a1: [c1a] * -> [c2a] 1", derived_from=a)
        c1b.association(c2a, "a2: [c1b] * -> [c2a] 1", derived_from=a)
        c1c.association(c2a, "a3: [c1c] * -> [c2a] 1", derived_from=a)
        c1a.association(c2b, "a4: [c1a] * -> [c2b] 1", derived_from=a)
        c1a.association(c2c, "a5: [c1a] * -> [c2c] 1", derived_from=a)

    def test_derived_from_target_multiplicities_on_multiple_associations_inheritance1(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m1, "C3", superclasses=c1)
        c4 = CClass(self.m2, "C4", superclasses=c2)
        c5 = CClass(self.m3, "C5")

        a = self.m1.association(self.m2, "a: [m1] * -> [m2] 1")
        b = self.m1.association(self.m3, "b: [m1] * -> [m3] 1")

        try:
            c1.association(c5, "b1: * -> 1", derived_from=b)
            c3.association(c4, "a-c3-c4: [c3] * -> [c4] 1", derived_from=a)
            c1.association(c2, "a-c1-c2: [c1] * -> [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "upper multiplicity '2' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' upper " +
                "multiplicity '1' this association is derived from")

    def test_derived_from_target_multiplicities_on_multiple_associations_inheritance2(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m1, "C3", superclasses=c1)

        a = self.m1.association(self.m2, "a: [m1] * -> [m2] 1")

        try:
            c3.association(c2, "a1: [c3] * -> [c2] 1", derived_from=a)
            c1.association(c2, "a2: [c1] * -> [c2] 1..*", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "upper multiplicity '*' (of this association, maybe combined with other derived " +
                "associations of the same kind) is larger than metaclass' upper " +
                "multiplicity '1' this association is derived from")

    def test_derived_from_target_multiplicities_on_multiple_associations_other_derived_association(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c5 = CClass(self.m3, "C5")

        a = self.m1.association(self.m2, "a: [m1] * -> [m2] 1")
        b = self.m1.association(self.m3, "b: [m1] * -> [m3] 1")

        c1.association(c5, "b1: * -> 1", derived_from=b)
        # testing to check this does not raise an exception, as other derived association is not
        # counted in upper multiplicity count
        c1.association(c2, "a: [c1] * -> [c2] 1", derived_from=a)

    def test_check_derived_association_has_same_aggregation_state(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a = self.m1.association(self.m2, "a: [m1] * -> [m2] 1")
        try:
            c1.association(c2, "ac: [c1] * <>- [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "derived association is an aggregation, but metaclass association is not")

        a = self.m1.association(self.m2, "a: [m1] * <>- [m2] 1")
        try:
            c1.association(c2, "ac: [c1] * -> [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "metaclass association is an aggregation, but derived association is not")

        a = self.m1.association(self.m2, "a: [m1] * -> [m2] 1")
        try:
            c1.association(c2, "ac: [c1] * <*>- [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "derived association is a composition, but metaclass association is not")

        a = self.m1.association(self.m2, "a: [m1] * <*>- [m2] 1")
        try:
            c1.association(c2, "ac: [c1] * -> [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "metaclass association is a composition, but derived association is not")

        a = self.m1.association(self.m2, "a: [m1] * <*>- [m2] 1")
        try:
            c1.association(c2, "ac: [c1] * <>- [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "derived association is an aggregation, but metaclass association is not")

        a = self.m1.association(self.m2, "a: [m1] * <>- [m2] 1")
        try:
            c1.association(c2, "ac: [c1] * <*>- [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "metaclass association is an aggregation, but derived association is not")

        a = self.m1.association(self.m2, "a: [m1] * <>- [m2] 1")
        try:
            c1.association(c2, "ac: [c1] * <*>- [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "metaclass association is an aggregation, but derived association is not")

        a = self.m1.association(self.m2, "a: [m1] * <*>- [m2] 1")
        try:
            c1.association(c2, "ac: [c1] * <>- [c2] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "derived association is an aggregation, but metaclass association is not")

    def test_derived_from_reversing_source_and_target_not_supported(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")
        try:
            c2.association(c1, "a2: [c2] * -> [c1] 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "association source class 'C2' is not derived source metaclass 'M1'")

    def test_check_derived_from_non_metaclass_association(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a = c1.association(c2, "* -> 1")

        try:
            c1.association(c2, "* -> 1", derived_from=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "association used as 'derived_from' parameter is not a metaclass-level association")

    def test_check_derived_association_is_metaclass_association(self):
        m1 = CMetaclass("MC1")
        m2 = CMetaclass("MC2")

        try:
            m1.association(m2, "* -> 1", derived_from=self.a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "association 'derived_from' is called on is not a class-level association")

    def test_changing_single_derived_from_relation(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        ma = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")
        a1 = c1.association(c2, "1 -> *", derived_from=self.a)
        a1.derived_from = ma

        eq_(a1.derived_from, ma)
        eq_(self.a.derived_associations, [])
        eq_(set(ma.derived_associations), {a1})

    def test_changing_two_derived_from_relation(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        ma = self.m1.association(self.m2, "a: [m1] 1 -> [m2] *")
        a1 = c1.association(c2, "1 -> *", derived_from=self.a)
        a2 = c1.association(c2, "1 -> *", derived_from=self.a)
        a1.derived_from = ma

        eq_(a1.derived_from, ma)
        eq_(a2.derived_from, self.a)
        eq_(set(self.a.derived_associations), {a2})
        eq_(set(ma.derived_associations), {a1})

    def test_setting_derived_from_relation_to_none(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a1 = c1.association(c2, "1 -> *", derived_from=self.a)
        a1.derived_from = None

        eq_(a1.derived_from, None)
        eq_(self.a.derived_associations, [])

    def test_setting_one_of_two_derived_from_relations_to_none(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        a1 = c1.association(c2, "1 -> *", derived_from=self.a)
        a2 = c1.association(c2, "1 -> *", derived_from=self.a)
        a1.derived_from = None

        eq_(a1.derived_from, None)
        eq_(a2.derived_from, self.a)
        eq_(set(self.a.derived_associations), {a2})

    def test_delete_derived_association(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        c = c1.association(c2, "ac: [c1] 1 -> [c2] *")
        c.delete()
        eq_(c.derived_from, None)

        b = c1.association(c2, "ac: [c1] 1 -> [c2] *", derived_from=self.a)

        b.delete()

        eq_(b.derived_from, None)
        eq_(self.a.derived_associations, [])

    def test_delete_one_of_two_derived_association(self):
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        b1 = c1.association(c2, "ac: [c1] 1 -> [c2] *", derived_from=self.a)
        b2 = c1.association(c2, "ac: [c1] 1 -> [c2] *", derived_from=self.a)

        b1.delete()

        eq_(b1.derived_from, None)
        eq_(b2.derived_from, self.a)
        eq_(set(self.a.derived_associations), {b2})

    def test_delete_derived_from_metaclass_association(self):
        m = self.m1.association(self.m2, "a: [m1] 1..2 -> [m2] *")
        m.delete()
        eq_(m.derived_associations, [])

        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")

        ma = self.m1.association(self.m2, "a: [m1] 1..2 -> [m2] *")
        b1 = c1.association(c2, "ac: [c1] 1 -> [c2] *", derived_from=ma)
        b2 = c1.association(c2, "ac: [c1] 1 -> [c2] *", derived_from=ma)

        ma.delete()

        eq_(b1.derived_from, None)
        eq_(b2.derived_from, None)
        eq_(ma.derived_associations, [])
示例#8
0
as well as an ``edge_relation`` to define a graph of such nodes.

"""

from codeable_models import CMetaclass, CBundle

# node types
activity_node = CMetaclass("Activity Node")
control_node = CMetaclass("Control Node", superclasses=activity_node)
initial_node = CMetaclass("Initial Node", superclasses=control_node)
final_node = CMetaclass("Final Node", superclasses=control_node)
activity_final_node = CMetaclass("Activity Final Node", superclasses=final_node)
fork_node = CMetaclass("Fork Node", superclasses=control_node)
join_node = CMetaclass("Join Node", superclasses=control_node)
decision_node = CMetaclass("Decision Node", superclasses=control_node, attributes={"decision": str})
merge_node = CMetaclass("Merge Node", superclasses=control_node)
action = CMetaclass("Action", superclasses=activity_node)
accept_event_action = CMetaclass("Accept Event Action", superclasses=action)
accept_time_event_action = CMetaclass("Accept Time Event Action", superclasses=accept_event_action,
                                      attributes={"description": str})
send_signal_action = CMetaclass("Send Signal Action", superclasses=action)

# edges
edge_relation = activity_node.association(activity_node, "next: [source] * -> [target] *")

_all = CBundle("activity_metamodel_all",
               elements=activity_node.get_connected_elements(add_stereotypes=True))

activity_metamodel_views = [
    _all, {}]
示例#9
0
    def test_reference_to_link(self):
        code = CClass(self.mcl, "Code")
        source = CClass(self.mcl, "Source")
        code_association = code.association(
            source, "[contained_code] * -> [source] *")
        code_a = CClass(self.mcl, "Code A", superclasses=code)
        code_b = CClass(self.mcl, "Code B", superclasses=code)
        a_b_association = code_a.association(code_b,
                                             "a_b: [code_a] * -> [code_b] *",
                                             superclasses=code)

        source_1 = CObject(source, "source_1")

        code_a1 = CObject(code_a, "code_a1")
        code_b1 = CObject(code_b, "code_b1")
        code_b2 = CObject(code_b, "code_b2")
        code_b3 = CObject(code_b, "code_b3")
        a_b_links = add_links({code_a1: [code_b1, code_b2]},
                              association=a_b_association)

        code_links = add_links(
            {
                source_1:
                [code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1]]
            },
            role_name="contained_code")
        eq_(len(code_links), 5)

        # test getter methods on object
        eq_(set(source_1.get_linked(role_name="contained_code")),
            {code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1]})
        eq_(set(source_1.linked),
            {code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1]})
        eq_(set(source_1.links), set(code_links))
        eq_(set(source_1.get_links_for_association(code_association)),
            set(code_links))
        eq_(set(get_links([source_1])), set(code_links))

        # test getter methods on link
        eq_(a_b_links[0].get_linked(role_name="source"), [source_1])
        eq_(a_b_links[0].linked, [source_1])
        eq_(a_b_links[0].links, [code_links[3]])
        eq_(a_b_links[0].get_links_for_association(code_association),
            [code_links[3]])
        eq_(set(get_links([a_b_links[0]])), {code_links[3]})
        eq_(
            set(get_links([code_a1, a_b_links[0], a_b_links[1]])), {
                code_links[0], a_b_links[0], a_b_links[1], code_links[3],
                code_links[4]
            })

        # test add/delete links
        code_b3_link = code_a1.add_links(code_b3)[0]
        source_1.add_links(code_b3_link)
        eq_(set(code_a1.linked), {code_b1, code_b2, source_1, code_b3})
        eq_(set(source_1.linked), {
            code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1], code_b3_link
        })
        eq_(code_b3_link.linked, [source_1])
        a_b_links[1].delete_links([source_1])
        eq_(set(source_1.linked),
            {code_a1, code_b2, code_b1, a_b_links[0], code_b3_link})
        source_1.delete_links([code_a1, a_b_links[0]])
        eq_(set(source_1.linked), {code_b2, code_b1, code_b3_link})

        # test whether metaclass links fail on class
        mcl_a = CMetaclass("M")
        mcl_b = CMetaclass("Source")
        mcl_association = mcl_a.association(mcl_b, "[a] * -> [b] *")

        cl_a = CClass(mcl_a, "cla")
        cl_b = CClass(mcl_a, "clb")
        class_link = add_links({cl_a: [cl_b]}, association=mcl_association)[0]

        try:
            add_links({source_1: [code_a1, code_b2, code_b1, class_link]},
                      role_name="contained_code")
            exception_expected_()
        except CException as e:
            eq_("link target is a class link, but source is an object",
                e.value)
示例#10
0
class TestStereotypesOnAssociations:
    def setup(self):
        self.m1 = CMetaclass("M1")
        self.m2 = CMetaclass("M2")
        self.a = self.m1.association(self.m2,
                                     name="A",
                                     multiplicity="1",
                                     role_name="m1",
                                     source_multiplicity="*",
                                     source_role_name="m2")

    def test_creation_of_one_stereotype(self):
        s = CStereotype("S", extended=self.a)
        eq_(s.name, "S")
        eq_(self.a.stereotypes, [s])
        eq_(s.extended, [self.a])

    def test_wrongs_types_in_list_of_extended_element_types(self):
        try:
            CStereotype("S", extended=[self.a, self.m1])
            exception_expected_()
        except CException as e:
            eq_("'M1' is not a association", e.value)
        try:
            CStereotype("S", extended=[self.a, CBundle("P")])
            exception_expected_()
        except CException as e:
            eq_("'P' is not a association", e.value)
        try:
            CStereotype("S", extended=[CBundle("P"), self.a])
            exception_expected_()
        except CException as e:
            eq_("unknown type of extend element: 'P'", e.value)

    def test_attempt_to_define_stereotypes_on_class_association(self):
        a_class = CClass(self.m1, "AClass")
        b_class = CClass(self.m1, "BClass")
        s = CStereotype("S")
        try:
            a_class.association(b_class, "1 -> 1", stereotypes=s)
            exception_expected_()
        except CException as e:
            eq_(
                "stereotypes on associations can only be defined for metaclass associations",
                e.value)

        association = a_class.association(b_class, "1 -> 1")
        try:
            association.stereotypes = s
            exception_expected_()
        except CException as e:
            eq_(
                "stereotypes on associations can only be defined for metaclass associations",
                e.value)

    def test_creation_of_3_stereotypes(self):
        s1 = CStereotype("S1")
        s2 = CStereotype("S2")
        s3 = CStereotype("S3")
        self.a.stereotypes = [s1, s2, s3]
        eq_(s1.extended, [self.a])
        eq_(s2.extended, [self.a])
        eq_(s3.extended, [self.a])
        eq_(set(self.a.stereotypes), {s1, s2, s3})

    def test_creation_of_unnamed_stereotype(self):
        s = CStereotype()
        eq_(s.name, None)
        eq_(self.a.stereotypes, [])
        eq_(s.extended, [])

    def test_delete_stereotype(self):
        s1 = CStereotype("S1")
        s1.delete()
        eq_(s1.name, None)
        eq_(self.a.stereotypes, [])
        s1 = CStereotype("S1", extended=self.a)
        s1.delete()
        eq_(s1.name, None)
        eq_(self.a.stereotypes, [])

        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", extended=self.a)
        s3 = CStereotype("s1",
                         superclasses=s2,
                         attributes={"i": 1},
                         extended=self.a)

        s1.delete()
        eq_(set(self.a.stereotypes), {s2, s3})
        s3.delete()
        eq_(set(self.a.stereotypes), {s2})

        eq_(s3.superclasses, [])
        eq_(s2.subclasses, [])
        eq_(s3.attributes, [])
        eq_(s3.attribute_names, [])
        eq_(s3.extended, [])
        eq_(s3.name, None)
        eq_(s3.bundles, [])

    def test_stereotype_extension_add_remove(self):
        s1 = CStereotype("S1")
        eq_(set(s1.extended), set())
        a1 = self.m1.association(self.m2,
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2",
                                 stereotypes=[s1])
        eq_(set(s1.extended), {a1})
        eq_(set(a1.stereotypes), {s1})
        a2 = self.m1.association(self.m2,
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2",
                                 stereotypes=s1)
        eq_(set(s1.extended), {a1, a2})
        eq_(set(a1.stereotypes), {s1})
        eq_(set(a2.stereotypes), {s1})
        s1.extended = [a2]
        eq_(set(s1.extended), {a2})
        eq_(set(a1.stereotypes), set())
        eq_(set(a2.stereotypes), {s1})
        s2 = CStereotype("S2", extended=[a2])
        eq_(set(a2.stereotypes), {s2, s1})
        eq_(set(s1.extended), {a2})
        eq_(set(s2.extended), {a2})
        a2.stereotypes = []
        eq_(set(a2.stereotypes), set())
        eq_(set(s1.extended), set())
        eq_(set(s2.extended), set())

    def test_stereotype_remove_stereotype_or_association(self):
        a1 = self.m1.association(self.m2,
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2")
        s1 = CStereotype("S1", extended=[a1])
        s2 = CStereotype("S2", extended=[a1])
        s3 = CStereotype("S3", extended=[a1])
        s4 = CStereotype("S4", extended=[a1])
        eq_(set(a1.stereotypes), {s1, s2, s3, s4})
        s2.delete()
        eq_(set(a1.stereotypes), {s1, s3, s4})
        eq_(set(s2.extended), set())
        eq_(set(s1.extended), {a1})
        a1.delete()
        eq_(set(a1.stereotypes), set())
        eq_(set(s1.extended), set())

    def test_stereotypes_wrong_type(self):
        a1 = self.m1.association(self.m2,
                                 name="a1",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2")
        try:
            a1.stereotypes = [a1]
            exception_expected_()
        except CException as e:
            eq_("'a1' is not a stereotype", e.value)

    def test_association_stereotypes_null_input(self):
        s = CStereotype()
        a1 = self.m1.association(self.m2,
                                 name="a1",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2",
                                 stereotypes=None)
        eq_(a1.stereotypes, [])
        eq_(s.extended, [])

    def test_association_stereotypes_non_list_input(self):
        s = CStereotype()
        a1 = self.m1.association(self.m2,
                                 name="a1",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2",
                                 stereotypes=s)
        eq_(a1.stereotypes, [s])
        eq_(s.extended, [a1])

    def test_association_stereotypes_non_list_input_wrong_type(self):
        try:
            a1 = self.m1.association(self.m2,
                                     name="a1",
                                     multiplicity="1",
                                     role_name="m1",
                                     source_multiplicity="*",
                                     source_role_name="m2")
            a1.stereotypes = a1
            exception_expected_()
        except CException as e:
            eq_("a list or a stereotype is required as input", e.value)

    def test_metaclass_stereotypes_append(self):
        s1 = CStereotype()
        s2 = CStereotype()
        a1 = self.m1.association(self.m2,
                                 name="a1",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2",
                                 stereotypes=s1)
        # should have no effect, as setter must be used
        a1.stereotypes.append(s2)
        eq_(a1.stereotypes, [s1])
        eq_(s1.extended, [a1])
        eq_(s2.extended, [])

    def test_stereotype_extended_null_input(self):
        a1 = self.m1.association(self.m2,
                                 name="a1",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2")
        s = CStereotype(extended=None)
        eq_(a1.stereotypes, [])
        eq_(s.extended, [])

    def test_stereotype_extended_non_list_input(self):
        a1 = self.m1.association(self.m2,
                                 name="a1",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2")
        s = CStereotype(extended=a1)
        eq_(a1.stereotypes, [s])
        eq_(s.extended, [a1])

    def test_stereotype_extended_append(self):
        a1 = self.m1.association(self.m2,
                                 name="a1",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2")
        a2 = self.m1.association(self.m2,
                                 name="a2",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2")
        s = CStereotype(extended=[a1])
        # should have no effect, as setter must be used
        s.extended.append(a2)
        eq_(a1.stereotypes, [s])
        eq_(a2.stereotypes, [])
        eq_(s.extended, [a1])

    def test_extended_association_that_is_deleted(self):
        a1 = self.m1.association(self.m2,
                                 name="a1",
                                 multiplicity="1",
                                 role_name="m1",
                                 source_multiplicity="*",
                                 source_role_name="m2")
        a1.delete()
        try:
            CStereotype(extended=[a1])
            exception_expected_()
        except CException as e:
            eq_(e.value, "cannot access named element that has been deleted")
示例#11
0
class TestStereotypeDefaultValues:
    def setup(self):
        self.mcl = CMetaclass("MCL")
        self.stereotype = CStereotype("S", extended=self.mcl)
        self.m1 = CMetaclass("M1")
        self.m2 = CMetaclass("M2")
        self.a = self.m1.association(self.m2,
                                     name="a",
                                     multiplicity="*",
                                     role_name="m1",
                                     source_multiplicity="1",
                                     source_role_name="m2")

    def test_default_values_on_stereotype(self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "aStr1": str,
                             "aList1": list,
                             "aStr2": "def",
                             "aList2": ["d1", "d2"],
                             "b": bool
                         })
        s1 = CStereotype("S1",
                         extended=mcl,
                         default_values={
                             "aStr1": "a",
                             "aList1": ["a"],
                             "aStr2": "def2",
                             "aList2": []
                         })
        eq_(s1.default_values, {
            "aStr1": "a",
            "aList1": ["a"],
            "aStr2": "def2",
            "aList2": []
        })
        eq_(s1.get_default_value("aStr1"), "a")
        s1.set_default_value("aStr1", "b")
        eq_(s1.get_default_value("aStr1"), "b")

        s1.default_values = {}
        # default_values should not delete existing values
        eq_(s1.default_values, {
            'aStr1': 'b',
            'aList1': ['a'],
            'aStr2': 'def2',
            'aList2': []
        })

        s1.default_values = {"b": True}
        eq_(
            s1.default_values, {
                'aStr1': 'b',
                'aList1': ['a'],
                'aStr2': 'def2',
                'aList2': [],
                'b': True
            })
        eq_(s1.get_default_value("b"), True)

    def test_default_values_on_stereotype__initialized_in_class_constructor(
            self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "aStr1": str,
                             "aList1": list,
                             "aStr2": "def",
                             "aList2": ["d1", "d2"],
                             "b": True
                         })
        s = CStereotype("S",
                        extended=mcl,
                        default_values={
                            "aStr1": "a",
                            "aList1": ["a"],
                            "aStr2": "def2",
                            "aList2": []
                        })
        c1 = CClass(mcl, "C1", stereotype_instances=s)
        # metaclass defaults are initialized at the end of construction, stereotype_instances runs before
        # and thus overwrites metaclass defaults
        eq_(
            c1.values, {
                "aStr1": "a",
                "aList1": ["a"],
                "aStr2": "def2",
                "aList2": [],
                "b": True
            })

    def test_default_values_on_stereotype__initialize_after_class_constructor(
            self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "aStr1": str,
                             "aList1": list,
                             "aStr2": "def",
                             "aList2": ["d1", "d2"],
                             "b": True
                         })
        s = CStereotype("S",
                        extended=mcl,
                        default_values={
                            "aStr1": "a",
                            "aList1": ["a"],
                            "aStr2": "def2",
                            "aList2": []
                        })
        c1 = CClass(mcl, "C1")
        c1.stereotype_instances = s
        # after construction, metaclass defaults are set. The stereotype defaults are set only for
        # values not yet set
        eq_(
            c1.values, {
                'aStr2': 'def',
                'aList2': ['d1', 'd2'],
                'b': True,
                'aStr1': 'a',
                'aList1': ['a']
            })

    def test_default_values_on_stereotype_exceptions(self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "aStr1": str,
                             "aList1": list,
                             "aStr2": "def",
                             "aList2": ["d1", "d2"],
                             "b": bool
                         })
        s1 = CStereotype("S1",
                         extended=mcl,
                         default_values={
                             "aStr1": "a",
                             "aList1": ["a"],
                             "aStr2": "def2",
                             "aList2": []
                         })
        try:
            s1.default_values = {"x": bool}
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "attribute 'x' unknown for metaclasses extended by stereotype 'S1'"
            )

        try:
            s1.default_values = {"b": bool}
            exception_expected_()
        except CException as e:
            eq_(e.value,
                "value for attribute 'b' is not a known attribute type")

        try:
            s1.default_values = {"b": []}
            exception_expected_()
        except CException as e:
            eq_(e.value,
                "value type for attribute 'b' does not match attribute type")

        try:
            s1.default_values = []
            exception_expected_()
        except CException as e:
            eq_(e.value, "malformed default values description: '[]'")

    def test_default_values_on_stereotype_inheritance1(self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "aStr2": "def",
                             "aList2": ["d1", "d2"],
                             "b": bool
                         })
        mcl2 = CMetaclass("MCL2",
                          superclasses=mcl,
                          attributes={
                              "aStr1": str,
                              "aList1": list
                          })
        s1 = CStereotype("S1",
                         extended=mcl2,
                         default_values={
                             "aStr1": "a",
                             "aList2": []
                         })
        s2 = CStereotype("S2",
                         superclasses=s1,
                         extended=mcl2,
                         default_values={
                             "aList1": ["a"],
                             "aStr2": "def2"
                         })

        eq_(s1.default_values, {"aStr1": "a", "aList2": []})
        eq_(s2.default_values, {"aList1": ["a"], "aStr2": "def2"})
        eq_(s1.get_default_value("aStr1"), "a")
        eq_(s2.get_default_value("aStr2"), "def2")
        eq_(s2.get_default_value("aStr1"), None)
        eq_(s1.get_default_value("aStr2"), None)

    def test_default_values_on_stereotype_inheritance2(self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "aStr2": "def",
                             "aList2": ["d1", "d2"],
                             "b": bool
                         })
        mcl2 = CMetaclass("MCL2",
                          superclasses=mcl,
                          attributes={
                              "aStr1": str,
                              "aList1": list
                          })
        try:
            CStereotype("S1",
                        extended=mcl,
                        default_values={
                            "aStr1": "a",
                            "aList2": []
                        })
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "attribute 'aStr1' unknown for metaclasses extended by stereotype 'S1'"
            )

        s2 = CStereotype("S2",
                         extended=mcl2,
                         default_values={
                             "aList1": ["a"],
                             "aStr2": "def2"
                         })
        eq_(s2.default_values, {"aList1": ["a"], "aStr2": "def2"})

    def test_default_values_on_stereotype__metaclass_delete(self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "aStr2": "def",
                             "aList2": ["d1", "d2"],
                             "b": bool
                         })
        mcl2 = CMetaclass("MCL2",
                          superclasses=mcl,
                          attributes={
                              "aStr1": str,
                              "aList1": list
                          })
        s1 = CStereotype("S1",
                         extended=mcl2,
                         default_values={
                             "aStr1": "a",
                             "aList2": []
                         })
        s2 = CStereotype("S2",
                         superclasses=s1,
                         extended=mcl2,
                         default_values={
                             "aList1": ["a"],
                             "aStr2": "def2"
                         })
        mcl.delete()

        eq_(s1.default_values, {"aStr1": "a"})
        eq_(s2.default_values, {"aList1": ["a"]})
        eq_(s1.get_default_value("aStr1"), "a")
        try:
            eq_(s2.get_default_value("aStr2"), "def2")
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "attribute 'aStr2' unknown for metaclasses extended by stereotype 'S2'"
            )
        eq_(s2.get_default_value("aStr1"), None)

    def test_delete_default_values(self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "isBoolean": True,
                             "intVal": int,
                             "floatVal": 1.1,
                             "string": "def",
                             "list": list
                         })
        s = CStereotype("S",
                        extended=mcl,
                        default_values={
                            "isBoolean": False,
                            "intVal": 1,
                            "string": "abc",
                            "list": ["a", "b"]
                        })
        c1 = CClass(mcl, "C1", stereotype_instances=s)
        s.delete_default_value("isBoolean")
        s.delete_default_value("intVal")
        list_value = s.delete_default_value("list")
        eq_(s.default_values, {"string": "abc"})
        eq_(list_value, ['a', 'b'])
        c2 = CClass(mcl, "C2", stereotype_instances=s)
        eq_(
            c1.values, {
                'isBoolean': False,
                'floatVal': 1.1,
                'string': 'abc',
                'intVal': 1,
                'list': ['a', 'b']
            })
        eq_(c2.values, {'isBoolean': True, 'floatVal': 1.1, 'string': 'abc'})

    def test_delete_default_values_with_superclass(self):
        mcl_super = CMetaclass("MCLSuper",
                               attributes={
                                   "isBoolean": False,
                                   "intVal": int,
                                   "intVal2": int
                               })
        mcl = CMetaclass("MCL",
                         superclasses=mcl_super,
                         attributes={
                             "isBoolean": False,
                             "intVal": int,
                             "intVal2": int
                         })
        sst = CStereotype("SST",
                          extended=mcl,
                          default_values={
                              "intVal": 20,
                              "intVal2": 30
                          })
        st = CStereotype("ST",
                         superclasses=sst,
                         default_values={
                             "isBoolean": True,
                             "intVal": 1
                         })
        c1 = CClass(mcl, "C1", stereotype_instances=st)
        eq_(c1.values, {'isBoolean': True, 'intVal': 1, 'intVal2': 30})
        st.delete_default_value("isBoolean")
        sst.delete_default_value("intVal2")
        st.delete_default_value("intVal")
        eq_(st.default_values, {})
        eq_(sst.default_values, {"intVal": 20})
        c2 = CClass(mcl, "C2", stereotype_instances=st)
        eq_(c1.values, {'isBoolean': True, 'intVal': 1, 'intVal2': 30})
        eq_(c2.values, {'isBoolean': False, 'intVal': 20})

        sst.set_default_value("intVal", 2, mcl_super)
        sst.set_default_value("intVal", 3, mcl)
        eq_(sst.default_values, {"intVal": 3})
        sst.delete_default_value("intVal")
        eq_(sst.default_values, {"intVal": 2})

        sst.set_default_value("intVal", 2, mcl_super)
        sst.set_default_value("intVal", 3, mcl)
        sst.delete_default_value("intVal", mcl)
        eq_(sst.default_values, {"intVal": 2})

        sst.set_default_value("intVal", 2, mcl_super)
        sst.set_default_value("intVal", 3, mcl)
        sst.delete_default_value("intVal", mcl_super)
        eq_(sst.default_values, {"intVal": 3})

    def test_default_values_exceptional_cases(self):
        mcl = CMetaclass("MCL",
                         attributes={
                             "isBoolean": True,
                             "intVal": int,
                             "floatVal": 1.1,
                             "string": "def",
                             "list": list
                         })
        s1 = CStereotype("S",
                         extended=mcl,
                         default_values={
                             "isBoolean": False,
                             "intVal": 1,
                             "string": "abc",
                             "list": ["a", "b"]
                         })
        s1.delete()

        try:
            s1.get_default_value("b")
            exception_expected_()
        except CException as e:
            eq_(e.value, "can't get default value 'b' on deleted stereotype")

        try:
            s1.set_default_value("b", 1)
            exception_expected_()
        except CException as e:
            eq_(e.value, "can't set default value 'b' on deleted stereotype")

        try:
            s1.delete_default_value("b")
            exception_expected_()
        except CException as e:
            eq_(e.value,
                "can't delete default value 'b' on deleted stereotype")

        try:
            s1.default_values = {"b": 1}
            exception_expected_()
        except CException as e:
            eq_(e.value, "can't set default values on deleted stereotype")

        try:
            # we just use list here, in order to not get a warning that s1.default_values has no effect
            list(s1.default_values)
            exception_expected_()
        except CException as e:
            eq_(e.value, "can't get default values on deleted stereotype")

        s = CStereotype("S",
                        extended=mcl,
                        default_values={
                            "isBoolean": False,
                            "intVal": 1,
                            "string": "abc",
                            "list": ["a", "b"]
                        })
        try:
            s.delete_default_value("x")
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "attribute 'x' unknown for metaclasses extended by stereotype 'S'"
            )

    def test_default_values_from_stereotype_on_association_fails(self):
        try:
            CStereotype("S1",
                        extended=self.a,
                        default_values={
                            "aStr1": "a",
                            "aList1": ["a"],
                            "aStr2": "def2",
                            "aList2": []
                        })
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "default values can only be used on a stereotype that extends metaclasses"
            )

    def test_set_default_value_from_stereotype_on_association_fails(self):
        try:
            s1 = CStereotype("S1", extended=self.a)
            s1.set_default_value("a", "1")
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "default values can only be used on a stereotype that extends metaclasses"
            )

    def test_get_default_value_from_stereotype_on_association_fails(self):
        try:
            s1 = CStereotype("S1", extended=self.a)
            s1.get_default_value("a")
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "default values can only be used on a stereotype that extends metaclasses"
            )

    def test_delete_default_value_from_stereotype_on_association_fails(self):
        try:
            s1 = CStereotype("S1", extended=self.a)
            s1.delete_default_value("a")
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "default values can only be used on a stereotype that extends metaclasses"
            )

    def test_default_values_from_stereotype_on_no_extension_fails(self):
        try:
            CStereotype("S1",
                        default_values={
                            "aStr1": "a",
                            "aList1": ["a"],
                            "aStr2": "def2",
                            "aList2": []
                        })
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "default values can only be used on a stereotype that extends metaclasses"
            )

    def test_set_default_value_from_stereotype_on_no_extension_fails(self):
        try:
            s1 = CStereotype("S1")
            s1.set_default_value("a", "1")
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "default values can only be used on a stereotype that extends metaclasses"
            )

    def test_get_default_value_from_stereotype_on_no_extension_fails(self):
        try:
            s1 = CStereotype("S1")
            s1.get_default_value("a")
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "default values can only be used on a stereotype that extends metaclasses"
            )

    def test_delete_default_value_from_stereotype_on_no_extension_fails(self):
        try:
            s1 = CStereotype("S1")
            s1.delete_default_value("a")
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "default values can only be used on a stereotype that extends metaclasses"
            )
示例#12
0
model_element = CMetaclass("Model Element", attributes={"aka": str, "description": str})
category = CMetaclass("Category", superclasses=model_element)

design_solution = CMetaclass("Design Solution", superclasses=model_element,
                             attributes={"background reading": str})

design_solution_domain_metaclass = CMetaclass("Design Solution / Domain Class",
                                              superclasses=[design_solution, domain_metaclass])

practice = CMetaclass("Practice", superclasses=design_solution)
pattern = CMetaclass("Pattern", superclasses=practice)

known_use = CMetaclass("Known Use", superclasses=model_element,
                       attributes={"reference": str})
solutions_known_uses_relation = design_solution.association(known_use, "used in: [solutions] * -> [knownUses] *")

decision = CMetaclass("Decision", superclasses=design_solution, attributes={"recommendation": str})
category_decisions_relation = category.association(decision, "[category] 1 <>- [decisions] *")

decision_type = CStereotype("Decision Type", extended=decision)
single_answer = CStereotype("Single Answers", superclasses=decision_type)
multiple_answers = CStereotype("Multiple Answers", superclasses=decision_type)

force = CMetaclass("Force", superclasses=model_element)
force_impact_relation = design_solution.association(force, "has force: [solutions] * -> [forces] *")

force_impact_type = CStereotype("Force Impact Type", extended=force_impact_relation)
very_positive = CStereotype("++", superclasses=force_impact_type)
positive = CStereotype("+", superclasses=force_impact_type)
neutral = CStereotype("o", superclasses=force_impact_type)
class TestLinkObjectsForMetaclasses:
    def setup(self):
        self.mcl = CMetaclass("MCL")

    def test_reference_to_link(self):
        code = CMetaclass("Code")

        source = CMetaclass("Source")
        code_association = code.association(source, "[contained_code] * -> [source] *")

        code_a = CMetaclass("Code A", superclasses=code)
        code_b = CMetaclass("Code B", superclasses=code)
        a_b_association = code_a.association(code_b, "a_b: [code_a] * -> [code_b] *", superclasses=code)

        source_1 = CClass(source, "source_1")

        code_a1 = CClass(code_a, "code_a1")
        code_b1 = CClass(code_b, "code_b1")
        code_b2 = CClass(code_b, "code_b2")
        code_b3 = CClass(code_b, "code_b3")
        a_b_links = add_links({code_a1: [code_b1, code_b2]}, association=a_b_association)

        code_links = add_links({source_1: [code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1]]},
                               role_name="contained_code")
        eq_(len(code_links), 5)

        # test getter methods on class
        eq_(set(source_1.get_linked(role_name="contained_code")),
            {code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1]})
        eq_(set(source_1.linked), {code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1]})
        eq_(set(source_1.links), set(code_links))
        eq_(set(source_1.get_links_for_association(code_association)), set(code_links))
        eq_(set(get_links([source_1])), set(code_links))

        # test getter methods on link
        eq_(a_b_links[0].get_linked(role_name="source"), [source_1])
        eq_(a_b_links[0].linked, [source_1])
        eq_(a_b_links[0].links, [code_links[3]])
        eq_(a_b_links[0].get_links_for_association(code_association), [code_links[3]])
        eq_(set(get_links([a_b_links[0]])), {code_links[3]})
        eq_(set(get_links([code_a1, a_b_links[0], a_b_links[1]])),
            {code_links[0], a_b_links[0], a_b_links[1], code_links[3], code_links[4]})

        # test add/delete links
        code_b3_link = code_a1.add_links(code_b3)[0]
        source_1.add_links(code_b3_link)
        eq_(set(code_a1.linked), {code_b1, code_b2, source_1, code_b3})
        eq_(set(source_1.linked), {code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1], code_b3_link})
        eq_(code_b3_link.linked, [source_1])
        a_b_links[1].delete_links([source_1])
        eq_(set(source_1.linked), {code_a1, code_b2, code_b1, a_b_links[0], code_b3_link})
        source_1.delete_links([code_a1, a_b_links[0]])
        eq_(set(source_1.linked), {code_b2, code_b1, code_b3_link})

        # test whether class links fail on metaclass
        cl_a = CClass(self.mcl, "CLA")
        cl_b = CClass(self.mcl, "CLB")
        cl_association = cl_a.association(cl_b, "[a] * -> [b] *")

        o_a = CObject(cl_a, "oa")
        o_b = CObject(cl_a, "ob")
        object_link = add_links({o_a: [o_b]}, association=cl_association)[0]

        try:
            add_links({source_1: [code_a1, code_b2, code_b1, object_link]}, role_name="contained_code")
            exception_expected_()
        except CException as e:
            eq_("link target is an object link, but source is a class", e.value)

    def test_link_association_has_a_compatible_superclass(self):
        code = CMetaclass("Code")

        source = CMetaclass("Source")
        code.association(source, "[contained_code] * -> [source] *")

        code_a = CMetaclass("Code A", superclasses=code)
        code_b = CMetaclass("Code B", superclasses=code)
        a_b_association = code_a.association(code_b, "a_b: [code_a] * -> [code_b] *")

        source_1 = CClass(source, "source_1")

        code_a1 = CClass(code_a, "code_a1")
        code_b1 = CClass(code_b, "code_b1")
        code_b2 = CClass(code_b, "code_b2")
        links = add_links({code_a1: [code_b1, code_b2]}, association=a_b_association)

        try:
            add_links({source_1: [code_a1, code_b2, code_b1, links[0], links[1]]},
                      role_name="contained_code")
            exception_expected_()
        except CException as e:
            eq_("the metaclass link's association is missing a compatible classifier", e.value)

        a_b_association.superclasses = self.mcl
        try:
            add_links({source_1: [code_a1, code_b2, code_b1, links[0], links[1]]},
                      role_name="contained_code")
            exception_expected_()
        except CException as e:
            eq_("no common metaclass for classes or links found", e.value)

        a_b_association.superclasses = code_b
        add_links({source_1: [code_a1, code_b2, code_b1, links[0], links[1]]},
                  role_name="contained_code")

    def test_association_to_association_not_possible(self):
        clx = CMetaclass("X")
        cla = CMetaclass("A")
        clb = CMetaclass("B")
        a_b_association = cla.association(clb, "a_b: [a] * -> [b] *")
        try:
            clx.association(a_b_association, "[x] * -> [a_b_association] *")
            exception_expected_()
        except CException as e:
            eq_("metaclass 'X' is not compatible with association target 'a_b'", e.value)

    def test_link_to_link(self):
        collection1 = CMetaclass("Collection1")
        collection2 = CMetaclass("Collection2")
        collections_association = collection1.association(collection2,
                                                          "element references: [references] * -> [referenced] *")
        type_a = CMetaclass("Type A", superclasses=collection1)
        type_b = CMetaclass("Type B", superclasses=collection1)
        a_b_association = type_a.association(type_b, "a_b: [type_a] * -> [type_b] *", superclasses=collection1)
        type_c = CMetaclass("Type C", superclasses=collection2)
        type_d = CMetaclass("Type D", superclasses=[collection1, collection2])
        c_d_association = type_c.association(type_d, "c_d: [type_c] * -> [type_d] *", superclasses=collection2)
        a_d_association = type_a.association(type_d, "a_d: [type_a] * -> [type_d] *",
                                             superclasses=[collection1, collection2])

        a1 = CClass(type_a, "a1")
        b1 = CClass(type_b, "b1")
        b2 = CClass(type_b, "b2")
        c1 = CClass(type_c, "c1")
        c2 = CClass(type_c, "c2")
        d1 = CClass(type_d, "d1")

        a_b_links = add_links({a1: [b1, b2]}, association=a_b_association)
        c_d_links = add_links({d1: [c1, c2]}, association=c_d_association)
        a_d_links = add_links({a1: [d1]}, association=a_d_association)

        references_links = add_links({a_b_links[0]: c_d_links[0],
                                      a_b_links[1]: [c1, c2, d1, c_d_links[1], c_d_links[0]],
                                      a_d_links[0]: [a_d_links[0], c_d_links[1], c1, d1]}, role_name="referenced")

        eq_(set(a_b_links[0].get_linked(role_name="referenced")),
            {c_d_links[0]})
        eq_(set(a_b_links[0].linked), {c_d_links[0]})
        eq_(set(a_b_links[0].links), {references_links[0]})
        eq_(set(a_b_links[0].get_links_for_association(collections_association)), {references_links[0]})
        eq_(set(get_links([a_b_links[0]])), {references_links[0]})

        eq_(set(a_b_links[1].get_linked(role_name="referenced")),
            {c1, c2, d1, c_d_links[1], c_d_links[0]})
        eq_(set(a_b_links[1].linked), {c1, c2, d1, c_d_links[1], c_d_links[0]})
        correct_links_set = {references_links[1], references_links[2], references_links[3], references_links[4],
                             references_links[5]}
        eq_(set(a_b_links[1].links), correct_links_set)
        eq_(set(a_b_links[1].get_links_for_association(collections_association)), correct_links_set)
        eq_(set(get_links([a_b_links[1]])), correct_links_set)

        eq_(set(a_d_links[0].get_linked(role_name="referenced")),
            {a_d_links[0], c_d_links[1], c1, d1})
        eq_(set(a_d_links[0].linked), {a_d_links[0], c_d_links[1], c1, d1})
        correct_links_set = {references_links[6], references_links[7], references_links[8], references_links[9]}
        eq_(set(a_d_links[0].links), correct_links_set)
        eq_(set(a_d_links[0].get_links_for_association(collections_association)), correct_links_set)
        eq_(set(get_links([a_d_links[0]])), correct_links_set)

    def test_links_as_attribute_values(self):
        code = CMetaclass("Code")
        source = CMetaclass("Source")
        code.association(source, "[contained_code] * -> [source] *")
        code_a = CMetaclass("Code A", superclasses=code)
        code_b = CMetaclass("Code B", superclasses=code)
        a_b_association = code_a.association(code_b, "a_b: [code_a] * -> [code_b] *", superclasses=code)
        CClass(source, "source_1")
        code_a1 = CClass(code_a, "code_a1")
        code_b1 = CClass(code_b, "code_b1")
        code_b2 = CClass(code_b, "code_b2")
        a_b_links = add_links({code_a1: [code_b1, code_b2]}, association=a_b_association)

        links_list = [code_a1, code_b2, code_b1, a_b_links[0], a_b_links[1]]

        collection_type = CMetaclass("Collection Type", attributes={
            "primary_code": code,
            "default_value_code": a_b_links[0],
            "codes": list,
            "default_values_list": links_list
        })
        collection = CClass(collection_type)

        eq_(collection.get_value("primary_code"), None)
        eq_(collection.get_value("default_value_code"), a_b_links[0])
        eq_(collection.get_value("codes"), None)
        eq_(collection.get_value("default_values_list"), links_list)

        collection.set_value("primary_code", a_b_links[1])
        collection.set_value("default_value_code", a_b_links[1])
        collection.set_value("codes", [code_a1, a_b_links[0]])
        collection.set_value("default_values_list", [a_b_links[0], a_b_links[1]])

        eq_(collection.get_value("primary_code"), a_b_links[1])
        eq_(collection.get_value("default_value_code"), a_b_links[1])
        eq_(collection.get_value("codes"), [code_a1, a_b_links[0]])
        eq_(collection.get_value("default_values_list"), [a_b_links[0], a_b_links[1]])

        collection.values = {'default_values_list': [a_b_links[0]], "codes": []}

        eq_(collection.values, {'default_value_code': a_b_links[1],
                                'default_values_list': [a_b_links[0]],
                                'codes': [],
                                'primary_code': a_b_links[1]})

        collection.delete_value("primary_code")
        collection.delete_value("default_value_code")
        collection.delete_value("codes")
        collection.delete_value("default_values_list")

        eq_(collection.get_value("primary_code"), None)
        eq_(collection.get_value("default_value_code"), None)
        eq_(collection.get_value("codes"), None)
        eq_(collection.get_value("default_values_list"), None)

    def create_simple_link_object_test_setup(self):
        self.a = CMetaclass("A")
        self.a1 = CMetaclass("A1", superclasses=self.a)
        self.a2 = CMetaclass("A2", superclasses=self.a)
        self.a_association = self.a1.association(self.a2, "[a1] * -> [a2] *", superclasses=self.a)
        self.b = CMetaclass("B")
        self.b_a_association = self.b.association(self.a, "[b] * -> [a] *")

        self.a1_1 = CClass(self.a1, "a1_1")
        self.a1_2 = CClass(self.a1, "a1_2")
        self.a2_1 = CClass(self.a2, "a2_1")
        self.b_1 = CClass(self.b, "b_1")
        self.a_links = add_links({self.a2_1: [self.a1_1, self.a1_2]}, association=self.a_association)

        self.b_a_links = add_links({self.b_1: [self.a_links[0], self.a_links[1]]}, association=self.b_a_association)

    def test_attributes_on_association_classifier(self):
        self.create_simple_link_object_test_setup()
        eq_(self.b_a_association.attributes, [])
        eq_(self.b_a_association.attribute_names, [])
        try:
            self.b_a_association.attributes = {
                "i1": int,
                "i2": 15,
                "s1": str,
                "s2": "abc"
            }
            exception_expected_()
        except CException as e:
            eq_("setting of attributes not supported for associations", e.value)

        eq_(self.b_a_association.get_attribute("i1"), None)

    def test_superclass_sub_class_method_on_association_classifier(self):
        self.create_simple_link_object_test_setup()
        eq_(self.a_association.superclasses, [self.a])
        eq_(self.a_association.subclasses, [])
        eq_(self.b_a_association.superclasses, [])
        eq_(self.b_a_association.subclasses, [])
        eq_(self.a.subclasses, [self.a1, self.a2, self.a_association])

        try:
            another_sc = CClass(self.mcl, "ASC")
            self.a_association.superclasses = [self.a, another_sc]
            exception_expected_()
        except CException as e:
            eq_("cannot add superclass 'ASC': not a metaclass or metaclass association", e.value)

        try:
            another_sc = CStereotype("ASC")
            self.a_association.superclasses = [self.a, another_sc]
            exception_expected_()
        except CException as e:
            eq_("cannot add superclass 'ASC': not a metaclass or metaclass association", e.value)

        another_sc = CMetaclass("ASC")
        self.a_association.superclasses = [self.a, another_sc]
        eq_(self.a_association.superclasses, [self.a, another_sc])
        eq_(set(self.a_association.all_superclasses), {self.a, another_sc})

        a2_association = self.a1.association(self.a2, "[a1] * -> [a2] *", superclasses=self.a)
        self.a_association.superclasses = [a2_association]
        eq_(self.a_association.superclasses, [a2_association])
        eq_(self.a_association.all_subclasses, set())
        eq_(self.a_association.all_superclasses, {a2_association, self.a})
        eq_(a2_association.superclasses, [self.a])
        eq_(a2_association.subclasses, [self.a_association])
        eq_(a2_association.all_subclasses, {self.a_association})

        eq_(a2_association.has_subclass(self.a_association), True)
        eq_(a2_association.has_subclass(self.a1), False)
        eq_(a2_association.has_superclass(self.a_association), False)
        eq_(a2_association.has_superclass(self.a), True)

        eq_(self.a_association.is_classifier_of_type(self.a_association), True)
        eq_(self.a_association.is_classifier_of_type(a2_association), True)
        eq_(self.a_association.is_classifier_of_type(self.a), True)
        eq_(self.a_association.is_classifier_of_type(self.a1), False)

        # test linking still works after superclass changes
        self.b_1.delete_links([self.a_links[0], self.a_links[1]])
        eq_(self.b_1.get_linked(), [])
        self.b_a_links = set_links({self.b_1: [self.a_links[1], self.a_links[0]]}, association=self.b_a_association)
        eq_(self.b_1.get_linked(), [self.a_links[1], self.a_links[0]])

    def test_delete_linked_association(self):
        self.create_simple_link_object_test_setup()
        self.a_association.delete()
        eq_(self.a.subclasses, [self.a1, self.a2])
        eq_(self.a2_1.get_linked(), [])
        eq_(self.b_1.get_linked(), [])

    def test_delete_linking_association(self):
        self.create_simple_link_object_test_setup()
        self.b_a_association.delete()
        eq_(self.a2_1.get_linked(), [self.a1_1, self.a1_2])
        eq_(self.b_1.get_linked(), [])

    def test_link_object_classifier(self):
        self.create_simple_link_object_test_setup()
        eq_(self.a_links[0].classifier, self.a_association)
        eq_(self.b_a_links[0].classifier, self.b_a_association)

        try:
            self.a_links[0].classifier = self.b_a_association
            exception_expected_()
        except CException as e:
            eq_("Changes to the classifier (i.e., the association) of a link" +
                " should not be performed with CObject methods", e.value)

    def test_link_object_class_object_class(self):
        self.create_simple_link_object_test_setup()
        eq_(self.a_links[0].class_object_class, None)
        eq_(self.b_a_links[0].class_object_class, None)

    def test_link_object_instance_of(self):
        self.create_simple_link_object_test_setup()
        eq_(self.a_links[0].instance_of(self.a_association), True)
        eq_(self.a_links[0].instance_of(self.b_a_association), False)
        eq_(self.a_links[0].instance_of(self.a), True)
        eq_(self.a_links[0].instance_of(self.a1), False)
        try:
            cl = CClass(self.mcl, "CL")
            eq_(self.a_links[0].instance_of(cl), False)
            exception_expected_()
        except CException as e:
            eq_("'CL' is not an association or a metaclass", e.value)

        eq_(self.b_a_links[0].instance_of(self.a_association), False)
        eq_(self.b_a_links[0].instance_of(self.b_a_association), True)
        eq_(self.b_a_links[0].instance_of(self.a), False)

    def test_link_object_delete(self):
        self.create_simple_link_object_test_setup()
        self.a_links[0].delete()
        self.b_a_links[0].delete()
        eq_(self.b_1.get_linked(), [self.a_links[1]])
        eq_(self.a2_1.get_linked(), [self.a1_2])
        eq_(self.a_links[1].get_linked(), [self.b_1])

        try:
            self.a_links[0].get_value("a")
            exception_expected_()
        except CException as e:
            eq_("can't get value 'a' on deleted link", e.value)

        try:
            self.a_links[0].delete_value("a")
            exception_expected_()
        except CException as e:
            eq_("can't delete value 'a' on deleted link", e.value)

        try:
            self.a_links[0].set_value("a", 1)
            exception_expected_()
        except CException as e:
            eq_("can't set value 'a' on deleted link", e.value)

        try:
            self.a_links[0].values = {"a": 1}
            exception_expected_()
        except CException as e:
            eq_("can't set values on deleted link", e.value)

    def test_class_link_classifier_bundable(self):
        self.create_simple_link_object_test_setup()

        bundle = CBundle("Bundle", elements=self.a.get_connected_elements())
        eq_(set(bundle.elements), {self.a, self.a1, self.a2, self.b})

        try:
            bundle.elements = self.a.get_connected_elements(add_links=True)
            exception_expected_()
        except CException as e:
            eq_("unknown keyword argument 'add_links', should be one of:" +
                " ['add_associations', 'add_stereotypes', 'process_stereotypes', 'add_bundles', 'process_bundles'," +
                " 'stop_elements_inclusive', 'stop_elements_exclusive']", e.value)

        eq_(self.a_association.bundles, [])

        bundle.elements = self.a.get_connected_elements(add_associations=True)
        eq_(set(bundle.elements), {self.a, self.a1, self.a2, self.b, self.a_association})

        eq_(self.a_association.bundles, [bundle])

        bundle2 = CBundle("Bundle2", elements=self.a_association.get_connected_elements(add_associations=True))
        eq_(set(bundle2.elements), {self.a, self.a1, self.a2, self.b, self.a_association})
        eq_(set(self.a_association.bundles), {bundle, bundle2})

        bundle2.delete()
        eq_(set(self.a_association.bundles), {bundle})

        self.a_association.delete()
        eq_(set(bundle.elements), {self.a, self.a1, self.a2, self.b})

    def test_class_link_bundable(self):
        self.create_simple_link_object_test_setup()

        bundle = CBundle("Bundle", elements=self.a1_1.class_object.get_connected_elements())
        eq_(set(bundle.elements), {self.a1_1.class_object, self.a1_2.class_object, self.a2_1.class_object})

        try:
            bundle.elements = self.a1_1.class_object.get_connected_elements(add_associations=True)
            exception_expected_()
        except CException as e:
            eq_("unknown keyword argument 'add_associations', should be one of:" +
                " ['add_links', 'add_bundles', 'process_bundles', 'stop_elements_inclusive', " +
                "'stop_elements_exclusive']", e.value)

        bundle.elements = self.b_1.class_object.get_connected_elements()
        eq_(set(bundle.elements), {self.b_1.class_object})

        eq_(self.a_links[0].bundles, [])

        bundle.elements = self.b_1.class_object.get_connected_elements(add_links=True)
        eq_(set(bundle.elements), {self.b_1.class_object, self.a_links[0], self.a_links[1]})

        eq_(self.a_links[0].bundles, [bundle])

        bundle2 = CBundle("Bundle2", elements=self.a_links[0].get_connected_elements(add_links=True))
        eq_(set(bundle2.elements), {self.b_1.class_object, self.a_links[0], self.a_links[1]})
        eq_(set(self.a_links[0].bundles), {bundle, bundle2})

        bundle2.delete()
        eq_(set(self.a_links[0].bundles), {bundle})

        self.a_links[0].delete()
        eq_(set(bundle.elements), {self.b_1.class_object, self.a_links[1]})
示例#14
0
from codeable_models import CMetaclass, CStereotype, CBundle
from metamodels.component_metamodel import component

deployment_node = CMetaclass("Deployment Node")
deployment_node_relation = deployment_node.association(deployment_node, "connected to: [from] * -> [to] *")
deployment_relation = component.association(deployment_node,
                                            "deployed on: [components] * -> [deployment_nodes] *")

device = CMetaclass("Device", superclasses=deployment_node)
execution_environment = CMetaclass("Execution Environment", superclasses=deployment_node)

#
# device types
#
device_type = CStereotype("Device Type", extended=device)

server_device_type = CStereotype("Server", superclasses=device_type)
web_server_device_type = CStereotype("Web Server", superclasses=server_device_type)
application_server_device_type = CStereotype("Application Server", superclasses=server_device_type)
client_workstation_device_type = CStereotype("Client Workstation", superclasses=device_type)
mobile_device_type = CStereotype("Mobile Device", superclasses=device_type)
embedded_device_type = CStereotype("Embedded Device", superclasses=device_type)
iot_device_type = CStereotype("IoT Device", superclasses=device_type)
cloud_devices_type = CStereotype("Cloud", superclasses=device_type)
paas_cloud_devices_type = CStereotype("PaaS Cloud", superclasses=cloud_devices_type)
cloud_server_device_type = CStereotype("Cloud Server", superclasses=[cloud_devices_type, server_device_type])
virtual_machine_device_type = CStereotype("Virtual Machine Device", superclasses=device_type)
cloud_vm_device_type = CStereotype("Cloud VM", superclasses=[cloud_devices_type, virtual_machine_device_type])

#
# execution environment types
class TestStereotypeInstancesOnLinks:
    def setup(self):
        self.m1 = CMetaclass("M1")
        self.m2 = CMetaclass("M2")
        self.a = self.m1.association(self.m2,
                                     name="a",
                                     multiplicity="*",
                                     role_name="m2",
                                     source_multiplicity="1",
                                     source_role_name="m1")

    def test_stereotype_instances_on_association_link(self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", extended=self.a)
        s3 = CStereotype("S3", extended=self.a)

        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m2, "C3")
        links = set_links({c1: [c2, c3]})
        l1 = links[0]

        eq_(l1.stereotype_instances, [])
        eq_(s1.extended_instances, [])
        l1.stereotype_instances = [s1]
        eq_(s1.extended_instances, [l1])
        eq_(l1.stereotype_instances, [s1])
        l1.stereotype_instances = [s1, s2, s3]
        eq_(s1.extended_instances, [l1])
        eq_(s2.extended_instances, [l1])
        eq_(s3.extended_instances, [l1])
        eq_(set(l1.stereotype_instances), {s1, s2, s3})
        l1.stereotype_instances = s2
        eq_(l1.stereotype_instances, [s2])
        eq_(s1.extended_instances, [])
        eq_(s2.extended_instances, [l1])
        eq_(s3.extended_instances, [])

        eq_(c1.get_links_for_association(self.a), links)
        eq_(c2.get_links_for_association(self.a), [l1])
        eq_(c3.get_links_for_association(self.a), [links[1]])

    def test_stereotype_instances_double_assignment(self):
        s1 = CStereotype("S1", extended=self.a)

        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        links = set_links({c1: c2})[0]

        try:
            links.stereotype_instances = [s1, s1]
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "'S1' is already a stereotype instance on link from 'C1' to 'C2'"
            )
        eq_(links.stereotype_instances, [s1])

    def test_stereotype_instances_none_assignment(self):
        CStereotype("S1", extended=self.a)

        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        links = set_links({c1: [c2]})[0]

        try:
            links.stereotype_instances = [None]
            exception_expected_()
        except CException as e:
            eq_(e.value, "'None' is not a stereotype")
        eq_(links.stereotype_instances, [])

    def test_stereotype_instances_wrong_type_in_assignment(self):
        CStereotype("S1", extended=self.a)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        links = c1.add_links(c2)[0]
        try:
            links.stereotype_instances = self.a
            exception_expected_()
        except CException as e:
            eq_(e.value, "a list or a stereotype is required as input")
        eq_(links.stereotype_instances, [])

    def test_multiple_extended_instances(self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", extended=self.a)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m2, "C3")
        c4 = CClass(self.m2, "C4")
        links = set_links({c1: [c2, c3, c4]})
        links[0].stereotype_instances = [s1]
        eq_(s1.extended_instances, [links[0]])
        links[1].stereotype_instances = [s1]
        eq_(set(s1.extended_instances), {links[0], links[1]})
        links[2].stereotype_instances = [s1, s2]
        eq_(set(s1.extended_instances), {links[0], links[1], links[2]})
        eq_(set(s2.extended_instances), {links[2]})

        eq_(c1.get_links_for_association(self.a), links)

    def test_delete_stereotype_of_extended_instances(self):
        s1 = CStereotype("S1", extended=self.a)
        s1.delete()
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        links = set_links({c1: c2})[0]
        try:
            links.stereotype_instances = [s1]
            exception_expected_()
        except CException as e:
            eq_(e.value, "cannot access named element that has been deleted")

    def test_delete_stereotyped_element_instance(self):
        s1 = CStereotype("S1", extended=self.a)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        links = set_links({c1: c2}, stereotype_instances=[s1])[0]
        eq_(s1.extended_instances, [links])
        eq_(links.stereotype_instances, [s1])
        links.delete()
        eq_(s1.extended_instances, [])
        eq_(links.stereotype_instances, [])

    def test_add_stereotype_instance_wrong_association(self):
        other_association = self.m1.association(self.m2,
                                                name="b",
                                                multiplicity="*",
                                                role_name="m1",
                                                source_multiplicity="1",
                                                source_role_name="m2")
        s1 = CStereotype("S1", extended=self.a)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        links = set_links({c1: c2}, association=other_association)[0]
        try:
            links.stereotype_instances = [s1]
            exception_expected_()
        except CException as e:
            eq_(
                e.value,
                "stereotype 'S1' cannot be added to link from 'C1' to 'C2': no extension by this stereotype found"
            )

    def test_add_stereotype_of_inherited_metaclass(self):
        sub1 = CMetaclass("Sub1", superclasses=self.m1)
        sub2 = CMetaclass("Sub2", superclasses=self.m2)
        s = CStereotype("S1", extended=self.a)
        c1 = CClass(sub1, "C1")
        c2 = CClass(sub2, "C2")
        links = add_links({c1: c2}, stereotype_instances=s)[0]
        eq_(s.extended_instances, [links])
        eq_(links.stereotype_instances, [s])

    def test_add_stereotype_instance_correct_by_inheritance_of_stereotype(
            self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", superclasses=s1)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        links = c1.add_links(c2, stereotype_instances=[s2])[0]
        eq_(s2.extended_instances, [links])
        eq_(links.stereotype_instances, [s2])

    def test_all_extended_instances(self):
        s1 = CStereotype("S1", extended=self.a)
        s2 = CStereotype("S2", superclasses=s1)
        c1 = CClass(self.m1, "C1")
        c2 = CClass(self.m2, "C2")
        c3 = CClass(self.m2, "C3")
        links = set_links({c1: [c2, c3]})
        links[0].stereotype_instances = s1
        links[1].stereotype_instances = s2
        eq_(s1.extended_instances, [links[0]])
        eq_(s2.extended_instances, [links[1]])
        eq_(s1.all_extended_instances, [links[0], links[1]])
        eq_(s2.all_extended_instances, [links[1]])
 def test_all_associations(self):
     s = CMetaclass("S")
     d = CMetaclass("D", superclasses=s)
     a = s.association(d, "is next: [prior s] * -> [next d] *")
     eq_(d.all_associations, [a])
     eq_(s.all_associations, [a])
class TestMetaclassAssociations:
    def setup(self):
        self.metaclassBundle = CBundle("P")
        self.m1 = CMetaclass("M1", bundles=self.metaclassBundle)
        self.m2 = CMetaclass("M2", bundles=self.metaclassBundle)
        self.m3 = CMetaclass("M3", bundles=self.metaclassBundle)
        self.m4 = CMetaclass("M4", bundles=self.metaclassBundle)
        self.m5 = CMetaclass("M5", bundles=self.metaclassBundle)

    def get_all_associations_in_bundle(self):
        associations = []
        for c in self.metaclassBundle.get_elements(type=CMetaclass):
            for a in c.all_associations:
                if a not in associations:
                    associations.append(a)
        return associations

    def test_association_creation(self):
        a1 = self.m1.association(self.m2,
                                 multiplicity="1",
                                 role_name="t",
                                 source_multiplicity="*",
                                 source_role_name="i")
        a2 = self.m1.association(self.m2, "[o]*->[s]1")
        a3 = self.m1.association(self.m3, "[a] 0..1 <*>- [n]*")
        a4 = self.m1.association(self.m3,
                                 multiplicity="*",
                                 role_name="e",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 composition=True)
        a5 = self.m4.association(self.m3,
                                 multiplicity="*",
                                 role_name="n",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 aggregation=True)
        a6 = self.m3.association(self.m2, '[a] 3 <>- [e]*')

        eq_(len(self.get_all_associations_in_bundle()), 6)

        eq_(self.m1.associations[0].role_name, "t")
        eq_(a5.role_name, "n")
        eq_(a2.role_name, "s")
        eq_(a1.multiplicity, "1")
        eq_(a1.source_multiplicity, "*")
        eq_(a4.source_multiplicity, "0..1")
        eq_(a6.source_multiplicity, "3")

        eq_(a1.composition, False)
        eq_(a1.aggregation, False)
        eq_(a3.composition, True)
        eq_(a3.aggregation, False)
        eq_(a5.composition, False)
        eq_(a5.aggregation, True)

        a1.aggregation = True
        eq_(a1.composition, False)
        eq_(a1.aggregation, True)
        a1.composition = True
        eq_(a1.composition, True)
        eq_(a1.aggregation, False)

    def test_mixed_association_types(self):
        c1 = CClass(self.m1, "C1")
        s1 = CStereotype("S1")
        try:
            self.m1.association(s1,
                                multiplicity="1",
                                role_name="t",
                                source_multiplicity="*",
                                source_role_name="i")
            exception_expected_()
        except CException as e:
            eq_(
                "metaclass 'M1' is not compatible with association target 'S1'",
                e.value)

        try:
            self.m1.association(c1,
                                multiplicity="1",
                                role_name="t",
                                source_multiplicity="*",
                                source_role_name="i")
            exception_expected_()
        except CException as e:
            eq_(
                "metaclass 'M1' is not compatible with association target 'C1'",
                e.value)

    def test_get_association_by_role_name(self):
        self.m1.association(self.m2,
                            multiplicity="1",
                            role_name="t",
                            source_multiplicity="*",
                            source_role_name="i")
        self.m1.association(self.m2,
                            multiplicity="1",
                            role_name="s",
                            source_multiplicity="*",
                            source_role_name="o")
        self.m1.association(self.m3,
                            multiplicity="*",
                            role_name="n",
                            source_multiplicity="0..1",
                            source_role_name="a",
                            composition=True)

        a_2 = next(a for a in self.m1.associations if a.role_name == "s")
        eq_(a_2.multiplicity, "1")
        eq_(a_2.source_role_name, "o")
        eq_(a_2.source_multiplicity, "*")

    def test_get_association_by_name(self):
        self.m1.association(self.m2,
                            name="n1",
                            multiplicity="1",
                            role_name="t",
                            source_multiplicity="*",
                            source_role_name="i")
        self.m1.association(self.m2,
                            name="n2",
                            multiplicity="1",
                            role_name="s",
                            source_multiplicity="*",
                            source_role_name="o")
        self.m1.association(self.m3, "n3: [a] 0..1 <*>- [n] *")

        a_2 = next(a for a in self.m1.associations if a.name == "n2")
        eq_(a_2.multiplicity, "1")
        eq_(a_2.source_role_name, "o")
        eq_(a_2.source_multiplicity, "*")

        a_3 = next(a for a in self.m1.associations if a.name == "n3")
        eq_(a_3.multiplicity, "*")
        eq_(a_3.role_name, "n")
        eq_(a_3.source_multiplicity, "0..1")
        eq_(a_3.source_role_name, "a")
        eq_(a_3.composition, True)

    def test_get_associations(self):
        a1 = self.m1.association(self.m2,
                                 multiplicity="1",
                                 role_name="t",
                                 source_multiplicity="*",
                                 source_role_name="i")
        a2 = self.m1.association(self.m2,
                                 multiplicity="1",
                                 role_name="s",
                                 source_multiplicity="*",
                                 source_role_name="o")
        a3 = self.m1.association(self.m3,
                                 multiplicity="*",
                                 role_name="n",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 composition=True)
        a4 = self.m1.association(self.m3,
                                 multiplicity="*",
                                 role_name="e",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 composition=True)
        a5 = self.m4.association(self.m3,
                                 multiplicity="*",
                                 role_name="n",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 aggregation=True)
        a6 = self.m3.association(self.m2,
                                 multiplicity="*",
                                 role_name="e",
                                 source_multiplicity="3",
                                 source_role_name="a",
                                 aggregation=True)
        eq_(self.m1.associations, [a1, a2, a3, a4])
        eq_(self.m2.associations, [a1, a2, a6])
        eq_(self.m3.associations, [a3, a4, a5, a6])
        eq_(self.m4.associations, [a5])
        eq_(self.m5.associations, [])

    def test_delete_associations(self):
        a1 = self.m1.association(self.m2,
                                 multiplicity="1",
                                 role_name="t",
                                 source_multiplicity="*",
                                 source_role_name="i")
        a2 = self.m1.association(self.m2,
                                 multiplicity="1",
                                 role_name="s",
                                 source_multiplicity="*",
                                 source_role_name="o")
        a3 = self.m1.association(self.m3,
                                 multiplicity="*",
                                 role_name="n",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 composition=True)
        a4 = self.m1.association(self.m3,
                                 multiplicity="*",
                                 role_name="e",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 composition=True)
        a5 = self.m4.association(self.m3,
                                 multiplicity="*",
                                 role_name="n",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 aggregation=True)
        a6 = self.m3.association(self.m2,
                                 multiplicity="*",
                                 role_name="e",
                                 source_multiplicity="3",
                                 source_role_name="a",
                                 aggregation=True)
        a7 = self.m1.association(self.m1,
                                 multiplicity="*",
                                 role_name="x",
                                 source_multiplicity="3",
                                 source_role_name="y")

        eq_(len(self.get_all_associations_in_bundle()), 7)

        a2.delete()
        a4.delete()

        eq_(len(self.get_all_associations_in_bundle()), 5)

        eq_(self.m1.associations, [a1, a3, a7])
        eq_(self.m2.associations, [a1, a6])
        eq_(self.m3.associations, [a3, a5, a6])
        eq_(self.m4.associations, [a5])
        eq_(self.m5.associations, [])

    def test_delete_class_and_get_associations(self):
        self.m1.association(self.m2,
                            multiplicity="1",
                            role_name="t",
                            source_multiplicity="*",
                            source_role_name="i")
        self.m1.association(self.m2,
                            multiplicity="1",
                            role_name="s",
                            source_multiplicity="*",
                            source_role_name="o")
        self.m1.association(self.m3,
                            multiplicity="*",
                            role_name="n",
                            source_multiplicity="0..1",
                            source_role_name="a",
                            composition=True)
        self.m1.association(self.m3,
                            multiplicity="*",
                            role_name="e",
                            source_multiplicity="0..1",
                            source_role_name="a",
                            composition=True)
        a5 = self.m4.association(self.m3,
                                 multiplicity="*",
                                 role_name="n",
                                 source_multiplicity="0..1",
                                 source_role_name="a",
                                 aggregation=True)
        a6 = self.m3.association(self.m2,
                                 multiplicity="*",
                                 role_name="e",
                                 source_multiplicity="3",
                                 source_role_name="a",
                                 aggregation=True)
        self.m1.association(self.m1,
                            multiplicity="*",
                            role_name="x",
                            source_multiplicity="3",
                            source_role_name="y")

        eq_(len(self.get_all_associations_in_bundle()), 7)

        self.m1.delete()

        eq_(len(self.get_all_associations_in_bundle()), 2)

        eq_(self.m1.associations, [])
        eq_(self.m2.associations, [a6])
        eq_(self.m3.associations, [a5, a6])
        eq_(self.m4.associations, [a5])
        eq_(self.m5.associations, [])

    def test_all_associations(self):
        s = CMetaclass("S")
        d = CMetaclass("D", superclasses=s)
        a = s.association(d, "is next: [prior s] * -> [next d] *")
        eq_(d.all_associations, [a])
        eq_(s.all_associations, [a])

    def test_get_opposite_classifier(self):
        a = self.m1.association(self.m2, "[o]*->[s]1")
        eq_(a.get_opposite_classifier(self.m1), self.m2)
        eq_(a.get_opposite_classifier(self.m2), self.m1)
        try:
            a.get_opposite_classifier(self.m3)
            exception_expected_()
        except CException as e:
            eq_(
                "can only get opposite if either source or target classifier is provided",
                e.value)
示例#18
0
class TestClassLinks:
    def setup(self):
        self.m1 = CMetaclass("M1")
        self.m2 = CMetaclass("M2")
        self.mcl = CMetaclass("MCL")

    def test_link_methods_wrong_keyword_args(self):
        c1 = CClass(self.m1, "C1")
        try:
            add_links({c1: c1}, associationX=None)
            exception_expected_()
        except CException as e:
            eq_(e.value, "unknown keywords argument")
        try:
            c1.add_links(c1, associationX=None)
            exception_expected_()
        except CException as e:
            eq_(e.value, "unknown keywords argument")
        try:
            set_links({c1: c1}, associationX=None)
            exception_expected_()
        except CException as e:
            eq_(e.value, "unknown keywords argument")
        try:
            c1.delete_links(c1, associationX=None)
            exception_expected_()
        except CException as e:
            eq_(e.value, "unknown keywords argument")
        try:
            delete_links({c1: c1}, associationX=None)
            exception_expected_()
        except CException as e:
            eq_(e.value, "unknown keywords argument")
        try:
            c1.get_linked(associationX=None)
            exception_expected_()
        except CException as e:
            eq_(e.value, "unknown keywords argument")
        try:
            delete_links({c1: c1}, stereotype_instances=None)
            exception_expected_()
        except CException as e:
            eq_(e.value, "unknown keywords argument")

    def test_set_one_to_one_link(self):
        self.m1.association(self.m2, name="l", multiplicity="1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")

        eq_(c1.linked, [])

        set_links({c1: c2})
        eq_(c1.linked, [c2])
        eq_(c2.linked, [c1])

        set_links({c1: c3})
        eq_(c1.linked, [c3])
        eq_(c2.linked, [])
        eq_(c3.linked, [c1])

    def test_add_one_to_one_link(self):
        self.m1.association(self.m2, "l: 1 -> [target] 0..1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")

        eq_(c1.linked, [])

        add_links({c1: c3})
        eq_(c1.linked, [c3])
        eq_(c3.linked, [c1])

        set_links({c1: []}, role_name="target")
        eq_(c1.linked, [])

        c1.add_links(c2)
        eq_(c1.linked, [c2])
        eq_(c2.linked, [c1])

        try:
            add_links({c1: c3})
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '2': should be '0..1'")
        eq_(c1.linked, [c2])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [])

    def test_wrong_types_add_links(self):
        self.m1.association(self.m2, name="l", multiplicity="1")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        try:
            add_links({c1: self.mcl})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'MCL' is not an object, class, or link")
        try:
            c1.add_links([c2, self.mcl])
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'MCL' is not an object, class, or link")

    def test_wrong_types_set_links(self):
        self.m1.association(self.m2, name="l", multiplicity="1")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        try:
            set_links({c1: self.mcl})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'MCL' is not an object, class, or link")
        try:
            set_links({c1: [c2, self.mcl]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'MCL' is not an object, class, or link")
        try:
            set_links({c1: [c2, None]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'None' is not an object, class, or link")
        try:
            set_links({self.mcl: c2})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link source 'MCL' is not an object, class, or link")
        try:
            set_links({None: c2})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link should not contain an empty source")

    def test_wrong_format_set_links(self):
        self.m1.association(self.m2, name="l", multiplicity="1")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        try:
            # noinspection PyTypeChecker
            set_links([c1, c2])
            exception_expected_()
        except CException as e:
            eq_(e.value, "link definitions should be of the form {<link source 1>: " +
                "<link target(s) 1>, ..., <link source n>: <link target(s) n>}")

    def test_remove_one_to_one_link(self):
        a = self.m1.association(self.m2, "l: 1 -> [c2] 0..1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m1, "c3")
        c4 = CClass(self.m2, "c4")

        links = set_links({c1: c2, c3: c4})
        eq_(c1.linked, [c2])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [c4])
        eq_(c4.linked, [c3])
        eq_(c1.links, [links[0]])
        eq_(c2.links, [links[0]])
        eq_(c3.links, [links[1]])
        eq_(c4.links, [links[1]])

        try:
            links = set_links({c1: None})
            exception_expected_()
        except CException as e:
            eq_(e.value, "matching association not found for source 'c1' and targets '[]'")

        set_links({c1: None}, association=a)
        eq_(c1.linked, [])
        eq_(c2.linked, [])
        eq_(c3.linked, [c4])
        eq_(c4.linked, [c3])
        eq_(c1.links, [])
        eq_(c2.links, [])
        eq_(c3.links, [links[1]])
        eq_(c4.links, [links[1]])

    def test_set_links_one_to_n_link(self):
        self.m1.association(self.m2, name="l")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")

        set_links({c1: [c2, c3]})
        eq_(c1.linked, [c2, c3])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [c1])
        set_links({c1: c2})
        eq_(c1.linked, [c2])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [])
        set_links({c3: c1, c2: c1})
        eq_(c1.linked, [c3, c2])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [c1])

    def test_add_links_one_to_n_link(self):
        self.m1.association(self.m2, name="l")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")
        c5 = CClass(self.m2, "c5")
        c6 = CClass(self.m2, "c6")

        add_links({c1: [c2, c3]})
        eq_(c1.linked, [c2, c3])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [c1])
        add_links({c1: c4})
        eq_(c1.linked, [c2, c3, c4])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [c1])
        eq_(c4.linked, [c1])
        c1.add_links([c5, c6])
        eq_(c1.linked, [c2, c3, c4, c5, c6])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [c1])
        eq_(c4.linked, [c1])
        eq_(c5.linked, [c1])
        eq_(c6.linked, [c1])

    def test_remove_one_to_n_link(self):
        a = self.m1.association(self.m2, name="l", multiplicity="*")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        set_links({c1: [c2, c3]})
        set_links({c1: c2})
        eq_(c1.linked, [c2])
        eq_(c2.linked, [c1])
        eq_(c3.linked, [])
        try:
            set_links({c1: []})
            exception_expected_()
        except CException as e:
            eq_(e.value, "matching association not found for source 'c1' and targets '[]'")
        set_links({c1: []}, association=a)
        eq_(c1.linked, [])
        eq_(c2.linked, [])
        eq_(c3.linked, [])

    def test_n_to_n_link(self):
        a = self.m1.association(self.m2, name="l", source_multiplicity="*")
        c1a = CClass(self.m1, "c1a")
        c1b = CClass(self.m1, "c1b")
        c1c = CClass(self.m1, "c1c")
        c2a = CClass(self.m2, "c2a")
        c2b = CClass(self.m2, "c2b")

        set_links({c1a: [c2a, c2b], c1b: [c2a], c1c: [c2b]})

        eq_(c1a.linked, [c2a, c2b])
        eq_(c1b.linked, [c2a])
        eq_(c1c.linked, [c2b])
        eq_(c2a.linked, [c1a, c1b])
        eq_(c2b.linked, [c1a, c1c])

        set_links({c2a: [c1a, c1b]})
        try:
            set_links({c2b: []})
            exception_expected_()
        except CException as e:
            eq_(e.value, "matching association not found for source 'c2b' and targets '[]'")
        set_links({c2b: []}, association=a)

        eq_(c1a.linked, [c2a])
        eq_(c1b.linked, [c2a])
        eq_(c1c.linked, [])
        eq_(c2a.linked, [c1a, c1b])
        eq_(c2b.linked, [])

    def test_remove_n_to_n_link(self):
        self.m1.association(self.m2, name="l", source_multiplicity="*", multiplicity="*")
        c1 = CClass(self.m1, "c2")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m1, "c4")
        set_links({c1: [c2, c3], c4: c2})
        set_links({c1: c2, c4: [c3, c2]})
        eq_(c1.linked, [c2])
        eq_(c2.linked, [c1, c4])
        eq_(c3.linked, [c4])
        eq_(c4.linked, [c3, c2])

    def test_n_to_n_set_self_link(self):
        self.m1.association(self.m1, name="a", source_multiplicity="*", multiplicity="*", source_role_name="super",
                            role_name="sub")

        top = CClass(self.m1, "Top")
        mid1 = CClass(self.m1, "Mid1")
        mid2 = CClass(self.m1, "Mid2")
        mid3 = CClass(self.m1, "Mid3")
        bottom1 = CClass(self.m1, "Bottom1")
        bottom2 = CClass(self.m1, "Bottom2")

        set_links({top: [mid1, mid2, mid3]}, role_name="sub")
        mid1.add_links([bottom1, bottom2], role_name="sub")

        eq_(top.linked, [mid1, mid2, mid3])
        eq_(mid1.linked, [top, bottom1, bottom2])
        eq_(mid2.linked, [top])
        eq_(mid3.linked, [top])
        eq_(bottom1.linked, [mid1])
        eq_(bottom2.linked, [mid1])

        eq_(top.get_linked(role_name="sub"), [mid1, mid2, mid3])
        eq_(mid1.get_linked(role_name="sub"), [bottom1, bottom2])
        eq_(mid2.get_linked(role_name="sub"), [])
        eq_(mid3.get_linked(role_name="sub"), [])
        eq_(bottom1.get_linked(role_name="sub"), [])
        eq_(bottom2.get_linked(role_name="sub"), [])

        eq_(top.get_linked(role_name="super"), [])
        eq_(mid1.get_linked(role_name="super"), [top])
        eq_(mid2.get_linked(role_name="super"), [top])
        eq_(mid3.get_linked(role_name="super"), [top])
        eq_(bottom1.get_linked(role_name="super"), [mid1])
        eq_(bottom2.get_linked(role_name="super"), [mid1])

    def test_n_to_n_set_self_link_delete_links(self):
        self.m1.association(self.m1, name="a", source_multiplicity="*", multiplicity="*", source_role_name="super",
                            role_name="sub")

        top = CClass(self.m1, "Top")
        mid1 = CClass(self.m1, "Mid1")
        mid2 = CClass(self.m1, "Mid2")
        mid3 = CClass(self.m1, "Mid3")
        bottom1 = CClass(self.m1, "Bottom1")
        bottom2 = CClass(self.m1, "Bottom2")

        set_links({top: [mid1, mid2, mid3], mid1: [bottom1, bottom2]}, role_name="sub")
        # delete links
        set_links({top: []}, role_name="sub")
        eq_(top.linked, [])
        eq_(mid1.linked, [bottom1, bottom2])
        # change links
        set_links({mid1: top, mid3: top, bottom1: mid1, bottom2: mid1}, role_name="super")

        eq_(top.linked, [mid1, mid3])
        eq_(mid1.linked, [top, bottom1, bottom2])
        eq_(mid2.linked, [])
        eq_(mid3.linked, [top])
        eq_(bottom1.linked, [mid1])
        eq_(bottom2.linked, [mid1])

        eq_(top.get_linked(role_name="sub"), [mid1, mid3])
        eq_(mid1.get_linked(role_name="sub"), [bottom1, bottom2])
        eq_(mid2.get_linked(role_name="sub"), [])
        eq_(mid3.get_linked(role_name="sub"), [])
        eq_(bottom1.get_linked(role_name="sub"), [])
        eq_(bottom2.get_linked(role_name="sub"), [])

        eq_(top.get_linked(role_name="super"), [])
        eq_(mid1.get_linked(role_name="super"), [top])
        eq_(mid2.get_linked(role_name="super"), [])
        eq_(mid3.get_linked(role_name="super"), [top])
        eq_(bottom1.get_linked(role_name="super"), [mid1])
        eq_(bottom2.get_linked(role_name="super"), [mid1])

    def test_incompatible_classifier(self):
        self.m1.association(self.m2, name="l", multiplicity="*")
        cl = CClass(self.mcl, "CLX")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CObject(cl, "c3")
        try:
            set_links({c1: [c2, c3]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'c3' is an object, but source is a class")
        try:
            set_links({c1: c3})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'c3' is an object, but source is a class")

    def test_duplicate_assignment(self):
        a = self.m1.association(self.m2, "l: *->*")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        try:
            set_links({c1: [c2, c2]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "trying to link the same link twice 'c1 -> c2'' twice for the same association")
        eq_(c1.get_linked(), [])
        eq_(c2.get_linked(), [])

        b = self.m1.association(self.m2, "l: *->*")
        c1.add_links(c2, association=a)
        c1.add_links(c2, association=b)
        eq_(c1.get_linked(), [c2, c2])
        eq_(c2.get_linked(), [c1, c1])

    def test_non_existing_role_name(self):
        self.m1.association(self.m1, role_name="next", source_role_name="prior",
                            source_multiplicity="1", multiplicity="1")
        c1 = CClass(self.m1, "c1")
        try:
            set_links({c1: c1}, role_name="target")
            exception_expected_()
        except CException as e:
            eq_(e.value, "matching association not found for source 'c1' and targets '['c1']'")

    def test_link_association_ambiguous(self):
        self.m1.association(self.m2, name="a1", role_name="c2", multiplicity="*")
        self.m1.association(self.m2, name="a2", role_name="c2", multiplicity="*")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        try:
            set_links({c1: c2})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link specification ambiguous, multiple matching associations found " +
                "for source 'c1' and targets '['c2']'")
        try:
            set_links({c1: c2}, role_name="c2")
            exception_expected_()
        except CException as e:
            eq_(e.value, "link specification ambiguous, multiple matching associations found " +
                "for source 'c1' and targets '['c2']'")

    def test_link_and_get_links_by_association(self):
        a1 = self.m1.association(self.m2, name="a1", multiplicity="*")
        a2 = self.m1.association(self.m2, name="a2", multiplicity="*")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")

        links_a1 = set_links({c1: c2}, association=a1)
        links_a2 = set_links({c1: [c2, c3]}, association=a2)

        eq_(c1.get_linked(), [c2, c2, c3])
        eq_(c1.linked, [c2, c2, c3])

        eq_(c1.get_linked(association=a1), [c2])
        eq_(c1.get_linked(association=a2), [c2, c3])

        eq_(c1.get_links_for_association(a1), links_a1)
        eq_(c1.get_links_for_association(a2), links_a2)

    def test_link_with_inheritance_in_classifier_targets(self):
        sub_class = CMetaclass(superclasses=self.m2)
        a1 = self.m1.association(sub_class, name="a1", multiplicity="*")
        a2 = self.m1.association(self.m2, name="a2", multiplicity="*")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c_sub_1 = CClass(sub_class, "c_sub_1")
        c_sub_2 = CClass(sub_class, "c_sub_2")
        c_super_1 = CClass(self.m2, "c_super_1")
        c_super_2 = CClass(self.m2, "c_super_2")
        try:
            # ambiguous, list works for both associations 
            set_links({c1: [c_sub_1, c_sub_2]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link specification ambiguous, multiple matching associations found " +
                "for source 'c1' and targets '['c_sub_1', 'c_sub_2']'")
        set_links({c1: [c_sub_1, c_sub_2]}, association=a1)
        set_links({c1: [c_sub_1]}, association=a2)
        set_links({c2: [c_super_1, c_super_2]})

        eq_(c1.linked, [c_sub_1, c_sub_2, c_sub_1])
        eq_(c1.get_linked(), [c_sub_1, c_sub_2, c_sub_1])
        eq_(c2.get_linked(), [c_super_1, c_super_2])
        eq_(c1.get_linked(association=a1), [c_sub_1, c_sub_2])
        eq_(c1.get_linked(association=a2), [c_sub_1])
        eq_(c2.get_linked(association=a1), [])
        eq_(c2.get_linked(association=a2), [c_super_1, c_super_2])

        # this mixed list is applicable only for a2
        set_links({c2: [c_sub_1, c_super_1]})
        eq_(c2.get_linked(association=a1), [])
        eq_(c2.get_linked(association=a2), [c_sub_1, c_super_1])

    def test_link_with_inheritance_in_classifier_targets_using_role_names(self):
        sub_class = CMetaclass(superclasses=self.m2)
        a1 = self.m1.association(sub_class, "a1: * -> [sub_class] *")
        a2 = self.m1.association(self.m2, "a2: * -> [c2] *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c_sub_1 = CClass(sub_class, "c_sub_1")
        c_sub_2 = CClass(sub_class, "c_sub_2")
        c_super_1 = CClass(self.m2, "c_super_1")
        c_super_2 = CClass(self.m2, "c_super_2")
        set_links({c1: [c_sub_1, c_sub_2]}, role_name="sub_class")
        set_links({c1: [c_sub_1]}, role_name="c2")
        set_links({c2: [c_super_1, c_super_2]})

        eq_(c1.linked, [c_sub_1, c_sub_2, c_sub_1])
        eq_(c1.get_linked(), [c_sub_1, c_sub_2, c_sub_1])
        eq_(c2.get_linked(), [c_super_1, c_super_2])
        eq_(c1.get_linked(association=a1), [c_sub_1, c_sub_2])
        eq_(c1.get_linked(association=a2), [c_sub_1])
        eq_(c2.get_linked(association=a1), [])
        eq_(c2.get_linked(association=a2), [c_super_1, c_super_2])
        eq_(c1.get_linked(role_name="sub_class"), [c_sub_1, c_sub_2])
        eq_(c1.get_linked(role_name="c2"), [c_sub_1])
        eq_(c2.get_linked(role_name="sub_class"), [])
        eq_(c2.get_linked(role_name="c2"), [c_super_1, c_super_2])

    def test_link_delete_association(self):
        a = self.m1.association(self.m2, name="l", source_multiplicity="*", multiplicity="*")
        c1 = CClass(self.m1, "c2")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m1, "c4")
        set_links({c1: [c2, c3]})
        set_links({c4: [c2]})
        set_links({c1: [c2]})
        set_links({c4: [c3, c2]})
        a.delete()
        eq_(c1.linked, [])
        eq_(c2.linked, [])
        eq_(c3.linked, [])
        eq_(c4.linked, [])
        try:
            set_links({c1: [c2, c3]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "matching association not found for source 'c2' and targets '['c2', 'c3']'")

    def test_link_delete_class_object(self):
        self.m1.association(self.m2, name="l", source_multiplicity="*", multiplicity="*")
        c1 = CClass(self.m1, "c2")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m1, "c4")
        add_links({c1: [c2, c3]})
        add_links({c4: [c3, c2]})

        c2.delete()
        eq_(c1.linked, [c3])
        eq_(c3.linked, [c1, c4])
        eq_(c4.linked, [c3])
        try:
            add_links({c1: [c2]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "cannot link to deleted target")
        try:
            add_links({c2: [c1]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "cannot link to deleted source")

    def test_one_to_one_link_multiplicity(self):
        a = self.m1.association(self.m2, name="l", multiplicity="1", source_multiplicity="1..1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m1, "c4")

        try:
            set_links({c1: []}, association=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '0': should be '1'")
        try:
            set_links({c1: [c2, c3]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '2': should be '1'")

        try:
            set_links({c2: []}, association=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c2' have wrong multiplicity '0': should be '1..1'")
        try:
            set_links({c2: [c1, c4]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c2' have wrong multiplicity '2': should be '1..1'")

    def test_one_to_n_link_multiplicity(self):
        a = self.m1.association(self.m2, name="l", source_multiplicity="1", multiplicity="1..*")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m1, "c4")

        try:
            set_links({c1: []}, association=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '0': should be '1..*'")

        set_links({c1: [c2, c3]})
        eq_(c1.get_linked(association=a), [c2, c3])

        try:
            set_links({c2: []}, association=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c2' have wrong multiplicity '0': should be '1'")
        try:
            set_links({c2: [c1, c4]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c2' have wrong multiplicity '2': should be '1'")

    def test_specific_n_to_n_link_multiplicity(self):
        a = self.m1.association(self.m2, name="l", source_multiplicity="1..2", multiplicity="2")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m1, "c4")
        c5 = CClass(self.m1, "c5")
        c6 = CClass(self.m2, "c6")

        try:
            set_links({c1: []}, association=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '0': should be '2'")
        try:
            set_links({c1: [c2]}, association=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '1': should be '2'")
        try:
            set_links({c1: [c2, c3, c6]}, association=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '3': should be '2'")

        set_links({c1: [c2, c3]})
        eq_(c1.get_linked(association=a), [c2, c3])
        set_links({c2: [c1, c4], c1: c3, c4: c3})
        eq_(c2.get_linked(association=a), [c1, c4])

        try:
            set_links({c2: []}, association=a)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c2' have wrong multiplicity '0': should be '1..2'")
        try:
            set_links({c2: [c1, c4, c5]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c2' have wrong multiplicity '3': should be '1..2'")

    def test_get_links(self):
        c1_sub_class = CMetaclass("C1Sub", superclasses=self.m1)
        c2_sub_class = CMetaclass("C2Sub", superclasses=self.m2)
        a1 = self.m1.association(self.m2, role_name="c2", source_role_name="c1",
                                 source_multiplicity="*", multiplicity="*")
        a2 = self.m1.association(self.m1, role_name="next", source_role_name="prior",
                                 source_multiplicity="1", multiplicity="0..1")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c1_sub_class = CClass(c1_sub_class, "c1_sub_class")
        c2_sub_class = CClass(c2_sub_class, "c2_sub_class")

        links1 = set_links({c1: c2})
        eq_(links1, c1.links)
        link1 = c1.links[0]
        link2 = [o for o in c1.links if o.association == a1][0]
        eq_(link1, link2)
        eq_(link1.association, a1)
        eq_(link1.source, c1)
        eq_(link1.target, c2)

        links2 = set_links({c1: c2_sub_class})
        eq_(links2, c1.links)
        eq_(len(c1.links), 1)
        link1 = c1.links[0]
        link2 = [o for o in c1.links if o.association == a1][0]
        eq_(link1, link2)
        eq_(link1.association, a1)
        eq_(link1.source, c1)
        eq_(link1.target, c2_sub_class)

        links3 = set_links({c1: c2})
        eq_(links3, c1.links)
        eq_(len(c1.links), 1)
        link1 = c1.links[0]
        link2 = [o for o in c1.links if o.association == a1][0]
        eq_(link1, link2)
        eq_(link1.association, a1)
        eq_(link1.source, c1)
        eq_(link1.target, c2)

        links4 = set_links({c1: c1}, role_name="next")
        eq_(links3 + links4, c1.links)
        eq_(len(c1.links), 2)
        link1 = c1.links[1]
        link2 = [o for o in c1.links if o.association == a2][0]
        eq_(link1, link2)
        eq_(link1.association, a2)
        eq_(link1.source, c1)
        eq_(link1.target, c1)

        links5 = set_links({c1: c1_sub_class}, role_name="next")
        eq_(links3 + links5, c1.links)
        eq_(len(c1.links), 2)
        link1 = c1.links[1]
        link2 = [o for o in c1.links if o.association == a2][0]
        eq_(link1, link2)
        eq_(link1.association, a2)
        eq_(link1.source, c1)
        eq_(link1.target, c1_sub_class)

        set_links({c1: c1}, role_name="next")
        eq_(len(c1.links), 2)
        link1 = c1.links[1]
        link2 = [o for o in c1.links if o.association == a2][0]
        eq_(link1, link2)
        eq_(link1.association, a2)
        eq_(link1.source, c1)
        eq_(link1.target, c1)

        set_links({c1: []}, association=a1)
        set_links({c1: []}, association=a2)
        eq_(len(c1.links), 0)

        set_links({c1_sub_class: c1}, role_name="next")
        eq_(len(c1_sub_class.links), 1)
        link1 = c1_sub_class.links[0]
        link2 = [o for o in c1_sub_class.links if o.association == a2][0]
        eq_(link1, link2)
        eq_(link1.association, a2)
        eq_(link1.source, c1_sub_class)
        eq_(link1.target, c1)

    def test_get_links_self_link(self):
        a1 = self.m1.association(self.m1, role_name="to", source_role_name="from",
                                 source_multiplicity="*", multiplicity="*")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m1, "c3")
        c4 = CClass(self.m1, "c4")

        set_links({c1: [c2, c3, c1]})
        add_links({c4: [c1, c3]})
        link1 = c1.links[0]
        link2 = [o for o in c1.links if o.association == a1][0]
        link3 = [o for o in c1.links if o.role_name == "to"][0]
        link4 = [o for o in c1.links if o.source_role_name == "from"][0]
        eq_(link1, link2)
        eq_(link1, link3)
        eq_(link1, link4)
        eq_(link1.association, a1)
        eq_(link1.source, c1)
        eq_(link1.target, c2)

        eq_(len(c1.links), 4)
        eq_(len(c2.links), 1)
        eq_(len(c3.links), 2)
        eq_(len(c4.links), 2)

    def test_add_links(self):
        self.m1.association(self.m2, "1 -> [role1] *")
        self.m1.association(self.m2, "* -> [role2] *")
        self.m1.association(self.m2, "1 -> [role3] 1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")

        add_links({c1: c2}, role_name="role1")
        eq_(c1.get_linked(role_name="role1"), [c2])
        add_links({c1: [c3, c4]}, role_name="role1")
        c1.get_linked(role_name="role1")
        eq_(c1.get_linked(role_name="role1"), [c2, c3, c4])

        c1.add_links(c2, role_name="role2")
        eq_(c1.get_linked(role_name="role2"), [c2])
        c1.add_links([c3, c4], role_name="role2")
        c1.get_linked(role_name="role2")
        eq_(c1.get_linked(role_name="role2"), [c2, c3, c4])

        c1.add_links(c2, role_name="role3")
        eq_(c1.get_linked(role_name="role3"), [c2])
        try:
            add_links({c1: [c3, c4]}, role_name="role3")
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '3': should be '1'")

        try:
            add_links({c1: [c3]}, role_name="role3")
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '2': should be '1'")
        eq_(c1.get_linked(role_name="role3"), [c2])

    def test_link_source_multiplicity(self):
        self.m1.association(self.m2, "[sourceRole1] 1 -> [role1] *")
        self.m1.association(self.m2, "[sourceRole2] 1 -> [role2] 1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m2, "c3")
        CClass(self.m2, "c4")
        CClass(self.m2, "c5")

        set_links({c1: c3}, role_name="role1")
        set_links({c2: c3}, role_name="role1")

        eq_(c3.get_linked(role_name="sourceRole1"), [c2])

    def test_add_links_source_multiplicity(self):
        self.m1.association(self.m2, "[sourceRole1] 1 -> [role1] *")
        self.m1.association(self.m2, "[sourceRole2] 1 -> [role2] 1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")
        c5 = CClass(self.m2, "c5")
        c6 = CClass(self.m2, "c6")

        add_links({c2: c3}, role_name="role1")
        add_links({c2: c4}, role_name="role1")

        eq_(c3.get_linked(role_name="sourceRole1"), [c2])

        add_links({c2: c5}, role_name="role1")
        eq_(c2.get_linked(role_name="role1"), [c3, c4, c5])

        try:
            add_links({c1: [c4]}, role_name="role1")
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c4' have wrong multiplicity '2': should be '1'")

        add_links({c1: c6}, role_name="role2")
        eq_(c1.get_linked(role_name="role2"), [c6])
        try:
            add_links({c1: [c3, c4]}, role_name="role2")
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '3': should be '1'")
        eq_(c1.get_linked(role_name="role2"), [c6])

    def test_set_links_multiple_links_in_definition(self):
        self.m1.association(self.m2, "[sourceRole1] * -> [role1] *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m1, "c3")
        c4 = CClass(self.m2, "c4")
        c5 = CClass(self.m2, "c5")

        set_links({c1: c4, c2: [c4], c5: [c1, c2, c3]})
        eq_(c1.get_linked(), [c4, c5])
        eq_(c2.get_linked(), [c4, c5])
        eq_(c3.get_linked(), [c5])
        eq_(c4.get_linked(), [c1, c2])
        eq_(c5.get_linked(), [c1, c2, c3])

    def test_add_links_multiple_links_in_definition(self):
        self.m1.association(self.m2, "[sourceRole1] * -> [role1] *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m1, "c3")
        c4 = CClass(self.m2, "c4")
        c5 = CClass(self.m2, "c5")

        add_links({c1: c4, c2: [c4], c5: [c1, c2, c3]})
        eq_(c1.get_linked(), [c4, c5])
        eq_(c2.get_linked(), [c4, c5])
        eq_(c3.get_linked(), [c5])
        eq_(c4.get_linked(), [c1, c2])
        eq_(c5.get_linked(), [c1, c2, c3])

    def test_wrong_types_delete_links(self):
        self.m1.association(self.m2, name="l", multiplicity="1")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        try:
            # noinspection PyTypeChecker
            delete_links(c1)
            exception_expected_()
        except CException as e:
            eq_(e.value, "link definitions should be of the form " +
                "{<link source 1>: <link target(s) 1>, ..., <link source n>: <link target(s) n>}")
        try:
            delete_links({c1: self.mcl})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'MCL' is not an object, class, or link")
        try:
            delete_links({c1: [c2, self.mcl]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'MCL' is not an object, class, or link")
        try:
            delete_links({c1: [c2, None]})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link target 'None' is not an object, class, or link")
        try:
            delete_links({self.mcl: c2})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link source 'MCL' is not an object, class, or link")
        try:
            delete_links({None: c2})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link should not contain an empty source")

    def test_delete_one_to_one_link(self):
        self.m1.association(self.m2, "l: 1 -> [c2] 0..1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m1, "c3")
        c4 = CClass(self.m2, "c4")

        links = add_links({c1: c2, c3: c4})
        c1.delete_links(c2)
        eq_(c1.linked, [])
        eq_(c2.linked, [])
        eq_(c3.linked, [c4])
        eq_(c4.linked, [c3])
        eq_(c1.links, [])
        eq_(c2.links, [])
        eq_(c3.links, [links[1]])
        eq_(c4.links, [links[1]])
        delete_links({c3: c4})
        eq_(c1.linked, [])
        eq_(c2.linked, [])
        eq_(c3.linked, [])
        eq_(c4.linked, [])
        eq_(c1.links, [])
        eq_(c2.links, [])
        eq_(c3.links, [])
        eq_(c4.links, [])

    def test_delete_one_to_one_link_wrong_multiplicity(self):
        self.m1.association(self.m2, "l: 1 -> [c2] 1")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        add_links({c1: c2})
        try:
            c1.delete_links(c2)
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c1' have wrong multiplicity '0': should be '1'")
        eq_(c1.linked, [c2])
        eq_(c2.linked, [c1])

    def test_delete_one_to_n_links(self):
        self.m1.association(self.m2, "l: 0..1 -> *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")
        c5 = CClass(self.m2, "c5")

        add_links({c1: [c3, c4], c2: [c5]})
        c4.delete_links([c1])
        eq_(c1.linked, [c3])
        eq_(c2.linked, [c5])
        eq_(c3.linked, [c1])
        eq_(c4.linked, [])
        eq_(c5.linked, [c2])

        c4.add_links([c2])
        eq_(c2.linked, [c5, c4])
        delete_links({c1: c3, c2: c2.linked})
        eq_(c1.linked, [])
        eq_(c2.linked, [])
        eq_(c3.linked, [])
        eq_(c4.linked, [])
        eq_(c5.linked, [])

    def test_delete_one_to_n_links_wrong_multiplicity(self):
        self.m1.association(self.m2, "l: 1 -> *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")
        c5 = CClass(self.m2, "c5")

        add_links({c1: [c3, c4], c2: [c5]})

        try:
            c4.delete_links([c1])
            exception_expected_()
        except CException as e:
            eq_(e.value, "links of object 'c4' have wrong multiplicity '0': should be '1'")

    def test_delete_n_to_n_links(self):
        self.m1.association(self.m2, "l: * -> *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")
        c5 = CClass(self.m2, "c5")
        c6 = CClass(self.m2, "c6")

        add_links({c1: [c3, c4], c2: [c4, c5]})
        c4.delete_links([c1, c2])
        eq_(c1.linked, [c3])
        eq_(c2.linked, [c5])
        eq_(c3.linked, [c1])
        eq_(c4.linked, [])
        eq_(c5.linked, [c2])

        add_links({c4: [c1, c2], c6: [c2, c1]})
        delete_links({c1: c6, c2: [c4, c5]})
        eq_(c1.linked, [c3, c4])
        eq_(c2.linked, [c6])
        eq_(c3.linked, [c1])
        eq_(c4.linked, [c1])
        eq_(c5.linked, [])
        eq_(c6.linked, [c2])

    def test_delete_link_no_matching_link(self):
        a = self.m1.association(self.m2, "l: 0..1 -> *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")
        c5 = CClass(self.m2, "c5")

        add_links({c1: [c3, c4], c2: [c5]}, association=a)

        try:
            delete_links({c1: c5})
            exception_expected_()
        except CException as e:
            eq_(e.value, "no link found for 'c1 -> c5' in delete links")

        b = self.m1.association(self.m2, "l: 0..1 -> *")
        try:
            delete_links({c1: c5})
            exception_expected_()
        except CException as e:
            eq_(e.value, "no link found for 'c1 -> c5' in delete links")

        try:
            c4.delete_links([c1], association=b)
            exception_expected_()
        except CException as e:
            eq_(e.value, "no link found for 'c4 -> c1' in delete links for given association")

    def test_delete_link_select_by_association(self):
        a = self.m1.association(self.m2, "a: * -> *")
        b = self.m1.association(self.m2, "b: * -> *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")

        add_links({c1: [c3], c2: [c3, c4]}, association=b)
        delete_links({c2: c3})
        eq_(c1.linked, [c3])
        eq_(c2.linked, [c4])
        eq_(c3.linked, [c1])
        eq_(c4.linked, [c2])
        add_links({c1: [c3], c2: [c3, c4]}, association=a)

        try:
            delete_links({c1: c3})
            exception_expected_()
        except CException as e:
            eq_(e.value, "link definition in delete links ambiguous for link 'c1->c3': found multiple matches")

        delete_links({c1: c3, c2: c4}, association=b)
        eq_(c1.linked, [c3])
        eq_(c2.linked, [c3, c4])
        eq_(c3.linked, [c1, c2])
        eq_(c4.linked, [c2])
        for o in [c1, c2, c3, c4]:
            for lo in o.links:
                eq_(lo.association, a)

        c1.add_links(c3, association=b)
        try:
            c1.delete_links(c3)
            exception_expected_()
        except CException as e:
            eq_(e.value, "link definition in delete links ambiguous for link 'c1->c3': found multiple matches")

        eq_(c1.linked, [c3, c3])
        eq_(c2.linked, [c3, c4])
        eq_(c3.linked, [c1, c2, c1])
        eq_(c4.linked, [c2])

        c1.delete_links(c3, association=a)
        eq_(c1.linked, [c3])
        eq_(c2.linked, [c3, c4])
        eq_(c3.linked, [c2, c1])
        eq_(c4.linked, [c2])

    def test_delete_link_select_by_role_name(self):
        a = self.m1.association(self.m2, "a: [sourceA] * -> [targetA] *")
        self.m1.association(self.m2, "b: [sourceB] * -> [targetB] *")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m1, "c2")
        c3 = CClass(self.m2, "c3")
        c4 = CClass(self.m2, "c4")

        add_links({c1: [c3], c2: [c3, c4]}, role_name="targetB")
        delete_links({c2: c3})
        eq_(c1.linked, [c3])
        eq_(c2.linked, [c4])
        eq_(c3.linked, [c1])
        eq_(c4.linked, [c2])
        add_links({c1: [c3], c2: [c3, c4]}, role_name="targetA")

        delete_links({c1: c3, c2: c4}, role_name="targetB")
        eq_(c1.linked, [c3])
        eq_(c2.linked, [c3, c4])
        eq_(c3.linked, [c1, c2])
        eq_(c4.linked, [c2])
        for o in [c1, c2, c3, c4]:
            for lo in o.links:
                eq_(lo.association, a)

        add_links({c1: [c3], c2: [c3, c4]}, role_name="targetB")
        c3.delete_links([c1, c2], role_name="sourceB")
        delete_links({c4: c2}, role_name="sourceB")

        eq_(c1.linked, [c3])
        eq_(c2.linked, [c3, c4])
        eq_(c3.linked, [c1, c2])
        eq_(c4.linked, [c2])
        for o in [c1, c2, c3, c4]:
            for lo in o.links:
                eq_(lo.association, a)

    def test_delete_links_wrong_role_name(self):
        self.m1.association(self.m2, "a: [sourceA] * -> [targetA] *")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c1.add_links(c2)
        try:
            c1.delete_links(c2, role_name="target")
            exception_expected_()
        except CException as e:
            eq_(e.value, "no link found for 'c1 -> c2' in delete links for given role name 'target'")

    def test_delete_links_wrong_association(self):
        self.m1.association(self.m2, "a: [sourceA] * -> [targetA] *")
        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c1.add_links(c2)
        try:
            c1.delete_links(c2, association=c1)
            exception_expected_()
        except CException as e:
            eq_(e.value, "'c1' is not a association")
        b = self.m1.association(self.m2, "b: [sourceB] * -> [targetB] *")
        try:
            c1.delete_links(c2, association=b)
            exception_expected_()
        except CException as e:
            eq_(e.value, "no link found for 'c1 -> c2' in delete links for given association")
        try:
            c1.delete_links(c2, association=b, role_name="x")
            exception_expected_()
        except CException as e:
            eq_(e.value,
                "no link found for 'c1 -> c2' in delete links for given role name 'x' and for given association")

    def test_link_label_none_default(self):
        a1 = self.m1.association(self.m2, name="a1", multiplicity="*")
        a2 = self.m1.association(self.m2, multiplicity="*")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")

        l1 = set_links({c1: c2}, association=a1)
        l2 = set_links({c1: [c2, c3]}, association=a2)

        eq_(l1[0].label, None)
        eq_(l2[0].label, None)
        eq_(l2[1].label, None)

    def test_link_label_get_set(self):
        a1 = self.m1.association(self.m2, name="a1", multiplicity="*")
        a2 = self.m1.association(self.m2, multiplicity="*")

        c1 = CClass(self.m1, "c1")
        c2 = CClass(self.m2, "c2")
        c3 = CClass(self.m2, "c3")

        l1 = set_links({c1: c2}, association=a1, label="l1")
        l2 = add_links({c1: [c2, c3]}, association=a2, label="l2")

        eq_(l1[0].label, "l1")
        eq_(l2[0].label, "l2")
        eq_(l2[1].label, "l2")

        l2[1].label = "l3"
        eq_(l2[0].label, "l2")
        eq_(l2[1].label, "l3")

        l3 = c1.add_links(c3, association=a1, label="x1")
        eq_(l3[0].label, "x1")

    def test_add_links_with_inherited_common_classifiers(self):
        super_a = CMetaclass("SuperA")
        super_b = CMetaclass("SuperB")
        super_a.association(super_b, "[a] 1 -> [b] *")

        sub_b1 = CMetaclass("SubB1", superclasses=[super_b])
        sub_b2 = CMetaclass("SubB2", superclasses=[super_b])
        sub_a = CMetaclass("SubA", superclasses=[super_a])

        cl_a = CClass(sub_a, "a")
        cl_b1 = CClass(sub_b1, "b1")
        cl_b2 = CClass(sub_b2, "b2")

        add_links({cl_a: [cl_b1, cl_b2]}, role_name="b")
        eq_(set(cl_a.get_linked(role_name="b")), {cl_b1, cl_b2})
示例#19
0
class TestStereotypesOnMetaclasses:
    def setup(self):
        self.mcl = CMetaclass("MCL")
        self.mcl = CMetaclass("MCL")

    def test_creation_of_one_stereotype(self):
        s = CStereotype("S", extended=self.mcl)
        eq_(s.name, "S")
        eq_(self.mcl.stereotypes, [s])
        eq_(s.extended, [self.mcl])

    def test_wrongs_types_in_list_of_extended_element_types(self):
        try:
            CStereotype(
                "S",
                extended=[self.mcl,
                          self.mcl.association(self.mcl, name="A")])
            exception_expected_()
        except CException as e:
            eq_("'A' is not a metaclass", e.value)
        try:
            CStereotype("S", extended=[self.mcl, CBundle("P")])
            exception_expected_()
        except CException as e:
            eq_("'P' is not a metaclass", e.value)
        try:
            CStereotype("S", extended=[CBundle("P"), self.mcl])
            exception_expected_()
        except CException as e:
            eq_("unknown type of extend element: 'P'", e.value)

    def test_creation_of_3_stereotypes(self):
        s1 = CStereotype("S1")
        s2 = CStereotype("S2")
        s3 = CStereotype("S3")
        self.mcl.stereotypes = [s1, s2, s3]
        eq_(s1.extended, [self.mcl])
        eq_(s2.extended, [self.mcl])
        eq_(s3.extended, [self.mcl])
        eq_(set(self.mcl.stereotypes), {s1, s2, s3})

    def test_creation_of_unnamed_stereotype(self):
        s = CStereotype()
        eq_(s.name, None)
        eq_(self.mcl.stereotypes, [])
        eq_(s.extended, [])

    def test_delete_stereotype(self):
        s1 = CStereotype("S1")
        s1.delete()
        eq_(s1.name, None)
        eq_(self.mcl.stereotypes, [])
        s1 = CStereotype("S1", extended=self.mcl)
        s1.delete()
        eq_(s1.name, None)
        eq_(self.mcl.stereotypes, [])

        s1 = CStereotype("S1", extended=self.mcl)
        s2 = CStereotype("S2", extended=self.mcl)
        s3 = CStereotype("s1",
                         superclasses=s2,
                         attributes={"i": 1},
                         extended=self.mcl)

        s1.delete()
        eq_(set(self.mcl.stereotypes), {s2, s3})
        s3.delete()
        eq_(set(self.mcl.stereotypes), {s2})

        eq_(s3.superclasses, [])
        eq_(s2.subclasses, [])
        eq_(s3.attributes, [])
        eq_(s3.attribute_names, [])
        eq_(s3.extended, [])
        eq_(s3.name, None)
        eq_(s3.bundles, [])

    def test_stereotype_extension_add_remove(self):
        s1 = CStereotype("S1")
        eq_(set(s1.extended), set())
        mcl1 = CMetaclass(stereotypes=[s1])
        eq_(set(s1.extended), {mcl1})
        eq_(set(mcl1.stereotypes), {s1})
        mcl2 = CMetaclass(stereotypes=s1)
        eq_(set(s1.extended), {mcl1, mcl2})
        eq_(set(mcl1.stereotypes), {s1})
        eq_(set(mcl2.stereotypes), {s1})
        s1.extended = [mcl2]
        eq_(set(s1.extended), {mcl2})
        eq_(set(mcl1.stereotypes), set())
        eq_(set(mcl2.stereotypes), {s1})
        s2 = CStereotype("S2", extended=[mcl2])
        eq_(set(mcl2.stereotypes), {s2, s1})
        eq_(set(s1.extended), {mcl2})
        eq_(set(s2.extended), {mcl2})
        mcl2.stereotypes = []
        eq_(set(mcl2.stereotypes), set())
        eq_(set(s1.extended), set())
        eq_(set(s2.extended), set())

    def test_stereotype_remove_stereotype_or_metaclass(self):
        mcl = CMetaclass("MCL1")
        s1 = CStereotype("S1", extended=[mcl])
        s2 = CStereotype("S2", extended=[mcl])
        s3 = CStereotype("S3", extended=[mcl])
        s4 = CStereotype("S4", extended=[mcl])
        eq_(set(mcl.stereotypes), {s1, s2, s3, s4})
        s2.delete()
        eq_(set(mcl.stereotypes), {s1, s3, s4})
        eq_(set(s2.extended), set())
        eq_(set(s1.extended), {mcl})
        mcl.delete()
        eq_(set(mcl.stereotypes), set())
        eq_(set(s1.extended), set())

    def test_stereotypes_wrong_type(self):
        try:
            self.mcl.stereotypes = [self.mcl]
            exception_expected_()
        except CException as e:
            eq_("'MCL' is not a stereotype", e.value)

    def test_extended_wrong_type(self):
        try:
            cl = CClass(self.mcl)
            CStereotype("S1", extended=[cl])
            exception_expected_()
        except CException as e:
            eq_("unknown type of extend element: ''", e.value)

    def test_metaclass_stereotypes_null_input(self):
        s = CStereotype()
        m = CMetaclass(stereotypes=None)
        eq_(m.stereotypes, [])
        eq_(s.extended, [])

    def test_metaclass_stereotypes_non_list_input(self):
        s = CStereotype()
        m = CMetaclass(stereotypes=s)
        eq_(m.stereotypes, [s])
        eq_(s.extended, [m])

    def test_metaclass_stereotypes_non_list_input_wrong_type(self):
        try:
            CMetaclass(stereotypes=self.mcl)
            exception_expected_()
        except CException as e:
            eq_("a list or a stereotype is required as input", e.value)

    def test_metaclass_stereotypes_append(self):
        s1 = CStereotype()
        s2 = CStereotype()
        m = CMetaclass(stereotypes=[s1])
        # should have no effect, as setter must be used
        m.stereotypes.append(s2)
        eq_(m.stereotypes, [s1])
        eq_(s1.extended, [m])
        eq_(s2.extended, [])

    def test_stereotype_extended_null_input(self):
        m = CMetaclass()
        s = CStereotype(extended=None)
        eq_(m.stereotypes, [])
        eq_(s.extended, [])

    def test_stereotype_extended_non_list_input(self):
        m = CMetaclass()
        s = CStereotype(extended=m)
        eq_(m.stereotypes, [s])
        eq_(s.extended, [m])

    def test_stereotype_extended_non_list_input_wrong_type(self):
        try:
            CStereotype(extended=CClass(self.mcl))
            exception_expected_()
        except CException as e:
            eq_("extended requires a list or a metaclass as input", e.value)

    def test_stereotype_extended_append(self):
        m1 = CMetaclass()
        m2 = CMetaclass()
        s = CStereotype(extended=[m1])
        # should have no effect, as setter must be used
        s.extended.append(m2)
        eq_(m1.stereotypes, [s])
        eq_(m2.stereotypes, [])
        eq_(s.extended, [m1])

    def test_extended_metaclass_that_is_deleted(self):
        m1 = CMetaclass("M1")
        m1.delete()
        try:
            CStereotype(extended=[m1])
            exception_expected_()
        except CException as e:
            eq_(e.value, "cannot access named element that has been deleted")

    def test_extended_metaclass_that_are_none(self):
        try:
            CStereotype(extended=[None])
            exception_expected_()
        except CException as e:
            eq_(e.value, "unknown type of extend element: 'None'")
示例#20
0
This is a simple component metamodel. As it is used for explaining meta-modelling with stereotypes, it is
described in :ref:`meta_model_stereotypes`.

It provides a ``component`` meta-class with a generic ``component_type`` stereotype for extensions
with component types, as well as a ``connectors_relation`` meta-class association with a generic ``connector_type``
stereotype for extensions with connector types.

"""

from codeable_models import CMetaclass, CBundle, CStereotype

# Component and component type
component = CMetaclass("Component")
component_type = CStereotype("Component Type", extended=component)

# connector relation and connector type
connectors_relation = component.association(
    component, "connected to: [source] * -> [target] *")
# attribute description can be used for explaining e.g. how the type affects the connector or what parts are affected
connector_type = CStereotype("Connector Type",
                             extended=connectors_relation,
                             attributes={"description": str})

_all_elements = component.get_connected_elements(add_stereotypes=True) + \
                connector_type.get_connected_elements(add_stereotypes=True) + \
                component_type.get_connected_elements(add_stereotypes=True)
_all = CBundle("component_model_all", elements=_all_elements)

componentMetamodelViews = [_all, {}]
示例#21
0
class TestBundlesOfStereotypes:
    def setup(self):
        self.mcl = CMetaclass("MCL")
        self.b1 = CBundle("B1")
        self.b2 = CBundle("B2")
        self.m1 = CMetaclass("M1")
        self.m2 = CMetaclass("M2")
        self.a = self.m1.association(self.m2,
                                     name="A",
                                     multiplicity="1",
                                     role_name="m1",
                                     source_multiplicity="*",
                                     source_role_name="m2")

    def test_stereotype_name_fail(self):
        try:
            # noinspection PyTypeChecker
            CStereotype(self.b1)
            exception_expected_()
        except CException as e:
            ok_(e.value.startswith("is not a name string: '"))
            ok_(e.value.endswith(" B1'"))

    def test_stereotype_defined_bundles(self):
        eq_(set(self.b1.get_elements(type=CStereotype)), set())
        s1 = CStereotype("s1", bundles=self.b1)
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1})
        s2 = CStereotype("s2", bundles=[self.b1])
        s3 = CStereotype("s3", bundles=[self.b1, self.b2])
        cl = CClass(self.mcl, "C", bundles=self.b1)
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1, s2, s3})
        eq_(set(self.b1.elements), {s1, s2, s3, cl})
        eq_(set(self.b2.get_elements(type=CStereotype)), {s3})
        eq_(set(self.b2.elements), {s3})

    def test_bundle_defined_stereotype(self):
        s1 = CStereotype("s1")
        s2 = CStereotype("s2")
        s3 = CStereotype("s3")
        eq_(set(self.b1.get_elements(type=CStereotype)), set())
        b1 = CBundle("B1", elements=[s1, s2, s3])
        eq_(set(b1.elements), {s1, s2, s3})
        cl = CClass(self.mcl, "C", bundles=b1)
        eq_(set(b1.elements), {s1, s2, s3, cl})
        eq_(set(b1.get_elements(type=CStereotype)), {s1, s2, s3})
        b2 = CBundle("B2")
        b2.elements = [s2, s3]
        eq_(set(b2.get_elements(type=CStereotype)), {s2, s3})
        eq_(set(s1.bundles), {b1})
        eq_(set(s2.bundles), {b1, b2})
        eq_(set(s3.bundles), {b1, b2})

    def test_get_stereotypes_by_name(self):
        eq_(set(self.b1.get_elements(type=CStereotype, name="s1")), set())
        s1 = CStereotype("s1", bundles=self.b1)
        c1 = CClass(self.mcl, "C1", bundles=self.b1)
        eq_(self.b1.get_elements(type=CClass), [c1])
        eq_(set(self.b1.get_elements(type=CStereotype, name="s1")), {s1})
        s2 = CStereotype("s1", bundles=self.b1)
        eq_(set(self.b1.get_elements(type=CStereotype, name="s1")), {s1, s2})
        ok_(s1 != s2)
        s3 = CStereotype("s1", bundles=self.b1)
        eq_(set(self.b1.get_elements(type=CStereotype, name="s1")),
            {s1, s2, s3})
        eq_(self.b1.get_element(type=CStereotype, name="s1"), s1)

    def test_get_stereotype_elements_by_name(self):
        eq_(set(self.b1.get_elements(name="s1")), set())
        s1 = CStereotype("s1", bundles=self.b1)
        eq_(set(self.b1.get_elements(name="s1")), {s1})
        c1 = CClass(self.mcl, "s1", bundles=self.b1)
        eq_(set(self.b1.get_elements(name="s1")), {s1, c1})
        s2 = CStereotype("s1", bundles=self.b1)
        eq_(set(self.b1.get_elements(name="s1")), {s1, c1, s2})
        ok_(s1 != s2)
        s3 = CStereotype("s1", bundles=self.b1)
        eq_(set(self.b1.get_elements(name="s1")), {s1, c1, s2, s3})
        eq_(self.b1.get_element(name="s1"), s1)

    def test_stereotype_defined_bundle_change(self):
        s1 = CStereotype("s1", bundles=self.b1)
        s2 = CStereotype("s2", bundles=self.b1)
        s3 = CStereotype("s3", bundles=self.b1)
        cl1 = CClass(self.mcl, "C1", bundles=self.b1)
        cl2 = CClass(self.mcl, "C2", bundles=self.b1)
        b = CBundle()
        s2.bundles = b
        s3.bundles = None
        cl2.bundles = b
        eq_(set(self.b1.elements), {cl1, s1})
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1})
        eq_(set(b.elements), {s2, cl2})
        eq_(set(b.get_elements(type=CStereotype)), {s2})
        eq_(s1.bundles, [self.b1])
        eq_(s2.bundles, [b])
        eq_(s3.bundles, [])

    def test_bundle_delete_stereotype_metaclass(self):
        s1 = CStereotype("s1", bundles=self.b1, extended=self.mcl)
        eq_(s1.extended, [self.mcl])
        s2 = CStereotype("s2", bundles=self.b1)
        s3 = CStereotype("s3", bundles=self.b1)
        self.b1.delete()
        eq_(set(self.b1.elements), set())
        eq_(s1.bundles, [])
        eq_(s1.extended, [self.mcl])
        eq_(s2.bundles, [])
        eq_(s3.bundles, [])

    def test_bundle_delete_stereotype_association(self):
        s1 = CStereotype("s1", bundles=self.b1, extended=self.a)
        eq_(s1.extended, [self.a])
        s2 = CStereotype("s2", bundles=self.b1)
        s3 = CStereotype("s3", bundles=self.b1)
        self.b1.delete()
        eq_(set(self.b1.elements), set())
        eq_(s1.bundles, [])
        eq_(s1.extended, [self.a])
        eq_(s2.bundles, [])
        eq_(s3.bundles, [])

    def test_creation_of_unnamed_stereotype_in_bundle(self):
        cl = CClass(self.mcl)
        s1 = CStereotype()
        s2 = CStereotype()
        s3 = CStereotype("x")
        self.b1.elements = [s1, s2, s3, cl]
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1, s2, s3})
        eq_(self.b1.get_element(name=None), s1)
        eq_(set(self.b1.get_elements(type=CStereotype, name=None)), {s1, s2})
        eq_(self.b1.get_element(name=None), s1)
        eq_(set(self.b1.get_elements(name=None)), {s1, s2, cl})

    def test_remove_stereotype_from_bundle(self):
        b1 = CBundle("B1")
        b2 = CBundle("B2")
        s1 = CStereotype("s1", bundles=b1)
        try:
            # noinspection PyTypeChecker
            b1.remove(None)
            exception_expected_()
        except CException as e:
            eq_("'None' is not an element of the bundle", e.value)
        try:
            b1.remove(CEnum("A"))
            exception_expected_()
        except CException as e:
            eq_("'A' is not an element of the bundle", e.value)
        try:
            b2.remove(s1)
            exception_expected_()
        except CException as e:
            eq_("'s1' is not an element of the bundle", e.value)
        b1.remove(s1)
        eq_(set(b1.get_elements(type=CStereotype)), set())

        s1 = CStereotype("s1", bundles=b1)
        s2 = CStereotype("s1", bundles=b1)
        s3 = CStereotype("s1",
                         superclasses=s2,
                         attributes={"i": 1},
                         bundles=b1,
                         extended=self.mcl)
        s4 = CStereotype("s1",
                         superclasses=s2,
                         attributes={"i": 1},
                         bundles=b1,
                         extended=self.a)

        b1.remove(s1)
        try:
            b1.remove(CStereotype("s2", bundles=b2))
            exception_expected_()
        except CException as e:
            eq_("'s2' is not an element of the bundle", e.value)
        try:
            b1.remove(s1)
            exception_expected_()
        except CException as e:
            eq_("'s1' is not an element of the bundle", e.value)

        eq_(set(b1.get_elements(type=CStereotype)), {s2, s3, s4})
        b1.remove(s3)
        b1.remove(s4)
        eq_(set(b1.get_elements(type=CStereotype)), {s2})

        eq_(s3.superclasses, [s2])
        eq_(s2.subclasses, [s3, s4])
        eq_(s3.attribute_names, ["i"])
        eq_(s3.extended, [self.mcl])
        eq_(s3.name, "s1")
        eq_(s3.bundles, [])
        eq_(s4.superclasses, [s2])
        eq_(s4.attribute_names, ["i"])
        eq_(s4.extended, [self.a])
        eq_(s4.name, "s1")
        eq_(s4.bundles, [])

    def test_delete_stereotype_from_bundle(self):
        b1 = CBundle("B1")
        s1 = CStereotype("s1", bundles=b1)
        s1.delete()
        eq_(set(b1.get_elements(type=CStereotype)), set())

        s1 = CStereotype("s1", bundles=b1)
        s2 = CStereotype("s1", bundles=b1)
        s3 = CStereotype("s1",
                         superclasses=s2,
                         attributes={"i": 1},
                         bundles=b1,
                         extended=self.mcl)
        s4 = CStereotype("s1",
                         superclasses=s2,
                         attributes={"i": 1},
                         bundles=b1,
                         extended=self.a)

        s1.delete()
        eq_(set(b1.get_elements(type=CStereotype)), {s2, s3, s4})
        s3.delete()
        s4.delete()
        eq_(set(b1.get_elements(type=CStereotype)), {s2})

        eq_(s3.superclasses, [])
        eq_(s2.subclasses, [])
        eq_(s3.attributes, [])
        eq_(s3.attribute_names, [])
        eq_(s3.extended, [])
        eq_(s3.name, None)
        eq_(s3.bundles, [])

        eq_(s4.superclasses, [])
        eq_(s4.attributes, [])
        eq_(s4.attribute_names, [])
        eq_(s4.extended, [])
        eq_(s4.name, None)
        eq_(s4.bundles, [])

    def test_remove_bundle_from_two_bundles(self):
        b1 = CBundle("B1")
        b2 = CBundle("B2")
        s1 = CStereotype("s1", bundles=[b1, b2])
        b1.remove(s1)
        eq_(set(b1.get_elements(type=CStereotype)), set())
        eq_(set(b2.get_elements(type=CStereotype)), {s1})
        eq_(set(s1.bundles), {b2})

    def test_delete_bundle_from_two_bundles(self):
        b1 = CBundle("B1")
        b2 = CBundle("B2")
        s1 = CStereotype("s1", bundles=[b1, b2])
        b1.delete()
        eq_(set(b1.get_elements(type=CStereotype)), set())
        eq_(set(b2.get_elements(type=CStereotype)), {s1})
        eq_(set(s1.bundles), {b2})

    def test_delete_stereotype_having_two_bundles(self):
        b1 = CBundle("B1")
        b2 = CBundle("B2")
        s1 = CStereotype("s1", bundles=[b1, b2])
        s2 = CStereotype("s2", bundles=[b2])
        s1.delete()
        eq_(set(b1.get_elements(type=CStereotype)), set())
        eq_(set(b2.get_elements(type=CStereotype)), {s2})
        eq_(set(s1.bundles), set())
        eq_(set(s2.bundles), {b2})

    def test_stereotype_remove_stereotype_or_metaclass(self):
        mcl = CMetaclass("MCL1")
        s1 = CStereotype("S1", extended=[mcl])
        s2 = CStereotype("S2", extended=[mcl])
        s3 = CStereotype("S3", extended=[mcl])
        s4 = CStereotype("S4", extended=[mcl])
        self.b1.elements = [mcl, s1, s2, s3, s4]
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1, s2, s3, s4})
        s2.delete()
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1, s3, s4})
        eq_(set(s2.extended), set())
        eq_(set(s1.extended), {mcl})
        mcl.delete()
        eq_(set(mcl.stereotypes), set())
        eq_(set(s1.extended), set())
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1, s3, s4})

    def test_double_assignment_stereotype_extension_metaclass(self):
        try:
            CStereotype("S1", bundles=self.b1, extended=[self.mcl, self.mcl])
            exception_expected_()
        except CException as e:
            eq_("'MCL' is already extended by stereotype 'S1'", e.value)
        s1 = self.b1.get_element(type=CStereotype, name="S1")
        eq_(s1.name, "S1")
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1})
        eq_(s1.bundles, [self.b1])
        eq_(self.mcl.stereotypes, [s1])

    def test_double_assignment_stereotype_extension_association(self):
        try:
            CStereotype("S1", bundles=self.b1, extended=[self.a, self.a])
            exception_expected_()
        except CException as e:
            eq_("'A' is already extended by stereotype 'S1'", e.value)
        s1 = self.b1.get_element(type=CStereotype, name="S1")
        eq_(s1.name, "S1")
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1})
        eq_(s1.bundles, [self.b1])
        eq_(self.a.stereotypes, [s1])

    def test_double_assignment_metaclass_stereotype(self):
        try:
            s1 = CStereotype("S1", bundles=self.b1)
            self.mcl.stereotypes = [s1, s1]
            exception_expected_()
        except CException as e:
            eq_("'S1' is already a stereotype of 'MCL'", e.value)
        s1 = self.b1.get_element(type=CStereotype, name="S1")
        eq_(s1.name, "S1")
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1})

    def test_double_assignment_association_stereotype(self):
        try:
            s1 = CStereotype("S1", bundles=self.b1)
            self.a.stereotypes = [s1, s1]
            exception_expected_()
        except CException as e:
            eq_("'S1' is already a stereotype of 'A'", e.value)
        s1 = self.b1.get_element(type=CStereotype, name="S1")
        eq_(s1.name, "S1")
        eq_(set(self.b1.get_elements(type=CStereotype)), {s1})

    def test_bundle_that_is_deleted(self):
        b1 = CBundle("B1")
        b1.delete()
        try:
            CStereotype("S1", bundles=b1)
            exception_expected_()
        except CException as e:
            eq_(e.value, "cannot access named element that has been deleted")

    def test_set_bundle_to_none(self):
        s = CStereotype("S1", bundles=None)
        eq_(s.bundles, [])
        eq_(s.name, "S1")
示例#22
0
"""
*File Name:* metamodels/domain_metamodel.py

This is a simple domain class meta-model that del domain classes and groups of those (generic groups,
and-combined and or-combined groups).

"""

from codeable_models import CMetaclass, CBundle

domain_metaclass = CMetaclass("Domain Class")
domain_metaclass_group = CMetaclass("Domain Class Group",
                                    superclasses=domain_metaclass)
and_combined_group = CMetaclass("And-Combined Domain Class Group",
                                superclasses=domain_metaclass_group)
or_combined_group = CMetaclass("Or-Combined Domain Class Group",
                               superclasses=domain_metaclass_group)
domain_metaclass_group.association(domain_metaclass,
                                   "[collection] * <>- [class] *")

domain_metamodel = CBundle("Domain Meta Model",
                           elements=domain_metaclass.get_connected_elements())