1 /*
2  *  Copyright (c) 2020, 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 <string.h>
30 
31 #include "test_platform.h"
32 
33 #include <openthread/config.h>
34 
35 #include "instance/instance.hpp"
36 #include "utils/parse_cmdline.hpp"
37 
38 #include "test_util.hpp"
39 
40 namespace ot {
41 
42 using Utils::CmdLineParser::ParseAsBool;
43 using Utils::CmdLineParser::ParseAsHexString;
44 using Utils::CmdLineParser::ParseAsHexStringSegment;
45 using Utils::CmdLineParser::ParseAsInt16;
46 using Utils::CmdLineParser::ParseAsInt32;
47 using Utils::CmdLineParser::ParseAsInt8;
48 using Utils::CmdLineParser::ParseAsUint16;
49 using Utils::CmdLineParser::ParseAsUint32;
50 using Utils::CmdLineParser::ParseAsUint64;
51 using Utils::CmdLineParser::ParseAsUint8;
52 
53 template <typename ValueType> struct TestCase
54 {
55     const char *mString;
56     otError     mError;
57     ValueType   mValue;
58 };
59 
60 template <typename ValueType, otError (&Parser)(const char *aString, ValueType &aValue)>
VerifyParser(const TestCase<ValueType> * aTestCases,const char * aParserName,const char * aPrintFormat)61 void VerifyParser(const TestCase<ValueType> *aTestCases, const char *aParserName, const char *aPrintFormat)
62 {
63     const TestCase<ValueType> *testCase = aTestCases;
64     ValueType                  value;
65     otError                    error;
66 
67     printf("----------------------------------------------------------\n");
68 
69     while (true)
70     {
71         printf("%s(\"%s\") -> ", aParserName, testCase->mString);
72 
73         if (testCase->mError != OT_ERROR_NONE)
74         {
75             printf("error:%s", otThreadErrorToString(testCase->mError));
76         }
77         else
78         {
79             printf(aPrintFormat, testCase->mValue);
80         }
81 
82         printf("\n");
83 
84         error = Parser(testCase->mString, value);
85 
86         VerifyOrQuit(error == testCase->mError, "Parser did not return the expected error");
87 
88         if (error == OT_ERROR_NONE)
89         {
90             VerifyOrQuit(value == testCase->mValue, "Parser failed");
91         }
92 
93         if (testCase->mString[0] == '\0')
94         {
95             break;
96         }
97 
98         testCase++;
99     }
100 }
101 
TestParsingInts(void)102 void TestParsingInts(void)
103 {
104     TestCase<bool> kBoolTestCases[] = {
105         {"0", OT_ERROR_NONE, false},          // Zero as false value
106         {"1", OT_ERROR_NONE, true},           // Non-zero as true value
107         {"0x0", OT_ERROR_NONE, false},        // Zero as false value
108         {"0x1", OT_ERROR_NONE, true},         // Non-zero (in hex) as true value
109         {"10", OT_ERROR_NONE, true},          // Non-zero as true value
110         {"a", OT_ERROR_INVALID_ARGS, false},  // Error case: Incorrect char
111         {"-1", OT_ERROR_INVALID_ARGS, false}, // Error case: Negative value
112         {"", OT_ERROR_INVALID_ARGS, false},   // Empty string indicate end of the list
113     };
114 
115     TestCase<uint8_t> kUint8TestCases[] = {
116         {"0", OT_ERROR_NONE, 0},
117         {"1", OT_ERROR_NONE, 1},
118         {"74", OT_ERROR_NONE, 74},
119         {"255", OT_ERROR_NONE, 255}, // Max `uint8` value (decimal format)
120         {"0xa", OT_ERROR_NONE, 0xa},
121         {"0x04", OT_ERROR_NONE, 4},
122         {"0x7e", OT_ERROR_NONE, 0x7e},
123         {"0xcd", OT_ERROR_NONE, 0xcd},
124         {"0x0", OT_ERROR_NONE, 0},
125         {"0xff", OT_ERROR_NONE, 0xff},     // Max `uint8` value (hex format)
126         {"0x0000ff", OT_ERROR_NONE, 0xff}, // Hex format (extra zeros)
127         {"0xB", OT_ERROR_NONE, 0xb},
128         {"0X04", OT_ERROR_NONE, 4},
129         {"0X7E", OT_ERROR_NONE, 0x7e},
130         {"0XCD", OT_ERROR_NONE, 0xcd},
131         {"0X0", OT_ERROR_NONE, 0},
132         {"0XFF", OT_ERROR_NONE, 0xff},
133         {"00", OT_ERROR_NONE, 0},
134         {"-5", OT_ERROR_INVALID_ARGS, 0},    // Error case: Negative value.
135         {"0y", OT_ERROR_INVALID_ARGS, 0},    // Error case: Incorrect prefix.
136         {"0x7g", OT_ERROR_INVALID_ARGS, 0},  // Error case: Bad hex char.
137         {"0xaaa", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out or range.
138         {"256", OT_ERROR_INVALID_ARGS, 0},   // Error case: Out of range (max value + 1)
139         {"12e", OT_ERROR_INVALID_ARGS, 0},   // Error case: Extra char.
140         {"", OT_ERROR_INVALID_ARGS, 0}       // Empty string indicates end of the list
141     };
142 
143     TestCase<uint16_t> kUint16TestCases[] = {
144         {"0", OT_ERROR_NONE, 0},
145         {"1245", OT_ERROR_NONE, 1245},
146         {"0xa", OT_ERROR_NONE, 0xa},
147         {"0xab7d", OT_ERROR_NONE, 0xab7d},
148         {"0X1AE", OT_ERROR_NONE, 0x1ae},
149         {"0X7E", OT_ERROR_NONE, 0x7e},
150         {"65535", OT_ERROR_NONE, 65535},       // Max `uint16` value (decimal format)
151         {"0xffff", OT_ERROR_NONE, 0xffff},     // Max `uint16` value (hex format)
152         {"-1", OT_ERROR_INVALID_ARGS, 0},      // Error case: Negative value
153         {"0y", OT_ERROR_INVALID_ARGS, 0},      // Error case: Incorrect prefix
154         {"0xq", OT_ERROR_INVALID_ARGS, 0},     // Error case: Bad hex char.
155         {"0x12345", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range.
156         {"65536", OT_ERROR_INVALID_ARGS, 0},   // Error case: Out of range (max value + 1)
157         {"", OT_ERROR_INVALID_ARGS, 0}         // Empty string indicates end of the list
158     };
159 
160     TestCase<uint32_t> kUint32TestCases[] = {
161         {"0", OT_ERROR_NONE, 0},
162         {"1234567", OT_ERROR_NONE, 1234567},
163         {"0xc", OT_ERROR_NONE, 0xc},
164         {"0x01234567", OT_ERROR_NONE, 0x1234567},
165         {"0XABCDEF09", OT_ERROR_NONE, 0xabcdef09},
166         {"0X54321", OT_ERROR_NONE, 0x54321},
167         {"4294967295", OT_ERROR_NONE, 4294967295}, // Max `uint32` value (decimal format)
168         {"0xffffffff", OT_ERROR_NONE, 0xffffffff}, // Max `uint32` value (hex format)
169         {"-1", OT_ERROR_INVALID_ARGS, 0},
170         {"0y", OT_ERROR_INVALID_ARGS, 0},
171         {"0x1234zz", OT_ERROR_INVALID_ARGS, 0},    // Error case: Bad hex char
172         {"0x123456789", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range
173         {"4294967296", OT_ERROR_INVALID_ARGS, 0},  // Error case: Out of range (max value + 1)
174         {"", OT_ERROR_INVALID_ARGS, 0}             // Empty string indicates end of the list.
175     };
176 
177     TestCase<uint64_t> kUint64TestCases[] = {
178         {"0", OT_ERROR_NONE, 0},
179         {"123456789087654321", OT_ERROR_NONE, 123456789087654321},
180         {"0xb", OT_ERROR_NONE, 0xb},
181         {"0x1234567890acbdef", OT_ERROR_NONE, 0x1234567890acbdef},
182         {"0XFEDCBA9876543210", OT_ERROR_NONE, 0xfedcba9876543210},
183         {"0xffffffffffffffff", OT_ERROR_NONE, 0xffffffffffffffff},        // Max `uint64` value (hex format)
184         {"18446744073709551615", OT_ERROR_NONE, 18446744073709551615ull}, // Max `uint64` value (decimal format)
185         {"-1", OT_ERROR_INVALID_ARGS, 0},
186         {"0x1234567890acbdef0", OT_ERROR_INVALID_ARGS, 0},  // Error case: Out of range
187         {"18446744073709551616", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out or range (max value + 1)
188         {"", OT_ERROR_INVALID_ARGS, 0}                      // Empty string indicates end of the list.
189     };
190 
191     TestCase<int8_t> kInt8TestCases[] = {
192         {"0", OT_ERROR_NONE, 0},
193         {"-1", OT_ERROR_NONE, -1},
194         {"+74", OT_ERROR_NONE, 74},
195         {"-0x12", OT_ERROR_NONE, -0x12},
196         {"-0XB", OT_ERROR_NONE, -11},
197         {"127", OT_ERROR_NONE, 127},        // Max `int8` value
198         {"-128", OT_ERROR_NONE, -128},      // Min `int8` value
199         {"128", OT_ERROR_INVALID_ARGS, 0},  // Error case: Out of range (max value + 1)
200         {"-129", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (min value - 1)
201         {"--1", OT_ERROR_INVALID_ARGS, 0},  // Error case: Extra sign
202         {"+-2", OT_ERROR_INVALID_ARGS, 0},  // Error case: Extra sign
203         {"++1", OT_ERROR_INVALID_ARGS, 0},  // Error case: Extra sign
204         {"", OT_ERROR_INVALID_ARGS, 0}      // Empty string indicates end of the list.
205     };
206 
207     TestCase<int16_t> kInt16TestCases[] = {
208         {"-1", OT_ERROR_NONE, -1},
209         {"+0x1234", OT_ERROR_NONE, 0x1234},
210         {"-0X6E8", OT_ERROR_NONE, -0x6E8},
211         {"32767", OT_ERROR_NONE, 32767},       // Max `int16` value
212         {"0X7FFF", OT_ERROR_NONE, 0x7fff},     // Max `int16` value (hex value)
213         {"-32768", OT_ERROR_NONE, -32768},     // Min `int16` value
214         {"-0x8000", OT_ERROR_NONE, -0x8000},   // Min `int16` value (hex value)
215         {"32768", OT_ERROR_INVALID_ARGS, 0},   // Error case: Out of range (max + 1)
216         {"0X8000", OT_ERROR_INVALID_ARGS, 0},  // Error case: Out of range (max + 1)
217         {"-32769", OT_ERROR_INVALID_ARGS, 0},  // Error case: Out of range (min - 1)
218         {"-0x8001", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (min - 1)
219         {"", OT_ERROR_INVALID_ARGS, 0}         // Empty string indicates end of the list.
220     };
221 
222     TestCase<int32_t> kInt32TestCases[] = {
223         {"-256", OT_ERROR_NONE, -256},
224         {"+0x12345678", OT_ERROR_NONE, 0x12345678},
225         {"-0X6677aB", OT_ERROR_NONE, -0X6677aB},
226         {"2147483647", OT_ERROR_NONE, 2147483647},
227         {"0x7fffFFFF", OT_ERROR_NONE, 0x7fffffff},   // Max `int32` value
228         {"-2147483648", OT_ERROR_NONE, -2147483648}, // Min `int32` value
229         {"2147483648", OT_ERROR_INVALID_ARGS, 0},    // Error case: Out of range (max + 1)
230         {"0X80000000", OT_ERROR_INVALID_ARGS, 0},    // Error case: Out of range (max + 1)
231         {"-2147483649", OT_ERROR_INVALID_ARGS, 0},   // Error case: Out of range (min - 1)
232         {"-0x80000001", OT_ERROR_INVALID_ARGS, 0},   // Error case: Out of range (min - 1)
233         {"", OT_ERROR_INVALID_ARGS, 0}               // Empty string indicates end of the list
234     };
235 
236     VerifyParser<bool, ParseAsBool>(kBoolTestCases, "ParseAsBool", "%d");
237     VerifyParser<uint8_t, ParseAsUint8>(kUint8TestCases, "ParseAsUint8", "0x%02x");
238     VerifyParser<uint16_t, ParseAsUint16>(kUint16TestCases, "ParseAsUint16", "0x%04x");
239     VerifyParser<uint32_t, ParseAsUint32>(kUint32TestCases, "ParseAsUint32", "0x%08x");
240     VerifyParser<uint64_t, ParseAsUint64>(kUint64TestCases, "ParseAsUint64", "0x%016llx");
241     VerifyParser<int8_t, ParseAsInt8>(kInt8TestCases, "ParseAsInt8", "%d");
242     VerifyParser<int16_t, ParseAsInt16>(kInt16TestCases, "ParseAsInt16", "%d");
243     VerifyParser<int32_t, ParseAsInt32>(kInt32TestCases, "ParseAsInt32", "%d");
244 }
245 
TestParsingHexStrings(void)246 void TestParsingHexStrings(void)
247 {
248     const char    kEvenHexString[]   = "DeadBeefCafeBabe";
249     const uint8_t kEvenParsedArray[] = {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe};
250 
251     const char    kOddHexString[]   = "abcdef9876543";
252     const uint8_t kOddParsedArray[] = {0xa, 0xbc, 0xde, 0xf9, 0x87, 0x65, 0x43};
253 
254     uint8_t        buffer[sizeof(kEvenParsedArray)];
255     uint8_t        buf3[3];
256     uint16_t       len;
257     const char    *string;
258     const uint8_t *bufPtr;
259 
260     // Verify `ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize)`
261 
262     buffer[0] = 0xff;
263     SuccessOrQuit(ParseAsHexString("0", buffer, 1));
264     VerifyOrQuit(buffer[0] == 0, "ParseAsHexString() parsed incorrectly");
265 
266     buffer[0] = 0;
267     SuccessOrQuit(ParseAsHexString("7e", buffer, 1));
268     VerifyOrQuit(buffer[0] == 0x7e, "ParseAsHexString() parsed incorrectly");
269 
270     VerifyOrQuit(ParseAsHexString("123", buffer, 1) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input");
271     SuccessOrQuit(ParseAsHexString("123", buffer, 2));
272     VerifyOrQuit(buffer[0] == 1 && buffer[1] == 0x23, "ParseAsHexString() parsed incorrectly");
273 
274     VerifyOrQuit(ParseAsHexString("123x", buffer, 2) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input");
275     VerifyOrQuit(ParseAsHexString(" 123", buffer, 2) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input");
276 
277     // Verify `ParseAsHexString<kMaxSize>()`
278 
279     VerifyOrQuit(ParseAsHexString("1122", buf3) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input");
280     VerifyOrQuit(ParseAsHexString("1122334", buf3) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input");
281     VerifyOrQuit(ParseAsHexString("11223344", buf3) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input");
282     SuccessOrQuit(ParseAsHexString("abbade", buf3));
283 
284     VerifyOrQuit(buf3[0] == 0xab && buf3[1] == 0xba && buf3[2] == 0xde, "ParseAsHexString() parsed incorrectly");
285     SuccessOrQuit(ParseAsHexString("012345", buf3));
286     VerifyOrQuit(buf3[0] == 0x01 && buf3[1] == 0x23 && buf3[2] == 0x45, "ParseAsHexString() parsed incorrectly");
287     SuccessOrQuit(ParseAsHexString("12345", buf3), "ParseAsHexString() failed with odd length");
288     VerifyOrQuit(buf3[0] == 0x01 && buf3[1] == 0x23 && buf3[2] == 0x45, "ParseAsHexString() parsed incorrectly");
289 
290     SuccessOrQuit(ParseAsHexString(kEvenHexString, buffer), "ParseAsHexString failed");
291     VerifyOrQuit(memcmp(buffer, kEvenParsedArray, sizeof(buffer)) == 0, "ParseAsHexString() parsed incorrectly");
292 
293     // Verify `ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer)`
294 
295     printf("----------------------------------------------------------\n");
296     len = sizeof(buffer);
297 
298     SuccessOrQuit(ParseAsHexString(kEvenHexString, len, buffer));
299     VerifyOrQuit(len == sizeof(kEvenParsedArray), "ParseAsHexString() parsed incorrectly");
300     VerifyOrQuit(memcmp(buffer, kEvenParsedArray, len) == 0, "ParseAsHexString() parsed incorrectly");
301     DumpBuffer(kEvenHexString, buffer, len);
302 
303     SuccessOrQuit(ParseAsHexString(kOddHexString, len, buffer));
304     VerifyOrQuit(len == sizeof(kOddParsedArray), "ParseAsHexString() parsed incorrectly");
305     VerifyOrQuit(memcmp(buffer, kOddParsedArray, len) == 0, "ParseAsHexString() parsed incorrectly");
306     DumpBuffer(kOddHexString, buffer, len);
307 
308     // Verify `ParseAsHexStringSegement()`
309 
310     printf("----------------------------------------------------------\n");
311 
312     for (uint8_t testIter = 0; testIter <= 1; testIter++)
313     {
314         for (size_t segmentLen = 1; segmentLen <= sizeof(buffer); segmentLen++)
315         {
316             if (testIter == 0)
317             {
318                 string = kEvenHexString;
319                 bufPtr = kEvenParsedArray;
320             }
321             else
322             {
323                 string = kOddHexString;
324                 bufPtr = kOddParsedArray;
325             }
326 
327             len = segmentLen;
328 
329             printf("\"%s\" segLen:%zu -> ", string, segmentLen);
330 
331             while (true)
332             {
333                 otError error = ParseAsHexStringSegment(string, len, buffer);
334 
335                 printf("%d (\"%s\") ", len, string);
336 
337                 if (error == OT_ERROR_NONE)
338                 {
339                     VerifyOrQuit(len <= segmentLen, "ParseAsHexStringSegment() parsed incorrectly");
340                     VerifyOrQuit(memcmp(buffer, bufPtr, len) == 0, "ParseAsHexStringSegment() parsed incorrectly");
341                     VerifyOrQuit(*string == '\0',
342                                  "ParseAsHexStringSegment() failed to update string pointer correctly");
343                     break;
344                 }
345 
346                 VerifyOrQuit(error == OT_ERROR_PENDING, "ParseAsHexStringSegment() failed");
347                 VerifyOrQuit(len == segmentLen, "ParseAsHexStringSegment() parsed incorrectly");
348                 VerifyOrQuit(memcmp(buffer, bufPtr, len) == 0, "ParseAsHexStringSegment() parsed incorrectly");
349                 bufPtr += len;
350             }
351 
352             printf("\n");
353         }
354     }
355 }
356 
357 } // namespace ot
358 
main(void)359 int main(void)
360 {
361     ot::TestParsingInts();
362     ot::TestParsingHexStrings();
363 
364     printf("All tests passed\n");
365     return 0;
366 }
367