2 * Copyright (c) 2010-2020 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.io.transport.modbus.test;
15 import static org.junit.jupiter.api.Assertions.*;
17 import java.nio.charset.Charset;
18 import java.nio.charset.StandardCharsets;
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.stream.Collectors;
22 import java.util.stream.Stream;
23 import java.util.stream.Stream.Builder;
25 import org.junit.jupiter.params.ParameterizedTest;
26 import org.junit.jupiter.params.provider.MethodSource;
27 import org.openhab.io.transport.modbus.ModbusBitUtilities;
28 import org.openhab.io.transport.modbus.ModbusRegisterArray;
31 * @author Sami Salonen - Initial contribution
33 public class BitUtilitiesExtractStringTest {
35 private static ModbusRegisterArray shortArrayToRegisterArray(int... arr) {
36 return new ModbusRegisterArray(arr);
39 public static Collection<Object[]> data() {
40 return Collections.unmodifiableList(Stream.of(
41 new Object[] { "", shortArrayToRegisterArray(0), 0, 0, StandardCharsets.UTF_8 },
42 new Object[] { "hello", shortArrayToRegisterArray(0x6865, 0x6c6c, 0x6f00), 0, 5,
43 StandardCharsets.UTF_8 },
44 new Object[] { "he", shortArrayToRegisterArray(0x6865, 0x6c6c, 0x6f00), 0, 2, StandardCharsets.UTF_8 }, // limited
47 new Object[] { "hello ", shortArrayToRegisterArray(0, 0, 0x6865, 0x6c6c, 0x6f20, 0, 0), 2, 6,
48 StandardCharsets.UTF_8 },
49 new Object[] { "hello", shortArrayToRegisterArray(0x6865, 0x6c6c, 0x6f00, 0x0000, 0x0000), 0, 10,
50 StandardCharsets.UTF_8 },
51 new Object[] { "árvíztűrő tükörfúrógép",
52 shortArrayToRegisterArray(0xc3a1, 0x7276, 0xc3ad, 0x7a74, 0xc5b1, 0x72c5, 0x9120, 0x74c3,
53 0xbc6b, 0xc3b6, 0x7266, 0xc3ba, 0x72c3, 0xb367, 0xc3a9, 0x7000),
54 0, 32, StandardCharsets.UTF_8 },
55 new Object[] { "你好,世界",
56 shortArrayToRegisterArray(0xe4bd, 0xa0e5, 0xa5bd, 0xefbc, 0x8ce4, 0xb896, 0xe795, 0x8c00), 0,
57 16, StandardCharsets.UTF_8 },
58 new Object[] { "árvíztűrő tükörfúrógép",
59 shortArrayToRegisterArray(0xe172, 0x76ed, 0x7a74, 0xfb72, 0xf520, 0x74fc, 0x6bf6, 0x7266,
60 0xfa72, 0xf367, 0xe970),
61 0, 22, Charset.forName("ISO-8859-2") },
62 // Example where registers contain 0 byte in between -- only the data preceding zero byte is parsed
63 new Object[] { "hello", shortArrayToRegisterArray(0x6865, 0x6c6c, 0x6f00, 0x776f, 0x726c, 0x64), 0, 10,
64 StandardCharsets.UTF_8 },
67 // 0xe4 = "ä" in extended ascii but not covered by US_ASCII. Will be replaced by �
68 new Object[] { "�", shortArrayToRegisterArray(0xe400), 0, 2, StandardCharsets.US_ASCII },
70 new Object[] { IllegalArgumentException.class, shortArrayToRegisterArray(0, 0), 2, 4,
71 StandardCharsets.UTF_8 },
73 new Object[] { IllegalArgumentException.class, shortArrayToRegisterArray(0, 0), 0, -1,
74 StandardCharsets.UTF_8 },
76 new Object[] { IllegalArgumentException.class, shortArrayToRegisterArray(0, 0), 0, 5,
77 StandardCharsets.UTF_8 })
78 .collect(Collectors.toList()));
81 public static Stream<Object[]> dataWithByteVariations() {
82 return data().stream().flatMap(vals -> {
83 Object expected = vals[0];
84 ModbusRegisterArray registers = (ModbusRegisterArray) vals[1];
85 int index = (int) vals[2];
86 int length = (int) vals[3];
87 Charset charset = (Charset) vals[4];
89 byte[] origBytes = registers.getBytes();
90 int origRegisterIndex = index;
91 int origByteIndex = origRegisterIndex * 2;
93 Builder<Object[]> streamBuilder = Stream.builder();
94 for (int offset = 0; offset < 5; offset++) {
95 byte[] bytesOffsetted = new byte[origBytes.length + offset];
96 System.arraycopy(origBytes, 0, bytesOffsetted, offset, origBytes.length);
98 new Object[] { expected, offset, bytesOffsetted, origByteIndex + offset, length, charset });
100 Stream<Object[]> variations = streamBuilder.build();
105 @SuppressWarnings({ "unchecked", "rawtypes" })
107 @MethodSource("data")
108 public void testExtractStringFromRegisters(Object expectedResult, ModbusRegisterArray registers, int index,
109 int length, Charset charset) {
110 if (expectedResult instanceof Class && Exception.class.isAssignableFrom((Class) expectedResult)) {
111 assertThrows((Class) expectedResult,
112 () -> ModbusBitUtilities.extractStringFromRegisters(registers, index, length, charset));
115 String actualState = ModbusBitUtilities.extractStringFromRegisters(registers, index, length, charset);
116 assertEquals(actualState, expectedResult,
117 String.format("registers=%s, index=%d, length=%d", registers, index, length));
121 @SuppressWarnings({ "unchecked", "rawtypes" })
123 @MethodSource("dataWithByteVariations")
124 public void testExtractStringFromBytes(Object expectedResult, int byteOffset, byte[] bytes, int byteIndex,
125 int length, Charset charset) {
126 if (expectedResult instanceof Class && Exception.class.isAssignableFrom((Class) expectedResult)) {
127 assertThrows((Class) expectedResult,
128 () -> ModbusBitUtilities.extractStringFromBytes(bytes, byteIndex, length, charset));
131 String actualState = ModbusBitUtilities.extractStringFromBytes(bytes, byteIndex, length, charset);
132 assertEquals(actualState, expectedResult, String.format("registers=%s, index=%d, length=%d, byteIndex=%d",
133 bytes, byteIndex, length, byteIndex));