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