TBEL Utils and tests

This commit is contained in:
Andrii Shvaika 2022-11-25 19:54:41 +02:00
parent 046d313581
commit acfd8afa0c
2 changed files with 166 additions and 10 deletions

View File

@ -24,6 +24,8 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Base64; import java.util.Base64;
import java.util.List; import java.util.List;
@ -65,12 +67,24 @@ public class TbUtils {
String.class))); String.class)));
parserConfig.addImport("parseHexToInt", new MethodStub(TbUtils.class.getMethod("parseHexToInt", parserConfig.addImport("parseHexToInt", new MethodStub(TbUtils.class.getMethod("parseHexToInt",
String.class, boolean.class))); String.class, boolean.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
List.class, int.class, int.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
List.class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesToInt", new MethodStub(TbUtils.class.getMethod("parseBytesToInt",
byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed", parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed",
double.class, int.class))); double.class, int.class)));
parserConfig.addImport("hexToBytes", new MethodStub(TbUtils.class.getMethod("hexToBytes", parserConfig.addImport("hexToBytes", new MethodStub(TbUtils.class.getMethod("hexToBytes",
ExecutionContext.class, String.class))); ExecutionContext.class, String.class)));
parserConfig.addImport("base64ToHex", new MethodStub(TbUtils.class.getMethod("base64ToHex", parserConfig.addImport("base64ToHex", new MethodStub(TbUtils.class.getMethod("base64ToHex",
String.class))); String.class)));
parserConfig.addImport("base64ToBytes", new MethodStub(TbUtils.class.getMethod("base64ToBytes",
String.class)));
parserConfig.addImport("bytesToBase64", new MethodStub(TbUtils.class.getMethod("bytesToBase64",
byte[].class)));
parserConfig.addImport("bytesToHex", new MethodStub(TbUtils.class.getMethod("bytesToHex", parserConfig.addImport("bytesToHex", new MethodStub(TbUtils.class.getMethod("bytesToHex",
byte[].class))); byte[].class)));
parserConfig.addImport("bytesToHex", new MethodStub(TbUtils.class.getMethod("bytesToHex", parserConfig.addImport("bytesToHex", new MethodStub(TbUtils.class.getMethod("bytesToHex",
@ -119,8 +133,8 @@ public class TbUtils {
private static List<Byte> bytesToList(ExecutionContext ctx, byte[] bytes) { private static List<Byte> bytesToList(ExecutionContext ctx, byte[] bytes) {
List<Byte> list = new ExecutionArrayList<>(ctx); List<Byte> list = new ExecutionArrayList<>(ctx);
for (int i = 0; i < bytes.length; i++) { for (byte aByte : bytes) {
list.add(bytes[i]); list.add(aByte);
} }
return list; return list;
} }
@ -194,14 +208,14 @@ public class TbUtils {
if (length > 8) { if (length > 8) {
throw new IllegalArgumentException("Hex string is too large. Maximum 8 symbols allowed."); throw new IllegalArgumentException("Hex string is too large. Maximum 8 symbols allowed.");
} }
if (bigEndian) { if (length % 2 > 0) {
return Integer.parseInt(hex, 16); throw new IllegalArgumentException("Hex string must be even-length.");
} else {
if (length < 8) {
hex = hex + "0".repeat(8 - length);
} }
return Integer.reverseBytes(Integer.parseInt(hex, 16)); byte[] data = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
} }
return parseBytesToInt(data, 0, data.length, bigEndian);
} }
public static ExecutionArrayList<Integer> hexToBytes(ExecutionContext ctx, String hex) { public static ExecutionArrayList<Integer> hexToBytes(ExecutionContext ctx, String hex) {
@ -221,6 +235,50 @@ public class TbUtils {
return bytesToHex(Base64.getDecoder().decode(base64)); return bytesToHex(Base64.getDecoder().decode(base64));
} }
public static String bytesToBase64(byte[] bytes) {
return Base64.getEncoder().encodeToString(bytes);
}
public static byte[] base64ToBytes(String input) {
return Base64.getDecoder().decode(input);
}
public static int parseBytesToInt(List<Byte> data, int offset, int length) {
return parseBytesToInt(data, offset, length, true);
}
public static int parseBytesToInt(List<Byte> data, int offset, int length, boolean bigEndian) {
final byte[] bytes = new byte[data.size()];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = data.get(i);
}
return parseBytesToInt(bytes, offset, length, bigEndian);
}
public static int parseBytesToInt(byte[] data, int offset, int length) {
return parseBytesToInt(data, offset, length, true);
}
public static int parseBytesToInt(byte[] data, int offset, int length, boolean bigEndian) {
if (offset > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!");
}
if (length > 4) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum 4 bytes is allowed!");
}
if (offset + length > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!");
}
var bb = ByteBuffer.allocate(4);
if (!bigEndian) {
bb.order(ByteOrder.LITTLE_ENDIAN);
}
bb.position(bigEndian ? 4 - length : 0);
bb.put(data, offset, length);
bb.position(0);
return bb.getInt();
}
public static String bytesToHex(ExecutionArrayList<?> bytesList) { public static String bytesToHex(ExecutionArrayList<?> bytesList) {
byte[] bytes = new byte[bytesList.size()]; byte[] bytes = new byte[bytesList.size()];
for (int i = 0; i < bytesList.size(); i++) { for (int i = 0; i < bytesList.size(); i++) {

View File

@ -0,0 +1,98 @@
/**
* Copyright © 2016-2022 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.script.api.tbel;
import org.junit.Assert;
import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class TbUtilsTest {
@Test
public void parseHexToInt() {
Assert.assertEquals(0xAB, TbUtils.parseHexToInt("AB"));
Assert.assertEquals(0xABBA, TbUtils.parseHexToInt("ABBA", true));
Assert.assertEquals(0xBAAB, TbUtils.parseHexToInt("ABBA", false));
Assert.assertEquals(0xAABBCC, TbUtils.parseHexToInt("AABBCC", true));
Assert.assertEquals(0xAABBCC, TbUtils.parseHexToInt("CCBBAA", false));
Assert.assertEquals(0xAABBCCDD, TbUtils.parseHexToInt("AABBCCDD", true));
Assert.assertEquals(0xAABBCCDD, TbUtils.parseHexToInt("DDCCBBAA", false));
Assert.assertEquals(0xDDCCBBAA, TbUtils.parseHexToInt("DDCCBBAA", true));
Assert.assertEquals(0xDDCCBBAA, TbUtils.parseHexToInt("AABBCCDD", false));
}
@Test
public void parseBytesToInt_checkPrimitives() {
int expected = 257;
byte[] data = ByteBuffer.allocate(4).putInt(expected).array();
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4));
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 2, 2, true));
Assert.assertEquals(1, TbUtils.parseBytesToInt(data, 3, 1, true));
expected = Integer.MAX_VALUE;
data = ByteBuffer.allocate(4).putInt(expected).array();
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
expected = 0xAABBCCDD;
data = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD};
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
data = new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA};
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, false));
expected = 0xAABBCC;
data = new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC};
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, true));
data = new byte[]{(byte) 0xCC, (byte) 0xBB, (byte) 0xAA};
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false));
}
@Test
public void parseBytesToInt_checkLists() {
int expected = 257;
List<Byte> data = toList(ByteBuffer.allocate(4).putInt(expected).array());
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4));
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 2, 2, true));
Assert.assertEquals(1, TbUtils.parseBytesToInt(data, 3, 1, true));
expected = Integer.MAX_VALUE;
data = toList(ByteBuffer.allocate(4).putInt(expected).array());
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
expected = 0xAABBCCDD;
data = toList(new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD});
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, true));
data = toList(new byte[]{(byte) 0xDD, (byte) 0xCC, (byte) 0xBB, (byte) 0xAA});
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 4, false));
expected = 0xAABBCC;
data = toList(new byte[]{(byte) 0xAA, (byte) 0xBB, (byte) 0xCC});
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, true));
data = toList(new byte[]{(byte) 0xCC, (byte) 0xBB, (byte) 0xAA});
Assert.assertEquals(expected, TbUtils.parseBytesToInt(data, 0, 3, false));
}
private static List<Byte> toList(byte[] data) {
List<Byte> result = new ArrayList<>(data.length);
for (Byte b : data) {
result.add(b);
}
return result;
}
}