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_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_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_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_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_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_add_one_to_one_link(self): self.c1.association(self.c2, "l: 1 -> [target] 0..1") o1 = CObject(self.c1, "o1") o2 = CObject(self.c2, "o2") o3 = CObject(self.c2, "o3") eq_(o1.linked, []) add_links({o1: o3}) eq_(o1.linked, [o3]) eq_(o3.linked, [o1]) set_links({o1: []}, role_name="target") eq_(o1.linked, []) o1.add_links(o2) eq_(o1.linked, [o2]) eq_(o2.linked, [o1]) try: add_links({o1: o3}) exception_expected_() except CException as e: eq_( e.value, "links of object 'o1' have wrong multiplicity '2': should be '0..1'" ) eq_(o1.linked, [o2]) eq_(o2.linked, [o1]) eq_(o3.linked, [])
def test_delete_class(self): cl1 = CClass(self.mcl, "CL1") cl1.delete() eq_(set(self.mcl.classes), set()) cl1 = CClass(self.mcl, "CL1") cl2 = CClass(self.mcl, "CL2") cl3 = CClass(self.mcl, "CL3", superclasses=cl2, attributes={"i": 1}) cl3.set_value("i", 7) CObject(cl3) cl1.delete() eq_(set(self.mcl.classes), {cl2, cl3}) cl3.delete() eq_(set(self.mcl.classes), {cl2}) eq_(cl3.superclasses, []) eq_(cl2.subclasses, []) eq_(cl3.attributes, []) eq_(cl3.attribute_names, []) eq_(cl3.metaclass, None) eq_(cl3.objects, []) eq_(cl3.name, None) eq_(cl3.bundles, []) try: cl3.get_value("i") exception_expected_() except CException as e: eq_("can't get value 'i' on deleted 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_link_delete_association(self): a = self.c1.association(self.c2, name="l", source_multiplicity="*", multiplicity="*") o1 = CObject(self.c1, "o2") o2 = CObject(self.c2, "o2") o3 = CObject(self.c2, "o3") o4 = CObject(self.c1, "o4") set_links({o1: [o2, o3]}) set_links({o4: [o2]}) set_links({o1: [o2]}) set_links({o4: [o3, o2]}) a.delete() eq_(o1.linked, []) eq_(o2.linked, []) eq_(o3.linked, []) eq_(o4.linked, []) try: set_links({o1: [o2, o3]}) exception_expected_() except CException as e: eq_( e.value, "matching association not found for source 'o2' and targets '['o2', 'o3']'" )
def test_link_delete_object(self): self.c1.association(self.c2, name="l", source_multiplicity="*", multiplicity="*") o1 = CObject(self.c1, "o2") o2 = CObject(self.c2, "o2") o3 = CObject(self.c2, "o3") o4 = CObject(self.c1, "o4") add_links({o1: [o2, o3]}) add_links({o4: [o3, o2]}) o2.delete() eq_(o1.linked, [o3]) eq_(o3.linked, [o1, o4]) eq_(o4.linked, [o3]) try: add_links({o1: [o2]}) exception_expected_() except CException as e: eq_(e.value, "cannot link to deleted target") try: add_links({o2: [o1]}) exception_expected_() except CException as e: eq_(e.value, "cannot link to deleted source")
def test_link_association_ambiguous(self): self.c1.association(self.c2, name="a1", role_name="c2", multiplicity="*") self.c1.association(self.c2, name="a2", role_name="c2", multiplicity="*") o1 = CObject(self.c1, "o1") o2 = CObject(self.c2, "o2") try: set_links({o1: o2}) exception_expected_() except CException as e: eq_( e.value, "link specification ambiguous, multiple matching associations " + "found for source 'o1' and targets '['o2']'") try: set_links({o1: o2}, role_name="c2") exception_expected_() except CException as e: eq_( e.value, "link specification ambiguous, multiple matching associations " + "found for source 'o1' and targets '['o2']'")
def test_n_to_n_link(self): a = self.c1.association(self.c2, name="l", source_multiplicity="*") o1a = CObject(self.c1, "o1a") o1b = CObject(self.c1, "o1b") o1c = CObject(self.c1, "o1c") o2a = CObject(self.c2, "o2a") o2b = CObject(self.c2, "o2b") set_links({o1a: [o2a, o2b], o1b: [o2a], o1c: [o2b]}) eq_(o1a.linked, [o2a, o2b]) eq_(o1b.linked, [o2a]) eq_(o1c.linked, [o2b]) eq_(o2a.linked, [o1a, o1b]) eq_(o2b.linked, [o1a, o1c]) set_links({o2a: [o1a, o1b]}) try: set_links({o2b: []}) exception_expected_() except CException as e: eq_( e.value, "matching association not found for source 'o2b' and targets '[]'" ) set_links({o2b: []}, association=a) eq_(o1a.linked, [o2a]) eq_(o1b.linked, [o2a]) eq_(o1c.linked, []) eq_(o2a.linked, [o1a, o1b]) eq_(o2b.linked, [])
def test_wrong_types_set_links(self): self.c1.association(self.c2, name="l", multiplicity="1") o1 = CObject(self.c1, "o1") o2 = CObject(self.c2, "o2") try: set_links({o1: self.mcl}) exception_expected_() except CException as e: eq_(e.value, "link target 'MCL' is not an object, class, or link") try: set_links({o1: [o2, self.mcl]}) exception_expected_() except CException as e: eq_(e.value, "link target 'MCL' is not an object, class, or link") try: set_links({o1: [o2, 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: o2}) exception_expected_() except CException as e: eq_(e.value, "link source 'MCL' is not an object, class, or link") try: set_links({None: o2}) exception_expected_() except CException as e: eq_(e.value, "link should not contain an empty source")
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_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_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_object_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_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_apply_stereotype_instances_wrong_metaclass_inheritance(self): mcl1 = CMetaclass("MCL1", superclasses=self.mcl) mcl2 = CMetaclass("MCL2", superclasses=self.mcl) s1 = CStereotype("S1", extended=mcl1) s2 = CStereotype("S2", extended=mcl2) super_stereotype = CStereotype("SuperST", extended=self.mcl) c = CClass(self.mcl, "CL") try: c.stereotype_instances = s1 exception_expected_() except CException as e: eq_( e.value, "stereotype 'S1' cannot be added to 'CL': no extension by this stereotype found" ) c.stereotype_instances = super_stereotype mcl1_class = CClass(mcl1, "Mcl1Class", stereotype_instances=s1) try: mcl1_class.stereotype_instances = [s1, s2] exception_expected_() except CException as e: eq_( e.value, "stereotype 'S2' cannot be added to 'Mcl1Class': no extension by this stereotype found" ) mcl1_class.stereotype_instances = [s1, super_stereotype] eq_(set(mcl1_class.stereotype_instances), {s1, super_stereotype}) eq_(c.stereotype_instances, [super_stereotype])
def test_delete_class_from_bundle(self): b1 = CBundle("B1") cl1 = CClass(self.mcl, "CL1", bundles=b1) cl1.delete() eq_(set(b1.get_elements(type=CClass)), set()) cl1 = CClass(self.mcl, "CL1", bundles=b1) cl2 = CClass(self.mcl, "CL2", bundles=b1) cl3 = CClass(self.mcl, "CL3", superclasses=cl2, attributes={"i": 1}, bundles=b1) cl3.set_value("i", 7) CObject(cl3, bundles=b1) cl1.delete() eq_(set(b1.get_elements(type=CClass)), {cl2, cl3}) cl3.delete() eq_(set(b1.get_elements(type=CClass)), {cl2}) eq_(cl3.superclasses, []) eq_(cl2.subclasses, []) eq_(cl3.attributes, []) eq_(cl3.attribute_names, []) eq_(cl3.metaclass, None) eq_(cl3.objects, []) eq_(cl3.name, None) eq_(cl3.bundles, []) eq_(b1.get_elements(type=CObject), []) try: cl3.get_value("i") exception_expected_() except CException as e: eq_("can't get value 'i' on deleted class", e.value)
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 = CMetaclass("ASC") self.a_association.superclasses = [self.a, another_sc] exception_expected_() except CException as e: eq_( "cannot add superclass 'ASC': not a class or class 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 class or class association", e.value) another_sc = CClass(self.mcl, "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_stereotype_of_extended_instances(self): s1 = CStereotype("S1", extended=self.mcl) s1.delete() try: CClass(self.mcl, "C1", stereotype_instances=[s1]) exception_expected_() except CException as e: eq_(e.value, "cannot access named element that has been deleted")
def test_bundle_elements_that_are_deleted(self): c = CClass(self.mcl, "C") c.delete() try: CBundle("B1", elements=[c]) exception_expected_() except CException as e: eq_(e.value, "cannot access named element that has been deleted")
def test_class_name_fail(self): try: # noinspection PyTypeChecker CClass(self.mcl, self.mcl) exception_expected_() except CException as e: ok_(e.value.startswith("is not a name string: '")) ok_(e.value.endswith(" MCL'"))
def test_type_object_attribute_class_is_deleted_in_constructor(self): attribute_class = CClass(self.mcl, "AC") attribute_class.delete() try: CMetaclass("M", attributes={"ac": attribute_class}) exception_expected_() except CException as e: eq_(e.value, "cannot access named element that has been deleted")
def test_attribute_type_check(self, type_to_check, wrong_default): self.mcl.attributes = {"a": type_to_check} attr = self.mcl.get_attribute("a") try: attr.default = wrong_default exception_expected_() except CException as e: eq_(f"default value '{wrong_default!s}' incompatible with attribute's type '{type_to_check!s}'", e.value)
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_stereotypes_that_are_deleted(self): s1 = CStereotype("S1") s1.delete() try: CMetaclass(stereotypes=[s1]) exception_expected_() except CException as e: eq_(e.value, "cannot access named element that has been deleted")
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_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")