Browse Source

TBEL: added parseBytesIntToFloat, parseBytesLongToDouble, byteArrayToExecutionArrayList (#11296)

* tbel: added  parseBytesIntLongToFloat

* tbel: added  to doubleToHex_Test() String valueHex = "0x000000000000000A";

* tbel: added  byteArray to ExecutionArrayList;
pull/11323/head
Kulikov 2 years ago
committed by GitHub
parent
commit
b48474861e
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 250
      common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java
  2. 190
      common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java

250
common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/TbUtils.java

@ -194,6 +194,22 @@ public class TbUtils {
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesToFloat",
byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesIntToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesIntToFloat",
List.class)));
parserConfig.addImport("parseBytesIntToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesIntToFloat",
List.class, int.class)));
parserConfig.addImport("parseBytesIntToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesIntToFloat",
List.class, int.class, int.class)));
parserConfig.addImport("parseBytesIntToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesIntToFloat",
List.class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesIntToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesIntToFloat",
byte[].class)));
parserConfig.addImport("parseBytesIntToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesIntToFloat",
byte[].class, int.class)));
parserConfig.addImport("parseBytesIntToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesIntToFloat",
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesIntToFloat", new MethodStub(TbUtils.class.getMethod("parseBytesIntToFloat",
byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseLittleEndianHexToDouble", new MethodStub(TbUtils.class.getMethod("parseLittleEndianHexToDouble",
String.class)));
parserConfig.addImport("parseBigEndianHexToDouble", new MethodStub(TbUtils.class.getMethod("parseBigEndianHexToDouble",
@ -218,6 +234,22 @@ public class TbUtils {
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesToDouble",
byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesLongToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesLongToDouble",
List.class)));
parserConfig.addImport("parseBytesLongToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesLongToDouble",
List.class, int.class)));
parserConfig.addImport("parseBytesLongToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesLongToDouble",
List.class, int.class, int.class)));
parserConfig.addImport("parseBytesLongToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesLongToDouble",
List.class, int.class, int.class, boolean.class)));
parserConfig.addImport("parseBytesLongToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesLongToDouble",
byte[].class)));
parserConfig.addImport("parseBytesLongToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesLongToDouble",
byte[].class, int.class)));
parserConfig.addImport("parseBytesLongToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesLongToDouble",
byte[].class, int.class, int.class)));
parserConfig.addImport("parseBytesLongToDouble", new MethodStub(TbUtils.class.getMethod("parseBytesLongToDouble",
byte[].class, int.class, int.class, boolean.class)));
parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed",
double.class, int.class)));
parserConfig.addImport("toFixed", new MethodStub(TbUtils.class.getMethod("toFixed",
@ -292,6 +324,9 @@ public class TbUtils {
String.class)));
parserConfig.addImport("isHexadecimal", new MethodStub(TbUtils.class.getMethod("isHexadecimal",
String.class)));
parserConfig.addImport("byteArrayToExecutionArrayList", new MethodStub(TbUtils.class.getMethod("byteArrayToExecutionArrayList",
ExecutionContext.class, byte[].class)));
}
public static String btoa(String input) {
@ -753,7 +788,7 @@ public class TbUtils {
long bits = Double.doubleToRawLongBits(d);
// Format the integer bits as a hexadecimal string
String result = String.format("0x%16X", bits);
String result = String.format("0x%016X", bits);
return bigEndian ? result : reverseHexStringByOrder(result);
}
@ -770,15 +805,15 @@ public class TbUtils {
}
public static int parseBytesToInt(List<Byte> data) {
return parseBytesToInt(Bytes.toArray(data));
return parseBytesToInt(data, 0);
}
public static int parseBytesToInt(List<Byte> data, int offset) {
return parseBytesToInt(Bytes.toArray(data), offset);
return parseBytesToInt(data, offset, validateLength(data.size(), offset, BYTES_LEN_INT_MAX));
}
public static int parseBytesToInt(List<Byte> data, int offset, int length) {
return parseBytesToInt(Bytes.toArray(data), offset, length);
return parseBytesToInt(data, offset, length, true);
}
public static int parseBytesToInt(List<Byte> data, int offset, int length, boolean bigEndian) {
@ -798,15 +833,7 @@ public class TbUtils {
}
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 > BYTES_LEN_INT_MAX) {
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 + "!");
}
validationNumberByLength(data, offset, length, BYTES_LEN_INT_MAX);
var bb = ByteBuffer.allocate(4);
if (!bigEndian) {
bb.order(ByteOrder.LITTLE_ENDIAN);
@ -818,15 +845,15 @@ public class TbUtils {
}
public static long parseBytesToLong(List<Byte> data) {
return parseBytesToLong(Bytes.toArray(data));
return parseBytesToLong(data, 0);
}
public static long parseBytesToLong(List<Byte> data, int offset) {
return parseBytesToLong(Bytes.toArray(data), offset);
return parseBytesToLong(data, offset, validateLength(data.size(), offset, BYTES_LEN_LONG_MAX));
}
public static long parseBytesToLong(List<Byte> data, int offset, int length) {
return parseBytesToLong(Bytes.toArray(data), offset, length);
return parseBytesToLong(data, offset, length, true);
}
public static long parseBytesToLong(List<Byte> data, int offset, int length, boolean bigEndian) {
@ -846,15 +873,7 @@ public class TbUtils {
}
public static long parseBytesToLong(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 > BYTES_LEN_LONG_MAX) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum " + BYTES_LEN_LONG_MAX + " 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 + "!");
}
validationNumberByLength(data, offset, length, BYTES_LEN_LONG_MAX);
var bb = ByteBuffer.allocate(BYTES_LEN_LONG_MAX);
if (!bigEndian) {
bb.order(ByteOrder.LITTLE_ENDIAN);
@ -866,15 +885,15 @@ public class TbUtils {
}
public static float parseBytesToFloat(List data) {
return parseBytesToFloat(Bytes.toArray(data), 0);
return parseBytesToFloat(data, 0);
}
public static float parseBytesToFloat(List data, int offset) {
return parseBytesToFloat(Bytes.toArray(data), offset, BYTES_LEN_INT_MAX);
return parseBytesToFloat(data, offset, validateLength(data.size(), offset, BYTES_LEN_INT_MAX));
}
public static float parseBytesToFloat(List data, int offset, int length) {
return parseBytesToFloat(Bytes.toArray(data), offset, length, true);
return parseBytesToFloat(data, offset, length, true);
}
public static float parseBytesToFloat(List data, int offset, int length, boolean bigEndian) {
@ -886,7 +905,7 @@ public class TbUtils {
}
public static float parseBytesToFloat(byte[] data, int offset) {
return parseBytesToFloat(data, offset, BYTES_LEN_INT_MAX);
return parseBytesToFloat(data, offset, validateLength(data.length, offset, BYTES_LEN_INT_MAX));
}
public static float parseBytesToFloat(byte[] data, int offset, int length) {
@ -894,39 +913,65 @@ public class TbUtils {
}
public static float parseBytesToFloat(byte[] data, int offset, int length, boolean bigEndian) {
if (length > BYTES_LEN_INT_MAX) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum " + BYTES_LEN_INT_MAX + " 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 + "!");
}
byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian);
if (bytesToNumber.length < BYTES_LEN_INT_MAX) {
byte[] extendedBytes = new byte[BYTES_LEN_INT_MAX];
Arrays.fill(extendedBytes, (byte) 0);
System.arraycopy(bytesToNumber, 0, extendedBytes, 0, bytesToNumber.length);
bytesToNumber = extendedBytes;
var bb = ByteBuffer.allocate(BYTES_LEN_INT_MAX);
if (!bigEndian) {
bb.order(ByteOrder.LITTLE_ENDIAN);
}
float floatValue = ByteBuffer.wrap(bytesToNumber).getFloat();
if (!Float.isNaN(floatValue)) {
return floatValue;
} else {
long longValue = parseBytesToLong(bytesToNumber, 0, BYTES_LEN_INT_MAX);
BigDecimal bigDecimalValue = new BigDecimal(longValue);
return bigDecimalValue.floatValue();
bb.position(bigEndian ? BYTES_LEN_INT_MAX - length : 0);
bb.put(data, offset, length);
bb.position(0);
float floatValue = bb.getFloat();
if (Float.isNaN(floatValue)) {
throw new NumberFormatException("byte[] 0x" + bytesToHex(data) + " is a Not-a-Number (NaN) value");
}
return floatValue;
}
public static float parseBytesIntToFloat(List data) {
return parseBytesIntToFloat(data, 0);
}
public static float parseBytesIntToFloat(List data, int offset) {
return parseBytesIntToFloat(data, offset, validateLength(data.size(), offset, BYTES_LEN_INT_MAX));
}
public static float parseBytesIntToFloat(List data, int offset, int length) {
return parseBytesIntToFloat(data, offset, length, true);
}
public static float parseBytesIntToFloat(List data, int offset, int length, boolean bigEndian) {
return parseBytesIntToFloat(Bytes.toArray(data), offset, length, bigEndian);
}
public static float parseBytesIntToFloat(byte[] data) {
return parseBytesIntToFloat(data, 0);
}
public static float parseBytesIntToFloat(byte[] data, int offset) {
return parseBytesIntToFloat(data, offset, validateLength(data.length, offset, BYTES_LEN_INT_MAX));
}
public static float parseBytesIntToFloat(byte[] data, int offset, int length) {
return parseBytesIntToFloat(data, offset, length, true);
}
public static float parseBytesIntToFloat(byte[] data, int offset, int length, boolean bigEndian) {
byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian, BYTES_LEN_INT_MAX);
long longValue = parseBytesToLong(bytesToNumber, 0, length);
BigDecimal bigDecimalValue = new BigDecimal(longValue);
return bigDecimalValue.floatValue();
}
public static double parseBytesToDouble(List data) {
return parseBytesToDouble(Bytes.toArray(data));
return parseBytesToDouble(data, 0);
}
public static double parseBytesToDouble(List data, int offset) {
return parseBytesToDouble(Bytes.toArray(data), offset);
return parseBytesToDouble(data, offset, validateLength(data.size(), offset, BYTES_LEN_LONG_MAX));
}
public static double parseBytesToDouble(List data, int offset, int length) {
return parseBytesToDouble(Bytes.toArray(data), offset, length);
return parseBytesToDouble(data, offset, length, true);
}
public static double parseBytesToDouble(List data, int offset, int length, boolean bigEndian) {
@ -938,7 +983,7 @@ public class TbUtils {
}
public static double parseBytesToDouble(byte[] data, int offset) {
return parseBytesToDouble(data, offset, BYTES_LEN_LONG_MAX);
return parseBytesToDouble(data, offset, validateLength(data.length, offset, BYTES_LEN_LONG_MAX));
}
public static double parseBytesToDouble(byte[] data, int offset, int length) {
@ -946,36 +991,58 @@ public class TbUtils {
}
public static double parseBytesToDouble(byte[] data, int offset, int length, boolean bigEndian) {
if (length > BYTES_LEN_LONG_MAX) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum " + BYTES_LEN_LONG_MAX + " 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 + "!");
}
byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian);
if (bytesToNumber.length < BYTES_LEN_LONG_MAX) {
byte[] extendedBytes = new byte[BYTES_LEN_LONG_MAX];
Arrays.fill(extendedBytes, (byte) 0);
System.arraycopy(bytesToNumber, 0, extendedBytes, 0, bytesToNumber.length);
bytesToNumber = extendedBytes;
var bb = ByteBuffer.allocate(BYTES_LEN_LONG_MAX);
if (!bigEndian) {
bb.order(ByteOrder.LITTLE_ENDIAN);
}
double doubleValue = ByteBuffer.wrap(bytesToNumber).getDouble();
if (!Double.isNaN(doubleValue)) {
return doubleValue;
} else {
BigInteger bigInt = new BigInteger(1, bytesToNumber);
BigDecimal bigDecimalValue = new BigDecimal(bigInt);
return bigDecimalValue.doubleValue();
bb.position(bigEndian ? BYTES_LEN_LONG_MAX - length : 0);
bb.put(data, offset, length);
bb.position(0);
double doubleValue = bb.getDouble();
if (Double.isNaN(doubleValue)) {
throw new NumberFormatException("byte[] 0x" + bytesToHex(data) + " is a Not-a-Number (NaN) value");
}
return doubleValue;
}
private static byte[] prepareBytesToNumber(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 ((offset + length) > data.length) {
throw new IllegalArgumentException("Default length is always " + length + " bytes. Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!");
}
public static double parseBytesLongToDouble(List data) {
return parseBytesLongToDouble(data, 0);
}
public static double parseBytesLongToDouble(List data, int offset) {
return parseBytesLongToDouble(data, offset, validateLength(data.size(), offset, BYTES_LEN_LONG_MAX));
}
public static double parseBytesLongToDouble(List data, int offset, int length) {
return parseBytesLongToDouble(data, offset, length, true);
}
public static double parseBytesLongToDouble(List data, int offset, int length, boolean bigEndian) {
return parseBytesLongToDouble(Bytes.toArray(data), offset, length, bigEndian);
}
public static double parseBytesLongToDouble(byte[] data) {
return parseBytesLongToDouble(data, 0);
}
public static double parseBytesLongToDouble(byte[] data, int offset) {
return parseBytesLongToDouble(data, offset, validateLength(data.length, offset, BYTES_LEN_LONG_MAX));
}
public static double parseBytesLongToDouble(byte[] data, int offset, int length) {
return parseBytesLongToDouble(data, offset, length, true);
}
public static double parseBytesLongToDouble(byte[] data, int offset, int length, boolean bigEndian) {
byte[] bytesToNumber = prepareBytesToNumber(data, offset, length, bigEndian, BYTES_LEN_LONG_MAX);
BigInteger bigInt = new BigInteger(1, bytesToNumber);
BigDecimal bigDecimalValue = new BigDecimal(bigInt);
return bigDecimalValue.doubleValue();
}
private static byte[] prepareBytesToNumber(byte[] data, int offset, int length, boolean bigEndian,
int bytesLenMax) {
validationNumberByLength(data, offset, length, bytesLenMax);
byte[] dataBytesArray = Arrays.copyOfRange(data, offset, (offset + length));
if (!bigEndian) {
ArrayUtils.reverse(dataBytesArray);
@ -1168,6 +1235,15 @@ public class TbUtils {
return str.matches("^-?(0[xX])?[0-9a-fA-F]+$") ? HEX_RADIX : -1;
}
public static List byteArrayToExecutionArrayList(ExecutionContext ctx, byte[] byteArray) {
List<Byte> byteList = new ArrayList<>();
for (byte b : byteArray) {
byteList.add(b);
}
List list = new ExecutionArrayList(byteList, ctx);
return list;
}
private static byte isValidIntegerToByte(Integer val) {
if (val > 255 || val < -128) {
throw new NumberFormatException("The value '" + val + "' could not be correctly converted to a byte. " +
@ -1194,5 +1270,23 @@ public class TbUtils {
String result = reversedHex.toString();
return isHexPref ? "0x" + result : result;
}
private static void validationNumberByLength(byte[] data, int offset, int length, int bytesLenMax) {
if (offset > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " is out of bounds for array with length: " + data.length + "!");
}
if (offset + length > data.length) {
throw new IllegalArgumentException("Offset: " + offset + " and Length: " + length + " is out of bounds for array with length: " + data.length + "!");
}
if (length > bytesLenMax) {
throw new IllegalArgumentException("Length: " + length + " is too large. Maximum " + bytesLenMax + " bytes is allowed!");
}
}
private static int validateLength(int dataLength, int offset, int bytesLenMax) {
return (dataLength < offset) ? dataLength : Math.min((dataLength - offset), bytesLenMax);
}
}

190
common/script/script-api/src/test/java/org/thingsboard/script/api/tbel/TbUtilsTest.java

@ -276,7 +276,10 @@ public class TbUtilsTest {
@Test
public void parseBytesToFloat() {
byte[] floatValByte = {65, -22, 98, -52};
byte[] floatValByte = {0x0A};
Assertions.assertEquals(0, Float.compare(1.4E-44f, TbUtils.parseBytesToFloat(floatValByte)));
floatValByte = new byte[]{65, -22, 98, -52};
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValByte, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValByte, 0, 4, false)));
@ -284,40 +287,101 @@ public class TbUtilsTest {
Assertions.assertEquals(0, Float.compare(floatVal, TbUtils.parseBytesToFloat(floatValList, 0)));
Assertions.assertEquals(0, Float.compare(floatValRev, TbUtils.parseBytesToFloat(floatValList, 0, 4, false)));
// 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF}
floatValByte = new byte[]{-1, -1, -1, -1};
float floatExpectedBe = 4294.9673f;
float floatExpectedLe = 4.2949673E9f;
// 1.1803216E8f == 0x4CE120E4
floatValByte = new byte[]{0x4C, (byte) 0xE1, (byte) 0x20, (byte) 0xE4};
float floatExpectedBe = 118.03216f;
float actualBe = TbUtils.parseBytesToFloat(floatValByte, 0, 4, true);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValByte, 0, 4, false)));
floatValList = Bytes.asList(floatValByte);
actualBe = TbUtils.parseBytesToFloat(floatValList, 0);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValList, 0, 4, false)));
// 2 143 289 344L == {0x7F, 0xC0, 0x00, 0x00}
floatValByte = new byte[]{0x7F, (byte) 0xC0, (byte) 0xFF, 0x00};
floatExpectedBe = 2143.3547f;
floatExpectedLe = -3.984375f;
actualBe = TbUtils.parseBytesToFloat(floatValByte, 0, 4, true);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
float floatExpectedLe = 8.0821E-41f;
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValByte, 0, 2, false)));
floatExpectedBe = 2.7579E-41f;
Assertions.assertEquals(0, Float.compare(floatExpectedBe, TbUtils.parseBytesToFloat(floatValByte, 0, 2)));
floatValList = Bytes.asList(floatValByte);
floatExpectedLe = 4.2908055E9f;
actualBe = TbUtils.parseBytesToFloat(floatValList, 0);
Assertions.assertEquals(0, Float.compare(floatExpectedBe, actualBe / 1000000));
floatExpectedLe = 3.019557E-39f;
Assertions.assertEquals(0, Float.compare(floatExpectedLe, TbUtils.parseBytesToFloat(floatValList, 0, 3, false)));
// 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF}
floatValByte = new byte[]{-1, -1, -1, -1};
String message = "is a Not-a-Number (NaN) value";
try {
TbUtils.parseBytesToFloat(floatValByte, 0, 4, true);
Assertions.fail("Should throw NumberFormatException");
} catch (RuntimeException e) {
Assertions.assertTrue(e.getMessage().contains(message));
}
// "01752B0367FA000500010488 FFFFFFFF FFFFFFFF 33";
String intToHexBe = "01752B0367FA000500010488FFFFFFFFFFFFFFFF33";
floatExpectedLe = 4294.9673f;
floatValList = TbUtils.hexToBytes(ctx, intToHexBe);
float actualLe = TbUtils.parseBytesToFloat(floatValList, 12, 4, false);
Assertions.assertEquals(0, Float.compare(floatExpectedLe, actualLe / 1000000));
actualLe = TbUtils.parseBytesToFloat(floatValList, 12 + 4, 4, false);
Assertions.assertEquals(0, Float.compare(floatExpectedLe, actualLe / 1000000));
try {
TbUtils.parseBytesToFloat(floatValList, 12, 4, false);
Assertions.fail("Should throw NumberFormatException");
} catch (RuntimeException e) {
Assertions.assertTrue(e.getMessage().contains(message));
}
}
@Test
public void parseBytesIntToFloat() {
byte[] intValByte = {0x00, 0x00, 0x00, 0x0A};
Float valueExpected = 10.0f;
Float valueActual = TbUtils.parseBytesIntToFloat(intValByte, 3, 1, true);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseBytesIntToFloat(intValByte, 3, 1, false);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseBytesIntToFloat(intValByte, 2, 2, true);
Assertions.assertEquals(valueExpected, valueActual);
valueExpected = 2560.0f;
valueActual = TbUtils.parseBytesIntToFloat(intValByte, 2, 2, false);
Assertions.assertEquals(valueExpected, valueActual);
valueExpected = 10.0f;
valueActual = TbUtils.parseBytesIntToFloat(intValByte, 0, 4, true);
Assertions.assertEquals(valueExpected, valueActual);
valueExpected = 1.6777216E8f;
valueActual = TbUtils.parseBytesIntToFloat(intValByte, 0, 4, false);
Assertions.assertEquals(valueExpected, valueActual);
String dataAT101 = "0x01756403671B01048836BF7701F000090722050000";
List<Byte> byteAT101 = TbUtils.hexToBytes(ctx, dataAT101);
float latitudeExpected = 24.62495f;
int offset = 9;
valueActual = TbUtils.parseBytesIntToFloat(byteAT101, offset, 4, false);
Assertions.assertEquals(latitudeExpected, valueActual / 1000000);
float longitudeExpected = 118.030576f;
valueActual = TbUtils.parseBytesIntToFloat(byteAT101, offset + 4, 4, false);
Assertions.assertEquals(longitudeExpected, valueActual / 1000000);
valueExpected = 9.185175E8f;
valueActual = TbUtils.parseBytesIntToFloat(byteAT101, offset);
Assertions.assertEquals(valueExpected, valueActual);
// 0x36BF
valueExpected = 14015.0f;
valueActual = TbUtils.parseBytesIntToFloat(byteAT101, offset, 2);
Assertions.assertEquals(valueExpected, valueActual);
// 0xBF36
valueExpected = 48950.0f;
valueActual = TbUtils.parseBytesIntToFloat(byteAT101, offset, 2, false);
Assertions.assertEquals(valueExpected, valueActual);
valueExpected = 0.0f;
valueActual = TbUtils.parseBytesIntToFloat(byteAT101, byteAT101.size());
Assertions.assertEquals(valueExpected, valueActual);
try {
TbUtils.parseBytesIntToFloat(byteAT101, byteAT101.size() + 1);
Assertions.fail("Should throw NumberFormatException");
} catch (RuntimeException e) {
Assertions.assertTrue(e.getMessage().contains("is out of bounds for array with length:"));
}
}
@Test
@ -390,7 +454,10 @@ public class TbUtilsTest {
@Test
public void parseBytesToDouble() {
byte[] doubleValByte = {64, -101, 4, -79, 12, -78, -107, -22};
byte[] doubleValByte = {0x0A};
Assertions.assertEquals(0, Double.compare(4.9E-323, TbUtils.parseBytesToDouble(doubleValByte)));
doubleValByte = new byte[]{64, -101, 4, -79, 12, -78, -107, -22};
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValByte, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValByte, 0, 8, false)));
@ -398,34 +465,61 @@ public class TbUtilsTest {
Assertions.assertEquals(0, Double.compare(doubleVal, TbUtils.parseBytesToDouble(doubleValList, 0)));
Assertions.assertEquals(0, Double.compare(doubleValRev, TbUtils.parseBytesToDouble(doubleValList, 0, 8, false)));
// 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
doubleValByte = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1};
double doubleExpectedBe = 18446.744073709553d;
double doubleExpectedLe = 1.8446744073709552E19d;
double actualBe = TbUtils.parseBytesToDouble(doubleValByte, 0, 8, true);
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe / 1000000000000000L));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValByte, 0, 8, false)));
doubleValList = Bytes.asList(doubleValByte);
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, TbUtils.parseBytesToDouble(doubleValList, 0) / 1000000000000000L));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValList, 0, 8, false)));
doubleValByte = new byte[]{0x7F, (byte) 0xC0, (byte) 0xFF, 0x00, 0x7F, (byte) 0xC0, (byte) 0xFF, 0x00};
doubleExpectedBe = 2387013.651780523d;
doubleExpectedLe = 7.234601680440024E-304d;
actualBe = TbUtils.parseBytesToDouble(doubleValByte, 0, 8, true);
double doubleExpectedBe = 2387013.651780523d;
double doubleExpectedLe = 7.234601680440024E-304d;
double actualBe = TbUtils.parseBytesToDouble(doubleValByte, 0, 8, true);
BigDecimal bigDecimal = new BigDecimal(actualBe);
// We move the decimal point to the left by 301 positions
actualBe = bigDecimal.movePointLeft(301).doubleValue();
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValByte, 0, 8, false)));
doubleValList = Bytes.asList(doubleValByte);
doubleExpectedLe = 5.828674572203954E303d;
actualBe = TbUtils.parseBytesToDouble(doubleValList, 0);
bigDecimal = new BigDecimal(actualBe);
actualBe = bigDecimal.movePointLeft(301).doubleValue();
Assertions.assertEquals(0, Double.compare(doubleExpectedBe, actualBe));
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, TbUtils.parseBytesToDouble(doubleValList, 0, 5, false)));
doubleExpectedLe = 26950.174646662283d;
double actualLe = TbUtils.parseBytesToDouble(doubleValList, 0, 5, false);
bigDecimal = new BigDecimal(actualLe);
actualLe = bigDecimal.movePointRight(316).doubleValue();
Assertions.assertEquals(0, Double.compare(doubleExpectedLe, actualLe));
// 4 294 967 295L == {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
doubleValByte = new byte[]{-1, -1, -1, -1, -1, -1, -1, -1};
String message = "is a Not-a-Number (NaN) value";
try {
TbUtils.parseBytesToDouble(doubleValByte, 0, 8, true);
Assertions.fail("Should throw NumberFormatException");
} catch (RuntimeException e) {
Assertions.assertTrue(e.getMessage().contains(message));
}
}
@Test
public void parseBytesLongToDouble() {
byte[] longValByte = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A};
Double valueExpected = 10.0d;
Double valueActual = TbUtils.parseBytesLongToDouble(longValByte);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseBytesLongToDouble(longValByte, 7, 1, true);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseBytesLongToDouble(longValByte, 7, 1, false);
Assertions.assertEquals(valueExpected, valueActual);
valueActual = TbUtils.parseBytesLongToDouble(longValByte, 6, 2, true);
Assertions.assertEquals(valueExpected, valueActual);
valueExpected = 2560.0d;
valueActual = TbUtils.parseBytesLongToDouble(longValByte, 6, 2, false);
Assertions.assertEquals(valueExpected, valueActual);
valueExpected = 10.0d;
valueActual = TbUtils.parseBytesLongToDouble(longValByte, 0, 8, true);
Assertions.assertEquals(valueExpected, valueActual);
valueExpected = 7.2057594037927936E17d;
valueActual = TbUtils.parseBytesLongToDouble(longValByte, 0, 8, false);
Assertions.assertEquals(valueExpected, valueActual);
}
@Test
@ -717,6 +811,13 @@ public class TbUtilsTest {
Assertions.assertEquals(value, valueActual);
valueActual = TbUtils.parseHexToFloat(valueHexRev, false);
Assertions.assertEquals(value, valueActual);
String valueHex = "0x0000000A";
float expectedValue = 1.4E-44f;
valueActual = TbUtils.parseHexToFloat(valueHex);
Assertions.assertEquals(expectedValue, valueActual);
actual = TbUtils.floatToHex(expectedValue);
Assertions.assertEquals(valueHex, actual);
}
// If the length is not equal to 8 characters, we process it as an integer (eg "0x0A" for 10.0f).
@ -748,6 +849,13 @@ public class TbUtilsTest {
actual = TbUtils.doubleToHex(doubleVal, false);
String expectedHexRev = "0xEA95B20CB1049B40";
Assertions.assertEquals(expectedHexRev, actual);
String valueHex = "0x000000000000000A";
Double expectedValue = 4.9E-323;
valueActual = TbUtils.parseHexToDouble(valueHex);
Assertions.assertEquals(expectedValue, valueActual);
actual = TbUtils.doubleToHex(expectedValue);
Assertions.assertEquals(valueHex, actual);
}
@Test

Loading…
Cancel
Save