Esempio n. 1
0
    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, [])
Esempio n. 2
0
    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, [])
Esempio n. 3
0
    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")
Esempio n. 4
0
    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])
Esempio n. 5
0
 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'")
Esempio n. 6
0
    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])
Esempio n. 7
0
    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])
Esempio n. 8
0
    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'")
Esempio n. 9
0
 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")
Esempio n. 10
0
    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)
Esempio n. 11
0
 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")
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]})
    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)