From 77502b6c6cfb1be4964ce84510b13375a0e82674 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 12 Feb 2026 16:07:09 +0100 Subject: [PATCH] tests: ensure parseBytesTo methods do not alter input data --- .../thingsboard/script/api/tbel/TbUtils.java | 8 +- .../script/api/tbel/TbUtilsTest.java | 95 +++++++++++++++++++ 2 files changed, 99 insertions(+), 4 deletions(-) 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 6340b02dd0..e206d2d78d 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 01ccd5d579..622d298bbb 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);