1 /*
2  *  Copyright (c) 2017, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "common/code_utils.hpp"
30 #include "instance/instance.hpp"
31 #include "lib/spinel/spinel_decoder.hpp"
32 
33 #include "test_util.hpp"
34 
35 namespace ot {
36 namespace Spinel {
37 
38 enum
39 {
40     kTestBufferSize = 800,
41 };
42 
TestDecoder(void)43 void TestDecoder(void)
44 {
45     uint8_t         buffer[kTestBufferSize];
46     Spinel::Decoder decoder;
47 
48     spinel_ssize_t frameLen;
49 
50     const bool     kBool_1 = true;
51     const bool     kBool_2 = false;
52     const uint8_t  kUint8  = 0x42;
53     const int8_t   kInt8   = -73;
54     const uint16_t kUint16 = 0xabcd;
55     const int16_t  kInt16  = -567;
56     const uint32_t kUint32 = 0xdeadbeef;
57     const int32_t  kInt32  = -123455678L;
58     const uint64_t kUint64 = 0xfe10dc32ba549876ULL;
59     const int64_t  kInt64  = -9197712039090021561LL;
60 
61     const unsigned int kUint_1 = 9;
62     const unsigned int kUint_2 = 0xa3;
63     const unsigned int kUint_3 = 0x8765;
64     const unsigned int kUint_4 = SPINEL_MAX_UINT_PACKED - 1;
65 
66     const spinel_ipv6addr_t kIp6Addr = {
67         {0x6B, 0x41, 0x65, 0x73, 0x42, 0x68, 0x61, 0x76, 0x54, 0x61, 0x72, 0x7A, 0x49, 0x69, 0x61, 0x4E}};
68 
69     const spinel_eui48_t kEui48 = {
70         {4, 8, 15, 16, 23, 42} // "Lost" EUI48!
71     };
72 
73     const spinel_eui64_t kEui64 = {
74         {2, 3, 5, 7, 11, 13, 17, 19}, // "Prime" EUI64!
75     };
76 
77     const char kString_1[] = "OpenThread";
78     const char kString_2[] = "";
79 
80     const uint16_t kData[] = {10, 20, 3, 15, 1000, 60, 16}; // ... then comes 17,18,19,20  :)
81 
82     bool                     b_1, b_2;
83     uint8_t                  u8;
84     int8_t                   i8;
85     uint16_t                 u16;
86     int16_t                  i16;
87     uint32_t                 u32;
88     int32_t                  i32;
89     uint64_t                 u64;
90     int64_t                  i64;
91     unsigned int             u_1, u_2, u_3, u_4;
92     const spinel_ipv6addr_t *ip6Addr;
93     const spinel_eui48_t    *eui48;
94     const spinel_eui64_t    *eui64;
95     const char              *utf_1;
96     const char              *utf_2;
97     const uint8_t           *dataPtr_1;
98     const uint8_t           *dataPtr_2;
99     uint16_t                 dataLen_1;
100     uint16_t                 dataLen_2;
101 
102     memset(buffer, 0, sizeof(buffer));
103 
104     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
105     printf("\nTest 1: Decoding simple types");
106 
107     frameLen = spinel_datatype_pack(
108         buffer, sizeof(buffer),
109         (SPINEL_DATATYPE_BOOL_S SPINEL_DATATYPE_BOOL_S SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_INT8_S
110              SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_INT16_S SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_INT32_S
111                  SPINEL_DATATYPE_UINT64_S SPINEL_DATATYPE_INT64_S SPINEL_DATATYPE_UINT_PACKED_S
112                      SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_UINT_PACKED_S
113                          SPINEL_DATATYPE_IPv6ADDR_S SPINEL_DATATYPE_EUI48_S SPINEL_DATATYPE_EUI64_S
114                              SPINEL_DATATYPE_UTF8_S SPINEL_DATATYPE_UTF8_S SPINEL_DATATYPE_DATA_WLEN_S
115                                  SPINEL_DATATYPE_DATA_S),
116         kBool_1, kBool_2, kUint8, kInt8, kUint16, kInt16, kUint32, kInt32, kUint64, kInt64, kUint_1, kUint_2, kUint_3,
117         kUint_4, &kIp6Addr, &kEui48, &kEui64, kString_1, kString_2, kData, sizeof(kData), kData, sizeof(kData));
118 
119     DumpBuffer("Packed Spinel Frame", buffer, static_cast<uint16_t>(frameLen));
120 
121     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
122 
123     VerifyOrQuit(decoder.GetFrame() == &buffer[0]);
124     VerifyOrQuit(decoder.GetLength() == frameLen);
125 
126     VerifyOrQuit(decoder.GetReadLength() == 0);
127     VerifyOrQuit(decoder.GetRemainingLength() == frameLen);
128     VerifyOrQuit(decoder.IsAllRead() == false);
129 
130     SuccessOrQuit(decoder.ReadBool(b_1));
131     SuccessOrQuit(decoder.ReadBool(b_2));
132     SuccessOrQuit(decoder.ReadUint8(u8));
133     SuccessOrQuit(decoder.ReadInt8(i8));
134     SuccessOrQuit(decoder.ReadUint16(u16));
135     SuccessOrQuit(decoder.ReadInt16(i16));
136     SuccessOrQuit(decoder.ReadUint32(u32));
137     SuccessOrQuit(decoder.ReadInt32(i32));
138     SuccessOrQuit(decoder.ReadUint64(u64));
139     SuccessOrQuit(decoder.ReadInt64(i64));
140 
141     // Check the state
142     VerifyOrQuit(decoder.GetReadLength() != 0);
143     VerifyOrQuit(decoder.GetRemainingLength() == frameLen - decoder.GetReadLength());
144     VerifyOrQuit(decoder.IsAllRead() == false);
145 
146     SuccessOrQuit(decoder.ReadUintPacked(u_1));
147 
148     SuccessOrQuit(decoder.ReadUintPacked(u_2));
149     SuccessOrQuit(decoder.ReadUintPacked(u_3));
150     SuccessOrQuit(decoder.ReadUintPacked(u_4));
151     SuccessOrQuit(decoder.ReadIp6Address(ip6Addr));
152     SuccessOrQuit(decoder.ReadEui48(eui48));
153     SuccessOrQuit(decoder.ReadEui64(eui64));
154     SuccessOrQuit(decoder.ReadUtf8(utf_1));
155     SuccessOrQuit(decoder.ReadUtf8(utf_2));
156     SuccessOrQuit(decoder.ReadDataWithLen(dataPtr_1, dataLen_1));
157     SuccessOrQuit(decoder.ReadData(dataPtr_2, dataLen_2));
158 
159     VerifyOrQuit(decoder.GetReadLength() == frameLen);
160     VerifyOrQuit(decoder.GetRemainingLength() == 0);
161     VerifyOrQuit(decoder.IsAllRead() == true);
162 
163     VerifyOrQuit(b_1 == kBool_1);
164     VerifyOrQuit(b_2 == kBool_2);
165     VerifyOrQuit(u8 == kUint8);
166     VerifyOrQuit(i8 == kInt8);
167     VerifyOrQuit(u16 == kUint16);
168     VerifyOrQuit(i16 == kInt16);
169     VerifyOrQuit(u32 == kUint32);
170     VerifyOrQuit(i32 == kInt32);
171     VerifyOrQuit(u64 == kUint64);
172     VerifyOrQuit(i64 == kInt64);
173     VerifyOrQuit(u_1 == kUint_1);
174     VerifyOrQuit(u_2 == kUint_2);
175     VerifyOrQuit(u_3 == kUint_3);
176     VerifyOrQuit(u_4 == kUint_4);
177     VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
178     VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
179     VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0);
180     VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
181     VerifyOrQuit(memcmp(utf_2, kString_2, sizeof(kString_2)) == 0);
182     VerifyOrQuit(dataLen_1 == sizeof(kData));
183     VerifyOrQuit(memcmp(dataPtr_1, &kData, sizeof(kData)) == 0);
184     VerifyOrQuit(dataLen_2 == sizeof(kData));
185     VerifyOrQuit(memcmp(dataPtr_2, &kData, sizeof(kData)) == 0);
186 
187     printf(" -- PASS\n");
188 
189     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
190     printf("\nTest 2: Test Reset(), SavePosition(), ResetToSaved()");
191 
192     // `ResetToSaved()` should fail if there is no saved position
193     VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE);
194 
195     decoder.Reset();
196 
197     VerifyOrQuit(decoder.GetFrame() == &buffer[0]);
198     VerifyOrQuit(decoder.GetLength() == frameLen);
199     VerifyOrQuit(decoder.GetReadLength() == 0);
200     VerifyOrQuit(decoder.GetRemainingLength() == frameLen);
201     VerifyOrQuit(decoder.IsAllRead() == false);
202 
203     SuccessOrQuit(decoder.ReadBool(b_1));
204     SuccessOrQuit(decoder.ReadBool(b_2));
205     SuccessOrQuit(decoder.ReadUint8(u8));
206     SuccessOrQuit(decoder.ReadInt8(i8));
207     SuccessOrQuit(decoder.ReadUint16(u16));
208     SuccessOrQuit(decoder.ReadInt16(i16));
209     SuccessOrQuit(decoder.ReadUint32(u32));
210     SuccessOrQuit(decoder.ReadInt32(i32));
211 
212     // `ResetToSaved()` should fail if there is no saved position
213     VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE);
214 
215     // Save position
216     decoder.SavePosition();
217 
218     SuccessOrQuit(decoder.ReadUint64(u64));
219     SuccessOrQuit(decoder.ReadInt64(i64));
220     SuccessOrQuit(decoder.ReadUintPacked(u_1));
221     SuccessOrQuit(decoder.ReadUintPacked(u_2));
222     SuccessOrQuit(decoder.ReadUintPacked(u_3));
223     SuccessOrQuit(decoder.ReadUintPacked(u_4));
224     SuccessOrQuit(decoder.ReadIp6Address(ip6Addr));
225 
226     VerifyOrQuit(b_1 == kBool_1);
227     VerifyOrQuit(b_2 == kBool_2);
228     VerifyOrQuit(u8 == kUint8);
229     VerifyOrQuit(i8 == kInt8);
230     VerifyOrQuit(u16 == kUint16);
231     VerifyOrQuit(i16 == kInt16);
232     VerifyOrQuit(u32 == kUint32);
233     VerifyOrQuit(i32 == kInt32);
234     VerifyOrQuit(u64 == kUint64);
235     VerifyOrQuit(i64 == kInt64);
236     VerifyOrQuit(u_1 == kUint_1);
237     VerifyOrQuit(u_2 == kUint_2);
238     VerifyOrQuit(u_3 == kUint_3);
239     VerifyOrQuit(u_4 == kUint_4);
240     VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
241 
242     SuccessOrQuit(decoder.ResetToSaved());
243 
244     SuccessOrQuit(decoder.ReadUint64(u64));
245     SuccessOrQuit(decoder.ReadInt64(i64));
246     SuccessOrQuit(decoder.ReadUintPacked(u_1));
247     SuccessOrQuit(decoder.ReadUintPacked(u_2));
248     SuccessOrQuit(decoder.ReadUintPacked(u_3));
249     SuccessOrQuit(decoder.ReadUintPacked(u_4));
250     SuccessOrQuit(decoder.ReadIp6Address(ip6Addr));
251 
252     VerifyOrQuit(u64 == kUint64);
253     VerifyOrQuit(i64 == kInt64);
254     VerifyOrQuit(u_1 == kUint_1);
255     VerifyOrQuit(u_2 == kUint_2);
256     VerifyOrQuit(u_3 == kUint_3);
257     VerifyOrQuit(u_4 == kUint_4);
258     VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
259 
260     // Go back to save position again.
261     SuccessOrQuit(decoder.ResetToSaved());
262 
263     SuccessOrQuit(decoder.ReadUint64(u64));
264     SuccessOrQuit(decoder.ReadInt64(i64));
265     SuccessOrQuit(decoder.ReadUintPacked(u_1));
266     SuccessOrQuit(decoder.ReadUintPacked(u_2));
267     SuccessOrQuit(decoder.ReadUintPacked(u_3));
268     SuccessOrQuit(decoder.ReadUintPacked(u_4));
269     SuccessOrQuit(decoder.ReadIp6Address(ip6Addr));
270 
271     VerifyOrQuit(u64 == kUint64);
272     VerifyOrQuit(i64 == kInt64);
273     VerifyOrQuit(u_1 == kUint_1);
274     VerifyOrQuit(u_2 == kUint_2);
275     VerifyOrQuit(u_3 == kUint_3);
276     VerifyOrQuit(u_4 == kUint_4);
277     VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
278 
279     // Ensure saved position is cleared when decoder is reset or re-initialized.
280 
281     decoder.Reset();
282 
283     // `ResetToSaved()` should fail if there is no saved position
284     VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE);
285 
286     decoder.SavePosition();
287     SuccessOrQuit(decoder.ResetToSaved());
288 
289     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
290     VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE);
291 
292     printf(" -- PASS\n");
293 
294     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
295     printf("\nTest 3: Test decoding a single simple struct.");
296 
297     frameLen = spinel_datatype_pack(buffer, sizeof(buffer),
298                                     (SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_STRUCT_S(
299                                         SPINEL_DATATYPE_UINT32_S SPINEL_DATATYPE_EUI48_S SPINEL_DATATYPE_UINT_PACKED_S)
300                                          SPINEL_DATATYPE_INT16_S
301 
302                                      ),
303                                     kUint8, kUint32, &kEui48, kUint_3, kInt16);
304 
305     DumpBuffer("Packed Spinel Frame (single struct)", buffer, static_cast<uint16_t>(frameLen));
306 
307     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
308 
309     SuccessOrQuit(decoder.ReadUint8(u8));
310     SuccessOrQuit(decoder.OpenStruct());
311     {
312         SuccessOrQuit(decoder.ReadUint32(u32));
313         SuccessOrQuit(decoder.ReadEui48(eui48));
314         SuccessOrQuit(decoder.ReadUintPacked(u_3));
315     }
316     SuccessOrQuit(decoder.CloseStruct());
317     SuccessOrQuit(decoder.ReadInt16(i16));
318     VerifyOrQuit(decoder.IsAllRead() == true);
319 
320     VerifyOrQuit(u8 == kUint8);
321     VerifyOrQuit(i16 == kInt16);
322     VerifyOrQuit(u32 == kUint32);
323     VerifyOrQuit(u_3 == kUint_3);
324     VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
325 
326     printf(" -- PASS\n");
327 
328     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
329     printf("\nTest 4: Test partial struct read");
330 
331     // Re-use same frame as the previous test.
332 
333     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
334 
335     SuccessOrQuit(decoder.ReadUint8(u8));
336     SuccessOrQuit(decoder.OpenStruct());
337     {
338         SuccessOrQuit(decoder.ReadUint32(u32));
339         // Skip the remaining fields in the struct
340     }
341     SuccessOrQuit(decoder.CloseStruct());
342     SuccessOrQuit(decoder.ReadInt16(i16));
343 
344     VerifyOrQuit(u8 == kUint8);
345     VerifyOrQuit(i16 == kInt16);
346 
347     printf(" -- PASS\n");
348 
349     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
350     printf("\nTest 5: Test `GetRemainingLengthInStruct()` and `IsAllReadInStruct`() in and out of an struct");
351 
352     // Re-use same frame as the previous test.
353 
354     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
355 
356     VerifyOrQuit(decoder.GetFrame() == &buffer[0]);
357     VerifyOrQuit(decoder.GetLength() == frameLen);
358 
359     VerifyOrQuit(decoder.GetReadLength() == 0);
360     VerifyOrQuit(decoder.GetRemainingLength() == frameLen);
361     VerifyOrQuit(decoder.IsAllRead() == false);
362 
363     // When not in an struct,  `etRemainingLengthInStruct()` should consider the whole frame.
364     VerifyOrQuit(decoder.GetRemainingLengthInStruct() == frameLen);
365     VerifyOrQuit(decoder.IsAllReadInStruct() == false);
366 
367     SuccessOrQuit(decoder.ReadUint8(u8));
368     SuccessOrQuit(decoder.OpenStruct());
369     {
370         VerifyOrQuit(decoder.IsAllReadInStruct() == false);
371 
372         SuccessOrQuit(decoder.ReadUint32(u32));
373         SuccessOrQuit(decoder.ReadEui48(eui48));
374         SuccessOrQuit(decoder.ReadUintPacked(u_3));
375 
376         VerifyOrQuit(decoder.IsAllReadInStruct() == true);
377         VerifyOrQuit(decoder.GetRemainingLengthInStruct() == 0);
378 
379         // Try reading beyond end of the struct and ensure it fails.
380         VerifyOrQuit(decoder.ReadUint8(u8) == OT_ERROR_PARSE);
381 
382         // `ReadData()` at end of struct should still succeed but return zero as the data length.
383         SuccessOrQuit(decoder.ReadData(dataPtr_1, dataLen_1));
384         VerifyOrQuit(dataLen_1 == 0);
385     }
386     SuccessOrQuit(decoder.CloseStruct());
387 
388     VerifyOrQuit(decoder.IsAllReadInStruct() == false);
389     SuccessOrQuit(decoder.ReadInt16(i16));
390     VerifyOrQuit(decoder.IsAllRead() == true);
391 
392     VerifyOrQuit(decoder.GetRemainingLengthInStruct() == 0);
393     VerifyOrQuit(decoder.IsAllReadInStruct() == true);
394 
395     // `ReadData()` at end of frame should still succeed but return zero as the data length.
396     SuccessOrQuit(decoder.ReadData(dataPtr_1, dataLen_1));
397     VerifyOrQuit(dataLen_1 == 0);
398 
399     VerifyOrQuit(u8 == kUint8);
400     VerifyOrQuit(i16 == kInt16);
401     VerifyOrQuit(u32 == kUint32);
402     VerifyOrQuit(u_3 == kUint_3);
403     VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
404 
405     printf(" -- PASS\n");
406 
407     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
408     printf("\nTest 6: Test multiple nested structs");
409 
410     frameLen = spinel_datatype_pack(
411         buffer, sizeof(buffer),
412         (SPINEL_DATATYPE_STRUCT_S(SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UTF8_S SPINEL_DATATYPE_STRUCT_S(
413             SPINEL_DATATYPE_BOOL_S SPINEL_DATATYPE_IPv6ADDR_S) SPINEL_DATATYPE_UINT16_S)
414              SPINEL_DATATYPE_EUI48_S SPINEL_DATATYPE_STRUCT_S(SPINEL_DATATYPE_UINT32_S) SPINEL_DATATYPE_INT32_S),
415         kUint8, kString_1, kBool_1, &kIp6Addr, kUint16, &kEui48, kUint32, kInt32);
416 
417     DumpBuffer("Packed Spinel Frame (multiple struct)", buffer, static_cast<uint16_t>(frameLen));
418 
419     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
420 
421     SuccessOrQuit(decoder.OpenStruct());
422     {
423         SuccessOrQuit(decoder.ReadUint8(u8));
424         SuccessOrQuit(decoder.ReadUtf8(utf_1));
425         SuccessOrQuit(decoder.OpenStruct());
426         {
427             SuccessOrQuit(decoder.ReadBool(b_1));
428             SuccessOrQuit(decoder.ReadIp6Address(ip6Addr));
429         }
430         SuccessOrQuit(decoder.CloseStruct());
431         SuccessOrQuit(decoder.ReadUint16(u16));
432     }
433     SuccessOrQuit(decoder.CloseStruct());
434     SuccessOrQuit(decoder.ReadEui48(eui48));
435     SuccessOrQuit(decoder.OpenStruct());
436     {
437         SuccessOrQuit(decoder.ReadUint32(u32));
438     }
439     SuccessOrQuit(decoder.CloseStruct());
440     SuccessOrQuit(decoder.ReadInt32(i32));
441 
442     VerifyOrQuit(decoder.GetReadLength() == frameLen);
443     VerifyOrQuit(decoder.GetRemainingLength() == 0);
444     VerifyOrQuit(decoder.IsAllRead() == true);
445 
446     VerifyOrQuit(b_1 == kBool_1);
447     VerifyOrQuit(u8 == kUint8);
448     VerifyOrQuit(u16 == kUint16);
449     VerifyOrQuit(u32 == kUint32);
450     VerifyOrQuit(i32 == kInt32);
451     VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
452     VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
453     VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
454 
455     printf(" -- PASS\n");
456 
457     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
458     printf("\nTest 7: Test `SavePosition()`, `ResetToSaved()` for nested structs");
459 
460     // Re-use same frame as the previous test.
461 
462     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
463 
464     SuccessOrQuit(decoder.OpenStruct());
465     {
466         SuccessOrQuit(decoder.ReadUint8(u8));
467 
468         decoder.SavePosition();
469 
470         SuccessOrQuit(decoder.ReadUtf8(utf_1));
471         SuccessOrQuit(decoder.OpenStruct());
472         {
473             SuccessOrQuit(decoder.ReadBool(b_1));
474         }
475 
476         // Verify the read content so far.
477 
478         VerifyOrQuit(u8 == kUint8);
479         VerifyOrQuit(b_1 == kBool_1);
480         VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
481 
482         // Do not close the inner struct and jump to previously saved position and re-read the content.
483 
484         SuccessOrQuit(decoder.ResetToSaved());
485 
486         SuccessOrQuit(decoder.ReadUtf8(utf_1));
487         SuccessOrQuit(decoder.OpenStruct());
488         {
489             SuccessOrQuit(decoder.ReadBool(b_1));
490             SuccessOrQuit(decoder.ReadIp6Address(ip6Addr));
491         }
492         SuccessOrQuit(decoder.CloseStruct());
493         SuccessOrQuit(decoder.ReadUint16(u16));
494     }
495     SuccessOrQuit(decoder.CloseStruct());
496     SuccessOrQuit(decoder.ReadEui48(eui48));
497     SuccessOrQuit(decoder.OpenStruct());
498     {
499         SuccessOrQuit(decoder.ReadUint32(u32));
500     }
501     SuccessOrQuit(decoder.CloseStruct());
502     SuccessOrQuit(decoder.ReadInt32(i32));
503 
504     VerifyOrQuit(decoder.GetReadLength() == frameLen);
505     VerifyOrQuit(decoder.GetRemainingLength() == 0);
506     VerifyOrQuit(decoder.IsAllRead() == true);
507 
508     VerifyOrQuit(b_1 == kBool_1);
509     VerifyOrQuit(u8 == kUint8);
510     VerifyOrQuit(u16 == kUint16);
511     VerifyOrQuit(u32 == kUint32);
512     VerifyOrQuit(i32 == kInt32);
513     VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
514     VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
515     VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
516 
517     printf(" -- PASS\n");
518 
519     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
520     printf("\nTest 8: Test saving position at start of an open struct");
521 
522     // Re-use same frame as the previous test.
523 
524     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
525 
526     SuccessOrQuit(decoder.OpenStruct());
527     {
528         SuccessOrQuit(decoder.ReadUint8(u8));
529         SuccessOrQuit(decoder.ReadUtf8(utf_1));
530         SuccessOrQuit(decoder.OpenStruct());
531         {
532             // Save position at start of the struct
533             decoder.SavePosition();
534             SuccessOrQuit(decoder.ReadBool(b_1));
535 
536             // Verify the read content so far.
537 
538             VerifyOrQuit(u8 == kUint8);
539             VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
540             VerifyOrQuit(b_1 == kBool_1);
541 
542             // Do not close the struct and jump to the previously saved position and re-read the content.
543 
544             SuccessOrQuit(decoder.ResetToSaved());
545             SuccessOrQuit(decoder.ReadBool(b_1));
546             SuccessOrQuit(decoder.ReadIp6Address(ip6Addr));
547         }
548         SuccessOrQuit(decoder.CloseStruct());
549         SuccessOrQuit(decoder.ReadUint16(u16));
550     }
551     SuccessOrQuit(decoder.CloseStruct());
552     SuccessOrQuit(decoder.ReadEui48(eui48));
553     SuccessOrQuit(decoder.OpenStruct());
554     {
555         SuccessOrQuit(decoder.ReadUint32(u32));
556     }
557     SuccessOrQuit(decoder.CloseStruct());
558     SuccessOrQuit(decoder.ReadInt32(i32));
559 
560     VerifyOrQuit(decoder.GetReadLength() == frameLen);
561     VerifyOrQuit(decoder.GetRemainingLength() == 0);
562     VerifyOrQuit(decoder.IsAllRead() == true);
563 
564     VerifyOrQuit(b_1 == kBool_1);
565     VerifyOrQuit(u8 == kUint8);
566     VerifyOrQuit(u16 == kUint16);
567     VerifyOrQuit(u32 == kUint32);
568     VerifyOrQuit(i32 == kInt32);
569     VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0);
570     VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0);
571     VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0);
572 
573     printf(" -- PASS\n");
574 
575     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
576     printf("\nTest 9: Test `ResetToSaved()` failure case (jumping back to a saved position closed struct).");
577 
578     // Re-use same frame as the previous test.
579 
580     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
581 
582     SuccessOrQuit(decoder.OpenStruct());
583     {
584         SuccessOrQuit(decoder.ReadUint8(u8));
585         SuccessOrQuit(decoder.ReadUtf8(utf_1));
586         SuccessOrQuit(decoder.OpenStruct());
587         {
588             SuccessOrQuit(decoder.ReadBool(b_1));
589 
590             decoder.SavePosition();
591 
592             SuccessOrQuit(decoder.ReadIp6Address(ip6Addr));
593         }
594         SuccessOrQuit(decoder.CloseStruct());
595         SuccessOrQuit(decoder.ReadUint16(u16));
596 
597         // `ResetToSaved()` should fail since the enclosing struct for the saved position is closed.
598         VerifyOrQuit(decoder.ResetToSaved() == OT_ERROR_INVALID_STATE);
599     }
600 
601     printf(" -- PASS\n");
602 
603     printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
604     printf("\nTest 10: Testing error cases and failures. (e.g., wrong struct length).");
605 
606     frameLen = spinel_datatype_pack(buffer, sizeof(buffer),
607                                     (SPINEL_DATATYPE_UINT8_S SPINEL_DATATYPE_UINT16_S // Treat this as struct length
608                                          SPINEL_DATATYPE_BOOL_S),
609                                     kUint8, 10, kBool_1);
610 
611     DumpBuffer("Packed Spinel Frame (incorrect format)", buffer, static_cast<uint16_t>(frameLen));
612 
613     decoder.Init(buffer, static_cast<uint16_t>(frameLen));
614 
615     decoder.SavePosition();
616 
617     SuccessOrQuit(decoder.ReadUint8(u8));
618     VerifyOrQuit(u8 == kUint8);
619 
620     // `OpenStruct()` should fail, since it expects a length 10 but there are not enough
621     // bytes in the frame.
622     VerifyOrQuit(decoder.OpenStruct() == OT_ERROR_PARSE);
623 
624     SuccessOrQuit(decoder.ResetToSaved());
625 
626     SuccessOrQuit(decoder.ReadUint8(u8));
627     VerifyOrQuit(u8 == kUint8);
628     VerifyOrQuit(decoder.ReadDataWithLen(dataPtr_1, dataLen_1) == OT_ERROR_PARSE);
629 
630     SuccessOrQuit(decoder.ResetToSaved());
631     SuccessOrQuit(decoder.ReadUint8(u8));
632     SuccessOrQuit(decoder.ReadUint16(u16));
633     SuccessOrQuit(decoder.ReadBool(b_1));
634 
635     // Try reading beyond end of frame.
636     VerifyOrQuit(decoder.ReadUint8(u8) == OT_ERROR_PARSE);
637 
638     printf(" -- PASS\n");
639 }
640 
641 } // namespace Spinel
642 } // namespace ot
643 
main(void)644 int main(void)
645 {
646     ot::Spinel::Decoder();
647     printf("\nAll tests passed.\n");
648     return 0;
649 }
650