From edba3517da4bfb91716abb3bdb7052876d23fce4 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 11 Jul 2025 14:37:02 +0300 Subject: [PATCH 1/7] tbel: add ExecutionArrayList with methods: add, addAll, remove, clear, sort, toSorted, toList --- .../service/script/TbelInvokeDocsIoTest.java | 258 ++++++++++++++++++ .../thingsboard/script/api/tbel/TbUtils.java | 21 ++ .../script/api/tbel/TbUtilsTest.java | 68 ++++- pom.xml | 2 +- 4 files changed, 344 insertions(+), 5 deletions(-) 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 c283a791fd..7900ca9b25 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 @@ -26,8 +26,10 @@ import java.util.Base64; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; @@ -750,6 +752,262 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected, actual); } + + // Sets + @Test + public void setsCreateNewSetFromMap_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"list": ["B", "A", "C", "A"]} + """; + decoderStr = """ + var originalMap = {}; + var set1 = originalMap.entrySet(); // create new Set from map, Empty + var set2 = set1.clone(); // clone new Set, Empty + var result1 = set1.addAll(msg.list); // addAll list, no sort, size = 3 ("A" - duplicate) + return {set1: set1, + set2: set2, + result1: result1 + } + """; + Set expectedSet1 = new LinkedHashSet(List.of("B", "A", "C", "A")); + Set expectedSet2 = new LinkedHashSet(); + Map expected = new LinkedHashMap<>(); + expected.put("set1", expectedSet1); + expected.put("set2", expectedSet2); + expected.put("result1", true); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected.toString(), actual.toString()); + } + + @Test + public void setsCreateNewSetFromCreateSetTbMethod_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"list": ["B", "A", "C", "A"]} + """; + decoderStr = """ + var set1 = createSetTb(msg.list); // create new Set from createSetTb() with list, no sort, size = 3 ("A" - duplicate) + var set2 = createSetTb(); // create new Set from createSetTb(), Empty + return {set1: set1, + set2: set2 + } + """; + Set expectedSet1 = new LinkedHashSet(List.of("B", "A", "C", "A")); + Set expectedSet2 = new LinkedHashSet(); + Map expected = new LinkedHashMap<>(); + expected.put("set1", expectedSet1); + expected.put("set2", expectedSet2); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected.toString(), actual.toString()); + } + + @Test + public void setsForeachForLoop_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"list": ["A", "B", "C"]} + """; + decoderStr = """ + var set2 = createSetTb(msg.list); // create new from list, size = 3 + var set2_0 = set2.toArray()[0]; // return "A", value with index = 0 from Set + var set2Size = set2.size(); // return size = 3 + var smthForeach = ""; + foreach (item : set2) { // foreach for Set + smthForeach += item; // return "ABC" + } + var smthForLoop= ""; + var set2Array = set2.toArray(); // for loop for Set (Set to array)) + for (var i =0; i < set2.size; i++) { + smthForLoop += set2Array[i]; // return "ABC" + } + return { + set2: set2, + set2_0: set2_0, + set2Size: set2Size, + smthForeach: smthForeach, + smthForLoop: smthForLoop + } + """; + Set expectedSet2 = new LinkedHashSet(List.of("A", "B", "C")); + Map expected = new LinkedHashMap<>(); + expected.put("set2", expectedSet2); + expected.put("set2_0", expectedSet2.toArray()[0]); + expected.put("set2Size", expectedSet2.size()); + AtomicReference smth = new AtomicReference<>(""); + expectedSet2.forEach(s -> smth.updateAndGet(v -> v + s)); + expected.put("smthForeach", smth.get()); + expected.put("smthForLoop", smth.get()); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected.toString(), actual.toString()); + } + + /** + * add + * delete/remove + * setCreate, setCreatList + */ + @Test + public void setsAddRemove_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"list": ["B", "C", "A", "B", "C", "hello", 34567]} + """; + decoderStr = """ + var msgRez = {}; + // add + var setAdd = createSetTb(["thigsboard", 4, 67]); // create new, size = 3 + var setAdd1_value = setAdd.clone(); // clone setAdd, size = 3 + var setAdd2_result = setAdd.add(35); // add value = 35, result = true + var setAdd2_value = setAdd.clone(); // clone setAdd (fixing the result add = 35), size = 4 + var setAddList1 = createSetTb(msg.list); // create new from list without duplicate value ("B" and "C" - only one), size = 5 + var setAdd3_result = setAdd.addAll(setAddList1); // add all without duplicate values, result = true + var setAdd3_value = setAdd.clone(); // clone setAdd (with addAll), size = 9 + var setAdd4_result = setAdd.add(35); // add duplicate value = 35, result = false + var setAdd4_value = setAdd.clone(); // clone setAdd (after add duplicate value = 35), size = 9 + var setAddList2 = createSetTb(msg.list); // create new from list without duplicate value ("B" and "C" - only one), start: size = 5, finish: size = 7 + var setAdd5_result1 = setAddList2.add(72); // add is not duplicate value = 72, result = true + var setAdd5_result2 = setAddList2.add(72); // add duplicate value = 72, result = false + var setAdd5_result3 = setAddList2.add("hello25"); // add is not duplicate value = "hello25", result = true + var setAdd5_value = setAddList2.clone(); // clone setAddList2, size = 7 + var setAdd6_result = setAdd.addAll(setAddList2); // add all with duplicate values, result = true + var setAdd6_value = setAdd.clone(); // clone setAdd (after addAll setAddList2), before size = 9, after size = 11, added only is not duplicate values {"hello25", 72} + + // remove + var setAdd7_value = setAdd6_value.clone(); // clone setAdd6_value, before size = 11, after remove value = 4 size = 10 + var setAdd7_result = setAdd7_value.remove(4); // remove value = 4, result = true + var setAdd8_value = setAdd7_value.clone(); // clone setAdd7_value, before size = 10, after clear size = 0 + setAdd8_value.clear(); // setAdd8_value clear, result size = 0 + return { + "setAdd1_value": setAdd1_value, + "setAdd2_result": setAdd2_result, + "setAdd2_value": setAdd2_value, + "setAddList1": setAddList1, + "setAdd3_result": setAdd3_result, + "setAdd3_value": setAdd3_value, + "setAdd4_result": setAdd4_result, + "setAdd4_value": setAdd4_value, + "setAdd5_result1": setAdd5_result1, + "setAdd5_result2": setAdd5_result2, + "setAdd5_result3": setAdd5_result3, + "setAddList2": setAddList2, + "setAdd5_value": setAdd5_value, + "setAdd6_result": setAdd6_result, + "setAdd6_value": setAdd6_value, + "setAdd7_result": setAdd7_result, + "setAdd7_value": setAdd7_value, + "setAdd8_value": setAdd8_value + }; + """; + ArrayList list = new ArrayList<>(List.of("B", "C", "A", "B", "C", "hello", 34567)); + ArrayList listAdd = new ArrayList<>(List.of("thigsboard", 4, 67)); + Set setAdd = new LinkedHashSet<>(listAdd); + Set setAdd1_value = new LinkedHashSet<>(setAdd); + boolean setAdd2_result = setAdd.add(35); + Set setAdd2_value = new LinkedHashSet<>(setAdd); + Set setAddList1 = new LinkedHashSet<>(list); + boolean setAdd3_result = setAdd.addAll(setAddList1); + Set setAdd3_value = new LinkedHashSet<>(setAdd); + boolean setAdd4_result = setAdd.add(35); + Set setAdd4_value = new LinkedHashSet<>(setAdd); + Set setAddList2 = new LinkedHashSet<>(list); + boolean setAdd5_result1 = setAddList2.add(72); + boolean setAdd5_result2 = setAddList2.add(72); + boolean setAdd5_result3 = setAddList2.add("hello25"); + Set setAdd5_value = new LinkedHashSet<>(setAddList2); + boolean setAdd6_result = setAdd.addAll(setAddList2); + Set setAdd6_value = new LinkedHashSet<>(setAdd); + // remove + Set setAdd7_value = new LinkedHashSet<>(setAdd6_value); + boolean setAdd7_result = setAdd7_value.remove(4); + Set setAdd8_value = new LinkedHashSet<>(setAdd7_value); + setAdd8_value.clear(); + + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("setAdd1_value", setAdd1_value); + expected.put("setAdd2_result", setAdd2_result); + expected.put("setAdd2_value", setAdd2_value); + expected.put("setAddList1", setAddList1); + expected.put("setAdd3_result", setAdd3_result); + expected.put("setAdd3_value", setAdd3_value); + expected.put("setAdd4_result", setAdd4_result); + expected.put("setAdd4_value", setAdd4_value); + expected.put("setAdd5_result1", setAdd5_result1); + expected.put("setAdd5_result2", setAdd5_result2); + expected.put("setAdd5_result3", setAdd5_result3); + expected.put("setAddList2", setAddList2); + expected.put("setAdd5_value", setAdd5_value); + expected.put("setAdd6_result", setAdd6_result); + expected.put("setAdd6_value", setAdd6_value); + expected.put("setAdd7_result", setAdd7_result); + expected.put("setAdd7_value", setAdd7_value); + expected.put("setAdd8_value", setAdd8_value); + + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected.toString(), actual.toString()); + } + + @Test + public void setsSort_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} + """; + decoderStr = """ + var msgRez = {}; + var set1 = msgRez.entrySet(); // create Set from map, size = 0 + set1.addAll(msg.list); // addAll to set1 from list no sort (length = 8), but set`s size = 6 ("A" and "C" is duplicated) + var set2 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) + var set1_asc = set1.clone(); // clone set1, size = 6 + var set1_desc = set1.clone(); // clone set1, size = 6 + var set2_asc = set2.clone(); // clone set2, size = 6 + var set2_desc = set2.clone(); // clone set2, size = 6 + set1.sort(); // sort set1 -> asc + set1_asc.sort(true); // sort set1_asc -> asc + set1_desc.sort(false); // sort set1_desc -> desc + set2.sort(); // sort set2 -> asc + set2_asc.sort(true); // sort set2_asc -> asc + set2_desc.sort(false); // sort set2_desc -> desc + return { + "set1": set1, + "set1_asc": set1_asc, + "set1_desc": set1_desc, + "set2": set2, + "set2_asc": set2_asc, + "set2_desc": set2_desc, + } + """; + ArrayList listSortAsc = new ArrayList<>(List.of(34, 34567, "A", "B", "C", "hello")); + Set expectedAsc = new LinkedHashSet<>(listSortAsc); + 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(expectedAsc.toString(), ((LinkedHashMap)actual).get("set2").toString()); + assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set2_asc").toString()); + assertEquals(expectedDesc.toString(), ((LinkedHashMap)actual).get("set1_desc").toString()); + assertEquals(expectedDesc.toString(), ((LinkedHashMap)actual).get("set2_desc").toString()); + } + + @Test + public void setsToList_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} + """; + decoderStr = """ + var set1 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) + var tolist = set1.toList(); // create new List from Set, size = 6 + return { + "list": msg.list, + "set1": set1, + "tolist": tolist + } + """; + List listOrigin = new ArrayList<>(List.of("C", "B", "A", 34567, "B", "C", "hello", 34)); + 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()); + } + @Test public void arraysWillCauseArrayIndexOutOfBoundsException_Test() throws ExecutionException, InterruptedException { msgStr = """ 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 b782040a99..339cafd217 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 @@ -23,6 +23,7 @@ import org.mvel2.ExecutionContext; import org.mvel2.ParserConfiguration; import org.mvel2.execution.ExecutionArrayList; import org.mvel2.execution.ExecutionHashMap; +import org.mvel2.execution.ExecutionLinkedHashSet; import org.mvel2.util.MethodStub; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.geo.Coordinates; @@ -46,6 +47,7 @@ import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -386,6 +388,12 @@ public class TbUtils { Object.class))); parserConfig.addImport("isArray", new MethodStub(TbUtils.class.getMethod("isArray", Object.class))); + parserConfig.addImport("createSetTb", new MethodStub(TbUtils.class.getMethod("createSetTb", + ExecutionContext.class))); + parserConfig.addImport("createSetTb", new MethodStub(TbUtils.class.getMethod("createSetTb", + List.class, ExecutionContext.class))); + parserConfig.addImport("isSet", new MethodStub(TbUtils.class.getMethod("isSet", + Object.class))); } public static String btoa(String input) { @@ -1481,6 +1489,19 @@ public class TbUtils { return obj != null && obj.getClass().isArray(); } + public static Set createSetTb(ExecutionContext ctx) { + return new ExecutionLinkedHashSet<>(ctx); + } + + public static Set createSetTb(List list, ExecutionContext ctx) { + Set newSet = new LinkedHashSet<>(list); + return new ExecutionLinkedHashSet<>(newSet, ctx); + } + + public static boolean isSet(Object obj) { + return obj instanceof Set; + } + private static byte isValidIntegerToByte(Integer val) { if (val > 255 || val < -128) { throw new NumberFormatException("The value '" + val + "' could not be correctly converted to a byte. " + 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 6d793f2c8d..1567fdeed8 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 @@ -28,6 +28,7 @@ import org.mvel2.ParserContext; import org.mvel2.SandboxedParserConfiguration; import org.mvel2.execution.ExecutionArrayList; import org.mvel2.execution.ExecutionHashMap; +import org.mvel2.execution.ExecutionLinkedHashSet; import java.io.IOException; import java.math.BigDecimal; @@ -39,14 +40,18 @@ import java.util.Base64; import java.util.Calendar; import java.util.Collections; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.Set; import java.util.concurrent.ExecutionException; import static java.lang.Character.MAX_RADIX; import static java.lang.Character.MIN_RADIX; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @Slf4j @@ -1184,10 +1189,11 @@ public class TbUtilsTest { @Test public void isList() throws ExecutionException, InterruptedException { - List liat = List.of(0x35); - assertTrue(TbUtils.isList(liat)); - assertFalse(TbUtils.isMap(liat)); - assertFalse(TbUtils.isArray(liat)); + List list = List.of(0x35); + assertTrue(TbUtils.isList(list)); + assertFalse(TbUtils.isMap(list)); + assertFalse(TbUtils.isArray(list)); + assertFalse(TbUtils.isSet(list)); } @Test @@ -1195,6 +1201,52 @@ public class TbUtilsTest { byte [] array = new byte[]{1, 2, 3}; assertTrue(TbUtils.isArray(array)); assertFalse(TbUtils.isList(array)); + assertFalse(TbUtils.isSet(array)); + } + + @Test + public void isSet() throws ExecutionException, InterruptedException { + Set set = toSet(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA}); + assertTrue(TbUtils.isSet(set)); + assertFalse(TbUtils.isList(set)); + assertFalse(TbUtils.isArray(set)); + } + @Test + public void setTest() throws ExecutionException, InterruptedException { + Set actual = TbUtils.createSetTb(ctx); + Set expected = toSet(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xCC}); + actual.add((byte) 0xDD); + actual.add((byte) 0xCC); + actual.add((byte) 0xCC); + assertTrue(expected.containsAll(actual)); + List list = toList(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA}); + actual.addAll(list); + assertEquals(4, actual.size()); + assertTrue(actual.containsAll(expected)); + actual = TbUtils.createSetTb(list, ctx); + expected = toSet(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xDA}); + actual.add((byte) 0xDA); + actual.remove((byte) 0xBB); + actual.remove((byte) 0xAA); + assertTrue(expected.containsAll(actual)); + assertEquals(actual.size(), 3); + actual.clear(); + assertTrue(actual.isEmpty()); + actual = TbUtils.createSetTb(list, ctx); + Set actualClone = TbUtils.createSetTb(list, ctx); + Set actualClone_asc = TbUtils.createSetTb(list, ctx); + Set actualClone_desc = TbUtils.createSetTb(list, ctx); + ((ExecutionLinkedHashSet)actualClone).sort(); + ((ExecutionLinkedHashSet)actualClone_asc).sort(true); + ((ExecutionLinkedHashSet)actualClone_desc).sort(false); + assertEquals(list.toString(), actual.toString()); + assertNotEquals(list.toString(), actualClone.toString()); + Collections.sort(list); + assertEquals(list.toString(), actualClone.toString()); + assertEquals(list.toString(), actualClone_asc.toString()); + Collections.sort(list, Collections.reverseOrder()); + assertNotEquals(list.toString(), actualClone_asc.toString()); + assertEquals(list.toString(), actualClone_desc.toString()); } private static List toList(byte[] data) { @@ -1204,5 +1256,13 @@ public class TbUtilsTest { } return result; } + + private static Set toSet(byte[] data) { + Set result = new LinkedHashSet<>(); + for (Byte b : data) { + result.add(b); + } + return result; + } } diff --git a/pom.xml b/pom.xml index 64cdd63eaf..f26581507a 100755 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ 3.9.3 3.25.5 1.63.0 - 1.2.6 + 1.2.7 1.18.32 1.2.5 1.2.5 From 03c135e6ca0be1da64eaf8a9572f00db52ea9e03 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 11 Jul 2025 15:18:46 +0300 Subject: [PATCH 2/7] tbel: add to tests isSet --- .../service/script/TbelInvokeDocsIoTest.java | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) 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 7900ca9b25..d49e091a5e 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 @@ -2657,25 +2657,21 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { list.add(0x35); return isList(list); """); + + } + + + @Test + public void isSet_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} + """; + decoderStr = """ + return isSet(createSetTb(msg.list)); // return true + """; Object actual = invokeScript(evalScript(decoderStr), msgStr); assertInstanceOf(Boolean.class, actual); assertTrue((Boolean) actual); - decoderStr = String.format(""" - var list = []; - list.add(0x35); - return isMap(list); - """); - actual = invokeScript(evalScript(decoderStr), msgStr); - assertInstanceOf(Boolean.class, actual); - assertFalse((Boolean) actual); - decoderStr = String.format(""" - var list = []; - list.add(0x35); - return isArray(list); - """); - actual = invokeScript(evalScript(decoderStr), msgStr); - assertInstanceOf(Boolean.class, actual); - assertFalse((Boolean) actual); } @Test @@ -2693,16 +2689,6 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { Object actual = invokeScript(evalScript(decoderStr), msgStr); assertInstanceOf(Boolean.class, actual); assertTrue((Boolean) actual); - decoderStr = """ - var array = new int[3]; - array[0] = 1; - array[1] = 2; - array[2] = 3; - return isList(array); - """; - actual = invokeScript(evalScript(decoderStr), msgStr); - assertInstanceOf(Boolean.class, actual); - assertFalse((Boolean) actual); } @Test From 62c8c1dbc0e4d8faa19e86d699b498b491727d9a Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 11 Jul 2025 15:19:37 +0300 Subject: [PATCH 3/7] tbel: add to tests isSet refactoring --- .../thingsboard/server/service/script/TbelInvokeDocsIoTest.java | 2 -- 1 file changed, 2 deletions(-) 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 d49e091a5e..b318fee08f 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 @@ -2657,10 +2657,8 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { list.add(0x35); return isList(list); """); - } - @Test public void isSet_Test() throws ExecutionException, InterruptedException { msgStr = """ From baf68bbbfcedbd33e2cc987b421dad1654af177f Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 11 Jul 2025 16:39:03 +0300 Subject: [PATCH 4/7] tbel: refactoring --- .../java/org/thingsboard/script/api/tbel/TbUtils.java | 4 ++-- .../org/thingsboard/script/api/tbel/TbUtilsTest.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 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 339cafd217..e48d236dba 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 @@ -391,7 +391,7 @@ public class TbUtils { parserConfig.addImport("createSetTb", new MethodStub(TbUtils.class.getMethod("createSetTb", ExecutionContext.class))); parserConfig.addImport("createSetTb", new MethodStub(TbUtils.class.getMethod("createSetTb", - List.class, ExecutionContext.class))); + ExecutionContext.class, List.class))); parserConfig.addImport("isSet", new MethodStub(TbUtils.class.getMethod("isSet", Object.class))); } @@ -1493,7 +1493,7 @@ public class TbUtils { return new ExecutionLinkedHashSet<>(ctx); } - public static Set createSetTb(List list, ExecutionContext ctx) { + public static Set createSetTb(ExecutionContext ctx, List list) { Set newSet = new LinkedHashSet<>(list); return new ExecutionLinkedHashSet<>(newSet, ctx); } 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 1567fdeed8..b7a3f4c07d 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 @@ -1223,7 +1223,7 @@ public class TbUtilsTest { actual.addAll(list); assertEquals(4, actual.size()); assertTrue(actual.containsAll(expected)); - actual = TbUtils.createSetTb(list, ctx); + actual = TbUtils.createSetTb(ctx, list); expected = toSet(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xDA}); actual.add((byte) 0xDA); actual.remove((byte) 0xBB); @@ -1232,10 +1232,10 @@ public class TbUtilsTest { assertEquals(actual.size(), 3); actual.clear(); assertTrue(actual.isEmpty()); - actual = TbUtils.createSetTb(list, ctx); - Set actualClone = TbUtils.createSetTb(list, ctx); - Set actualClone_asc = TbUtils.createSetTb(list, ctx); - Set actualClone_desc = TbUtils.createSetTb(list, ctx); + actual = TbUtils.createSetTb(ctx, list); + Set actualClone = TbUtils.createSetTb(ctx, list); + Set actualClone_asc = TbUtils.createSetTb(ctx, list); + Set actualClone_desc = TbUtils.createSetTb(ctx, list); ((ExecutionLinkedHashSet)actualClone).sort(); ((ExecutionLinkedHashSet)actualClone_asc).sort(true); ((ExecutionLinkedHashSet)actualClone_desc).sort(false); From 017d523cc661c67d197714e7e9d7ffd8dfdd4c40 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 11 Jul 2025 18:24:51 +0300 Subject: [PATCH 5/7] tbel: test for docs: add Contains --- .../service/script/TbelInvokeDocsIoTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) 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 b318fee08f..ead78a349c 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 @@ -985,6 +985,29 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expectedDesc.toString(), ((LinkedHashMap)actual).get("set2_desc").toString()); } + @Test + public void setsContains_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} + """; + decoderStr = """ + var set1 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) + var result1 = set1.contains("A"); // return true + var result2 = set1.contains("H"); // return false + return { + "set1": set1, + "result1": result1, + "result2": result2 + } + """; + 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")); + } + @Test public void setsToList_Test() throws ExecutionException, InterruptedException { msgStr = """ From 3d5d84eb1ac0f00c508f5c94368dc6629a891f70 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 11 Jul 2025 20:21:39 +0300 Subject: [PATCH 6/7] tbel: test for docs: add toSorted --- .../service/script/TbelInvokeDocsIoTest.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) 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 ead78a349c..4aeb0d8c95 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 @@ -850,7 +850,6 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { {"list": ["B", "C", "A", "B", "C", "hello", 34567]} """; decoderStr = """ - var msgRez = {}; // add var setAdd = createSetTb(["thigsboard", 4, 67]); // create new, size = 3 var setAdd1_value = setAdd.clone(); // clone setAdd, size = 3 @@ -949,29 +948,28 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} """; decoderStr = """ - var msgRez = {}; - var set1 = msgRez.entrySet(); // create Set from map, size = 0 - set1.addAll(msg.list); // addAll to set1 from list no sort (length = 8), but set`s size = 6 ("A" and "C" is duplicated) - var set2 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) + var set1 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) + var set2 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) var set1_asc = set1.clone(); // clone set1, size = 6 var set1_desc = set1.clone(); // clone set1, size = 6 - var set2_asc = set2.clone(); // clone set2, size = 6 - var set2_desc = set2.clone(); // clone set2, size = 6 set1.sort(); // sort set1 -> asc set1_asc.sort(true); // sort set1_asc -> asc set1_desc.sort(false); // sort set1_desc -> desc - set2.sort(); // sort set2 -> asc - set2_asc.sort(true); // sort set2_asc -> asc - set2_desc.sort(false); // sort set2_desc -> desc + var set3 = set2.toSorted(); // toSorted set3 -> asc + var set3_asc = set2.toSorted(true); // toSorted set3 -> asc + var set3_desc = set2.toSorted(false); // toSorted set3 -> desc return { "set1": set1, "set1_asc": set1_asc, "set1_desc": set1_desc, "set2": set2, - "set2_asc": set2_asc, - "set2_desc": set2_desc, + "set3": set3, + "set3_asc": set3_asc, + "set3_desc": set3_desc, } """; + ArrayList list = new ArrayList<>(List.of("C", "B", "A", 34567, "hello", 34)); + Set expected = new LinkedHashSet<>(list); ArrayList listSortAsc = new ArrayList<>(List.of(34, 34567, "A", "B", "C", "hello")); Set expectedAsc = new LinkedHashSet<>(listSortAsc); ArrayList listSortDesc = new ArrayList<>(List.of("hello", "C", "B", "A", 34567, 34)); @@ -979,10 +977,11 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set1").toString()); assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set1_asc").toString()); - assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set2").toString()); - assertEquals(expectedAsc.toString(), ((LinkedHashMap)actual).get("set2_asc").toString()); assertEquals(expectedDesc.toString(), ((LinkedHashMap)actual).get("set1_desc").toString()); - assertEquals(expectedDesc.toString(), ((LinkedHashMap)actual).get("set2_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 From 5f6cc76d11d4bcc3cb300cf2cb7acc9fb9899a09 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Wed, 16 Jul 2025 17:31:59 +0300 Subject: [PATCH 7/7] tbel: reName createSetTb to newSet and to toSet --- .../service/script/TbelInvokeDocsIoTest.java | 22 +++++++++---------- .../thingsboard/script/api/tbel/TbUtils.java | 8 +++---- .../script/api/tbel/TbUtilsTest.java | 12 +++++----- 3 files changed, 21 insertions(+), 21 deletions(-) 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 4aeb0d8c95..a7affe6dff 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 @@ -785,8 +785,8 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { {"list": ["B", "A", "C", "A"]} """; decoderStr = """ - var set1 = createSetTb(msg.list); // create new Set from createSetTb() with list, no sort, size = 3 ("A" - duplicate) - var set2 = createSetTb(); // create new Set from createSetTb(), Empty + var set1 = toSet(msg.list); // create new Set from toSet() with list, no sort, size = 3 ("A" - duplicate) + var set2 = newSet(); // create new Set from newSet(), Empty return {set1: set1, set2: set2 } @@ -806,7 +806,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { {"list": ["A", "B", "C"]} """; decoderStr = """ - var set2 = createSetTb(msg.list); // create new from list, size = 3 + var set2 = toSet(msg.list); // create new from list, size = 3 var set2_0 = set2.toArray()[0]; // return "A", value with index = 0 from Set var set2Size = set2.size(); // return size = 3 var smthForeach = ""; @@ -851,16 +851,16 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { """; decoderStr = """ // add - var setAdd = createSetTb(["thigsboard", 4, 67]); // create new, size = 3 + var setAdd = toSet(["thigsboard", 4, 67]); // create new, size = 3 var setAdd1_value = setAdd.clone(); // clone setAdd, size = 3 var setAdd2_result = setAdd.add(35); // add value = 35, result = true var setAdd2_value = setAdd.clone(); // clone setAdd (fixing the result add = 35), size = 4 - var setAddList1 = createSetTb(msg.list); // create new from list without duplicate value ("B" and "C" - only one), size = 5 + var setAddList1 = toSet(msg.list); // create new from list without duplicate value ("B" and "C" - only one), size = 5 var setAdd3_result = setAdd.addAll(setAddList1); // add all without duplicate values, result = true var setAdd3_value = setAdd.clone(); // clone setAdd (with addAll), size = 9 var setAdd4_result = setAdd.add(35); // add duplicate value = 35, result = false var setAdd4_value = setAdd.clone(); // clone setAdd (after add duplicate value = 35), size = 9 - var setAddList2 = createSetTb(msg.list); // create new from list without duplicate value ("B" and "C" - only one), start: size = 5, finish: size = 7 + var setAddList2 = toSet(msg.list); // create new from list without duplicate value ("B" and "C" - only one), start: size = 5, finish: size = 7 var setAdd5_result1 = setAddList2.add(72); // add is not duplicate value = 72, result = true var setAdd5_result2 = setAddList2.add(72); // add duplicate value = 72, result = false var setAdd5_result3 = setAddList2.add("hello25"); // add is not duplicate value = "hello25", result = true @@ -948,8 +948,8 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} """; decoderStr = """ - var set1 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) - var set2 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) + var set1 = toSet(msg.list); // create new from method toSet(List list) no sort, size = 6 ("A" and "C" is duplicated) + var set2 = toSet(msg.list); // create new from method toSet(List list) no sort, size = 6 ("A" and "C" is duplicated) var set1_asc = set1.clone(); // clone set1, size = 6 var set1_desc = set1.clone(); // clone set1, size = 6 set1.sort(); // sort set1 -> asc @@ -990,7 +990,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} """; decoderStr = """ - var set1 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) + var set1 = toSet(msg.list); // create new from method toSet(List list) no sort, size = 6 ("A" and "C" is duplicated) var result1 = set1.contains("A"); // return true var result2 = set1.contains("H"); // return false return { @@ -1013,7 +1013,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} """; decoderStr = """ - var set1 = createSetTb(msg.list); // create new from method createSetTb(List list) no sort, size = 6 ("A" and "C" is duplicated) + var set1 = toSet(msg.list); // create new from method toSet(List list) no sort, size = 6 ("A" and "C" is duplicated) var tolist = set1.toList(); // create new List from Set, size = 6 return { "list": msg.list, @@ -2687,7 +2687,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { {"list": ["C", "B", "A", 34567, "B", "C", "hello", 34]} """; decoderStr = """ - return isSet(createSetTb(msg.list)); // return true + return isSet(toSet(msg.list)); // return true """; Object actual = invokeScript(evalScript(decoderStr), msgStr); assertInstanceOf(Boolean.class, actual); 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 e48d236dba..072a17835d 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 @@ -388,9 +388,9 @@ public class TbUtils { Object.class))); parserConfig.addImport("isArray", new MethodStub(TbUtils.class.getMethod("isArray", Object.class))); - parserConfig.addImport("createSetTb", new MethodStub(TbUtils.class.getMethod("createSetTb", + parserConfig.addImport("newSet", new MethodStub(TbUtils.class.getMethod("newSet", ExecutionContext.class))); - parserConfig.addImport("createSetTb", new MethodStub(TbUtils.class.getMethod("createSetTb", + parserConfig.addImport("toSet", new MethodStub(TbUtils.class.getMethod("toSet", ExecutionContext.class, List.class))); parserConfig.addImport("isSet", new MethodStub(TbUtils.class.getMethod("isSet", Object.class))); @@ -1489,11 +1489,11 @@ public class TbUtils { return obj != null && obj.getClass().isArray(); } - public static Set createSetTb(ExecutionContext ctx) { + public static Set newSet(ExecutionContext ctx) { return new ExecutionLinkedHashSet<>(ctx); } - public static Set createSetTb(ExecutionContext ctx, List list) { + public static Set toSet(ExecutionContext ctx, List list) { Set newSet = new LinkedHashSet<>(list); return new ExecutionLinkedHashSet<>(newSet, ctx); } 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 b7a3f4c07d..4dcbd2d69c 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 @@ -1213,7 +1213,7 @@ public class TbUtilsTest { } @Test public void setTest() throws ExecutionException, InterruptedException { - Set actual = TbUtils.createSetTb(ctx); + Set actual = TbUtils.newSet(ctx); Set expected = toSet(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xCC}); actual.add((byte) 0xDD); actual.add((byte) 0xCC); @@ -1223,7 +1223,7 @@ public class TbUtilsTest { actual.addAll(list); assertEquals(4, actual.size()); assertTrue(actual.containsAll(expected)); - actual = TbUtils.createSetTb(ctx, list); + actual = TbUtils.toSet(ctx, list); expected = toSet(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xDA}); actual.add((byte) 0xDA); actual.remove((byte) 0xBB); @@ -1232,10 +1232,10 @@ public class TbUtilsTest { assertEquals(actual.size(), 3); actual.clear(); assertTrue(actual.isEmpty()); - actual = TbUtils.createSetTb(ctx, list); - Set actualClone = TbUtils.createSetTb(ctx, list); - Set actualClone_asc = TbUtils.createSetTb(ctx, list); - Set actualClone_desc = TbUtils.createSetTb(ctx, list); + actual = TbUtils.toSet(ctx, list); + Set actualClone = TbUtils.toSet(ctx, list); + Set actualClone_asc = TbUtils.toSet(ctx, list); + Set actualClone_desc = TbUtils.toSet(ctx, list); ((ExecutionLinkedHashSet)actualClone).sort(); ((ExecutionLinkedHashSet)actualClone_asc).sort(true); ((ExecutionLinkedHashSet)actualClone_desc).sort(false);