1 /** 2 * Copyright © 2025 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "json_parser_utils.hpp" 17 18 #include <nlohmann/json.hpp> 19 20 #include <cstdint> 21 #include <exception> 22 #include <stdexcept> 23 #include <string> 24 #include <vector> 25 26 #include <gtest/gtest.h> 27 28 using namespace phosphor::power::json_parser_utils; 29 using json = nlohmann::json; 30 31 TEST(JSONParserUtilsTests, GetRequiredProperty) 32 { 33 // Test where property exists 34 { 35 const json element = R"( { "format": "linear" } )"_json; 36 const json& propertyElement = getRequiredProperty(element, "format"); 37 EXPECT_EQ(propertyElement.get<std::string>(), "linear"); 38 } 39 40 // Test where property does not exist 41 try 42 { 43 const json element = R"( { "volts": 1.03 } )"_json; 44 getRequiredProperty(element, "format"); 45 ADD_FAILURE() << "Should not have reached this line."; 46 } 47 catch (const std::invalid_argument& e) 48 { 49 EXPECT_STREQ(e.what(), "Required property missing: format"); 50 } 51 } 52 53 TEST(JSONParserUtilsTests, ParseBitPosition) 54 { 55 // Test where works: 0 56 { 57 const json element = R"( 0 )"_json; 58 uint8_t value = parseBitPosition(element); 59 EXPECT_EQ(value, 0); 60 } 61 62 // Test where works: 7 63 { 64 const json element = R"( 7 )"_json; 65 uint8_t value = parseBitPosition(element); 66 EXPECT_EQ(value, 7); 67 } 68 69 // Test where fails: Element is not an integer 70 try 71 { 72 const json element = R"( 1.03 )"_json; 73 parseBitPosition(element); 74 ADD_FAILURE() << "Should not have reached this line."; 75 } 76 catch (const std::invalid_argument& e) 77 { 78 EXPECT_STREQ(e.what(), "Element is not an integer"); 79 } 80 81 // Test where fails: Value < 0 82 try 83 { 84 const json element = R"( -1 )"_json; 85 parseBitPosition(element); 86 ADD_FAILURE() << "Should not have reached this line."; 87 } 88 catch (const std::invalid_argument& e) 89 { 90 EXPECT_STREQ(e.what(), "Element is not a bit position"); 91 } 92 93 // Test where fails: Value > 7 94 try 95 { 96 const json element = R"( 8 )"_json; 97 parseBitPosition(element); 98 ADD_FAILURE() << "Should not have reached this line."; 99 } 100 catch (const std::invalid_argument& e) 101 { 102 EXPECT_STREQ(e.what(), "Element is not a bit position"); 103 } 104 } 105 106 TEST(JSONParserUtilsTests, ParseBitValue) 107 { 108 // Test where works: 0 109 { 110 const json element = R"( 0 )"_json; 111 uint8_t value = parseBitValue(element); 112 EXPECT_EQ(value, 0); 113 } 114 115 // Test where works: 1 116 { 117 const json element = R"( 1 )"_json; 118 uint8_t value = parseBitValue(element); 119 EXPECT_EQ(value, 1); 120 } 121 122 // Test where fails: Element is not an integer 123 try 124 { 125 const json element = R"( 0.5 )"_json; 126 parseBitValue(element); 127 ADD_FAILURE() << "Should not have reached this line."; 128 } 129 catch (const std::invalid_argument& e) 130 { 131 EXPECT_STREQ(e.what(), "Element is not an integer"); 132 } 133 134 // Test where fails: Value < 0 135 try 136 { 137 const json element = R"( -1 )"_json; 138 parseBitValue(element); 139 ADD_FAILURE() << "Should not have reached this line."; 140 } 141 catch (const std::invalid_argument& e) 142 { 143 EXPECT_STREQ(e.what(), "Element is not a bit value"); 144 } 145 146 // Test where fails: Value > 1 147 try 148 { 149 const json element = R"( 2 )"_json; 150 parseBitValue(element); 151 ADD_FAILURE() << "Should not have reached this line."; 152 } 153 catch (const std::invalid_argument& e) 154 { 155 EXPECT_STREQ(e.what(), "Element is not a bit value"); 156 } 157 } 158 159 TEST(JSONParserUtilsTests, ParseBoolean) 160 { 161 // Test where works: true 162 { 163 const json element = R"( true )"_json; 164 bool value = parseBoolean(element); 165 EXPECT_EQ(value, true); 166 } 167 168 // Test where works: false 169 { 170 const json element = R"( false )"_json; 171 bool value = parseBoolean(element); 172 EXPECT_EQ(value, false); 173 } 174 175 // Test where fails: Element is not a boolean 176 try 177 { 178 const json element = R"( 1 )"_json; 179 parseBoolean(element); 180 ADD_FAILURE() << "Should not have reached this line."; 181 } 182 catch (const std::invalid_argument& e) 183 { 184 EXPECT_STREQ(e.what(), "Element is not a boolean"); 185 } 186 } 187 188 TEST(JSONParserUtilsTests, ParseDouble) 189 { 190 // Test where works: floating point value 191 { 192 const json element = R"( 1.03 )"_json; 193 double value = parseDouble(element); 194 EXPECT_EQ(value, 1.03); 195 } 196 197 // Test where works: integer value 198 { 199 const json element = R"( 24 )"_json; 200 double value = parseDouble(element); 201 EXPECT_EQ(value, 24.0); 202 } 203 204 // Test where fails: Element is not a number 205 try 206 { 207 const json element = R"( true )"_json; 208 parseDouble(element); 209 ADD_FAILURE() << "Should not have reached this line."; 210 } 211 catch (const std::invalid_argument& e) 212 { 213 EXPECT_STREQ(e.what(), "Element is not a number"); 214 } 215 } 216 217 TEST(JSONParserUtilsTests, ParseHexByte) 218 { 219 // Test where works: "0xFF" 220 { 221 const json element = R"( "0xFF" )"_json; 222 uint8_t value = parseHexByte(element); 223 EXPECT_EQ(value, 0xFF); 224 } 225 226 // Test where works: "0xff" 227 { 228 const json element = R"( "0xff" )"_json; 229 uint8_t value = parseHexByte(element); 230 EXPECT_EQ(value, 0xff); 231 } 232 233 // Test where works: "0xf" 234 { 235 const json element = R"( "0xf" )"_json; 236 uint8_t value = parseHexByte(element); 237 EXPECT_EQ(value, 0xf); 238 } 239 240 // Test where fails: "0xfff" 241 try 242 { 243 const json element = R"( "0xfff" )"_json; 244 parseHexByte(element); 245 ADD_FAILURE() << "Should not have reached this line."; 246 } 247 catch (const std::invalid_argument& e) 248 { 249 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 250 } 251 252 // Test where fails: "0xAG" 253 try 254 { 255 const json element = R"( "0xAG" )"_json; 256 parseHexByte(element); 257 ADD_FAILURE() << "Should not have reached this line."; 258 } 259 catch (const std::invalid_argument& e) 260 { 261 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 262 } 263 264 // Test where fails: "ff" 265 try 266 { 267 const json element = R"( "ff" )"_json; 268 parseHexByte(element); 269 ADD_FAILURE() << "Should not have reached this line."; 270 } 271 catch (const std::invalid_argument& e) 272 { 273 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 274 } 275 276 // Test where fails: "" 277 try 278 { 279 const json element = ""; 280 parseHexByte(element); 281 ADD_FAILURE() << "Should not have reached this line."; 282 } 283 catch (const std::invalid_argument& e) 284 { 285 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 286 } 287 288 // Test where fails: "f" 289 try 290 { 291 const json element = R"( "f" )"_json; 292 parseHexByte(element); 293 ADD_FAILURE() << "Should not have reached this line."; 294 } 295 catch (const std::invalid_argument& e) 296 { 297 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 298 } 299 300 // Test where fails: "0x" 301 try 302 { 303 const json element = R"( "0x" )"_json; 304 parseHexByte(element); 305 ADD_FAILURE() << "Should not have reached this line."; 306 } 307 catch (const std::invalid_argument& e) 308 { 309 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 310 } 311 312 // Test where fails: "0Xff" 313 try 314 { 315 const json element = R"( "0XFF" )"_json; 316 parseHexByte(element); 317 ADD_FAILURE() << "Should not have reached this line."; 318 } 319 catch (const std::invalid_argument& e) 320 { 321 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 322 } 323 } 324 325 TEST(JSONParserUtilsTests, ParseHexByteArray) 326 { 327 // Test where works 328 { 329 const json element = R"( [ "0xCC", "0xFF" ] )"_json; 330 std::vector<uint8_t> hexBytes = parseHexByteArray(element); 331 std::vector<uint8_t> expected = {0xcc, 0xff}; 332 EXPECT_EQ(hexBytes, expected); 333 } 334 335 // Test where fails: Element is not an array 336 try 337 { 338 const json element = 0; 339 parseHexByteArray(element); 340 ADD_FAILURE() << "Should not have reached this line."; 341 } 342 catch (const std::invalid_argument& e) 343 { 344 EXPECT_STREQ(e.what(), "Element is not an array"); 345 } 346 } 347 348 TEST(JSONParserUtilsTests, ParseInt8) 349 { 350 // Test where works: INT8_MIN 351 { 352 const json element = R"( -128 )"_json; 353 int8_t value = parseInt8(element); 354 EXPECT_EQ(value, -128); 355 } 356 357 // Test where works: INT8_MAX 358 { 359 const json element = R"( 127 )"_json; 360 int8_t value = parseInt8(element); 361 EXPECT_EQ(value, 127); 362 } 363 364 // Test where fails: Element is not an integer 365 try 366 { 367 const json element = R"( 1.03 )"_json; 368 parseInt8(element); 369 ADD_FAILURE() << "Should not have reached this line."; 370 } 371 catch (const std::invalid_argument& e) 372 { 373 EXPECT_STREQ(e.what(), "Element is not an integer"); 374 } 375 376 // Test where fails: Value < INT8_MIN 377 try 378 { 379 const json element = R"( -129 )"_json; 380 parseInt8(element); 381 ADD_FAILURE() << "Should not have reached this line."; 382 } 383 catch (const std::invalid_argument& e) 384 { 385 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 386 } 387 388 // Test where fails: Value > INT8_MAX 389 try 390 { 391 const json element = R"( 128 )"_json; 392 parseInt8(element); 393 ADD_FAILURE() << "Should not have reached this line."; 394 } 395 catch (const std::invalid_argument& e) 396 { 397 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 398 } 399 } 400 401 TEST(JSONParserUtilsTests, ParseString) 402 { 403 // Test where works: Empty string 404 { 405 const json element = ""; 406 std::string value = parseString(element, true); 407 EXPECT_EQ(value, ""); 408 } 409 410 // Test where works: Non-empty string 411 { 412 const json element = "vdd_regulator"; 413 std::string value = parseString(element, false); 414 EXPECT_EQ(value, "vdd_regulator"); 415 } 416 417 // Test where fails: Element is not a string 418 try 419 { 420 const json element = R"( { "foo": "bar" } )"_json; 421 parseString(element); 422 ADD_FAILURE() << "Should not have reached this line."; 423 } 424 catch (const std::invalid_argument& e) 425 { 426 EXPECT_STREQ(e.what(), "Element is not a string"); 427 } 428 429 // Test where fails: Empty string 430 try 431 { 432 const json element = ""; 433 parseString(element); 434 ADD_FAILURE() << "Should not have reached this line."; 435 } 436 catch (const std::invalid_argument& e) 437 { 438 EXPECT_STREQ(e.what(), "Element contains an empty string"); 439 } 440 } 441 442 TEST(JSONParserUtilsTests, ParseUint8) 443 { 444 // Test where works: 0 445 { 446 const json element = R"( 0 )"_json; 447 uint8_t value = parseUint8(element); 448 EXPECT_EQ(value, 0); 449 } 450 451 // Test where works: UINT8_MAX 452 { 453 const json element = R"( 255 )"_json; 454 uint8_t value = parseUint8(element); 455 EXPECT_EQ(value, 255); 456 } 457 458 // Test where fails: Element is not an integer 459 try 460 { 461 const json element = R"( 1.03 )"_json; 462 parseUint8(element); 463 ADD_FAILURE() << "Should not have reached this line."; 464 } 465 catch (const std::invalid_argument& e) 466 { 467 EXPECT_STREQ(e.what(), "Element is not an integer"); 468 } 469 470 // Test where fails: Value < 0 471 try 472 { 473 const json element = R"( -1 )"_json; 474 parseUint8(element); 475 ADD_FAILURE() << "Should not have reached this line."; 476 } 477 catch (const std::invalid_argument& e) 478 { 479 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); 480 } 481 482 // Test where fails: Value > UINT8_MAX 483 try 484 { 485 const json element = R"( 256 )"_json; 486 parseUint8(element); 487 ADD_FAILURE() << "Should not have reached this line."; 488 } 489 catch (const std::invalid_argument& e) 490 { 491 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); 492 } 493 } 494 495 TEST(JSONParserUtilsTests, ParseUnsignedInteger) 496 { 497 // Test where works: 1 498 { 499 const json element = R"( 1 )"_json; 500 unsigned int value = parseUnsignedInteger(element); 501 EXPECT_EQ(value, 1); 502 } 503 504 // Test where fails: Element is not an integer 505 try 506 { 507 const json element = R"( 1.5 )"_json; 508 parseUnsignedInteger(element); 509 ADD_FAILURE() << "Should not have reached this line."; 510 } 511 catch (const std::invalid_argument& e) 512 { 513 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 514 } 515 516 // Test where fails: Value < 0 517 try 518 { 519 const json element = R"( -1 )"_json; 520 parseUnsignedInteger(element); 521 ADD_FAILURE() << "Should not have reached this line."; 522 } 523 catch (const std::invalid_argument& e) 524 { 525 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 526 } 527 } 528 529 TEST(JSONParserUtilsTests, VerifyIsArray) 530 { 531 // Test where element is an array 532 { 533 const json element = R"( [ "foo", "bar" ] )"_json; 534 verifyIsArray(element); 535 } 536 537 // Test where element is not an array 538 try 539 { 540 const json element = R"( { "foo": "bar" } )"_json; 541 verifyIsArray(element); 542 ADD_FAILURE() << "Should not have reached this line."; 543 } 544 catch (const std::invalid_argument& e) 545 { 546 EXPECT_STREQ(e.what(), "Element is not an array"); 547 } 548 } 549 550 TEST(JSONParserUtilsTests, VerifyIsObject) 551 { 552 // Test where element is an object 553 { 554 const json element = R"( { "foo": "bar" } )"_json; 555 verifyIsObject(element); 556 } 557 558 // Test where element is not an object 559 try 560 { 561 const json element = R"( [ "foo", "bar" ] )"_json; 562 verifyIsObject(element); 563 ADD_FAILURE() << "Should not have reached this line."; 564 } 565 catch (const std::invalid_argument& e) 566 { 567 EXPECT_STREQ(e.what(), "Element is not an object"); 568 } 569 } 570 571 TEST(JSONParserUtilsTests, VerifyPropertyCount) 572 { 573 // Test where element has expected number of properties 574 { 575 const json element = R"( 576 { 577 "comments": [ "Set voltage rule" ], 578 "id": "set_voltage_rule" 579 } 580 )"_json; 581 verifyPropertyCount(element, 2); 582 } 583 584 // Test where element has unexpected number of properties 585 try 586 { 587 const json element = R"( 588 { 589 "comments": [ "Set voltage rule" ], 590 "id": "set_voltage_rule", 591 "foo": 1.3 592 } 593 )"_json; 594 verifyPropertyCount(element, 2); 595 ADD_FAILURE() << "Should not have reached this line."; 596 } 597 catch (const std::invalid_argument& e) 598 { 599 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 600 } 601 } 602