diff --git a/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd b/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd index da358f6f9c591f5ef5ce6e392219ca30169a0984..7e4bde916d565d16bdef34598d638d2080f2f5fa 100644 --- a/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd +++ b/ragconnect.base/src/main/jastadd/intermediate/Generation.jadd @@ -102,8 +102,8 @@ aspect AttributesForMustache { return preemptiveExpectedValue() + " == " + lastResult(); } if (endpointDef().isReceiveTypeEndpointDefinition() && endpointDef().asReceiveTypeEndpointDefinition().getWithAdd()) { - // only check if received list is empty (may also be skipped, since addAll would not do anything anyways) - return lastResult() + " == null || " + lastResult() + ".numChildren() == 0"; + // only check if received list is not null + return lastResult() + " == null"; } if (endpointDef().isTypeEndpointDefinition() && type().isOptComponent()) { // use "hasX()" instead of "getX() != null" for optionals diff --git a/ragconnect.tests/build.gradle b/ragconnect.tests/build.gradle index fdea9d0ae1751e509bbcc37ef97b1b9840a327c3..61470f5292531d0ec7ca5d3691a3b248bcff1588 100644 --- a/ragconnect.tests/build.gradle +++ b/ragconnect.tests/build.gradle @@ -503,3 +503,62 @@ task compileSingleListIncremental(type: RagConnectTest, dependsOn: ':ragconnect. '--flush=full'] } } + +// --- Test: singleListVariant-manual --- +task compileSingleListVariantManual(type: RagConnectTest, dependsOn: ':ragconnect.base:jar') { + ragconnect { + outputDir = file('src/test/02-after-ragconnect/singleListVariant') + inputFiles = [file('src/test/01-input/singleListVariant/Test.relast'), + file('src/test/01-input/singleListVariant/Test.connect'), + file('src/test/01-input/singleListVariant/TestDependencies.connect')] + rootNode = 'Root' + } + relast { + useJastAddNames = true + grammarName = 'src/test/03-after-relast/singleListVariant/singleListVariant' + serializer = 'jackson' + } + jastadd { + jastAddList = 'JastAddList' + packageName = 'singleListVariant.ast' + inputFiles = [file('src/test/01-input/singleListVariant/Test.jadd')] + } +} + +// --- Test: singleListVariant-incremental --- +task compileSingleListVariantIncremental(type: RagConnectTest, dependsOn: ':ragconnect.base:jar') { + ragconnect { + outputDir = file('src/test/02-after-ragconnect/singleListVariantInc') + inputFiles = [file('src/test/01-input/singleListVariant/Test.relast'), + file('src/test/01-input/singleListVariant/Test.connect')] + rootNode = 'Root' + } + relast { + useJastAddNames = true + grammarName = 'src/test/03-after-relast/singleListVariantInc/singleListVariantInc' + serializer = 'jackson' + } + jastadd { + jastAddList = 'JastAddList' + packageName = 'singleListVariantInc.ast' + inputFiles = [file('src/test/01-input/singleListVariant/Test.jadd')] + extraOptions = ['--tracing=cache,flush', + '--incremental=param', + '--cache=all', + '--rewrite=cnta', + '--flush=full'] + } +} + +//task cleanCurrentManualTest(type: Delete) { +// delete "src/test/02-after-ragconnect/singleListVariant" +// delete "src/test/03-after-relast/singleListVariant" +// delete "src/test/java-gen/singleListVariant/ast" +//} +//task cleanCurrentIncrementalTest(type: Delete) { +// delete "src/test/02-after-ragconnect/singleListVariantInc" +// delete "src/test/03-after-relast/singleListVariantInc" +// delete "src/test/java-gen/singleListVariantInc/ast" +//} +//compileSingleListVariantManual.dependsOn cleanCurrentManualTest +//compileSingleListVariantIncremental.dependsOn cleanCurrentIncrementalTest diff --git a/ragconnect.tests/src/test/01-input/singleList/Test.relast b/ragconnect.tests/src/test/01-input/singleList/Test.relast index 59e57d7f4c5d526b6831ea8fd090960f5d4c9e08..0d97bb6c6b2fa4be6a4628b5e7e45926817364d0 100644 --- a/ragconnect.tests/src/test/01-input/singleList/Test.relast +++ b/ragconnect.tests/src/test/01-input/singleList/Test.relast @@ -8,5 +8,4 @@ SenderRoot : Nameable ::= <Input1:int> /A1:A/ <InOutput:int> ; ReceiverRoot : Nameable ::= A* UsingWildcardA:A* WithAddA:A* UsingWildcardWithAddA:A* ; -A : Nameable ::= ; -B : Nameable ; +A : Nameable ; diff --git a/ragconnect.tests/src/test/01-input/singleListVariant/README.md b/ragconnect.tests/src/test/01-input/singleListVariant/README.md new file mode 100644 index 0000000000000000000000000000000000000000..4004ac42c136c25f2447efe5c1161c98754f32c1 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/singleListVariant/README.md @@ -0,0 +1,61 @@ +# Single List + +Idea: send and receive single values for lists of subtrees. +Test different variants of the structure/shape of the send/received value. + +## Execution-Model + +TODO: check again (old model copied from `singleList`) + +``` +SenderRoot/ReceiverRoot + |- T_Empty ::= /* empty */ ; + |- T_Token ::= <Value:String> ; + |- T_OneChild ::= Other ; + |- T_OneOpt ::= [Other] ; + |- T_OneList ::= Other* ; + |- T_TwoChildren ::= Left:Other Right:Other ; + |- T_OneOfEach ::= First:Other [Second:Other] Third:Other* <Fourth:String> ; + |- abstract T_Abstract ::= <ValueAbstract> ; +``` + +## Computation + +``` +T.ID = Input +T.token = Input +T.Other.ID = Input + 1 +``` + +## Execution-Trace (SendInitialValue) + +Inputs: + +- 1 +- 1 +- 2 +- 3 + +| Input | [A1,A2,A3,A4,IO] | # | A* | UsingWcA | WithAddA | UsingWcWithAddA:A | +|---|---|---|---|---|---|---| +| * | [1,2,3,4,0] | 5 | [1,2,3,4,0] | [1,2,3,4,0] | [1,2,3,4,0] | [1,2,3,4,0] | +| I1:1 | [2,2,3,4,0] | 6 | [2,2,3,4,0] | [2,2,3,4,0] | [1,2,3,4,0,2] | [1,2,3,4,0,2] | +| I1:1 | [2,2,3,4,0] | 6 | [2,2,3,4,0] | [2,2,3,4,0] | [1,2,3,4,0,2] | [1,2,3,4,0,2] | +| I1:2 | [3,2,3,4,0] | 7 | [3,2,3,4,0] | [3,2,3,4,0] | [1,2,3,4,0,2,3] | [1,2,3,4,0,2,3] | +| IO:5 | [3,2,3,4,5] | 8 | [3,2,3,4,5] | [3,2,3,4,5] | [1,2,3,4,0,2,3,5] | [1,2,3,4,0,2,3,5] +| I3:4 | [3,2,7,4,5] | 9 | [3,2,7,4,5] | [3,2,7,4,5] | [1,2,3,4,0,2,3,5,7] | [1,2,3,4,0,2,3,5,7] | + +*: (1:0, 2:0, 3:0, 4:0, 5:0) + +## Execution-Trace (OnlyUpdate) + +| Input | [A1,A2,A3,A4,IO] | # | A* | UsingWcA | WithAddA | UsingWcWithAddA:A | +|---|---|---|---|---|---|---| +| * | [-,-,-,-,-] | 0 | [0,0,0,0,0] | [] | [] | [] | +| I1:1 | [2,-,-,-,-] | 1 | [2,0,0,0,0] | [2] | [2] | [2] | +| I1:1 | [2,-,-,-,-] | 1 | [2,0,0,0,0] | [2] | [2] | [2] | +| I1:2 | [3,-,-,-,-] | 2 | [3,0,0,0,0] | [3] | [2,3] | [2,3] | +| IO:5 | [2,-,-,-,5] | 3 | [3,0,0,0,5] | [3,5] | [2,3,5] | [2,3,5] +| I3:4 | [2,-,7,-,5] | 4 | [3,0,7,0,5] | [3,5,7] | [2,3,5,7] | [2,3,5,7] | + +*: (1:0, 2:0, 3:0, 4:0, 5:0) diff --git a/ragconnect.tests/src/test/01-input/singleListVariant/Test.connect b/ragconnect.tests/src/test/01-input/singleListVariant/Test.connect new file mode 100644 index 0000000000000000000000000000000000000000..23365109901425e8a6060c3ef3c2d8fe4cfc7656 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/singleListVariant/Test.connect @@ -0,0 +1,28 @@ +send tree SenderRoot.T_Empty ; +send tree SenderRoot.T_Token ; +send tree SenderRoot.T_OneChild ; +send tree SenderRoot.T_OneOpt ; +send tree SenderRoot.T_OneList ; +send tree SenderRoot.T_TwoChildren ; +send tree SenderRoot.T_OneOfEach ; +send tree SenderRoot.T_Abstract ; + +receive tree ReceiverRoot.T_Empty ; +receive tree ReceiverRoot.T_Token ; +receive tree ReceiverRoot.T_OneChild ; +receive tree ReceiverRoot.T_OneOpt ; +receive tree ReceiverRoot.T_OneList ; +receive tree ReceiverRoot.T_TwoChildren ; +receive tree ReceiverRoot.T_OneOfEach ; +receive tree ReceiverRoot.T_Abstract ; + +receive tree ReceiverRoot.MyEmpty ; + +receive tree with add ReceiverRoot.EmptyWithAdd ; +receive tree with add ReceiverRoot.TokenWithAdd ; +receive tree with add ReceiverRoot.OneChildWithAdd ; +receive tree with add ReceiverRoot.OneOptWithAdd ; +receive tree with add ReceiverRoot.OneListWithAdd ; +receive tree with add ReceiverRoot.TwoChildrenWithAdd ; +receive tree with add ReceiverRoot.OneOfEachWithAdd ; +receive tree with add ReceiverRoot.AbstractWithAdd ; diff --git a/ragconnect.tests/src/test/01-input/singleListVariant/Test.jadd b/ragconnect.tests/src/test/01-input/singleListVariant/Test.jadd new file mode 100644 index 0000000000000000000000000000000000000000..10ed1174a4cbb99e46cd5ba582df829d547bd446 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/singleListVariant/Test.jadd @@ -0,0 +1,75 @@ +aspect Computation { + syn T_Empty SenderRoot.getT_Empty() = new T_Empty().setID(getInput()); + syn T_Token SenderRoot.getT_Token() = new T_Token().setID(getInput()) + .setValue(Integer.toString(getInput())); + syn T_OneChild SenderRoot.getT_OneChild() { + T_OneChild result = new T_OneChild().setID(getInput()); + result.setOther(createOther()); + return result; + } + syn T_OneOpt SenderRoot.getT_OneOpt() { + T_OneOpt result = new T_OneOpt().setID(getInput()); + if (getShouldSetOptAndList()) { + result.setOther(createOther()); + } + return result; + } + syn T_OneList SenderRoot.getT_OneList() { + T_OneList result = new T_OneList().setID(getInput()); + if (getShouldSetOptAndList()) { + result.addOther(createOther()); + } + return result; + } + syn T_TwoChildren SenderRoot.getT_TwoChildren() { + T_TwoChildren result = new T_TwoChildren().setID(getInput()); + result.setLeft(createOther()); + result.setRight(createOther()); + return result; + } + syn T_OneOfEach SenderRoot.getT_OneOfEach() { + T_OneOfEach result = new T_OneOfEach().setID(getInput()); + result.setFirst(createOther()); + if (getShouldSetOptAndList()) { + result.setSecond(createOther()); + result.addThird(createOther()); + } + result.setFourth(Integer.toString(getInput())); + return result; + } + syn T_Abstract SenderRoot.getT_Abstract() = new T_SubClass() + .setValueSub(Integer.toString(getInput())) + .setID(getInput()) + .setValueAbstract(Integer.toString(getInput())); + + private Other SenderRoot.createOther() { + return new Other().setID(getInput() + 1); + } + + syn boolean ASTNode.isNameable() = false; + eq Nameable.isNameable() = true; +} + +aspect Testing { + class SenderRoot implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperSenderRoot {} + class ReceiverRoot implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperReceiverRoot {} + class Other implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperOther {} + class T_Empty implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperT_Empty {} + class T_Token implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperT_Token {} + class T_OneChild implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperT_OneChild {} + class T_OneOpt implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperT_OneOpt {} + class T_OneList implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperT_OneList {} + class T_TwoChildren implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperT_TwoChildren {} + class T_OneOfEach implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperT_OneOfEach {} + class T_Abstract implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperT_Abstract {} + class JastAddList<T> implements org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.TestWrapperJastAddList<T> {} +} + +aspect NameResolution { + // overriding customID guarantees to produce the same JSON representation for equal lists + // otherwise, the value for id is different each time + @Override + protected String Nameable.customID() { + return getClass().getSimpleName() + getID(); + } +} diff --git a/ragconnect.tests/src/test/01-input/singleListVariant/Test.relast b/ragconnect.tests/src/test/01-input/singleListVariant/Test.relast new file mode 100644 index 0000000000000000000000000000000000000000..4ac99ae124e19d182d9ad23b4c4ae65980272013 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/singleListVariant/Test.relast @@ -0,0 +1,44 @@ +Root ::= SenderRoot* ReceiverRoot* ; + +Nameable ::= <ID:int> ; +SenderRoot : Nameable ::= <Input:int> <ShouldSetOptAndList:boolean> +/T_Empty/ +/T_Token/ +/T_OneChild/ +/T_OneOpt/ +/T_OneList/ +/T_TwoChildren/ +/T_OneOfEach/ +/T_Abstract/ +; + +ReceiverRoot : Nameable ::= +T_Empty* +T_Token* +T_OneChild* +T_OneOpt* +T_OneList* +T_TwoChildren* +T_OneOfEach* +T_Abstract* +MyEmpty:T_Empty* +EmptyWithAdd:T_Empty* +TokenWithAdd:T_Token* +OneChildWithAdd:T_OneChild* +OneOptWithAdd:T_OneOpt* +OneListWithAdd:T_OneList* +TwoChildrenWithAdd:T_TwoChildren* +OneOfEachWithAdd:T_OneOfEach* +AbstractWithAdd:T_Abstract* +; + +T_Empty : Nameable ::= /* empty */ ; +T_Token : Nameable ::= <Value:String> ; +T_OneChild : Nameable ::= Other ; +T_OneOpt : Nameable ::= [Other] ; +T_OneList : Nameable ::= Other* ; +T_TwoChildren : Nameable ::= Left:Other Right:Other ; +T_OneOfEach : Nameable ::= First:Other [Second:Other] Third:Other* <Fourth:String> ; +abstract T_Abstract : Nameable ::= <ValueAbstract>; +T_SubClass : T_Abstract ::= <ValueSub> ; +Other : Nameable ; diff --git a/ragconnect.tests/src/test/01-input/singleListVariant/TestDependencies.connect b/ragconnect.tests/src/test/01-input/singleListVariant/TestDependencies.connect new file mode 100644 index 0000000000000000000000000000000000000000..2ac87895268cfa631fcfee65a8c2c90f4c13b3c7 --- /dev/null +++ b/ragconnect.tests/src/test/01-input/singleListVariant/TestDependencies.connect @@ -0,0 +1,16 @@ +SenderRoot.T_Empty canDependOn SenderRoot.Input as InputDependencyToT_Empty ; +SenderRoot.T_Token canDependOn SenderRoot.Input as InputDependencyToT_Token ; +SenderRoot.T_OneChild canDependOn SenderRoot.Input as InputDependencyToT_OneChild ; + +SenderRoot.T_OneOpt canDependOn SenderRoot.ShouldSetOptAndList as ShouldSetOptAndListDependencyToT_OneOpt ; +SenderRoot.T_OneOpt canDependOn SenderRoot.Input as InputDependencyToT_OneOpt ; + +SenderRoot.T_OneList canDependOn SenderRoot.ShouldSetOptAndList as ShouldSetOptAndListDependencyToT_OneList ; +SenderRoot.T_OneList canDependOn SenderRoot.Input as InputDependencyToT_OneList ; + +SenderRoot.T_TwoChildren canDependOn SenderRoot.Input as InputDependencyToT_TwoChildren ; + +SenderRoot.T_OneOfEach canDependOn SenderRoot.ShouldSetOptAndList as ShouldSetOptAndListDependencyToT_OneOfEach ; +SenderRoot.T_OneOfEach canDependOn SenderRoot.Input as InputDependencyToT_OneOfEach ; + +SenderRoot.T_Abstract canDependOn SenderRoot.Input as InputDependencyToT_Abstract ; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java new file mode 100644 index 0000000000000000000000000000000000000000..465ad8ac024d595f29a87757c776db6c88e72fe4 --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/AbstractSingleListVariantTest.java @@ -0,0 +1,406 @@ +package org.jastadd.ragconnect.tests.singleListVariant; + +import org.jastadd.ragconnect.tests.AbstractMqttTest; +import org.jastadd.ragconnect.tests.TestUtils; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Paths; +import java.util.List; +import java.util.function.BiConsumer; + +import static java.lang.Math.abs; +import static java.util.Collections.addAll; +import static org.assertj.core.util.Lists.newArrayList; +import static org.jastadd.ragconnect.tests.TestUtils.mqttUri; +import static org.jastadd.ragconnect.tests.TestUtils.testJaddContainReferenceToJackson; +import static org.jastadd.ragconnect.tests.singleListVariant.AbstractSingleListVariantTest.IntList.list; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Base class for test cases "singleList manual" and "singleList incremental". + * + * @author rschoene - Initial contribution + */ +@Tag("List") +@Tag("SingleList") +public abstract class AbstractSingleListVariantTest extends AbstractMqttTest { + + public interface TestWrapperJastAddList<T> extends Iterable<T> { + int getNumChild(); + } + public interface TestWrapperReceiverRoot { + TestWrapperJastAddList<? extends TestWrapperT_Empty> getT_EmptyList(); + TestWrapperJastAddList<? extends TestWrapperT_Token> getT_TokenList(); + TestWrapperJastAddList<? extends TestWrapperT_OneChild> getT_OneChildList(); + TestWrapperJastAddList<? extends TestWrapperT_OneOpt> getT_OneOptList(); + TestWrapperJastAddList<? extends TestWrapperT_OneList> getT_OneListList(); + TestWrapperJastAddList<? extends TestWrapperT_TwoChildren> getT_TwoChildrenList(); + TestWrapperJastAddList<? extends TestWrapperT_OneOfEach> getT_OneOfEachList(); + TestWrapperJastAddList<? extends TestWrapperT_Abstract> getT_AbstractList(); + + TestWrapperJastAddList<? extends TestWrapperT_Empty> getMyEmptyList(); + + TestWrapperJastAddList<? extends TestWrapperT_Empty> getEmptyWithAddList(); + TestWrapperJastAddList<? extends TestWrapperT_Token> getTokenWithAddList(); + TestWrapperJastAddList<? extends TestWrapperT_OneChild> getOneChildWithAddList(); + TestWrapperJastAddList<? extends TestWrapperT_OneOpt> getOneOptWithAddList(); + TestWrapperJastAddList<? extends TestWrapperT_OneList> getOneListWithAddList(); + TestWrapperJastAddList<? extends TestWrapperT_TwoChildren> getTwoChildrenWithAddList(); + TestWrapperJastAddList<? extends TestWrapperT_OneOfEach> getOneOfEachWithAddList(); + TestWrapperJastAddList<? extends TestWrapperT_Abstract> getAbstractWithAddList(); + + boolean connectT_Empty(String mqttUri) throws IOException; + boolean connectT_Token(String mqttUri) throws IOException; + boolean connectT_OneChild(String mqttUri) throws IOException; + boolean connectT_OneOpt(String mqttUri) throws IOException; + boolean connectT_OneList(String mqttUri) throws IOException; + boolean connectT_TwoChildren(String mqttUri) throws IOException; + boolean connectT_OneOfEach(String mqttUri) throws IOException; + boolean connectT_Abstract(String mqttUri) throws IOException; + + boolean connectMyEmpty(String mqttUri) throws IOException; + + boolean connectEmptyWithAdd(String mqttUri) throws IOException; + boolean connectTokenWithAdd(String mqttUri) throws IOException; + boolean connectOneChildWithAdd(String mqttUri) throws IOException; + boolean connectOneOptWithAdd(String mqttUri) throws IOException; + boolean connectOneListWithAdd(String mqttUri) throws IOException; + boolean connectTwoChildrenWithAdd(String mqttUri) throws IOException; + boolean connectOneOfEachWithAdd(String mqttUri) throws IOException; + boolean connectAbstractWithAdd(String mqttUri) throws IOException; + } + @SuppressWarnings("UnusedReturnValue") + public interface TestWrapperSenderRoot { + boolean connectT_Empty(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean connectT_Token(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean connectT_OneChild(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean connectT_OneOpt(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean connectT_OneList(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean connectT_TwoChildren(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean connectT_OneOfEach(String mqttUri, boolean writeCurrentValue) throws IOException; + boolean connectT_Abstract(String mqttUri, boolean writeCurrentValue) throws IOException; + + TestWrapperSenderRoot setInput(int input); + TestWrapperSenderRoot setShouldSetOptAndList(boolean shouldSetOptAndList); + TestWrapperT_Empty getT_Empty(); + TestWrapperT_OneOpt getT_OneOpt(); + } + public interface TestWrapperNameable { + int getID(); + } + public interface TestWrapperOther extends TestWrapperNameable {} + public interface TestWrapperT_Empty extends TestWrapperNameable {} + public interface TestWrapperT_Token extends TestWrapperNameable { + String getValue(); + } + public interface TestWrapperT_OneChild extends TestWrapperNameable { + TestWrapperNameable getOther(); + } + public interface TestWrapperT_OneOpt extends TestWrapperNameable { + boolean hasOther(); + TestWrapperNameable getOther(); + } + public interface TestWrapperT_OneList extends TestWrapperNameable { + int getNumOther(); + TestWrapperNameable getOther(int index); + } + public interface TestWrapperT_TwoChildren extends TestWrapperNameable { + TestWrapperNameable getLeft(); + TestWrapperNameable getRight(); + } + public interface TestWrapperT_OneOfEach extends TestWrapperNameable { + TestWrapperNameable getFirst(); + boolean hasSecond(); + TestWrapperNameable getSecond(); + int getNumThird(); + TestWrapperNameable getThird(int index); + String getFourth(); + } + public interface TestWrapperT_Abstract extends TestWrapperNameable { + String getValueAbstract(); + String getValueSub(); + } + + AbstractSingleListVariantTest(String shortName) { + this.shortName = shortName; + } + + protected static final String TOPIC_T_Empty = "t/Empty"; + protected static final String TOPIC_T_Token = "t/Token"; + protected static final String TOPIC_T_OneChild = "t/OneChild"; + protected static final String TOPIC_T_OneOpt = "t/OneOpt"; + protected static final String TOPIC_T_OneList = "t/OneList"; + protected static final String TOPIC_T_TwoChildren = "t/TwoChildren"; + protected static final String TOPIC_T_OneOfEach = "t/OneOfEach"; + protected static final String TOPIC_T_Abstract = "t/Abstract"; + protected static final String TOPIC_T_all = "t/#"; + + protected TestWrapperSenderRoot senderRoot; + protected TestWrapperReceiverRoot receiverRoot; + protected ReceiverData data; + + private final String shortName; + + @Test + public void checkJacksonReference() { + testJaddContainReferenceToJackson( + Paths.get("src", "test", + "02-after-ragconnect", shortName, "RagConnect.jadd"), true); + } + + @Override + protected void setupReceiverAndConnect(boolean writeCurrentValue) throws IOException, InterruptedException { + // late model initialization + setInput(0); + setShouldSetOptAndList(false); + + setupReceiverAndConnectPart(); + + // connect. important: first receivers, then senders. to not miss initial value. + + // receive: unnamed + assertTrue(receiverRoot.connectT_Empty(mqttUri(TOPIC_T_Empty))); + assertTrue(receiverRoot.connectT_Token(mqttUri(TOPIC_T_Token))); + assertTrue(receiverRoot.connectT_OneChild(mqttUri(TOPIC_T_OneChild))); + assertTrue(receiverRoot.connectT_OneOpt(mqttUri(TOPIC_T_OneOpt))); + assertTrue(receiverRoot.connectT_OneList(mqttUri(TOPIC_T_OneList))); + assertTrue(receiverRoot.connectT_TwoChildren(mqttUri(TOPIC_T_TwoChildren))); + assertTrue(receiverRoot.connectT_OneOfEach(mqttUri(TOPIC_T_OneOfEach))); + assertTrue(receiverRoot.connectT_Abstract(mqttUri(TOPIC_T_Abstract))); + + // receive: named + assertTrue(receiverRoot.connectMyEmpty(mqttUri(TOPIC_T_Empty))); + + // receive: with add + assertTrue(receiverRoot.connectEmptyWithAdd(mqttUri(TOPIC_T_Empty))); + assertTrue(receiverRoot.connectTokenWithAdd(mqttUri(TOPIC_T_Token))); + assertTrue(receiverRoot.connectOneChildWithAdd(mqttUri(TOPIC_T_OneChild))); + assertTrue(receiverRoot.connectOneOptWithAdd(mqttUri(TOPIC_T_OneOpt))); + assertTrue(receiverRoot.connectOneListWithAdd(mqttUri(TOPIC_T_OneList))); + assertTrue(receiverRoot.connectTwoChildrenWithAdd(mqttUri(TOPIC_T_TwoChildren))); + assertTrue(receiverRoot.connectOneOfEachWithAdd(mqttUri(TOPIC_T_OneOfEach))); + assertTrue(receiverRoot.connectAbstractWithAdd(mqttUri(TOPIC_T_Abstract))); + + // send + assertTrue(senderRoot.connectT_Empty(mqttUri(TOPIC_T_Empty), writeCurrentValue)); + assertTrue(senderRoot.connectT_Token(mqttUri(TOPIC_T_Token), writeCurrentValue)); + assertTrue(senderRoot.connectT_OneChild(mqttUri(TOPIC_T_OneChild), writeCurrentValue)); + assertTrue(senderRoot.connectT_OneOpt(mqttUri(TOPIC_T_OneOpt), writeCurrentValue)); + assertTrue(senderRoot.connectT_OneList(mqttUri(TOPIC_T_OneList), writeCurrentValue)); + assertTrue(senderRoot.connectT_TwoChildren(mqttUri(TOPIC_T_TwoChildren), writeCurrentValue)); + assertTrue(senderRoot.connectT_OneOfEach(mqttUri(TOPIC_T_OneOfEach), writeCurrentValue)); + assertTrue(senderRoot.connectT_Abstract(mqttUri(TOPIC_T_Abstract), writeCurrentValue)); + } + + abstract protected void setupReceiverAndConnectPart() throws IOException; + + @Override + protected void communicateSendInitialValue() throws InterruptedException { + // transmissions: 8 * 1 = 8 + checkTree(8, list(-0), list(0), list(-0)); + + setInput(1); + // transmissions: 8 + 8 = 16 + checkTree(16, list(-1), list(0, 1), list(-0, -1)); + + setInput(1); + // transmissions: 16 + checkTree(16, list(-1), list(0, 1), list(-0, -1)); + + setShouldSetOptAndList(true); + // transmissions: 16 + 3 = 19 + checkTree(19, list(1), list(0, 1), list(-0, -1, 1)); + + setShouldSetOptAndList(true); + // transmissions: 19 + checkTree(19, list(1), list(0, 1), list(-0, -1, 1)); + + setInput(2); + // transmissions: 19 + 8 = 27 + checkTree(27, list(2), list(0, 1, 2), list(-0, -1, 1, 2)); + + setInput(5); + // transmissions: 27 + 8 = 35 + checkTree(35, list(5), list(0, 1, 2, 5), list(-0, -1, 1, 2, 5)); + } + + @Override + protected void communicateOnlyUpdatedValue() throws InterruptedException { + // transmissions: 0 + checkTree(0, list(), list(), list()); + + setInput(1); + // transmissions: 8 * 1 = 0 + checkTree(8, list(-1), list(1), list(-1)); + + setInput(1); + // transmissions: 8 + checkTree(8, list(-1), list(1), list(-1)); + + setShouldSetOptAndList(true); + // transmissions: 8 + 3 = 11 + checkTree(11, list(1), list(1), list(-1, 1)); + + setShouldSetOptAndList(true); + // transmissions: 11 + checkTree(11, list(1), list(1), list(-1, 1)); + + setInput(2); + // transmissions: 11 + 8 = 19 + checkTree(19, list(2), list(1, 2), list(-1, 1, 2)); + + setInput(5); + // transmissions: 19 + 8 = 27 + checkTree(27, list(5), list(1, 2, 5), list(-1, 1, 2, 5)); + } + + protected void setInput(int input) { + senderRoot.setInput(input); + assertEquals(input, senderRoot.getT_Empty().getID(), "ID value of empty"); + } + + protected void setShouldSetOptAndList(boolean shouldSetOptAndList) { + senderRoot.setShouldSetOptAndList(shouldSetOptAndList); + assertEquals(shouldSetOptAndList, senderRoot.getT_OneOpt().hasOther(), "opt is filled or not"); + } + + /** + * Check against expected lists of IDs. + * If an ID is negative, do not check Opts and Lists, but use absolute value for comparison. + * The tests starts with ID 0 and does not use opts and lists at this point, so checking with > 0 is used. + * @param expectedTransmissions expected number of total transmissions + * @param expectedList ids for unnamed and named endpoints without add + * @param expectedWithAddList ids for endpoints with add, but not those with opts and lists + * (only positive numbers can/need to be passed) + * @param expectedWithAddListForOptAndList ids for endpoints with add and with opts and lists + * @throws InterruptedException if interrupted in TestUtils.waitForMqtt + */ + private void checkTree(int expectedTransmissions, + IntList expectedList, + IntList expectedWithAddList, + IntList expectedWithAddListForOptAndList) + throws InterruptedException { + TestUtils.waitForMqtt(); + assertEquals(expectedTransmissions, data.numberOfElements, "transmissions for any element"); + + // check unnamed + checkList(expectedList.toList(), receiverRoot.getT_EmptyList(), (e, n) -> {}); + checkList(expectedList.toList(), receiverRoot.getT_TokenList(), + (e, n) -> assertEquals(Integer.toString(abs(e)), n.getValue())); + checkList(expectedList.toList(), receiverRoot.getT_OneChildList(), + (e, n) -> assertEquals(abs(e) + 1, n.getOther().getID())); + checkList(expectedList.toList(), receiverRoot.getT_OneOptList(), + (e, n) -> { + assertEquals(e > 0, n.hasOther()); + if (n.hasOther()) { + assertEquals(abs(e) + 1, n.getOther().getID()); + } + }); + checkList(expectedList.toList(), receiverRoot.getT_OneListList(), + (e, n) -> { + assertEquals(e > 0 ? 1 : 0, n.getNumOther()); + if (n.getNumOther() > 0) { + assertEquals(abs(e) + 1, n.getOther(0).getID()); + } + }); + checkList(expectedList.toList(), receiverRoot.getT_TwoChildrenList(), + (e, n) -> { + assertEquals(abs(e) + 1, n.getLeft().getID()); + assertEquals(abs(e) + 1, n.getRight().getID()); + }); + checkList(expectedList.toList(), receiverRoot.getT_OneOfEachList(), + (e, n) -> { + assertEquals(abs(e) + 1, n.getFirst().getID()); + assertEquals(e > 0, n.hasSecond()); + if (n.hasSecond()) { + assertEquals(abs(e) + 1, n.getSecond().getID()); + } + assertEquals(e > 0 ? 1 : 0, n.getNumThird()); + if (n.getNumThird() > 0) { + assertEquals(abs(e) + 1, n.getThird(0).getID()); + } + assertEquals(Integer.toString(abs(e)), n.getFourth()); + }); + checkList(expectedList.toList(), receiverRoot.getT_AbstractList(), + (e, n) -> { + assertEquals(Integer.toString(abs(e)), n.getValueAbstract()); + assertEquals(Integer.toString(abs(e)), n.getValueSub()); + }); + + // check named + checkList(expectedList.toList(), receiverRoot.getMyEmptyList(), (e, n) -> {}); + + // check with add + checkList(expectedWithAddList.toList(), receiverRoot.getEmptyWithAddList(), (e, n) -> {}); + checkList(expectedWithAddList.toList(), receiverRoot.getTokenWithAddList(), + (e, n) -> assertEquals(Integer.toString(abs(e)), n.getValue())); + checkList(expectedWithAddList.toList(), receiverRoot.getOneChildWithAddList(), + (e, n) -> assertEquals(abs(e) + 1, n.getOther().getID())); + checkList(expectedWithAddListForOptAndList.toList(), receiverRoot.getOneOptWithAddList(), + (e, n) -> { + if (n.hasOther()) { + assertEquals(abs(e) + 1, n.getOther().getID()); + } + }); + checkList(expectedWithAddListForOptAndList.toList(), receiverRoot.getOneListWithAddList(), + (e, n) -> { + if (n.getNumOther() > 0) { + assertEquals(abs(e) + 1, n.getOther(0).getID()); + } + }); + checkList(expectedWithAddList.toList(), receiverRoot.getTwoChildrenWithAddList(), + (e, n) -> { + assertEquals(abs(e) + 1, n.getLeft().getID()); + assertEquals(abs(e) + 1, n.getRight().getID()); + }); + checkList(expectedWithAddListForOptAndList.toList(), receiverRoot.getOneOfEachWithAddList(), + (e, n) -> { + assertEquals(abs(e) + 1, n.getFirst().getID()); + if (n.hasSecond()) { + assertEquals(abs(e) + 1, n.getSecond().getID()); + } + if (n.getNumThird() > 0) { + assertEquals(abs(e) + 1, n.getThird(0).getID()); + } + assertEquals(Integer.toString(abs(e)), n.getFourth()); + }); + checkList(expectedWithAddList.toList(), receiverRoot.getAbstractWithAddList(), + (e, n) -> { + assertEquals(Integer.toString(abs(e)), n.getValueAbstract()); + assertEquals(Integer.toString(abs(e)), n.getValueSub()); + }); + } + + private <T extends TestWrapperNameable> void checkList(List<Integer> expectedList, TestWrapperJastAddList<T> actualList, BiConsumer<Integer, T> additionalTest) { + assertEquals(expectedList.size(), actualList.getNumChild(), "same list size"); + int index = 0; + for (T element : actualList) { + assertEquals(abs(expectedList.get(index)), element.getID(), "correct ID for A"); + additionalTest.accept(expectedList.get(index), element); + index++; + } + } + + protected static class ReceiverData { + int numberOfElements = 0; + } + + protected static class IntList { + private final List<Integer> integers = newArrayList(); + public IntList(Integer... values) { + addAll(integers, values); + } + + public List<Integer> toList() { + return integers; + } + + public static IntList list(Integer... values) { + return new IntList(values); + } + } + +} diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9a55da378b93cc3bcc741d1904dc58b3d9ae96bd --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantIncrementalVariantTest.java @@ -0,0 +1,62 @@ +package org.jastadd.ragconnect.tests.singleListVariant; + +import org.jastadd.ragconnect.tests.TestUtils; +import org.junit.jupiter.api.Tag; +import singleListVariantInc.ast.*; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Test case "list incremental". + * + * @author rschoene - Initial contribution + */ +@Tag("Incremental") +public class SingleListVariantIncrementalVariantTest extends AbstractSingleListVariantTest { + + private Root model; + private MqttHandler handler; + + SingleListVariantIncrementalVariantTest() { + super("singleListVariantInc"); + } + + @Override + protected void createModel() { + model = new Root(); + senderRoot = new SenderRoot(); + model.addSenderRoot((SenderRoot) senderRoot); + + ReceiverRoot localReceiverRoot = new ReceiverRoot(); + model.addReceiverRoot(localReceiverRoot); + receiverRoot = localReceiverRoot; + assertEquals(0, receiverRoot.getT_EmptyList().getNumChild()); + } + + @Override + protected void setupReceiverAndConnectPart() throws IOException { + model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS); + + handler = new MqttHandler().dontSendWelcomeMessage().setHost(TestUtils.getMqttHost()); + assertTrue(handler.waitUntilReady(2, TimeUnit.SECONDS)); + + // no dependencies + + data = new ReceiverData(); + handler.newConnection(TOPIC_T_all, bytes -> data.numberOfElements += 1); + } + + @Override + protected void closeConnections() { + if (handler != null) { + handler.close(); + } + if (model != null) { + model.ragconnectCloseConnections(); + } + } +} diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c65a09ec65add4afd7fa5ca8a2809b28e0be4df2 --- /dev/null +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/singleListVariant/SingleListVariantManualVariantTest.java @@ -0,0 +1,72 @@ +package org.jastadd.ragconnect.tests.singleListVariant; + +import org.jastadd.ragconnect.tests.TestUtils; +import singleListVariant.ast.*; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Test case "list manual". + * + * @author rschoene - Initial contribution + */ +public class SingleListVariantManualVariantTest extends AbstractSingleListVariantTest { + + private Root model; + private MqttHandler handler; + + SingleListVariantManualVariantTest() { + super("singleListVariant"); + } + + @Override + protected void createModel() { + model = new Root(); + senderRoot = new SenderRoot(); + model.addSenderRoot((SenderRoot) senderRoot); + + ReceiverRoot localReceiverRoot = new ReceiverRoot(); + model.addReceiverRoot(localReceiverRoot); + receiverRoot = localReceiverRoot; + assertEquals(0, receiverRoot.getT_EmptyList().getNumChild()); + } + + @Override + protected void setupReceiverAndConnectPart() throws IOException { + model.ragconnectSetupMqttWaitUntilReady(2, TimeUnit.SECONDS); + + handler = new MqttHandler().dontSendWelcomeMessage().setHost(TestUtils.getMqttHost()); + assertTrue(handler.waitUntilReady(2, TimeUnit.SECONDS)); + + // add dependencies: input + ((SenderRoot) senderRoot).addInputDependencyToT_Empty((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addInputDependencyToT_Token((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addInputDependencyToT_OneChild((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addInputDependencyToT_OneOpt((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addInputDependencyToT_OneList((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addInputDependencyToT_TwoChildren((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addInputDependencyToT_OneOfEach((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addInputDependencyToT_Abstract((SenderRoot) senderRoot); + // add dependencies: shouldSetOptAndList + ((SenderRoot) senderRoot).addShouldSetOptAndListDependencyToT_OneOpt((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addShouldSetOptAndListDependencyToT_OneList((SenderRoot) senderRoot); + ((SenderRoot) senderRoot).addShouldSetOptAndListDependencyToT_OneOfEach((SenderRoot) senderRoot); + + data = new ReceiverData(); + handler.newConnection(TOPIC_T_all, bytes -> data.numberOfElements += 1); + } + + @Override + protected void closeConnections() { + if (handler != null) { + handler.close(); + } + if (model != null) { + model.ragconnectCloseConnections(); + } + } +}