diff --git a/.gitignore b/.gitignore index 0e0b7169249e659f71fd6741bfa3f5804ac72341..a5b7d04336a4a3dd2c22ab2e8f7c2522d73f20c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -*.jar +*.jarsrc/test/java/org/jastadd/relast/tests/Resolver2.java .idea/ .gradle/ build @@ -15,5 +15,8 @@ src/test/jastadd/multiple/Multiple.jadd src/test/jastadd/resolver/Resolver.ast src/test/jastadd/resolver/Resolver.jadd src/test/jastadd/resolver/ResolverRefResolver.jadd +src/test/jastadd/resolver2/Resolver.ast +src/test/jastadd/resolver2/Resolver.jadd +src/test/jastadd/resolver2/ResolverRefResolver.jadd src/test/jastadd/listnames/ListNames.ast src/test/jastadd/listnames/ListNames.jadd \ No newline at end of file diff --git a/build.gradle b/build.gradle index fdf2acc274d909b8a9436cf2ffbf72e1b253f379..0383ec1426d52eb248d733b7fd55a1d748f8a07b 100644 --- a/build.gradle +++ b/build.gradle @@ -201,6 +201,29 @@ task compileResolverTest(type: JavaExec, group: 'verification') { args '--o=src/test/java-gen/', '--package=resolver.ast', 'src/test/jastadd/resolver/Resolver.ast', 'src/test/jastadd/resolver/Resolver.jadd', 'src/test/jastadd/resolver/ResolverUtils.jadd', 'src/test/jastadd/resolver/ResolverRefResolver.jadd', 'src/test/jastadd/resolver/MyRefResolver.jadd', 'src/test/jastadd/Utils.jadd' } + +task preprocessResolver2Test(type: JavaExec, group: 'verification') { + + doFirst { + delete 'src/test/jastadd/resolver2/Resolver.ast', 'src/test/jastadd/resolver2/Resolver.jadd', 'src/test/jastadd/resolver2/ResolverRefResolver.jadd' + } + + classpath = sourceSets.main.runtimeClasspath + main = 'org.jastadd.relast.compiler.Compiler' + args 'src/test/jastadd/resolver2/Resolver.relast', '--file', '--grammarName=src/test/jastadd/resolver2/Resolver', '--resolverHelper' +} + +task compileResolver2Test(type: JavaExec, group: 'verification') { + + doFirst { + delete 'src/test/java-gen/resolver2' + } + + classpath = sourceSets.main.runtimeClasspath + main = 'org.jastadd.JastAdd' + args '--o=src/test/java-gen/', '--package=resolver2.ast', 'src/test/jastadd/resolver2/Resolver.ast', 'src/test/jastadd/resolver2/Resolver.jadd', 'src/test/jastadd/resolver2/ResolverUtils.jadd', 'src/test/jastadd/resolver2/ResolverRefResolver.jadd', 'src/test/jastadd/resolver2/MyRefResolver.jadd', 'src/test/jastadd/Utils.jadd' +} + task preprocessListNamesTest(type: JavaExec, group: 'verification') { doFirst { @@ -243,5 +266,8 @@ compileMultipleTest.dependsOn preprocessMultipleTest test.dependsOn compileResolverTest compileResolverTest.dependsOn preprocessResolverTest +test.dependsOn compileResolver2Test +compileResolver2Test.dependsOn preprocessResolver2Test + test.dependsOn compileListNamesTest compileListNamesTest.dependsOn preprocessListNamesTest \ No newline at end of file diff --git a/src/test/jastadd/resolver2/MyRefResolver.jadd b/src/test/jastadd/resolver2/MyRefResolver.jadd new file mode 100644 index 0000000000000000000000000000000000000000..fa585c919296a0ea027cd06caf679cb9a5b62a00 --- /dev/null +++ b/src/test/jastadd/resolver2/MyRefResolver.jadd @@ -0,0 +1,22 @@ +aspect MyRewrites { + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveNamedElementByToken(String id) { + System.out.println("resolving " + id + " to " + root().findNamedElement(id)); + return root().findNamedElement(id); + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveAByToken(String id) { + System.out.println("resolving " + id + " to " + root().findNamedElement(id)); + return root().findA(id); + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.globallyResolveBByToken(String id) { + System.out.println("resolving " + id + " to " + root().findNamedElement(id)); + return root().findB(id); + } + +} + diff --git a/src/test/jastadd/resolver2/Resolver.relast b/src/test/jastadd/resolver2/Resolver.relast new file mode 100644 index 0000000000000000000000000000000000000000..93a52019c56ee00c4a7af797a3d806f9d80da4ee --- /dev/null +++ b/src/test/jastadd/resolver2/Resolver.relast @@ -0,0 +1,23 @@ +Root ::= A* B*; +abstract NamedElement ::= <Name:String>; +A:NamedElement; +B:NamedElement; + +rel A.Rel1 -> NamedElement; +rel A.Rel2 -> NamedElement; + +rel A.Di1 -> B; +rel A.Di2? -> B; +rel A.Di3* -> B; + +rel A.Bi1l <-> B.Bi1; +rel A.Bi2l <-> B.Bi2?; +rel A.Bi3l <-> B.Bi3*; + +rel A.Bi4l? <-> B.Bi4; +rel A.Bi5l? <-> B.Bi5?; +rel A.Bi6l? <-> B.Bi6*; + +rel A.Bi7l* <-> B.Bi7; +rel A.Bi8l* <-> B.Bi8?; +rel A.Bi9l* <-> B.Bi9*; diff --git a/src/test/jastadd/resolver2/ResolverUtils.jadd b/src/test/jastadd/resolver2/ResolverUtils.jadd new file mode 100644 index 0000000000000000000000000000000000000000..a8d547321c3231220cd02c3f94494c85afd0786f --- /dev/null +++ b/src/test/jastadd/resolver2/ResolverUtils.jadd @@ -0,0 +1,38 @@ +aspect Utils { + + inh Root ASTNode.root(); + eq Root.getA(int i).root() = this; + eq Root.getB(int i).root() = this; + + syn NamedElement Root.findNamedElement(String name) { + for (A a : getAList()) { + if (a.getName().equals(name)) { + return a; + } + } + for (B b : getBList()) { + if (b.getName().equals(name)) { + return b; + } + } + return null; + } + + syn A Root.findA(String name) { + for (A a : getAList()) { + if (a.getName().equals(name)) { + return a; + } + } + return null; + } + + syn B Root.findB(String name) { + for (B b : getBList()) { + if (b.getName().equals(name)) { + return b; + } + } + return null; + } +} \ No newline at end of file diff --git a/src/test/java/org/jastadd/relast/tests/Resolver2.java b/src/test/java/org/jastadd/relast/tests/Resolver2.java new file mode 100644 index 0000000000000000000000000000000000000000..c653c3c04627124fac2a9563e84cb6977103477c --- /dev/null +++ b/src/test/java/org/jastadd/relast/tests/Resolver2.java @@ -0,0 +1,771 @@ +package org.jastadd.relast.tests; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import resolver2.ast.A; +import resolver2.ast.B; +import resolver2.ast.NamedElement; +import resolver2.ast.Root; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +@SuppressWarnings("ArraysAsListWithZeroOrOneArgument") +class Resolver2 { + private Root r; + private A a1; + private A a2; + private A a3; + private B b1; + private B b2; + private B b3; + + + /** + * rel A.Di1 -> B; + */ + @Test + void testNameRes1() { + setup(); + a1.setRel1(NamedElement.createRef("b2")); + System.out.println("Rel 1 of a1 has type " + a1.getRel1().getClass().getSimpleName()); + assertSame(a1.getRel1(), b2); + } + + /** + * rel A.Di1 -> B; + */ + @Test + void testDi1() { + setup(); + a1.setDi1(B.createRef("b2")); + a2.setDi1(B.createRef("b1")); + + assertSame(a1.getDi1(), b2); + assertSame(a2.getDi1(), b1); + + a2.setDi1(b2); + + assertSame(a1.getDi1(), b2); + assertSame(a2.getDi1(), b2); + + try { + a3.setDi1(null); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + } + + + /** + * rel A.Di2? -> B; + */ + @Test + void testDi2() { + setup(); + a1.setDi2(B.createRef("b2")); + a2.setDi2(B.createRef("b1")); + + assertSame(a1.getDi2(), b2); + assertSame(a2.getDi2(), b1); + + a2.setDi2(b2); + + assertSame(a1.getDi2(), b2); + assertSame(a2.getDi2(), b2); + + a2.clearDi2(); + + assertSame(a1.getDi2(), b2); + assertNull(a2.getDi2()); + + assertTrue(a1.hasDi2()); + assertFalse(a2.hasDi2()); + assertFalse(a3.hasDi2()); + } + + + /** + * rel A.Di3* -> B; + */ + @Test + void testDi3() { + setup(); + a1.addDi3(B.createRef("b1")); + a1.addDi3(B.createRef("b2")); + a1.addDi3(B.createRef("b3")); + a2.addDi3(B.createRef("b2")); + + assertEquals(a1.getDi3s(), Arrays.asList(b1, b2, b3)); + assertEquals(a1.getDi3List(), Arrays.asList(b1, b2, b3)); + assertEquals(a2.getDi3s(), Arrays.asList(b2)); + assertEquals(a2.getDi3List(), Arrays.asList(b2)); + assertEquals(a3.getDi3s(), Arrays.asList()); + assertEquals(a3.getDi3List(), Arrays.asList()); + + a1.addDi3(B.createRef("b1")); + a2.addDi3(B.createRef("b1")); + a2.addDi3(B.createRef("b2")); + + assertEquals(a1.getDi3s(), Arrays.asList(b1, b2, b3, b1)); + assertEquals(a1.getDi3List(), Arrays.asList(b1, b2, b3, b1)); + assertEquals(a2.getDi3s(), Arrays.asList(b2, b1, b2)); + assertEquals(a2.getDi3List(), Arrays.asList(b2, b1, b2)); + assertEquals(a3.getDi3s(), Arrays.asList()); + assertEquals(a3.getDi3List(), Arrays.asList()); + + a1.removeDi3(b1); + a2.removeDi3(b2); + + assertEquals(a1.getDi3s(), Arrays.asList(b2, b3, b1)); + assertEquals(a1.getDi3List(), Arrays.asList(b2, b3, b1)); + assertEquals(a2.getDi3s(), Arrays.asList(b1, b2)); + assertEquals(a2.getDi3List(), Arrays.asList(b1, b2)); + assertEquals(a3.getDi3s(), Arrays.asList()); + assertEquals(a3.getDi3List(), Arrays.asList()); + } + + + /** + * rel A.Bi1 <-> B.Bi1; + */ + + @Test + void testBi11() { + // Init + setup(); + a1.setBi1l(B.createRef("b1")); + + // before a1.Bi1() is resolved, the opposite direction is null + assertNull(b1.getBi1()); + + // now, the relation is resolved, and thus the opposite direction is also set + assertSame(b1, a1.getBi1l()); + assertSame(a1, b1.getBi1()); + + // create another, unrelated relation, perform the same tests + a2.setBi1l(B.createRef("b2")); + assertNull(b2.getBi1()); + assertSame(b2, a2.getBi1l()); + assertSame(a2, b2.getBi1()); + + // change the relation of a2 to overwrite the existing one in a1<->b1 + a2.setBi1l(B.createRef("b1")); + + // as long as no resolution took place, the old reference still exists + assertSame(b1, a1.getBi1l()); + assertSame(a1, b1.getBi1()); + + // now, we resolve a2->b1 + assertSame(b1, a2.getBi1l()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.getBi1l(), b1); + assertSame(b1.getBi1(), a2); + assertNull(a1.getBi1l()); + assertNull(b2.getBi1()); + } + + @Test + void testBi12() { + // Init + setup(); + a1.setBi1l(B.createRef("b2")); + + // Change + a2.setBi1l(B.createRef("b2")); + + // unresolved + assertNull(b2.getBi1()); + + assertSame(b2, a1.getBi1l()); + // a1 resolved + assertSame(a1, b2.getBi1()); + + // now resolve the change: + assertSame(b2, a2.getBi1l()); + + // now finally, a1->null + assertNull(a1.getBi1l()); + assertSame(a2.getBi1l(), b2); + assertNull(b1.getBi1()); + assertSame(b2.getBi1(), a2); + } + + + /** + * rel A.Bi2 <-> B.Bi2?; + */ + + @Test + void testBi21() { + // Init + setup(); + a1.setBi2l(B.createRef("b1")); + + // before a1.Bi2() is resolved, the opposite direction is null + assertNull(b1.getBi2()); + + // now, the relation is resolved, and thus the opposite direction is also set + assertSame(b1, a1.getBi2l()); + assertSame(a1, b1.getBi2()); + + // create another, unrelated relation, perform the same tests + a2.setBi2l(B.createRef("b2")); + assertNull(b2.getBi2()); + assertSame(b2, a2.getBi2l()); + assertSame(a2, b2.getBi2()); + + // change the relation of a2 to overwrite the existing one in a1<->b1 + a2.setBi2l(B.createRef("b1")); + + // as long as no resolution took place, the old reference still exists + assertSame(b1, a1.getBi2l()); + assertSame(a1, b1.getBi2()); + + // now, we resolve a2->b1 + assertSame(b1, a2.getBi2l()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.getBi2l(), b1); + assertSame(b1.getBi2(), a2); + assertNull(a1.getBi2l()); + assertNull(b2.getBi2()); + } + + @Test + void testBi22() { + // Init + setup(); + a1.setBi2l(B.createRef("b2")); + + // Change + a2.setBi2l(B.createRef("b2")); + + // unresolved + assertNull(b2.getBi2()); + + assertSame(b2, a1.getBi2l()); + // a1 resolved + assertSame(a1, b2.getBi2()); + + // now resolve the change: + assertSame(b2, a2.getBi2l()); + + // now finally, a1->null + assertNull(a1.getBi2l()); + assertSame(a2.getBi2l(), b2); + assertNull(b1.getBi2()); + assertSame(b2.getBi2(), a2); + } + + + + /** + * rel A.Bi3 <-> B.Bi3*; + */ + @Test + void testBi3() { + setup(); + a2.setBi3l(B.createRef("b2")); + + assertNull(a1.getBi3l()); + assertSame(a2.getBi3l(), b2); + assertEquals(b1.getBi3s(), Arrays.asList()); + assertEquals(b1.getBi3List(), Arrays.asList()); + assertEquals(b2.getBi3s(), Arrays.asList(a2)); + assertEquals(b2.getBi3List(), Arrays.asList(a2)); + assertEquals(b3.getBi3s(), Arrays.asList()); + assertEquals(b3.getBi3List(), Arrays.asList()); + + a2.setBi3l(B.createRef("b3")); + + assertNull(a1.getBi3l()); + assertSame(a2.getBi3l(), b3); + assertEquals(b1.getBi3s(), Arrays.asList()); + assertEquals(b1.getBi3List(), Arrays.asList()); + assertEquals(b2.getBi3s(), Arrays.asList()); + assertEquals(b2.getBi3List(), Arrays.asList()); + assertEquals(b3.getBi3s(), Arrays.asList(a2)); + assertEquals(b3.getBi3List(), Arrays.asList(a2)); + + a1.setBi3l(B.createRef("b3")); + a3.setBi3l(B.createRef("b3")); + + assertSame(a1.getBi3l(), b3); + assertSame(a2.getBi3l(), b3); + assertSame(a3.getBi3l(), b3); + assertEquals(b1.getBi3s(), Arrays.asList()); + assertEquals(b1.getBi3List(), Arrays.asList()); + assertEquals(b2.getBi3s(), Arrays.asList()); + assertEquals(b2.getBi3List(), Arrays.asList()); + assertEquals(b3.getBi3s(), Arrays.asList(a2, a1, a3)); + assertEquals(b3.getBi3List(), Arrays.asList(a2, a1, a3)); + + a2.setBi3l(B.createRef("b1")); + + assertSame(a1.getBi3l(), b3); + assertSame(a2.getBi3l(), b1); + assertSame(a3.getBi3l(), b3); + assertEquals(b1.getBi3s(), Arrays.asList(a2)); + assertEquals(b1.getBi3List(), Arrays.asList(a2)); + assertEquals(b2.getBi3s(), Arrays.asList()); + assertEquals(b2.getBi3List(), Arrays.asList()); + assertEquals(b3.getBi3s(), Arrays.asList(a1, a3)); + assertEquals(b3.getBi3List(), Arrays.asList(a1, a3)); + + try { + a2.setBi3l(null); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + } + + + /** + * rel A.Bi4? <-> B.Bi4; + */ + @Test + void testBi41() { + // Init + setup(); + a1.setBi4l(B.createRef("b1")); + + // before a1.Bi4() is resolved, the opposite direction is null + assertNull(b1.getBi4()); + + // now, the relation is resolved, and thus the opposite direction is also set + assertSame(b1, a1.getBi4l()); + assertSame(a1, b1.getBi4()); + + // create another, unrelated relation, perform the same tests + a2.setBi4l(B.createRef("b2")); + assertNull(b2.getBi4()); + assertSame(b2, a2.getBi4l()); + assertSame(a2, b2.getBi4()); + + // change the relation of a2 to overwrite the existing one in a1<->b1 + a2.setBi4l(B.createRef("b1")); + + // as long as no resolution took place, the old reference still exists + assertSame(b1, a1.getBi4l()); + assertSame(a1, b1.getBi4()); + + // now, we resolve a2->b1 + assertSame(b1, a2.getBi4l()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.getBi4l(), b1); + assertSame(b1.getBi4(), a2); + assertNull(a1.getBi4l()); + assertNull(b2.getBi4()); + } + + @Test + void testBi42() { + // Init + setup(); + a1.setBi4l(B.createRef("b2")); + + // Change + a2.setBi4l(B.createRef("b2")); + + // unresolved + assertNull(b2.getBi4()); + + assertSame(b2, a1.getBi4l()); + // a1 resolved + assertSame(a1, b2.getBi4()); + + // now resolve the change: + assertSame(b2, a2.getBi4l()); + + // now finally, a1->null + assertNull(a1.getBi4l()); + assertSame(a2.getBi4l(), b2); + assertNull(b1.getBi4()); + assertSame(b2.getBi4(), a2); + } + + + /** + * rel A.Bi5? <-> B.Bi5?; + */ + @Test + void testBi51() { + // Init + setup(); + a1.setBi5l(B.createRef("b1")); + + // before a1.Bi5() is resolved, the opposite direction is null + assertNull(b1.getBi5()); + + // now, the relation is resolved, and thus the opposite direction is also set + assertSame(b1, a1.getBi5l()); + assertSame(a1, b1.getBi5()); + + // create another, unrelated relation, perform the same tests + a2.setBi5l(B.createRef("b2")); + assertNull(b2.getBi5()); + assertSame(b2, a2.getBi5l()); + assertSame(a2, b2.getBi5()); + + // change the relation of a2 to overwrite the existing one in a1<->b1 + a2.setBi5l(B.createRef("b1")); + + // as long as no resolution took place, the old reference still exists + assertSame(b1, a1.getBi5l()); + assertSame(a1, b1.getBi5()); + + // now, we resolve a2->b1 + assertSame(b1, a2.getBi5l()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.getBi5l(), b1); + assertSame(b1.getBi5(), a2); + assertNull(a1.getBi5l()); + assertNull(b2.getBi5()); + } + + @Test + void testBi52() { + // Init + setup(); + a1.setBi5l(B.createRef("b2")); + + // Change + a2.setBi5l(B.createRef("b2")); + + // unresolved + assertNull(b2.getBi5()); + + assertSame(b2, a1.getBi5l()); + // a1 resolved + assertSame(a1, b2.getBi5()); + + // now resolve the change: + assertSame(b2, a2.getBi5l()); + + // now finally, a1->null + assertNull(a1.getBi5l()); + assertSame(a2.getBi5l(), b2); + assertNull(b1.getBi5()); + assertSame(b2.getBi5(), a2); + } + + + /** + * rel A.Bi6? <-> B.Bi6*; + */ + @Test + void testBi6() { + setup(); + a2.setBi6l(B.createRef("b2")); + + assertNull(a1.getBi6l()); + assertSame(a2.getBi6l(), b2); + assertEquals(b1.getBi6s(), Arrays.asList()); + assertEquals(b1.getBi6List(), Arrays.asList()); + assertEquals(b2.getBi6s(), Arrays.asList(a2)); + assertEquals(b2.getBi6List(), Arrays.asList(a2)); + assertEquals(b3.getBi6s(), Arrays.asList()); + assertEquals(b3.getBi6List(), Arrays.asList()); + + a2.setBi6l(B.createRef("b3")); + + assertNull(a1.getBi6l()); + assertSame(a2.getBi6l(), b3); + assertEquals(b1.getBi6s(), Arrays.asList()); + assertEquals(b1.getBi6List(), Arrays.asList()); + assertEquals(b2.getBi6s(), Arrays.asList()); + assertEquals(b2.getBi6List(), Arrays.asList()); + assertEquals(b3.getBi6s(), Arrays.asList(a2)); + assertEquals(b3.getBi6List(), Arrays.asList(a2)); + + a1.setBi6l(B.createRef("b3")); + a3.setBi6l(B.createRef("b3")); + + assertSame(a1.getBi6l(), b3); + assertSame(a2.getBi6l(), b3); + assertSame(a3.getBi6l(), b3); + assertEquals(b1.getBi6s(), Arrays.asList()); + assertEquals(b1.getBi6List(), Arrays.asList()); + assertEquals(b2.getBi6s(), Arrays.asList()); + assertEquals(b2.getBi6List(), Arrays.asList()); + assertEquals(b3.getBi6s(), Arrays.asList(a2, a1, a3)); + assertEquals(b3.getBi6List(), Arrays.asList(a2, a1, a3)); + + a2.setBi6l(B.createRef("b1")); + + assertSame(a1.getBi6l(), b3); + assertSame(a2.getBi6l(), b1); + assertSame(a3.getBi6l(), b3); + assertEquals(b1.getBi6s(), Arrays.asList(a2)); + assertEquals(b1.getBi6List(), Arrays.asList(a2)); + assertEquals(b2.getBi6s(), Arrays.asList()); + assertEquals(b2.getBi6List(), Arrays.asList()); + assertEquals(b3.getBi6s(), Arrays.asList(a1, a3)); + assertEquals(b3.getBi6List(), Arrays.asList(a1, a3)); + + a2.clearBi6l(); + + assertSame(a1.getBi6l(), b3); + assertNull(a2.getBi6l()); + assertSame(a3.getBi6l(), b3); + assertEquals(b1.getBi6s(), Arrays.asList()); + assertEquals(b1.getBi6List(), Arrays.asList()); + assertEquals(b2.getBi6s(), Arrays.asList()); + assertEquals(b2.getBi6List(), Arrays.asList()); + assertEquals(b3.getBi6s(), Arrays.asList(a1, a3)); + assertEquals(b3.getBi6List(), Arrays.asList(a1, a3)); + + assertTrue(a1.hasBi6l()); + assertFalse(a2.hasBi6l()); + assertTrue(a3.hasBi6l()); + } + + + /** + * rel A.Bi7* <-> B.Bi7; + */ + @Test + void testBi7() { + setup(); + a2.addBi7l(B.createRef("b2")); + + // a1 list is empty + assertEquals(a1.getBi7ls(), Arrays.asList()); + assertEquals(a1.getBi7lList(), Arrays.asList()); + + // a2 list contains b2 (because resolution took place) + assertEquals(a2.getBi7ls(), Arrays.asList(b2)); + assertEquals(a2.getBi7lList(), Arrays.asList(b2)); + + // of all the bs, only b2 contains a back ref to a2 + assertNull(b1.getBi7()); + assertSame(b2.getBi7(), a2); + assertNull(b3.getBi7()); + + a2.addBi7l(B.createRef("b3")); + a1.addBi7l(B.createRef("b2")); + + assertEquals(a1.getBi7ls(), Arrays.asList(b2)); + assertEquals(a1.getBi7lList(), Arrays.asList(b2)); + assertEquals(a2.getBi7ls(), Arrays.asList(b3)); + assertEquals(a2.getBi7lList(), Arrays.asList(b3)); + assertNull(b1.getBi7()); + assertSame(b2.getBi7(), a1); + assertSame(b3.getBi7(), a2); + + a1.addBi7l(B.createRef("b1")); + + assertEquals(a1.getBi7ls(), Arrays.asList(b2, b1)); + assertEquals(a1.getBi7lList(), Arrays.asList(b2, b1)); + assertEquals(a2.getBi7ls(), Arrays.asList(b3)); + assertEquals(a2.getBi7lList(), Arrays.asList(b3)); + assertSame(b1.getBi7(), a1); + assertSame(b2.getBi7(), a1); + assertSame(b3.getBi7(), a2); + + a1.addBi7l(B.createRef("b1")); + + assertEquals(a1.getBi7ls(), Arrays.asList(b2, b1)); + assertEquals(a1.getBi7lList(), Arrays.asList(b2, b1)); + assertEquals(a2.getBi7ls(), Arrays.asList(b3)); + assertEquals(a2.getBi7lList(), Arrays.asList(b3)); + assertSame(b1.getBi7(), a1); + assertSame(b2.getBi7(), a1); + assertSame(b3.getBi7(), a2); + + a1.removeBi7l(b1); + + assertEquals(a1.getBi7ls(), Arrays.asList(b2)); + assertEquals(a1.getBi7lList(), Arrays.asList(b2)); + assertEquals(a2.getBi7ls(), Arrays.asList(b3)); + assertEquals(a2.getBi7lList(), Arrays.asList(b3)); + assertNull(b1.getBi7()); + assertSame(b2.getBi7(), a1); + assertSame(b3.getBi7(), a2); + } + + + /** + * rel A.Bi8* <-> B.Bi8?; + */ + @Test + void testBi8() { + setup(); + a2.addBi8l(B.createRef("b2")); + + assertEquals(a1.getBi8ls(), Arrays.asList()); + assertEquals(a1.getBi8lList(), Arrays.asList()); + assertEquals(a2.getBi8ls(), Arrays.asList(b2)); + assertEquals(a2.getBi8lList(), Arrays.asList(b2)); + assertNull(b1.getBi8()); + assertSame(b2.getBi8(), a2); + assertNull(b3.getBi8()); + + a2.addBi8l(B.createRef("b3")); + a1.addBi8l(B.createRef("b2")); + + assertEquals(a1.getBi8ls(), Arrays.asList(b2)); + assertEquals(a1.getBi8lList(), Arrays.asList(b2)); + assertEquals(a2.getBi8ls(), Arrays.asList(b3)); + assertEquals(a2.getBi8lList(), Arrays.asList(b3)); + assertNull(b1.getBi8()); + assertSame(b2.getBi8(), a1); + assertSame(b3.getBi8(), a2); + + a1.addBi8l(B.createRef("b1")); + + assertEquals(a1.getBi8ls(), Arrays.asList(b2, b1)); + assertEquals(a1.getBi8lList(), Arrays.asList(b2, b1)); + assertEquals(a2.getBi8ls(), Arrays.asList(b3)); + assertEquals(a2.getBi8lList(), Arrays.asList(b3)); + assertSame(b1.getBi8(), a1); + assertSame(b2.getBi8(), a1); + assertSame(b3.getBi8(), a2); + + a1.addBi8l(B.createRef("b1")); + + assertEquals(a1.getBi8ls(), Arrays.asList(b2, b1)); + assertEquals(a1.getBi8lList(), Arrays.asList(b2, b1)); + assertEquals(a2.getBi8ls(), Arrays.asList(b3)); + assertEquals(a2.getBi8lList(), Arrays.asList(b3)); + assertSame(b1.getBi8(), a1); + assertSame(b2.getBi8(), a1); + assertSame(b3.getBi8(), a2); + + a1.removeBi8l(b1); + + assertEquals(a1.getBi8ls(), Arrays.asList(b2)); + assertEquals(a1.getBi8lList(), Arrays.asList(b2)); + assertEquals(a2.getBi8ls(), Arrays.asList(b3)); + assertEquals(a2.getBi8lList(), Arrays.asList(b3)); + assertNull(b1.getBi8()); + assertSame(b2.getBi8(), a1); + assertSame(b3.getBi8(), a2); + } + + + /** + * rel A.Bi9* <-> B.Bi9*; + */ + @Test + void testBi9() { + setup(); + a1.addBi9l(B.createRef("b1")); + a1.addBi9l(B.createRef("b2")); + + assertEquals(a1.getBi9ls(), Arrays.asList(b1, b2)); + assertEquals(a1.getBi9lList(), Arrays.asList(b1, b2)); + assertEquals(a2.getBi9ls(), Arrays.asList()); + assertEquals(a2.getBi9lList(), Arrays.asList()); + assertEquals(a3.getBi9ls(), Arrays.asList()); + assertEquals(a3.getBi9lList(), Arrays.asList()); + assertEquals(b1.getBi9s(), Arrays.asList(a1)); + assertEquals(b1.getBi9List(), Arrays.asList(a1)); + assertEquals(b2.getBi9s(), Arrays.asList(a1)); + assertEquals(b2.getBi9List(), Arrays.asList(a1)); + assertEquals(b3.getBi9s(), Arrays.asList()); + assertEquals(b3.getBi9List(), Arrays.asList()); + + b3.addBi9(A.createRef("a1")); + b3.addBi9(A.createRef("a3")); + b3.addBi9(A.createRef("a1")); + + // b3 is not resolved yet, so the as look like before + assertEquals(a1.getBi9ls(), Arrays.asList(b1, b2)); + assertEquals(a1.getBi9lList(), Arrays.asList(b1, b2)); + assertEquals(a2.getBi9ls(), Arrays.asList()); + assertEquals(a2.getBi9lList(), Arrays.asList()); + assertEquals(a3.getBi9ls(), Arrays.asList()); + assertEquals(a3.getBi9lList(), Arrays.asList()); + + // let's resolve b3 + assertEquals(b1.getBi9s(), Arrays.asList(a1)); + assertEquals(b1.getBi9List(), Arrays.asList(a1)); + assertEquals(b2.getBi9s(), Arrays.asList(a1)); + assertEquals(b2.getBi9List(), Arrays.asList(a1)); + assertEquals(b3.getBi9s(), Arrays.asList(a1, a3, a1)); + assertEquals(b3.getBi9List(), Arrays.asList(a1, a3, a1)); + + // now the as are updated + assertEquals(a1.getBi9ls(), Arrays.asList(b1, b2, b3, b3)); + assertEquals(a1.getBi9lList(), Arrays.asList(b1, b2, b3, b3)); + assertEquals(a2.getBi9ls(), Arrays.asList()); + assertEquals(a2.getBi9lList(), Arrays.asList()); + assertEquals(a3.getBi9ls(), Arrays.asList(b3)); + assertEquals(a3.getBi9lList(), Arrays.asList(b3)); + + b3.removeBi9(a1); + + assertEquals(a1.getBi9ls(), Arrays.asList(b1, b2, b3)); + assertEquals(a1.getBi9lList(), Arrays.asList(b1, b2, b3)); + assertEquals(a2.getBi9ls(), Arrays.asList()); + assertEquals(a2.getBi9lList(), Arrays.asList()); + assertEquals(a3.getBi9ls(), Arrays.asList(b3)); + assertEquals(a3.getBi9lList(), Arrays.asList(b3)); + assertEquals(b1.getBi9s(), Arrays.asList(a1)); + assertEquals(b1.getBi9List(), Arrays.asList(a1)); + assertEquals(b2.getBi9s(), Arrays.asList(a1)); + assertEquals(b2.getBi9List(), Arrays.asList(a1)); + assertEquals(b3.getBi9s(), Arrays.asList(a3, a1)); + assertEquals(b3.getBi9List(), Arrays.asList(a3, a1)); + } + + + @Test + void testImmutableList() { + setup(); + + a1.addDi3(B.createRef("b1")); + a1.addDi3(B.createRef("b2")); + try { + a1.getDi3s().add(b3); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + + a1.addBi7l(B.createRef("b1")); + a1.addBi7l(B.createRef("b2")); + try { + a1.getBi7ls().add(B.createRef("b3")); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + + a1.addBi9l(B.createRef("b1")); + a1.addBi9l(B.createRef("b2")); + try { + a1.getBi9ls().add(B.createRef("b3")); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + } + + @BeforeEach + void setup() { + r = new Root(); + a1 = new A("a1"); + a2 = new A("a2"); + a3 = new A("a3"); + b1 = new B("b1"); + b2 = new B("b2"); + b3 = new B("b3"); + + r.addA(a1); + r.addA(a2); + r.addA(a3); + r.addB(b1); + r.addB(b2); + r.addB(b3); + } + +}