/** * Copyright © 2025 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "json_parser_utils.hpp" #include #include #include #include #include #include #include using namespace phosphor::power::json_parser_utils; using json = nlohmann::json; TEST(JSONParserUtilsTests, GetRequiredProperty) { // Test where property exists { const json element = R"( { "format": "linear" } )"_json; const json& propertyElement = getRequiredProperty(element, "format"); EXPECT_EQ(propertyElement.get(), "linear"); } // Test where property does not exist try { const json element = R"( { "volts": 1.03 } )"_json; getRequiredProperty(element, "format"); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Required property missing: format"); } } TEST(JSONParserUtilsTests, ParseBitPosition) { // Test where works: 0 { const json element = R"( 0 )"_json; uint8_t value = parseBitPosition(element); EXPECT_EQ(value, 0); } // Test where works: 7 { const json element = R"( 7 )"_json; uint8_t value = parseBitPosition(element); EXPECT_EQ(value, 7); } // Test where fails: Element is not an integer try { const json element = R"( 1.03 )"_json; parseBitPosition(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an integer"); } // Test where fails: Value < 0 try { const json element = R"( -1 )"_json; parseBitPosition(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not a bit position"); } // Test where fails: Value > 7 try { const json element = R"( 8 )"_json; parseBitPosition(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not a bit position"); } } TEST(JSONParserUtilsTests, ParseBitValue) { // Test where works: 0 { const json element = R"( 0 )"_json; uint8_t value = parseBitValue(element); EXPECT_EQ(value, 0); } // Test where works: 1 { const json element = R"( 1 )"_json; uint8_t value = parseBitValue(element); EXPECT_EQ(value, 1); } // Test where fails: Element is not an integer try { const json element = R"( 0.5 )"_json; parseBitValue(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an integer"); } // Test where fails: Value < 0 try { const json element = R"( -1 )"_json; parseBitValue(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not a bit value"); } // Test where fails: Value > 1 try { const json element = R"( 2 )"_json; parseBitValue(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not a bit value"); } } TEST(JSONParserUtilsTests, ParseBoolean) { // Test where works: true { const json element = R"( true )"_json; bool value = parseBoolean(element); EXPECT_EQ(value, true); } // Test where works: false { const json element = R"( false )"_json; bool value = parseBoolean(element); EXPECT_EQ(value, false); } // Test where fails: Element is not a boolean try { const json element = R"( 1 )"_json; parseBoolean(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not a boolean"); } } TEST(JSONParserUtilsTests, ParseDouble) { // Test where works: floating point value { const json element = R"( 1.03 )"_json; double value = parseDouble(element); EXPECT_EQ(value, 1.03); } // Test where works: integer value { const json element = R"( 24 )"_json; double value = parseDouble(element); EXPECT_EQ(value, 24.0); } // Test where fails: Element is not a number try { const json element = R"( true )"_json; parseDouble(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not a number"); } } TEST(JSONParserUtilsTests, ParseHexByte) { // Test where works: "0xFF" { const json element = R"( "0xFF" )"_json; uint8_t value = parseHexByte(element); EXPECT_EQ(value, 0xFF); } // Test where works: "0xff" { const json element = R"( "0xff" )"_json; uint8_t value = parseHexByte(element); EXPECT_EQ(value, 0xff); } // Test where works: "0xf" { const json element = R"( "0xf" )"_json; uint8_t value = parseHexByte(element); EXPECT_EQ(value, 0xf); } // Test where fails: "0xfff" try { const json element = R"( "0xfff" )"_json; parseHexByte(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); } // Test where fails: "0xAG" try { const json element = R"( "0xAG" )"_json; parseHexByte(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); } // Test where fails: "ff" try { const json element = R"( "ff" )"_json; parseHexByte(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); } // Test where fails: "" try { const json element = ""; parseHexByte(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); } // Test where fails: "f" try { const json element = R"( "f" )"_json; parseHexByte(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); } // Test where fails: "0x" try { const json element = R"( "0x" )"_json; parseHexByte(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); } // Test where fails: "0Xff" try { const json element = R"( "0XFF" )"_json; parseHexByte(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); } } TEST(JSONParserUtilsTests, ParseHexByteArray) { // Test where works { const json element = R"( [ "0xCC", "0xFF" ] )"_json; std::vector hexBytes = parseHexByteArray(element); std::vector expected = {0xcc, 0xff}; EXPECT_EQ(hexBytes, expected); } // Test where fails: Element is not an array try { const json element = 0; parseHexByteArray(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an array"); } } TEST(JSONParserUtilsTests, ParseInt8) { // Test where works: INT8_MIN { const json element = R"( -128 )"_json; int8_t value = parseInt8(element); EXPECT_EQ(value, -128); } // Test where works: INT8_MAX { const json element = R"( 127 )"_json; int8_t value = parseInt8(element); EXPECT_EQ(value, 127); } // Test where fails: Element is not an integer try { const json element = R"( 1.03 )"_json; parseInt8(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an integer"); } // Test where fails: Value < INT8_MIN try { const json element = R"( -129 )"_json; parseInt8(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); } // Test where fails: Value > INT8_MAX try { const json element = R"( 128 )"_json; parseInt8(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); } } TEST(JSONParserUtilsTests, ParseString) { // Test where works: Empty string { const json element = ""; std::string value = parseString(element, true); EXPECT_EQ(value, ""); } // Test where works: Non-empty string { const json element = "vdd_regulator"; std::string value = parseString(element, false); EXPECT_EQ(value, "vdd_regulator"); } // Test where fails: Element is not a string try { const json element = R"( { "foo": "bar" } )"_json; parseString(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not a string"); } // Test where fails: Empty string try { const json element = ""; parseString(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element contains an empty string"); } } TEST(JSONParserUtilsTests, ParseUint8) { // Test where works: 0 { const json element = R"( 0 )"_json; uint8_t value = parseUint8(element); EXPECT_EQ(value, 0); } // Test where works: UINT8_MAX { const json element = R"( 255 )"_json; uint8_t value = parseUint8(element); EXPECT_EQ(value, 255); } // Test where fails: Element is not an integer try { const json element = R"( 1.03 )"_json; parseUint8(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an integer"); } // Test where fails: Value < 0 try { const json element = R"( -1 )"_json; parseUint8(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); } // Test where fails: Value > UINT8_MAX try { const json element = R"( 256 )"_json; parseUint8(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); } } TEST(JSONParserUtilsTests, ParseUnsignedInteger) { // Test where works: 1 { const json element = R"( 1 )"_json; unsigned int value = parseUnsignedInteger(element); EXPECT_EQ(value, 1); } // Test where fails: Element is not an integer try { const json element = R"( 1.5 )"_json; parseUnsignedInteger(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); } // Test where fails: Value < 0 try { const json element = R"( -1 )"_json; parseUnsignedInteger(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); } } TEST(JSONParserUtilsTests, VerifyIsArray) { // Test where element is an array { const json element = R"( [ "foo", "bar" ] )"_json; verifyIsArray(element); } // Test where element is not an array try { const json element = R"( { "foo": "bar" } )"_json; verifyIsArray(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an array"); } } TEST(JSONParserUtilsTests, VerifyIsObject) { // Test where element is an object { const json element = R"( { "foo": "bar" } )"_json; verifyIsObject(element); } // Test where element is not an object try { const json element = R"( [ "foo", "bar" ] )"_json; verifyIsObject(element); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element is not an object"); } } TEST(JSONParserUtilsTests, VerifyPropertyCount) { // Test where element has expected number of properties { const json element = R"( { "comments": [ "Set voltage rule" ], "id": "set_voltage_rule" } )"_json; verifyPropertyCount(element, 2); } // Test where element has unexpected number of properties try { const json element = R"( { "comments": [ "Set voltage rule" ], "id": "set_voltage_rule", "foo": 1.3 } )"_json; verifyPropertyCount(element, 2); ADD_FAILURE() << "Should not have reached this line."; } catch (const std::invalid_argument& e) { EXPECT_STREQ(e.what(), "Element contains an invalid property"); } }