$:.unshift File.join(File.dirname(__FILE__),"..","lib") require 'test/unit' require 'rgen/metamodel_builder' require 'rgen/array_extensions' require 'bigdecimal' class MetamodelBuilderTest < Test::Unit::TestCase module TestMetamodel extend RGen::MetamodelBuilder::ModuleExtension class SimpleClass < RGen::MetamodelBuilder::MMBase KindType = RGen::MetamodelBuilder::DataTypes::Enum.new([:simple, :extended]) has_attr 'name' # default is String has_attr 'stringWithDefault', String, :defaultValueLiteral => "xtest" has_attr 'integerWithDefault', Integer, :defaultValueLiteral => "123" has_attr 'longWithDefault', Long, :defaultValueLiteral => "1234567890" has_attr 'floatWithDefault', Float, :defaultValueLiteral => "0.123" has_attr 'boolWithDefault', Boolean, :defaultValueLiteral => "true" has_attr 'anything', Object has_attr 'allowed', RGen::MetamodelBuilder::DataTypes::Boolean has_attr 'kind', KindType has_attr 'kindWithDefault', KindType, :defaultValueLiteral => "extended" end class ManyAttrClass < RGen::MetamodelBuilder::MMBase has_many_attr 'literals', String has_many_attr 'bools', Boolean has_many_attr 'integers', Integer has_many_attr 'enums', RGen::MetamodelBuilder::DataTypes::Enum.new([:a, :b, :c]) has_many_attr 'limitTest', Integer, :upperBound => 2 end class ClassA < RGen::MetamodelBuilder::MMBase # metamodel accessors must work independent of the ==() method module ClassModule def ==(o) o.is_a?(ClassA) end end end class ClassB < RGen::MetamodelBuilder::MMBase end class ClassC < RGen::MetamodelBuilder::MMBase end class HasOneTestClass < RGen::MetamodelBuilder::MMBase has_one 'classA', ClassA has_one 'classB', ClassB end class HasManyTestClass < RGen::MetamodelBuilder::MMBase has_many 'classA', ClassA end class OneClass < RGen::MetamodelBuilder::MMBase end class ManyClass < RGen::MetamodelBuilder::MMBase end OneClass.one_to_many 'manyClasses', ManyClass, 'oneClass', :upperBound => 5 class AClassMM < RGen::MetamodelBuilder::MMBase end class BClassMM < RGen::MetamodelBuilder::MMBase end AClassMM.many_to_many 'bClasses', BClassMM, 'aClasses' module SomePackage extend RGen::MetamodelBuilder::ModuleExtension class ClassA < RGen::MetamodelBuilder::MMBase end module SubPackage extend RGen::MetamodelBuilder::ModuleExtension class ClassB < RGen::MetamodelBuilder::MMBase end end end class OneClass2 < RGen::MetamodelBuilder::MMBase end class ManyClass2 < RGen::MetamodelBuilder::MMBase end ManyClass2.many_to_one 'oneClass', OneClass2, 'manyClasses' class AClassOO < RGen::MetamodelBuilder::MMBase end class BClassOO < RGen::MetamodelBuilder::MMBase end AClassOO.one_to_one 'bClass', BClassOO, 'aClass' class SomeSuperClass < RGen::MetamodelBuilder::MMBase has_attr "name" has_many "classAs", ClassA end class SomeSubClass < SomeSuperClass has_attr "subname" has_many "classBs", ClassB end class OtherSubClass < SomeSuperClass has_attr "othersubname" has_many "classCs", ClassC end class SubSubClass < RGen::MetamodelBuilder::MMMultiple(SomeSubClass, OtherSubClass) has_attr "subsubname" end module AnnotatedModule extend RGen::MetamodelBuilder::ModuleExtension annotation "moduletag" => "modulevalue" class AnnotatedClass < RGen::MetamodelBuilder::MMBase annotation "sometag" => "somevalue", "othertag" => "othervalue" annotation :source => "rgen/test", :details => {"thirdtag" => "thirdvalue"} has_attr "boolAttr", Boolean do annotation "attrtag" => "attrval" annotation :source => "rgen/test2", :details => {"attrtag2" => "attrvalue2", "attrtag3" => "attrvalue3"} end has_many "others", AnnotatedClass do annotation "reftag" => "refval" annotation :source => "rgen/test3", :details => {"reftag2" => "refvalue2", "reftag3" => "refvalue3"} end many_to_many "m2m", AnnotatedClass, "m2mback" do annotation "m2mtag" => "m2mval" opposite_annotation "opposite_m2mtag" => "opposite_m2mval" end end end class AbstractClass < RGen::MetamodelBuilder::MMBase abstract end class ContainedClass < RGen::MetamodelBuilder::MMBase end class ContainerClass < RGen::MetamodelBuilder::MMBase contains_one_uni 'oneChildUni', ContainedClass contains_one_uni 'oneChildUni2', ContainedClass contains_one 'oneChild', ContainedClass, 'parentOne' contains_one 'oneChild2', ContainedClass, 'parentOne2' contains_many_uni 'manyChildUni', ContainedClass contains_many_uni 'manyChildUni2', ContainedClass contains_many 'manyChild', ContainedClass, 'parentMany' contains_many 'manyChild2', ContainedClass, 'parentMany2' end class NestedContainerClass < ContainedClass contains_one_uni 'oneChildUni', ContainedClass end class OppositeRefAssocA < RGen::MetamodelBuilder::MMBase end class OppositeRefAssocB < RGen::MetamodelBuilder::MMBase end OppositeRefAssocA.one_to_one 'bClass', OppositeRefAssocB, 'aClass' end def mm TestMetamodel end def test_has_attr sc = mm::SimpleClass.new assert_respond_to sc, :name assert_respond_to sc, :name= sc.name = "TestName" assert_equal "TestName", sc.name sc.name = nil assert_equal nil, sc.name err = assert_raise StandardError do sc.name = 5 end assert_match /In (\w+::)+SimpleClass : Can not use a Fixnum where a String is expected/, err.message assert_equal "EString", mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="name"}.eType.name assert_equal "xtest", sc.stringWithDefault assert_equal :extended, sc.kindWithDefault assert_equal 123, sc.integerWithDefault assert_equal 1234567890, sc.longWithDefault assert_equal 0.123, sc.floatWithDefault assert_equal true, sc.boolWithDefault # setting nil should not make the default value appear on next read sc.stringWithDefault = nil assert_nil sc.stringWithDefault sc.anything = :asymbol assert_equal :asymbol, sc.anything sc.anything = self # a class assert_equal self, sc.anything assert_respond_to sc, :allowed assert_respond_to sc, :allowed= sc.allowed = true assert_equal true, sc.allowed sc.allowed = false assert_equal false, sc.allowed sc.allowed = nil assert_equal nil, sc.allowed err = assert_raise StandardError do sc.allowed = :someSymbol end assert_match /In (\w+::)+SimpleClass : Can not use a Symbol\(:someSymbol\) where a \[true,false\] is expected/, err.message err = assert_raise StandardError do sc.allowed = "a string" end assert_match /In (\w+::)+SimpleClass : Can not use a String where a \[true,false\] is expected/, err.message assert_equal "EBoolean", mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="allowed"}.eType.name assert_respond_to sc, :kind assert_respond_to sc, :kind= sc.kind = :simple assert_equal :simple, sc.kind sc.kind = :extended assert_equal :extended, sc.kind sc.kind = nil assert_equal nil, sc.kind err = assert_raise StandardError do sc.kind = :false end assert_match /In (\w+::)+SimpleClass : Can not use a Symbol\(:false\) where a \[:simple,:extended\] is expected/, err.message err = assert_raise StandardError do sc.kind = "a string" end assert_match /In (\w+::)+SimpleClass : Can not use a String where a \[:simple,:extended\] is expected/, err.message enum = mm::SimpleClass.ecore.eAttributes.find{|a| a.name=="kind"}.eType assert_equal ["extended", "simple"], enum.eLiterals.name.sort end def test_float sc = mm::SimpleClass.new sc.floatWithDefault = 7.89 assert_equal 7.89, sc.floatWithDefault if BigDecimal.double_fig == 16 sc.floatWithDefault = 123456789012345678.0 # loss of precision assert_equal "123456789012345680.0", sprintf("%.1f", sc.floatWithDefault) end sc.floatWithDefault = nil sc.floatWithDefault = BigDecimal.new("123456789012345678.0") assert sc.floatWithDefault.is_a?(BigDecimal) assert_equal "123456789012345678.0", sc.floatWithDefault.to_s("F") dump = Marshal.dump(sc) sc2 = Marshal.load(dump) assert sc2.floatWithDefault.is_a?(BigDecimal) assert_equal "123456789012345678.0", sc2.floatWithDefault.to_s("F") end def test_long sc = mm::SimpleClass.new sc.longWithDefault = 5 assert_equal 5, sc.longWithDefault sc.longWithDefault = (2**(0.size * 8 -2) -1) + 1 assert_equal (2**(0.size * 8 -2) -1) + 1, sc.longWithDefault assert sc.longWithDefault.is_a?(Bignum) assert sc.longWithDefault.is_a?(Integer) err = assert_raise StandardError do sc.longWithDefault = "a string" end assert_match /In (\w+::)+SimpleClass : Can not use a String where a Integer is expected/, err.message end def test_many_attr o = mm::ManyAttrClass.new assert_respond_to o, :literals assert_respond_to o, :addLiterals assert_respond_to o, :removeLiterals err = assert_raise(StandardError) do o.addLiterals(1) end assert_match /In (\w+::)+ManyAttrClass : Can not use a Fixnum where a String is expected/, err.message assert_equal [], o.literals o.addLiterals("a") assert_equal ["a"], o.literals o.addLiterals("b") assert_equal ["a", "b"], o.literals o.addLiterals("b") assert_equal ["a", "b", "b"], o.literals # attributes allow the same object several times o.addLiterals(o.literals.first) assert_equal ["a", "b", "b", "a"], o.literals assert o.literals[0].object_id == o.literals[3].object_id # removing works by object identity, so providing a new string won't delete an existing one o.removeLiterals("a") assert_equal ["a", "b", "b", "a"], o.literals theA = o.literals.first # each remove command removes only one element: remove first "a" o.removeLiterals(theA) assert_equal ["b", "b", "a"], o.literals # remove second "a" (same object) o.removeLiterals(theA) assert_equal ["b", "b"], o.literals o.removeLiterals(o.literals.first) assert_equal ["b"], o.literals o.removeLiterals(o.literals.first) assert_equal [], o.literals # setting multiple elements at a time o.literals = ["a", "b", "c"] assert_equal ["a", "b", "c"], o.literals # can only take enumerables err = assert_raise(StandardError) do o.literals = 1 end assert_match /In (\w+::)+ManyAttrClass : Can not use a Fixnum where a Enumerable is expected/, err.message o.bools = [true, false, true, false] assert_equal [true, false, true, false], o.bools o.integers = [1, 2, 2, 3, 3] assert_equal [1, 2, 2, 3, 3], o.integers o.enums = [:a, :a, :b, :c, :c] assert_equal [:a, :a, :b, :c, :c], o.enums lit = mm::ManyAttrClass.ecore.eAttributes.find{|a| a.name == "literals"} assert lit.is_a?(RGen::ECore::EAttribute) assert lit.many lim = mm::ManyAttrClass.ecore.eAttributes.find{|a| a.name == "limitTest"} assert lit.many assert_equal 2, lim.upperBound end def test_many_attr_insert o = mm::ManyAttrClass.new o.addLiterals("a") o.addLiterals("b", 0) o.addLiterals("c", 1) assert_equal ["b", "c", "a"], o.literals end def test_has_one sc = mm::HasOneTestClass.new assert_respond_to sc, :classA assert_respond_to sc, :classA= ca = mm::ClassA.new sc.classA = ca assert_equal ca, sc.classA sc.classA = nil assert_equal nil, sc.classA assert_respond_to sc, :classB assert_respond_to sc, :classB= cb = mm::ClassB.new sc.classB = cb assert_equal cb, sc.classB err = assert_raise StandardError do sc.classB = ca end assert_match /In (\w+::)+HasOneTestClass : Can not use a (\w+::)+ClassA where a (\w+::)+ClassB is expected/, err.message assert_equal [], mm::ClassA.ecore.eReferences assert_equal [], mm::ClassB.ecore.eReferences assert_equal ["classA", "classB"].sort, mm::HasOneTestClass.ecore.eReferences.name.sort assert_equal [], mm::HasOneTestClass.ecore.eReferences.select { |a| a.many == true } assert_equal [], mm::HasOneTestClass.ecore.eAttributes end def test_has_many o = mm::HasManyTestClass.new ca1 = mm::ClassA.new ca2 = mm::ClassA.new ca3 = mm::ClassA.new o.addClassA(ca1) o.addClassA(ca2) assert_equal [ca1, ca2], o.classA # make sure we get a copy o.classA.clear assert_equal [ca1, ca2], o.classA o.removeClassA(ca3) assert_equal [ca1, ca2], o.classA o.removeClassA(ca2) assert_equal [ca1], o.classA err = assert_raise StandardError do o.addClassA(mm::ClassB.new) end assert_match /In (\w+::)+HasManyTestClass : Can not use a (\w+::)+ClassB where a (\w+::)+ClassA is expected/, err.message assert_equal [], mm::HasManyTestClass.ecore.eReferences.select{|r| r.many == false} assert_equal ["classA"], mm::HasManyTestClass.ecore.eReferences.select{|r| r.many == true}.name end def test_has_many_insert o = mm::HasManyTestClass.new ca1 = mm::ClassA.new ca2 = mm::ClassA.new ca3 = mm::ClassA.new ca4 = mm::ClassA.new ca5 = mm::ClassA.new o.addClassA(ca1) o.addClassA(ca2) o.addClassA(ca3,0) o.addClassA(ca4,1) o.addGeneric("classA",ca5,2) assert_equal [ca3, ca4, ca5, ca1, ca2], o.classA end def test_one_to_many oc = mm::OneClass.new assert_respond_to oc, :manyClasses assert oc.manyClasses.empty? mc = mm::ManyClass.new assert_respond_to mc, :oneClass assert_respond_to mc, :oneClass= assert_nil mc.oneClass # put the OneClass into the ManyClass mc.oneClass = oc assert_equal oc, mc.oneClass assert oc.manyClasses.include?(mc) # remove the OneClass from the ManyClass mc.oneClass = nil assert_equal nil, mc.oneClass assert !oc.manyClasses.include?(mc) # put the ManyClass into the OneClass oc.addManyClasses mc assert oc.manyClasses.include?(mc) assert_equal oc, mc.oneClass # remove the ManyClass from the OneClass oc.removeManyClasses mc assert !oc.manyClasses.include?(mc) assert_equal nil, mc.oneClass assert_equal [], mm::OneClass.ecore.eReferences.select{|r| r.many == false} assert_equal ["manyClasses"], mm::OneClass.ecore.eReferences.select{|r| r.many == true}.name assert_equal 5, mm::OneClass.ecore.eReferences.find{|r| r.many == true}.upperBound assert_equal ["oneClass"], mm::ManyClass.ecore.eReferences.select{|r| r.many == false}.name assert_equal [], mm::ManyClass.ecore.eReferences.select{|r| r.many == true} end def test_one_to_many_replace1 oc1 = mm::OneClass.new oc2 = mm::OneClass.new mc = mm::ManyClass.new oc1.manyClasses = [mc] assert_equal [mc], oc1.manyClasses assert_equal [], oc2.manyClasses assert_equal oc1, mc.oneClass oc2.manyClasses = [mc] assert_equal [mc], oc2.manyClasses assert_equal [], oc1.manyClasses assert_equal oc2, mc.oneClass end def test_one_to_many_replace2 oc = mm::OneClass.new mc1 = mm::ManyClass.new mc2 = mm::ManyClass.new mc1.oneClass = oc assert_equal [mc1], oc.manyClasses assert_equal oc, mc1.oneClass assert_equal nil, mc2.oneClass mc2.oneClass = oc assert_equal [mc1, mc2], oc.manyClasses assert_equal oc, mc1.oneClass assert_equal oc, mc2.oneClass end def test_one_to_many_insert oc = mm::OneClass.new mc1 = mm::ManyClass.new mc2 = mm::ManyClass.new oc.addManyClasses(mc1, 0) oc.addManyClasses(mc2, 0) assert_equal [mc2, mc1], oc.manyClasses assert_equal oc, mc1.oneClass assert_equal oc, mc2.oneClass end def test_one_to_many2 oc = mm::OneClass2.new assert_respond_to oc, :manyClasses assert oc.manyClasses.empty? mc = mm::ManyClass2.new assert_respond_to mc, :oneClass assert_respond_to mc, :oneClass= assert_nil mc.oneClass # put the OneClass into the ManyClass mc.oneClass = oc assert_equal oc, mc.oneClass assert oc.manyClasses.include?(mc) # remove the OneClass from the ManyClass mc.oneClass = nil assert_equal nil, mc.oneClass assert !oc.manyClasses.include?(mc) # put the ManyClass into the OneClass oc.addManyClasses mc assert oc.manyClasses.include?(mc) assert_equal oc, mc.oneClass # remove the ManyClass from the OneClass oc.removeManyClasses mc assert !oc.manyClasses.include?(mc) assert_equal nil, mc.oneClass assert_equal [], mm::OneClass2.ecore.eReferences.select{|r| r.many == false} assert_equal ["manyClasses"], mm::OneClass2.ecore.eReferences.select{|r| r.many == true}.name assert_equal ["oneClass"], mm::ManyClass2.ecore.eReferences.select{|r| r.many == false}.name assert_equal [], mm::ManyClass2.ecore.eReferences.select{|r| r.many == true} end def test_one_to_one ac = mm::AClassOO.new assert_respond_to ac, :bClass assert_respond_to ac, :bClass= assert_nil ac.bClass bc = mm::BClassOO.new assert_respond_to bc, :aClass assert_respond_to bc, :aClass= assert_nil bc.aClass # put the AClass into the BClass bc.aClass = ac assert_equal ac, bc.aClass assert_equal bc, ac.bClass # remove the AClass from the BClass bc.aClass = nil assert_equal nil, bc.aClass assert_equal nil, ac.bClass # put the BClass into the AClass ac.bClass = bc assert_equal bc, ac.bClass assert_equal ac, bc.aClass # remove the BClass from the AClass ac.bClass = nil assert_equal nil, ac.bClass assert_equal nil, bc.aClass assert_equal ["bClass"], mm::AClassOO.ecore.eReferences.select{|r| r.many == false}.name assert_equal [], mm::AClassOO.ecore.eReferences.select{|r| r.many == true} assert_equal ["aClass"], mm::BClassOO.ecore.eReferences.select{|r| r.many == false}.name assert_equal [], mm::BClassOO.ecore.eReferences.select{|r| r.many == true} end def test_one_to_one_replace a = mm::AClassOO.new b1 = mm::BClassOO.new b2 = mm::BClassOO.new a.bClass = b1 assert_equal b1, a.bClass assert_equal a, b1.aClass assert_equal nil, b2.aClass a.bClass = b2 assert_equal b2, a.bClass assert_equal nil, b1.aClass assert_equal a, b2.aClass end def test_many_to_many ac = mm::AClassMM.new assert_respond_to ac, :bClasses assert ac.bClasses.empty? bc = mm::BClassMM.new assert_respond_to bc, :aClasses assert bc.aClasses.empty? # put the AClass into the BClass bc.addAClasses ac assert bc.aClasses.include?(ac) assert ac.bClasses.include?(bc) # put something else into the BClass err = assert_raise StandardError do bc.addAClasses :notaaclass end assert_match /In (\w+::)+BClassMM : Can not use a Symbol\(:notaaclass\) where a (\w+::)+AClassMM is expected/, err.message # remove the AClass from the BClass bc.removeAClasses ac assert !bc.aClasses.include?(ac) assert !ac.bClasses.include?(bc) # put the BClass into the AClass ac.addBClasses bc assert ac.bClasses.include?(bc) assert bc.aClasses.include?(ac) # put something else into the AClass err = assert_raise StandardError do ac.addBClasses :notabclass end assert_match /In (\w+::)+AClassMM : Can not use a Symbol\(:notabclass\) where a (\w+::)+BClassMM is expected/, err.message # remove the BClass from the AClass ac.removeBClasses bc assert !ac.bClasses.include?(bc) assert !bc.aClasses.include?(ac) assert_equal [], mm::AClassMM.ecore.eReferences.select{|r| r.many == false} assert_equal ["bClasses"], mm::AClassMM.ecore.eReferences.select{|r| r.many == true}.name assert_equal [], mm::BClassMM.ecore.eReferences.select{|r| r.many == false} assert_equal ["aClasses"], mm::BClassMM.ecore.eReferences.select{|r| r.many == true}.name end def test_many_to_many_insert ac1 = mm::AClassMM.new ac2 = mm::AClassMM.new bc1= mm::BClassMM.new bc2= mm::BClassMM.new ac1.addBClasses(bc1) ac1.addBClasses(bc2, 0) ac2.addBClasses(bc1) ac2.addBClasses(bc2, 0) assert_equal [bc2, bc1], ac1.bClasses assert_equal [bc2, bc1], ac2.bClasses assert_equal [ac1, ac2], bc1.aClasses assert_equal [ac1, ac2], bc2.aClasses end def test_inheritance assert_equal ["name"], mm::SomeSuperClass.ecore.eAllAttributes.name assert_equal ["classAs"], mm::SomeSuperClass.ecore.eAllReferences.name assert_equal ["name", "subname"], mm::SomeSubClass.ecore.eAllAttributes.name.sort assert_equal ["classAs", "classBs"], mm::SomeSubClass.ecore.eAllReferences.name.sort assert_equal ["name", "othersubname"], mm::OtherSubClass.ecore.eAllAttributes.name.sort assert_equal ["classAs", "classCs"], mm::OtherSubClass.ecore.eAllReferences.name.sort assert mm::SomeSubClass.new.is_a?(mm::SomeSuperClass) assert_equal ["name", "othersubname", "subname", "subsubname"], mm::SubSubClass.ecore.eAllAttributes.name.sort assert_equal ["classAs", "classBs", "classCs"], mm::SubSubClass.ecore.eAllReferences.name.sort assert mm::SubSubClass.new.is_a?(mm::SomeSuperClass) assert mm::SubSubClass.new.is_a?(mm::SomeSubClass) assert mm::SubSubClass.new.is_a?(mm::OtherSubClass) end def test_annotations assert_equal 1, mm::AnnotatedModule.ecore.eAnnotations.size anno = mm::AnnotatedModule.ecore.eAnnotations.first checkAnnotation(anno, nil, {"moduletag" => "modulevalue"}) eClass = mm::AnnotatedModule::AnnotatedClass.ecore assert_equal 2, eClass.eAnnotations.size anno = eClass.eAnnotations.find{|a| a.source == "rgen/test"} checkAnnotation(anno, "rgen/test", {"thirdtag" => "thirdvalue"}) anno = eClass.eAnnotations.find{|a| a.source == nil} checkAnnotation(anno, nil, {"sometag" => "somevalue", "othertag" => "othervalue"}) eAttr = eClass.eAttributes.first assert_equal 2, eAttr.eAnnotations.size anno = eAttr.eAnnotations.find{|a| a.source == "rgen/test2"} checkAnnotation(anno, "rgen/test2", {"attrtag2" => "attrvalue2", "attrtag3" => "attrvalue3"}) anno = eAttr.eAnnotations.find{|a| a.source == nil} checkAnnotation(anno, nil, {"attrtag" => "attrval"}) eRef = eClass.eReferences.find{|r| !r.eOpposite} assert_equal 2, eRef.eAnnotations.size anno = eRef.eAnnotations.find{|a| a.source == "rgen/test3"} checkAnnotation(anno, "rgen/test3", {"reftag2" => "refvalue2", "reftag3" => "refvalue3"}) anno = eRef.eAnnotations.find{|a| a.source == nil} checkAnnotation(anno, nil, {"reftag" => "refval"}) eRef = eClass.eReferences.find{|r| r.eOpposite} assert_equal 1, eRef.eAnnotations.size anno = eRef.eAnnotations.first checkAnnotation(anno, nil, {"m2mtag" => "m2mval"}) eRef = eRef.eOpposite assert_equal 1, eRef.eAnnotations.size anno = eRef.eAnnotations.first checkAnnotation(anno, nil, {"opposite_m2mtag" => "opposite_m2mval"}) end def checkAnnotation(anno, source, hash) assert anno.is_a?(RGen::ECore::EAnnotation) assert_equal source, anno.source assert_equal hash.size, anno.details.size hash.each_pair do |k, v| detail = anno.details.find{|d| d.key == k} assert detail.is_a?(RGen::ECore::EStringToStringMapEntry) assert_equal v, detail.value end end def test_ecore_identity subPackage = mm::SomePackage::SubPackage.ecore assert_equal subPackage.eClassifiers.first.object_id, mm::SomePackage::SubPackage::ClassB.ecore.object_id somePackage = mm::SomePackage.ecore assert_equal somePackage.eSubpackages.first.object_id, subPackage.object_id end def test_proxy p = RGen::MetamodelBuilder::MMProxy.new("test") assert_equal "test", p.targetIdentifier p.targetIdentifier = 123 assert_equal 123, p.targetIdentifier p.data = "additional info" assert_equal "additional info", p.data q = RGen::MetamodelBuilder::MMProxy.new("ident", "data") assert_equal "data", q.data end def test_proxies_has_one e = mm::HasOneTestClass.new proxy = RGen::MetamodelBuilder::MMProxy.new e.classA = proxy assert_equal proxy, e.classA a = mm::ClassA.new # displace proxy e.classA = a assert_equal a, e.classA # displace by proxy e.classA = proxy assert_equal proxy, e.classA end def test_proxies_has_many e = mm::HasManyTestClass.new proxy = RGen::MetamodelBuilder::MMProxy.new e.addClassA(proxy) assert_equal [proxy], e.classA # again e.addClassA(proxy) assert_equal [proxy], e.classA proxy2 = RGen::MetamodelBuilder::MMProxy.new e.addClassA(proxy2) assert_equal [proxy, proxy2], e.classA e.removeClassA(proxy) assert_equal [proxy2], e.classA # again e.removeClassA(proxy) assert_equal [proxy2], e.classA e.removeClassA(proxy2) assert_equal [], e.classA end def test_proxies_one_to_one ea = mm::AClassOO.new eb = mm::BClassOO.new proxy1 = RGen::MetamodelBuilder::MMProxy.new proxy2 = RGen::MetamodelBuilder::MMProxy.new ea.bClass = proxy1 eb.aClass = proxy2 assert_equal proxy1, ea.bClass assert_equal proxy2, eb.aClass # displace proxies ea.bClass = eb assert_equal eb, ea.bClass assert_equal ea, eb.aClass # displace by proxy ea.bClass = proxy1 assert_equal proxy1, ea.bClass assert_nil eb.aClass end def test_proxies_one_to_many eo = mm::OneClass.new em = mm::ManyClass.new proxy1 = RGen::MetamodelBuilder::MMProxy.new proxy2 = RGen::MetamodelBuilder::MMProxy.new eo.addManyClasses(proxy1) assert_equal [proxy1], eo.manyClasses em.oneClass = proxy2 assert_equal proxy2, em.oneClass # displace proxies at many side # adding em will set em.oneClass to eo and displace the proxy from em.oneClass eo.addManyClasses(em) assert_equal [proxy1, em], eo.manyClasses assert_equal eo, em.oneClass eo.removeManyClasses(proxy1) assert_equal [em], eo.manyClasses assert_equal eo, em.oneClass # displace by proxy em.oneClass = proxy2 assert_equal [], eo.manyClasses assert_equal proxy2, em.oneClass # displace proxies at one side em.oneClass = eo assert_equal [em], eo.manyClasses assert_equal eo, em.oneClass end def test_proxies_many_to_many e1 = mm::AClassMM.new e2 = mm::BClassMM.new proxy1 = RGen::MetamodelBuilder::MMProxy.new proxy2 = RGen::MetamodelBuilder::MMProxy.new e1.addBClasses(proxy1) e2.addAClasses(proxy2) assert_equal [proxy1], e1.bClasses assert_equal [proxy2], e2.aClasses e1.addBClasses(e2) assert_equal [proxy1, e2], e1.bClasses assert_equal [proxy2, e1], e2.aClasses e1.removeBClasses(proxy1) e2.removeAClasses(proxy2) assert_equal [e2], e1.bClasses assert_equal [e1], e2.aClasses end # Multiplicity agnostic convenience methods def test_genericAccess e1 = mm::OneClass.new e2 = mm::ManyClass.new e3 = mm::OneClass.new e4 = mm::ManyClass.new # use on "many" feature e1.setOrAddGeneric("manyClasses", e2) assert_equal [e2], e1.manyClasses assert_equal [e2], e1.getGeneric("manyClasses") assert_equal [e2], e1.getGenericAsArray("manyClasses") # use on "one" feature e2.setOrAddGeneric("oneClass", e3) assert_equal e3, e2.oneClass assert_equal e3, e2.getGeneric("oneClass") assert_equal [e3], e2.getGenericAsArray("oneClass") assert_nil e4.getGeneric("oneClass") assert_equal [], e4.getGenericAsArray("oneClass") end def test_setNilOrRemoveGeneric e1 = mm::OneClass.new e2 = mm::ManyClass.new e3 = mm::OneClass.new # use on "many" feature e1.addManyClasses(e2) assert_equal [e2], e1.manyClasses e1.setNilOrRemoveGeneric("manyClasses", e2) assert_equal [], e1.manyClasses # use on "one" feature e2.oneClass = e3 assert_equal e3, e2.oneClass e2.setNilOrRemoveGeneric("oneClass", e3) assert_nil e2.oneClass end def test_setNilOrRemoveAllGeneric e1 = mm::OneClass.new e2 = mm::ManyClass.new e3 = mm::OneClass.new e4 = mm::ManyClass.new # use on "many" feature e1.addManyClasses(e2) e1.addManyClasses(e4) assert_equal [e2, e4], e1.manyClasses e1.setNilOrRemoveAllGeneric("manyClasses") assert_equal [], e1.manyClasses # use on "one" feature e2.oneClass = e3 assert_equal e3, e2.oneClass e2.setNilOrRemoveAllGeneric("oneClass") assert_nil e2.oneClass end def test_abstract err = assert_raise StandardError do mm::AbstractClass.new end assert_match /Class (\w+::)+AbstractClass is abstract/, err.message end module BadDefaultValueLiteralContainer Test1 = proc do class BadClass < RGen::MetamodelBuilder::MMBase has_attr 'integerWithDefault', Integer, :defaultValueLiteral => "1.1" end end Test2 = proc do class BadClass < RGen::MetamodelBuilder::MMBase has_attr 'integerWithDefault', Integer, :defaultValueLiteral => "x" end end Test3 = proc do class BadClass < RGen::MetamodelBuilder::MMBase has_attr 'boolWithDefault', Boolean, :defaultValueLiteral => "1" end end Test4 = proc do class BadClass < RGen::MetamodelBuilder::MMBase has_attr 'floatWithDefault', Float, :defaultValueLiteral => "1" end end Test5 = proc do class BadClass < RGen::MetamodelBuilder::MMBase has_attr 'floatWithDefault', Float, :defaultValueLiteral => "true" end end Test6 = proc do class BadClass < RGen::MetamodelBuilder::MMBase kindType = RGen::MetamodelBuilder::DataTypes::Enum.new([:simple, :extended]) has_attr 'enumWithDefault', kindType, :defaultValueLiteral => "xxx" end end Test7 = proc do class BadClass < RGen::MetamodelBuilder::MMBase kindType = RGen::MetamodelBuilder::DataTypes::Enum.new([:simple, :extended]) has_attr 'enumWithDefault', kindType, :defaultValueLiteral => "7" end end Test8 = proc do class BadClass < RGen::MetamodelBuilder::MMBase has_attr 'longWithDefault', Integer, :defaultValueLiteral => "1.1" end end end def test_bad_default_value_literal err = assert_raise StandardError do BadDefaultValueLiteralContainer::Test1.call end assert_equal "Property integerWithDefault can not take value 1.1, expected an Integer", err.message err = assert_raise StandardError do BadDefaultValueLiteralContainer::Test2.call end assert_equal "Property integerWithDefault can not take value x, expected an Integer", err.message err = assert_raise StandardError do BadDefaultValueLiteralContainer::Test3.call end assert_equal "Property boolWithDefault can not take value 1, expected true or false", err.message err = assert_raise StandardError do BadDefaultValueLiteralContainer::Test4.call end assert_equal "Property floatWithDefault can not take value 1, expected a Float", err.message err = assert_raise StandardError do BadDefaultValueLiteralContainer::Test5.call end assert_equal "Property floatWithDefault can not take value true, expected a Float", err.message err = assert_raise StandardError do BadDefaultValueLiteralContainer::Test6.call end assert_equal "Property enumWithDefault can not take value xxx, expected one of :simple, :extended", err.message err = assert_raise StandardError do BadDefaultValueLiteralContainer::Test7.call end assert_equal "Property enumWithDefault can not take value 7, expected one of :simple, :extended", err.message err = assert_raise StandardError do BadDefaultValueLiteralContainer::Test8.call end assert_equal "Property longWithDefault can not take value 1.1, expected an Integer", err.message end def test_isset_set_to_nil e = mm::SimpleClass.new assert_respond_to e, :name assert !e.eIsSet(:name) assert !e.eIsSet("name") e.name = nil assert e.eIsSet(:name) end def test_isset_set_to_default e = mm::SimpleClass.new assert !e.eIsSet(:stringWithDefault) # set the default value e.name = "xtest" assert e.eIsSet(:name) end def test_isset_many_add e = mm::ManyAttrClass.new assert_equal [], e.literals assert !e.eIsSet(:literals) e.addLiterals("x") assert e.eIsSet(:literals) end def test_isset_many_remove e = mm::ManyAttrClass.new assert_equal [], e.literals assert !e.eIsSet(:literals) # removing a value which is not there e.removeLiterals("x") assert e.eIsSet(:literals) end def test_isset_ref ac = mm::AClassOO.new bc = mm::BClassOO.new assert !bc.eIsSet(:aClass) assert !ac.eIsSet(:bClass) bc.aClass = ac assert bc.eIsSet(:aClass) assert ac.eIsSet(:bClass) end def test_isset_ref_many ac = mm::AClassMM.new bc = mm::BClassMM.new assert !bc.eIsSet(:aClasses) assert !ac.eIsSet(:bClasses) bc.aClasses = [ac] assert bc.eIsSet(:aClasses) assert ac.eIsSet(:bClasses) end def test_unset_nil e = mm::SimpleClass.new e.name = nil assert e.eIsSet(:name) e.eUnset(:name) assert !e.eIsSet(:name) end def test_unset_string e = mm::SimpleClass.new e.name = "someone" assert e.eIsSet(:name) e.eUnset(:name) assert !e.eIsSet(:name) end def test_unset_ref ac = mm::AClassOO.new bc = mm::BClassOO.new bc.aClass = ac assert bc.eIsSet(:aClass) assert ac.eIsSet(:bClass) assert_equal bc, ac.bClass bc.eUnset(:aClass) assert_nil bc.aClass assert_nil ac.bClass assert !bc.eIsSet(:aClass) # opposite ref is nil but still "set" assert ac.eIsSet(:bClass) end def test_unset_ref_many ac = mm::AClassMM.new bc = mm::BClassMM.new bc.aClasses = [ac] assert bc.eIsSet(:aClasses) assert ac.eIsSet(:bClasses) assert_equal [bc], ac.bClasses bc.eUnset(:aClasses) assert_equal [], bc.aClasses assert_equal [], ac.bClasses assert !bc.eIsSet(:aClasses) # opposite ref is empty but still "set" assert ac.eIsSet(:bClasses) end def test_unset_marshal e = mm::SimpleClass.new e.name = "someone" e.eUnset(:name) e2 = Marshal.load(Marshal.dump(e)) assert e.object_id != e2.object_id assert !e2.eIsSet(:name) end def test_conainer_one_uni a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainedClass.new assert_equal [], a.eContents assert_equal [], a.eAllContents assert_nil b.eContainer assert_nil b.eContainingFeature a.oneChildUni = b assert_equal a, b.eContainer assert_equal :oneChildUni, b.eContainingFeature assert_equal [b], a.eContents assert_equal [b], a.eAllContents a.oneChildUni = c assert_nil b.eContainer assert_nil b.eContainingFeature assert_equal a, c.eContainer assert_equal :oneChildUni, c.eContainingFeature assert_equal [c], a.eContents assert_equal [c], a.eAllContents a.oneChildUni = nil assert_nil c.eContainer assert_nil c.eContainingFeature assert_equal [], a.eContents assert_equal [], a.eAllContents end def test_container_many_uni a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainedClass.new assert_equal [], a.eContents assert_equal [], a.eAllContents a.addManyChildUni(b) assert_equal a, b.eContainer assert_equal :manyChildUni, b.eContainingFeature assert_equal [b], a.eContents assert_equal [b], a.eAllContents a.addManyChildUni(c) assert_equal a, c.eContainer assert_equal :manyChildUni, c.eContainingFeature assert_equal [b, c], a.eContents assert_equal [b, c], a.eAllContents a.removeManyChildUni(b) assert_nil b.eContainer assert_nil b.eContainingFeature assert_equal a, c.eContainer assert_equal :manyChildUni, c.eContainingFeature assert_equal [c], a.eContents assert_equal [c], a.eAllContents a.removeManyChildUni(c) assert_nil c.eContainer assert_nil c.eContainingFeature assert_equal [], a.eContents assert_equal [], a.eAllContents end def test_conainer_one_bi a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainerClass.new d = mm::ContainedClass.new a.oneChild = b assert_equal a, b.eContainer assert_equal :oneChild, b.eContainingFeature assert_equal [b], a.eContents assert_equal [b], a.eAllContents c.oneChild = d assert_equal c, d.eContainer assert_equal :oneChild, d.eContainingFeature assert_equal [d], c.eContents assert_equal [d], c.eAllContents a.oneChild = d assert_nil b.eContainer assert_nil b.eContainingFeature assert_equal a, d.eContainer assert_equal :oneChild, d.eContainingFeature assert_equal [d], a.eContents assert_equal [d], a.eAllContents assert_equal [], c.eContents assert_equal [], c.eAllContents end def test_conainer_one_bi_rev a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainerClass.new d = mm::ContainedClass.new a.oneChild = b assert_equal a, b.eContainer assert_equal :oneChild, b.eContainingFeature assert_equal [b], a.eContents assert_equal [b], a.eAllContents c.oneChild = d assert_equal c, d.eContainer assert_equal :oneChild, d.eContainingFeature assert_equal [d], c.eContents assert_equal [d], c.eAllContents d.parentOne = a assert_nil b.eContainer assert_nil b.eContainingFeature assert_equal a, d.eContainer assert_equal :oneChild, d.eContainingFeature assert_equal [d], a.eContents assert_equal [d], a.eAllContents assert_equal [], c.eContents assert_equal [], c.eAllContents end def test_conainer_one_bi_nil a = mm::ContainerClass.new b = mm::ContainedClass.new a.oneChild = b assert_equal a, b.eContainer assert_equal :oneChild, b.eContainingFeature assert_equal [b], a.eContents assert_equal [b], a.eAllContents a.oneChild = nil assert_nil b.eContainer assert_nil b.eContainingFeature assert_equal [], a.eContents assert_equal [], a.eAllContents end def test_conainer_one_bi_nil_rev a = mm::ContainerClass.new b = mm::ContainedClass.new a.oneChild = b assert_equal a, b.eContainer assert_equal :oneChild, b.eContainingFeature assert_equal [b], a.eContents assert_equal [b], a.eAllContents b.parentOne = nil assert_nil b.eContainer assert_nil b.eContainingFeature assert_equal [], a.eContents assert_equal [], a.eAllContents end def test_container_many_bi a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainedClass.new a.addManyChild(b) a.addManyChild(c) assert_equal a, b.eContainer assert_equal :manyChild, b.eContainingFeature assert_equal a, c.eContainer assert_equal :manyChild, c.eContainingFeature assert_equal [b, c], a.eContents assert_equal [b, c], a.eAllContents a.removeManyChild(b) assert_nil b.eContainer assert_nil b.eContainingFeature assert_equal [c], a.eContents assert_equal [c], a.eAllContents end def test_conainer_many_bi_steal a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainedClass.new d = mm::ContainerClass.new a.addManyChild(b) a.addManyChild(c) assert_equal a, b.eContainer assert_equal :manyChild, b.eContainingFeature assert_equal a, c.eContainer assert_equal :manyChild, c.eContainingFeature assert_equal [b, c], a.eContents assert_equal [b, c], a.eAllContents d.addManyChild(b) assert_equal d, b.eContainer assert_equal :manyChild, b.eContainingFeature assert_equal [c], a.eContents assert_equal [c], a.eAllContents assert_equal [b], d.eContents assert_equal [b], d.eAllContents end def test_conainer_many_bi_steal_rev a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainedClass.new d = mm::ContainerClass.new a.addManyChild(b) a.addManyChild(c) assert_equal a, b.eContainer assert_equal :manyChild, b.eContainingFeature assert_equal a, c.eContainer assert_equal :manyChild, c.eContainingFeature assert_equal [b, c], a.eContents assert_equal [b, c], a.eAllContents b.parentMany = d assert_equal d, b.eContainer assert_equal :manyChild, b.eContainingFeature assert_equal [c], a.eContents assert_equal [c], a.eAllContents assert_equal [b], d.eContents assert_equal [b], d.eAllContents end def test_all_contents a = mm::ContainerClass.new b = mm::NestedContainerClass.new c = mm::ContainedClass.new a.oneChildUni = b b.oneChildUni = c assert_equal [b, c], a.eAllContents end def test_all_contents_with_block a = mm::ContainerClass.new b = mm::NestedContainerClass.new c = mm::ContainedClass.new a.oneChildUni = b b.oneChildUni = c yielded = [] a.eAllContents do |e| yielded << e end assert_equal [b, c], yielded end def test_all_contents_prune a = mm::ContainerClass.new b = mm::NestedContainerClass.new c = mm::ContainedClass.new a.oneChildUni = b b.oneChildUni = c yielded = [] a.eAllContents do |e| yielded << e :prune end assert_equal [b], yielded end def test_container_generic a = mm::ContainerClass.new assert_nothing_raised do a.oneChild = RGen::MetamodelBuilder::MMGeneric.new end end def test_opposite_assoc_on_first_write ac = mm::OppositeRefAssocA.new bc = mm::OppositeRefAssocB.new # no access to 'aClass' or 'bClass' methods before # test if on-demand metamodel building creates opposite ref association on first write bc.aClass = ac assert_equal ac, bc.aClass assert_equal bc, ac.bClass end def test_clear_by_array_assignment oc1 = mm::OneClass.new mc1 = mm::ManyClass.new mc2 = mm::ManyClass.new mc3 = mm::ManyClass.new oc1.manyClasses = [mc1, mc2] assert_equal [mc1, mc2], oc1.manyClasses oc1.manyClasses = [] assert_equal [], oc1.manyClasses end def test_clear_by_array_assignment_uni a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainedClass.new a.manyChildUni = [b, c] assert_equal [b, c], a.manyChildUni a.manyChildUni = [] assert_equal [], a.manyChildUni end def test_disconnectContainer_one_uni a = mm::ContainerClass.new b = mm::ContainedClass.new a.oneChildUni = b b.disconnectContainer assert_nil a.oneChildUni end def test_disconnectContainer_one a = mm::ContainerClass.new b = mm::ContainedClass.new a.oneChild = b b.disconnectContainer assert_nil a.oneChild assert_nil b.parentOne end def test_disconnectContainer_many_uni a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainedClass.new a.addManyChildUni(b) a.addManyChildUni(c) b.disconnectContainer assert_equal [c], a.manyChildUni end def test_disconnectContainer_many a = mm::ContainerClass.new b = mm::ContainedClass.new c = mm::ContainedClass.new a.addManyChild(b) a.addManyChild(c) b.disconnectContainer assert_nil b.parentMany assert_equal [c], a.manyChild end # Duplicate Containment Tests # # Testing that no element is contained in two different containers at a time. # This must also work for uni-directional containments as well as # for containments via different roles. # here the bi-dir reference disconnects from the previous container def test_duplicate_containment_bidir_samerole_one a1 = mm::ContainerClass.new a2 = mm::ContainerClass.new b = mm::ContainedClass.new a1.oneChild = b a2.oneChild = b assert_nil a1.oneChild end # here the bi-dir reference disconnects from the previous container def test_duplicate_containment_bidir_samerole_many a1 = mm::ContainerClass.new a2 = mm::ContainerClass.new b = mm::ContainedClass.new a1.addManyChild(b) a2.addManyChild(b) assert_equal [], a1.manyChild end def test_duplicate_containment_unidir_samerole_one a1 = mm::ContainerClass.new a2 = mm::ContainerClass.new b = mm::ContainedClass.new a1.oneChildUni = b a2.oneChildUni = b assert_nil a1.oneChildUni end def test_duplicate_containment_unidir_samerole_many a1 = mm::ContainerClass.new a2 = mm::ContainerClass.new b = mm::ContainedClass.new a1.addManyChildUni(b) a2.addManyChildUni(b) assert_equal [], a1.manyChildUni end def test_duplicate_containment_bidir_otherrole_one a1 = mm::ContainerClass.new a2 = mm::ContainerClass.new b = mm::ContainedClass.new a1.oneChild = b a2.oneChild2 = b assert_nil a1.oneChild end def test_duplicate_containment_bidir_otherrole_many a1 = mm::ContainerClass.new a2 = mm::ContainerClass.new b = mm::ContainedClass.new a1.addManyChild(b) a2.addManyChild2(b) assert_equal [], a1.manyChild end def test_duplicate_containment_unidir_otherrole_one a1 = mm::ContainerClass.new a2 = mm::ContainerClass.new b = mm::ContainedClass.new a1.oneChildUni = b a2.oneChildUni2 = b assert_nil a1.oneChildUni end def test_duplicate_containment_unidir_otherrole_many a1 = mm::ContainerClass.new a2 = mm::ContainerClass.new b = mm::ContainedClass.new a1.addManyChildUni(b) a2.addManyChildUni2(b) assert_equal [], a1.manyChildUni end end