From 49d05e03c63247c84ae0ec1c6daf40957359ff29 Mon Sep 17 00:00:00 2001 From: Johannes Mey <johannes.mey@tu-dresden.de> Date: Tue, 26 Feb 2019 14:48:09 +0100 Subject: [PATCH] resolver helper now works for all sorts of relations --- .gitignore | 1 + src/main/jastadd/Backend.jadd | 63 +- src/test/jastadd/resolver/MyRefResolver.jadd | 12 + src/test/jastadd/resolver/Resolver.relast | 16 + .../jastadd/relast/tests/ResolverHelper.java | 722 +++++++++++++++++- 5 files changed, 803 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index dd28858..0e0b716 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build src/gen-res/ src/gen/ +out/ *.class src/test/jastadd/relations/Relations.ast src/test/jastadd/relations/Relations.jadd diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd index 7e02ef0..59d8c53 100644 --- a/src/main/jastadd/Backend.jadd +++ b/src/main/jastadd/Backend.jadd @@ -217,7 +217,7 @@ aspect BackendDirectedAPI { sb.append(".get" + nameCapitalized() + "() {\n"); if (resolverHelper) { sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null && get" + getImplAttributeName() + "().unresolved()) {\n"); - sb.append(ind(3) + "set" + getImplAttributeName() + "(resolve" + nameCapitalized() + "(get" + getImplAttributeName() + "().asUnresolved" + ofTypeDecl() + "().get__token()));\n"); + sb.append(ind(3) + "set" + nameCapitalized() + "(resolve" + nameCapitalized() + "(get" + getImplAttributeName() + "().asUnresolved" + ofTypeDecl() + "().get__token()));\n"); sb.append(ind(2) + "}\n"); } sb.append(ind(2) + "return get" + getImplAttributeName() + "();\n"); @@ -250,6 +250,20 @@ aspect BackendDirectedAPI { sb.append(".get" + nameCapitalized() + "List() {\n"); sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); + // resolve the entire list + if (resolverHelper) { + sb.append(ind(2) + "int removedElements = 0;\n"); + sb.append(ind(2) + "if (l != null) {\n"); + sb.append(ind(3) + "for (int i = 0; i < l.size() - removedElements; i++) {\n"); + sb.append(ind(4) + "if (get" + getImplAttributeName() + "().get(i) != null && get" + getImplAttributeName() + "().get(i).unresolved()) {\n"); + sb.append(ind(5) + ofTypeDecl() + " element = l.remove(i);\n"); + sb.append(ind(5) + "add" + nameCapitalized() + "(resolve" + nameCapitalized() + "(element.asUnresolved" + ofTypeDecl() + "().get__token(), i));\n"); + sb.append(ind(5) + "i--; // go back an index, because we removed an element\n"); + sb.append(ind(5) + "removedElements++; // no need to iterate over the removed elements again\n"); + sb.append(ind(4) + "}\n"); + sb.append(ind(3) + "}\n"); + sb.append(ind(2) + "}\n"); + } sb.append(ind(2) + "return l != null ? Collections.unmodifiableList(l) : Collections.emptyList();\n"); sb.append(ind(1) + "}\n"); } @@ -306,20 +320,42 @@ aspect BackendBidirectionalAPI { if (!isOpt) { sb.append(ind(2) + "assertNotNull(o);\n"); } - sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null) {\n"); + // unset the old opposite +// if (resolverHelper) { +// sb.append(ind(2) + "if (!o.unresolved() && get" + getImplAttributeName() + "() != null) {\n"); +// } else { + sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null) {\n"); +// } sb.append(ind(3) + "get" + getImplAttributeName() + "().set" + otherSide().getImplAttributeName() + "(null);\n"); sb.append(ind(2) + "}\n"); - sb.append(ind(2) + "if (o != null && o.get" + otherSide().getImplAttributeName() + "() != null) {\n"); + if (resolverHelper) { + sb.append(ind(2) + "if (!o.unresolved() && o != null && o.get" + otherSide().getImplAttributeName() + "() != null) {\n"); + } else { + sb.append(ind(2) + "if (o != null && o.get" + otherSide().getImplAttributeName() + "() != null) {\n"); + } sb.append(ind(3) + "o.get" + otherSide().getImplAttributeName() + "().set" + getImplAttributeName() + "(null);\n"); sb.append(ind(2) + "}\n"); sb.append(ind(2) + "set" + getImplAttributeName() + "(o);\n"); - if (isOpt) { - sb.append(ind(2) + "if (o != null) {\n"); - sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + if (resolverHelper) { + sb.append(ind(2) + "if (!o.unresolved()) {\n"); + if (isOpt) { + sb.append(ind(3) + "if (o != null) {\n"); + sb.append(ind(4) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + sb.append(ind(3) + "}\n"); + } else { + sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + } sb.append(ind(2) + "}\n"); } else { - sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + if (isOpt) { + sb.append(ind(2) + "if (o != null) {\n"); + sb.append(ind(3) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + sb.append(ind(2) + "}\n"); + } else { + sb.append(ind(2) + "o.set" + otherSide().getImplAttributeName() + "(this);\n"); + } } + sb.append(ind(1) + "}\n"); if (isOpt) { @@ -610,7 +646,8 @@ aspect NameResolutionHelper { relation().getLeft().generateContextDependentNameResolution(sb); } public void Bidirectional.generateContextDependentNameResolution(StringBuilder sb) { - // TODO + relation().getLeft().generateContextDependentNameResolution(sb); + relation().getRight().generateContextDependentNameResolution(sb); } public abstract void RelationComponent.generateContextDependentNameResolution(StringBuilder sb); @@ -618,10 +655,16 @@ aspect NameResolutionHelper { generateDirectedContextDependentNameResolution(sb); } public void OptionalRelationComponent.generateContextDependentNameResolution(StringBuilder sb) { - // TODO + // optional relations are resolved in the same way as mandatory relations + // TODO maybe, there should be a check if the id to be solved is empty or null + generateDirectedContextDependentNameResolution(sb); } public void ManyRelationComponent.generateContextDependentNameResolution(StringBuilder sb) { - // TODO + sb.append(ind(1) + "// context-dependent name resolution\n"); + sb.append(ind(1) + "syn " + ofTypeDecl() + " " + toTypeDecl() + ".resolve" + nameCapitalized() + "(String id, int position) {\n"); + sb.append(ind(2) + "// default to context-independent name resolution\n"); + sb.append(ind(2) + "return resolve" + ofTypeDecl() + "(id);\n"); + sb.append(ind(1) + "}\n"); } public void RelationComponent.generateDirectedContextDependentNameResolution(StringBuilder sb) { diff --git a/src/test/jastadd/resolver/MyRefResolver.jadd b/src/test/jastadd/resolver/MyRefResolver.jadd index c152e17..a6114c6 100644 --- a/src/test/jastadd/resolver/MyRefResolver.jadd +++ b/src/test/jastadd/resolver/MyRefResolver.jadd @@ -6,5 +6,17 @@ aspect MyRewrites { return root().findNamedElement(id); } + // context-independent name resolution + refine RefResolverStubs eq ASTNode.resolveA(String id) { + System.out.println("resolving " + id + " to " + root().findNamedElement(id)); + return root().findA(id); + } + + // context-independent name resolution + refine RefResolverStubs eq ASTNode.resolveB(String id) { + System.out.println("resolving " + id + " to " + root().findNamedElement(id)); + return root().findB(id); + } + } diff --git a/src/test/jastadd/resolver/Resolver.relast b/src/test/jastadd/resolver/Resolver.relast index 51cfc61..5cbaecf 100644 --- a/src/test/jastadd/resolver/Resolver.relast +++ b/src/test/jastadd/resolver/Resolver.relast @@ -5,3 +5,19 @@ B:NamedElement; rel A.Rel1 -> NamedElement; rel A.Rel2 -> NamedElement; + +rel A.Di1 -> B; +rel A.Di2? -> B; +rel A.Di3* -> B; + +rel A.Bi1 <-> B.Bi1; +rel A.Bi2 <-> B.Bi2?; +rel A.Bi3 <-> B.Bi3*; + +rel A.Bi4? <-> B.Bi4; +rel A.Bi5? <-> B.Bi5?; +rel A.Bi6? <-> B.Bi6*; + +rel A.Bi7* <-> B.Bi7; +rel A.Bi8* <-> B.Bi8?; +rel A.Bi9* <-> B.Bi9*; diff --git a/src/test/java/org/jastadd/relast/tests/ResolverHelper.java b/src/test/java/org/jastadd/relast/tests/ResolverHelper.java index 3e3eeff..783c6d5 100644 --- a/src/test/java/org/jastadd/relast/tests/ResolverHelper.java +++ b/src/test/java/org/jastadd/relast/tests/ResolverHelper.java @@ -7,7 +7,10 @@ import resolver.ast.B; import resolver.ast.NamedElement; import resolver.ast.Root; -import static org.junit.jupiter.api.Assertions.assertSame; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; @SuppressWarnings("ArraysAsListWithZeroOrOneArgument") class ResolverHelper { @@ -31,6 +34,723 @@ class ResolverHelper { 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.setBi1(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.getBi1()); + assertSame(a1, b1.getBi1()); + + // create another, unrelated relation, perform the same tests + a2.setBi1(B.createRef("b2")); + assertNull(b2.getBi1()); + assertSame(b2, a2.getBi1()); + assertSame(a2, b2.getBi1()); + + // change the relation of a2 to overwrite the existing one in a1<->b1 + a2.setBi1(B.createRef("b1")); + + // as long as no resolution took place, the old reference still exists + assertSame(b1, a1.getBi1()); + assertSame(a1, b1.getBi1()); + + // now, we resolve a2->b1 + assertSame(b1, a2.getBi1()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.getBi1(), b1); + assertSame(b1.getBi1(), a2); + assertNull(a1.getBi1()); + assertNull(b2.getBi1()); + } + + @Test + void testBi12() { + // Init + setup(); + a1.setBi1(B.createRef("b2")); + + // Change + a2.setBi1(B.createRef("b2")); + + // unresolved + assertNull(b2.getBi1()); + + assertSame(b2, a1.getBi1()); + // a1 resolved + assertSame(a1, b2.getBi1()); + + // now resolve the change: + assertSame(b2, a2.getBi1()); + + // now finally, a1->null + assertNull(a1.getBi1()); + assertSame(a2.getBi1(), b2); + assertNull(b1.getBi1()); + assertSame(b2.getBi1(), a2); + } + + + /** + * rel A.Bi2 <-> B.Bi2?; + */ + + @Test + void testBi21() { + // Init + setup(); + a1.setBi2(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.getBi2()); + assertSame(a1, b1.getBi2()); + + // create another, unrelated relation, perform the same tests + a2.setBi2(B.createRef("b2")); + assertNull(b2.getBi2()); + assertSame(b2, a2.getBi2()); + assertSame(a2, b2.getBi2()); + + // change the relation of a2 to overwrite the existing one in a1<->b1 + a2.setBi2(B.createRef("b1")); + + // as long as no resolution took place, the old reference still exists + assertSame(b1, a1.getBi2()); + assertSame(a1, b1.getBi2()); + + // now, we resolve a2->b1 + assertSame(b1, a2.getBi2()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.getBi2(), b1); + assertSame(b1.getBi2(), a2); + assertNull(a1.getBi2()); + assertNull(b2.getBi2()); + } + + @Test + void testBi22() { + // Init + setup(); + a1.setBi2(B.createRef("b2")); + + // Change + a2.setBi2(B.createRef("b2")); + + // unresolved + assertNull(b2.getBi2()); + + assertSame(b2, a1.getBi2()); + // a1 resolved + assertSame(a1, b2.getBi2()); + + // now resolve the change: + assertSame(b2, a2.getBi2()); + + // now finally, a1->null + assertNull(a1.getBi2()); + assertSame(a2.getBi2(), b2); + assertNull(b1.getBi2()); + assertSame(b2.getBi2(), a2); + } + + + + /** + * rel A.Bi3 <-> B.Bi3*; + */ + @Test + void testBi3() { + setup(); + a2.setBi3(B.createRef("b2")); + + assertNull(a1.getBi3()); + assertSame(a2.getBi3(), 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.setBi3(B.createRef("b3")); + + assertNull(a1.getBi3()); + assertSame(a2.getBi3(), 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.setBi3(B.createRef("b3")); + a3.setBi3(B.createRef("b3")); + + assertSame(a1.getBi3(), b3); + assertSame(a2.getBi3(), b3); + assertSame(a3.getBi3(), 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.setBi3(B.createRef("b1")); + + assertSame(a1.getBi3(), b3); + assertSame(a2.getBi3(), b1); + assertSame(a3.getBi3(), 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.setBi3(null); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + } + + + /** + * rel A.Bi4? <-> B.Bi4; + */ + @Test + void testBi41() { + // Init + setup(); + a1.setBi4(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.getBi4()); + assertSame(a1, b1.getBi4()); + + // create another, unrelated relation, perform the same tests + a2.setBi4(B.createRef("b2")); + assertNull(b2.getBi4()); + assertSame(b2, a2.getBi4()); + assertSame(a2, b2.getBi4()); + + // change the relation of a2 to overwrite the existing one in a1<->b1 + a2.setBi4(B.createRef("b1")); + + // as long as no resolution took place, the old reference still exists + assertSame(b1, a1.getBi4()); + assertSame(a1, b1.getBi4()); + + // now, we resolve a2->b1 + assertSame(b1, a2.getBi4()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.getBi4(), b1); + assertSame(b1.getBi4(), a2); + assertNull(a1.getBi4()); + assertNull(b2.getBi4()); + } + + @Test + void testBi42() { + // Init + setup(); + a1.setBi4(B.createRef("b2")); + + // Change + a2.setBi4(B.createRef("b2")); + + // unresolved + assertNull(b2.getBi4()); + + assertSame(b2, a1.getBi4()); + // a1 resolved + assertSame(a1, b2.getBi4()); + + // now resolve the change: + assertSame(b2, a2.getBi4()); + + // now finally, a1->null + assertNull(a1.getBi4()); + assertSame(a2.getBi4(), b2); + assertNull(b1.getBi4()); + assertSame(b2.getBi4(), a2); + } + + + /** + * rel A.Bi5? <-> B.Bi5?; + */ + @Test + void testBi51() { + // Init + setup(); + a1.setBi5(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.getBi5()); + assertSame(a1, b1.getBi5()); + + // create another, unrelated relation, perform the same tests + a2.setBi5(B.createRef("b2")); + assertNull(b2.getBi5()); + assertSame(b2, a2.getBi5()); + assertSame(a2, b2.getBi5()); + + // change the relation of a2 to overwrite the existing one in a1<->b1 + a2.setBi5(B.createRef("b1")); + + // as long as no resolution took place, the old reference still exists + assertSame(b1, a1.getBi5()); + assertSame(a1, b1.getBi5()); + + // now, we resolve a2->b1 + assertSame(b1, a2.getBi5()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.getBi5(), b1); + assertSame(b1.getBi5(), a2); + assertNull(a1.getBi5()); + assertNull(b2.getBi5()); + } + + @Test + void testBi52() { + // Init + setup(); + a1.setBi5(B.createRef("b2")); + + // Change + a2.setBi5(B.createRef("b2")); + + // unresolved + assertNull(b2.getBi5()); + + assertSame(b2, a1.getBi5()); + // a1 resolved + assertSame(a1, b2.getBi5()); + + // now resolve the change: + assertSame(b2, a2.getBi5()); + + // now finally, a1->null + assertNull(a1.getBi5()); + assertSame(a2.getBi5(), b2); + assertNull(b1.getBi5()); + assertSame(b2.getBi5(), a2); + } + + + /** + * rel A.Bi6? <-> B.Bi6*; + */ + @Test + void testBi6() { + setup(); + a2.setBi6(B.createRef("b2")); + + assertNull(a1.getBi6()); + assertSame(a2.getBi6(), 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.setBi6(B.createRef("b3")); + + assertNull(a1.getBi6()); + assertSame(a2.getBi6(), 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.setBi6(B.createRef("b3")); + a3.setBi6(B.createRef("b3")); + + assertSame(a1.getBi6(), b3); + assertSame(a2.getBi6(), b3); + assertSame(a3.getBi6(), 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.setBi6(B.createRef("b1")); + + assertSame(a1.getBi6(), b3); + assertSame(a2.getBi6(), b1); + assertSame(a3.getBi6(), 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.clearBi6(); + + assertSame(a1.getBi6(), b3); + assertNull(a2.getBi6()); + assertSame(a3.getBi6(), 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.hasBi6()); + assertFalse(a2.hasBi6()); + assertTrue(a3.hasBi6()); + } + + + /** + * rel A.Bi7* <-> B.Bi7; + */ + @Test + void testBi7() { + setup(); + a2.addBi7(B.createRef("b2")); + + // a1 list is empty + assertEquals(a1.getBi7s(), Arrays.asList()); + assertEquals(a1.getBi7List(), Arrays.asList()); + + // a2 list contains b2 (because resolution took place) + assertEquals(a2.getBi7s(), Arrays.asList(b2)); + assertEquals(a2.getBi7List(), 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.addBi7(B.createRef("b3")); + a1.addBi7(B.createRef("b2")); + + assertEquals(a1.getBi7s(), Arrays.asList(b2)); + assertEquals(a1.getBi7List(), Arrays.asList(b2)); + assertEquals(a2.getBi7s(), Arrays.asList(b3)); + assertEquals(a2.getBi7List(), Arrays.asList(b3)); + assertNull(b1.getBi7()); + assertSame(b2.getBi7(), a1); + assertSame(b3.getBi7(), a2); + + a1.addBi7(B.createRef("b1")); + + assertEquals(a1.getBi7s(), Arrays.asList(b2, b1)); + assertEquals(a1.getBi7List(), Arrays.asList(b2, b1)); + assertEquals(a2.getBi7s(), Arrays.asList(b3)); + assertEquals(a2.getBi7List(), Arrays.asList(b3)); + assertSame(b1.getBi7(), a1); + assertSame(b2.getBi7(), a1); + assertSame(b3.getBi7(), a2); + + a1.addBi7(B.createRef("b1")); + + assertEquals(a1.getBi7s(), Arrays.asList(b2, b1)); + assertEquals(a1.getBi7List(), Arrays.asList(b2, b1)); + assertEquals(a2.getBi7s(), Arrays.asList(b3)); + assertEquals(a2.getBi7List(), Arrays.asList(b3)); + assertSame(b1.getBi7(), a1); + assertSame(b2.getBi7(), a1); + assertSame(b3.getBi7(), a2); + + a1.removeBi7(b1); + + assertEquals(a1.getBi7s(), Arrays.asList(b2)); + assertEquals(a1.getBi7List(), Arrays.asList(b2)); + assertEquals(a2.getBi7s(), Arrays.asList(b3)); + assertEquals(a2.getBi7List(), Arrays.asList(b3)); + assertNull(b1.getBi7()); + assertSame(b2.getBi7(), a1); + assertSame(b3.getBi7(), a2); + } + + + /** + * rel A.Bi8* <-> B.Bi8?; + */ + @Test + void testBi8() { + setup(); + a2.addBi8(B.createRef("b2")); + + assertEquals(a1.getBi8s(), Arrays.asList()); + assertEquals(a1.getBi8List(), Arrays.asList()); + assertEquals(a2.getBi8s(), Arrays.asList(b2)); + assertEquals(a2.getBi8List(), Arrays.asList(b2)); + assertNull(b1.getBi8()); + assertSame(b2.getBi8(), a2); + assertNull(b3.getBi8()); + + a2.addBi8(B.createRef("b3")); + a1.addBi8(B.createRef("b2")); + + assertEquals(a1.getBi8s(), Arrays.asList(b2)); + assertEquals(a1.getBi8List(), Arrays.asList(b2)); + assertEquals(a2.getBi8s(), Arrays.asList(b3)); + assertEquals(a2.getBi8List(), Arrays.asList(b3)); + assertNull(b1.getBi8()); + assertSame(b2.getBi8(), a1); + assertSame(b3.getBi8(), a2); + + a1.addBi8(B.createRef("b1")); + + assertEquals(a1.getBi8s(), Arrays.asList(b2, b1)); + assertEquals(a1.getBi8List(), Arrays.asList(b2, b1)); + assertEquals(a2.getBi8s(), Arrays.asList(b3)); + assertEquals(a2.getBi8List(), Arrays.asList(b3)); + assertSame(b1.getBi8(), a1); + assertSame(b2.getBi8(), a1); + assertSame(b3.getBi8(), a2); + + a1.addBi8(B.createRef("b1")); + + assertEquals(a1.getBi8s(), Arrays.asList(b2, b1)); + assertEquals(a1.getBi8List(), Arrays.asList(b2, b1)); + assertEquals(a2.getBi8s(), Arrays.asList(b3)); + assertEquals(a2.getBi8List(), Arrays.asList(b3)); + assertSame(b1.getBi8(), a1); + assertSame(b2.getBi8(), a1); + assertSame(b3.getBi8(), a2); + + a1.removeBi8(b1); + + assertEquals(a1.getBi8s(), Arrays.asList(b2)); + assertEquals(a1.getBi8List(), Arrays.asList(b2)); + assertEquals(a2.getBi8s(), Arrays.asList(b3)); + assertEquals(a2.getBi8List(), Arrays.asList(b3)); + assertNull(b1.getBi8()); + assertSame(b2.getBi8(), a1); + assertSame(b3.getBi8(), a2); + } + + + /** + * rel A.Bi9* <-> B.Bi9*; + */ + @Test + void testBi9() { + setup(); + a1.addBi9(B.createRef("b1")); + a1.addBi9(B.createRef("b2")); + + assertEquals(a1.getBi9s(), Arrays.asList(b1, b2)); + assertEquals(a1.getBi9List(), Arrays.asList(b1, b2)); + assertEquals(a2.getBi9s(), Arrays.asList()); + assertEquals(a2.getBi9List(), Arrays.asList()); + assertEquals(a3.getBi9s(), Arrays.asList()); + assertEquals(a3.getBi9List(), 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.getBi9s(), Arrays.asList(b1, b2)); + assertEquals(a1.getBi9List(), Arrays.asList(b1, b2)); + assertEquals(a2.getBi9s(), Arrays.asList()); + assertEquals(a2.getBi9List(), Arrays.asList()); + assertEquals(a3.getBi9s(), Arrays.asList()); + assertEquals(a3.getBi9List(), 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.getBi9s(), Arrays.asList(b1, b2, b3, b3)); + assertEquals(a1.getBi9List(), Arrays.asList(b1, b2, b3, b3)); + assertEquals(a2.getBi9s(), Arrays.asList()); + assertEquals(a2.getBi9List(), Arrays.asList()); + assertEquals(a3.getBi9s(), Arrays.asList(b3)); + assertEquals(a3.getBi9List(), Arrays.asList(b3)); + + b3.removeBi9(a1); + + assertEquals(a1.getBi9s(), Arrays.asList(b1, b2, b3)); + assertEquals(a1.getBi9List(), Arrays.asList(b1, b2, b3)); + assertEquals(a2.getBi9s(), Arrays.asList()); + assertEquals(a2.getBi9List(), Arrays.asList()); + assertEquals(a3.getBi9s(), Arrays.asList(b3)); + assertEquals(a3.getBi9List(), 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.addBi7(B.createRef("b1")); + a1.addBi7(B.createRef("b2")); + try { + a1.getBi7s().add(B.createRef("b3")); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + + a1.addBi9(B.createRef("b1")); + a1.addBi9(B.createRef("b2")); + try { + a1.getBi9s().add(B.createRef("b3")); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + } + @BeforeEach void setup() { r = new Root(); -- GitLab