From 57231f97245b298c08257dde6e2ee519af0a4e28 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 23 Oct 2024 18:21:31 +0300 Subject: [PATCH 01/18] tbel: add test tbel docsIo: map, list --- .../service/script/TbelInvokeDocsIoTest.java | 713 ++++++++++++++++++ 1 file changed, 713 insertions(+) create mode 100644 application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java 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 new file mode 100644 index 0000000000..1650ce81c7 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeDocsIoTest.java @@ -0,0 +1,713 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.script; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.script.api.ScriptType; +import org.thingsboard.script.api.tbel.TbelInvokeService; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.controller.AbstractControllerTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicReference; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; + +@DaoSqlTest +class TbelInvokeDocsIoTest extends AbstractControllerTest { + + @Autowired + private TbelInvokeService invokeService; + + private String decoderStr; + private String msgStr; + + private final String msgMapStr = "{\"temperature\": 42, \"nested\" : \"508\"};\n"; + private final LinkedHashMap expectedMap = new LinkedHashMap<>(Map.of("temperature", 42, "nested", "508")); + + // Simple Property Expression + @Test + void simplePropertyBooleanExpression_Test() throws ExecutionException, InterruptedException { + msgStr = "{\"temperature\": 15, \"humidity\" : 30}"; + decoderStr = "return (msg.temperature > 10 && msg.temperature < 20) || (msg.humidity > 10 && msg.humidity < 60);"; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + boolean expected = true; + assertEquals(expected, actual); + } + + // Multiple statements + @Test + public void multipleStatements_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = "var a = 2;\n" + + "var b = 2;\n" + + "return a + b;"; + Integer expected = 4; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + // Maps + @Test + public void mapsChangeValueKey_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "msg.temperature = 0;\n" + + "return msg;"; + LinkedHashMap expected = expectedMap; + expected.put("temperature", 0); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + + @Test + public void mapsCheckExistenceKey_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "if(msg.temperature != null){\n" + + " msg.temperature = 2;\n" + + "}\n" + + "return msg;"; + LinkedHashMap expected = expectedMap; + expected.put("temperature", 2); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsNullSafeExpressionsUsing_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "msg.existingKey = {};\n" + + "msg.existingKey.smth = 20;\n" + + "if(msg.?nonExistingKey.smth > 10){\n" + + " msg.temperature = 2;\n" + + "}\n" + + "if(msg.?existingKey.smth > 10){\n" + + " msg.nested = \"100\";\n" + + "}\n" + + "return msg;"; + LinkedHashMap expected = expectedMap; + expected.put("nested", "100"); + LinkedHashMap existingKey = new LinkedHashMap<>(Map.of("smth", 20)); + expected.put("existingKey", existingKey); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsIterateThrough_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "foreach(element : msg.entrySet()){\n" + + " if(element.getKey() == null){\n" + + " return raiseError(\"Bad getKey\");\n" + + " }\n" + + " if(element.key == null){\n" + + " return raiseError(\"Bad key\");\n" + + " }\n" + + " if(element.getValue() == null){\n" + + " return raiseError(\"Bad getValue\");\n" + + " }\n" + + " if(element.value == null){\n" + + " return raiseError(\"Bad value\");\n" + + " }\n" + + "}\n" + + "return msg;"; + LinkedHashMap expected = expectedMap; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsGetInfoSize_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "var size = msg.size();\n" + + "return size;"; + Integer expected = 2; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsGetInfoMemorySize_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = + "var memorySize = msg.memorySize();\n" + + "return memorySize;"; + Long expected = 24L; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsGetInfoPut_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "msg.humidity = 73;\n" + + "msg.put(\"humidity\", 74); \n" + + "msg.putIfAbsent(\"temperature1\", 73);\n" + + "return msg;"; + LinkedHashMap expected = expectedMap; + expected.put("humidity", 74); + expected.putIfAbsent("temperature1", 73); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsChangeValuePut_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = + "msg.temperature = 73;\n" + + "msg.putIfAbsent(\"temperature1\", 73);\n" + + "var put1 = msg.put(\"temperature\", 74);\n" + + "msg.putIfAbsent(\"humidity\", 73); \n" + + "var putIfAbsent1 = msg.putIfAbsent(\"humidity\", 74); \n" + + "return {map: msg,\n" + + " put1: put1,\n" + + " putIfAbsent1: putIfAbsent1\n" + + " }"; + LinkedHashMap expectedMapChangeValue = expectedMap; + expectedMapChangeValue.replace("temperature", 42, 74); + expectedMapChangeValue.put("humidity", 73); + expectedMapChangeValue.putIfAbsent("temperature1", 73); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("map", expectedMapChangeValue); + expected.put("put1", 73); + expected.put("putIfAbsent1", 73); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsChangeValueReplace_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "msg.put(\"humidity\", 73); \n" + + "msg.putIfAbsent(\"temperature1\", 73);\n" + + "var replace = msg.replace(\"temperature\", 56);\n" + + "var replace1 = msg.replace(\"temperature\", 56, 45);\n" + + "var replace2 = msg.replace(\"temperature\", 48, 56);\n" + + "return {map: msg,\n" + + " replace: replace,\n" + + " replace1: replace1,\n" + + " replace2: replace2\n" + + " }"; + LinkedHashMap expectedMapReplaceValue = expectedMap; + expectedMapReplaceValue.replace("temperature", 42, 45); + expectedMapReplaceValue.put("humidity", 73); + expectedMapReplaceValue.putIfAbsent("temperature1", 73); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("map", expectedMapReplaceValue); + expected.put("replace", 42); + expected.put("replace1", true); + expected.put("replace2", false); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsRemoveEntryFromMapByKey_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "msg.put(\"humidity\", 73); \n" + + "msg.putIfAbsent(\"temperature1\", 73);\n" + + "msg.remove(\"temperature\");\n" + + "return msg;"; + LinkedHashMap expected = expectedMap; + expected.put("humidity", 73); + expected.putIfAbsent("temperature1", 73); + expected.remove("temperature"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsGetKeysValues_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "msg.put(\"humidity\", 73); \n" + + "msg.putIfAbsent(\"temperature1\", 73);\n" + + "msg.remove(\"temperature\");\n" + + "var keys = msg.keys();\n" + + "var values = msg.values();\n" + + "return {keys: keys,\n" + + " values: values\n" + + " }"; + LinkedHashMap expectedMapKeysValues = expectedMap; + expectedMapKeysValues.put("humidity", 73); + expectedMapKeysValues.putIfAbsent("temperature1", 73); + expectedMapKeysValues.remove("temperature"); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("keys", expectedMapKeysValues.keySet().stream().toList()); + expected.put("values", expectedMapKeysValues.values().stream().toList()); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void mapsSort_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "msg.put(\"humidity\", 73); \n" + + "msg.putIfAbsent(\"temperature1\", 73);\n" + + "msg.remove(\"temperature\");\n" + + "msg.sortByKey();\n" + + "var mapSortByKey = msg.clone();\n" + + "var sortByValue = msg.sortByValue(); \n" + + "return {mapSortByKey: mapSortByKey,\n" + + " sortByValue: sortByValue,\n" + + " mapSortByValue: msg\n" + + " }"; + LinkedHashMap expectedMapSortByKey = new LinkedHashMap<>(); + expectedMapSortByKey.put("humidity", 73); + expectedMapSortByKey.put("nested", "508"); + expectedMapSortByKey.put("temperature1", 73); + LinkedHashMap expectedMapSortByValue = new LinkedHashMap<>(); + expectedMapSortByValue.put("humidity", 73); + expectedMapSortByValue.put("temperature1", 73); + expectedMapSortByValue.put("nested", "508"); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("mapSortByKey", expectedMapSortByKey); + expected.put("mapSortByValue", expectedMapSortByValue); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + assertEquals(expected.get("mapSortByKey"), ((LinkedHashMap) actual).get("mapSortByKey")); + assertEquals(((LinkedHashMap) expected.get("mapSortByKey")).keySet().toArray()[0], ((LinkedHashMap) ((LinkedHashMap) actual).get("mapSortByKey")).keySet().toArray()[0]); + assertEquals(((LinkedHashMap) expected.get("mapSortByKey")).keySet().toArray()[1], ((LinkedHashMap) ((LinkedHashMap) actual).get("mapSortByKey")).keySet().toArray()[1]); + assertEquals(((LinkedHashMap) expected.get("mapSortByKey")).keySet().toArray()[2], ((LinkedHashMap) ((LinkedHashMap) actual).get("mapSortByKey")).keySet().toArray()[2]); + assertEquals(expected.get("mapSortByValue"), ((LinkedHashMap) actual).get("mapSortByValue")); + assertEquals(((LinkedHashMap) expected.get("mapSortByValue")).keySet().toArray()[0], ((LinkedHashMap) ((LinkedHashMap) actual).get("mapSortByValue")).keySet().toArray()[0]); + assertEquals(((LinkedHashMap) expected.get("mapSortByValue")).keySet().toArray()[1], ((LinkedHashMap) ((LinkedHashMap) actual).get("mapSortByValue")).keySet().toArray()[1]); + assertEquals(((LinkedHashMap) expected.get("mapSortByValue")).keySet().toArray()[2], ((LinkedHashMap) ((LinkedHashMap) actual).get("mapSortByValue")).keySet().toArray()[2]); + } + + @Test + public void mapsAddNewEntry_Test() throws ExecutionException, InterruptedException { + msgStr = msgMapStr; + decoderStr = "msg.put(\"humidity\", 73); \n" + + "msg.putIfAbsent(\"temperature1\", 73);\n" + + "msg.remove(\"temperature\");\n" + + "var mapAdd = {\"test\": 12, \"input\" : {\"http\": 130}};\n" + + "msg.putAll(mapAdd);\n" + + "return msg;"; + LinkedHashMap expected = expectedMap; + expected.put("humidity", 73); + expected.putIfAbsent("temperature1", 73); + expected.remove("temperature"); + LinkedHashMap expectedMapAdd = new LinkedHashMap<>(); + expectedMapAdd.put("test", 12); + LinkedHashMap expectedInput = new LinkedHashMap<>(); + expectedInput.put("http", 130); + expectedMapAdd.put("input", expectedInput); + expected.putAll(expectedMapAdd); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + // Lists + @Test + public void listsCreateNewList_Test() throws ExecutionException, InterruptedException { + msgStr = "{\"list\": [\"A\", \"B\", \"C\"]}"; + decoderStr = "var list = msg.list;\n" + + "var list0 = list[0];\n" + + "var listSize = list.size();\n" + + "var smthForeach = \"\";\n" + + "foreach (item : list) {\n" + + " smthForeach += item;\n" + + "}\n" + + "var smthForLoop= \"\";\n" + + "for (var i =0; i < list.size; i++) {\n" + + " smthForLoop += list[i];\n" + + "}\n" + + "return {list: list,\n" + + " list0: list0,\n" + + " listSize: listSize,\n" + + " smthForeach: smthForeach,\n" + + " smthForLoop: smthForLoop\n" + + " }\n"; + List expectedList = new ArrayList<>(List.of("A", "B", "C")); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("list", expectedList); + expected.put("list0", expectedList.get(0)); + expected.put("listSize", expectedList.size()); + AtomicReference smth = new AtomicReference<>(""); + expectedList.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, actual); + } + + /** + * add/push + * delete + */ + @Test + public void listAddPushDelete_Test() throws ExecutionException, InterruptedException { + msgStr = "{\"list\": [\"A\", \"B\", \"C\", \"B\", \"C\", \"hello\", 34567]}"; + decoderStr = "var list = msg.list;\n" + + "var msgList = {};\n" + + "// add/push\n" + + "msgList.put(\"list\", list.clone());\n" + + "var listAdd = [\"thigsboard\", 4, 67];\n" + + "var addAll = list.addAll(listAdd);\n" + + "msgList.put(\"addAll\", addAll);\n" + + "msgList.put(\"addAllList\", list.clone());\n" + + "var addAllIndex = list.addAll(2, listAdd);\n" + + "msgList.put(\"addAllIndex\", addAllIndex);\n" + + "msgList.put(\"addAllIndexList\", list.clone());\n" + + "var addIndex = list.add(3, \"thigsboard\");\n" + + "if(addIndex != null) {\n" + + " msgList.put(\"addIndex\", addIndex);\n" + + "};\n" + + "msgList.put(\"addIndexList\", list.clone());\n" + + "var push = list.push(\"thigsboard\");\n" + + "msgList.put(\"push\", push);\n" + + "if(push != null) {\n" + + " msgList.put(\"push\", push);\n" + + "}\n" + + "msgList.put(\"pushList\", list.clone());\n" + + "var unshift = list.unshift(\"r\");\n" + + "msgList.put(\"unshift\", unshift);\n" + + "msgList.put(\"unshiftList\", list.clone());\n" + + "var unshiftQ = [\"Q\", 4];\n" + + "msgList.put(\"unshift\", list.unshift(unshiftQ));\n" + + "msgList.put(\"unshiftQunList\", list.clone());\n" + + "// delete\n" + + "msgList.put(\"removeIndex2\", list.remove(2));\n" + + "msgList.put(\"removeIndex2List\", list.clone());\n" + + "msgList.put(\"removeValueC\", list.remove(\"C\"));\n" + + "msgList.put(\"removeValueCList\", list.clone());\n" + + "msgList.put(\"shift\", list.shift());\n" + + "msgList.put(\"shiftList\", list.clone());\n" + + "msgList.put(\"pop\", list.pop());\n" + + "msgList.put(\"popList\", list.clone());\n" + + "msgList.put(\"splice3\", list.splice(3));\n" + + "msgList.put(\"splice3List\", list.clone());\n" + + "msgList.put(\"splice2\", list.splice(2, 2));\n" + + "msgList.put(\"splice2List\", list.clone());\n" + + "msgList.put(\"splice1_4\", list.splice(1, 4, \"start\", 5, \"end\"));\n" + + "msgList.put(\"splice1_4List\", list.clone());\n" + + "return msgList"; + ArrayList list = new ArrayList<>(List.of("A", "B", "C", "B", "C", "hello", 34567)); + LinkedHashMap expected = new LinkedHashMap<>(); + // add/push + expected.put("list", list.clone()); + List listAdd = new ArrayList<>(List.of("thigsboard", 4, 67)); + expected.put("addAll", list.addAll(listAdd)); + expected.put("addAllList", list.clone()); + expected.put("addAllIndex", list.addAll(2, listAdd)); + expected.put("addAllIndexList", list.clone()); + list.add(3, "thigsboard"); + expected.put("addIndexList", list.clone()); + expected.put("push", list.add("thigsboard")); + expected.put("pushList", list.clone()); + list.add(0, "r"); + expected.put("unshiftList", list.clone()); + ArrayList unshiftQ = new ArrayList<>(List.of("Q", 4)); + list.add(0, unshiftQ); + expected.put("unshiftQunList", list.clone()); + // delete + expected.put("removeIndex2", list.remove(2)); + expected.put("removeIndex2List", list.clone()); + expected.put("removeValueC", list.remove("C")); + expected.put("removeValueCList", list.clone()); + expected.put("shift", list.remove(0)); + expected.put("shiftList", list.clone()); + expected.put("pop", list.remove(list.size() - 1)); + expected.put("popList", list.clone()); + expected.put("splice3", splice(list, 3)); + expected.put("splice3List", list.clone()); + expected.put("splice2", splice(list, 2, 2)); + expected.put("splice2List", list.clone()); + expected.put("splice1_4", splice(list, 1, 4, "start", 5, "end")); + expected.put("splice1_4List", list.clone()); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void listChange_Test() throws ExecutionException, InterruptedException { + msgStr = "{\"list\": [\"r\", \"start\", 5, \"end\"]}"; + decoderStr = "var list = msg.list;\n" + + "var msgList = {};\n" + + "msgList.put(\"list\", list.clone());\n" + + "msgList.put(\"set\", list.set(3, \"65\"));\n" + + "msgList.put(\"setList\", list.clone());\n" + + "list[1] = \"98\";\n" + + "msgList.put(\"listChangeIndex1List\", list.clone());\n" + + "list[0] = 2096;\n" + + "msgList.put(\"listChangeIndex0List\", list.clone());\n" + + "return msgList"; + ArrayList list = new ArrayList<>(List.of("r", "start", 5, "end")); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("list", list.clone()); + expected.put("set", list.set(3, "65")); + expected.put("setList", list.clone()); + list.set(1, "98"); + expected.put("listChangeIndex1List", list.clone()); + list.set(0, 2096); + expected.put("listChangeIndex0List", list.clone()); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void listSort_Test() throws ExecutionException, InterruptedException { + msgStr = "{\"list\": [2096, \"98\", 5, \"65\"]}"; + decoderStr = "var list = msg.list;\n" + + "var msgList = {};\n" + + "msgList.put(\"list\", list.clone());\n" + + "msgList.put(\"sort\", list.sort());\n" + + "msgList.put(\"sortList\", list.clone());\n" + + "msgList.put(\"sortTrue\", list.sort(true));\n" + + "msgList.put(\"sortTrueList\", list.clone());\n" + + "msgList.put(\"sortFalse\", list.sort(false));\n" + + "msgList.put(\"sortFalseList\", list.clone());\n" + + "msgList.put(\"reverse\", list.reverse());\n" + + "msgList.put(\"reverseList\", list.clone());\n" + + "msgList.put(\"fill\", list.fill(67));\n" + + "msgList.put(\"fillList\", list.clone());\n" + + "msgList.put(\"fill4\", list.fill(4, 1));\n" + + "msgList.put(\"fill4List\", list.clone());\n" + + "msgList.put(\"fill4_6\", list.fill(2, 1, 4));\n" + + "msgList.put(\"fill4_6List\", list.clone());\n" + + "return msgList"; + ArrayList list = new ArrayList<>(List.of(2096, "98", 5, "65")); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("list", list.clone()); + list.sort(numericCompAsc); + expected.put("sortList", list.clone()); + expected.put("sortTrueList", list.clone()); + list.sort(numericCompDesc); + expected.put("sortFalseList", list.clone()); + Collections.reverse(list); + expected.put("reverseList", list.clone()); + expected.put("fill", fill(list,67)); + expected.put("fillList", list.clone()); + expected.put("fill4", fill(list,4, 1)); + expected.put("fill4List", list.clone()); + expected.put("fill4_6", fill(list,2, 1, 4)); + expected.put("fill4_6List", list.clone()); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void listNewListOrStringSort_Test() throws ExecutionException, InterruptedException { + msgStr = "{\"list\": [67, 2, 2, 2]}"; + decoderStr = "var list = msg.list;\n" + + "var listAdd = [\"thigsboard\", 4, 67];\n" + + "var msgList = {};\n" + + "msgList.put(\"list\", list.clone());\n" + + "msgList.put(\"toSorted\", list.toSorted());\n" + + "msgList.put(\"toSortedList\", list.clone());\n" + + "msgList.put(\"toSortedTrue\", list.toSorted(true));\n" + + "msgList.put(\"toSortedTrueList\", list.clone());\n" + + "msgList.put(\"toSortedFalse\", list.toSorted(false));\n" + + "msgList.put(\"toSortedFalseList\", list.clone());\n" + + "msgList.put(\"toReversed\", list.toReversed());\n" + + "msgList.put(\"toReversedList\", list.clone());\n" + + "msgList.put(\"slice\", list.slice());\n" + + "msgList.put(\"sliceList\", list.clone());\n" + + "msgList.put(\"slice4\", list.slice(3));\n" + + "msgList.put(\"slice4List\", list.clone());\n" + + "msgList.put(\"slice1_5\", list.slice(0,2));\n" + + "msgList.put(\"slice1_5List\", list.clone());\n" + + "msgList.put(\"with1\", list.with(1, 69));\n" + + "msgList.put(\"with1List\", list.clone());\n" + + "msgList.put(\"concat\", list.concat(listAdd));\n" + + "msgList.put(\"concatList\", list.clone());\n" + + "msgList.put(\"join\", list.join());\n" + + "msgList.put(\"joinList\", list.clone());\n" + + "msgList.put(\"toSpliced2\", list.toSpliced(1, 0, \"Feb\"));\n" + + "msgList.put(\"toSpliced2List\", list.clone());\n" + + "msgList.put(\"toSpliced0_2\", list.toSpliced(0, 2));\n" + + "msgList.put(\"toSpliced0_2List\", list.clone());\n" + + "msgList.put(\"toSpliced2_2\", list.toSpliced(2, 2));\n" + + "msgList.put(\"toSpliced2_2List\", list.clone());\n" + + "msgList.put(\"toSpliced4_5\", list.toSpliced(2, 4, \"start\", 5, \"end\"));\n" + + "msgList.put(\"toSpliced4_5List\", list.clone());\n" + + "return msgList"; + ArrayList list = new ArrayList<>(List.of(67, 2, 2, 2)); + ArrayList oldList = (ArrayList) list.clone(); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("list", oldList); + list.sort(numericCompAsc); + expected.put("toSorted", list); + expected.put("toSortedList", oldList); + expected.put("toSortedTrue", list); + expected.put("toSortedTrueList", oldList); + list = (ArrayList) oldList.clone(); + list.sort(numericCompDesc); + expected.put("toSortedFalse", list); + expected.put("toSortedFalseList", oldList); + list = (ArrayList) oldList.clone(); + Collections.reverse(list); + expected.put("toReversed", list); + expected.put("toReversedList", oldList); + list = (ArrayList) oldList.clone(); + expected.put("slice", list); + expected.put("sliceList", oldList); + expected.put("slice4", list.subList(3, 4)); + expected.put("slice4List", oldList); + expected.put("slice1_5", list.subList(0, 2)); + expected.put("slice1_5List", oldList); + list = (ArrayList) oldList.clone(); + list.set(1, 69); + list.add(2); + expected.put("with1", list); + expected.put("with1List", oldList); + list = (ArrayList) oldList.clone(); + List listAdd = new ArrayList<>(List.of("thigsboard", 4, 67)); + list.addAll(listAdd); + expected.put("concat", list); + expected.put("concatList", oldList); + list = (ArrayList) oldList.clone(); + String join = list.toString().substring(1, list.toString().length()-1).replaceAll(" ", ""); + expected.put("join", join); + expected.put("joinList", oldList); + list.set(1, "Feb"); + list.add(2); + expected.put("toSpliced2", list); + expected.put("toSpliced2List", oldList); + list = (ArrayList) oldList.clone(); + list.remove(0); + list.remove(0); + expected.put("toSpliced0_2", list); + expected.put("toSpliced0_2List", oldList); + list = (ArrayList) oldList.clone(); + list.remove(2); + list.remove(2); + expected.put("toSpliced2_2", list); + expected.put("toSpliced2_2List", oldList); + list = (ArrayList) oldList.clone(); + list.remove(2); + list.remove(2); + list.add("start"); + list.add(5); + list.add("end"); + expected.put("toSpliced4_5", list); + expected.put("toSpliced4_5List", oldList); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void listGetInfo_Test() throws ExecutionException, InterruptedException { + msgStr = "{\"list\": [67, 2, 2, 2]}"; + decoderStr = "var list = msg.list;\n" + + "var listAdd = [\"thigsboard\", 4, 67];\n" + + "var msgList = {};\n" + + "msgList.put(\"list\", list.clone());\n" + + "msgList.put(\"length\", list.length());\n" + + "msgList.put(\"memorySize\", list.memorySize());\n" + + "msgList.put(\"indOf1\", list.indexOf(\"B\", 1));\n" + + "msgList.put(\"indOf2\", list.indexOf(2, 2));\n" + + "msgList.put(\"sStr\", list.validateClazzInArrayIsOnlyString());\n" + + "return msgList"; + ArrayList list = new ArrayList<>(List.of(67, 2, 2, 2)); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("list", list); + expected.put("length", list.size()); + expected.put("memorySize", 32L); + expected.put("indOf1", -1); + expected.put("indOf2", 2); + expected.put("sStr", false); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + private UUID evalScript(String script) throws ExecutionException, InterruptedException { + return invokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, script, "msg", "metadata", "msgType").get(); + } + + private Object invokeScript(UUID scriptId, String str) throws ExecutionException, InterruptedException { + var msg = JacksonUtil.fromString(str, Map.class); + return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get(); + } + + private List splice(List oldList, int start, int deleteCount, Object... values) { + start = initStartIndex(oldList, start); + deleteCount = deleteCount < 0 ? 0 : Math.min(deleteCount, (oldList.size() - start)); + List removed = new ArrayList<>(); + while (deleteCount > 0) { + removed.add(oldList.remove(start)); + deleteCount--; + } + int insertIdx = start; + for (Object e : values) { + oldList.add(insertIdx++, e); + } + return removed; + } + + private List splice(List oldList, int start) { + return this.splice(oldList, start, oldList.size() - start); + } + + private List fill(List oldList, Object value) { + return fill(oldList, value, 0); + } + + private List fill(List oldList, Object value, int start) { + return fill(oldList, value, start, oldList.size()); + } + private List fill(List oldList, Object value, int start, int end) { + start = initStartIndex(oldList, start); + end = initEndIndex(oldList, end); + + if (start < oldList.size() && end > start) { + for (int i = start; i < end; ++i) { + oldList.set(i, value); + } + } + return oldList; + } + + private int initStartIndex(List oldList, int start) { + return start < -oldList.size() ? 0 : + start < 0 ? start + oldList.size() : + start; + } + + private int initEndIndex(List oldList, int end) { + return end < -oldList.size() ? 0 : + end < 0 ? end + oldList.size() : + Math.min(end, oldList.size()); + } + private static final Comparator numericCompAsc = new Comparator() { + public int compare(Object o1, Object o2) { + Double first = Double.parseDouble(String.valueOf(o1)); + Double second = Double.parseDouble(String.valueOf(o2)); + return first.compareTo(second); + } + }; + + private static final Comparator numericCompDesc = new Comparator() { + public int compare(Object o1, Object o2) { + Double first = Double.parseDouble(String.valueOf(o1)); + Double second = Double.parseDouble(String.valueOf(o2)); + return second.compareTo(first); + } + }; +} + From a18105ca59e70b3245adaac37b984a2e60065e6b Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 24 Oct 2024 12:25:54 +0300 Subject: [PATCH 02/18] tbel_test_docsIo: add Abstract class --- .../script/AbstractTbelInvokeTest.java | 48 +++++++++++++++++++ .../service/script/TbelInvokeDocsIoTest.java | 23 +-------- .../service/script/TbelInvokeServiceTest.java | 35 ++++---------- 3 files changed, 57 insertions(+), 49 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/service/script/AbstractTbelInvokeTest.java diff --git a/application/src/test/java/org/thingsboard/server/service/script/AbstractTbelInvokeTest.java b/application/src/test/java/org/thingsboard/server/service/script/AbstractTbelInvokeTest.java new file mode 100644 index 0000000000..11b61f64c4 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/script/AbstractTbelInvokeTest.java @@ -0,0 +1,48 @@ +/** + * Copyright © 2016-2024 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.service.script; + +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.script.api.ScriptType; +import org.thingsboard.script.api.tbel.TbelInvokeService; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.controller.AbstractControllerTest; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; + +public abstract class AbstractTbelInvokeTest extends AbstractControllerTest { + + @Autowired + protected TbelInvokeService invokeService; + + protected UUID evalScript(String script) throws ExecutionException, InterruptedException { + return invokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, script, "msg", "metadata", "msgType").get(); + } + + protected String invokeScriptResultString(UUID scriptId, String str) throws ExecutionException, InterruptedException { + var msg = JacksonUtil.fromString(str, Map.class); + return invokeScript(scriptId, str).toString(); + } + protected Object invokeScript(UUID scriptId, String str) throws ExecutionException, InterruptedException { + var msg = JacksonUtil.fromString(str, Map.class); + return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get(); + } +} 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 1650ce81c7..db961b0839 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 @@ -16,12 +16,6 @@ package org.thingsboard.server.service.script; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.script.api.ScriptType; -import org.thingsboard.script.api.tbel.TbelInvokeService; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.controller.AbstractControllerTest; import org.thingsboard.server.dao.service.DaoSqlTest; import java.util.ArrayList; @@ -30,18 +24,13 @@ import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @DaoSqlTest -class TbelInvokeDocsIoTest extends AbstractControllerTest { - - @Autowired - private TbelInvokeService invokeService; +class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { private String decoderStr; private String msgStr; @@ -635,16 +624,6 @@ class TbelInvokeDocsIoTest extends AbstractControllerTest { Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); } - - private UUID evalScript(String script) throws ExecutionException, InterruptedException { - return invokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, script, "msg", "metadata", "msgType").get(); - } - - private Object invokeScript(UUID scriptId, String str) throws ExecutionException, InterruptedException { - var msg = JacksonUtil.fromString(str, Map.class); - return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get(); - } - private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); deleteCount = deleteCount < 0 ? 0 : Math.min(deleteCount, (oldList.size() - start)); diff --git a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java index 9e3b6221b1..071fdf77fc 100644 --- a/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/script/TbelInvokeServiceTest.java @@ -20,15 +20,10 @@ import com.github.benmanes.caffeine.cache.Cache; import org.junit.Assert; import org.junit.Ignore; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.script.api.ScriptType; -import org.thingsboard.script.api.tbel.TbelInvokeService; import org.thingsboard.script.api.tbel.TbelScript; -import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.controller.AbstractControllerTest; import org.thingsboard.server.dao.service.DaoSqlTest; import java.io.Serializable; @@ -42,7 +37,6 @@ import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_REQUEST; @DaoSqlTest @TestPropertySource(properties = { @@ -52,10 +46,7 @@ import static org.thingsboard.server.common.data.msg.TbMsgType.POST_TELEMETRY_RE "tbel.max_errors=2", "tbel.compiled_scripts_cache_size=100" }) -class TbelInvokeServiceTest extends AbstractControllerTest { - - @Autowired - private TbelInvokeService invokeService; +class TbelInvokeServiceTest extends AbstractTbelInvokeTest { @Value("${tbel.max_errors}") private int maxJsErrors; @@ -69,14 +60,14 @@ class TbelInvokeServiceTest extends AbstractControllerTest { for (int i = 0; i < 100; i++) { msg.put("temperature", i); boolean expected = i > 20; - boolean result = Boolean.parseBoolean(invokeScript(scriptId, JacksonUtil.toString(msg))); + boolean result = Boolean.parseBoolean(invokeScriptResultString(scriptId, JacksonUtil.toString(msg))); Assert.assertEquals(expected, result); } long startTs = System.currentTimeMillis(); for (int i = 0; i < iterations; i++) { msg.put("temperature", i); boolean expected = i > 20; - boolean result = Boolean.parseBoolean(invokeScript(scriptId, JacksonUtil.toString(msg))); + boolean result = Boolean.parseBoolean(invokeScriptResultString(scriptId, JacksonUtil.toString(msg))); Assert.assertEquals(expected, result); } long duration = System.currentTimeMillis() - startTs; @@ -101,7 +92,7 @@ class TbelInvokeServiceTest extends AbstractControllerTest { for (int i = 0; i < maxJsErrors; i++) { assertThatThrownBy(() -> { - invokeScript(scriptId, hugeMsg); + invokeScriptResultString(scriptId, hugeMsg); }).hasMessageContaining("input arguments exceed maximum"); } assertThatScriptIsBlocked(scriptId); @@ -114,7 +105,7 @@ class TbelInvokeServiceTest extends AbstractControllerTest { for (int i = 0; i < maxJsErrors; i++) { assertThatThrownBy(() -> { - invokeScript(scriptId, "{}"); + invokeScriptResultString(scriptId, "{}"); }).hasMessageContaining("result exceeds maximum allowed size"); } assertThatScriptIsBlocked(scriptId); @@ -182,7 +173,7 @@ class TbelInvokeServiceTest extends AbstractControllerTest { scriptsIds.add(scriptId); for (int j = 0; j < i; j++) { - invokeScript(scriptId, "{ \"temperature\": 12 }"); // so that scriptsIds is ordered by number of invocations + invokeScriptResultString(scriptId, "{ \"temperature\": 12 }"); // so that scriptsIds is ordered by number of invocations } } @@ -201,23 +192,13 @@ class TbelInvokeServiceTest extends AbstractControllerTest { UUID scriptRemovedFromCache = scriptsIds.get(0); assertThat(compiledScriptsCache.getIfPresent(scriptIdToHash.get(scriptRemovedFromCache))).isNull(); - invokeScript(scriptRemovedFromCache, "{ \"temperature\": 12 }"); + invokeScriptResultString(scriptRemovedFromCache, "{ \"temperature\": 12 }"); assertThat(compiledScriptsCache.getIfPresent(scriptIdToHash.get(scriptRemovedFromCache))).isNotNull(); } private void assertThatScriptIsBlocked(UUID scriptId) { assertThatThrownBy(() -> { - invokeScript(scriptId, "{}"); + invokeScriptResultString(scriptId, "{}"); }).hasMessageContaining("invocation is blocked due to maximum error"); } - - private UUID evalScript(String script) throws ExecutionException, InterruptedException { - return invokeService.eval(TenantId.SYS_TENANT_ID, ScriptType.RULE_NODE_SCRIPT, script, "msg", "metadata", "msgType").get(); - } - - private String invokeScript(UUID scriptId, String str) throws ExecutionException, InterruptedException { - var msg = JacksonUtil.fromString(str, Map.class); - return invokeService.invokeScript(TenantId.SYS_TENANT_ID, null, scriptId, msg, "{}", POST_TELEMETRY_REQUEST.name()).get().toString(); - } - } From 777104e6202cd3d1a024bb126e489a2e7c34a0d1 Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 24 Oct 2024 17:16:38 +0300 Subject: [PATCH 03/18] tbel_test_doc: refactoring String to Text Blocks --- .../service/script/TbelInvokeDocsIoTest.java | 525 ++++++++++-------- 1 file changed, 291 insertions(+), 234 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 db961b0839..3014cfcfa6 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 @@ -35,13 +35,17 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { private String decoderStr; private String msgStr; - private final String msgMapStr = "{\"temperature\": 42, \"nested\" : \"508\"};\n"; + private final String msgMapStr = """ + {"temperature": 42, "nested" : "508"}; + """; private final LinkedHashMap expectedMap = new LinkedHashMap<>(Map.of("temperature", 42, "nested", "508")); // Simple Property Expression @Test void simplePropertyBooleanExpression_Test() throws ExecutionException, InterruptedException { - msgStr = "{\"temperature\": 15, \"humidity\" : 30}"; + msgStr = """ + {"temperature": 15, "humidity" : 30} + """; decoderStr = "return (msg.temperature > 10 && msg.temperature < 20) || (msg.humidity > 10 && msg.humidity < 60);"; Object actual = invokeScript(evalScript(decoderStr), msgStr); boolean expected = true; @@ -52,9 +56,11 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void multipleStatements_Test() throws ExecutionException, InterruptedException { msgStr = "{}"; - decoderStr = "var a = 2;\n" + - "var b = 2;\n" + - "return a + b;"; + decoderStr = """ + var a = 2; + var b = 2; + return a + b; + """; Integer expected = 4; Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); @@ -64,8 +70,10 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsChangeValueKey_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "msg.temperature = 0;\n" + - "return msg;"; + decoderStr = """ + msg.temperature = 0; + return msg; + """; LinkedHashMap expected = expectedMap; expected.put("temperature", 0); Object actual = invokeScript(evalScript(decoderStr), msgStr); @@ -76,10 +84,12 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsCheckExistenceKey_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "if(msg.temperature != null){\n" + - " msg.temperature = 2;\n" + - "}\n" + - "return msg;"; + decoderStr = """ + if(msg.temperature != null){ + msg.temperature = 2; + } + return msg; + """; LinkedHashMap expected = expectedMap; expected.put("temperature", 2); Object actual = invokeScript(evalScript(decoderStr), msgStr); @@ -89,15 +99,17 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsNullSafeExpressionsUsing_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "msg.existingKey = {};\n" + - "msg.existingKey.smth = 20;\n" + - "if(msg.?nonExistingKey.smth > 10){\n" + - " msg.temperature = 2;\n" + - "}\n" + - "if(msg.?existingKey.smth > 10){\n" + - " msg.nested = \"100\";\n" + - "}\n" + - "return msg;"; + decoderStr = """ + msg.existingKey = {}; + msg.existingKey.smth = 20; + if(msg.?nonExistingKey.smth > 10){ + msg.temperature = 2; + } + if(msg.?existingKey.smth > 10){ + msg.nested = "100"; + } + return msg; + """; LinkedHashMap expected = expectedMap; expected.put("nested", "100"); LinkedHashMap existingKey = new LinkedHashMap<>(Map.of("smth", 20)); @@ -109,21 +121,23 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsIterateThrough_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "foreach(element : msg.entrySet()){\n" + - " if(element.getKey() == null){\n" + - " return raiseError(\"Bad getKey\");\n" + - " }\n" + - " if(element.key == null){\n" + - " return raiseError(\"Bad key\");\n" + - " }\n" + - " if(element.getValue() == null){\n" + - " return raiseError(\"Bad getValue\");\n" + - " }\n" + - " if(element.value == null){\n" + - " return raiseError(\"Bad value\");\n" + - " }\n" + - "}\n" + - "return msg;"; + decoderStr = """ + foreach(element : msg.entrySet()){ + if(element.getKey() == null){ + return raiseError("Bad getKey"); + } + if(element.key == null){ + return raiseError("Bad key"); + } + if(element.getValue() == null){ + return raiseError("Bad getValue"); + } + if(element.value == null){ + return raiseError("Bad value"); + } + } + return msg; + """; LinkedHashMap expected = expectedMap; Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); @@ -132,8 +146,10 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsGetInfoSize_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "var size = msg.size();\n" + - "return size;"; + decoderStr = """ + var size = msg.size(); + return size; + """; Integer expected = 2; Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); @@ -142,9 +158,10 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsGetInfoMemorySize_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = - "var memorySize = msg.memorySize();\n" + - "return memorySize;"; + decoderStr = """ + var memorySize = msg.memorySize(); + return memorySize; + """; Long expected = 24L; Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); @@ -153,10 +170,12 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsGetInfoPut_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "msg.humidity = 73;\n" + - "msg.put(\"humidity\", 74); \n" + - "msg.putIfAbsent(\"temperature1\", 73);\n" + - "return msg;"; + decoderStr = """ + msg.humidity = 73; + msg.put("humidity", 74); + msg.putIfAbsent("temperature1", 73); + return msg; + """; LinkedHashMap expected = expectedMap; expected.put("humidity", 74); expected.putIfAbsent("temperature1", 73); @@ -167,16 +186,17 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsChangeValuePut_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = - "msg.temperature = 73;\n" + - "msg.putIfAbsent(\"temperature1\", 73);\n" + - "var put1 = msg.put(\"temperature\", 74);\n" + - "msg.putIfAbsent(\"humidity\", 73); \n" + - "var putIfAbsent1 = msg.putIfAbsent(\"humidity\", 74); \n" + - "return {map: msg,\n" + - " put1: put1,\n" + - " putIfAbsent1: putIfAbsent1\n" + - " }"; + decoderStr = """ + msg.temperature = 73; + msg.putIfAbsent("temperature1", 73); + var put1 = msg.put("temperature", 74); + msg.putIfAbsent("humidity", 73); + var putIfAbsent1 = msg.putIfAbsent("humidity", 74); + return {map: msg, + put1: put1, + putIfAbsent1: putIfAbsent1 + }; + """; LinkedHashMap expectedMapChangeValue = expectedMap; expectedMapChangeValue.replace("temperature", 42, 74); expectedMapChangeValue.put("humidity", 73); @@ -192,16 +212,18 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsChangeValueReplace_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "msg.put(\"humidity\", 73); \n" + - "msg.putIfAbsent(\"temperature1\", 73);\n" + - "var replace = msg.replace(\"temperature\", 56);\n" + - "var replace1 = msg.replace(\"temperature\", 56, 45);\n" + - "var replace2 = msg.replace(\"temperature\", 48, 56);\n" + - "return {map: msg,\n" + - " replace: replace,\n" + - " replace1: replace1,\n" + - " replace2: replace2\n" + - " }"; + decoderStr = """ + msg.put("humidity", 73); + msg.putIfAbsent("temperature1", 73); + var replace = msg.replace("temperature", 56); + var replace1 = msg.replace("temperature", 56, 45); + var replace2 = msg.replace("temperature", 48, 56); + return {map: msg, + replace: replace, + replace1: replace1, + replace2: replace2 + } + """; LinkedHashMap expectedMapReplaceValue = expectedMap; expectedMapReplaceValue.replace("temperature", 42, 45); expectedMapReplaceValue.put("humidity", 73); @@ -218,10 +240,12 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsRemoveEntryFromMapByKey_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "msg.put(\"humidity\", 73); \n" + - "msg.putIfAbsent(\"temperature1\", 73);\n" + - "msg.remove(\"temperature\");\n" + - "return msg;"; + decoderStr = """ + msg.put("humidity", 73); + msg.putIfAbsent("temperature1", 73); + msg.remove("temperature"); + return msg; + """; LinkedHashMap expected = expectedMap; expected.put("humidity", 73); expected.putIfAbsent("temperature1", 73); @@ -233,14 +257,16 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsGetKeysValues_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "msg.put(\"humidity\", 73); \n" + - "msg.putIfAbsent(\"temperature1\", 73);\n" + - "msg.remove(\"temperature\");\n" + - "var keys = msg.keys();\n" + - "var values = msg.values();\n" + - "return {keys: keys,\n" + - " values: values\n" + - " }"; + decoderStr = """ + msg.put("humidity", 73); + msg.putIfAbsent("temperature1", 73); + msg.remove("temperature"); + var keys = msg.keys(); + var values = msg.values(); + return {keys: keys, + values: values + } + """; LinkedHashMap expectedMapKeysValues = expectedMap; expectedMapKeysValues.put("humidity", 73); expectedMapKeysValues.putIfAbsent("temperature1", 73); @@ -255,16 +281,18 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsSort_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "msg.put(\"humidity\", 73); \n" + - "msg.putIfAbsent(\"temperature1\", 73);\n" + - "msg.remove(\"temperature\");\n" + - "msg.sortByKey();\n" + - "var mapSortByKey = msg.clone();\n" + - "var sortByValue = msg.sortByValue(); \n" + - "return {mapSortByKey: mapSortByKey,\n" + - " sortByValue: sortByValue,\n" + - " mapSortByValue: msg\n" + - " }"; + decoderStr = """ + msg.put("humidity", 73); + msg.putIfAbsent("temperature1", 73); + msg.remove("temperature"); + msg.sortByKey(); + var mapSortByKey = msg.clone(); + var sortByValue = msg.sortByValue(); + return {mapSortByKey: mapSortByKey, + sortByValue: sortByValue, + mapSortByValue: msg + } + """; LinkedHashMap expectedMapSortByKey = new LinkedHashMap<>(); expectedMapSortByKey.put("humidity", 73); expectedMapSortByKey.put("nested", "508"); @@ -291,12 +319,14 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void mapsAddNewEntry_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; - decoderStr = "msg.put(\"humidity\", 73); \n" + - "msg.putIfAbsent(\"temperature1\", 73);\n" + - "msg.remove(\"temperature\");\n" + - "var mapAdd = {\"test\": 12, \"input\" : {\"http\": 130}};\n" + - "msg.putAll(mapAdd);\n" + - "return msg;"; + decoderStr = """ + msg.put("humidity", 73); + msg.putIfAbsent("temperature1", 73); + msg.remove("temperature"); + var mapAdd = {"test": 12, "input" : {"http": 130}}; + msg.putAll(mapAdd); + return msg; + """; LinkedHashMap expected = expectedMap; expected.put("humidity", 73); expected.putIfAbsent("temperature1", 73); @@ -314,24 +344,28 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { // Lists @Test public void listsCreateNewList_Test() throws ExecutionException, InterruptedException { - msgStr = "{\"list\": [\"A\", \"B\", \"C\"]}"; - decoderStr = "var list = msg.list;\n" + - "var list0 = list[0];\n" + - "var listSize = list.size();\n" + - "var smthForeach = \"\";\n" + - "foreach (item : list) {\n" + - " smthForeach += item;\n" + - "}\n" + - "var smthForLoop= \"\";\n" + - "for (var i =0; i < list.size; i++) {\n" + - " smthForLoop += list[i];\n" + - "}\n" + - "return {list: list,\n" + - " list0: list0,\n" + - " listSize: listSize,\n" + - " smthForeach: smthForeach,\n" + - " smthForLoop: smthForLoop\n" + - " }\n"; + msgStr = """ + {"list": ["A", "B", "C"]} + """; + decoderStr = """ + var list = msg.list; + var list0 = list[0]; + var listSize = list.size(); + var smthForeach = ""; + foreach (item : list) { + smthForeach += item; + } + var smthForLoop= ""; + for (var i =0; i < list.size; i++) { + smthForLoop += list[i]; + } + return {list: list, + list0: list0, + listSize: listSize, + smthForeach: smthForeach, + smthForLoop: smthForLoop + } + """; List expectedList = new ArrayList<>(List.of("A", "B", "C")); LinkedHashMap expected = new LinkedHashMap<>(); expected.put("list", expectedList); @@ -351,51 +385,55 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { */ @Test public void listAddPushDelete_Test() throws ExecutionException, InterruptedException { - msgStr = "{\"list\": [\"A\", \"B\", \"C\", \"B\", \"C\", \"hello\", 34567]}"; - decoderStr = "var list = msg.list;\n" + - "var msgList = {};\n" + - "// add/push\n" + - "msgList.put(\"list\", list.clone());\n" + - "var listAdd = [\"thigsboard\", 4, 67];\n" + - "var addAll = list.addAll(listAdd);\n" + - "msgList.put(\"addAll\", addAll);\n" + - "msgList.put(\"addAllList\", list.clone());\n" + - "var addAllIndex = list.addAll(2, listAdd);\n" + - "msgList.put(\"addAllIndex\", addAllIndex);\n" + - "msgList.put(\"addAllIndexList\", list.clone());\n" + - "var addIndex = list.add(3, \"thigsboard\");\n" + - "if(addIndex != null) {\n" + - " msgList.put(\"addIndex\", addIndex);\n" + - "};\n" + - "msgList.put(\"addIndexList\", list.clone());\n" + - "var push = list.push(\"thigsboard\");\n" + - "msgList.put(\"push\", push);\n" + - "if(push != null) {\n" + - " msgList.put(\"push\", push);\n" + - "}\n" + - "msgList.put(\"pushList\", list.clone());\n" + - "var unshift = list.unshift(\"r\");\n" + - "msgList.put(\"unshift\", unshift);\n" + - "msgList.put(\"unshiftList\", list.clone());\n" + - "var unshiftQ = [\"Q\", 4];\n" + - "msgList.put(\"unshift\", list.unshift(unshiftQ));\n" + - "msgList.put(\"unshiftQunList\", list.clone());\n" + - "// delete\n" + - "msgList.put(\"removeIndex2\", list.remove(2));\n" + - "msgList.put(\"removeIndex2List\", list.clone());\n" + - "msgList.put(\"removeValueC\", list.remove(\"C\"));\n" + - "msgList.put(\"removeValueCList\", list.clone());\n" + - "msgList.put(\"shift\", list.shift());\n" + - "msgList.put(\"shiftList\", list.clone());\n" + - "msgList.put(\"pop\", list.pop());\n" + - "msgList.put(\"popList\", list.clone());\n" + - "msgList.put(\"splice3\", list.splice(3));\n" + - "msgList.put(\"splice3List\", list.clone());\n" + - "msgList.put(\"splice2\", list.splice(2, 2));\n" + - "msgList.put(\"splice2List\", list.clone());\n" + - "msgList.put(\"splice1_4\", list.splice(1, 4, \"start\", 5, \"end\"));\n" + - "msgList.put(\"splice1_4List\", list.clone());\n" + - "return msgList"; + msgStr = """ + {"list": ["A", "B", "C", "B", "C", "hello", 34567]} + """; + decoderStr = """ + var list = msg.list; + var msgList = {}; + // add/push + msgList.put("list", list.clone()); + var listAdd = ["thigsboard", 4, 67]; + var addAll = list.addAll(listAdd); + msgList.put("addAll", addAll); + msgList.put("addAllList", list.clone()); + var addAllIndex = list.addAll(2, listAdd); + msgList.put("addAllIndex", addAllIndex); + msgList.put("addAllIndexList", list.clone()); + var addIndex = list.add(3, "thigsboard"); + if(addIndex != null) { + msgList.put("addIndex", addIndex); + }; + msgList.put("addIndexList", list.clone()); + var push = list.push("thigsboard"); + msgList.put("push", push); + if(push != null) { + msgList.put("push", push); + } + msgList.put("pushList", list.clone()); + var unshift = list.unshift("r"); + msgList.put("unshift", unshift); + msgList.put("unshiftList", list.clone()); + var unshiftQ = ["Q", 4]; + msgList.put("unshift", list.unshift(unshiftQ)); + msgList.put("unshiftQunList", list.clone()); + // delete + msgList.put("removeIndex2", list.remove(2)); + msgList.put("removeIndex2List", list.clone()); + msgList.put("removeValueC", list.remove("C")); + msgList.put("removeValueCList", list.clone()); + msgList.put("shift", list.shift()); + msgList.put("shiftList", list.clone()); + msgList.put("pop", list.pop()); + msgList.put("popList", list.clone()); + msgList.put("splice3", list.splice(3)); + msgList.put("splice3List", list.clone()); + msgList.put("splice2", list.splice(2, 2)); + msgList.put("splice2List", list.clone()); + msgList.put("splice1_4", list.splice(1, 4, "start", 5, "end")); + msgList.put("splice1_4List", list.clone()); + return msgList + """; ArrayList list = new ArrayList<>(List.of("A", "B", "C", "B", "C", "hello", 34567)); LinkedHashMap expected = new LinkedHashMap<>(); // add/push @@ -435,17 +473,21 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listChange_Test() throws ExecutionException, InterruptedException { - msgStr = "{\"list\": [\"r\", \"start\", 5, \"end\"]}"; - decoderStr = "var list = msg.list;\n" + - "var msgList = {};\n" + - "msgList.put(\"list\", list.clone());\n" + - "msgList.put(\"set\", list.set(3, \"65\"));\n" + - "msgList.put(\"setList\", list.clone());\n" + - "list[1] = \"98\";\n" + - "msgList.put(\"listChangeIndex1List\", list.clone());\n" + - "list[0] = 2096;\n" + - "msgList.put(\"listChangeIndex0List\", list.clone());\n" + - "return msgList"; + msgStr = """ + {"list": ["r", "start", 5, "end"]} + """; + decoderStr = """ + var list = msg.list; + var msgList = {}; + msgList.put("list", list.clone()); + msgList.put("set", list.set(3, "65")); + msgList.put("setList", list.clone()); + list[1] = "98"; + msgList.put("listChangeIndex1List", list.clone()); + list[0] = 2096; + msgList.put("listChangeIndex0List", list.clone()); + return msgList + """; ArrayList list = new ArrayList<>(List.of("r", "start", 5, "end")); LinkedHashMap expected = new LinkedHashMap<>(); expected.put("list", list.clone()); @@ -461,25 +503,29 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listSort_Test() throws ExecutionException, InterruptedException { - msgStr = "{\"list\": [2096, \"98\", 5, \"65\"]}"; - decoderStr = "var list = msg.list;\n" + - "var msgList = {};\n" + - "msgList.put(\"list\", list.clone());\n" + - "msgList.put(\"sort\", list.sort());\n" + - "msgList.put(\"sortList\", list.clone());\n" + - "msgList.put(\"sortTrue\", list.sort(true));\n" + - "msgList.put(\"sortTrueList\", list.clone());\n" + - "msgList.put(\"sortFalse\", list.sort(false));\n" + - "msgList.put(\"sortFalseList\", list.clone());\n" + - "msgList.put(\"reverse\", list.reverse());\n" + - "msgList.put(\"reverseList\", list.clone());\n" + - "msgList.put(\"fill\", list.fill(67));\n" + - "msgList.put(\"fillList\", list.clone());\n" + - "msgList.put(\"fill4\", list.fill(4, 1));\n" + - "msgList.put(\"fill4List\", list.clone());\n" + - "msgList.put(\"fill4_6\", list.fill(2, 1, 4));\n" + - "msgList.put(\"fill4_6List\", list.clone());\n" + - "return msgList"; + msgStr = """ + {"list": [2096, "98", 5, "65"]} + """; + decoderStr = """ + var list = msg.list; + var msgList = {}; + msgList.put("list", list.clone()); + msgList.put("sort", list.sort()); + msgList.put("sortList", list.clone()); + msgList.put("sortTrue", list.sort(true)); + msgList.put("sortTrueList", list.clone()); + msgList.put("sortFalse", list.sort(false)); + msgList.put("sortFalseList", list.clone()); + msgList.put("reverse", list.reverse()); + msgList.put("reverseList", list.clone()); + msgList.put("fill", list.fill(67)); + msgList.put("fillList", list.clone()); + msgList.put("fill4", list.fill(4, 1)); + msgList.put("fill4List", list.clone()); + msgList.put("fill4_6", list.fill(2, 1, 4)); + msgList.put("fill4_6List", list.clone()); + return msgList + """; ArrayList list = new ArrayList<>(List.of(2096, "98", 5, "65")); LinkedHashMap expected = new LinkedHashMap<>(); expected.put("list", list.clone()); @@ -490,11 +536,11 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { expected.put("sortFalseList", list.clone()); Collections.reverse(list); expected.put("reverseList", list.clone()); - expected.put("fill", fill(list,67)); + expected.put("fill", fill(list, 67)); expected.put("fillList", list.clone()); - expected.put("fill4", fill(list,4, 1)); + expected.put("fill4", fill(list, 4, 1)); expected.put("fill4List", list.clone()); - expected.put("fill4_6", fill(list,2, 1, 4)); + expected.put("fill4_6", fill(list, 2, 1, 4)); expected.put("fill4_6List", list.clone()); Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); @@ -502,40 +548,44 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listNewListOrStringSort_Test() throws ExecutionException, InterruptedException { - msgStr = "{\"list\": [67, 2, 2, 2]}"; - decoderStr = "var list = msg.list;\n" + - "var listAdd = [\"thigsboard\", 4, 67];\n" + - "var msgList = {};\n" + - "msgList.put(\"list\", list.clone());\n" + - "msgList.put(\"toSorted\", list.toSorted());\n" + - "msgList.put(\"toSortedList\", list.clone());\n" + - "msgList.put(\"toSortedTrue\", list.toSorted(true));\n" + - "msgList.put(\"toSortedTrueList\", list.clone());\n" + - "msgList.put(\"toSortedFalse\", list.toSorted(false));\n" + - "msgList.put(\"toSortedFalseList\", list.clone());\n" + - "msgList.put(\"toReversed\", list.toReversed());\n" + - "msgList.put(\"toReversedList\", list.clone());\n" + - "msgList.put(\"slice\", list.slice());\n" + - "msgList.put(\"sliceList\", list.clone());\n" + - "msgList.put(\"slice4\", list.slice(3));\n" + - "msgList.put(\"slice4List\", list.clone());\n" + - "msgList.put(\"slice1_5\", list.slice(0,2));\n" + - "msgList.put(\"slice1_5List\", list.clone());\n" + - "msgList.put(\"with1\", list.with(1, 69));\n" + - "msgList.put(\"with1List\", list.clone());\n" + - "msgList.put(\"concat\", list.concat(listAdd));\n" + - "msgList.put(\"concatList\", list.clone());\n" + - "msgList.put(\"join\", list.join());\n" + - "msgList.put(\"joinList\", list.clone());\n" + - "msgList.put(\"toSpliced2\", list.toSpliced(1, 0, \"Feb\"));\n" + - "msgList.put(\"toSpliced2List\", list.clone());\n" + - "msgList.put(\"toSpliced0_2\", list.toSpliced(0, 2));\n" + - "msgList.put(\"toSpliced0_2List\", list.clone());\n" + - "msgList.put(\"toSpliced2_2\", list.toSpliced(2, 2));\n" + - "msgList.put(\"toSpliced2_2List\", list.clone());\n" + - "msgList.put(\"toSpliced4_5\", list.toSpliced(2, 4, \"start\", 5, \"end\"));\n" + - "msgList.put(\"toSpliced4_5List\", list.clone());\n" + - "return msgList"; + msgStr = """ + {"list": [67, 2, 2, 2]} + """; + decoderStr = """ + var list = msg.list; + var listAdd = ["thigsboard", 4, 67]; + var msgList = {}; + msgList.put("list", list.clone()); + msgList.put("toSorted", list.toSorted()); + msgList.put("toSortedList", list.clone()); + msgList.put("toSortedTrue", list.toSorted(true)); + msgList.put("toSortedTrueList", list.clone()); + msgList.put("toSortedFalse", list.toSorted(false)); + msgList.put("toSortedFalseList", list.clone()); + msgList.put("toReversed", list.toReversed()); + msgList.put("toReversedList", list.clone()); + msgList.put("slice", list.slice()); + msgList.put("sliceList", list.clone()); + msgList.put("slice4", list.slice(3)); + msgList.put("slice4List", list.clone()); + msgList.put("slice1_5", list.slice(0,2)); + msgList.put("slice1_5List", list.clone()); + msgList.put("with1", list.with(1, 69)); + msgList.put("with1List", list.clone()); + msgList.put("concat", list.concat(listAdd)); + msgList.put("concatList", list.clone()); + msgList.put("join", list.join()); + msgList.put("joinList", list.clone()); + msgList.put("toSpliced2", list.toSpliced(1, 0, "Feb")); + msgList.put("toSpliced2List", list.clone()); + msgList.put("toSpliced0_2", list.toSpliced(0, 2)); + msgList.put("toSpliced0_2List", list.clone()); + msgList.put("toSpliced2_2", list.toSpliced(2, 2)); + msgList.put("toSpliced2_2List", list.clone()); + msgList.put("toSpliced4_5", list.toSpliced(2, 4, "start", 5, "end")); + msgList.put("toSpliced4_5List", list.clone()); + return msgList + """; ArrayList list = new ArrayList<>(List.of(67, 2, 2, 2)); ArrayList oldList = (ArrayList) list.clone(); LinkedHashMap expected = new LinkedHashMap<>(); @@ -571,7 +621,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { expected.put("concat", list); expected.put("concatList", oldList); list = (ArrayList) oldList.clone(); - String join = list.toString().substring(1, list.toString().length()-1).replaceAll(" ", ""); + String join = list.toString().substring(1, list.toString().length() - 1).replaceAll(" ", ""); expected.put("join", join); expected.put("joinList", oldList); list.set(1, "Feb"); @@ -602,17 +652,21 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listGetInfo_Test() throws ExecutionException, InterruptedException { - msgStr = "{\"list\": [67, 2, 2, 2]}"; - decoderStr = "var list = msg.list;\n" + - "var listAdd = [\"thigsboard\", 4, 67];\n" + - "var msgList = {};\n" + - "msgList.put(\"list\", list.clone());\n" + - "msgList.put(\"length\", list.length());\n" + - "msgList.put(\"memorySize\", list.memorySize());\n" + - "msgList.put(\"indOf1\", list.indexOf(\"B\", 1));\n" + - "msgList.put(\"indOf2\", list.indexOf(2, 2));\n" + - "msgList.put(\"sStr\", list.validateClazzInArrayIsOnlyString());\n" + - "return msgList"; + msgStr = """ + {"list": [67, 2, 2, 2]} + """; + decoderStr = """ + var list = msg.list; + var listAdd = ["thigsboard", 4, 67]; + var msgList = {}; + msgList.put("list", list.clone()); + msgList.put("length", list.length()); + msgList.put("memorySize", list.memorySize()); + msgList.put("indOf1", list.indexOf("B", 1)); + msgList.put("indOf2", list.indexOf(2, 2)); + msgList.put("sStr", list.validateClazzInArrayIsOnlyString()); + return msgList + """; ArrayList list = new ArrayList<>(List.of(67, 2, 2, 2)); LinkedHashMap expected = new LinkedHashMap<>(); expected.put("list", list); @@ -624,6 +678,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); } + private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); deleteCount = deleteCount < 0 ? 0 : Math.min(deleteCount, (oldList.size() - start)); @@ -650,6 +705,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { private List fill(List oldList, Object value, int start) { return fill(oldList, value, start, oldList.size()); } + private List fill(List oldList, Object value, int start, int end) { start = initStartIndex(oldList, start); end = initEndIndex(oldList, end); @@ -673,6 +729,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { end < 0 ? end + oldList.size() : Math.min(end, oldList.size()); } + private static final Comparator numericCompAsc = new Comparator() { public int compare(Object o1, Object o2) { Double first = Double.parseDouble(String.valueOf(o1)); From 9dc991a1d8507461618b1faeb1359da7757b3eca Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 24 Oct 2024 17:59:34 +0300 Subject: [PATCH 04/18] tbel_test_doc: add arrays --- .../service/script/TbelInvokeDocsIoTest.java | 70 +++++++++++++++++-- 1 file changed, 65 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 3014cfcfa6..3b1faf3b9c 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 @@ -27,6 +27,7 @@ import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals; @DaoSqlTest @@ -432,7 +433,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { msgList.put("splice2List", list.clone()); msgList.put("splice1_4", list.splice(1, 4, "start", 5, "end")); msgList.put("splice1_4List", list.clone()); - return msgList + return msgList; """; ArrayList list = new ArrayList<>(List.of("A", "B", "C", "B", "C", "hello", 34567)); LinkedHashMap expected = new LinkedHashMap<>(); @@ -486,7 +487,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { msgList.put("listChangeIndex1List", list.clone()); list[0] = 2096; msgList.put("listChangeIndex0List", list.clone()); - return msgList + return msgList; """; ArrayList list = new ArrayList<>(List.of("r", "start", 5, "end")); LinkedHashMap expected = new LinkedHashMap<>(); @@ -524,7 +525,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { msgList.put("fill4List", list.clone()); msgList.put("fill4_6", list.fill(2, 1, 4)); msgList.put("fill4_6List", list.clone()); - return msgList + return msgList; """; ArrayList list = new ArrayList<>(List.of(2096, "98", 5, "65")); LinkedHashMap expected = new LinkedHashMap<>(); @@ -584,7 +585,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { msgList.put("toSpliced2_2List", list.clone()); msgList.put("toSpliced4_5", list.toSpliced(2, 4, "start", 5, "end")); msgList.put("toSpliced4_5List", list.clone()); - return msgList + return msgList; """; ArrayList list = new ArrayList<>(List.of(67, 2, 2, 2)); ArrayList oldList = (ArrayList) list.clone(); @@ -665,7 +666,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { msgList.put("indOf1", list.indexOf("B", 1)); msgList.put("indOf2", list.indexOf(2, 2)); msgList.put("sStr", list.validateClazzInArrayIsOnlyString()); - return msgList + return msgList; """; ArrayList list = new ArrayList<>(List.of(67, 2, 2, 2)); LinkedHashMap expected = new LinkedHashMap<>(); @@ -679,6 +680,65 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected, actual); } + // Arrays + @Test + public void arrays_Test() throws ExecutionException, InterruptedException { + String str = "My String"; + msgStr = String.format(""" + {"str": "%s"} + """, str); + decoderStr = """ + var msgArray = {}; + // Create new array + var array = new int[3]; + array[0] = 1; + array[1] = 2; + array[2] = 3; + msgArray.put("array", array); + var str = msg.str; + msgArray.put("str", msg.str); + msgArray.put("str0", str[0]); + function sum(list){ + var result = 0; + for(var i = 0; i < list.length; i++){ + result += list[i]; + } + return result; + }; + msgArray.put("sum", sum(array)); +// array[3] = 4; // Will cause ArrayIndexOutOfBoundsException + return msgArray; + """; + ArrayList list = new ArrayList<>(List.of(1, 2, 3)); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("array", list); + expected.put("str", str); + expected.put("str0", str.toCharArray()[0]); + expected.put("sum", 6); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + @Test + public void arraysWillCauseArrayIndexOutOfBoundsException_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {} + """; + decoderStr = """ + var array = new int[3]; + array[0] = 1; + array[1] = 2; + array[2] = 3; + array[3] = 4; + return array; + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Invalid statement: 4") + .hasMessageContaining("[Line: 5, Column: 12]"); + } + + + private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); deleteCount = deleteCount < 0 ? 0 : Math.min(deleteCount, (oldList.size() - start)); From 4f7f8428b1297c562e1fb72c8acedb2c5373a32d Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 24 Oct 2024 18:32:13 +0300 Subject: [PATCH 05/18] tbel_test_doc: add Using Java Classes --- .../service/script/TbelInvokeDocsIoTest.java | 279 ++++++++++-------- 1 file changed, 150 insertions(+), 129 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 3b1faf3b9c..4898bfaf8a 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 @@ -188,16 +188,16 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { public void mapsChangeValuePut_Test() throws ExecutionException, InterruptedException { msgStr = msgMapStr; decoderStr = """ - msg.temperature = 73; - msg.putIfAbsent("temperature1", 73); - var put1 = msg.put("temperature", 74); - msg.putIfAbsent("humidity", 73); - var putIfAbsent1 = msg.putIfAbsent("humidity", 74); - return {map: msg, - put1: put1, - putIfAbsent1: putIfAbsent1 - }; - """; + msg.temperature = 73; + msg.putIfAbsent("temperature1", 73); + var put1 = msg.put("temperature", 74); + msg.putIfAbsent("humidity", 73); + var putIfAbsent1 = msg.putIfAbsent("humidity", 74); + return {map: msg, + put1: put1, + putIfAbsent1: putIfAbsent1 + }; + """; LinkedHashMap expectedMapChangeValue = expectedMap; expectedMapChangeValue.replace("temperature", 42, 74); expectedMapChangeValue.put("humidity", 73); @@ -346,8 +346,8 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listsCreateNewList_Test() throws ExecutionException, InterruptedException { msgStr = """ - {"list": ["A", "B", "C"]} - """; + {"list": ["A", "B", "C"]} + """; decoderStr = """ var list = msg.list; var list0 = list[0]; @@ -387,53 +387,53 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listAddPushDelete_Test() throws ExecutionException, InterruptedException { msgStr = """ - {"list": ["A", "B", "C", "B", "C", "hello", 34567]} - """; + {"list": ["A", "B", "C", "B", "C", "hello", 34567]} + """; decoderStr = """ var list = msg.list; - var msgList = {}; + var msgRez = {}; // add/push - msgList.put("list", list.clone()); + msgRez.put("list", list.clone()); var listAdd = ["thigsboard", 4, 67]; var addAll = list.addAll(listAdd); - msgList.put("addAll", addAll); - msgList.put("addAllList", list.clone()); + msgRez.put("addAll", addAll); + msgRez.put("addAllList", list.clone()); var addAllIndex = list.addAll(2, listAdd); - msgList.put("addAllIndex", addAllIndex); - msgList.put("addAllIndexList", list.clone()); + msgRez.put("addAllIndex", addAllIndex); + msgRez.put("addAllIndexList", list.clone()); var addIndex = list.add(3, "thigsboard"); if(addIndex != null) { - msgList.put("addIndex", addIndex); + msgRez.put("addIndex", addIndex); }; - msgList.put("addIndexList", list.clone()); + msgRez.put("addIndexList", list.clone()); var push = list.push("thigsboard"); - msgList.put("push", push); + msgRez.put("push", push); if(push != null) { - msgList.put("push", push); + msgRez.put("push", push); } - msgList.put("pushList", list.clone()); + msgRez.put("pushList", list.clone()); var unshift = list.unshift("r"); - msgList.put("unshift", unshift); - msgList.put("unshiftList", list.clone()); + msgRez.put("unshift", unshift); + msgRez.put("unshiftList", list.clone()); var unshiftQ = ["Q", 4]; - msgList.put("unshift", list.unshift(unshiftQ)); - msgList.put("unshiftQunList", list.clone()); + msgRez.put("unshift", list.unshift(unshiftQ)); + msgRez.put("unshiftQunList", list.clone()); // delete - msgList.put("removeIndex2", list.remove(2)); - msgList.put("removeIndex2List", list.clone()); - msgList.put("removeValueC", list.remove("C")); - msgList.put("removeValueCList", list.clone()); - msgList.put("shift", list.shift()); - msgList.put("shiftList", list.clone()); - msgList.put("pop", list.pop()); - msgList.put("popList", list.clone()); - msgList.put("splice3", list.splice(3)); - msgList.put("splice3List", list.clone()); - msgList.put("splice2", list.splice(2, 2)); - msgList.put("splice2List", list.clone()); - msgList.put("splice1_4", list.splice(1, 4, "start", 5, "end")); - msgList.put("splice1_4List", list.clone()); - return msgList; + msgRez.put("removeIndex2", list.remove(2)); + msgRez.put("removeIndex2List", list.clone()); + msgRez.put("removeValueC", list.remove("C")); + msgRez.put("removeValueCList", list.clone()); + msgRez.put("shift", list.shift()); + msgRez.put("shiftList", list.clone()); + msgRez.put("pop", list.pop()); + msgRez.put("popList", list.clone()); + msgRez.put("splice3", list.splice(3)); + msgRez.put("splice3List", list.clone()); + msgRez.put("splice2", list.splice(2, 2)); + msgRez.put("splice2List", list.clone()); + msgRez.put("splice1_4", list.splice(1, 4, "start", 5, "end")); + msgRez.put("splice1_4List", list.clone()); + return msgRez; """; ArrayList list = new ArrayList<>(List.of("A", "B", "C", "B", "C", "hello", 34567)); LinkedHashMap expected = new LinkedHashMap<>(); @@ -475,19 +475,19 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listChange_Test() throws ExecutionException, InterruptedException { msgStr = """ - {"list": ["r", "start", 5, "end"]} - """; + {"list": ["r", "start", 5, "end"]} + """; decoderStr = """ var list = msg.list; - var msgList = {}; - msgList.put("list", list.clone()); - msgList.put("set", list.set(3, "65")); - msgList.put("setList", list.clone()); + var msgRez = {}; + msgRez.put("list", list.clone()); + msgRez.put("set", list.set(3, "65")); + msgRez.put("setList", list.clone()); list[1] = "98"; - msgList.put("listChangeIndex1List", list.clone()); + msgRez.put("listChangeIndex1List", list.clone()); list[0] = 2096; - msgList.put("listChangeIndex0List", list.clone()); - return msgList; + msgRez.put("listChangeIndex0List", list.clone()); + return msgRez; """; ArrayList list = new ArrayList<>(List.of("r", "start", 5, "end")); LinkedHashMap expected = new LinkedHashMap<>(); @@ -505,27 +505,27 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listSort_Test() throws ExecutionException, InterruptedException { msgStr = """ - {"list": [2096, "98", 5, "65"]} - """; + {"list": [2096, "98", 5, "65"]} + """; decoderStr = """ var list = msg.list; - var msgList = {}; - msgList.put("list", list.clone()); - msgList.put("sort", list.sort()); - msgList.put("sortList", list.clone()); - msgList.put("sortTrue", list.sort(true)); - msgList.put("sortTrueList", list.clone()); - msgList.put("sortFalse", list.sort(false)); - msgList.put("sortFalseList", list.clone()); - msgList.put("reverse", list.reverse()); - msgList.put("reverseList", list.clone()); - msgList.put("fill", list.fill(67)); - msgList.put("fillList", list.clone()); - msgList.put("fill4", list.fill(4, 1)); - msgList.put("fill4List", list.clone()); - msgList.put("fill4_6", list.fill(2, 1, 4)); - msgList.put("fill4_6List", list.clone()); - return msgList; + var msgRez = {}; + msgRez.put("list", list.clone()); + msgRez.put("sort", list.sort()); + msgRez.put("sortList", list.clone()); + msgRez.put("sortTrue", list.sort(true)); + msgRez.put("sortTrueList", list.clone()); + msgRez.put("sortFalse", list.sort(false)); + msgRez.put("sortFalseList", list.clone()); + msgRez.put("reverse", list.reverse()); + msgRez.put("reverseList", list.clone()); + msgRez.put("fill", list.fill(67)); + msgRez.put("fillList", list.clone()); + msgRez.put("fill4", list.fill(4, 1)); + msgRez.put("fill4List", list.clone()); + msgRez.put("fill4_6", list.fill(2, 1, 4)); + msgRez.put("fill4_6List", list.clone()); + return msgRez; """; ArrayList list = new ArrayList<>(List.of(2096, "98", 5, "65")); LinkedHashMap expected = new LinkedHashMap<>(); @@ -550,42 +550,42 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listNewListOrStringSort_Test() throws ExecutionException, InterruptedException { msgStr = """ - {"list": [67, 2, 2, 2]} - """; + {"list": [67, 2, 2, 2]} + """; decoderStr = """ var list = msg.list; var listAdd = ["thigsboard", 4, 67]; - var msgList = {}; - msgList.put("list", list.clone()); - msgList.put("toSorted", list.toSorted()); - msgList.put("toSortedList", list.clone()); - msgList.put("toSortedTrue", list.toSorted(true)); - msgList.put("toSortedTrueList", list.clone()); - msgList.put("toSortedFalse", list.toSorted(false)); - msgList.put("toSortedFalseList", list.clone()); - msgList.put("toReversed", list.toReversed()); - msgList.put("toReversedList", list.clone()); - msgList.put("slice", list.slice()); - msgList.put("sliceList", list.clone()); - msgList.put("slice4", list.slice(3)); - msgList.put("slice4List", list.clone()); - msgList.put("slice1_5", list.slice(0,2)); - msgList.put("slice1_5List", list.clone()); - msgList.put("with1", list.with(1, 69)); - msgList.put("with1List", list.clone()); - msgList.put("concat", list.concat(listAdd)); - msgList.put("concatList", list.clone()); - msgList.put("join", list.join()); - msgList.put("joinList", list.clone()); - msgList.put("toSpliced2", list.toSpliced(1, 0, "Feb")); - msgList.put("toSpliced2List", list.clone()); - msgList.put("toSpliced0_2", list.toSpliced(0, 2)); - msgList.put("toSpliced0_2List", list.clone()); - msgList.put("toSpliced2_2", list.toSpliced(2, 2)); - msgList.put("toSpliced2_2List", list.clone()); - msgList.put("toSpliced4_5", list.toSpliced(2, 4, "start", 5, "end")); - msgList.put("toSpliced4_5List", list.clone()); - return msgList; + var msgRez = {}; + msgRez.put("list", list.clone()); + msgRez.put("toSorted", list.toSorted()); + msgRez.put("toSortedList", list.clone()); + msgRez.put("toSortedTrue", list.toSorted(true)); + msgRez.put("toSortedTrueList", list.clone()); + msgRez.put("toSortedFalse", list.toSorted(false)); + msgRez.put("toSortedFalseList", list.clone()); + msgRez.put("toReversed", list.toReversed()); + msgRez.put("toReversedList", list.clone()); + msgRez.put("slice", list.slice()); + msgRez.put("sliceList", list.clone()); + msgRez.put("slice4", list.slice(3)); + msgRez.put("slice4List", list.clone()); + msgRez.put("slice1_5", list.slice(0,2)); + msgRez.put("slice1_5List", list.clone()); + msgRez.put("with1", list.with(1, 69)); + msgRez.put("with1List", list.clone()); + msgRez.put("concat", list.concat(listAdd)); + msgRez.put("concatList", list.clone()); + msgRez.put("join", list.join()); + msgRez.put("joinList", list.clone()); + msgRez.put("toSpliced2", list.toSpliced(1, 0, "Feb")); + msgRez.put("toSpliced2List", list.clone()); + msgRez.put("toSpliced0_2", list.toSpliced(0, 2)); + msgRez.put("toSpliced0_2List", list.clone()); + msgRez.put("toSpliced2_2", list.toSpliced(2, 2)); + msgRez.put("toSpliced2_2List", list.clone()); + msgRez.put("toSpliced4_5", list.toSpliced(2, 4, "start", 5, "end")); + msgRez.put("toSpliced4_5List", list.clone()); + return msgRez; """; ArrayList list = new ArrayList<>(List.of(67, 2, 2, 2)); ArrayList oldList = (ArrayList) list.clone(); @@ -654,19 +654,19 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void listGetInfo_Test() throws ExecutionException, InterruptedException { msgStr = """ - {"list": [67, 2, 2, 2]} - """; + {"list": [67, 2, 2, 2]} + """; decoderStr = """ var list = msg.list; var listAdd = ["thigsboard", 4, 67]; - var msgList = {}; - msgList.put("list", list.clone()); - msgList.put("length", list.length()); - msgList.put("memorySize", list.memorySize()); - msgList.put("indOf1", list.indexOf("B", 1)); - msgList.put("indOf2", list.indexOf(2, 2)); - msgList.put("sStr", list.validateClazzInArrayIsOnlyString()); - return msgList; + return { + list: list.clone(), + length: list.length(), + memorySize: list.memorySize(), + indOf1: list.indexOf("B", 1), + indOf2: list.indexOf(2, 2), + sStr: list.validateClazzInArrayIsOnlyString() + } """; ArrayList list = new ArrayList<>(List.of(67, 2, 2, 2)); LinkedHashMap expected = new LinkedHashMap<>(); @@ -685,29 +685,30 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { public void arrays_Test() throws ExecutionException, InterruptedException { String str = "My String"; msgStr = String.format(""" - {"str": "%s"} - """, str); + {"str": "%s"} + """, str); decoderStr = """ - var msgArray = {}; // Create new array var array = new int[3]; array[0] = 1; array[1] = 2; array[2] = 3; - msgArray.put("array", array); var str = msg.str; - msgArray.put("str", msg.str); - msgArray.put("str0", str[0]); + var str0 = str[0]; function sum(list){ var result = 0; for(var i = 0; i < list.length; i++){ result += list[i]; } return result; - }; - msgArray.put("sum", sum(array)); -// array[3] = 4; // Will cause ArrayIndexOutOfBoundsException - return msgArray; + }; + var sum = sum(array); + return { + array: array, + str: str, + str0: str0, + sum: sum + } """; ArrayList list = new ArrayList<>(List.of(1, 2, 3)); LinkedHashMap expected = new LinkedHashMap<>(); @@ -718,11 +719,12 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); } + @Test public void arraysWillCauseArrayIndexOutOfBoundsException_Test() throws ExecutionException, InterruptedException { msgStr = """ - {} - """; + {} + """; decoderStr = """ var array = new int[3]; array[0] = 1; @@ -734,10 +736,29 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertThatThrownBy(() -> { invokeScript(evalScript(decoderStr), msgStr); }).hasMessageContaining("Invalid statement: 4") - .hasMessageContaining("[Line: 5, Column: 12]"); + .hasMessageContaining("[Line: 5, Column: 12]"); } - + // Using Java Classes + @Test + public void sqrt_Test() throws ExecutionException, InterruptedException { + int i = 4; + msgStr = String.format(""" + {"i": %d} + """, i); + decoderStr = """ + var foo = Math.sqrt(msg.i); + return{ + i: msg.i, + foo: foo + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("i", i); + expected.put("foo", Math.sqrt(i)); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); From c7d2d718cc4e4e7c9f2cd7cb74e226d2fde77fc2 Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 25 Oct 2024 18:00:34 +0300 Subject: [PATCH 06/18] tbel_test_doc: add Number HexDecimal and Flow Control --- .../service/script/TbelInvokeDocsIoTest.java | 262 ++++++++++++++++++ 1 file changed, 262 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 4898bfaf8a..f32fc84270 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 @@ -760,6 +760,268 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected, actual); } + // Convert Number to Hexadecimal/Octal/Binary String + @Test + public void byteIntegerToString_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var b16 = Integer.toString(0x1A, 16); + var b10 = Integer.toString(0x1A, 10); + var b8 = Integer.toString(0x1A, 8); + var b2 = Integer.toString(0x1A, 2); + return{ + b16: b16, + b10: b10, + b8: b8, + b2: b2 + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("b16", "1a"); + expected.put("b10", "26"); + expected.put("b8", "32"); + expected.put("b2", "11010"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void integerIntegerToString_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var i16 = Integer.toString(-255, 16); + var i10 = Integer.toString(-255, 10); + var i8 = Integer.toString(-255, 8); + var i2 = Integer.toString(-255, 2); + return{ + i16: i16, + i10: i10, + i8: i8, + i2: i2 + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("i16", "-ff"); + expected.put("i10", "-255"); + expected.put("i8", "-377"); + expected.put("i2", "-11111111"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void floatToString_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var f0 =7823764.8374; + var f16 = Float.toHexString(f0); + var f10 = f0.toString(); + return{ + f16: f16, + f10: f10 + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("f16", "0x1.dd8654p22"); + expected.put("f10", "7823764.8374"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void longToString_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var l16 = Long.toString(9223372036854775807, 16); + var l10 = Long.toString(9223372036854775807, 10); + var l8 = Long.toString(9223372036854775807, 8); + var l2 = Long.toString(9223372036854775807, 2); + return{ + l16: l16, + l10: l10, + l8: l8, + l2: l2 + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("l16", "7fffffffffffffff"); + expected.put("l10", "9223372036854775807"); + expected.put("l8", "777777777777777777777"); + expected.put("l2", "111111111111111111111111111111111111111111111111111111111111111"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void dpubleToString_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var dd0 = 99993219.156013e-002; + var dd16 = Double.toHexString(dd0); + var dd10 = String.format("%.8f",dd0); + return{ + dd16: dd16, + dd10: dd10 + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("dd16", "0x1.e83f862142b5bp19"); + expected.put("dd10", "999932,19156013"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + // Flow Control + @Test + public void ifTthenElseBlocks_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"temperature": 20} + """; + decoderStr = """ + if (msg.temperature > 0) { + return "Greater than zero!"; + } else if (msg.temperature == -1) { + return "Minus one!"; + } else { + return "Something else!"; + } + """; + String expected = "Greater than zero!"; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void ternarySstatements_Test() throws ExecutionException, InterruptedException { + msgStr = """ + {"temperature": 20} + """; + decoderStr = """ + return msg.temperature > 0 ? "Yes" : "No"; + """; + String expected = "Yes"; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void foreach_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var numbers = [1, 2, 3]; + var sum = 0; + foreach (n : numbers) { + sum+=n; + } + return sum; + """; + Integer expected = 6; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void foreachStringsIiterable_Test() throws ExecutionException, InterruptedException { + String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + msgStr = String.format(""" + {"str": "%s"} + """, str); + decoderStr = """ + int l = msg.str.length(); + var array = new int[l]; + var i = 0; + foreach (c : msg.str) { + array[i] = (int)c; + i++; + } + return array; + """; + List expected = new ArrayList<>(List.of(str.chars().boxed().toArray(Integer[]::new))); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void forLoop_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var sum = 0; + for (var i =0; i < 100; i++) {\s + sum += i; + } + return sum; + """; + Integer expected = 4950; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void doWhile_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var x = "doWhile"; + var a = null; + do { + x = a; + } + while (x != null); + return x; + """; + String expected = null; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void doUntil_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var x = "doWhile"; + var a = null; + do { + x = a; + } + until (x == null); + return x; + """; + String expected = null; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void standardWhile_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var x = "doWhile"; + var a = null; + while (x != null) { + x = a; + } + return x; + """; + String expected = null; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void standardUntil_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var x = "doWhile"; + var a = null; + until (x == null) { + x = a; + } + return x; + """; + String expected = null; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); deleteCount = deleteCount < 0 ? 0 : Math.min(deleteCount, (oldList.size() - start)); From 1d6abc5fbc52409364bbb42cd1ad10feb7702c2e Mon Sep 17 00:00:00 2001 From: nick Date: Fri, 25 Oct 2024 20:56:46 +0300 Subject: [PATCH 07/18] tbel_test_doc: add Helper functions --- .../service/script/TbelInvokeDocsIoTest.java | 76 +++++++++++++++++++ 1 file changed, 76 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 f32fc84270..6d2af47645 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 @@ -18,7 +18,9 @@ package org.thingsboard.server.service.script; import org.junit.jupiter.api.Test; import org.thingsboard.server.dao.service.DaoSqlTest; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Base64; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; @@ -1022,6 +1024,72 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected, actual); } + // Helper functions + @Test + public void atobBtoa_Test() throws ExecutionException, InterruptedException { + String str = "Hello, world"; + msgStr = String.format(""" + {"str": "%s"} + """, str); + decoderStr = """ + var encodedData = btoa(msg.str); + var decodedData = atob(encodedData); + return{ + "btoa": encodedData, + "atob": decodedData + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("btoa", Base64.getEncoder().encodeToString(str.getBytes())); + expected.put("atob", str); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void toFixed_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return{ + toFixed1: toFixed(0.345, 1), + toFixed2: toFixed(0.345, 2) + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("toFixed1", 0.3); + expected.put("toFixed2", 0.35); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void stringToBytes_Test() throws ExecutionException, InterruptedException { + String base64Str = "eyJoZWxsbyI6ICJ3b3JsZCJ9"; + String inputStr = "hello, world"; + msgStr = String.format(""" + { + "base64Str": "%s", + "inputStr": "%s" + } + """, base64Str, inputStr); + decoderStr = """ + var bytesStr = atob(msg.base64Str); + var charsetStr = "UTF8"; + return{ + bytesStr: stringToBytes(bytesStr), + inputStr: stringToBytes(msg.inputStr), + inputStrUTF8: stringToBytes(msg.inputStr, charsetStr) + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("bytesStr", bytesToList(Base64.getDecoder().decode(base64Str))); + expected.put("inputStr", bytesToList(inputStr.getBytes())); + expected.put("inputStrUTF8", bytesToList(inputStr.getBytes(StandardCharsets.UTF_8))); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); deleteCount = deleteCount < 0 ? 0 : Math.min(deleteCount, (oldList.size() - start)); @@ -1088,5 +1156,13 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { return second.compareTo(first); } }; + + private static List bytesToList(byte[] bytes) { + List list = new ArrayList<>(); + for (byte aByte : bytes) { + list.add(aByte); + } + return list; + } } From b98730a7b8cf022c0c42d096b28073e545360260 Mon Sep 17 00:00:00 2001 From: nick Date: Mon, 28 Oct 2024 14:33:01 +0200 Subject: [PATCH 08/18] tbel_test_doc: add Helper functions: stringToBytes, bytesToString, decodeToJson, isTypeInValue, encodeDecodeUri, raiseError, printUnsignedBytes --- .../service/script/TbelInvokeDocsIoTest.java | 137 +++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) 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 6d2af47645..a519fa1cd7 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 @@ -16,6 +16,7 @@ package org.thingsboard.server.service.script; import org.junit.jupiter.api.Test; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.dao.service.DaoSqlTest; import java.nio.charset.StandardCharsets; @@ -1063,7 +1064,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } @Test - public void stringToBytes_Test() throws ExecutionException, InterruptedException { + public void stringToBytesBinaryString_Test() throws ExecutionException, InterruptedException { String base64Str = "eyJoZWxsbyI6ICJ3b3JsZCJ9"; String inputStr = "hello, world"; msgStr = String.format(""" @@ -1089,6 +1090,140 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected, actual); } + @Test + public void stringToBytesObjectFromJsonAsString_Test() throws ExecutionException, InterruptedException { + String inputStr = "hello, world"; + msgStr = "{}"; + decoderStr = String.format(""" + var dataMap = {}; + dataMap.inputStr = "%s"; + var dataJsonStr = JSON.stringify(dataMap); + var dataJson = JSON.parse(dataJsonStr); + return stringToBytes(dataJson.inputStr); + """, inputStr); + List expected = bytesToList(inputStr.getBytes()); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void bytesToString_Test() throws ExecutionException, InterruptedException { + byte[] inputBytes = new byte[]{0x48, 0x45, 0x4C, 0x4C, 0x4F}; + msgStr = "{}"; + decoderStr = """ + var bytes = [0x48,0x45,0x4C,0x4C,0x4F]; + return bytesToString(bytes); + """; + String expected = new String(inputBytes); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void decodeToJson_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var base64Str = "eyJoZWxsbyI6ICJ3b3JsZCJ9"; + var bytesStr = atob(base64Str); + var bytes = stringToBytes(bytesStr); + return decodeToJson(bytes); + """; + String expected = "{\"hello\":\"world\"}"; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, JacksonUtil.toString(actual)); + } + + @Test + public void isTypeInValue_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return{ + "binary": isBinary("1100110"), + "notBinary": isBinary("2100110"), + "octal": isOctal("4567734"), + "notOctal": isOctal("8100110"), + "decimal": isDecimal("4567039"), + "notDecimal": isDecimal("C100110"), + "hexadecimal": isHexadecimal("F5D7039"), + "notHexadecimal": isHexadecimal("K100110") + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("binary", 2); + expected.put("notBinary", -1); + expected.put("octal", 8); + expected.put("notOctal", -1); + expected.put("decimal", 10); + expected.put("notDecimal", -1); + expected.put("hexadecimal", 16); + expected.put("notHexadecimal", -1); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void encodeDecodeUri_Test() throws ExecutionException, InterruptedException { + String uriOriginal = "-_.!~*'();/?:@&=+$,#ht://example.ж д a/path with spaces/?param1=Київ 1¶m2=Україна2"; + String uriEncode = "-_.!~*'();/?:@&=+$,#ht://example.%D0%B6%20%D0%B4%20a/path%20with%20spaces/?param1=%D0%9A%D0%B8%D1%97%D0%B2%201¶m2=%D0%A3%D0%BA%D1%80%D0%B0%D1%97%D0%BD%D0%B02"; + msgStr = "{}"; + decoderStr = String.format(""" + var uriOriginal = "%s"; + var uriEncode = "%s"; + return{ + "encodeURI": encodeURI(uriOriginal), + "decodeURI": decodeURI(uriEncode) + } + """, uriOriginal, uriEncode); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("encodeURI", uriEncode); + expected.put("decodeURI", uriOriginal); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void raiseError_Test() throws ExecutionException, InterruptedException { + String message = "frequency_weighting_type must be 0, 1 or 2."; + msgStr = "{}"; + decoderStr = String.format(""" + var message = "%s"; + return raiseError(message); + """, message); + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining(message); + + Integer value = 4; + message = "frequency_weighting_type must be 0, 1 or 2. A value of " + value + " is invalid."; + decoderStr = String.format(""" + var message = "%s"; + return raiseError(message); + """, message); + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining(message); + } + @Test + public void printUnsignedBytes_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var hexStrBe = "D8FF"; + var listBe = hexToBytes(hexStrBe); + return printUnsignedBytes(listBe); + """; + ArrayList expected = new ArrayList<>(List.of(216, 255)); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + decoderStr = """ + var hexStrLe = "FFD8"; + var listLe = hexToBytes(hexStrLe); + return printUnsignedBytes(listLe); + """; + expected = new ArrayList<>(List.of(255, 216)); + actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); From 589822a8c2643426da87f5f44f8a79da679908e8 Mon Sep 17 00:00:00 2001 From: nick Date: Mon, 28 Oct 2024 17:24:15 +0200 Subject: [PATCH 09/18] tbel_test_doc: add Helper functions: pad, numberToRadixString, parseHex, parseBytes --- .../service/script/TbelInvokeDocsIoTest.java | 244 ++++++++++++++++++ 1 file changed, 244 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 a519fa1cd7..9a621bbc14 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 @@ -1203,6 +1203,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { invokeScript(evalScript(decoderStr), msgStr); }).hasMessageContaining(message); } + @Test public void printUnsignedBytes_Test() throws ExecutionException, InterruptedException { msgStr = "{}"; @@ -1224,6 +1225,249 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected, actual); } + @Test + public void pad_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + // padStart + decoderStr = """ + var str1 = "010011"; + var str2 ="1001010011"; + var fullNumber = "203439900FFCD5581"; + var last4Digits = fullNumber.substring(11); + return { + padStart1: padStart(str1, 8, '0'), + padStart2: padStart(str2, 8, '0'), + padStart16: padStart(str2, 16, '*'), + padStartFullNumber: padStart(last4Digits, fullNumber.length(), '*') + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("padStart1", "00010011"); + expected.put("padStart2", "1001010011"); + expected.put("padStart16", "******1001010011"); + expected.put("padStartFullNumber", "***********CD5581"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + // padEnd + decoderStr = """ + var str1 = "010011"; + var str2 ="1001010011"; + var fullNumber = "203439900FFCD5581"; + var last4Digits = fullNumber.substring(0, 11); + return { + padEnd1: padEnd(str1, 8, '0'), + padEnd2: padEnd(str2, 8, '0'), + padEnd16: padEnd(str2, 16, '*'), + padEndFullNumber: padEnd(last4Digits, fullNumber.length(), '*') + } + """; + expected = new LinkedHashMap<>(); + expected.put("padEnd1", "01001100"); + expected.put("padEnd2", "1001010011"); + expected.put("padEnd16", "1001010011******"); + expected.put("padEndFullNumber", "203439900FF******"); + actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void numberToRadixStringIntLongFloatDouble_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var i = 0x7FFFFFFF; + return { + "intToHex1": intToHex(i, true, true), + "intToHex2": intToHex(171, true, false), + "intToHex3": intToHex(0xABCDEF, false, true, 4), + "intToHex4": intToHex(0xABCD, false, false, 2), + "longToHex1": longToHex(9223372036854775807, true, true), + "longToHex2": longToHex(0x7A12BCD3, true, true, 4), + "longToHex3": longToHex(0x7A12BCD3, false, false, 4), + "floatToHex1": floatToHex(123456789.00), + "floatToHex2": floatToHex(123456789.00, false), + "doubleToHex1": doubleToHex(1729.1729d), + "doubleToHex2": doubleToHex(1729.1729d, false) + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("intToHex1", "0x7FFFFFFF"); + expected.put("intToHex2", "AB"); + expected.put("intToHex3", "0xCDAB"); + expected.put("intToHex4", "AB"); + expected.put("longToHex1", "0x7FFFFFFFFFFFFFFF"); + expected.put("longToHex2", "0xBCD3"); + expected.put("longToHex3", "127A"); + expected.put("floatToHex1", "0x4CEB79A3"); + expected.put("floatToHex2", "0xA379EB4C"); + expected.put("doubleToHex1", "0x409B04B10CB295EA"); + expected.put("doubleToHex2", "0xEA95B20CB1049B40"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void intLongToRadixString_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return { + "bin1": intLongToRadixString(58, 2), + "bin2": intLongToRadixString(9223372036854775807, 2), + "octal1": intLongToRadixString(13158, 8), + "octal2": intLongToRadixString(-13158, 8), + "decimal": intLongToRadixString(-13158, 10), + "hexDecimal1": intLongToRadixString(13158, 16), + "hexDecimal2": intLongToRadixString(-13158, 16), + "hexDecimal3": intLongToRadixString(9223372036854775807, 16), + "hexDecimal4": intLongToRadixString(-13158, 16, true, true) + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("bin1", "00111010"); + expected.put("bin2", "0111111111111111111111111111111111111111111111111111111111111111"); + expected.put("octal1", "31546"); + expected.put("octal2", "1777777777777777746232"); + expected.put("decimal", "-13158"); + expected.put("hexDecimal1", "3366"); + expected.put("hexDecimal2", "FFCC9A"); + expected.put("hexDecimal3", "7FFFFFFFFFFFFFFF"); + expected.put("hexDecimal4", "0xFFCC9A"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void parseHex_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return { + "hexToInt1": parseHexToInt("BBAA"), + "hexToInt2": parseHexToInt("BBAA", true), + "hexToInt3": parseHexToInt("AABB", false), + "hexToInt4": parseHexToInt("BBAA", false), + "hexToFloat1": parseHexToFloat("41EA62CC"), + "hexToFloat2": parseHexToFloat("41EA62CC", true), + "hexToFloat3": parseHexToFloat("41EA62CC", false), + "hexToFloat4": parseHexToFloat("CC62EA41", false), + "hexIntLongToFloat1": parseHexIntLongToFloat("0x0A", true), + "hexIntLongToFloat2": parseHexIntLongToFloat("0x0A", false), + "hexIntLongToFloat3": parseHexIntLongToFloat("0x00000A", true), + "hexIntLongToFloat4": parseHexIntLongToFloat("0x0A0000", false), + "hexIntLongToFloat5": parseHexIntLongToFloat("0x000A0A", true), + "hexIntLongToFloat6": parseHexIntLongToFloat("0x0A0A00", false), + "hexToDouble1": parseHexToDouble("409B04B10CB295EA"), + "hexToDouble2": parseHexToDouble("409B04B10CB295EA", false), + "hexToDouble3": parseHexToDouble("409B04B10CB295EA", true), + "hexToDouble4": parseHexToDouble("EA95B20CB1049B40", false) + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("hexToInt1", 48042); + expected.put("hexToInt2", 48042); + expected.put("hexToInt3", 48042); + expected.put("hexToInt4", 43707); + expected.put("hexToFloat1", 29.29824f); + expected.put("hexToFloat2", 29.29824f); + expected.put("hexToFloat3", -5.948442E7f); + expected.put("hexToFloat4", 29.29824f); + expected.put("hexIntLongToFloat1", 10.0f); + expected.put("hexIntLongToFloat2", 10.0f); + expected.put("hexIntLongToFloat3", 10.0f); + expected.put("hexIntLongToFloat4", 10.0f); + expected.put("hexIntLongToFloat5", 2570.0f); + expected.put("hexIntLongToFloat6", 2570.0f); + expected.put("hexToDouble1", 1729.1729); + expected.put("hexToDouble2", -2.7208640774822924E205); + expected.put("hexToDouble3", 1729.1729); + expected.put("hexToDouble4", 1729.1729); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void parseBytes_Test() throws ExecutionException, InterruptedException { + byte[] bytesExecutionArrayList = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD}; + msgStr = "{}"; + decoderStr = """ + var bytes = [0xBB, 0xAA]; + var list = [-69, 83]; + var intValByte = [0xAA, 0xBB, 0xCC, 0xDD]; + var longValByte = [64, -101, 4, -79, 12, -78, -107, -22]; + var bytesFloat = [0x0A]; + var floatValByte = [0x41, 0xEA, 0x62, 0xCC]; + var floatValList = [65, -22, 98, -52]; + var intValByteFromInt = [0x00, 0x00, 0x00, 0x0A]; + var dataAT101 = "0x01756403671B01048836BF7701F000090722050000"; + var byteAT101 = hexToBytes(dataAT101); + var offsetLatInt = 9; + var coordinatesAsHex = "0x32D009423F23B300B0106E08D96B6C00"; + var coordinatesasBytes = hexToBytes(coordinatesAsHex); + var offsetLatLong = 0; + var factor = 1e15; + var bytesExecutionArrayList = [0xAA, 0xBB, 0xCC, 0xDD]; + return { + "bytesToHex1": bytesToHex(bytes), + "bytesToHex2": bytesToHex(list), + "bytesToInt1": parseBytesToInt(intValByte, 0, 3), + "bytesToInt2": parseBytesToInt(intValByte, 0, 3, true), + "bytesToInt3": parseBytesToInt(intValByte, 0, 3, false), + "bytesToLong1": parseBytesToLong(longValByte, 0, 8), + "bytesToLong2": parseBytesToLong(longValByte, 0, 8, false), + "bytesToFloat1": parseBytesToFloat(bytesFloat), + "bytesToFloat2": parseBytesToFloat(floatValByte, 0), + "bytesToFloat3": parseBytesToFloat(floatValByte, 0, 2, false), + "bytesToFloat4": parseBytesToFloat(floatValByte, 0, 2, true), + "bytesToFloat5": parseBytesToFloat(floatValByte, 0, 3, false), + "bytesToFloat6": parseBytesToFloat(floatValByte, 0, 3, true), + "bytesToFloat7": parseBytesToFloat(floatValByte, 0, 4, false), + "bytesToFloat8": parseBytesToFloat(floatValList, 0), + "bytesToFloat9": parseBytesToFloat(floatValList, 0, 4, false), + "bytesIntToFloat1": parseBytesIntToFloat(intValByteFromInt, 3, 1, true), + "bytesIntToFloat2": parseBytesIntToFloat(intValByteFromInt, 3, 1, false), + "bytesIntToFloat3": parseBytesIntToFloat(intValByteFromInt, 2, 2, true), + "bytesIntToFloat4": parseBytesIntToFloat(intValByteFromInt, 2, 2, false), + "bytesIntToFloat5": parseBytesIntToFloat(intValByteFromInt, 0, 4, true), + "bytesIntToFloat6": parseBytesIntToFloat(intValByteFromInt, 0, 4, false), + "bytesIntToFloat7": parseBytesIntToFloat(byteAT101, offsetLatInt, 4, false) / 1000000, + "bytesIntToFloat8": parseBytesIntToFloat(byteAT101, offsetLatInt + 4, 4, false) / 1000000, + "bytesLongToDouble1": parseBytesLongToDouble(coordinatesasBytes, offsetLatLong, 8, false) / factor, + "bytesLongToDouble2": parseBytesLongToDouble(coordinatesasBytes, offsetLatLong + 8, 8, false) / factor, + "bytesLongToExecutionArrayList": bytesToExecutionArrayList(bytesExecutionArrayList) + + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("bytesToHex1", "BBAA"); + expected.put("bytesToHex2", "BB53"); + expected.put("bytesToInt1", 11189196); + expected.put("bytesToInt2", 11189196); + expected.put("bytesToInt3", 13417386); + expected.put("bytesToLong1", 4655319798286292458L); + expected.put("bytesToLong2", -1543131529725306048L); + expected.put("bytesToFloat1", 1.4E-44f); + expected.put("bytesToFloat2", 29.29824f); + expected.put("bytesToFloat3", 8.4034E-41f); + expected.put("bytesToFloat4", 2.3646E-41f); + expected.put("bytesToFloat5", 9.083913E-39f); + expected.put("bytesToFloat6", 6.053388E-39f); + expected.put("bytesToFloat7", -5.948442E7f); + expected.put("bytesToFloat8", 29.29824f); + expected.put("bytesToFloat9", -5.948442E7f); + expected.put("bytesIntToFloat1", 10.0f); + expected.put("bytesIntToFloat2", 10.0f); + expected.put("bytesIntToFloat3", 10.0f); + expected.put("bytesIntToFloat4", 2560.0f); + expected.put("bytesIntToFloat5", 10.0f); + expected.put("bytesIntToFloat6", 1.6777216E8f); + expected.put("bytesIntToFloat7", 24.62495f); + expected.put("bytesIntToFloat8", 118.030576f); + expected.put("bytesLongToDouble1", 50.422775429058610d); + expected.put("bytesLongToDouble2", 30.517877378257072d); + expected.put("bytesLongToExecutionArrayList", bytesToList(bytesExecutionArrayList)); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + // parseBinaryArray private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); From 7369b000710c69da1be5804301fa2d35d4c62997 Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 29 Oct 2024 12:26:12 +0200 Subject: [PATCH 10/18] tbel: fix bug validate decimal with <+> --- .../src/main/java/org/thingsboard/script/api/tbel/TbUtils.java | 2 +- .../test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 7f7b1f699f..6b321a3570 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 @@ -1255,7 +1255,7 @@ public class TbUtils { if (str == null || str.isEmpty()) { return -1; } - return str.matches("-?\\d+(\\.\\d+)?") ? DEC_RADIX : -1; + return str.matches("[+-]?\\d+(\\.\\d+)?") ? DEC_RADIX : -1; } public static int isHexadecimal(String str) { 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 b7276edd8d..1c5a1a2e1a 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 @@ -213,6 +213,7 @@ public class TbUtilsTest { Assertions.assertEquals((Integer) 0, TbUtils.parseInt("0")); Assertions.assertEquals((Integer) 0, TbUtils.parseInt("-0")); + Assertions.assertEquals((Integer) 0, TbUtils.parseInt("+0")); Assertions.assertEquals(java.util.Optional.of(473).get(), TbUtils.parseInt("473")); Assertions.assertEquals(java.util.Optional.of(-255).get(), TbUtils.parseInt("-0xFF")); Assertions.assertThrows(NumberFormatException.class, () -> TbUtils.parseInt("-0xFF123")); From 13882f24be84fd332e022a03703299f81f275b2a Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 29 Oct 2024 13:43:22 +0200 Subject: [PATCH 11/18] tbel: doc Io tets: parseBinaryArray, parseNumber --- .../service/script/TbelInvokeDocsIoTest.java | 228 ++++++++++++++++++ 1 file changed, 228 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 9a621bbc14..f4f6f9cada 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 @@ -1468,6 +1468,234 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } // parseBinaryArray + @Test + public void parseBinaryArray_Test() throws ExecutionException, InterruptedException { + byte[] value = new byte[]{1, 0, 0, 1, 1, 1}; + msgStr = "{}"; + decoderStr = """ + // parseByteToBinaryArray + var byteVal = 0x39; + var value = parseByteToBinaryArray(byteVal, 6, false); + var actualLowCurrent1Alarm = value[0]; + var actualHighCurrent1Alarm = value[1]; + var actualLowCurrent2Alarm = value[2]; + var actualHighCurrent2Alarm = value[3]; + var actualLowCurrent3Alarm = value[4]; + var actualHighCurrent3Alarm = value[5]; + // parseBytesToBinaryArray + var bytesVal = [0xCE, 0xB2]; + // parseLongToBinaryArray + var longValue = 52914L; + return { + // parseByteToBinaryArray + "parseByteToBinaryArray_All": parseByteToBinaryArray(byteVal), + "parseByteToBinaryArray_1": parseByteToBinaryArray(byteVal, 3), + "parseByteToBinaryArray_2": parseByteToBinaryArray(byteVal, 8, false), + "parseByteToBinaryArray_3": parseByteToBinaryArray(byteVal, 5, false), + "parseByteToBinaryArray_4": parseByteToBinaryArray(byteVal, 4, false), + "parseByteToBinaryArray_5": parseByteToBinaryArray(byteVal, 3, false), + "parseByteToBinaryArray_value": parseByteToBinaryArray(byteVal, 6, false), + "parseByteToBinaryArray_value0": value[0], + "parseByteToBinaryArray_value1": value[1], + "parseByteToBinaryArray_value2": value[2], + "parseByteToBinaryArray_value3": value[3], + "parseByteToBinaryArray_value4": value[4], + "parseByteToBinaryArray_value5": value[5], + // parseBytesToBinaryArray + "parseBytesToBinaryArray_All": parseBytesToBinaryArray(bytesVal), + "parseBytesToBinaryArray_1": parseBytesToBinaryArray(bytesVal, 15), + "parseBytesToBinaryArray_2": parseBytesToBinaryArray(bytesVal, 14), + "parseBytesToBinaryArray_3": parseBytesToBinaryArray(bytesVal, 2), + // parseLongToBinaryArray + "parseLongToBinaryArray_1": parseLongToBinaryArray(longValue), + "parseLongToBinaryArray_2": parseLongToBinaryArray(longValue, 16), + // parseBinaryArrayToInt + "parseBinaryArrayToIn_1": parseBinaryArrayToInt([1, 0, 0, 1, 1, 1, 1, 1]), + "parseBinaryArrayToIn_2": parseBinaryArrayToInt([1, 0, 0, 1, 1, 1, 1, 1], 1, 7) + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + // parseByteToBinaryArray + expected.put("parseByteToBinaryArray_All", bytesToList(new byte[]{0, 0, 1, 1, 1, 0, 0, 1})); + expected.put("parseByteToBinaryArray_1", bytesToList(new byte[]{0, 0, 1})); + expected.put("parseByteToBinaryArray_2", bytesToList(new byte[]{1, 0, 0, 1, 1, 1, 0, 0})); + expected.put("parseByteToBinaryArray_3", bytesToList(new byte[]{1, 0, 0, 1, 1})); + expected.put("parseByteToBinaryArray_4", bytesToList(new byte[]{1, 0, 0, 1})); + expected.put("parseByteToBinaryArray_5", bytesToList(new byte[]{1, 0, 0})); + expected.put("parseByteToBinaryArray_value", bytesToList(value)); + expected.put("parseByteToBinaryArray_value0", value[0]); + expected.put("parseByteToBinaryArray_value1", value[1]); + expected.put("parseByteToBinaryArray_value2", value[2]); + expected.put("parseByteToBinaryArray_value3", value[3]); + expected.put("parseByteToBinaryArray_value4", value[4]); + expected.put("parseByteToBinaryArray_value5", value[5]); + // parseBytesToBinaryArray + expected.put("parseBytesToBinaryArray_All", bytesToList(new byte[]{1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0})); + expected.put("parseBytesToBinaryArray_1", bytesToList(new byte[]{1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0})); + expected.put("parseBytesToBinaryArray_2", bytesToList(new byte[]{0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0})); + expected.put("parseBytesToBinaryArray_3", bytesToList(new byte[]{1, 0})); + // parseLongToBinaryArray + expected.put("parseLongToBinaryArray_1", bytesToList(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0})); + expected.put("parseLongToBinaryArray_2", bytesToList(new byte[]{1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0})); + // parseBinaryArrayToInt + expected.put("parseBinaryArrayToIn_1", -97); + expected.put("parseBinaryArrayToIn_2", 31); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + // parseNumber + @Test + public void parseInt_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return { + "parseInt_01": parseInt("0"), + "parseInt_02": parseInt("473"), + "parseInt_03": parseInt("+42"), + "parseInt_04": parseInt("-0", 10), + "parseInt_05": parseInt("-0xFF"), + "parseInt_06": parseInt("-FF", 16), + "parseInt_07": parseInt("1100110", 2), + "parseInt_08": parseInt("2147483647", 10), + "parseInt_09": parseInt("-2147483648", 10), + "parseInt_10": parseInt("Kona", 27) + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("parseInt_01", 0); + expected.put("parseInt_02", 473); + expected.put("parseInt_03", 42); + expected.put("parseInt_04", 0); + expected.put("parseInt_05", -255); + expected.put("parseInt_06", -255); + expected.put("parseInt_07", 102); + expected.put("parseInt_08", 2147483647); + expected.put("parseInt_09",-2147483648); + expected.put("parseInt_10", 411787); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + + decoderStr = """ + return parseInt("2147483648", 10); + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseInt(\"2147483648\", 10): For input string: \"2147483648\"") + .hasMessageContaining("[Line: 1, Column: 12]"); + + decoderStr = """ + return parseInt("99", 8); + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseInt(\"99\", 8): Failed radix [8] for value: \"99\"") + .hasMessageContaining("[Line: 1, Column: 12]"); + + decoderStr = """ + return parseInt("Kona", 10); + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseInt(\"Kona\", 10): Failed radix [10] for value: \"Kona\"") + .hasMessageContaining("[Line: 1, Column: 12]"); + } + + @Test + public void parseLong_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return { + "parseLong_01": parseLong("0"), + "parseLong_02": parseLong("473"), + "parseLong_03": parseLong("+42"), + "parseLong_04": parseLong("-0", 10), + "parseLong_05": parseLong("-0xFFFF"), + "parseLong_06": parseLong("-FFFF", 16), + "parseLong_07": parseLong("11001101100110", 2), + "parseLong_08": parseLong("777777777777777777777", 8), + "parseLong_09": parseLong("KonaLong", 27), + "parseLong_10": parseLong("9223372036854775807", 10), + "parseLong_11": parseLong("-9223372036854775808", 10), + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("parseLong_01", 0L); + expected.put("parseLong_02", 473L); + expected.put("parseLong_03", 42L); + expected.put("parseLong_04", 0L); + expected.put("parseLong_05", -65535L); + expected.put("parseLong_06", -65535L); + expected.put("parseLong_07", 13158L); + expected.put("parseLong_08", 9223372036854775807L); + expected.put("parseLong_09", 218840926543L); + expected.put("parseLong_10", 9223372036854775807L); + expected.put("parseLong_11", -9223372036854775808L); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + + decoderStr = """ + return parseLong("9223372036854775808", 10); + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseLong(\"9223372036854775808\", 10): For input string: \"9223372036854775808\"") + .hasMessageContaining("[Line: 1, Column: 12]"); + + decoderStr = """ + return parseLong("0xFGFFFFFF", 16); + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseLong(\"0xFGFFFFFF\", 16): Failed radix [16] for value: \"0xFGFFFFFF\"") + .hasMessageContaining("[Line: 1, Column: 12]"); + + decoderStr = """ + return parseLong("FFFFFFFFF", 16); + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseLong(\"FFFFFFFFF\", 16): The hexadecimal value: \"FFFFFFFFF\"") + .hasMessageContaining("[Line: 1, Column: 12]"); + + decoderStr = """ + return parseLong("1787", 8); + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseLong(\"1787\", 8): Failed radix [8] for value: \"1787\"") + .hasMessageContaining("[Line: 1, Column: 12]"); + + decoderStr = """ + return parseLong("KonaLong", 10); + """; + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseLong(\"KonaLong\", 10): Failed radix [10] for value: \"KonaLong\"") + .hasMessageContaining("[Line: 1, Column: 12]"); + } + + @Test + public void parseFloat_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return parseFloat("4.2"); + """; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(4.2f, actual); + } + + @Test + public void parseDouble_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return parseDouble("4.2"); + """; + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(4.2d, actual); + } + + // base64 private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); From 780605440c376d2843e2b98992772e9a911e8cce Mon Sep 17 00:00:00 2001 From: nick Date: Tue, 29 Oct 2024 18:53:45 +0200 Subject: [PATCH 12/18] tbel: doc Io tests: base64, toFlatMap, tDateString, tbDateInstant --- .../service/script/TbelInvokeDocsIoTest.java | 269 +++++++++++++++++- 1 file changed, 262 insertions(+), 7 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 f4f6f9cada..165f6f7088 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 @@ -17,9 +17,11 @@ package org.thingsboard.server.service.script; import org.junit.jupiter.api.Test; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.script.api.tbel.TbDate; import org.thingsboard.server.dao.service.DaoSqlTest; import java.nio.charset.StandardCharsets; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Base64; import java.util.Collections; @@ -1571,7 +1573,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { expected.put("parseInt_06", -255); expected.put("parseInt_07", 102); expected.put("parseInt_08", 2147483647); - expected.put("parseInt_09",-2147483648); + expected.put("parseInt_09", -2147483648); expected.put("parseInt_10", 411787); Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); @@ -1601,7 +1603,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { .hasMessageContaining("[Line: 1, Column: 12]"); } - @Test + @Test public void parseLong_Test() throws ExecutionException, InterruptedException { msgStr = "{}"; decoderStr = """ @@ -1658,13 +1660,13 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { }).hasMessageContaining("Error: parseLong(\"FFFFFFFFF\", 16): The hexadecimal value: \"FFFFFFFFF\"") .hasMessageContaining("[Line: 1, Column: 12]"); - decoderStr = """ + decoderStr = """ return parseLong("1787", 8); """; - assertThatThrownBy(() -> { - invokeScript(evalScript(decoderStr), msgStr); - }).hasMessageContaining("Error: parseLong(\"1787\", 8): Failed radix [8] for value: \"1787\"") - .hasMessageContaining("[Line: 1, Column: 12]"); + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("Error: parseLong(\"1787\", 8): Failed radix [8] for value: \"1787\"") + .hasMessageContaining("[Line: 1, Column: 12]"); decoderStr = """ return parseLong("KonaLong", 10); @@ -1696,6 +1698,259 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } // base64 + @Test + public void base64_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + return { + "base64ToHex": base64ToHex("Kkk="), + "bytesToBase64": bytesToBase64([42, 73]), + "base64ToBytes": base64ToBytes("Kkk=") + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("base64ToHex", "2A49"); + expected.put("bytesToBase64", "Kkk="); + expected.put("base64ToBytes", bytesToList(new byte[]{42, 73})); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + // toFlatMap + @Test + public void toFlatMap_Test() throws ExecutionException, InterruptedException { + msgStr = """ + { + "key1": "value1", + "key2": 12, + "key3": { + "key4": "value4", + "key5": 34, + "key6": [{ + "key7": "value7" + }, + { + "key8": "value8" + }, + "just_string_value_in_array", + 56 + ], + "key9": { + "key10": ["value10_1", "value10_2", "value10_3"] + } + }, + "key_to_overwrite": "root_value", + "key11": { + "key_to_overwrite": "second_level_value" + } + }; + """; + decoderStr = """ + return { + "toFlatMap": toFlatMap(msg), + "toFlatMapFalse": toFlatMap(msg, false), + "toFlatMapExcludeList": toFlatMap(msg, ["key1", "key3"]), + "toFlatMapExcludeListFalse": toFlatMap(msg, ["key2", "key4"], false) + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + LinkedHashMap expectedJson = new LinkedHashMap<>(); + expectedJson.put("key1", "value1"); + expectedJson.put("key2", 12); + expectedJson.put("key3.key4", "value4"); + expectedJson.put("key3.key5", 34); + expectedJson.put("key3.key6.0.key7", "value7"); + expectedJson.put("key3.key6.1.key8", "value8"); + expectedJson.put("key3.key6.2", "just_string_value_in_array"); + expectedJson.put("key3.key6.3", 56); + expectedJson.put("key3.key9.key10.0", "value10_1"); + expectedJson.put("key3.key9.key10.1", "value10_2"); + expectedJson.put("key3.key9.key10.2", "value10_3"); + expectedJson.put("key_to_overwrite", "root_value"); + expectedJson.put("key11.key_to_overwrite", "second_level_value"); + expected.put("toFlatMap", expectedJson); + LinkedHashMap expectedJsonFalse = new LinkedHashMap<>(); + expectedJsonFalse.put("key1", "value1"); + expectedJsonFalse.put("key2", 12); + expectedJsonFalse.put("key4", "value4"); + expectedJsonFalse.put("key5", 34); + expectedJsonFalse.put("key7", "value7"); + expectedJsonFalse.put("key8", "value8"); + expectedJsonFalse.put("key6.2", "just_string_value_in_array"); + expectedJsonFalse.put("key6.3", 56); + expectedJsonFalse.put("key10.0", "value10_1"); + expectedJsonFalse.put("key10.1", "value10_2"); + expectedJsonFalse.put("key10.2", "value10_3"); + expectedJsonFalse.put("key_to_overwrite", "second_level_value"); + expected.put("toFlatMapFalse", expectedJsonFalse); + LinkedHashMap expectedJsonExcludeList = new LinkedHashMap<>(); + expectedJsonExcludeList.put("key2", 12); + expectedJsonExcludeList.put("key_to_overwrite", "root_value"); + expectedJsonExcludeList.put("key11.key_to_overwrite", "second_level_value"); + expected.put("toFlatMapExcludeList", expectedJsonExcludeList); + LinkedHashMap expectedJsonExcludeListFalse = new LinkedHashMap<>(); + expectedJsonExcludeListFalse.put("key1", "value1"); + expectedJsonExcludeListFalse.put("key5", 34); + expectedJsonExcludeListFalse.put("key7", "value7"); + expectedJsonExcludeListFalse.put("key8", "value8"); + expectedJsonExcludeListFalse.put("key6.2", "just_string_value_in_array"); + expectedJsonExcludeListFalse.put("key6.3", 56); + expectedJsonExcludeListFalse.put("key10.0", "value10_1"); + expectedJsonExcludeListFalse.put("key10.1", "value10_2"); + expectedJsonExcludeListFalse.put("key10.2", "value10_3"); + expectedJsonExcludeListFalse.put("key_to_overwrite", "second_level_value"); + expected.put("toFlatMapExcludeListFalse", expectedJsonExcludeListFalse); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + // tbDate + @Test + public void tbDateStringTZ_Test() throws ExecutionException, InterruptedException { + int h = 12; + String s2 = String.format("2023-08-06T%s:04:05.123", String.format("%02d", h)); + msgStr = "{}"; + decoderStr = String.format(""" + var d1 = new Date("2023-08-06T04:04:05.123Z"); + var d2 = new Date("%s"); + var d3 = new Date("2023-08-06T04:04:05.00-04"); + var d4 = new Date("2023-08-06T04:04:05.00+02:00"); + var d5 = new Date("2023-08-06T04:04:05.00+03:00:00"); + var d6 = new Date("Tue, 3 Jun 2008 11:05:30 GMT"); + var d7 = new Date("Tue, 3 Jun 2008 11:05:30 +043056"); + return { + "dIso_1": d1.toISOString(), + "dIso_2": d2.toISOString(), + "dIso_3": d3.toISOString(), + "dIso_4": d4.toISOString(), + "dIso_5": d5.toISOString(), + "dIso_6": d6.toISOString(), + "dIso_7": d7.toISOString() + } + """, s2); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("dIso_1", "2023-08-06T04:04:05.123Z"); + TbDate d2 = new TbDate(s2); + int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d2.getInstant()).getTotalSeconds() / 60 / 60; + int hrs2 = h - localOffsetHrs; + String expected_dIso_2 = String.format("2023-08-06T%s:04:05.123Z", String.format("%02d", hrs2)); + expected.put("dIso_2", expected_dIso_2); + expected.put("dIso_3", "2023-08-06T08:04:05Z"); + expected.put("dIso_4", "2023-08-06T02:04:05Z"); + expected.put("dIso_5", "2023-08-06T01:04:05Z"); + expected.put("dIso_6", "2008-06-03T11:05:30Z"); + expected.put("dIso_7", "2008-06-03T06:34:34Z"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void tbDateStringPattern_Test() throws ExecutionException, InterruptedException { + int h = 12; + String s3 = String.format("2023-08-06 %s:04:05.000", String.format("%02d", h)); + String pattern3 = "yyyy-MM-dd HH:mm:ss.SSS"; + msgStr = "{}"; + decoderStr = String.format(""" + var pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX"; + var d1 = new Date("2023-08-06 04:04:05.000Z", pattern); + var d2 = new Date("2023-08-06 04:04:05.000-04:00", pattern); + var d3 = new Date("%s","%s"); + return { + "dIso_1": d1.toISOString(), + "dIso_2": d2.toISOString(), + "dIso_3": d3.toISOString() + } + """, s3, pattern3); + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("dIso_1", "2023-08-06T04:04:05Z"); + expected.put("dIso_2", "2023-08-06T08:04:05Z"); + TbDate d3 = new TbDate(s3, pattern3); + int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d3.getInstant()).getTotalSeconds() / 60 / 60; + int hrs3 = h - localOffsetHrs; + String expected_dIso_3 = String.format("2023-08-06T%s:04:05Z", String.format("%02d", hrs3)); + expected.put("dIso_3", expected_dIso_3); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void tbDateStringPatternLocale_Test() throws ExecutionException, InterruptedException { + int h = 12; + String sDe = String.format("%s:15:30 PM, So. 10/09/2022", String.format("%02d", h)); + String sUs = String.format("%s:15:30 PM, Sun 10/09/2022", String.format("%02d", h)); + var pattern = "hh:mm:ss a, EEE M/d/uuuu"; + msgStr = "{}"; + decoderStr = String.format(""" + var pattern = "%s"; + var d1 = new Date("%s", pattern, "de"); + var d2 = new Date("%s", pattern, "en-US"); + return { + "dIso_1": d1.toISOString(), + "dLocal_1": d1.toLocaleString("de"), + "dIso_2": d2.toISOString(), + "dLocal_2": d2.toLocaleString("en-US") + } + """, pattern, sDe, sUs); + LinkedHashMap expected = new LinkedHashMap<>(); + TbDate d1 = new TbDate(sDe, pattern, "de"); + int localOffsetHrs1 = ZoneId.systemDefault().getRules().getOffset(d1.getInstant()).getTotalSeconds() / 60 / 60; + int hrs1 = h - localOffsetHrs1; + String expected_dIso_1 = String.format("2022-10-09T%s:15:30Z", String.format("%02d", hrs1)); + String expected_dLocal_1 = String.format("09.10.22, %s:15:30", String.format("%02d", h)); + expected.put("dIso_1", expected_dIso_1); + expected.put("dLocal_1", expected_dLocal_1); + TbDate d2 = new TbDate(sUs, pattern, "en-US"); + int localOffsetHrs2 = ZoneId.systemDefault().getRules().getOffset(d2.getInstant()).getTotalSeconds() / 60 / 60; + int hrs2 = h - localOffsetHrs2; + String expected_dIso_2 = String.format("2022-10-09T%s:15:30Z", String.format("%02d", hrs2)); + String expected_dLocal_2 = String.format("10/9/22, %s:15:30 PM", String.format("%02d", h)); + expected.put("dIso_2", expected_dIso_2); + expected.put("dLocal_2", expected_dLocal_2); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + + decoderStr = String.format(""" + var pattern = "%s"; + var d = new Date("02:15:30 PM, Sun 10/09/2022", pattern, "de"); + return d; + """, pattern); + assertThatThrownBy(() -> { + invokeScript(evalScript(decoderStr), msgStr); + }).hasMessageContaining("[Error: could not create constructor") + .hasMessageContaining("[Line: 2, Column: 16]"); + } + + @Test + public void tbDateInstantYearMonthDateHrsMinSecond_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var d1 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Kyiv"); + var d2 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Berlin");; + return { + "dLocal_1": d1.toLocaleString(), + "dIso_1": d1.toISOString(), + "date_1": d1.toString(), + "dLocal_2": d2.toLocaleString(), + "dLocal_2_us": d2.toLocaleString("en-us", "America/New_York"), + "dIso_2": d2.toISOString(), + "date_2": d2.toString() + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + expected.put("dLocal_1", "2023-08-06 04:04:05"); + expected.put("dIso_1", "2023-08-06T01:04:05Z"); + TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Kyiv"); + expected.put("date_1", d1.toString()); + expected.put("dLocal_2", "2023-08-06 05:04:05"); + expected.put("dLocal_2_us", "8/5/23, 10:04:05 PM"); + expected.put("dIso_2", "2023-08-06T02:04:05Z"); + TbDate d2 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); + expected.put("date_2", d2.toString()); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + // locale private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); From 18f9c25e6b63be87fe30ff16d5b1486d54509d1d Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 30 Oct 2024 14:45:24 +0200 Subject: [PATCH 13/18] tbel: doc Io tests: tbDate with ZoneId.systemDefault() --- .../service/script/TbelInvokeDocsIoTest.java | 210 ++++++++++++++---- 1 file changed, 164 insertions(+), 46 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 165f6f7088..72b80af98e 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 @@ -21,7 +21,6 @@ import org.thingsboard.script.api.tbel.TbDate; import org.thingsboard.server.dao.service.DaoSqlTest; import java.nio.charset.StandardCharsets; -import java.time.ZoneId; import java.util.ArrayList; import java.util.Base64; import java.util.Collections; @@ -1807,17 +1806,16 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { // tbDate @Test public void tbDateStringTZ_Test() throws ExecutionException, InterruptedException { - int h = 12; - String s2 = String.format("2023-08-06T%s:04:05.123", String.format("%02d", h)); + String s2 = "2023-08-06T12:04:05.123"; msgStr = "{}"; decoderStr = String.format(""" - var d1 = new Date("2023-08-06T04:04:05.123Z"); - var d2 = new Date("%s"); - var d3 = new Date("2023-08-06T04:04:05.00-04"); - var d4 = new Date("2023-08-06T04:04:05.00+02:00"); - var d5 = new Date("2023-08-06T04:04:05.00+03:00:00"); - var d6 = new Date("Tue, 3 Jun 2008 11:05:30 GMT"); - var d7 = new Date("Tue, 3 Jun 2008 11:05:30 +043056"); + var d1 = new Date("2023-08-06T04:04:05.123Z"); // TZ => "UTC" + var d2 = new Date("%s"); // TZ = ZoneId.systemDefault() instant + var d3 = new Date("2023-08-06T04:04:05.00-04"); // TZ => "-04" + var d4 = new Date("2023-08-06T04:04:05.00+02:00"); // TZ => "+02:00" + var d5 = new Date("2023-08-06T04:04:05.00+03:00:00"); // TZ => "+03:00:00" + var d6 = new Date("Tue, 3 Jun 2008 11:05:30 GMT"); // TZ => "GMT" + var d7 = new Date("Tue, 3 Jun 2008 11:05:30 +043056"); // TZ => "+043056" return { "dIso_1": d1.toISOString(), "dIso_2": d2.toISOString(), @@ -1831,10 +1829,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { LinkedHashMap expected = new LinkedHashMap<>(); expected.put("dIso_1", "2023-08-06T04:04:05.123Z"); TbDate d2 = new TbDate(s2); - int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d2.getInstant()).getTotalSeconds() / 60 / 60; - int hrs2 = h - localOffsetHrs; - String expected_dIso_2 = String.format("2023-08-06T%s:04:05.123Z", String.format("%02d", hrs2)); - expected.put("dIso_2", expected_dIso_2); + expected.put("dIso_2", d2.toISOString()); expected.put("dIso_3", "2023-08-06T08:04:05Z"); expected.put("dIso_4", "2023-08-06T02:04:05Z"); expected.put("dIso_5", "2023-08-06T01:04:05Z"); @@ -1846,15 +1841,14 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void tbDateStringPattern_Test() throws ExecutionException, InterruptedException { - int h = 12; - String s3 = String.format("2023-08-06 %s:04:05.000", String.format("%02d", h)); + String s3 = "2023-08-06 12:04:05.000"; String pattern3 = "yyyy-MM-dd HH:mm:ss.SSS"; msgStr = "{}"; decoderStr = String.format(""" var pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX"; - var d1 = new Date("2023-08-06 04:04:05.000Z", pattern); - var d2 = new Date("2023-08-06 04:04:05.000-04:00", pattern); - var d3 = new Date("%s","%s"); + var d1 = new Date("2023-08-06 04:04:05.000Z", pattern); // Pattern without TZ => ZoneId "UTC" + var d2 = new Date("2023-08-06 04:04:05.000-04:00", pattern); // Pattern with TZ => "-04:00" + var d3 = new Date("%s","%s"); // Pattern without TZ, TZ = ZoneId.systemDefault() instant return { "dIso_1": d1.toISOString(), "dIso_2": d2.toISOString(), @@ -1865,25 +1859,21 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { expected.put("dIso_1", "2023-08-06T04:04:05Z"); expected.put("dIso_2", "2023-08-06T08:04:05Z"); TbDate d3 = new TbDate(s3, pattern3); - int localOffsetHrs = ZoneId.systemDefault().getRules().getOffset(d3.getInstant()).getTotalSeconds() / 60 / 60; - int hrs3 = h - localOffsetHrs; - String expected_dIso_3 = String.format("2023-08-06T%s:04:05Z", String.format("%02d", hrs3)); - expected.put("dIso_3", expected_dIso_3); + expected.put("dIso_3", d3.toISOString()); Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); } @Test public void tbDateStringPatternLocale_Test() throws ExecutionException, InterruptedException { - int h = 12; - String sDe = String.format("%s:15:30 PM, So. 10/09/2022", String.format("%02d", h)); - String sUs = String.format("%s:15:30 PM, Sun 10/09/2022", String.format("%02d", h)); + String sDe = "12:15:30 PM, So. 10/09/2022"; + String sUs = "12:15:30 PM, Sun 10/09/2022"; var pattern = "hh:mm:ss a, EEE M/d/uuuu"; msgStr = "{}"; decoderStr = String.format(""" var pattern = "%s"; - var d1 = new Date("%s", pattern, "de"); - var d2 = new Date("%s", pattern, "en-US"); + var d1 = new Date("%s", pattern, "de"); // Pattern without TZ, TZ = ZoneId.systemDefault() instant + var d2 = new Date("%s", pattern, "en-US"); // Pattern without TZ, TZ = ZoneId.systemDefault() instant return { "dIso_1": d1.toISOString(), "dLocal_1": d1.toLocaleString("de"), @@ -1893,19 +1883,11 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { """, pattern, sDe, sUs); LinkedHashMap expected = new LinkedHashMap<>(); TbDate d1 = new TbDate(sDe, pattern, "de"); - int localOffsetHrs1 = ZoneId.systemDefault().getRules().getOffset(d1.getInstant()).getTotalSeconds() / 60 / 60; - int hrs1 = h - localOffsetHrs1; - String expected_dIso_1 = String.format("2022-10-09T%s:15:30Z", String.format("%02d", hrs1)); - String expected_dLocal_1 = String.format("09.10.22, %s:15:30", String.format("%02d", h)); - expected.put("dIso_1", expected_dIso_1); - expected.put("dLocal_1", expected_dLocal_1); + expected.put("dIso_1", d1.toISOString()); + expected.put("dLocal_1",d1.toLocaleString("de")); TbDate d2 = new TbDate(sUs, pattern, "en-US"); - int localOffsetHrs2 = ZoneId.systemDefault().getRules().getOffset(d2.getInstant()).getTotalSeconds() / 60 / 60; - int hrs2 = h - localOffsetHrs2; - String expected_dIso_2 = String.format("2022-10-09T%s:15:30Z", String.format("%02d", hrs2)); - String expected_dLocal_2 = String.format("10/9/22, %s:15:30 PM", String.format("%02d", h)); - expected.put("dIso_2", expected_dIso_2); - expected.put("dLocal_2", expected_dLocal_2); + expected.put("dIso_2", d2.toISOString()); + expected.put("dLocal_2", d2.toLocaleString("en-US")); Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); @@ -1920,12 +1902,35 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { .hasMessageContaining("[Line: 2, Column: 16]"); } + @Test + public void tbDateStringPatternLocaleTZ_Test() throws ExecutionException, InterruptedException { + String s = "2023-08-06 04:04:05.000-04:00"; + var pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX"; + msgStr = "{}"; + decoderStr = String.format(""" + var d = new Date("%s", "%s", "de", "Europe/Kyiv"); // Pattern with TZ => "-04:00" but `Time Zone` as parameter = "Europe/Kyiv" = "+03:00" + return { + "dIso": d.toISOString(), + "dLocal_de": d.toLocaleString("de"), + "dLocal_us": d.toLocaleString("en-US") + } + """, s, pattern); + LinkedHashMap expected = new LinkedHashMap<>(); + TbDate d = new TbDate(s, pattern, "de", "Europe/Kyiv"); + expected.put("dIso", d.toISOString()); + expected.put("dLocal_de", d.toLocaleString("de")); + expected.put("dLocal_us", d.toLocaleString("en-US")); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test public void tbDateInstantYearMonthDateHrsMinSecond_Test() throws ExecutionException, InterruptedException { msgStr = "{}"; decoderStr = """ var d1 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Kyiv"); - var d2 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Berlin");; + var d2 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); return { "dLocal_1": d1.toLocaleString(), "dIso_1": d1.toISOString(), @@ -1937,20 +1942,133 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } """; LinkedHashMap expected = new LinkedHashMap<>(); - expected.put("dLocal_1", "2023-08-06 04:04:05"); - expected.put("dIso_1", "2023-08-06T01:04:05Z"); TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Kyiv"); + expected.put("dLocal_1", d1.toLocaleString()); + expected.put("dIso_1", "2023-08-06T01:04:05Z"); expected.put("date_1", d1.toString()); - expected.put("dLocal_2", "2023-08-06 05:04:05"); + TbDate d2 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); + expected.put("dLocal_2", d2.toLocaleString()); expected.put("dLocal_2_us", "8/5/23, 10:04:05 PM"); expected.put("dIso_2", "2023-08-06T02:04:05Z"); - TbDate d2 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); expected.put("date_2", d2.toString()); Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); } - // locale + @Test + public void tbDateLocale_Test() throws ExecutionException, InterruptedException { + String s2 = "2023-08-06T04:04:05.000"; + msgStr = "{}"; + decoderStr = String.format(""" + // Input date Without TZ (TZ Default = ZoneId.systemDefault()) + var d1 = new Date(2023, 8, 6, 4, 4, 5); // Parameters (int year, int month, int dayOfMonth, int hours, int minutes, int seconds) => TZ Default = ZoneId.systemDefault() + var d2 = new Date("%s"); // Parameter (String 'yyyy-MM-ddThh:mm:ss.ms') => TZ Default = ZoneId.systemDefault() + // Input date With TZ (TZ = parameter TZ or 'Z' equals 'UTC') + var d3 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); // Parameters (int year, int month, int dayOfMonth, int hours, int minutes, int seconds, TZ) => TZ "Europe/Berlin" + return { + "dLocal_1_us": d1.toLocaleString("en-US"), + "dIso_1": d1.toISOString(), + "d1": d1.toString(), + "dIso_2": d2.toISOString(), + "dLocal_2_de": d2.toLocaleString("de"), + "dLocal_2_utc": d2.toLocaleString("UTC"), + "dIso_3": d3.toISOString(), + "dLocal_3_utc": d3.toLocaleString("UTC"), + "dLocal_3_us": d3.toLocaleString("en-us"), + "dLocal_3_de": d3.toLocaleString("de") + } + """, s2); + LinkedHashMap expected = new LinkedHashMap<>(); + TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5); + expected.put("dLocal_1_us", "8/6/23, 4:04:05 AM"); + expected.put("dIso_1", d1.toISOString()); + expected.put("d1", d1.toString()); + TbDate d2 = new TbDate(s2); + expected.put("dIso_2", d2.toISOString()); + expected.put("dLocal_2_de", "06.08.23, 04:04:05"); + expected.put("dLocal_2_utc", "2023-08-06 04:04:05"); + TbDate d3 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); + expected.put("dIso_3", d3.toISOString()); + expected.put("dLocal_3_utc", "2023-08-06 05:04:05"); + expected.put("dLocal_3_us", "8/6/23, 5:04:05 AM"); + expected.put("dLocal_3_de", "06.08.23, 05:04:05"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void tbDateLocaleTZ_Test() throws ExecutionException, InterruptedException { + msgStr = "{}"; + decoderStr = """ + var d = new Date(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); // Parameters (int year, int month, int dayOfMonth, int hours, int minutes, int seconds, TZ) => TZ "Europe/Berlin"; + return { + "dIso": d.toISOString(), + "dLocal_utc": d.toLocaleString("UTC"), + "dLocal_us": d.toLocaleString("en-us", "America/New_York"), + "dLocal_de": d.toLocaleString("de", "Europe/Berlin") + } + """; + LinkedHashMap expected = new LinkedHashMap<>(); + TbDate d = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); + expected.put("dIso", d.toISOString()); + expected.put("dLocal_utc", d.toLocaleString("UTC")); + expected.put("dLocal_us", "8/5/23, 10:04:05 PM"); + expected.put("dLocal_de", "06.08.23, 04:04:05"); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + + @Test + public void tbDateLocalPatternMap_Test() throws ExecutionException, InterruptedException { + String s1 = "2023-08-06T04:04:05.00Z"; + msgStr = "{}"; + decoderStr = String.format(""" + var d1 = new Date("%s"); // TZ => "UTC" + var options1 = {"timeZone":"America/New_York"}; // TZ = "-04:00" + var options1Str = JSON.stringify(options1); + var d2 = new Date("2023-08-06T04:04:05.000"); // TZ => Default = ZoneId.systemDefault + var options2 = {"timeZone":"America/New_York"}; + var options2Str = JSON.stringify(options2); + var d3 = new Date(2023, 8, 6, 4, 4, 5); // TZ => Default = ZoneId.systemDefault + var options3 = {"timeZone":"America/New_York", "pattern": "M-d/yyyy, h:mm=ss a"}; + var options3Str = JSON.stringify(options3); + var d4 = new Date(2023, 8, 6, 4, 4, 5, "UTC"); // TZ => "UTC" + var options4 = {"timeZone":"America/New_York","dateStyle":"full","timeStyle":"full"}; + var options4Str = JSON.stringify(options4); + return { + "dIso_1": d1.toISOString(), + "dLocal_1": d1.toLocaleString(), + "dLocal_1_options": d1.toLocaleString("en-US", options1Str), + "dIso_2": d2.toISOString(), + "dLocal_2_options": d2.toLocaleString("en-US", options2Str);, + "dIso_3": d3.toISOString(), + "dLocal_3_options": d3.toLocaleString("en-US", options3Str), + "dIso_4": d4.toISOString(), + "dLocal_4_options_ua": d4.toLocaleString("uk-UA", options4Str), + "dLocal_4_options_us": d4.toLocaleString("en-US", options4Str), + "dLocal_4_options_de": d4.toLocaleString("de", options4Str) + } + """, s1); + LinkedHashMap expected = new LinkedHashMap<>(); + TbDate d1 = new TbDate(s1); + expected.put("dIso_1", "2023-08-06T04:04:05Z"); + expected.put("dLocal_1", d1.toLocaleString()); + expected.put("dLocal_1_options", "8/6/23, 12:04:05 AM"); + expected.put("dIso_2", "2023-08-06T01:04:05Z"); + expected.put("dLocal_2_options", "8/5/23, 9:04:05 PM"); + TbDate d3 = new TbDate(2023, 8, 6, 4, 4, 5); + expected.put("dIso_3", d3.toISOString()); + expected.put("dLocal_3_options", "8-5/2023, 9:04=05 PM"); + TbDate d4 = new TbDate(2023, 8, 6, 4, 4, 5, "UTC"); + String options4Str = "{\"timeZone\":\"America/New_York\",\"dateStyle\":\"full\",\"timeStyle\":\"full\"}"; + expected.put("dIso_4", "2023-08-06T04:04:05Z"); + expected.put("dLocal_4_options_ua", d4.toLocaleString("uk-UA", options4Str)); + expected.put("dLocal_4_options_us", d4.toLocaleString("en-US", options4Str)); + expected.put("dLocal_4_options_de", d4.toLocaleString("de", options4Str)); + Object actual = invokeScript(evalScript(decoderStr), msgStr); + assertEquals(expected, actual); + } + private List splice(List oldList, int start, int deleteCount, Object... values) { start = initStartIndex(oldList, start); From a00ae9e621573b939abd2533ae10cedb6b8c2ae0 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 30 Oct 2024 15:14:59 +0200 Subject: [PATCH 14/18] tbel: doc Io tests: tbDate with ZoneId.systemDefault() - 2 --- .../server/service/script/TbelInvokeDocsIoTest.java | 12 +++++++----- 1 file changed, 7 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 72b80af98e..d91c7e5ed2 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 @@ -1944,12 +1944,12 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { LinkedHashMap expected = new LinkedHashMap<>(); TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Kyiv"); expected.put("dLocal_1", d1.toLocaleString()); - expected.put("dIso_1", "2023-08-06T01:04:05Z"); + expected.put("dIso_1", d1.toISOString()); expected.put("date_1", d1.toString()); TbDate d2 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); expected.put("dLocal_2", d2.toLocaleString()); expected.put("dLocal_2_us", "8/5/23, 10:04:05 PM"); - expected.put("dIso_2", "2023-08-06T02:04:05Z"); + expected.put("dIso_2", d2.toISOString()); expected.put("date_2", d2.toString()); Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); @@ -2021,12 +2021,13 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void tbDateLocalPatternMap_Test() throws ExecutionException, InterruptedException { String s1 = "2023-08-06T04:04:05.00Z"; + String s2 = "2023-08-06T04:04:05.000"; msgStr = "{}"; decoderStr = String.format(""" var d1 = new Date("%s"); // TZ => "UTC" var options1 = {"timeZone":"America/New_York"}; // TZ = "-04:00" var options1Str = JSON.stringify(options1); - var d2 = new Date("2023-08-06T04:04:05.000"); // TZ => Default = ZoneId.systemDefault + var d2 = new Date("%s"); // TZ => Default = ZoneId.systemDefault var options2 = {"timeZone":"America/New_York"}; var options2Str = JSON.stringify(options2); var d3 = new Date(2023, 8, 6, 4, 4, 5); // TZ => Default = ZoneId.systemDefault @@ -2048,13 +2049,14 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { "dLocal_4_options_us": d4.toLocaleString("en-US", options4Str), "dLocal_4_options_de": d4.toLocaleString("de", options4Str) } - """, s1); + """, s1, s2); LinkedHashMap expected = new LinkedHashMap<>(); TbDate d1 = new TbDate(s1); expected.put("dIso_1", "2023-08-06T04:04:05Z"); expected.put("dLocal_1", d1.toLocaleString()); expected.put("dLocal_1_options", "8/6/23, 12:04:05 AM"); - expected.put("dIso_2", "2023-08-06T01:04:05Z"); + TbDate d2 = new TbDate(s2); + expected.put("dIso_2", d2.toISOString()); expected.put("dLocal_2_options", "8/5/23, 9:04:05 PM"); TbDate d3 = new TbDate(2023, 8, 6, 4, 4, 5); expected.put("dIso_3", d3.toISOString()); From 64930967bae796bff0ce34efe3123ff6e822a140 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 30 Oct 2024 15:47:26 +0200 Subject: [PATCH 15/18] tbel: doc Io tests: tbDate with ZoneId.systemDefault() - 3 --- .../service/script/TbelInvokeDocsIoTest.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 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 d91c7e5ed2..c851a01a07 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 @@ -2025,15 +2025,15 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { msgStr = "{}"; decoderStr = String.format(""" var d1 = new Date("%s"); // TZ => "UTC" - var options1 = {"timeZone":"America/New_York"}; // TZ = "-04:00" + var options1 = {"timeZone":"America/New_York"}; // TZ = "-04:00" var options1Str = JSON.stringify(options1); - var d2 = new Date("%s"); // TZ => Default = ZoneId.systemDefault + var d2 = new Date("%s"); // TZ => Default = ZoneId.systemDefault var options2 = {"timeZone":"America/New_York"}; var options2Str = JSON.stringify(options2); - var d3 = new Date(2023, 8, 6, 4, 4, 5); // TZ => Default = ZoneId.systemDefault + var d3 = new Date(2023, 8, 6, 4, 4, 5); // TZ => Default = ZoneId.systemDefault var options3 = {"timeZone":"America/New_York", "pattern": "M-d/yyyy, h:mm=ss a"}; var options3Str = JSON.stringify(options3); - var d4 = new Date(2023, 8, 6, 4, 4, 5, "UTC"); // TZ => "UTC" + var d4 = new Date(2023, 8, 6, 4, 4, 5, "UTC"); // TZ => "UTC" var options4 = {"timeZone":"America/New_York","dateStyle":"full","timeStyle":"full"}; var options4Str = JSON.stringify(options4); return { @@ -2056,11 +2056,13 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { expected.put("dLocal_1", d1.toLocaleString()); expected.put("dLocal_1_options", "8/6/23, 12:04:05 AM"); TbDate d2 = new TbDate(s2); + String options2Str = "{\"timeZone\":\"America/New_York\"}"; expected.put("dIso_2", d2.toISOString()); - expected.put("dLocal_2_options", "8/5/23, 9:04:05 PM"); + expected.put("dLocal_2_options", d2.toLocaleString("en-US", options2Str)); TbDate d3 = new TbDate(2023, 8, 6, 4, 4, 5); + String options3Str = "{\"timeZone\":\"America/New_York\", \"pattern\": \"M-d/yyyy, h:mm=ss a\"}"; expected.put("dIso_3", d3.toISOString()); - expected.put("dLocal_3_options", "8-5/2023, 9:04=05 PM"); + expected.put("dLocal_3_options", d3.toLocaleString("en-US", options3Str)); TbDate d4 = new TbDate(2023, 8, 6, 4, 4, 5, "UTC"); String options4Str = "{\"timeZone\":\"America/New_York\",\"dateStyle\":\"full\",\"timeStyle\":\"full\"}"; expected.put("dIso_4", "2023-08-06T04:04:05Z"); From 7814db1620e06460dba4dc7c077ceb466ec0e734 Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 30 Oct 2024 16:17:45 +0200 Subject: [PATCH 16/18] tbel: doc Io tests: tbDate with ZoneId.systemDefault() - 4 --- .../server/service/script/TbelInvokeDocsIoTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 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 c851a01a07..b4ee224f77 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 @@ -1989,9 +1989,9 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { expected.put("dLocal_2_utc", "2023-08-06 04:04:05"); TbDate d3 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); expected.put("dIso_3", d3.toISOString()); - expected.put("dLocal_3_utc", "2023-08-06 05:04:05"); - expected.put("dLocal_3_us", "8/6/23, 5:04:05 AM"); - expected.put("dLocal_3_de", "06.08.23, 05:04:05"); + expected.put("dLocal_3_utc", d3.toLocaleString("UTC")); + expected.put("dLocal_3_us", d3.toLocaleString("en-us")); + expected.put("dLocal_3_de", d3.toLocaleString("de")); Object actual = invokeScript(evalScript(decoderStr), msgStr); assertEquals(expected, actual); } From bc9af20aae4d64061b4163e0840ef9558193692d Mon Sep 17 00:00:00 2001 From: nick Date: Wed, 30 Oct 2024 16:49:51 +0200 Subject: [PATCH 17/18] tbel: doc Io tests: doubleToString - 5 --- .../service/script/TbelInvokeDocsIoTest.java | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 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 b4ee224f77..36827dacfe 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 @@ -857,7 +857,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } @Test - public void dpubleToString_Test() throws ExecutionException, InterruptedException { + public void doubleToString_Test() throws ExecutionException, InterruptedException { msgStr = "{}"; decoderStr = """ var dd0 = 99993219.156013e-002; @@ -869,10 +869,11 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } """; LinkedHashMap expected = new LinkedHashMap<>(); + Double dd0 = 99993219.156013e-002d; expected.put("dd16", "0x1.e83f862142b5bp19"); - expected.put("dd10", "999932,19156013"); + expected.put("dd10", String.format("%.8f", dd0)); Object actual = invokeScript(evalScript(decoderStr), msgStr); - assertEquals(expected, actual); + assertEquals(expected.toString(), actual.toString()); } // Flow Control @@ -1884,7 +1885,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { LinkedHashMap expected = new LinkedHashMap<>(); TbDate d1 = new TbDate(sDe, pattern, "de"); expected.put("dIso_1", d1.toISOString()); - expected.put("dLocal_1",d1.toLocaleString("de")); + expected.put("dLocal_1", d1.toLocaleString("de")); TbDate d2 = new TbDate(sUs, pattern, "en-US"); expected.put("dIso_2", d2.toISOString()); expected.put("dLocal_2", d2.toLocaleString("en-US")); @@ -1925,7 +1926,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { assertEquals(expected, actual); } - @Test + @Test public void tbDateInstantYearMonthDateHrsMinSecond_Test() throws ExecutionException, InterruptedException { msgStr = "{}"; decoderStr = """ @@ -1960,24 +1961,24 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { String s2 = "2023-08-06T04:04:05.000"; msgStr = "{}"; decoderStr = String.format(""" - // Input date Without TZ (TZ Default = ZoneId.systemDefault()) - var d1 = new Date(2023, 8, 6, 4, 4, 5); // Parameters (int year, int month, int dayOfMonth, int hours, int minutes, int seconds) => TZ Default = ZoneId.systemDefault() - var d2 = new Date("%s"); // Parameter (String 'yyyy-MM-ddThh:mm:ss.ms') => TZ Default = ZoneId.systemDefault() - // Input date With TZ (TZ = parameter TZ or 'Z' equals 'UTC') - var d3 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); // Parameters (int year, int month, int dayOfMonth, int hours, int minutes, int seconds, TZ) => TZ "Europe/Berlin" - return { - "dLocal_1_us": d1.toLocaleString("en-US"), - "dIso_1": d1.toISOString(), - "d1": d1.toString(), - "dIso_2": d2.toISOString(), - "dLocal_2_de": d2.toLocaleString("de"), - "dLocal_2_utc": d2.toLocaleString("UTC"), - "dIso_3": d3.toISOString(), - "dLocal_3_utc": d3.toLocaleString("UTC"), - "dLocal_3_us": d3.toLocaleString("en-us"), - "dLocal_3_de": d3.toLocaleString("de") - } - """, s2); + // Input date Without TZ (TZ Default = ZoneId.systemDefault()) + var d1 = new Date(2023, 8, 6, 4, 4, 5); // Parameters (int year, int month, int dayOfMonth, int hours, int minutes, int seconds) => TZ Default = ZoneId.systemDefault() + var d2 = new Date("%s"); // Parameter (String 'yyyy-MM-ddThh:mm:ss.ms') => TZ Default = ZoneId.systemDefault() + // Input date With TZ (TZ = parameter TZ or 'Z' equals 'UTC') + var d3 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); // Parameters (int year, int month, int dayOfMonth, int hours, int minutes, int seconds, TZ) => TZ "Europe/Berlin" + return { + "dLocal_1_us": d1.toLocaleString("en-US"), + "dIso_1": d1.toISOString(), + "d1": d1.toString(), + "dIso_2": d2.toISOString(), + "dLocal_2_de": d2.toLocaleString("de"), + "dLocal_2_utc": d2.toLocaleString("UTC"), + "dIso_3": d3.toISOString(), + "dLocal_3_utc": d3.toLocaleString("UTC"), + "dLocal_3_us": d3.toLocaleString("en-us"), + "dLocal_3_de": d3.toLocaleString("de") + } + """, s2); LinkedHashMap expected = new LinkedHashMap<>(); TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5); expected.put("dLocal_1_us", "8/6/23, 4:04:05 AM"); From e30b2a2201c62edc9096ede8401a61ebcb649949 Mon Sep 17 00:00:00 2001 From: nick Date: Thu, 31 Oct 2024 06:54:28 -0400 Subject: [PATCH 18/18] tbel: doc Io tests: toLocaleString ZoneId.systemDefault(): "America/New_York" = "-04:00" --- .../service/script/TbelInvokeDocsIoTest.java | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 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 36827dacfe..188599a530 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 @@ -1906,11 +1906,11 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { @Test public void tbDateStringPatternLocaleTZ_Test() throws ExecutionException, InterruptedException { - String s = "2023-08-06 04:04:05.000-04:00"; + String s = "2023-08-06 04:04:05.000+02:00"; var pattern = "yyyy-MM-dd HH:mm:ss.SSSXXX"; msgStr = "{}"; decoderStr = String.format(""" - var d = new Date("%s", "%s", "de", "Europe/Kyiv"); // Pattern with TZ => "-04:00" but `Time Zone` as parameter = "Europe/Kyiv" = "+03:00" + var d = new Date("%s", "%s", "de", "America/New_York"); // Pattern with TZ => "+02:00" but `Time Zone` as parameter = "America/New_York" = "-04:00" return { "dIso": d.toISOString(), "dLocal_de": d.toLocaleString("de"), @@ -1918,7 +1918,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } """, s, pattern); LinkedHashMap expected = new LinkedHashMap<>(); - TbDate d = new TbDate(s, pattern, "de", "Europe/Kyiv"); + TbDate d = new TbDate(s, pattern, "de", "America/New_York"); expected.put("dIso", d.toISOString()); expected.put("dLocal_de", d.toLocaleString("de")); expected.put("dLocal_us", d.toLocaleString("en-US")); @@ -1930,7 +1930,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { public void tbDateInstantYearMonthDateHrsMinSecond_Test() throws ExecutionException, InterruptedException { msgStr = "{}"; decoderStr = """ - var d1 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Kyiv"); + var d1 = new Date(2023, 8, 6, 4, 4, 5, "America/New_York"); var d2 = new Date(2023, 8, 6, 4, 4, 5, "Europe/Berlin"); return { "dLocal_1": d1.toLocaleString(), @@ -1943,7 +1943,7 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { } """; LinkedHashMap expected = new LinkedHashMap<>(); - TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5, "Europe/Kyiv"); + TbDate d1 = new TbDate(2023, 8, 6, 4, 4, 5, "America/New_York"); expected.put("dLocal_1", d1.toLocaleString()); expected.put("dIso_1", d1.toISOString()); expected.put("date_1", d1.toString()); @@ -2023,26 +2023,25 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { public void tbDateLocalPatternMap_Test() throws ExecutionException, InterruptedException { String s1 = "2023-08-06T04:04:05.00Z"; String s2 = "2023-08-06T04:04:05.000"; + String options1_2Str = "{\"timeZone\":\"Europe/Berlin\"}"; msgStr = "{}"; decoderStr = String.format(""" - var d1 = new Date("%s"); // TZ => "UTC" - var options1 = {"timeZone":"America/New_York"}; // TZ = "-04:00" - var options1Str = JSON.stringify(options1); + var d1 = new Date("%s"); // TZ => "UTC" var d2 = new Date("%s"); // TZ => Default = ZoneId.systemDefault - var options2 = {"timeZone":"America/New_York"}; - var options2Str = JSON.stringify(options2); + var options1_2 = %s; // TZ = "+02:00" + var options1_2Str = JSON.stringify(options1_2); var d3 = new Date(2023, 8, 6, 4, 4, 5); // TZ => Default = ZoneId.systemDefault - var options3 = {"timeZone":"America/New_York", "pattern": "M-d/yyyy, h:mm=ss a"}; + var options3 = {"timeZone":"Europe/Berlin", "pattern": "M-d/yyyy, h:mm=ss a"}; var options3Str = JSON.stringify(options3); var d4 = new Date(2023, 8, 6, 4, 4, 5, "UTC"); // TZ => "UTC" - var options4 = {"timeZone":"America/New_York","dateStyle":"full","timeStyle":"full"}; + var options4 = {"timeZone":"Europe/Berlin","dateStyle":"full","timeStyle":"full"}; var options4Str = JSON.stringify(options4); return { "dIso_1": d1.toISOString(), "dLocal_1": d1.toLocaleString(), - "dLocal_1_options": d1.toLocaleString("en-US", options1Str), + "dLocal_1_options": d1.toLocaleString("en-US", options1_2Str), "dIso_2": d2.toISOString(), - "dLocal_2_options": d2.toLocaleString("en-US", options2Str);, + "dLocal_2_options": d2.toLocaleString("en-US", options1_2Str);, "dIso_3": d3.toISOString(), "dLocal_3_options": d3.toLocaleString("en-US", options3Str), "dIso_4": d4.toISOString(), @@ -2050,22 +2049,21 @@ class TbelInvokeDocsIoTest extends AbstractTbelInvokeTest { "dLocal_4_options_us": d4.toLocaleString("en-US", options4Str), "dLocal_4_options_de": d4.toLocaleString("de", options4Str) } - """, s1, s2); + """, s1, s2, options1_2Str); LinkedHashMap expected = new LinkedHashMap<>(); TbDate d1 = new TbDate(s1); expected.put("dIso_1", "2023-08-06T04:04:05Z"); expected.put("dLocal_1", d1.toLocaleString()); - expected.put("dLocal_1_options", "8/6/23, 12:04:05 AM"); + expected.put("dLocal_1_options", d1.toLocaleString("en-US", options1_2Str)); TbDate d2 = new TbDate(s2); - String options2Str = "{\"timeZone\":\"America/New_York\"}"; expected.put("dIso_2", d2.toISOString()); - expected.put("dLocal_2_options", d2.toLocaleString("en-US", options2Str)); + expected.put("dLocal_2_options", d2.toLocaleString("en-US", options1_2Str)); TbDate d3 = new TbDate(2023, 8, 6, 4, 4, 5); - String options3Str = "{\"timeZone\":\"America/New_York\", \"pattern\": \"M-d/yyyy, h:mm=ss a\"}"; + String options3Str = "{\"timeZone\":\"Europe/Berlin\", \"pattern\": \"M-d/yyyy, h:mm=ss a\"}"; expected.put("dIso_3", d3.toISOString()); expected.put("dLocal_3_options", d3.toLocaleString("en-US", options3Str)); TbDate d4 = new TbDate(2023, 8, 6, 4, 4, 5, "UTC"); - String options4Str = "{\"timeZone\":\"America/New_York\",\"dateStyle\":\"full\",\"timeStyle\":\"full\"}"; + String options4Str = "{\"timeZone\":\"Europe/Berlin\",\"dateStyle\":\"full\",\"timeStyle\":\"full\"}"; expected.put("dIso_4", "2023-08-06T04:04:05Z"); expected.put("dLocal_4_options_ua", d4.toLocaleString("uk-UA", options4Str)); expected.put("dLocal_4_options_us", d4.toLocaleString("en-US", options4Str));