/* * Copyright (c) 2020, The OpenThread Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holder nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "test_platform.h" #include #include "instance/instance.hpp" #include "utils/parse_cmdline.hpp" #include "test_util.hpp" namespace ot { using Utils::CmdLineParser::ParseAsBool; using Utils::CmdLineParser::ParseAsHexString; using Utils::CmdLineParser::ParseAsHexStringSegment; using Utils::CmdLineParser::ParseAsInt16; using Utils::CmdLineParser::ParseAsInt32; using Utils::CmdLineParser::ParseAsInt8; using Utils::CmdLineParser::ParseAsUint16; using Utils::CmdLineParser::ParseAsUint32; using Utils::CmdLineParser::ParseAsUint64; using Utils::CmdLineParser::ParseAsUint8; template struct TestCase { const char *mString; otError mError; ValueType mValue; }; template void VerifyParser(const TestCase *aTestCases, const char *aParserName, const char *aPrintFormat) { const TestCase *testCase = aTestCases; ValueType value; otError error; printf("----------------------------------------------------------\n"); while (true) { printf("%s(\"%s\") -> ", aParserName, testCase->mString); if (testCase->mError != OT_ERROR_NONE) { printf("error:%s", otThreadErrorToString(testCase->mError)); } else { printf(aPrintFormat, testCase->mValue); } printf("\n"); error = Parser(testCase->mString, value); VerifyOrQuit(error == testCase->mError, "Parser did not return the expected error"); if (error == OT_ERROR_NONE) { VerifyOrQuit(value == testCase->mValue, "Parser failed"); } if (testCase->mString[0] == '\0') { break; } testCase++; } } void TestParsingInts(void) { TestCase kBoolTestCases[] = { {"0", OT_ERROR_NONE, false}, // Zero as false value {"1", OT_ERROR_NONE, true}, // Non-zero as true value {"0x0", OT_ERROR_NONE, false}, // Zero as false value {"0x1", OT_ERROR_NONE, true}, // Non-zero (in hex) as true value {"10", OT_ERROR_NONE, true}, // Non-zero as true value {"a", OT_ERROR_INVALID_ARGS, false}, // Error case: Incorrect char {"-1", OT_ERROR_INVALID_ARGS, false}, // Error case: Negative value {"", OT_ERROR_INVALID_ARGS, false}, // Empty string indicate end of the list }; TestCase kUint8TestCases[] = { {"0", OT_ERROR_NONE, 0}, {"1", OT_ERROR_NONE, 1}, {"74", OT_ERROR_NONE, 74}, {"255", OT_ERROR_NONE, 255}, // Max `uint8` value (decimal format) {"0xa", OT_ERROR_NONE, 0xa}, {"0x04", OT_ERROR_NONE, 4}, {"0x7e", OT_ERROR_NONE, 0x7e}, {"0xcd", OT_ERROR_NONE, 0xcd}, {"0x0", OT_ERROR_NONE, 0}, {"0xff", OT_ERROR_NONE, 0xff}, // Max `uint8` value (hex format) {"0x0000ff", OT_ERROR_NONE, 0xff}, // Hex format (extra zeros) {"0xB", OT_ERROR_NONE, 0xb}, {"0X04", OT_ERROR_NONE, 4}, {"0X7E", OT_ERROR_NONE, 0x7e}, {"0XCD", OT_ERROR_NONE, 0xcd}, {"0X0", OT_ERROR_NONE, 0}, {"0XFF", OT_ERROR_NONE, 0xff}, {"00", OT_ERROR_NONE, 0}, {"-5", OT_ERROR_INVALID_ARGS, 0}, // Error case: Negative value. {"0y", OT_ERROR_INVALID_ARGS, 0}, // Error case: Incorrect prefix. {"0x7g", OT_ERROR_INVALID_ARGS, 0}, // Error case: Bad hex char. {"0xaaa", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out or range. {"256", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (max value + 1) {"12e", OT_ERROR_INVALID_ARGS, 0}, // Error case: Extra char. {"", OT_ERROR_INVALID_ARGS, 0} // Empty string indicates end of the list }; TestCase kUint16TestCases[] = { {"0", OT_ERROR_NONE, 0}, {"1245", OT_ERROR_NONE, 1245}, {"0xa", OT_ERROR_NONE, 0xa}, {"0xab7d", OT_ERROR_NONE, 0xab7d}, {"0X1AE", OT_ERROR_NONE, 0x1ae}, {"0X7E", OT_ERROR_NONE, 0x7e}, {"65535", OT_ERROR_NONE, 65535}, // Max `uint16` value (decimal format) {"0xffff", OT_ERROR_NONE, 0xffff}, // Max `uint16` value (hex format) {"-1", OT_ERROR_INVALID_ARGS, 0}, // Error case: Negative value {"0y", OT_ERROR_INVALID_ARGS, 0}, // Error case: Incorrect prefix {"0xq", OT_ERROR_INVALID_ARGS, 0}, // Error case: Bad hex char. {"0x12345", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range. {"65536", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (max value + 1) {"", OT_ERROR_INVALID_ARGS, 0} // Empty string indicates end of the list }; TestCase kUint32TestCases[] = { {"0", OT_ERROR_NONE, 0}, {"1234567", OT_ERROR_NONE, 1234567}, {"0xc", OT_ERROR_NONE, 0xc}, {"0x01234567", OT_ERROR_NONE, 0x1234567}, {"0XABCDEF09", OT_ERROR_NONE, 0xabcdef09}, {"0X54321", OT_ERROR_NONE, 0x54321}, {"4294967295", OT_ERROR_NONE, 4294967295}, // Max `uint32` value (decimal format) {"0xffffffff", OT_ERROR_NONE, 0xffffffff}, // Max `uint32` value (hex format) {"-1", OT_ERROR_INVALID_ARGS, 0}, {"0y", OT_ERROR_INVALID_ARGS, 0}, {"0x1234zz", OT_ERROR_INVALID_ARGS, 0}, // Error case: Bad hex char {"0x123456789", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range {"4294967296", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (max value + 1) {"", OT_ERROR_INVALID_ARGS, 0} // Empty string indicates end of the list. }; TestCase kUint64TestCases[] = { {"0", OT_ERROR_NONE, 0}, {"123456789087654321", OT_ERROR_NONE, 123456789087654321}, {"0xb", OT_ERROR_NONE, 0xb}, {"0x1234567890acbdef", OT_ERROR_NONE, 0x1234567890acbdef}, {"0XFEDCBA9876543210", OT_ERROR_NONE, 0xfedcba9876543210}, {"0xffffffffffffffff", OT_ERROR_NONE, 0xffffffffffffffff}, // Max `uint64` value (hex format) {"18446744073709551615", OT_ERROR_NONE, 18446744073709551615ull}, // Max `uint64` value (decimal format) {"-1", OT_ERROR_INVALID_ARGS, 0}, {"0x1234567890acbdef0", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range {"18446744073709551616", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out or range (max value + 1) {"", OT_ERROR_INVALID_ARGS, 0} // Empty string indicates end of the list. }; TestCase kInt8TestCases[] = { {"0", OT_ERROR_NONE, 0}, {"-1", OT_ERROR_NONE, -1}, {"+74", OT_ERROR_NONE, 74}, {"-0x12", OT_ERROR_NONE, -0x12}, {"-0XB", OT_ERROR_NONE, -11}, {"127", OT_ERROR_NONE, 127}, // Max `int8` value {"-128", OT_ERROR_NONE, -128}, // Min `int8` value {"128", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (max value + 1) {"-129", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (min value - 1) {"--1", OT_ERROR_INVALID_ARGS, 0}, // Error case: Extra sign {"+-2", OT_ERROR_INVALID_ARGS, 0}, // Error case: Extra sign {"++1", OT_ERROR_INVALID_ARGS, 0}, // Error case: Extra sign {"", OT_ERROR_INVALID_ARGS, 0} // Empty string indicates end of the list. }; TestCase kInt16TestCases[] = { {"-1", OT_ERROR_NONE, -1}, {"+0x1234", OT_ERROR_NONE, 0x1234}, {"-0X6E8", OT_ERROR_NONE, -0x6E8}, {"32767", OT_ERROR_NONE, 32767}, // Max `int16` value {"0X7FFF", OT_ERROR_NONE, 0x7fff}, // Max `int16` value (hex value) {"-32768", OT_ERROR_NONE, -32768}, // Min `int16` value {"-0x8000", OT_ERROR_NONE, -0x8000}, // Min `int16` value (hex value) {"32768", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (max + 1) {"0X8000", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (max + 1) {"-32769", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (min - 1) {"-0x8001", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (min - 1) {"", OT_ERROR_INVALID_ARGS, 0} // Empty string indicates end of the list. }; TestCase kInt32TestCases[] = { {"-256", OT_ERROR_NONE, -256}, {"+0x12345678", OT_ERROR_NONE, 0x12345678}, {"-0X6677aB", OT_ERROR_NONE, -0X6677aB}, {"2147483647", OT_ERROR_NONE, 2147483647}, {"0x7fffFFFF", OT_ERROR_NONE, 0x7fffffff}, // Max `int32` value {"-2147483648", OT_ERROR_NONE, -2147483648}, // Min `int32` value {"2147483648", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (max + 1) {"0X80000000", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (max + 1) {"-2147483649", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (min - 1) {"-0x80000001", OT_ERROR_INVALID_ARGS, 0}, // Error case: Out of range (min - 1) {"", OT_ERROR_INVALID_ARGS, 0} // Empty string indicates end of the list }; VerifyParser(kBoolTestCases, "ParseAsBool", "%d"); VerifyParser(kUint8TestCases, "ParseAsUint8", "0x%02x"); VerifyParser(kUint16TestCases, "ParseAsUint16", "0x%04x"); VerifyParser(kUint32TestCases, "ParseAsUint32", "0x%08x"); VerifyParser(kUint64TestCases, "ParseAsUint64", "0x%016llx"); VerifyParser(kInt8TestCases, "ParseAsInt8", "%d"); VerifyParser(kInt16TestCases, "ParseAsInt16", "%d"); VerifyParser(kInt32TestCases, "ParseAsInt32", "%d"); } void TestParsingHexStrings(void) { const char kEvenHexString[] = "DeadBeefCafeBabe"; const uint8_t kEvenParsedArray[] = {0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe}; const char kOddHexString[] = "abcdef9876543"; const uint8_t kOddParsedArray[] = {0xa, 0xbc, 0xde, 0xf9, 0x87, 0x65, 0x43}; uint8_t buffer[sizeof(kEvenParsedArray)]; uint8_t buf3[3]; uint16_t len; const char *string; const uint8_t *bufPtr; // Verify `ParseAsHexString(const char *aString, uint8_t *aBuffer, uint16_t aSize)` buffer[0] = 0xff; SuccessOrQuit(ParseAsHexString("0", buffer, 1)); VerifyOrQuit(buffer[0] == 0, "ParseAsHexString() parsed incorrectly"); buffer[0] = 0; SuccessOrQuit(ParseAsHexString("7e", buffer, 1)); VerifyOrQuit(buffer[0] == 0x7e, "ParseAsHexString() parsed incorrectly"); VerifyOrQuit(ParseAsHexString("123", buffer, 1) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input"); SuccessOrQuit(ParseAsHexString("123", buffer, 2)); VerifyOrQuit(buffer[0] == 1 && buffer[1] == 0x23, "ParseAsHexString() parsed incorrectly"); VerifyOrQuit(ParseAsHexString("123x", buffer, 2) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input"); VerifyOrQuit(ParseAsHexString(" 123", buffer, 2) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input"); // Verify `ParseAsHexString()` VerifyOrQuit(ParseAsHexString("1122", buf3) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input"); VerifyOrQuit(ParseAsHexString("1122334", buf3) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input"); VerifyOrQuit(ParseAsHexString("11223344", buf3) != OT_ERROR_NONE, "ParseAsHexString() passed with bad input"); SuccessOrQuit(ParseAsHexString("abbade", buf3)); VerifyOrQuit(buf3[0] == 0xab && buf3[1] == 0xba && buf3[2] == 0xde, "ParseAsHexString() parsed incorrectly"); SuccessOrQuit(ParseAsHexString("012345", buf3)); VerifyOrQuit(buf3[0] == 0x01 && buf3[1] == 0x23 && buf3[2] == 0x45, "ParseAsHexString() parsed incorrectly"); SuccessOrQuit(ParseAsHexString("12345", buf3), "ParseAsHexString() failed with odd length"); VerifyOrQuit(buf3[0] == 0x01 && buf3[1] == 0x23 && buf3[2] == 0x45, "ParseAsHexString() parsed incorrectly"); SuccessOrQuit(ParseAsHexString(kEvenHexString, buffer), "ParseAsHexString failed"); VerifyOrQuit(memcmp(buffer, kEvenParsedArray, sizeof(buffer)) == 0, "ParseAsHexString() parsed incorrectly"); // Verify `ParseAsHexString(const char *aString, uint16_t &aSize, uint8_t *aBuffer)` printf("----------------------------------------------------------\n"); len = sizeof(buffer); SuccessOrQuit(ParseAsHexString(kEvenHexString, len, buffer)); VerifyOrQuit(len == sizeof(kEvenParsedArray), "ParseAsHexString() parsed incorrectly"); VerifyOrQuit(memcmp(buffer, kEvenParsedArray, len) == 0, "ParseAsHexString() parsed incorrectly"); DumpBuffer(kEvenHexString, buffer, len); SuccessOrQuit(ParseAsHexString(kOddHexString, len, buffer)); VerifyOrQuit(len == sizeof(kOddParsedArray), "ParseAsHexString() parsed incorrectly"); VerifyOrQuit(memcmp(buffer, kOddParsedArray, len) == 0, "ParseAsHexString() parsed incorrectly"); DumpBuffer(kOddHexString, buffer, len); // Verify `ParseAsHexStringSegement()` printf("----------------------------------------------------------\n"); for (uint8_t testIter = 0; testIter <= 1; testIter++) { for (size_t segmentLen = 1; segmentLen <= sizeof(buffer); segmentLen++) { if (testIter == 0) { string = kEvenHexString; bufPtr = kEvenParsedArray; } else { string = kOddHexString; bufPtr = kOddParsedArray; } len = segmentLen; printf("\"%s\" segLen:%zu -> ", string, segmentLen); while (true) { otError error = ParseAsHexStringSegment(string, len, buffer); printf("%d (\"%s\") ", len, string); if (error == OT_ERROR_NONE) { VerifyOrQuit(len <= segmentLen, "ParseAsHexStringSegment() parsed incorrectly"); VerifyOrQuit(memcmp(buffer, bufPtr, len) == 0, "ParseAsHexStringSegment() parsed incorrectly"); VerifyOrQuit(*string == '\0', "ParseAsHexStringSegment() failed to update string pointer correctly"); break; } VerifyOrQuit(error == OT_ERROR_PENDING, "ParseAsHexStringSegment() failed"); VerifyOrQuit(len == segmentLen, "ParseAsHexStringSegment() parsed incorrectly"); VerifyOrQuit(memcmp(buffer, bufPtr, len) == 0, "ParseAsHexStringSegment() parsed incorrectly"); bufPtr += len; } printf("\n"); } } } } // namespace ot int main(void) { ot::TestParsingInts(); ot::TestParsingHexStrings(); printf("All tests passed\n"); return 0; }