diff --git a/ros2rag.base/src/main/jastadd/Analysis.jrag b/ros2rag.base/src/main/jastadd/Analysis.jrag index 246645f2e92f18ef325466530f95e5b5f37847a5..6c8755e77db354ed36900f3439cd6fd8c5e6f2f5 100644 --- a/ros2rag.base/src/main/jastadd/Analysis.jrag +++ b/ros2rag.base/src/main/jastadd/Analysis.jrag @@ -4,8 +4,9 @@ aspect Analysis { syn boolean JavaTypeUse.isPrimitiveType() = false; eq SimpleJavaTypeUse.isPrimitiveType() { switch(getName()) { - case "short": case "int": + case "short": + case "long": case "float": case "double": case "char": diff --git a/ros2rag.base/src/main/jastadd/Navigation.jrag b/ros2rag.base/src/main/jastadd/Navigation.jrag index a43beba54597e06cae95d577e610b5bba5b1e2c9..ce2029496eebf41a537d8f72554e8ddb2021a675 100644 --- a/ros2rag.base/src/main/jastadd/Navigation.jrag +++ b/ros2rag.base/src/main/jastadd/Navigation.jrag @@ -34,4 +34,8 @@ aspect Navigation { } return null; } + + // --- isDefaultMappingDefinition --- + syn boolean MappingDefinition.isDefaultMappingDefinition() = false; + eq DefaultMappingDefinition.isDefaultMappingDefinition() = true; } diff --git a/ros2rag.base/src/main/jastadd/backend/Generation.jadd b/ros2rag.base/src/main/jastadd/backend/Generation.jadd index b74743d183fd56390537348e3be580090b77e3f3..e827c68c947baf50b43bf8abfc2651dfc7bced2c 100644 --- a/ros2rag.base/src/main/jastadd/backend/Generation.jadd +++ b/ros2rag.base/src/main/jastadd/backend/Generation.jadd @@ -95,7 +95,7 @@ aspect AspectGeneration { for (UpdateDefinition def : getUpdateDefinitionList()) { def.generateAspect(sb); } - for (MappingDefinition def : getMappingDefinitionList()) { + for (MappingDefinition def : allMappingDefinitions()) { def.generateAspect(sb); } for (DependencyDefinition def : getDependencyDefinitionList()) { @@ -112,11 +112,11 @@ aspect AspectGeneration { final String resultVariablePrefix = "result"; // we do not need "_" here, because methodName begins with one String inputVariableName = initialInputVariableName; // last variable need to be declared before begin of try - MappingDefinition lastDefinition = getMappingList().get(getMappingList().size() - 1); + MappingDefinition lastDefinition = effectiveMappings().get(effectiveMappings().size() - 1); sb.append(ind(indent)).append(lastDefinition.getToType().prettyPrint()).append(" ") .append(resultVariablePrefix).append(lastDefinition.methodName()).append(";\n"); sb.append(ind(indent)).append("try {\n"); - for (MappingDefinition mappingDefinition : getMappingList()) { + for (MappingDefinition mappingDefinition : effectiveMappings()) { String resultVariableName = resultVariablePrefix + mappingDefinition.methodName(); sb.append(ind(indent + 1)); if (mappingDefinition != lastDefinition) { @@ -135,6 +135,9 @@ aspect AspectGeneration { sb.append(ind(indent)).append("if (").append(preemptiveExpectedValue()); if (getToken().isPrimitiveType()) { sb.append(" == ").append(inputVariableName); + } else if (effectiveMappings().get(effectiveMappings().size() - 1).isDefaultMappingDefinition()) { + sb.append(" != null && ").append(preemptiveExpectedValue()).append(".equals(") + .append(inputVariableName).append(")"); } else { sb.append(" != null ? ").append(preemptiveExpectedValue()).append(".equals(") .append(inputVariableName).append(")").append(" : ") diff --git a/ros2rag.base/src/main/jastadd/backend/Mappings.jrag b/ros2rag.base/src/main/jastadd/backend/Mappings.jrag new file mode 100644 index 0000000000000000000000000000000000000000..4bfe070a81b49e63996ba8f9a32a43eb13af6d1f --- /dev/null +++ b/ros2rag.base/src/main/jastadd/backend/Mappings.jrag @@ -0,0 +1,204 @@ +aspect DefaultMappings { + + private DefaultMappingDefinition Ros2Rag.baseDefaultMappingDefinitionFromBytes(String typeName) { + DefaultMappingDefinition result = new DefaultMappingDefinition(); + result.setID("_DefaultBytesTo" + Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1) + "Mapping"); + result.setFromType(new JavaArrayMappingDefinitionType(new SimpleJavaTypeUse("byte"))); + result.setFromVariableName("bytes"); + result.setToType(new JavaMappingDefinitionType(new SimpleJavaTypeUse(typeName))); + return result; + } + + private DefaultMappingDefinition Ros2Rag.baseDefaultMappingDefinitionToBytes(String typeName) { + DefaultMappingDefinition result = new DefaultMappingDefinition(); + result.setID("_Default" + Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1) + "ToBytesMapping"); + result.setFromType(new JavaMappingDefinitionType(new SimpleJavaTypeUse(typeName))); + result.setFromVariableName("input"); + result.setToType(new JavaArrayMappingDefinitionType(new SimpleJavaTypeUse("byte"))); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultBytesToIntMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("int"); + result.setContent("return java.nio.ByteBuffer.wrap(bytes).getInt();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultBytesToShortMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("short"); + result.setContent("return java.nio.ByteBuffer.wrap(bytes).getShort();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultBytesToLongMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("long"); + result.setContent("return java.nio.ByteBuffer.wrap(bytes).getLong();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultBytesToFloatMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("float"); + result.setContent("return java.nio.ByteBuffer.wrap(bytes).getFloat();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultBytesToDoubleMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("double"); + result.setContent("return java.nio.ByteBuffer.wrap(bytes).getDouble();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultBytesToCharMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("char"); + result.setContent("return java.nio.ByteBuffer.wrap(bytes).getChar();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultBytesToStringMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionFromBytes("String"); + result.setContent("return new String(bytes);"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultIntToBytesMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("int"); + result.setContent("return java.nio.ByteBuffer.allocate(4).putInt(input).array();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultShortToBytesMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("short"); + result.setContent("return java.nio.ByteBuffer.allocate(2).putShort(input).array();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultLongToBytesMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("long"); + result.setContent("return java.nio.ByteBuffer.allocate(8).putLong(input).array();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultFloatToBytesMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("float"); + result.setContent("return java.nio.ByteBuffer.allocate(4).putFloat(input).array();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultDoubleToBytesMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("double"); + result.setContent("return java.nio.ByteBuffer.allocate(8).putDouble(input).array();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultCharToBytesMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("char"); + result.setContent("return java.nio.ByteBuffer.allocate(2).putChar(input).array();"); + return result; + } + + syn nta DefaultMappingDefinition Ros2Rag.defaultStringToBytesMapping() { + DefaultMappingDefinition result = baseDefaultMappingDefinitionToBytes("String"); + result.setContent("return input.getBytes();"); + return result; + } +} + +aspect Mappings { + // --- effectiveMappings --- + syn java.util.List<MappingDefinition> UpdateDefinition.effectiveMappings(); + eq ReadFromMqttDefinition.effectiveMappings() { + // if there is a first mapping, check if its input type is byte[]. + // or if no mappings are specified. + // then prepend the suitable default mapping + java.util.List<MappingDefinition> result; + if (getMappingList().size() == 0 || !getMappingList().get(0).getFromType().isByteArray()) { + result = new java.util.ArrayList(); + result.add(suitableDefaultMapping()); + result.addAll(getMappingList()); + } else { + result = getMappingList(); + } + return result; + } + eq WriteToMqttDefinition.effectiveMappings() { + // if there is a mapping, check if the output type of the last mapping is byte[]. + // or if no mappings are specified. + // then append the suitable default mapping + java.util.List<MappingDefinition> result; + int numMappings = getMappingList().size(); + if (numMappings == 0 || !getMappingList().get(numMappings - 1).getToType().isByteArray()) { + result = new java.util.ArrayList(); + result.addAll(getMappingList()); + result.add(suitableDefaultMapping()); + } else { + result = getMappingList(); + } + return result; + } + + // --- suitableDefaultMapping --- + syn DefaultMappingDefinition UpdateDefinition.suitableDefaultMapping(); + eq ReadFromMqttDefinition.suitableDefaultMapping() { + String typeName = getToken().getJavaTypeUse().getName(); + switch(typeName) { + case "int": + case "Integer": return ros2rag().defaultBytesToIntMapping(); + case "short": + case "Short": return ros2rag().defaultBytesToShortMapping(); + case "long": + case "Long": return ros2rag().defaultBytesToLongMapping(); + case "float": + case "Float": return ros2rag().defaultBytesToFloatMapping(); + case "double": + case "Double": return ros2rag().defaultBytesToDoubleMapping(); + case "char": + case "Character": return ros2rag().defaultBytesToCharMapping(); + case "String": return ros2rag().defaultBytesToStringMapping(); + default: return null; + } + } + eq WriteToMqttDefinition.suitableDefaultMapping() { + String typeName = getToken().getJavaTypeUse().getName(); + switch(typeName) { + case "int": + case "Integer": return ros2rag().defaultIntToBytesMapping(); + case "short": + case "Short": return ros2rag().defaultShortToBytesMapping(); + case "long": + case "Long": return ros2rag().defaultLongToBytesMapping(); + case "float": + case "Float": return ros2rag().defaultFloatToBytesMapping(); + case "double": + case "Double": return ros2rag().defaultDoubleToBytesMapping(); + case "char": + case "Character": return ros2rag().defaultCharToBytesMapping(); + case "String": return ros2rag().defaultStringToBytesMapping(); + default: return null; + } + } + + // --- isByteArray --- + syn boolean MappingDefinitionType.isByteArray() = false; + eq JavaArrayMappingDefinitionType.isByteArray() = getType().getName().equals("byte"); + + // --- allMappingDefinitions --- + syn java.util.List<MappingDefinition> Ros2Rag.allMappingDefinitions() { + java.util.List<MappingDefinition> result = new java.util.ArrayList<>(); + getMappingDefinitionList().iterator().forEachRemaining(result::add); + result.add(defaultBytesToIntMapping()); + result.add(defaultBytesToShortMapping()); + result.add(defaultBytesToLongMapping()); + result.add(defaultBytesToFloatMapping()); + result.add(defaultBytesToDoubleMapping()); + result.add(defaultBytesToCharMapping()); + result.add(defaultBytesToStringMapping()); + result.add(defaultIntToBytesMapping()); + result.add(defaultShortToBytesMapping()); + result.add(defaultLongToBytesMapping()); + result.add(defaultFloatToBytesMapping()); + result.add(defaultDoubleToBytesMapping()); + result.add(defaultCharToBytesMapping()); + result.add(defaultStringToBytesMapping()); + return result; + } +} diff --git a/ros2rag.base/src/main/jastadd/parser/Ros2Rag.parser b/ros2rag.base/src/main/jastadd/parser/Ros2Rag.parser index f2ab264c5b39a53d2dd37634b30b0d11c899dce1..015b4e664950fd9f49601dbea53fc67225c41169 100644 --- a/ros2rag.base/src/main/jastadd/parser/Ros2Rag.parser +++ b/ros2rag.base/src/main/jastadd/parser/Ros2Rag.parser @@ -12,8 +12,6 @@ Ros2Rag ros2rag } :} ; -// read Joint.CurrentPosition using LinkStateToIntPosition ; -// write RobotArm._AppropriateSpeed using CreateSpeedMessage ; UpdateDefinition update_definition = READ ID.type_name DOT ID.token_name SCOL {: @@ -52,7 +50,6 @@ ArrayList string_list | string_list COMMA ID ; -// RobotArm._AppropriateSpeed canDependOn Joint.CurrentPosition as dependency1 ; DependencyDefinition dependency_definition = ID.target_type DOT ID.target_token CAN_DEPEND_ON ID.source_type DOT ID.source_token AS ID.id SCOL {: @@ -64,10 +61,6 @@ DependencyDefinition dependency_definition :} ; -//LinkStateToIntPosition maps protobuf panda.Linkstate.PandaLinkState x to IntPosition y { -// panda.Linkstate.PandaLinkState.Position p = x.getPos(); -// y = IntPosition.of((int) p.getPositionX(), (int) p.getPositionY(), (int) p.getPositionZ()); -//} MappingDefinition mapping_definition = ID.id MAPS mapping_type.from_type ID.from_name TO mapping_type.to_type MAPPING_CONTENT.content {: diff --git a/ros2rag.tests/build.gradle b/ros2rag.tests/build.gradle index c37cfdd23f9a7ffd87393fda2e722c821983eff7..6c939f991b113912ea1c777a909d56794c8459e2 100644 --- a/ros2rag.tests/build.gradle +++ b/ros2rag.tests/build.gradle @@ -54,6 +54,7 @@ protobuf { } } +// --- Test: Example --- task preprocessExampleTest(type: JavaExec, group: 'verification') { doFirst { delete 'src/test/02-after-ros2rag/example/Grammar.relast', @@ -70,22 +71,6 @@ task preprocessExampleTest(type: JavaExec, group: 'verification') { '--rootNode=Model' } -//task compileExampleTest(type: JavaExec, group: 'verification') { -// -// doFirst { -// delete 'src/test/java-gen/example' -// } -// -// classpath = sourceSets.main.runtimeClasspath -// main = 'org.jastadd.JastAdd' -// //noinspection GroovyAssignabilityCheck -// args '--o=src/test/java-gen/', '--package=example.ast', -// 'src/test/jastadd-gen/example/Grammar.relast', -// 'src/test/jastadd-gen/example/MqttUpdater.java', -// 'src/test/jastadd-gen/example/ROS2RAG.jadd', -// 'src/test/jastadd/Example.jadd' -//} - task compileExampleTest(type: RelastTest) { verbose = true useJastAddNames = true @@ -101,6 +86,38 @@ task compileExampleTest(type: RelastTest) { test.dependsOn compileExampleTest compileExampleTest.dependsOn preprocessExampleTest +// --- Test: default-only-read --- +task preprocessDefaultOnlyReadTest(type: JavaExec, group: 'verification') { + doFirst { + delete 'src/test/02-after-ros2rag/defaultOnlyRead/Grammar.relast', + 'src/test/02-after-ros2rag/defaultOnlyRead/MqttUpdater.java', + 'src/test/02-after-ros2rag/defaultOnlyRead/ROS2RAG.jadd' + } + + classpath = sourceSets.main.runtimeClasspath + main = 'org.jastadd.ros2rag.compiler.Compiler' + //noinspection GroovyAssignabilityCheck + args '--outputDir=src/test/02-after-ros2rag/defaultOnlyRead', + '--inputGrammar=src/test/01-input/defaultOnlyRead/Example.relast', + '--inputRos2Rag=src/test/01-input/defaultOnlyRead/Example.ros2rag', + '--rootNode=A', + '--verbose' +} + +task compileDefaultOnlyReadTest(type: RelastTest) { + verbose = true + useJastAddNames = true + jastAddList = 'JastAddList' + relastFiles 'src/test/02-after-ros2rag/defaultOnlyRead/Grammar.relast' + grammarName = 'src/test/03-after-relast/defaultOnlyRead/defaultOnlyRead' + packageName = 'defaultOnlyRead.ast' + moreInputFiles 'src/test/02-after-ros2rag/defaultOnlyRead/MqttUpdater.jadd', + 'src/test/02-after-ros2rag/defaultOnlyRead/ROS2RAG.jadd' +} + +test.dependsOn compileDefaultOnlyReadTest +compileDefaultOnlyReadTest.dependsOn preprocessDefaultOnlyReadTest + clean { - delete 'src/test/02-after-ros2rag/example/', 'src/test/03-after-relast/example/' + delete 'src/test/02-after-ros2rag/*/', 'src/test/03-after-relast/*/' } diff --git a/ros2rag.tests/src/test/01-input/defaultOnlyRead/Example.relast b/ros2rag.tests/src/test/01-input/defaultOnlyRead/Example.relast new file mode 100644 index 0000000000000000000000000000000000000000..30eba76b346dace40c72ca4e172b88ef206ea063 --- /dev/null +++ b/ros2rag.tests/src/test/01-input/defaultOnlyRead/Example.relast @@ -0,0 +1,3 @@ +A ::= NativeTypes* BoxedTypes* ; +NativeTypes ::= <IntValue:int> <ShortValue:short> <LongValue:long> <FloatValue:float> <DoubleValue:double> <CharValue:char> <StringValue:String> ; +BoxedTypes ::= <IntValue:Integer> <ShortValue:Short> <LongValue:Long> <FloatValue:Float> <DoubleValue:Double> <CharValue:Character> ; diff --git a/ros2rag.tests/src/test/01-input/defaultOnlyRead/Example.ros2rag b/ros2rag.tests/src/test/01-input/defaultOnlyRead/Example.ros2rag new file mode 100644 index 0000000000000000000000000000000000000000..90e2ccabb89b8d1f48ad1ba01fa9112e5c762a70 --- /dev/null +++ b/ros2rag.tests/src/test/01-input/defaultOnlyRead/Example.ros2rag @@ -0,0 +1,15 @@ +// --- update definitions --- +read NativeTypes.IntValue; +read NativeTypes.ShortValue; +read NativeTypes.LongValue; +read NativeTypes.FloatValue; +read NativeTypes.DoubleValue; +read NativeTypes.CharValue; +read NativeTypes.StringValue; + +read BoxedTypes.IntValue; +read BoxedTypes.ShortValue; +read BoxedTypes.LongValue; +read BoxedTypes.FloatValue; +read BoxedTypes.DoubleValue; +read BoxedTypes.CharValue; diff --git a/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/DefaultOnlyReadTest.java b/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/DefaultOnlyReadTest.java new file mode 100644 index 0000000000000000000000000000000000000000..88b51d69cdef68399297768ebdd98c6631508b8b --- /dev/null +++ b/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/DefaultOnlyReadTest.java @@ -0,0 +1,139 @@ +package org.jastadd.ros2rag.tests; + +import defaultOnlyRead.ast.A; +import defaultOnlyRead.ast.BoxedTypes; +import defaultOnlyRead.ast.MqttUpdater; +import defaultOnlyRead.ast.NativeTypes; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Test case "defaultOnlyRead". + * + * @author rschoene - Initial contribution + */ +public class DefaultOnlyReadTest { + + private static final String TOPIC_NATIVE_INT = "native/int"; + private static final String TOPIC_NATIVE_SHORT = "native/short"; + private static final String TOPIC_NATIVE_LONG = "native/long"; + private static final String TOPIC_NATIVE_FLOAT = "native/float"; + private static final String TOPIC_NATIVE_DOUBLE = "native/double"; + private static final String TOPIC_NATIVE_CHAR = "native/char"; + private static final String TOPIC_NATIVE_STRING = "native/string"; + + private static final String TOPIC_BOXED_INTEGER = "boxed/Integer"; + private static final String TOPIC_BOXED_SHORT = "boxed/Short"; + private static final String TOPIC_BOXED_LONG = "boxed/Long"; + private static final String TOPIC_BOXED_FLOAT = "boxed/Float"; + private static final String TOPIC_BOXED_DOUBLE = "boxed/Double"; + private static final String TOPIC_BOXED_CHARACTER = "boxed/Character"; + + private A model; + private NativeTypes integers; + private NativeTypes floats; + private NativeTypes chars; + private BoxedTypes allBoxed; + private MqttUpdater sender; + + @AfterEach + public void closeConnections() { + if (sender != null) { + sender.close(); + } + if (model != null) { + model.MqttCloseConnections(); + } + } + + + @Test + public void buildModel() { + createModel(); + } + + @Test + public void communicate() throws IOException, InterruptedException { + createModel(); + + model.MqttSetHost(TestUtils.getMqttHost()); + assertTrue(model.MqttWaitUntilReady(2, TimeUnit.SECONDS)); + + integers.connectIntValue(TOPIC_NATIVE_INT); + integers.connectShortValue(TOPIC_NATIVE_SHORT); + integers.connectLongValue(TOPIC_NATIVE_LONG); + floats.connectFloatValue(TOPIC_NATIVE_FLOAT); + floats.connectDoubleValue(TOPIC_NATIVE_DOUBLE); + chars.connectCharValue(TOPIC_NATIVE_CHAR); + chars.connectStringValue(TOPIC_NATIVE_STRING); + allBoxed.connectIntValue(TOPIC_BOXED_INTEGER); + allBoxed.connectShortValue(TOPIC_BOXED_SHORT); + allBoxed.connectLongValue(TOPIC_BOXED_LONG); + allBoxed.connectFloatValue(TOPIC_BOXED_FLOAT); + allBoxed.connectDoubleValue(TOPIC_BOXED_DOUBLE); + allBoxed.connectCharValue(TOPIC_BOXED_CHARACTER); + + sender = new MqttUpdater().dontSendWelcomeMessage().setHost(TestUtils.getMqttHost()); + assertTrue(sender.waitUntilReady(2, TimeUnit.SECONDS)); + + final int expectedIntValue = 1; + final short expectedShortValue = 2; + final long expectedLongValue = 3L; + final float expectedFloatValue = 4.1f; + final double expectedDoubleValue = 5.2; + final char expectedCharValue = 'c'; + final String expectedStringValue = "6.3"; + + sender.publish(TOPIC_NATIVE_INT, ByteBuffer.allocate(4).putInt(expectedIntValue).array()); + sender.publish(TOPIC_NATIVE_SHORT, ByteBuffer.allocate(2).putShort(expectedShortValue).array()); + sender.publish(TOPIC_NATIVE_LONG, ByteBuffer.allocate(8).putLong(expectedLongValue).array()); + sender.publish(TOPIC_NATIVE_FLOAT, ByteBuffer.allocate(4).putFloat(expectedFloatValue).array()); + sender.publish(TOPIC_NATIVE_DOUBLE, ByteBuffer.allocate(8).putDouble(expectedDoubleValue).array()); + sender.publish(TOPIC_NATIVE_CHAR, ByteBuffer.allocate(2).putChar(expectedCharValue).array()); + sender.publish(TOPIC_NATIVE_STRING, expectedStringValue.getBytes()); + + sender.publish(TOPIC_BOXED_INTEGER, ByteBuffer.allocate(4).putInt(expectedIntValue).array()); + sender.publish(TOPIC_BOXED_SHORT, ByteBuffer.allocate(2).putShort(expectedShortValue).array()); + sender.publish(TOPIC_BOXED_LONG, ByteBuffer.allocate(8).putLong(expectedLongValue).array()); + sender.publish(TOPIC_BOXED_FLOAT, ByteBuffer.allocate(4).putFloat(expectedFloatValue).array()); + sender.publish(TOPIC_BOXED_DOUBLE, ByteBuffer.allocate(8).putDouble(expectedDoubleValue).array()); + sender.publish(TOPIC_BOXED_CHARACTER, ByteBuffer.allocate(2).putChar(expectedCharValue).array()); + + TimeUnit.SECONDS.sleep(2); + + assertEquals(expectedIntValue, integers.getIntValue()); + assertEquals(expectedShortValue, integers.getShortValue()); + assertEquals(expectedLongValue, integers.getLongValue()); + assertEquals(expectedFloatValue, floats.getFloatValue(), TestUtils.DELTA); + assertEquals(expectedDoubleValue, floats.getDoubleValue(), TestUtils.DELTA); + assertEquals(expectedCharValue, chars.getCharValue()); + assertEquals(expectedStringValue, chars.getStringValue()); + + assertEquals(expectedIntValue, allBoxed.getIntValue().intValue()); + assertEquals(expectedShortValue, allBoxed.getShortValue().shortValue()); + assertEquals(expectedLongValue, allBoxed.getLongValue().longValue()); + assertEquals(expectedFloatValue, allBoxed.getFloatValue(), TestUtils.DELTA); + assertEquals(expectedDoubleValue, allBoxed.getDoubleValue(), TestUtils.DELTA); + assertEquals(expectedCharValue, allBoxed.getCharValue().charValue()); + } + + private void createModel() { + model = new A(); + integers = new NativeTypes(); + model.addNativeTypes(integers); + floats = new NativeTypes(); + model.addNativeTypes(floats); + chars = new NativeTypes(); + model.addNativeTypes(chars); + allBoxed = new BoxedTypes(); + model.addBoxedTypes(allBoxed); + } + +} diff --git a/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/ExampleTest.java b/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/ExampleTest.java index d70f89378395d32ff0b88cc0be72fab72e85f84c..c58eda7703dad37f824b7faa6c6df036d3ac869b 100644 --- a/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/ExampleTest.java +++ b/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/ExampleTest.java @@ -9,7 +9,6 @@ import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; @@ -21,20 +20,21 @@ import static org.junit.Assert.*; */ public class ExampleTest { - private static final double DELTA = 0.001d; private static final String TOPIC_CONFIG = "robot/config"; private static final String TOPIC_JOINT1 = "robot/arm/joint1"; private Model model; private RobotArm robotArm; private Joint joint1; - - private CountDownLatch stop; + private MqttUpdater receiver; @AfterEach - public void signalCondition() { - if (stop != null) { - stop.countDown(); + public void closeConnections() { + if (receiver != null) { + receiver.close(); + } + if (model != null) { + model.MqttCloseConnections(); } } @@ -48,10 +48,7 @@ public class ExampleTest { createModel(); List<RobotConfig> receivedConfigs = new ArrayList<>(); - CountDownLatch start = new CountDownLatch(1); - stop = new CountDownLatch(1); - createListenerThread(receivedConfigs, start, stop); - start.await(); + createListener(receivedConfigs); model.MqttSetHost(TestUtils.getMqttHost()); assertTrue(model.MqttWaitUntilReady(2, TimeUnit.SECONDS)); @@ -68,39 +65,28 @@ public class ExampleTest { // there should be two configs received by now (the initial one, and the updated) assertEquals(2, receivedConfigs.size()); RobotConfig actualInitialConfig = receivedConfigs.get(0); - assertEquals(robotArm.speedLow(), actualInitialConfig.getSpeed(), DELTA); + assertEquals(robotArm.speedLow(), actualInitialConfig.getSpeed(), TestUtils.DELTA); RobotConfig actualUpdatedConfig = receivedConfigs.get(1); - assertEquals(robotArm.speedHigh(), actualUpdatedConfig.getSpeed(), DELTA); - model.MqttCloseConnections(); + assertEquals(robotArm.speedHigh(), actualUpdatedConfig.getSpeed(), TestUtils.DELTA); } - private void createListenerThread(List<RobotConfig> receivedConfigs, - CountDownLatch startCondition, CountDownLatch stopCondition) { - new Thread(() -> { - MqttUpdater receiver = new MqttUpdater("receiver"); - try { - receiver.setHost(TestUtils.getMqttHost(), TestUtils.getMqttDefaultPort()); - } catch (IOException e) { - fail("Could not set host: " + e.getMessage()); - } - assertTrue(receiver.waitUntilReady(2, TimeUnit.SECONDS)); - receiver.newConnection(TOPIC_CONFIG, bytes -> { - try { - RobotConfig config = RobotConfig.parseFrom(bytes); - receivedConfigs.add(config); - } catch (InvalidProtocolBufferException e) { - fail("Received bad config: " + e.getMessage()); - } - }); - startCondition.countDown(); + private void createListener(List<RobotConfig> receivedConfigs) { + receiver = new MqttUpdater("receiver"); + try { + receiver.setHost(TestUtils.getMqttHost(), TestUtils.getMqttDefaultPort()); + } catch (IOException e) { + fail("Could not set host: " + e.getMessage()); + } + assertTrue(receiver.waitUntilReady(2, TimeUnit.SECONDS)); + receiver.newConnection(TOPIC_CONFIG, bytes -> { try { - stopCondition.await(); - receiver.close(); - } catch (InterruptedException e) { - e.printStackTrace(); + RobotConfig config = RobotConfig.parseFrom(bytes); + receivedConfigs.add(config); + } catch (InvalidProtocolBufferException e) { + fail("Received bad config: " + e.getMessage()); } - }).start(); + }); } private void createModel() { diff --git a/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/TestUtils.java b/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/TestUtils.java index 083b9982cfce12243080dd10d75b15a22dd2c8cf..e910f3b13c47cef53cefb3206aefa64fa2514c29 100644 --- a/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/TestUtils.java +++ b/ros2rag.tests/src/test/java/org/jastadd/ros2rag/tests/TestUtils.java @@ -7,6 +7,8 @@ package org.jastadd.ros2rag.tests; */ public class TestUtils { + public static final double DELTA = 0.001d; + public static String getMqttHost() { if (System.getenv("GITLAB_CI") != null) { // we are in the CI, so use "mqtt" as host