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