diff --git a/src/Fame-Core/FMMultiMultivalueLink.class.st b/src/Fame-Core/FMMultiMultivalueLink.class.st index e65e3bb4..a6f721d1 100644 --- a/src/Fame-Core/FMMultiMultivalueLink.class.st +++ b/src/Fame-Core/FMMultiMultivalueLink.class.st @@ -45,6 +45,34 @@ FMMultiMultivalueLink >> removeAll [ do: [ :anElement | (anElement perform: opposite) remove: owner ] ] +{ #category : #'private - adding' } +FMMultiMultivalueLink >> uncheckAdd: anElement [ + (anElement perform: opposite) uncheckUnsafeAdd: owner. + values add: anElement. + ^ anElement +] + +{ #category : #'private - adding' } +FMMultiMultivalueLink >> uncheckAddAll: aCollection [ + "Include all the elements of aCollection as the receiver's elements. Answer + aCollection. Actually, any object responding to #do: can be used as argument." + aCollection do: [ :each | self uncheckAdd: each ]. + ^ aCollection +] + +{ #category : #'private - adding' } +FMMultiMultivalueLink >> uncheckUnsafeAdd: element [ + values add: element +] + +{ #category : #adding } +FMMultiMultivalueLink >> value: aCollection [ + + ^ self + removeAll: values copy; + uncheckAddAll: aCollection asOrderedCollection removeDuplicates +] + { #category : #private } FMMultiMultivalueLink >> with: element opposite: oppositeSelector [ self assert: oppositeSelector numArgs = 0. diff --git a/src/Fame-Core/FMMultivalueLink.class.st b/src/Fame-Core/FMMultivalueLink.class.st index 68658688..aa8ab75f 100644 --- a/src/Fame-Core/FMMultivalueLink.class.st +++ b/src/Fame-Core/FMMultivalueLink.class.st @@ -75,7 +75,7 @@ FMMultivalueLink >> = otherCollection [ ^ values hasEqualElements: otherCollection asOrderedCollection ] -{ #category : #accessing } +{ #category : #adding } FMMultivalueLink >> add: anElement [ anElement perform: opposite with: owner. self unsafeAdd: anElement. @@ -204,7 +204,7 @@ FMMultivalueLink >> unsafeRemove: element [ values remove: element ifAbsent: nil ] -{ #category : #accessing } +{ #category : #adding } FMMultivalueLink >> value: aCollection [ ^self removeAll: values copy; addAll: aCollection diff --git a/src/Fame-Tests/FMDungeonExample.class.st b/src/Fame-Tests/FMDungeonExample.class.st index e1f06575..b8a1b681 100644 --- a/src/Fame-Tests/FMDungeonExample.class.st +++ b/src/Fame-Tests/FMDungeonExample.class.st @@ -1,3 +1,8 @@ +" +This class contains tests. + +More tests dedicated to `FMMultiMultivalueLink` are in `FMMultiMultivalueLinkTest` +" Class { #name : #FMDungeonExample, #superclass : #TestCase, diff --git a/src/Fame-Tests/FMMultiMultivalueLinkTest.class.st b/src/Fame-Tests/FMMultiMultivalueLinkTest.class.st new file mode 100644 index 00000000..305d1cc9 --- /dev/null +++ b/src/Fame-Tests/FMMultiMultivalueLinkTest.class.st @@ -0,0 +1,260 @@ +" +This class is complementary with the tests in `FMDungeonExample` +" +Class { + #name : #FMMultiMultivalueLinkTest, + #superclass : #TestCase, + #category : #'Fame-Tests-Core' +} + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testOneDragonIsKilledByOneHero [ + + | dragon1 hero1 | + dragon1 := RPGDragon new. + hero1 := RPGHero new. + dragon1 killedBy: { hero1 }. + self assert: dragon1 killedBy size equals: 1. + self assert: dragon1 killedBy anyOne equals: hero1 +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testOneHeroKillOneDragon [ + + | dragon1 hero1 | + dragon1 := RPGDragon new. + hero1 := RPGHero new. + hero1 kills: { dragon1 }. + self assert: hero1 kills size equals: 1. + self assert: hero1 kills anyOne equals: dragon1 +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testOneHeroKillOneDragonThenTheDragonDecideToNotBeKilled [ + + | dragon1 hero1 | + dragon1 := RPGDragon new. + hero1 := RPGHero new. + hero1 kills: { dragon1 }. + dragon1 killedBy: { }. + self assert: hero1 kills size equals: 0. + self assert: dragon1 killedBy size equals: 0 +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testOneHeroKillOneDragonsThenTwoWithTheFirstOneAgain [ + + | dragon1 dragon2 hero1 | + dragon1 := RPGDragon new. + dragon2 := RPGDragon new. + hero1 := RPGHero new. + hero1 kills: { dragon1 }. + hero1 kills: { + dragon1. + dragon2 }. + self assert: hero1 kills size equals: 2. + self assertCollection: hero1 kills hasSameElements: { + dragon1. + dragon2 }. + + self assert: dragon1 killedBy size equals: 1. + self assert: dragon2 killedBy size equals: 1. + self assert: dragon1 killedBy anyOne equals: hero1. + self assert: dragon2 killedBy anyOne equals: hero1 +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testOneHeroKillTwiceTheSameDragon [ + + | dragon1 hero1 | + dragon1 := RPGDragon new. + hero1 := RPGHero new. + hero1 kills: { + dragon1. + dragon1 }. + self assert: hero1 kills size equals: 1. + self assert: hero1 kills anyOne equals: dragon1. + self assert: dragon1 killedBy size equals: 1. + self assert: dragon1 killedBy anyOne equals: hero1 +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testOneHeroKillTwoDragons [ + + | dragon1 dragon2 hero1 | + dragon1 := RPGDragon new. + dragon2 := RPGDragon new. + hero1 := RPGHero new. + hero1 kills: { + dragon1. + dragon2 }. + self assert: hero1 kills size equals: 2. + self assertCollection: hero1 kills hasSameElements: { + dragon1. + dragon2 } +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testOneHeroKillTwoDragonsAndFinallyOnlyOne [ + + | dragon1 dragon2 hero1 | + dragon1 := RPGDragon new. + dragon2 := RPGDragon new. + hero1 := RPGHero new. + hero1 kills: { + dragon1. + dragon2 }. + hero1 kills: { dragon1 }. + self assert: hero1 kills size equals: 1. + self assertCollection: hero1 kills hasSameElements: { dragon1 }. + self assert: dragon1 killedBy size equals: 1. + self assert: dragon1 killedBy anyOne equals: hero1. + self assert: dragon2 killedBy size equals: 0 +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testOneHeroKilledLotOfDragon [ + + "This is a performance test" + + | dragons hero1 | + dragons := OrderedCollection new. + 1 to: 50000 do: [ :index | dragons add: RPGDragon new ]. + hero1 := RPGHero new. + hero1 kills: dragons. + self assert: hero1 kills size equals: 50000. +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testTwoDragonsAreKilledByOneHero [ + + | dragon1 hero1 dragon2 | + dragon1 := RPGDragon new. + dragon2 := RPGDragon new. + hero1 := RPGHero new. + dragon1 killedBy: { hero1 }. + dragon2 killedBy: { hero1 }. + "From dragon to hero relation" + self assert: dragon1 killedBy size equals: 1. + self assert: dragon1 killedBy anyOne equals: hero1. + self assert: dragon2 killedBy size equals: 1. + self assert: dragon2 killedBy anyOne equals: hero1. + "From hero to dragon relation" + self assert: hero1 kills size equals: 2. + self assertCollection: hero1 kills hasSameElements: { + dragon1. + dragon2 } +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testTwoDragonsAreKilledByTwoHeros [ + + | dragon1 hero1 dragon2 hero2 | + dragon1 := RPGDragon new. + dragon2 := RPGDragon new. + hero1 := RPGHero new. + hero2 := RPGHero new. + dragon1 killedBy: { + hero1. + hero2 }. + dragon2 killedBy: { + hero1. + hero2 }. + self assert: dragon1 killedBy size equals: 2. + self assertCollection: dragon1 killedBy hasSameElements: { + hero1. + hero2 }. + self assert: dragon2 killedBy size equals: 2. + self assertCollection: dragon2 killedBy hasSameElements: { + hero1. + hero2 }. + "From hero to dragon relation" + self assert: hero1 kills size equals: 2. + self assert: hero2 kills size equals: 2. + self assertCollection: hero1 kills hasSameElements: { + dragon1. + dragon2 }. + self assertCollection: hero2 kills hasSameElements: { + dragon1. + dragon2 } +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testTwoHerosKillTWiceTwoDragons [ + + | dragon1 dragon2 hero1 hero2 | + dragon1 := RPGDragon new. + dragon2 := RPGDragon new. + hero1 := RPGHero new. + hero2 := RPGHero new. + hero1 kills: { + dragon1. + dragon1. + dragon2. + dragon2 }. + hero2 kills: { + dragon1. + dragon1. + dragon2. + dragon2 }. + self assert: hero1 kills size equals: 2. + self assert: hero1 kills anyOne equals: dragon1. + self assert: hero2 kills size equals: 2. + self assert: hero2 kills anyOne equals: dragon1. + self assert: dragon1 killedBy size equals: 2. + self assertCollection: dragon1 killedBy hasSameElements: { + hero1. + hero2 }. + self assert: dragon2 killedBy size equals: 2. + self assertCollection: dragon2 killedBy hasSameElements: { + hero1. + hero2 } +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testTwoHerosKillThriceTheSameDragon [ + + | dragon1 hero1 hero2 | + dragon1 := RPGDragon new. + hero1 := RPGHero new. + hero2 := RPGHero new. + hero1 kills: { + dragon1. + dragon1 }. + hero1 kills add: dragon1. + hero2 kills: { + dragon1. + dragon1 }. + hero2 kills add: dragon1. + self assert: hero1 kills size equals: 1. + self assert: hero1 kills anyOne equals: dragon1. + self assert: hero2 kills size equals: 1. + self assert: hero2 kills anyOne equals: dragon1. + self assert: dragon1 killedBy size equals: 2. + self assertCollection: dragon1 killedBy hasSameElements: { + hero1. + hero2 } +] + +{ #category : #tests } +FMMultiMultivalueLinkTest >> testTwoHerosKillTwiceTheSameDragon [ + + | dragon1 hero1 hero2 | + dragon1 := RPGDragon new. + hero1 := RPGHero new. + hero2 := RPGHero new. + hero1 kills: { + dragon1. + dragon1 }. + hero2 kills: { + dragon1. + dragon1 }. + self assert: hero1 kills size equals: 1. + self assert: hero1 kills anyOne equals: dragon1. + self assert: hero2 kills size equals: 1. + self assert: hero2 kills anyOne equals: dragon1. + self assert: dragon1 killedBy size equals: 2. + self assertCollection: dragon1 killedBy hasSameElements: { + hero1. + hero2 } +]