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)
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, [])
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, {}]
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)
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")
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" )
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]})
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)
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})
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'")
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, {}]
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")
""" *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())