diff --git a/ragconnect.base/src/main/jastadd/Intermediate.jadd b/ragconnect.base/src/main/jastadd/Intermediate.jadd index c3c513d18e2d8f1de1b29492621c3bffc3796ab2..69ff5d8932cd33a97e44b2fa3562b13cd52617f2 100644 --- a/ragconnect.base/src/main/jastadd/Intermediate.jadd +++ b/ragconnect.base/src/main/jastadd/Intermediate.jadd @@ -429,9 +429,11 @@ aspect MustacheReceiveAndSendAndHandleUri { eq AttributeEndpointTarget.parentTypeName() = getParentTypeDecl().getName(); eq AttributeEndpointTarget.entityName() = getName(); - eq RelationEndpointTarget.getterMethodName() = "get" + getRole().getterMethodName(); + eq RelationEndpointTarget.getterMethodName() = forwardingNTA_Name(); eq RelationEndpointTarget.parentTypeName() = getRole().getType().getName(); eq RelationEndpointTarget.entityName() = getRole().getName(); + eq RelationEndpointTarget.realGetterMethodName() = "get" + getRole().getterMethodName(); + eq RelationEndpointTarget.realGetterMethodCall() = realGetterMethodName() + (containingEndpointDefinition().indexedSend() ? "(index)" : "()"); syn String NavigableRole.getterMethodName() = getName(); eq ListRole.getterMethodName() = getName() + "List"; @@ -492,6 +494,8 @@ aspect MustacheSendDefinition { syn String EndpointDefinition.forwardingNTA_Name() = getEndpointTarget().forwardingNTA_Name(); syn String EndpointDefinition.forwardingNTA_Type() = getEndpointTarget().forwardingNTA_Type(); + syn boolean EndpointDefinition.relationEndpointWithListRole() = getEndpointTarget().relationEndpointWithListRole(); + syn String EndpointDefinition.senderName() = getEndpointTarget().senderName(); syn boolean EndpointDefinition.shouldNotResetValue() = getSend() && !getEndpointTarget().hasAttributeResetMethod(); @@ -505,13 +509,17 @@ aspect MustacheSendDefinition { // === attributes needed for computing above ones === syn boolean EndpointTarget.needForwardingNTA() = false; eq TypeEndpointTarget.needForwardingNTA() = containingEndpointDefinition().getSend() && !getType().getNTA(); + eq RelationEndpointTarget.needForwardingNTA() = containingEndpointDefinition().getSend(); - syn String EndpointTarget.forwardingNTA_Name() = null; + syn String EndpointTarget.forwardingNTA_Name() = null; // only needed, if needForwardingNTA evaluates to true eq TypeEndpointTarget.forwardingNTA_Name() = ragconnect().internalRagConnectPrefix() + getType().getName(); + eq RelationEndpointTarget.forwardingNTA_Name() = ragconnect().internalRagConnectPrefix() + getRole().getName(); - syn String EndpointTarget.forwardingNTA_Type() = null; + syn String EndpointTarget.forwardingNTA_Type() = null; // only needed, if needForwardingNTA evaluates to true eq TypeEndpointTarget.forwardingNTA_Type() = getType().forwardingNTA_Type( containingEndpointDefinition().getIndexBasedListAccess()); + eq RelationEndpointTarget.forwardingNTA_Type() = getRole().forwardingNTA_Type( +containingEndpointDefinition().getIndexBasedListAccess()); syn String TypeComponent.forwardingNTA_Type(boolean indexBasedListAccess); eq NormalComponent.forwardingNTA_Type(boolean indexBasedListAccess) = getTypeDecl().getName(); @@ -521,6 +529,14 @@ aspect MustacheSendDefinition { getTypeDecl().getName() : ragconnect().configJastAddList() + "<" + getTypeDecl().getName() + ">"; + syn String Role.forwardingNTA_Type(boolean indexBasedListAccess) = oppositeRole().getType().getName(); + eq ListRole.forwardingNTA_Type(boolean indexBasedListAccess) = indexBasedListAccess ? + oppositeRole().getType().getName() : + "java.util.List<" + oppositeRole().getType().getName() + ">"; + + syn boolean EndpointTarget.relationEndpointWithListRole() = false; + eq RelationEndpointTarget.relationEndpointWithListRole() = getRole().isListRole(); + syn String EndpointTarget.senderName() = ragconnect().internalRagConnectPrefix() + "_sender_" + entityName(); eq ContextFreeTypeEndpointTarget.senderName() = null; diff --git a/ragconnect.base/src/main/resources/sendDefinition.mustache b/ragconnect.base/src/main/resources/sendDefinition.mustache index ba6661bb20daa90926eba165121a8e8aeb400293..1e66fdedcc7620aefe31a89fcece47dbcf9708ac 100644 --- a/ragconnect.base/src/main/resources/sendDefinition.mustache +++ b/ragconnect.base/src/main/resources/sendDefinition.mustache @@ -123,5 +123,20 @@ protected void {{parentTypeName}}.{{writeMethodName}}({{#IndexBasedListAccess}}i } {{#needForwardingNTA}} -syn {{{forwardingNTA_Type}}} {{parentTypeName}}.{{forwardingNTA_Name}}({{#IndexBasedListAccess}}int index{{/IndexBasedListAccess}}) = {{realGetterMethodCall}}.{{touchedTerminalsMethodName}}(); +syn {{{forwardingNTA_Type}}} {{parentTypeName}}.{{forwardingNTA_Name}}({{#IndexBasedListAccess}}int index{{/IndexBasedListAccess}}) { +{{#relationEndpointWithListRole}} +// for (var element : {{realGetterMethodCall}}) { +// element.{{touchedTerminalsMethodName}}(); +// } + {{realGetterMethodCall}}.stream().forEach(element -> element.{{touchedTerminalsMethodName}}()); + return {{realGetterMethodCall}}; +{{/relationEndpointWithListRole}} +{{^relationEndpointWithListRole}} + {{{forwardingNTA_Type}}} result = {{realGetterMethodCall}}; + if (result == null) { + return null; + } + return result.{{touchedTerminalsMethodName}}(); +{{/relationEndpointWithListRole}} +} {{/needForwardingNTA}} diff --git a/ragconnect.tests/src/test/01-input/relation/Test.connect b/ragconnect.tests/src/test/01-input/relation/Test.connect index b122934e2a7ea82ac6923a1426cb96da90fe9aaf..61e81d25e3a3bcb898a59112340402c7f21ecccc 100644 --- a/ragconnect.tests/src/test/01-input/relation/Test.connect +++ b/ragconnect.tests/src/test/01-input/relation/Test.connect @@ -1,18 +1,18 @@ send SenderRoot.MyA; send SenderRoot.OptionalA; -send SenderRoot.ListA; +send SenderRoot.ManyA; send SenderRoot.BiMyA; send SenderRoot.BiOptionalA; -send SenderRoot.BiListA; +send SenderRoot.BiManyA; send SenderRoot.MyB using ConcatValues; send SenderRoot.OptionalB using ConcatValues; -send SenderRoot.ListB using ConcatValueList; +send SenderRoot.ManyB using ConcatValueList; send SenderRoot.BiMyB using ConcatValues; send SenderRoot.BiOptionalB using ConcatValues; -send SenderRoot.BiListB using ConcatValueList; +send SenderRoot.BiManyB using ConcatValueList; ConcatValues maps B b to String {: return b.getValue() + "+" + b.getInner().getInnerValue(); @@ -28,16 +28,16 @@ ConcatValueList maps java.util.List<B> list to String {: receive ReceiverRoot.FromMyA; receive ReceiverRoot.FromOptionalA; -receive ReceiverRoot.FromListA; +receive ReceiverRoot.FromManyA; receive ReceiverRoot.FromBiMyA; receive ReceiverRoot.FromBiOptionalA; -receive ReceiverRoot.FromBiListA; +receive ReceiverRoot.FromBiManyA; receive ReceiverRoot.FromMyB; receive ReceiverRoot.FromOptionalB; -receive ReceiverRoot.FromListB; +receive ReceiverRoot.FromManyB; receive ReceiverRoot.FromBiMyB; receive ReceiverRoot.FromBiOptionalB; -receive ReceiverRoot.FromBiListB; +receive ReceiverRoot.FromBiManyB; diff --git a/ragconnect.tests/src/test/01-input/relation/Test.relast b/ragconnect.tests/src/test/01-input/relation/Test.relast index d0cc7790d80eeeb27de65b68a52cd615bfc5761f..7effc867e0f5f45f444ac87607be607f1a23e31a 100644 --- a/ragconnect.tests/src/test/01-input/relation/Test.relast +++ b/ragconnect.tests/src/test/01-input/relation/Test.relast @@ -2,25 +2,25 @@ Root ::= SenderRoot* ReceiverRoot; SenderRoot ::= A* B* ; rel SenderRoot.MyA -> A; rel SenderRoot.OptionalA? -> A; -rel SenderRoot.ListA* -> A; +rel SenderRoot.ManyA* -> A; rel SenderRoot.BiMyA <-> A.ToMyA?; rel SenderRoot.BiOptionalA? <-> A.ToOptionalA?; -rel SenderRoot.BiListA* <-> A.ToListA?; +rel SenderRoot.BiManyA* <-> A.ToManyA?; rel SenderRoot.MyB -> B; rel SenderRoot.OptionalB? -> B; -rel SenderRoot.ListB* -> B; +rel SenderRoot.ManyB* -> B; rel SenderRoot.BiMyB <-> B.ToMyB?; rel SenderRoot.BiOptionalB? <-> B.ToOptionalB?; -rel SenderRoot.BiListB* <-> B.ToListB?; +rel SenderRoot.BiManyB* <-> B.ToManyB?; ReceiverRoot ::= -FromMyA:A FromOptionalA:A FromListA:A* -FromBiMyA:A FromBiOptionalA:A FromBiListA:A* -<FromMyB:String> <FromOptionalB:String> <FromListB:String> -<FromBiMyB:String> <FromBiOptionalB:String> <FromBiListB:String> +FromMyA:A FromOptionalA:A FromManyA:A* +FromBiMyA:A FromBiOptionalA:A FromBiManyA:A* +<FromMyB:String> <FromOptionalB:String> <FromManyB:String> +<FromBiMyB:String> <FromBiOptionalB:String> <FromBiManyB:String> ; A ::= <Value> Inner ; diff --git a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RelationTest.java b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RelationTest.java index b8349f30943bd8d9d02e71df185367b7aa521d30..c2affb34586f144a6462f31021c1ba1d2b44d6c1 100644 --- a/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RelationTest.java +++ b/ragconnect.tests/src/test/java/org/jastadd/ragconnect/tests/RelationTest.java @@ -1,19 +1,17 @@ package org.jastadd.ragconnect.tests; import org.assertj.core.groups.Tuple; -import relationInc.ast.*; import org.junit.jupiter.api.Tag; +import relationInc.ast.*; import java.io.IOException; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; -import java.util.function.Predicate; import static java.util.function.Predicate.isEqual; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.groups.Tuple.tuple; -import static org.hamcrest.Matchers.hasProperty; import static org.jastadd.ragconnect.tests.TestUtils.*; import static org.junit.jupiter.api.Assertions.*; @@ -29,16 +27,16 @@ public class RelationTest extends AbstractMqttTest { private static final String TOPIC_WILDCARD = "rel/#"; private static final String TOPIC_MY_A = "rel/my_a"; private static final String TOPIC_OPTIONAL_A = "rel/optional_a"; - private static final String TOPIC_LIST_A = "rel/list_a"; + private static final String TOPIC_MANY_A = "rel/many_a"; private static final String TOPIC_BI_MY_A = "rel/bi_my_a"; private static final String TOPIC_BI_OPTIONAL_A = "rel/bi_optional_a"; - private static final String TOPIC_BI_LIST_A = "rel/bi_list_a"; + private static final String TOPIC_BI_MANY_A = "rel/bi_many_a"; private static final String TOPIC_MY_B = "rel/my_b"; private static final String TOPIC_OPTIONAL_B = "rel/optional_b"; - private static final String TOPIC_LIST_B = "rel/list_b"; + private static final String TOPIC_MANY_B = "rel/many_b"; private static final String TOPIC_BI_MY_B = "rel/bi_my_b"; private static final String TOPIC_BI_OPTIONAL_B = "rel/bi_optional_b"; - private static final String TOPIC_BI_LIST_B = "rel/bi_list_b"; + private static final String TOPIC_BI_MANY_B = "rel/bi_many_b"; private MqttHandler handler; private ReceiverData data; @@ -52,21 +50,13 @@ public class RelationTest extends AbstractMqttTest { protected void createModel() { model = new Root(); // model.trace().setReceiver(TestUtils::logEvent); - senderUni = new SenderRoot(); - A a1 = createA("a1"); - senderUni.addA(a1); - senderUni.setMyA(a1); - senderUni.setBiMyA(a1); - senderUni.addA(createA("a2")); - senderUni.addA(createA("a3")); - - senderBi = new SenderRoot(); - B b1 = createB("b1"); - senderUni.addB(b1); - senderUni.setMyB(b1); - senderUni.setBiMyB(b1); - senderUni.addB(createB("b2")); - senderUni.addB(createB("b3")); + senderUni = createSenderRoot("uni"); + senderUni.setMyA(uniA(1)); + senderUni.setMyB(uniB(1)); + + senderBi = createSenderRoot("bi"); + senderBi.setBiMyA(biA(1)); + senderBi.setBiMyB(biB(1)); receiverRoot = new ReceiverRoot(); model.addSenderRoot(senderUni); @@ -74,14 +64,52 @@ public class RelationTest extends AbstractMqttTest { model.setReceiverRoot(receiverRoot); } + private SenderRoot createSenderRoot(String name) { + SenderRoot result = new SenderRoot(); + A dummyA = createA(name + "-dummyA"); + result.addA(dummyA); + result.addA(createA(name + "-a1")); + result.addA(createA(name + "-a2")); + result.addA(createA(name + "-a3")); + + B dummyB = createB(name + "-dummyB"); + result.addB(dummyB); + result.addB(createB(name + "-b1")); + result.addB(createB(name + "-b2")); + result.addB(createB(name + "-b3")); + + result.setMyA(dummyA); + result.setBiMyA(dummyA); + result.setMyB(dummyB); + result.setBiMyB(dummyB); + + return result; + } + private A createA(String value) { return new A().setValue(value) - .setInner(new Inner().setInnerValue("inner" + value)); + .setInner(new Inner().setInnerValue("inner-" + value)); } private B createB(String value) { return new B().setValue(value) - .setInner(new Inner().setInnerValue("inner" + value)); + .setInner(new Inner().setInnerValue("inner-" + value)); + } + + private A uniA(int index) { + return senderUni.getA(index); + } + + private B uniB(int index) { + return senderUni.getB(index); + } + + private A biA(int index) { + return senderBi.getA(index); + } + + private B biB(int index) { + return senderBi.getB(index); } @Override @@ -96,33 +124,33 @@ public class RelationTest extends AbstractMqttTest { // connect receive assertTrue(receiverRoot.connectFromMyA(mqttUri(TOPIC_MY_A))); assertTrue(receiverRoot.connectFromOptionalA(mqttUri(TOPIC_OPTIONAL_A))); - assertTrue(receiverRoot.connectFromListAList(mqttUri(TOPIC_LIST_A))); + assertTrue(receiverRoot.connectFromManyAList(mqttUri(TOPIC_MANY_A))); assertTrue(receiverRoot.connectFromBiMyA(mqttUri(TOPIC_BI_MY_A))); assertTrue(receiverRoot.connectFromBiOptionalA(mqttUri(TOPIC_BI_OPTIONAL_A))); - assertTrue(receiverRoot.connectFromBiListAList(mqttUri(TOPIC_BI_LIST_A))); + assertTrue(receiverRoot.connectFromBiManyAList(mqttUri(TOPIC_BI_MANY_A))); assertTrue(receiverRoot.connectFromMyB(mqttUri(TOPIC_MY_B))); assertTrue(receiverRoot.connectFromOptionalB(mqttUri(TOPIC_OPTIONAL_B))); - assertTrue(receiverRoot.connectFromListB(mqttUri(TOPIC_LIST_B))); + assertTrue(receiverRoot.connectFromManyB(mqttUri(TOPIC_MANY_B))); assertTrue(receiverRoot.connectFromBiMyB(mqttUri(TOPIC_BI_MY_B))); assertTrue(receiverRoot.connectFromBiOptionalB(mqttUri(TOPIC_BI_OPTIONAL_B))); - assertTrue(receiverRoot.connectFromBiListB(mqttUri(TOPIC_BI_LIST_B))); + assertTrue(receiverRoot.connectFromBiManyB(mqttUri(TOPIC_BI_MANY_B))); // connect send, and wait to receive (if writeCurrentValue is set) assertTrue(senderUni.connectMyA(mqttUri(TOPIC_MY_A), isWriteCurrentValue())); assertTrue(senderUni.connectOptionalA(mqttUri(TOPIC_OPTIONAL_A), isWriteCurrentValue())); - assertTrue(senderUni.connectListA(mqttUri(TOPIC_LIST_A), isWriteCurrentValue())); + assertTrue(senderUni.connectManyA(mqttUri(TOPIC_MANY_A), isWriteCurrentValue())); assertTrue(senderBi.connectBiMyA(mqttUri(TOPIC_BI_MY_A), isWriteCurrentValue())); assertTrue(senderBi.connectBiOptionalA(mqttUri(TOPIC_BI_OPTIONAL_A), isWriteCurrentValue())); - assertTrue(senderBi.connectBiListA(mqttUri(TOPIC_BI_LIST_A), isWriteCurrentValue())); + assertTrue(senderBi.connectBiManyA(mqttUri(TOPIC_BI_MANY_A), isWriteCurrentValue())); assertTrue(senderUni.connectMyB(mqttUri(TOPIC_MY_B), isWriteCurrentValue())); assertTrue(senderUni.connectOptionalB(mqttUri(TOPIC_OPTIONAL_B), isWriteCurrentValue())); - assertTrue(senderUni.connectListB(mqttUri(TOPIC_LIST_B), isWriteCurrentValue())); + assertTrue(senderUni.connectManyB(mqttUri(TOPIC_MANY_B), isWriteCurrentValue())); assertTrue(senderBi.connectBiMyB(mqttUri(TOPIC_BI_MY_B), isWriteCurrentValue())); assertTrue(senderBi.connectBiOptionalB(mqttUri(TOPIC_BI_OPTIONAL_B), isWriteCurrentValue())); - assertTrue(senderBi.connectBiListB(mqttUri(TOPIC_BI_LIST_B), isWriteCurrentValue())); + assertTrue(senderBi.connectBiManyB(mqttUri(TOPIC_BI_MANY_B), isWriteCurrentValue())); // waitForNonNull(receiverRoot::getFromMyA); // waitForNonNull(receiverRoot::getFromBiMyA); @@ -130,24 +158,146 @@ public class RelationTest extends AbstractMqttTest { // waitForNonNull(receiverRoot::getFromBiMyB); } - private <T> void waitForValue(T expectedValue, Callable<T> callable) { - if (isWriteCurrentValue()) { - awaitMqtt().until(callable, isEqual(expectedValue)); - } - } - - private <T> void waitForNonNull(Callable<T> callable) { - if (isWriteCurrentValue()) { - awaitMqtt().until(callable, Predicate.not(isEqual(null))); - } - } +// private <T> void waitForValue(T expectedValue, Callable<T> callable) { +// if (isWriteCurrentValue()) { +// awaitMqtt().until(callable, isEqual(expectedValue)); +// } +// } +// +// private <T> void waitForNonNull(Callable<T> callable) { +// if (isWriteCurrentValue()) { +// awaitMqtt().until(callable, Predicate.not(isEqual(null))); +// } +// } @Override protected void communicateSendInitialValue() throws IOException, InterruptedException { - // TODO implement test // TODO also check disconnect - check(6, "a1", null, tuple(), null, null, tuple(), - "b1", null, tuple(), null, null, tuple()); + // myA -> a1, myB -> b1 + // biMyA -> a1, biMyB -> b1 + check(8, "uni-a1", null, tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + // --- testing unmapped unidirectional normal role --- // + + uniA(1).setValue("test-1"); + check(9, "test-1:inner-uni-a1", null, tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + senderUni.setMyA(uniA(2)); + check(10, "uni-a2", null, tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + // changing something that was previously the relation target must not trigger a message + uniA(1).setValue("test-2-ignored"); + check(10, "uni-a2", null, tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple(), true); + + uniA(2).setValue("test-3"); + check(11, "test-3:inner-uni-a2", null, tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + uniA(2).getInner().setInnerValue("test-4"); + check(12, "test-3:test-4", null, tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + // setting a new relation target resulting in the same serialization must not trigger a message + uniA(1).setValue("test-3"); + uniA(1).getInner().setInnerValue("test-4"); + senderUni.setMyA(uniA(1)); + check(12, "test-3:test-4", null, tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple(), true); + + // --- testing unmapped unidirectional optional role --- // + + // reset a2 + uniA(2).setValue("uni-a2"); + uniA(2).getInner().setInnerValue("inner-uni-a2"); + + senderUni.setOptionalA(uniA(2)); + check(13, "test-3:test-4", "uni-a2", tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + uniA(2).setValue("test-5"); + check(14, "test-3:test-4", "test-5:inner-uni-a2", tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + senderUni.setOptionalA(uniA(1)); + check(15, "test-3:test-4", "test-3:test-4", tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + // change a nonterminal target of two relations must trigger two messages + uniA(1).getInner().setInnerValue("test-6"); + check(17, "test-3:test-6", "test-3:test-6", tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + // setting an optional relation to null is allowed, but must not trigger a message + senderUni.setOptionalA(null); + check(17, "test-3:test-6", "test-3:test-6", tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple(), true); + + // setting the previous nonterminal as relation target again won't trigger a message + senderUni.setOptionalA(uniA(1)); + check(17, "test-3:test-6", "test-3:test-6", tuple(), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple(), true); + + // --- testing unmapped unidirectional list role --- // + + senderUni.addManyA(uniA(3)); + check(18, "test-3:test-6", "test-3:test-6", tuple("uni-a3"), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + uniA(3).setValue("test-7"); + check(19, "test-3:test-6", "test-3:test-6", tuple("test-7:inner-uni-a3"), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + senderUni.addManyA(uniA(2)); + check(20, "test-3:test-6", "test-3:test-6", tuple("test-7:inner-uni-a3", "test-5:inner-uni-a2"), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + senderUni.addManyA(uniA(1)); + check(21, "test-3:test-6", "test-3:test-6", tuple("test-7:inner-uni-a3", "test-5:inner-uni-a2", "test-3:test-6"), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + uniA(2).getInner().setInnerValue("test-8"); + check(22, "test-3:test-6", "test-3:test-6", tuple("test-7:inner-uni-a3", "test-5:test-8", "test-3:test-6"), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + senderUni.removeManyA(uniA(2)); + check(23, "test-3:test-6", "test-3:test-6", tuple("test-7:inner-uni-a3", "test-3:test-6"), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple()); + + // disconnect my-a, optional-a, many-a - resetting afterwards must not trigger a message + senderUni.disconnectMyA(mqttUri(TOPIC_MY_A)); + senderUni.disconnectOptionalA(mqttUri(TOPIC_OPTIONAL_A)); + senderUni.disconnectManyA(mqttUri(TOPIC_MANY_A)); + uniA(1).setValue("a1"); + uniA(1).getInner().setInnerValue("inner-a1"); + uniA(2).setValue("a2"); + uniA(2).getInner().setInnerValue("inner-a2"); + uniA(3).setValue("a3"); + uniA(3).getInner().setInnerValue("inner-a3"); + check(23, "test-3:test-6", "test-3:test-6", tuple("test-7:inner-uni-a3", "test-3:test-6"), "bi-a1", null, tuple(), + "uni-b1", null, tuple(), "bi-b1", null, tuple(), true); + + // --- todo testing unmapped bidirectional normal role --- // + + // --- todo testing unmapped bidirectional optional role --- // + + // --- todo testing unmapped bidirectional list role --- // + + // --- todo testing transformed unidirectional normal role --- // + + // --- todo testing transformed unidirectional optional role --- // + + // --- todo testing transformed unidirectional list role --- // + + // --- todo testing transformed bidirectional normal role --- // + + // --- todo testing transformed bidirectional optional role --- // + + // --- todo testing transformed bidirectional list role --- // + } @Override @@ -158,10 +308,22 @@ public class RelationTest extends AbstractMqttTest { } private void check(int numberOfValues, - String myA, String optionalA, Tuple listA, - String biMyA, String biOptionalA, Tuple biListA, - String myB, String optionalB, Tuple listB, - String biMyB, String biOptionalB, Tuple biListB) { + String myA, String optionalA, Tuple manyA, + String biMyA, String biOptionalA, Tuple biManyA, + String myB, String optionalB, Tuple manyB, + String biMyB, String biOptionalB, Tuple biManyB) throws InterruptedException { + check(numberOfValues, myA, optionalA, manyA, biMyA, biOptionalA, biManyA, + myB, optionalB, manyB, biMyB, biOptionalB, biManyB, false); + } + + private void check(int numberOfValues, + String myA, String optionalA, Tuple manyA, + String biMyA, String biOptionalA, Tuple biManyA, + String myB, String optionalB, Tuple manyB, + String biMyB, String biOptionalB, Tuple biManyB, boolean wait) throws InterruptedException { + if (wait) { + waitForMqtt(); + } awaitEquals(numberOfValues, () -> data.numberOfValues, "numberOfValues"); // awaitEquals(Objects.requireNonNullElse(basic, ""), @@ -170,20 +332,20 @@ public class RelationTest extends AbstractMqttTest { // A values assertNullOrA(myA, receiverRoot.getFromMyA(), "myA"); assertNullOrA(optionalA, receiverRoot.getFromOptionalA(), "optionalA"); - assertListEqualsForA(listA.toList(), receiverRoot.getFromListAList(), "listA"); + assertListEqualsForA(manyA.toList(), receiverRoot.getFromManyAList(), "manyA"); assertNullOrA(biMyA, receiverRoot.getFromBiMyA(), "biMyA"); assertNullOrA(biOptionalA, receiverRoot.getFromBiOptionalA(), "biOptionalA"); - assertListEqualsForA(biListA.toList(), receiverRoot.getFromBiListAList(), "biListA"); + assertListEqualsForA(biManyA.toList(), receiverRoot.getFromBiManyAList(), "biManyA"); // B values assertNullOrB(myB, receiverRoot.getFromMyB(), "myB"); assertNullOrB(optionalB, receiverRoot.getFromOptionalB(), "optionalB"); - assertListEqualsForB(listB.toList(), receiverRoot.getFromListB(), "listB"); + assertListEqualsForB(manyB.toList(), receiverRoot.getFromManyB(), "manyB"); assertNullOrB(biMyB, receiverRoot.getFromBiMyB(), "biMyB"); assertNullOrB(biOptionalB, receiverRoot.getFromBiOptionalB(), "biOptionalB"); - assertListEqualsForB(biListB.toList(), receiverRoot.getFromBiListB(), "biListB"); + assertListEqualsForB(biManyB.toList(), receiverRoot.getFromBiManyB(), "biManyB"); } private <T> void awaitEquals(T expected, Callable<T> actual, String alias) { @@ -195,7 +357,15 @@ public class RelationTest extends AbstractMqttTest { assertNull(actual, alias); return; } - String expectedInner = "inner" + expectedValue; + final String expectedInner; + if (expectedValue.contains(":")) { + String[] tokens = expectedValue.split(":"); + assertEquals(2, tokens.length); + expectedValue = tokens[0]; + expectedInner = tokens[1]; + } else { + expectedInner = "inner-" + expectedValue; + } assertThat(actual.getValue()).describedAs(alias + ".Value").isEqualTo(expectedValue); assertThat(actual.getInner()).describedAs(alias + ".inner != null").isNotNull(); assertThat(actual.getInner().getInnerValue()).describedAs(alias + ".inner.Value").isEqualTo(expectedInner); @@ -214,7 +384,7 @@ public class RelationTest extends AbstractMqttTest { if (expected == null) { expectedValue = ""; } else { - expectedValue = expected + "+inner" + expected; + expectedValue = expected + "+inner-" + expected; } assertEquals(expectedValue, actual, alias); }