View Javadoc
1   package net.sourceforge.jarduino;
2   
3   import java.io.IOException;
4   import java.io.InputStream;
5   import java.nio.charset.StandardCharsets;
6   import java.util.Arrays;
7   import java.util.stream.Stream;
8   
9   import org.junit.jupiter.api.Assertions;
10  import org.junit.jupiter.api.DynamicContainer;
11  import org.junit.jupiter.api.DynamicNode;
12  import org.junit.jupiter.api.DynamicTest;
13  import org.junit.jupiter.api.TestFactory;
14  
15  import net.sourceforge.jarduino.message.ArduinoGenerator;
16  import net.sourceforge.jarduino.message.ArduinoLibrary;
17  import net.sourceforge.jarduino.message.ArduinoMessage;
18  import net.sourceforge.jarduino.message.ArduinoMsgFilter;
19  import net.sourceforge.jarduino.message.ArduinoParser;
20  import net.sourceforge.jarduino.message.ArduinoSystem;
21  import net.sourceforge.jarduino.util.ArduinoField;
22  
23  /**
24   * Arduino Test classes.
25   */
26  public class ArduinoTest {
27      /**
28       * Build test stream.
29       * @return the test stream
30       */
31      @TestFactory
32      public Stream<DynamicNode> buildTests() {
33          /* Create tests */
34          Stream<DynamicNode> myStream = Stream.empty();
35          myStream = Stream.concat(myStream, loadTest("Test1"));
36          myStream = Stream.concat(myStream, loadTest("Test2"));
37          myStream = Stream.concat(myStream, loadTest("Test3"));
38          return Stream.concat(myStream, parseTest());
39      }
40  
41      /**
42       * loadTest.
43       * @param pName the test name
44       * @return the test stream.
45       */
46      private Stream<DynamicNode> loadTest(final String pName) {
47          return Stream.of(DynamicTest.dynamicTest(pName, () -> testDBCFile(pName)));
48      }
49  
50      /**
51       * parseTest.
52       * @return the test stream.
53       */
54      private Stream<DynamicNode> parseTest() {
55          return Stream.of(DynamicContainer.dynamicContainer("fields", Stream.of(
56                  DynamicTest.dynamicTest("parse", () -> parseTest()),
57                  DynamicTest.dynamicTest("littleEndian", () -> checkLittleEndian()),
58                  DynamicTest.dynamicTest("bigEndian", () -> checkBigEndian())
59          )));
60      }
61  
62      /**
63       * Test DBC file.
64       * @param pName the test name
65       * @throws ArduinoException on error
66       */
67      private void testDBCFile(final String pName) throws ArduinoException {
68          /* Protect against exceptions */
69          try (InputStream myStream = ArduinoTest.class.getResourceAsStream(pName + ".dbc")) {
70              /* Parse the resource */
71              final ArduinoSystem mySystem = ArduinoParser.parseStream(pName, StandardCharsets.ISO_8859_1, myStream);
72  
73              /* Build the selection */
74              final ArduinoMsgFilter myFilter = new ArduinoMsgFilter();
75              myFilter.resetSelection(mySystem);
76  
77              /* Load library header */
78              ArduinoLibrary.loadLibraryHeader();
79  
80              /* Load library code */
81              ArduinoLibrary.loadLibraryCode();
82  
83              /* Load message headers */
84              ArduinoGenerator.formatHeader(mySystem, myFilter);
85  
86              /* Load message code */
87              ArduinoGenerator.formatBody(mySystem, myFilter);
88  
89              /* Loop through the messages */
90              for (ArduinoMessage myMessage : mySystem.getMessages()) {
91                  myMessage.toString();
92              }
93  
94              /* Handle exceptions */
95          } catch (IOException e) {
96              throw new ArduinoException("Failed to load file", e);
97          }
98      }
99  
100     /**
101      * Test parsing fields.
102      */
103     private void checkParseFields() {
104         /* Define the buffer */
105         final byte[] myBuff = { (byte) 0b11001000, (byte) 0b00110011, (byte) 0b11000011 };
106 
107         /* Run littleEndianTests */
108         long myValue = ArduinoField.parseLEField(myBuff, 5, 2, false);
109         Assertions.assertEquals(0b10, myValue, "Parse failure");
110         myValue = ArduinoField.parseLEField(myBuff, 0, 8, false);
111         Assertions.assertEquals(0b11001000, myValue, "Parse failure");
112         myValue = ArduinoField.parseLEField(myBuff, 6, 8, false);
113         Assertions.assertEquals(0b11001111, myValue, "Parse failure");
114         myValue = ArduinoField.parseLEField(myBuff, 0, 10, false);
115         Assertions.assertEquals(0b1111001000, myValue, "Parse failure");
116         myValue = ArduinoField.parseLEField(myBuff, 14, 10, false);
117         Assertions.assertEquals(0b1100001100, myValue, "Parse failure");
118         myValue = ArduinoField.parseLEField(myBuff, 6, 17, false);
119         Assertions.assertEquals(0b10000110011001111, myValue, "Parse failure");
120 
121         /* Run bigEndian tests */
122         myValue = ArduinoField.parseBEField(myBuff, 5, 3, false); /*  */
123         Assertions.assertEquals(0b001, myValue, "Parse failure");
124         myValue = ArduinoField.parseBEField(myBuff, 7, 8, false); /*  */
125         Assertions.assertEquals(0b11001000, myValue, "Parse failure");
126         myValue = ArduinoField.parseBEField(myBuff, 9, 8, false); /*  */
127         Assertions.assertEquals(0b11110000, myValue, "Parse failure");
128         myValue = ArduinoField.parseBEField(myBuff, 6, 12, false); /*  */
129         Assertions.assertEquals(0b100100000110, myValue, "Parse failure");
130         myValue = ArduinoField.parseBEField(myBuff, 6, 16, false); /*  */
131         Assertions.assertEquals(0b1001000001100111, myValue, "Parse failure");
132     }
133 
134     /**
135      * Test littleEndian fields.
136      */
137     private void checkLittleEndian() {
138         /* Check short value */
139         checkLittleEndian(0, 3);
140         checkLittleEndian(3, 3);
141         checkLittleEndian(1, 6);
142         checkLittleEndian(9, 3);
143 
144         /* Check full byte value */
145         checkLittleEndian(0, 8);
146         checkLittleEndian(8, 8);
147         checkLittleEndian(16, 8);
148 
149         /* Check full multi-byte value */
150         checkLittleEndian(0, 16);
151         checkLittleEndian(8, 16);
152         checkLittleEndian(16, 16);
153 
154         /* Check span byte-boundary value */
155         checkLittleEndian(5, 8);
156         checkLittleEndian(11, 7);
157         checkLittleEndian(18, 7);
158 
159         /* Check span multi-byte-boundary value */
160         checkLittleEndian(7, 18);
161 
162         /* Check long value */
163         checkLittleEndian(7, 38);
164         checkLittleEndian(0, 64);
165     }
166 
167     /**
168      * Test littleEndian fields.
169      * @param pStart the start bit
170      * @param pLength the length
171      */
172     private void checkLittleEndian(final int pStart,
173                                    final int pLength) {
174         /* Create a buffer */
175         final byte[] myBuff = new byte[Long.BYTES];
176 
177         /* Determine the range of values */
178         final long myMax = (1L << pLength) - 1;
179         final long myRange = Math.min(myMax, Short.MAX_VALUE);
180 
181         /* Loop through all values */
182         for (long i = 0; i <= myRange; i++) {
183             /* Check low unsigned values */
184             ArduinoField.setLEField(myBuff, pStart, pLength, i);
185             long myValue = ArduinoField.parseLEField(myBuff, pStart, pLength, false);
186             Assertions.assertEquals(i, myValue, "Parse failure");
187             Arrays.fill(myBuff, (byte) 0);
188 
189             /* Check low signed values */
190             long mySigned = i - (1L << pLength - 1);
191             ArduinoField.setLEField(myBuff, pStart, pLength, mySigned);
192             myValue = ArduinoField.parseLEField(myBuff, pStart, pLength, true);
193             Assertions.assertEquals(mySigned, myValue, "Parse failure");
194             Arrays.fill(myBuff, (byte) 0);
195 
196             /* If we have a large range */
197             if (myRange < myMax) {
198                 /* Check high unsigned values */
199                 long myTest = i + (myMax - myRange);
200                 ArduinoField.setLEField(myBuff, pStart, pLength, myTest);
201                 myValue = ArduinoField.parseLEField(myBuff, pStart, pLength, false);
202                 Assertions.assertEquals(myTest, myValue, "Parse failure");
203                 Arrays.fill(myBuff, (byte) 0);
204 
205                 /* Check high signed values */
206                 mySigned = myTest - (1L << pLength - 1);
207                 ArduinoField.setLEField(myBuff, pStart, pLength, mySigned);
208                 myValue = ArduinoField.parseLEField(myBuff, pStart, pLength, true);
209                 Assertions.assertEquals(mySigned, myValue, "Parse failure");
210                 Arrays.fill(myBuff, (byte) 0);
211             }
212         }
213     }
214 
215     /**
216      * Test bigEndian fields.
217      */
218     private void checkBigEndian() {
219         /* Check short value */
220         checkBigEndian(7, 3);
221         checkBigEndian(5, 3);
222         checkBigEndian(6, 6);
223         checkBigEndian(14, 3);
224 
225         /* Check full byte value */
226         checkBigEndian(7, 8);
227         checkBigEndian(15, 8);
228         checkBigEndian(23, 8);
229 
230         /* Check full multi-byte value */
231         checkBigEndian(7, 16);
232         checkBigEndian(15, 16);
233         checkBigEndian(23, 16);
234 
235         /* Check span byte-boundary value */
236         checkBigEndian(5, 8);
237         checkBigEndian(11, 7);
238         checkBigEndian(18, 7);
239 
240         /* Check span multi-byte-boundary value */
241         checkBigEndian(0, 18);
242 
243         /* Check long value */
244         checkBigEndian(1, 38);
245         checkBigEndian(7, 64);
246     }
247 
248     /**
249      * Test bigEndian fields.
250      * @param pStart the start bit
251      * @param pLength the length
252      */
253     private void checkBigEndian(final int pStart,
254                                 final int pLength) {
255         /* Create a buffer */
256         final byte[] myBuff = new byte[Long.BYTES];
257 
258         /* Determine the range of values */
259         final long myMax = (1L << pLength) - 1;
260         final long myRange = Math.min(myMax, Short.MAX_VALUE);
261 
262         /* Loop through all values */
263         for (long i = 0; i <= myRange; i++) {
264             /* Check low unsigned values */
265             ArduinoField.setBEField(myBuff, pStart, pLength, i);
266             long myValue = ArduinoField.parseBEField(myBuff, pStart, pLength, false);
267             Assertions.assertEquals(i, myValue, "Parse failure");
268             Arrays.fill(myBuff, (byte) 0);
269 
270             /* Check low signed values */
271             long mySigned = i - (1L << pLength - 1);
272             Arrays.fill(myBuff, (byte) -1);
273             ArduinoField.setBEField(myBuff, pStart, pLength, mySigned);
274             myValue = ArduinoField.parseBEField(myBuff, pStart, pLength, true);
275             Assertions.assertEquals(mySigned, myValue, "Parse failure");
276 
277             /* If we have a large range */
278             if (myRange < myMax) {
279                 /* Check high unsigned values */
280                 long myTest = i + (myMax - myRange);
281                 ArduinoField.setBEField(myBuff, pStart, pLength, myTest);
282                 myValue = ArduinoField.parseBEField(myBuff, pStart, pLength, false);
283                 Assertions.assertEquals(myTest, myValue, "Parse failure");
284                 Arrays.fill(myBuff, (byte) 0);
285 
286                 /* Check high signed values */
287                 mySigned = myTest - (1L << pLength - 1);
288                 ArduinoField.setLEField(myBuff, pStart, pLength, mySigned);
289                 myValue = ArduinoField.parseLEField(myBuff, pStart, pLength, true);
290                 Assertions.assertEquals(mySigned, myValue, "Parse failure");
291                 Arrays.fill(myBuff, (byte) 0);
292             }
293         }
294     }
295 }