diff --git a/build.gradle b/build.gradle index 149926618f6de1bf2d5774cf5ea3b874ddc3726f..b87e92bca0da5825980e9885e4e0ae8d1a63d0d0 100644 --- a/build.gradle +++ b/build.gradle @@ -115,7 +115,7 @@ task preprocessRelationTest(type: JavaExec, group: 'verification') { classpath = sourceSets.main.runtimeClasspath main = 'org.jastadd.relast.compiler.Compiler' //noinspection GroovyAssignabilityCheck - args 'src/test/jastadd/relations/Relations.relast', '--file', '--grammarName=src/test/jastadd/relations/Relations' + args 'src/test/jastadd/relations/Relations.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/relations/Relations' } task doublePreprocessRelationTest(type: JavaExec, group: 'verification') { @@ -127,7 +127,7 @@ task doublePreprocessRelationTest(type: JavaExec, group: 'verification') { classpath = sourceSets.main.runtimeClasspath main = 'org.jastadd.relast.compiler.Compiler' //noinspection GroovyAssignabilityCheck - args 'src/test/jastadd/relations/Relations.ast', '--file', '--grammarName=src/test/jastadd/relations/Relations2' + args 'src/test/jastadd/relations/Relations.ast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/relations/Relations2' } task compileRelationTest(type: JavaExec, group: 'verification') { @@ -145,6 +145,59 @@ task compileRelationTest(type: JavaExec, group: 'verification') { 'src/test/jastadd/Utils.jadd' } +task preprocessDefaultNamesTest(type: JavaExec, group: 'verification') { + + doFirst { + delete 'src/test/jastadd/relations/Relations.ast', 'src/test/jastadd/relations/Relations.jadd' + } + + classpath = sourceSets.main.runtimeClasspath + main = 'org.jastadd.relast.compiler.Compiler' + args 'src/test/jastadd/relations/Relations.relast', '--file', '--grammarName=src/test/jastadd/relations/Relations' +} + +task compileDefaultNamesTest(type: JavaExec, group: 'verification') { + + doFirst { + delete 'src/test/java-gen/relations' + } + + classpath = sourceSets.main.runtimeClasspath + main = 'org.jastadd.JastAdd' + args '--o=src/test/java-gen/', '--package=defaultnames.ast', 'src/test/jastadd/relations/Relations.ast', 'src/test/jastadd/relations/Relations.jadd', 'src/test/jastadd/Utils.jadd' +} + +task preprocessDefaultNamesResolverTest(type: JavaExec, group: 'verification') { + + doFirst { + delete 'src/test/jastadd/resolver/Resolver.ast', 'src/test/jastadd/resolver/Resolver.jadd', 'src/test/jastadd/resolver/ResolverRefResolver.jadd' + } + + classpath = sourceSets.main.runtimeClasspath + main = 'org.jastadd.relast.compiler.Compiler' + args 'src/test/jastadd/resolver/Resolver.relast', '--file', '--grammarName=src/test/jastadd/resolver/Resolver', '--resolverHelper' +} + +task compileDefaultNamesResolverTest(type: JavaExec, group: 'verification') { + + doFirst { + delete 'src/test/java-gen/resolver' + } + + classpath = sourceSets.main.runtimeClasspath + main = 'org.jastadd.JastAdd' + //noinspection GroovyAssignabilityCheck + args '--o=src/test/java-gen/', + '--package=defaultnames.resolver.ast', + 'src/test/jastadd/resolver/Resolver.ast', + 'src/test/jastadd/resolver/Resolver.jadd', + 'src/test/jastadd/resolver/ResolverUtils.jadd', + 'src/test/jastadd/resolver/ResolverResolverStubs.jrag', + 'src/test/jastadd/resolver/ResolverRefResolver.jadd', + 'src/test/jastadd/resolver/MyRefResolver.jadd', + 'src/test/jastadd/Utils.jadd' +} + task preprocessLowerBoundsTest(type: JavaExec, group: 'verification') { doFirst { @@ -154,7 +207,7 @@ task preprocessLowerBoundsTest(type: JavaExec, group: 'verification') { classpath = sourceSets.main.runtimeClasspath main = 'org.jastadd.relast.compiler.Compiler' //noinspection GroovyAssignabilityCheck - args 'src/test/jastadd/lowerbounds/LowerBounds.relast', '--file', '--grammarName=src/test/jastadd/lowerbounds/LowerBounds' + args 'src/test/jastadd/lowerbounds/LowerBounds.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/lowerbounds/LowerBounds' } task compileLowerBoundsTest(type: JavaExec, group: 'verification') { @@ -181,7 +234,7 @@ task preprocessMultipleTest(type: JavaExec, group: 'verification') { classpath = sourceSets.main.runtimeClasspath main = 'org.jastadd.relast.compiler.Compiler' //noinspection GroovyAssignabilityCheck - args 'src/test/jastadd/multiple/Part1.relast', 'src/test/jastadd/multiple/Part2.relast', 'src/test/jastadd/multiple/Part3.relast', '--file', '--grammarName=src/test/jastadd/multiple/Multiple' + args 'src/test/jastadd/multiple/Part1.relast', '--useJastAddNames', 'src/test/jastadd/multiple/Part2.relast', 'src/test/jastadd/multiple/Part3.relast', '--file', '--grammarName=src/test/jastadd/multiple/Multiple' } task compileMultipleTest(type: JavaExec, group: 'verification') { @@ -208,7 +261,7 @@ task preprocessResolverTest(type: JavaExec, group: 'verification') { classpath = sourceSets.main.runtimeClasspath main = 'org.jastadd.relast.compiler.Compiler' //noinspection GroovyAssignabilityCheck - args 'src/test/jastadd/resolver/Resolver.relast', '--file', '--grammarName=src/test/jastadd/resolver/Resolver', '--resolverHelper' + args 'src/test/jastadd/resolver/Resolver.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/resolver/Resolver', '--resolverHelper' } task compileResolverTest(type: JavaExec, group: 'verification') { @@ -240,7 +293,7 @@ task preprocessResolver2Test(type: JavaExec, group: 'verification') { classpath = sourceSets.main.runtimeClasspath main = 'org.jastadd.relast.compiler.Compiler' //noinspection GroovyAssignabilityCheck - args 'src/test/jastadd/resolver2/Resolver.relast', '--file', '--grammarName=src/test/jastadd/resolver2/Resolver', '--resolverHelper' + args 'src/test/jastadd/resolver2/Resolver.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/resolver2/Resolver', '--resolverHelper' } task compileResolver2Test(type: JavaExec, group: 'verification') { @@ -271,7 +324,7 @@ task preprocessListNamesTest(type: JavaExec, group: 'verification') { classpath = sourceSets.main.runtimeClasspath main = 'org.jastadd.relast.compiler.Compiler' //noinspection GroovyAssignabilityCheck - args 'src/test/jastadd/listnames/ListNames.relast', '--file', '--grammarName=src/test/jastadd/listnames/ListNames', '--jastAddList=ListyMcListface' + args 'src/test/jastadd/listnames/ListNames.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/listnames/ListNames', '--jastAddList=ListyMcListface' } task compileListNamesTest(type: JavaExec, group: 'verification') { @@ -303,7 +356,7 @@ task preprocessSerializerTest(type: JavaExec, group: 'verification') { classpath = sourceSets.main.runtimeClasspath main = 'org.jastadd.relast.compiler.Compiler' //noinspection GroovyAssignabilityCheck - args 'src/test/jastadd/serializer/Serializer.relast', '--file', '--grammarName=src/test/jastadd/serializer/Serializer', '--serializer=jackson' + args 'src/test/jastadd/serializer/Serializer.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/serializer/Serializer', '--serializer=jackson' } task compileSerializerTest(type: JavaExec, group: 'verification') { @@ -334,6 +387,11 @@ test.dependsOn compileRelationTest compileRelationTest.dependsOn doublePreprocessRelationTest doublePreprocessRelationTest.dependsOn preprocessRelationTest +test.dependsOn compileDefaultNamesTest +compileDefaultNamesTest.dependsOn preprocessDefaultNamesTest +test.dependsOn compileDefaultNamesResolverTest +compileDefaultNamesResolverTest.dependsOn preprocessDefaultNamesResolverTest + test.dependsOn compileLowerBoundsTest compileLowerBoundsTest.dependsOn preprocessLowerBoundsTest @@ -348,6 +406,5 @@ compileResolver2Test.dependsOn preprocessResolver2Test test.dependsOn compileListNamesTest compileListNamesTest.dependsOn preprocessListNamesTest - test.dependsOn compileSerializerTest -compileSerializerTest.dependsOn preprocessSerializerTest \ No newline at end of file +compileSerializerTest.dependsOn preprocessSerializerTest diff --git a/src/main/jastadd/Backend.jadd b/src/main/jastadd/Backend.jadd index f4f43224957206f7e4949fb5d01850a11ff50c8b..3e294aaf9f80c0b4a61478ef01901083f2835592 100644 --- a/src/main/jastadd/Backend.jadd +++ b/src/main/jastadd/Backend.jadd @@ -5,6 +5,7 @@ aspect BackendAbstractGrammar { public static boolean ASTNode.resolverHelper = false; public static boolean ASTNode.serializer = false; + public static boolean ASTNode.useJastAddNames = false; public String Program.generateAbstractGrammar() { StringBuilder sb = new StringBuilder(); @@ -191,15 +192,19 @@ aspect BackendDirectedAPI { public void ManyRelationComponent.generateDirectedAPI(StringBuilder sb) { // Get - // getXs - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); - sb.append(".get" + nameCapitalized() + "s() {\n"); - sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); - sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl() + "."); + if (useJastAddNames) { + // getXs + sb.append("get" + nameCapitalized() + "s() {\n"); + sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); + sb.append(ind(1) + "}\n"); - // getXList - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); - sb.append(".get" + nameCapitalized() + "List() {\n"); + // getXList + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); + sb.append(".get" + nameCapitalized() + "List() {\n"); + } else { + sb.append(name() + "() {\n"); + } sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); // resolve the entire list if (resolverHelper | serializer) { @@ -223,6 +228,9 @@ aspect BackendDirectedAPI { // Add sb.append(ind(1) + "public void " + toTypeDecl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); @@ -234,7 +242,11 @@ aspect BackendDirectedAPI { sb.append(ind(1) + "}\n"); // Insert / add at specific position - sb.append(ind(1) + "public void " + toTypeDecl() + ".add" + nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); + sb.append(ind(1) + "public void " + toTypeDecl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); sb.append(ind(2) + "if (list == null) {\n"); @@ -246,6 +258,9 @@ aspect BackendDirectedAPI { // Remove sb.append(ind(1) + "public void " + toTypeDecl() + ".remove"); + if (!useJastAddNames) { + sb.append("From"); + } sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); @@ -256,8 +271,13 @@ aspect BackendDirectedAPI { } public void RelationComponent.generateGetOne(StringBuilder sb) { - sb.append(ind(1) + "public " + ofTypeDecl() + " " + toTypeDecl()); - sb.append(".get" + nameCapitalized() + "() {\n"); + sb.append(ind(1) + "public " + ofTypeDecl() + " " + toTypeDecl() + "."); + if (useJastAddNames) { + sb.append("get" + nameCapitalized()); + } else { + sb.append(name()); + } + sb.append("() {\n"); if (resolverHelper | serializer) { sb.append(ind(2) + "if (get" + getImplAttributeName() + "() != null && get" + getImplAttributeName() + "().unresolved()) {\n"); sb.append(ind(3) + "if (get" + getImplAttributeName() + "().asUnresolved().get__resolve_opposite()) {\n"); @@ -275,7 +295,13 @@ aspect BackendDirectedAPI { // has sb.append(ind(1) + "public boolean " + toTypeDecl()); sb.append(".has" + nameCapitalized() + "() {\n"); - sb.append(ind(2) + "return get" + nameCapitalized() + "() != null;\n"); + sb.append(ind(2) + "return "); + if (useJastAddNames) { + sb.append("get" + nameCapitalized()); + } else { + sb.append(name()); + } + sb.append("() != null;\n"); sb.append(ind(1) + "}\n"); // clear @@ -379,15 +405,19 @@ aspect BackendBidirectionalAPI { public void RelationComponent.generateBiManyMany(StringBuilder sb, RelationComponent opposite) { // Get - // getXs - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); - sb.append(".get" + nameCapitalized() + "s() {\n"); - sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); - sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl() + "."); + if (useJastAddNames) { + // getXs + sb.append("get" + nameCapitalized() + "s() {\n"); + sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); + sb.append(ind(1) + "}\n"); - // getXList - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); - sb.append(".get" + nameCapitalized() + "List() {\n"); + // getXList + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); + sb.append(".get" + nameCapitalized() + "List() {\n"); + } else { + sb.append(name() + "() {\n"); + } sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); // resolve the entire list if (resolverHelper | serializer) { @@ -419,6 +449,9 @@ aspect BackendBidirectionalAPI { // Add sb.append(ind(1) + "public void " + toTypeDecl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); @@ -437,7 +470,11 @@ aspect BackendBidirectionalAPI { sb.append(ind(1) + "}\n"); // Insert / add at specific position - sb.append(ind(1) + "public void " + toTypeDecl() + ".add" + nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); + sb.append(ind(1) + "public void " + toTypeDecl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); sb.append(ind(2) + "if (list == null) {\n"); @@ -456,6 +493,9 @@ aspect BackendBidirectionalAPI { // Remove sb.append(ind(1) + "public void " + toTypeDecl() + ".remove"); + if (!useJastAddNames) { + sb.append("From"); + } sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); @@ -472,15 +512,19 @@ aspect BackendBidirectionalAPI { public void RelationComponent.generateBiManyOne(StringBuilder sb, RelationComponent opposite) { // Get - // getXs - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); - sb.append(".get" + nameCapitalized() + "s() {\n"); - sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); - sb.append(ind(1) + "}\n"); + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl() + "."); + if (useJastAddNames) { + // getXs + sb.append("get" + nameCapitalized() + "s() {\n"); + sb.append(ind(2) + "return get" + nameCapitalized() + "List();\n"); + sb.append(ind(1) + "}\n"); - // getXList - sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); - sb.append(".get" + nameCapitalized() + "List() {\n"); + // getXList + sb.append(ind(1) + "public java.util.List<" + ofTypeDecl() + "> " + toTypeDecl()); + sb.append(".get" + nameCapitalized() + "List() {\n"); + } else { + sb.append(name() + "() {\n"); + } sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> l = get" + getImplAttributeName() + "();\n"); // resolve the entire list if (resolverHelper | serializer) { @@ -518,6 +562,9 @@ aspect BackendBidirectionalAPI { // Add sb.append(ind(1) + "public void " + toTypeDecl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + "if (o != null && o.get" + otherSide().getImplAttributeName() + "() != null) {\n"); @@ -537,7 +584,11 @@ aspect BackendBidirectionalAPI { sb.append(ind(1) + "}\n"); // Insert / add at specific position - sb.append(ind(1) + "public void " + toTypeDecl() + ".add" + nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); + sb.append(ind(1) + "public void " + toTypeDecl() + ".add"); + if (!useJastAddNames) { + sb.append("To"); + } + sb.append(nameCapitalized() + "(int index, " + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + "if (o != null && o.get" + otherSide().getImplAttributeName() + "() != null) {\n"); sb.append(ind(3) + ASTNode.listClass + "<" + ofTypeDecl() + "> list2 = o.get" + otherSide().getImplAttributeName() + "().get" + getImplAttributeName() + "();\n"); @@ -555,6 +606,9 @@ aspect BackendBidirectionalAPI { // Remove sb.append(ind(1) + "public void " + toTypeDecl() + ".remove"); + if (!useJastAddNames) { + sb.append("From"); + } sb.append(nameCapitalized() + "(" + ofTypeDecl() + " o) {\n"); sb.append(ind(2) + "assertNotNull(o);\n"); sb.append(ind(2) + ASTNode.listClass + "<" + ofTypeDecl() + "> list = get" + getImplAttributeName() + "();\n"); @@ -649,7 +703,13 @@ aspect LowerBoundCheck { } public void OneRelationComponent.generateLowerBoundCheck(StringBuilder sb) { - sb.append(ind(2) + "if (get" + nameCapitalized() + "() == null) {\n"); + sb.append(ind(2) + "if ("); + if (useJastAddNames) { + sb.append("get" + nameCapitalized()); + } else { + sb.append(name()); + } + sb.append("() == null) {\n"); sb.append(ind(3) + "list.add(new Pair<>(this, \"" + name() + "\"));\n"); sb.append(ind(2) + "}\n"); } @@ -880,7 +940,13 @@ aspect NameResolutionHelper { sb.append(ind(1) + "// enforce resolving of all non-containment relations of the current non-terminal\n"); sb.append(ind(1) + "public void " + getID() + ".resolveAll() {\n"); for (RelationComponent relationComponent : relationComponents()) { - sb.append(ind(2) + "get" + relationComponent.nameCapitalized() + (relationComponent.isMany()?"List":"") + "();\n"); + sb.append(ind(2)); + if (useJastAddNames) { + sb.append("get" + relationComponent.nameCapitalized()); + } else { + sb.append(relationComponent.name()); + } + sb.append(relationComponent.isMany() && useJastAddNames ? "List" : "").append("();\n"); } sb.append(ind(2) + "super.resolveAll();\n"); sb.append(ind(1) + "}\n"); diff --git a/src/main/java/org/jastadd/relast/compiler/Compiler.java b/src/main/java/org/jastadd/relast/compiler/Compiler.java index 533b30d02bcffc1949207d4e24fc19a1ac925189..93afb42b34eba9a1718af25658ecd2a414916d00 100644 --- a/src/main/java/org/jastadd/relast/compiler/Compiler.java +++ b/src/main/java/org/jastadd/relast/compiler/Compiler.java @@ -21,6 +21,7 @@ public class Compiler { private StringOption optionGrammarName; private EnumOption optionSerializer; private FlagOption optionResolverHelper; + private FlagOption optionUseJastaddNames; private CommandLine commandLine; public Compiler(String[] args) throws CommandLineException { @@ -80,6 +81,11 @@ public class Compiler { ASTNode.listClass = optionListClass.getValue(); } + if (optionUseJastaddNames.isSet()) { + System.out.println("Using JastAdd names"); + ASTNode.useJastAddNames = true; + } + String grammarName = "Grammar"; if (optionGrammarName.isSet()) { grammarName = optionGrammarName.getValue(); @@ -143,6 +149,7 @@ public class Compiler { optionGrammarName = addOption(new StringOption("grammarName", "name of the generated grammar and aspect (without file extension)")); optionResolverHelper = addOption(new FlagOption("resolverHelper", "create a subtype for each type containing a string that can be used to resolve the type later")); optionJastAddList = addOption(new StringOption("jastAddList", "set the name of the List type in JastAdd (has to match the option '--List' or its default List)")); + optionUseJastaddNames = addOption(new FlagOption("useJastAddNames", "generate names in the form of addX, removeX and setX. If omitted, the default, original naming scheme resulting in addToX, removeFromX and setX will be used.")); optionSerializer = addOption(new EnumOption("serializer", "generate a (de-)serializer", Arrays.asList("jackson"), "jackson")); } diff --git a/src/test/java/org/jastadd/relast/tests/DefaultNames.java b/src/test/java/org/jastadd/relast/tests/DefaultNames.java new file mode 100644 index 0000000000000000000000000000000000000000..1335e1ef1ba7b7fabf340b716b0d7e9a87a64a3f --- /dev/null +++ b/src/test/java/org/jastadd/relast/tests/DefaultNames.java @@ -0,0 +1,561 @@ +package org.jastadd.relast.tests; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import defaultnames.ast.A; +import defaultnames.ast.B; +import defaultnames.ast.Root; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Arrays; + +import static org.jastadd.relast.tests.TestHelpers.readFile; +import static org.junit.jupiter.api.Assertions.*; + + +@SuppressWarnings({"ArraysAsListWithZeroOrOneArgument", "Duplicates"}) +class DefaultNames { + private Root r; + private A a1; + private A a2; + private A a3; + private B b1; + private B b2; + private B b3; + + @Test + void doubleRelastRun() throws IOException { + + String firstRun = "./src/test/jastadd/relations/Relations.ast"; + String secondRun = "./src/test/jastadd/relations/Relations2.ast"; + + + String first = readFile(firstRun, Charset.defaultCharset()); + String second = readFile(secondRun, Charset.defaultCharset()); + + Assertions.assertEquals(first, second); + } + + /** + * rel A.Di1 -> B; + */ + @Test + void testDi1() { + setup(); + a1.setDi1(b2); + a2.setDi1(b1); + + assertSame(a1.Di1(), b2); + assertSame(a2.Di1(), b1); + + a2.setDi1(b2); + + assertSame(a1.Di1(), b2); + assertSame(a2.Di1(), b2); + + try { + a3.setDi1(null); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + } + + + /** + * rel A.Di2? -> B; + */ + @Test + void testDi2() { + setup(); + a1.setDi2(b2); + a2.setDi2(b1); + + assertSame(a1.Di2(), b2); + assertSame(a2.Di2(), b1); + + a2.setDi2(b2); + + assertSame(a1.Di2(), b2); + assertSame(a2.Di2(), b2); + + a2.clearDi2(); + + assertSame(a1.Di2(), b2); + assertNull(a2.Di2()); + + assertTrue(a1.hasDi2()); + assertFalse(a2.hasDi2()); + assertFalse(a3.hasDi2()); + } + + + /** + * rel A.Di3* -> B; + */ + @Test + void testDi3() { + setup(); + a1.addToDi3(b1); + a1.addToDi3(b2); + a1.addToDi3(b3); + a2.addToDi3(b2); + + assertEquals(a1.Di3(), Arrays.asList(b1, b2, b3)); + assertEquals(a2.Di3(), Arrays.asList(b2)); + assertEquals(a3.Di3(), Arrays.asList()); + + a1.addToDi3(b1); + a2.addToDi3(b1); + a2.addToDi3(b2); + + assertEquals(a1.Di3(), Arrays.asList(b1, b2, b3, b1)); + assertEquals(a2.Di3(), Arrays.asList(b2, b1, b2)); + assertEquals(a3.Di3(), Arrays.asList()); + + a1.removeFromDi3(b1); + a2.removeFromDi3(b2); + + assertEquals(a1.Di3(), Arrays.asList(b2, b3, b1)); + assertEquals(a2.Di3(), Arrays.asList(b1, b2)); + assertEquals(a3.Di3(), Arrays.asList()); + } + + + /** + * rel A.Bi1 <-> B.Bi1; + */ + + + @Test + void testBi11() { + // Init + setup(); + a1.setBi1(b1); + a2.setBi1(b2); + + // Change + a2.setBi1(b1); + + assertNull(a1.Bi1()); + assertSame(a2.Bi1(), b1); + assertSame(b1.Bi1(), a2); + assertNull(b2.Bi1()); + } + + @Test + void testBi12() { + // Init + setup(); + a1.setBi1(b2); + + // Change + a2.setBi1(b2); + + assertNull(a1.Bi1()); + assertSame(a2.Bi1(), b2); + assertNull(b1.Bi1()); + assertSame(b2.Bi1(), a2); + } + + + /** + * rel A.Bi2 <-> B.Bi2?; + */ + + @Test + void testBi21() { + // Init + setup(); + a1.setBi2(b1); + a2.setBi2(b2); + + // Change + a2.setBi2(b1); + + assertNull(a1.Bi2()); + assertSame(a2.Bi2(), b1); + assertSame(b1.Bi2(), a2); + assertNull(b2.Bi2()); + } + + @Test + void testBi22() { + // Init + setup(); + a1.setBi2(b2); + + // Change + a2.setBi2(b2); + + assertNull(a1.Bi2()); + assertSame(a2.Bi2(), b2); + assertNull(b1.Bi2()); + assertSame(b2.Bi2(), a2); + } + + + /** + * rel A.Bi3 <-> B.Bi3*; + */ + @Test + void testBi3() { + setup(); + a2.setBi3(b2); + + assertNull(a1.Bi3()); + assertSame(a2.Bi3(), b2); + assertEquals(b1.Bi3(), Arrays.asList()); + assertEquals(b2.Bi3(), Arrays.asList(a2)); + assertEquals(b3.Bi3(), Arrays.asList()); + + a2.setBi3(b3); + + assertNull(a1.Bi3()); + assertSame(a2.Bi3(), b3); + assertEquals(b1.Bi3(), Arrays.asList()); + assertEquals(b2.Bi3(), Arrays.asList()); + assertEquals(b3.Bi3(), Arrays.asList(a2)); + + a1.setBi3(b3); + a3.setBi3(b3); + + assertSame(a1.Bi3(), b3); + assertSame(a2.Bi3(), b3); + assertSame(a3.Bi3(), b3); + assertEquals(b1.Bi3(), Arrays.asList()); + assertEquals(b2.Bi3(), Arrays.asList()); + assertEquals(b3.Bi3(), Arrays.asList(a2, a1, a3)); + + a2.setBi3(b1); + + assertSame(a1.Bi3(), b3); + assertSame(a2.Bi3(), b1); + assertSame(a3.Bi3(), b3); + assertEquals(b1.Bi3(), Arrays.asList(a2)); + assertEquals(b2.Bi3(), Arrays.asList()); + assertEquals(b3.Bi3(), 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(b1); + a2.setBi4(b2); + + // Change + a2.setBi4(b1); + + assertNull(a1.Bi4()); + assertSame(a2.Bi4(), b1); + assertSame(b1.Bi4(), a2); + assertNull(b2.Bi4()); + } + + @Test + void testBi42() { + // Init + setup(); + a1.setBi4(b2); + + // Change + a2.setBi4(b2); + + assertNull(a1.Bi4()); + assertSame(a2.Bi4(), b2); + assertNull(b1.Bi4()); + assertSame(b2.Bi4(), a2); + } + + + /** + * rel A.Bi5? <-> B.Bi5?; + */ + @Test + void testBi51() { + // Init + setup(); + a1.setBi5(b1); + a2.setBi5(b2); + + // Change + a2.setBi5(b1); + + assertNull(a1.Bi5()); + assertSame(a2.Bi5(), b1); + assertSame(b1.Bi5(), a2); + assertNull(b2.Bi5()); + } + + @Test + void testBi52() { + // Init + setup(); + a1.setBi5(b2); + + // Change + a2.setBi5(b2); + + assertNull(a1.Bi5()); + assertSame(a2.Bi5(), b2); + assertNull(b1.Bi5()); + assertSame(b2.Bi5(), a2); + } + + + /** + * rel A.Bi6? <-> B.Bi6*; + */ + @Test + void testBi6() { + setup(); + a2.setBi6(b2); + + assertNull(a1.Bi6()); + assertSame(a2.Bi6(), b2); + assertEquals(b1.Bi6(), Arrays.asList()); + assertEquals(b2.Bi6(), Arrays.asList(a2)); + assertEquals(b3.Bi6(), Arrays.asList()); + + a2.setBi6(b3); + + assertNull(a1.Bi6()); + assertSame(a2.Bi6(), b3); + assertEquals(b1.Bi6(), Arrays.asList()); + assertEquals(b2.Bi6(), Arrays.asList()); + assertEquals(b3.Bi6(), Arrays.asList(a2)); + + a1.setBi6(b3); + a3.setBi6(b3); + + assertSame(a1.Bi6(), b3); + assertSame(a2.Bi6(), b3); + assertSame(a3.Bi6(), b3); + assertEquals(b1.Bi6(), Arrays.asList()); + assertEquals(b2.Bi6(), Arrays.asList()); + assertEquals(b3.Bi6(), Arrays.asList(a2, a1, a3)); + + a2.setBi6(b1); + + assertSame(a1.Bi6(), b3); + assertSame(a2.Bi6(), b1); + assertSame(a3.Bi6(), b3); + assertEquals(b1.Bi6(), Arrays.asList(a2)); + assertEquals(b2.Bi6(), Arrays.asList()); + assertEquals(b3.Bi6(), Arrays.asList(a1, a3)); + + a2.clearBi6(); + + assertSame(a1.Bi6(), b3); + assertNull(a2.Bi6()); + assertSame(a3.Bi6(), b3); + assertEquals(b1.Bi6(), Arrays.asList()); + assertEquals(b2.Bi6(), Arrays.asList()); + assertEquals(b3.Bi6(), Arrays.asList(a1, a3)); + + assertTrue(a1.hasBi6()); + assertFalse(a2.hasBi6()); + assertTrue(a3.hasBi6()); + } + + + /** + * rel A.Bi7* <-> B.Bi7; + */ + @Test + void testBi7() { + setup(); + a2.addToBi7(b2); + + assertEquals(a1.Bi7(), Arrays.asList()); + assertEquals(a2.Bi7(), Arrays.asList(b2)); + assertNull(b1.Bi7()); + assertSame(b2.Bi7(), a2); + assertNull(b3.Bi7()); + + a2.addToBi7(b3); + a1.addToBi7(b2); + + assertEquals(a1.Bi7(), Arrays.asList(b2)); + assertEquals(a2.Bi7(), Arrays.asList(b3)); + assertNull(b1.Bi7()); + assertSame(b2.Bi7(), a1); + assertSame(b3.Bi7(), a2); + + a1.addToBi7(b1); + + assertEquals(a1.Bi7(), Arrays.asList(b2, b1)); + assertEquals(a2.Bi7(), Arrays.asList(b3)); + assertSame(b1.Bi7(), a1); + assertSame(b2.Bi7(), a1); + assertSame(b3.Bi7(), a2); + + a1.addToBi7(b1); + + assertEquals(a1.Bi7(), Arrays.asList(b2, b1)); + assertEquals(a2.Bi7(), Arrays.asList(b3)); + assertSame(b1.Bi7(), a1); + assertSame(b2.Bi7(), a1); + assertSame(b3.Bi7(), a2); + + a1.removeFromBi7(b1); + + assertEquals(a1.Bi7(), Arrays.asList(b2)); + assertEquals(a2.Bi7(), Arrays.asList(b3)); + assertNull(b1.Bi7()); + assertSame(b2.Bi7(), a1); + assertSame(b3.Bi7(), a2); + } + + + /** + * rel A.Bi8* <-> B.Bi8?; + */ + @Test + void testBi8() { + setup(); + a2.addToBi8(b2); + + assertEquals(a1.Bi8(), Arrays.asList()); + assertEquals(a2.Bi8(), Arrays.asList(b2)); + assertNull(b1.Bi8()); + assertSame(b2.Bi8(), a2); + assertNull(b3.Bi8()); + + a2.addToBi8(b3); + a1.addToBi8(b2); + + assertEquals(a1.Bi8(), Arrays.asList(b2)); + assertEquals(a2.Bi8(), Arrays.asList(b3)); + assertNull(b1.Bi8()); + assertSame(b2.Bi8(), a1); + assertSame(b3.Bi8(), a2); + + a1.addToBi8(b1); + + assertEquals(a1.Bi8(), Arrays.asList(b2, b1)); + assertEquals(a2.Bi8(), Arrays.asList(b3)); + assertSame(b1.Bi8(), a1); + assertSame(b2.Bi8(), a1); + assertSame(b3.Bi8(), a2); + + a1.addToBi8(b1); + + assertEquals(a1.Bi8(), Arrays.asList(b2, b1)); + assertEquals(a2.Bi8(), Arrays.asList(b3)); + assertSame(b1.Bi8(), a1); + assertSame(b2.Bi8(), a1); + assertSame(b3.Bi8(), a2); + + a1.removeFromBi8(b1); + + assertEquals(a1.Bi8(), Arrays.asList(b2)); + assertEquals(a2.Bi8(), Arrays.asList(b3)); + assertNull(b1.Bi8()); + assertSame(b2.Bi8(), a1); + assertSame(b3.Bi8(), a2); + } + + + /** + * rel A.Bi9* <-> B.Bi9*; + */ + @Test + void testBi9() { + setup(); + a1.addToBi9(b1); + a1.addToBi9(b2); + + assertEquals(a1.Bi9(), Arrays.asList(b1, b2)); + assertEquals(a2.Bi9(), Arrays.asList()); + assertEquals(a3.Bi9(), Arrays.asList()); + assertEquals(b1.Bi9(), Arrays.asList(a1)); + assertEquals(b2.Bi9(), Arrays.asList(a1)); + assertEquals(b3.Bi9(), Arrays.asList()); + + b3.addToBi9(a1); + b3.addToBi9(a3); + b3.addToBi9(a1); + + assertEquals(a1.Bi9(), Arrays.asList(b1, b2, b3, b3)); + assertEquals(a2.Bi9(), Arrays.asList()); + assertEquals(a3.Bi9(), Arrays.asList(b3)); + assertEquals(b1.Bi9(), Arrays.asList(a1)); + assertEquals(b2.Bi9(), Arrays.asList(a1)); + assertEquals(b3.Bi9(), Arrays.asList(a1, a3, a1)); + + b3.removeFromBi9(a1); + + assertEquals(a1.Bi9(), Arrays.asList(b1, b2, b3)); + assertEquals(a2.Bi9(), Arrays.asList()); + assertEquals(a3.Bi9(), Arrays.asList(b3)); + assertEquals(b1.Bi9(), Arrays.asList(a1)); + assertEquals(b2.Bi9(), Arrays.asList(a1)); + assertEquals(b3.Bi9(), Arrays.asList(a3, a1)); + } + + + @Test + void testImmutableList() { + setup(); + + a1.addToDi3(b1); + a1.addToDi3(b2); + try { + a1.Di3().add(b3); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + + a1.addToBi7(b1); + a1.addToBi7(b2); + try { + a1.Bi7().add(b3); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + + a1.addToBi9(b1); + a1.addToBi9(b2); + try { + a1.Bi9().add(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); + } +} diff --git a/src/test/java/org/jastadd/relast/tests/DefaultNamesResolverHelper.java b/src/test/java/org/jastadd/relast/tests/DefaultNamesResolverHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..defcbfa826be16abe6533e61b115944c707516fc --- /dev/null +++ b/src/test/java/org/jastadd/relast/tests/DefaultNamesResolverHelper.java @@ -0,0 +1,694 @@ +package org.jastadd.relast.tests; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import defaultnames.resolver.ast.A; +import defaultnames.resolver.ast.B; +import defaultnames.resolver.ast.NamedElement; +import defaultnames.resolver.ast.Root; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; + +@SuppressWarnings("ArraysAsListWithZeroOrOneArgument") +class DefaultNamesResolverHelper { + 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.Rel1().getClass().getSimpleName()); + assertSame(a1.Rel1(), b2); + } + + /** + * rel A.Di1 -> B; + */ + @Test + void testDi1() { + setup(); + a1.setDi1(B.createRef("b2")); + a2.setDi1(B.createRef("b1")); + + assertSame(a1.Di1(), b2); + assertSame(a2.Di1(), b1); + + a2.setDi1(b2); + + assertSame(a1.Di1(), b2); + assertSame(a2.Di1(), 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.Di2(), b2); + assertSame(a2.Di2(), b1); + + a2.setDi2(b2); + + assertSame(a1.Di2(), b2); + assertSame(a2.Di2(), b2); + + a2.clearDi2(); + + assertSame(a1.Di2(), b2); + assertNull(a2.Di2()); + + assertTrue(a1.hasDi2()); + assertFalse(a2.hasDi2()); + assertFalse(a3.hasDi2()); + } + + + /** + * rel A.Di3* -> B; + */ + @Test + void testDi3() { + setup(); + a1.addToDi3(B.createRef("b1")); + a1.addToDi3(B.createRef("b2")); + a1.addToDi3(B.createRef("b3")); + a2.addToDi3(B.createRef("b2")); + + assertEquals(a1.Di3(), Arrays.asList(b1, b2, b3)); + assertEquals(a2.Di3(), Arrays.asList(b2)); + assertEquals(a3.Di3(), Arrays.asList()); + + a1.addToDi3(B.createRef("b1")); + a2.addToDi3(B.createRef("b1")); + a2.addToDi3(B.createRef("b2")); + + assertEquals(a1.Di3(), Arrays.asList(b1, b2, b3, b1)); + assertEquals(a2.Di3(), Arrays.asList(b2, b1, b2)); + assertEquals(a3.Di3(), Arrays.asList()); + + a1.removeFromDi3(b1); + a2.removeFromDi3(b2); + + assertEquals(a1.Di3(), Arrays.asList(b2, b3, b1)); + assertEquals(a2.Di3(), Arrays.asList(b1, b2)); + assertEquals(a3.Di3(), 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.Bi1()); + + // now, the relation is resolved, and thus the opposite direction is also set + assertSame(b1, a1.Bi1()); + assertSame(a1, b1.Bi1()); + + // create another, unrelated relation, perform the same tests + a2.setBi1(B.createRef("b2")); + assertNull(b2.Bi1()); + assertSame(b2, a2.Bi1()); + assertSame(a2, b2.Bi1()); + + // 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.Bi1()); + assertSame(a1, b1.Bi1()); + + // now, we resolve a2->b1 + assertSame(b1, a2.Bi1()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.Bi1(), b1); + assertSame(b1.Bi1(), a2); + assertNull(a1.Bi1()); + assertNull(b2.Bi1()); + } + + @Test + void testBi12() { + // Init + setup(); + a1.setBi1(B.createRef("b2")); + + // Change + a2.setBi1(B.createRef("b2")); + + // unresolved + assertNull(b2.Bi1()); + + assertSame(b2, a1.Bi1()); + // a1 resolved + assertSame(a1, b2.Bi1()); + + // now resolve the change: + assertSame(b2, a2.Bi1()); + + // now finally, a1->null + assertNull(a1.Bi1()); + assertSame(a2.Bi1(), b2); + assertNull(b1.Bi1()); + assertSame(b2.Bi1(), 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.Bi2()); + + // now, the relation is resolved, and thus the opposite direction is also set + assertSame(b1, a1.Bi2()); + assertSame(a1, b1.Bi2()); + + // create another, unrelated relation, perform the same tests + a2.setBi2(B.createRef("b2")); + assertNull(b2.Bi2()); + assertSame(b2, a2.Bi2()); + assertSame(a2, b2.Bi2()); + + // 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.Bi2()); + assertSame(a1, b1.Bi2()); + + // now, we resolve a2->b1 + assertSame(b1, a2.Bi2()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.Bi2(), b1); + assertSame(b1.Bi2(), a2); + assertNull(a1.Bi2()); + assertNull(b2.Bi2()); + } + + @Test + void testBi22() { + // Init + setup(); + a1.setBi2(B.createRef("b2")); + + // Change + a2.setBi2(B.createRef("b2")); + + // unresolved + assertNull(b2.Bi2()); + + assertSame(b2, a1.Bi2()); + // a1 resolved + assertSame(a1, b2.Bi2()); + + // now resolve the change: + assertSame(b2, a2.Bi2()); + + // now finally, a1->null + assertNull(a1.Bi2()); + assertSame(a2.Bi2(), b2); + assertNull(b1.Bi2()); + assertSame(b2.Bi2(), a2); + } + + + + /** + * rel A.Bi3 <-> B.Bi3*; + */ + @Test + void testBi3() { + setup(); + a2.setBi3(B.createRef("b2")); + + assertNull(a1.Bi3()); + assertSame(a2.Bi3(), b2); + assertEquals(b1.Bi3(), Arrays.asList()); + assertEquals(b2.Bi3(), Arrays.asList(a2)); + assertEquals(b3.Bi3(), Arrays.asList()); + + a2.setBi3(B.createRef("b3")); + + assertNull(a1.Bi3()); + assertSame(a2.Bi3(), b3); + assertEquals(b1.Bi3(), Arrays.asList()); + assertEquals(b2.Bi3(), Arrays.asList()); + assertEquals(b3.Bi3(), Arrays.asList(a2)); + + a1.setBi3(B.createRef("b3")); + a3.setBi3(B.createRef("b3")); + + assertSame(a1.Bi3(), b3); + assertSame(a2.Bi3(), b3); + assertSame(a3.Bi3(), b3); + assertEquals(b1.Bi3(), Arrays.asList()); + assertEquals(b2.Bi3(), Arrays.asList()); + assertEquals(b3.Bi3(), Arrays.asList(a2, a1, a3)); + + a2.setBi3(B.createRef("b1")); + + assertSame(a1.Bi3(), b3); + assertSame(a2.Bi3(), b1); + assertSame(a3.Bi3(), b3); + assertEquals(b1.Bi3(), Arrays.asList(a2)); + assertEquals(b2.Bi3(), Arrays.asList()); + assertEquals(b3.Bi3(), 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.Bi4()); + + // now, the relation is resolved, and thus the opposite direction is also set + assertSame(b1, a1.Bi4()); + assertSame(a1, b1.Bi4()); + + // create another, unrelated relation, perform the same tests + a2.setBi4(B.createRef("b2")); + assertNull(b2.Bi4()); + assertSame(b2, a2.Bi4()); + assertSame(a2, b2.Bi4()); + + // 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.Bi4()); + assertSame(a1, b1.Bi4()); + + // now, we resolve a2->b1 + assertSame(b1, a2.Bi4()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.Bi4(), b1); + assertSame(b1.Bi4(), a2); + assertNull(a1.Bi4()); + assertNull(b2.Bi4()); + } + + @Test + void testBi42() { + // Init + setup(); + a1.setBi4(B.createRef("b2")); + + // Change + a2.setBi4(B.createRef("b2")); + + // unresolved + assertNull(b2.Bi4()); + + assertSame(b2, a1.Bi4()); + // a1 resolved + assertSame(a1, b2.Bi4()); + + // now resolve the change: + assertSame(b2, a2.Bi4()); + + // now finally, a1->null + assertNull(a1.Bi4()); + assertSame(a2.Bi4(), b2); + assertNull(b1.Bi4()); + assertSame(b2.Bi4(), 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.Bi5()); + + // now, the relation is resolved, and thus the opposite direction is also set + assertSame(b1, a1.Bi5()); + assertSame(a1, b1.Bi5()); + + // create another, unrelated relation, perform the same tests + a2.setBi5(B.createRef("b2")); + assertNull(b2.Bi5()); + assertSame(b2, a2.Bi5()); + assertSame(a2, b2.Bi5()); + + // 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.Bi5()); + assertSame(a1, b1.Bi5()); + + // now, we resolve a2->b1 + assertSame(b1, a2.Bi5()); + + // now the final situation should be a2<->b1, a1->null, b2->null + assertSame(a2.Bi5(), b1); + assertSame(b1.Bi5(), a2); + assertNull(a1.Bi5()); + assertNull(b2.Bi5()); + } + + @Test + void testBi52() { + // Init + setup(); + a1.setBi5(B.createRef("b2")); + + // Change + a2.setBi5(B.createRef("b2")); + + // unresolved + assertNull(b2.Bi5()); + + assertSame(b2, a1.Bi5()); + // a1 resolved + assertSame(a1, b2.Bi5()); + + // now resolve the change: + assertSame(b2, a2.Bi5()); + + // now finally, a1->null + assertNull(a1.Bi5()); + assertSame(a2.Bi5(), b2); + assertNull(b1.Bi5()); + assertSame(b2.Bi5(), a2); + } + + + /** + * rel A.Bi6? <-> B.Bi6*; + */ + @Test + void testBi6() { + setup(); + a2.setBi6(B.createRef("b2")); + + assertNull(a1.Bi6()); + assertSame(a2.Bi6(), b2); + assertEquals(b1.Bi6(), Arrays.asList()); + assertEquals(b2.Bi6(), Arrays.asList(a2)); + assertEquals(b3.Bi6(), Arrays.asList()); + + a2.setBi6(B.createRef("b3")); + + assertNull(a1.Bi6()); + assertSame(a2.Bi6(), b3); + assertEquals(b1.Bi6(), Arrays.asList()); + assertEquals(b2.Bi6(), Arrays.asList()); + assertEquals(b3.Bi6(), Arrays.asList(a2)); + + a1.setBi6(B.createRef("b3")); + a3.setBi6(B.createRef("b3")); + + assertSame(a1.Bi6(), b3); + assertSame(a2.Bi6(), b3); + assertSame(a3.Bi6(), b3); + assertEquals(b1.Bi6(), Arrays.asList()); + assertEquals(b2.Bi6(), Arrays.asList()); + assertEquals(b3.Bi6(), Arrays.asList(a2, a1, a3)); + + a2.setBi6(B.createRef("b1")); + + assertSame(a1.Bi6(), b3); + assertSame(a2.Bi6(), b1); + assertSame(a3.Bi6(), b3); + assertEquals(b1.Bi6(), Arrays.asList(a2)); + assertEquals(b2.Bi6(), Arrays.asList()); + assertEquals(b3.Bi6(), Arrays.asList(a1, a3)); + + a2.clearBi6(); + + assertSame(a1.Bi6(), b3); + assertNull(a2.Bi6()); + assertSame(a3.Bi6(), b3); + assertEquals(b1.Bi6(), Arrays.asList()); + assertEquals(b2.Bi6(), Arrays.asList()); + assertEquals(b3.Bi6(), Arrays.asList(a1, a3)); + + assertTrue(a1.hasBi6()); + assertFalse(a2.hasBi6()); + assertTrue(a3.hasBi6()); + } + + + /** + * rel A.Bi7* <-> B.Bi7; + */ + @Test + void testBi7() { + setup(); + a2.addToBi7(B.createRef("b2")); + + // a1 list is empty + assertEquals(a1.Bi7(), Arrays.asList()); + + // a2 list contains b2 (because resolution took place) + assertEquals(a2.Bi7(), Arrays.asList(b2)); + + // of all the bs, only b2 contains a back ref to a2 + assertNull(b1.Bi7()); + assertSame(b2.Bi7(), a2); + assertNull(b3.Bi7()); + + a2.addToBi7(B.createRef("b3")); + a1.addToBi7(B.createRef("b2")); + + assertEquals(a1.Bi7(), Arrays.asList(b2)); + assertEquals(a2.Bi7(), Arrays.asList(b3)); + assertNull(b1.Bi7()); + assertSame(b2.Bi7(), a1); + assertSame(b3.Bi7(), a2); + + a1.addToBi7(B.createRef("b1")); + + assertEquals(a1.Bi7(), Arrays.asList(b2, b1)); + assertEquals(a2.Bi7(), Arrays.asList(b3)); + assertSame(b1.Bi7(), a1); + assertSame(b2.Bi7(), a1); + assertSame(b3.Bi7(), a2); + + a1.addToBi7(B.createRef("b1")); + + assertEquals(a1.Bi7(), Arrays.asList(b2, b1)); + assertEquals(a2.Bi7(), Arrays.asList(b3)); + assertSame(b1.Bi7(), a1); + assertSame(b2.Bi7(), a1); + assertSame(b3.Bi7(), a2); + + a1.removeFromBi7(b1); + + assertEquals(a1.Bi7(), Arrays.asList(b2)); + assertEquals(a2.Bi7(), Arrays.asList(b3)); + assertNull(b1.Bi7()); + assertSame(b2.Bi7(), a1); + assertSame(b3.Bi7(), a2); + } + + + /** + * rel A.Bi8* <-> B.Bi8?; + */ + @Test + void testBi8() { + setup(); + a2.addToBi8(B.createRef("b2")); + + assertEquals(a1.Bi8(), Arrays.asList()); + assertEquals(a2.Bi8(), Arrays.asList(b2)); + assertNull(b1.Bi8()); + assertSame(b2.Bi8(), a2); + assertNull(b3.Bi8()); + + a2.addToBi8(B.createRef("b3")); + a1.addToBi8(B.createRef("b2")); + + assertEquals(a1.Bi8(), Arrays.asList(b2)); + assertEquals(a2.Bi8(), Arrays.asList(b3)); + assertNull(b1.Bi8()); + assertSame(b2.Bi8(), a1); + assertSame(b3.Bi8(), a2); + + a1.addToBi8(B.createRef("b1")); + + assertEquals(a1.Bi8(), Arrays.asList(b2, b1)); + assertEquals(a2.Bi8(), Arrays.asList(b3)); + assertSame(b1.Bi8(), a1); + assertSame(b2.Bi8(), a1); + assertSame(b3.Bi8(), a2); + + a1.addToBi8(B.createRef("b1")); + + assertEquals(a1.Bi8(), Arrays.asList(b2, b1)); + assertEquals(a2.Bi8(), Arrays.asList(b3)); + assertSame(b1.Bi8(), a1); + assertSame(b2.Bi8(), a1); + assertSame(b3.Bi8(), a2); + + a1.removeFromBi8(b1); + + assertEquals(a1.Bi8(), Arrays.asList(b2)); + assertEquals(a2.Bi8(), Arrays.asList(b3)); + assertNull(b1.Bi8()); + assertSame(b2.Bi8(), a1); + assertSame(b3.Bi8(), a2); + } + + + /** + * rel A.Bi9* <-> B.Bi9*; + */ + @Test + void testBi9() { + setup(); + a1.addToBi9(B.createRef("b1")); + a1.addToBi9(B.createRef("b2")); + + assertEquals(a1.Bi9(), Arrays.asList(b1, b2)); + assertEquals(a2.Bi9(), Arrays.asList()); + assertEquals(a3.Bi9(), Arrays.asList()); + assertEquals(b1.Bi9(), Arrays.asList(a1)); + assertEquals(b2.Bi9(), Arrays.asList(a1)); + assertEquals(b3.Bi9(), Arrays.asList()); + + b3.addToBi9(A.createRef("a1")); + b3.addToBi9(A.createRef("a3")); + b3.addToBi9(A.createRef("a1")); + + // b3 is not resolved yet, so the as look like before + assertEquals(a1.Bi9(), Arrays.asList(b1, b2)); + assertEquals(a2.Bi9(), Arrays.asList()); + assertEquals(a3.Bi9(), Arrays.asList()); + + // let's resolve b3 + assertEquals(b1.Bi9(), Arrays.asList(a1)); + assertEquals(b2.Bi9(), Arrays.asList(a1)); + assertEquals(b3.Bi9(), Arrays.asList(a1, a3, a1)); + + // now the as are updated + assertEquals(a1.Bi9(), Arrays.asList(b1, b2, b3, b3)); + assertEquals(a2.Bi9(), Arrays.asList()); + assertEquals(a3.Bi9(), Arrays.asList(b3)); + + b3.removeFromBi9(a1); + + assertEquals(a1.Bi9(), Arrays.asList(b1, b2, b3)); + assertEquals(a2.Bi9(), Arrays.asList()); + assertEquals(a3.Bi9(), Arrays.asList(b3)); + assertEquals(b1.Bi9(), Arrays.asList(a1)); + assertEquals(b2.Bi9(), Arrays.asList(a1)); + assertEquals(b3.Bi9(), Arrays.asList(a3, a1)); + } + + + @Test + void testImmutableList() { + setup(); + + a1.addToDi3(B.createRef("b1")); + a1.addToDi3(B.createRef("b2")); + try { + a1.Di3().add(b3); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + + a1.addToBi7(B.createRef("b1")); + a1.addToBi7(B.createRef("b2")); + try { + a1.Bi7().add(B.createRef("b3")); + fail("should throw an exception"); + } catch (Exception e) { + // OK + } + + a1.addToBi9(B.createRef("b1")); + a1.addToBi9(B.createRef("b2")); + try { + a1.Bi9().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); + } + +}