diff --git a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java index 67e4ba8f32..9a3421b219 100644 --- a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java +++ b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.service.script; +import org.junit.jupiter.api.RepeatedTest; import org.junit.jupiter.api.Test; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.script.api.tbel.TbDate; @@ -779,7 +780,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected.toString(), actual.toString()); } - @Test + @Test public void setsCreateNewSetFromCreateSetTbMethod_Test() throws ExecutionException, InterruptedException { msgStr = """ {"list": ["B", "A", "C", "A"]} @@ -800,7 +801,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected.toString(), actual.toString()); } - @Test + @Test public void setsForeachForLoop_Test() throws ExecutionException, InterruptedException { msgStr = """ {"list": ["A", "B", "C"]} @@ -975,13 +976,13 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { ArrayList listSortDesc = new ArrayList<>(List.of("hello", "C", "B", "A", 34567, 34)); Set expectedDesc = new LinkedHashSet<>(listSortDesc); Object actual = invokeScript(evalScript(decoderStr), msgStr); - assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set1").toString()); - assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set1_asc").toString()); - assertEquals(expectedDesc.toString(), ((LinkedHashMap)actual).get("set1_desc").toString()); - assertEquals(expected.toString(), ((LinkedHashMap)actual).get("set2").toString()); - assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set3").toString()); - assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set3_asc").toString()); - assertEquals(expectedDesc.toString(), ((LinkedHashMap)actual).get("set3_desc").toString()); + assertEquals(expectedAsc.toString(), ((LinkedHashMap) actual).get("set1").toString()); + assertEquals(expectedAsc.toString(), ((LinkedHashMap) actual).get("set1_asc").toString()); + assertEquals(expectedDesc.toString(), ((LinkedHashMap) actual).get("set1_desc").toString()); + assertEquals(expected.toString(), ((LinkedHashMap) actual).get("set2").toString()); + assertEquals(expectedAsc.toString(), ((LinkedHashMap) actual).get("set3").toString()); + assertEquals(expectedAsc.toString(), ((LinkedHashMap) actual).get("set3_asc").toString()); + assertEquals(expectedDesc.toString(), ((LinkedHashMap) actual).get("set3_desc").toString()); } @Test @@ -1002,9 +1003,9 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { List listOrigin = new ArrayList<>(List.of("C", "B", "A", 34567, "B", "C", "hello", 34)); Set expectedSet = new LinkedHashSet<>(listOrigin); Object actual = invokeScript(evalScript(decoderStr), msgStr); - assertEquals(expectedSet.toString(), ((LinkedHashMap)actual).get("set1").toString()); - assertEquals(true, ((LinkedHashMap)actual).get("result1")); - assertEquals(false, ((LinkedHashMap)actual).get("result2")); + assertEquals(expectedSet.toString(), ((LinkedHashMap) actual).get("set1").toString()); + assertEquals(true, ((LinkedHashMap) actual).get("result1")); + assertEquals(false, ((LinkedHashMap) actual).get("result2")); } @Test @@ -1025,9 +1026,9 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { Set expectedSet = new LinkedHashSet<>(listOrigin); List expectedToList = new ArrayList<>(expectedSet); Object actual = invokeScript(evalScript(decoderStr), msgStr); - assertEquals(listOrigin.toString(), ((LinkedHashMap)actual).get("list").toString()); - assertEquals(expectedSet.toString(), ((LinkedHashMap)actual).get("set1").toString()); - assertEquals(expectedToList.toString(), ((LinkedHashMap)actual).get("tolist").toString()); + assertEquals(listOrigin.toString(), ((LinkedHashMap) actual).get("list").toString()); + assertEquals(expectedSet.toString(), ((LinkedHashMap) actual).get("set1").toString()); + assertEquals(expectedToList.toString(), ((LinkedHashMap) actual).get("tolist").toString()); } @Test @@ -1713,7 +1714,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected, actual); } - @Test + @RepeatedTest(value = 3, name = "{displayName} {currentRepetition}/{totalRepetitions}") public void parseBytes_Test() throws ExecutionException, InterruptedException { byte[] bytesExecutionArrayList = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD}; msgStr = "{}"; @@ -2821,5 +2822,6 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } return list; } + } diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java index 7fb56a89ff..ec8eacbc67 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java @@ -898,11 +898,11 @@ public class TbUtils { public static int parseBytesToInt(byte[] data, int offset, int length, boolean bigEndian) { validationNumberByLength(data, offset, length, BYTES_LEN_INT_MAX); - var bb = ByteBuffer.allocate(4); + var bb = ByteBuffer.allocate(BYTES_LEN_INT_MAX); if (!bigEndian) { bb.order(ByteOrder.LITTLE_ENDIAN); } - bb.position(bigEndian ? 4 - length : 0); + bb.position(bigEndian ? BYTES_LEN_INT_MAX - length : 0); bb.put(data, offset, length); bb.position(0); return bb.getInt(); @@ -923,11 +923,11 @@ public class TbUtils { public static long parseBytesToUnsignedInt(byte[] data, int offset, int length, boolean bigEndian) { validationNumberByLength(data, offset, length, BYTES_LEN_INT_MAX); - ByteBuffer bb = ByteBuffer.allocate(8); + ByteBuffer bb = ByteBuffer.allocate(BYTES_LEN_LONG_MAX); if (!bigEndian) { bb.order(ByteOrder.LITTLE_ENDIAN); } - bb.position(bigEndian ? 8 - length : 0); + bb.position(bigEndian ? BYTES_LEN_LONG_MAX - length : 0); bb.put(data, offset, length); bb.position(0); diff --git a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java index bdafeac8a7..ef1729ab73 100644 --- a/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java +++ b/common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java @@ -155,6 +155,101 @@ public class TbUtilsTest { Assertions.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false)); } + @Test + public void parseBytesToInt_doesNotChangeInputData() { + byte[] data = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD}; + byte[] copy = data.clone(); + TbUtils.parseBytesToInt(data, 0, 4, true); + Assertions.assertArrayEquals(copy, data); + TbUtils.parseBytesToInt(data, 0, 4, false); + Assertions.assertArrayEquals(copy, data); + + TbUtils.parseBytesToUnsignedInt(data, 0, 4, true); + Assertions.assertArrayEquals(copy, data); + TbUtils.parseBytesToUnsignedInt(data, 0, 4, false); + Assertions.assertArrayEquals(copy, data); + + TbUtils.parseBytesToLong(data, 0, 4, true); + Assertions.assertArrayEquals(copy, data); + TbUtils.parseBytesToLong(data, 0, 4, false); + Assertions.assertArrayEquals(copy, data); + + TbUtils.parseBytesToFloat(data, 0, 4, true); + Assertions.assertArrayEquals(copy, data); + TbUtils.parseBytesToFloat(data, 0, 4, false); + Assertions.assertArrayEquals(copy, data); + + TbUtils.parseBytesIntToFloat(data, 0, 4, true); + Assertions.assertArrayEquals(copy, data); + TbUtils.parseBytesIntToFloat(data, 0, 4, false); + Assertions.assertArrayEquals(copy, data); + + TbUtils.parseBytesToDouble(data, 0, 4, true); + Assertions.assertArrayEquals(copy, data); + TbUtils.parseBytesToDouble(data, 0, 4, false); + Assertions.assertArrayEquals(copy, data); + + TbUtils.parseBytesLongToDouble(data, 0, 4, true); + Assertions.assertArrayEquals(copy, data); + TbUtils.parseBytesLongToDouble(data, 0, 4, false); + Assertions.assertArrayEquals(copy, data); + + List listData = toList(new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD}); + List listCopy = new ArrayList<>(listData); + TbUtils.parseBytesToInt(listData, 0, 4, true); + Assertions.assertEquals(listCopy, listData); + TbUtils.parseBytesToInt(listData, 0, 4, false); + Assertions.assertEquals(listCopy, listData); + + TbUtils.parseBytesToUnsignedInt(listData, 0, 4, true); + Assertions.assertEquals(listCopy, listData); + TbUtils.parseBytesToUnsignedInt(listData, 0, 4, false); + Assertions.assertEquals(listCopy, listData); + + TbUtils.parseBytesToLong(listData, 0, 4, true); + Assertions.assertEquals(listCopy, listData); + TbUtils.parseBytesToLong(listData, 0, 4, false); + Assertions.assertEquals(listCopy, listData); + + TbUtils.parseBytesToFloat(listData, 0, 4, true); + Assertions.assertEquals(listCopy, listData); + TbUtils.parseBytesToFloat(listData, 0, 4, false); + Assertions.assertEquals(listCopy, listData); + + TbUtils.parseBytesIntToFloat(listData, 0, 4, true); + Assertions.assertEquals(listCopy, listData); + TbUtils.parseBytesIntToFloat(listData, 0, 4, false); + Assertions.assertEquals(listCopy, listData); + + TbUtils.parseBytesToDouble(listData, 0, 4, true); + Assertions.assertEquals(listCopy, listData); + TbUtils.parseBytesToDouble(listData, 0, 4, false); + Assertions.assertEquals(listCopy, listData); + + TbUtils.parseBytesLongToDouble(listData, 0, 4, true); + Assertions.assertEquals(listCopy, listData); + TbUtils.parseBytesLongToDouble(listData, 0, 4, false); + Assertions.assertEquals(listCopy, listData); + } + + @Test + public void compare_parseBytesToInt_and_parseBytesToUnsignedInt() { + byte[] data = new byte[]{(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF}; + + // 4 bytes: parseBytesToInt returns -1, parseBytesToUnsignedInt returns 4294967295L + Assertions.assertEquals(-1, TbUtils.parseBytesToInt(data, 0, 4, true)); + Assertions.assertEquals(4294967295L, TbUtils.parseBytesToUnsignedInt(data, 0, 4, true)); + + // 2 bytes (0xFFFF): both return 65535 (no sign extension for parseBytesToInt when length < 4) + Assertions.assertEquals(65535, TbUtils.parseBytesToInt(data, 0, 2, true)); + Assertions.assertEquals(65535L, TbUtils.parseBytesToUnsignedInt(data, 0, 2, true)); + + // 2 bytes with high bit set (0x8000) + byte[] data2 = new byte[]{(byte) 0x80, (byte) 0x00}; + Assertions.assertEquals(32768, TbUtils.parseBytesToInt(data2, 0, 2, true)); + Assertions.assertEquals(32768L, TbUtils.parseBytesToUnsignedInt(data2, 0, 2, true)); + } + @Test public void toFlatMap() { ExecutionHashMap inputMap = new ExecutionHashMap<>(16, ctx); diff --git a/pom.xml b/pom.xml index 71ca7a1e48..e80f3d51f6 100755 --- a/pom.xml +++ b/pom.xml @@ -65,7 +65,7 @@ 3.9.3 3.25.5 1.76.0 - 1.2.8 + 1.2.9 1.18.38 1.2.5 1.2.5 @@ -837,6 +837,7 @@ **/test/resources/lwm2m/** **/resources/lwm2m/models/** src/main/data/resources/** + .claude/** JAVADOC_STYLE