View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.codec.digest;
19  
20  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertNotSame;
23  
24  import java.nio.charset.StandardCharsets;
25  import java.nio.file.Paths;
26  import java.util.function.Supplier;
27  import java.util.zip.Checksum;
28  
29  import org.apache.commons.codec.binary.StringUtils;
30  import org.apache.commons.io.file.PathUtils;
31  import org.apache.commons.io.function.Uncheck;
32  import org.junit.jupiter.api.Test;
33  import org.junit.jupiter.params.ParameterizedTest;
34  import org.junit.jupiter.params.provider.MethodSource;
35  
36  /**
37   * Tests {@link Crc16}.
38   */
39  class Crc16Test {
40  
41      private static final String BIG_TEXT = Uncheck.get(() -> PathUtils.readString(Paths.get("LICENSE.txt"), StandardCharsets.US_ASCII));
42      private static final byte[] TEST_BYTES = "123456789".getBytes(StandardCharsets.US_ASCII);
43      private static final int TEST_BYTES_LEN = TEST_BYTES.length;
44  
45      static Object[][] testArcDefault() {
46          // @formatter:off
47          return new Object[][] {
48              { "", 0x0000 },
49              { "1", 0xD4C1 },
50              { "12", 0x4594 },
51              { "123", 0xBA04 },
52              { "1234", 0x14BA },
53              { "12345", 0xA455 },
54              { "123456", 0x29E4 },
55              { "1234567", 0x9D68 },
56              { "12345678", 0x3C9D },
57              { "123456789", 0xBB3D },
58              { BIG_TEXT, 0xD01C }
59          };
60          // @formatter:on
61      }
62  
63      static Object[][] testCcittDefault() {
64          // @formatter:off
65          return new Object[][] {
66              { "", 0x0000 },
67              { "1", 0x200A },
68              { "12", 0xBDEB },
69              { "123", 0x5A78 },
70              { "1234", 0x8832 },
71              { "12345", 0x7437 },
72              { "123456", 0x11FD },
73              { "1234567", 0x6947 },
74              { "12345678", 0x8B19 },
75              { "123456789", 0x2189 },
76              { BIG_TEXT, 0xA912 }
77          };
78          // @formatter:on
79      }
80  
81      static Object[][] testDnpDefault() {
82          // @formatter:off
83          return new Object[][] {
84              { "", 0xFFFF },
85              { "1", 0x5265 },
86              { "12", 0x8FC8 },
87              { "123", 0x26F7 },
88              { "1234", 0x4213 },
89              { "12345", 0x711C },
90              { "123456", 0x57DE },
91              { "1234567", 0xF8F8 },
92              { "12345678", 0x182F },
93              { "123456789", 0xEA82 },
94              { BIG_TEXT, 0x7E33 }
95          };
96          // @formatter:on
97      }
98  
99      @SuppressWarnings("unchecked")
100     static Supplier<int[]>[] testGetTables() {
101         // @formatter:off
102         return new Supplier[] {
103             Crc16::getArcTable,
104             Crc16::getCcittTable,
105             Crc16::getDnpTable,
106             Crc16::getMcrf4xxTable,
107             Crc16::getMaximTable,
108             Crc16::getModbusTable,
109             Crc16::getNrsc5Table
110         };
111         // @formatter:on
112     }
113 
114     static Object[][] testIbmSdlcDefault() {
115         // @formatter:off
116         return new Object[][] {
117             { "", 0x0000 },
118             { "1", 0xD072 },
119             { "12", 0xB2AC },
120             { "123", 0x9CB4 },
121             { "1234", 0x74EC },
122             { "12345", 0xBB40 },
123             { "123456", 0xE672 },
124             { "1234567", 0xE537 },
125             { "12345678", 0x086A },
126             { "123456789", 0x906E },
127             { BIG_TEXT, 0x6C3F }
128         };
129         // @formatter:on
130     }
131 
132     static Object[][] testMaximDefault() {
133         // @formatter:off
134         return new Object[][] {
135             { "", 0xFFFF },
136             { "1", 0x2B3E },
137             { "12", 0xBA6B },
138             { "123", 0x45FB },
139             { "1234", 0xEB45 },
140             { "12345", 0x5BAA },
141             { "123456", 0xD61B },
142             { "1234567", 0x6297 },
143             { "12345678", 0xC362 },
144             { "123456789", 0x44C2 },
145             { BIG_TEXT, 0x2FE3 }
146         };
147         // @formatter:on
148     }
149 
150     static Object[][] testMcrf4xxDefault() {
151         // @formatter:off
152         return new Object[][] {
153             { "", 0xFFFF },
154             { "1", 0x2F8D },
155             { "12", 0x4D53 },
156             { "123", 0x634B },
157             { "1234", 0x8B13 },
158             { "12345", 0x44BF },
159             { "123456", 0x198D },
160             { "1234567", 0x1AC8 },
161             { "12345678", 0xF795 },
162             { "123456789", 0x6F91 },
163             { BIG_TEXT, 0x93C0 }
164         };
165         // @formatter:on
166     }
167 
168     static Object[][] testModbusDefault() {
169         // @formatter:off
170         return new Object[][] {
171             { "", 0xFFFF },
172             { "1", 0x947E },
173             { "12", 0xF595 },
174             { "123", 0x7A75 },
175             { "1234", 0x30BA },
176             { "12345", 0xA471 },
177             { "123456", 0x32E4 },
178             { "1234567", 0x9D73 },
179             { "12345678", 0x37DD },
180             { "123456789", 0x4B37 },
181             { BIG_TEXT, 0xEC67 }
182         };
183         // @formatter:on
184     }
185 
186     static Object[][] testNrsc5Default() {
187         // @formatter:off
188         return new Object[][] {
189             { "", 0xFFFF },
190             { "1", 0x083E },
191             { "12", 0xDB99 },
192             { "123", 0x8286 },
193             { "1234", 0x95DC },
194             { "12345", 0xB42C },
195             { "123456", 0x7CFF },
196             { "1234567", 0xB565 },
197             { "12345678", 0x9C8A },
198             { "123456789", 0xA066 },
199             { BIG_TEXT, 0x2A84 }
200         };
201         // @formatter:on
202     }
203 
204     static Object[][] testUsbDefault() {
205         // @formatter:off
206         return new Object[][] {
207             { "", 0x0000 },
208             { "1", 0x6B81 },
209             { "12", 0x0A6A },
210             { "123", 0x858A },
211             { "1234", 0xCF45 },
212             { "12345", 0x5B8E },
213             { "123456", 0xCD1B },
214             { "1234567", 0x628C },
215             { "12345678", 0xC822 },
216             { "123456789", 0xB4C8 },
217             { BIG_TEXT, 0x1398 }
218         };
219         // @formatter:on
220     }
221 
222     private Supplier<String> messageSupplier(final Checksum crc16, final long expected) {
223         return () -> String.format("Expected %04X but was %s", expected, crc16);
224     }
225 
226     void stdUpdate(final Checksum crc16) {
227         crc16.update(TEST_BYTES, 0, TEST_BYTES_LEN);
228     }
229 
230     @ParameterizedTest
231     @MethodSource
232     void testArcDefault(final String source, final long expected) {
233         testUpdateReset(source, expected, Crc16.arc());
234     }
235 
236     @ParameterizedTest
237     @MethodSource
238     void testCcittDefault(final String source, final long expected) {
239         testUpdateReset(source, expected, Crc16.ccitt());
240     }
241 
242     @ParameterizedTest
243     @MethodSource
244     void testDnpDefault(final String source, final long expected) {
245         testUpdateReset(source, expected, Crc16.dnp());
246     }
247 
248     @ParameterizedTest
249     @MethodSource
250     void testGetTables(final Supplier<int[]> supplier) {
251         final int[] value1 = supplier.get();
252         final int[] value2 = supplier.get();
253         assertNotSame(value1, value2);
254         assertArrayEquals(value1, value2);
255     }
256 
257     @ParameterizedTest
258     @MethodSource
259     void testIbmSdlcDefault(final String source, final long expected) {
260         testUpdateReset(source, expected, Crc16.ibmSdlc());
261     }
262 
263     @Test
264     void testInit() {
265         final Checksum crc16 = Crc16.builder().setTable(Crc16.getModbusTable()).setInit(0xFFFF).get();
266         stdUpdate(crc16);
267         assertEquals(0x4B37, crc16.getValue());
268         stdUpdate(crc16);
269         assertEquals(0x090A, crc16.getValue());
270         crc16.reset();
271         stdUpdate(crc16);
272         assertEquals(0x4B37, crc16.getValue());
273     }
274 
275     @ParameterizedTest
276     @MethodSource
277     void testMaximDefault(final String source, final long expected) {
278         testUpdateReset(source, expected, Crc16.maxim());
279     }
280 
281     @ParameterizedTest
282     @MethodSource
283     void testMcrf4xxDefault(final String source, final long expected) {
284         testUpdateReset(source, expected, Crc16.mcrf4xx());
285     }
286 
287     @Test
288     void testModbusCustom() {
289         final Checksum crc16 = Crc16.builder().setTable(Crc16.getModbusTable()).setInit(0xFFFF).get();
290         stdUpdate(crc16);
291         assertEquals(0x4B37, crc16.getValue());
292         stdUpdate(crc16);
293         assertEquals(0x090A, crc16.getValue());
294         crc16.reset();
295         stdUpdate(crc16);
296         assertEquals(0x4B37, crc16.getValue());
297     }
298 
299     @ParameterizedTest
300     @MethodSource
301     void testModbusDefault(final String source, final long expected) {
302         testUpdateReset(source, expected, Crc16.modbus());
303     }
304 
305     @ParameterizedTest
306     @MethodSource
307     void testNrsc5Default(final String source, final long expected) {
308         testUpdateReset(source, expected, Crc16.nrsc5());
309     }
310 
311     @Test
312     void testReset() {
313         final Checksum crc16 = Crc16.modbus();
314         stdUpdate(crc16);
315         assertEquals(0x4B37, crc16.getValue());
316         stdUpdate(crc16);
317         assertEquals(0x090A, crc16.getValue());
318         crc16.reset();
319         stdUpdate(crc16);
320         assertEquals(0x4B37, crc16.getValue());
321     }
322 
323     @Test
324     void testResetCustomModbus() {
325         final Checksum crc16 = Crc16.builder().setTable(Crc16.getModbusTable()).setInit(0x0000).get();
326         stdUpdate(crc16);
327         assertEquals(0xBB3D, crc16.getValue());
328         stdUpdate(crc16);
329         assertEquals(0xED7B, crc16.getValue());
330         crc16.reset();
331         stdUpdate(crc16);
332         assertEquals(0xbb3d, crc16.getValue());
333     }
334 
335     @Test
336     void testUpdateArray() {
337         final Checksum crc16 = Crc16.builder().setTable(Crc16.getModbusTable()).setInit(0x0000).get();
338         stdUpdate(crc16);
339         assertEquals(0xBB3D, crc16.getValue());
340     }
341 
342     @Test
343     void testUpdateInt() {
344         final Checksum crc16 = Crc16.builder().setTable(Crc16.getModbusTable()).setInit(0x0000).get();
345         final byte[] bytes = TEST_BYTES;
346         for (final byte element : bytes) {
347             crc16.update(element);
348         }
349         assertEquals(0xBB3D, crc16.getValue());
350     }
351 
352     void testUpdateReset(final String source, final long expected, final Checksum crc16) {
353         final byte[] bytes = StringUtils.getBytesUsAscii(source);
354         crc16.update(bytes, 0, bytes.length);
355         long actual = crc16.getValue();
356         assertEquals(expected, actual, messageSupplier(crc16, expected));
357         crc16.reset();
358         crc16.update(bytes, 0, bytes.length);
359         actual = crc16.getValue();
360         assertEquals(expected, actual, messageSupplier(crc16, expected));
361     }
362 
363     @ParameterizedTest
364     @MethodSource
365     void testUsbDefault(final String source, final long expected) {
366         testUpdateReset(source, expected, Crc16.usb());
367     }
368 
369 }