1 /** 2 * Copyright © 2020 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 "action.hpp" 17 #include "and_action.hpp" 18 #include "chassis.hpp" 19 #include "compare_presence_action.hpp" 20 #include "compare_vpd_action.hpp" 21 #include "config_file_parser.hpp" 22 #include "config_file_parser_error.hpp" 23 #include "configuration.hpp" 24 #include "device.hpp" 25 #include "i2c_capture_bytes_action.hpp" 26 #include "i2c_compare_bit_action.hpp" 27 #include "i2c_compare_byte_action.hpp" 28 #include "i2c_compare_bytes_action.hpp" 29 #include "i2c_interface.hpp" 30 #include "i2c_write_bit_action.hpp" 31 #include "i2c_write_byte_action.hpp" 32 #include "i2c_write_bytes_action.hpp" 33 #include "log_phase_fault_action.hpp" 34 #include "not_action.hpp" 35 #include "or_action.hpp" 36 #include "phase_fault.hpp" 37 #include "phase_fault_detection.hpp" 38 #include "pmbus_read_sensor_action.hpp" 39 #include "pmbus_utils.hpp" 40 #include "pmbus_write_vout_command_action.hpp" 41 #include "presence_detection.hpp" 42 #include "rail.hpp" 43 #include "rule.hpp" 44 #include "run_rule_action.hpp" 45 #include "sensor_monitoring.hpp" 46 #include "sensors.hpp" 47 #include "set_device_action.hpp" 48 #include "temporary_file.hpp" 49 50 #include <sys/stat.h> // for chmod() 51 52 #include <nlohmann/json.hpp> 53 54 #include <cstdint> 55 #include <cstring> 56 #include <exception> 57 #include <filesystem> 58 #include <fstream> 59 #include <memory> 60 #include <optional> 61 #include <stdexcept> 62 #include <string> 63 #include <tuple> 64 #include <vector> 65 66 #include <gtest/gtest.h> 67 68 using namespace phosphor::power::regulators; 69 using namespace phosphor::power::regulators::config_file_parser; 70 using namespace phosphor::power::regulators::config_file_parser::internal; 71 using json = nlohmann::json; 72 using TemporaryFile = phosphor::power::util::TemporaryFile; 73 74 void writeConfigFile(const std::filesystem::path& pathName, 75 const std::string& contents) 76 { 77 std::ofstream file{pathName}; 78 file << contents; 79 } 80 81 void writeConfigFile(const std::filesystem::path& pathName, 82 const json& contents) 83 { 84 std::ofstream file{pathName}; 85 file << contents; 86 } 87 88 TEST(ConfigFileParserTests, Parse) 89 { 90 // Test where works 91 { 92 const json configFileContents = R"( 93 { 94 "rules": [ 95 { 96 "id": "set_voltage_rule1", 97 "actions": [ 98 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 99 ] 100 }, 101 { 102 "id": "set_voltage_rule2", 103 "actions": [ 104 { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } } 105 ] 106 } 107 ], 108 "chassis": [ 109 { "number": 1, "inventory_path": "system/chassis1" }, 110 { "number": 2, "inventory_path": "system/chassis2" }, 111 { "number": 3, "inventory_path": "system/chassis3" } 112 ] 113 } 114 )"_json; 115 116 TemporaryFile configFile; 117 std::filesystem::path pathName{configFile.getPath()}; 118 writeConfigFile(pathName, configFileContents); 119 120 std::vector<std::unique_ptr<Rule>> rules{}; 121 std::vector<std::unique_ptr<Chassis>> chassis{}; 122 std::tie(rules, chassis) = parse(pathName); 123 124 EXPECT_EQ(rules.size(), 2); 125 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 126 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 127 128 EXPECT_EQ(chassis.size(), 3); 129 EXPECT_EQ(chassis[0]->getNumber(), 1); 130 EXPECT_EQ(chassis[0]->getInventoryPath(), 131 "/xyz/openbmc_project/inventory/system/chassis1"); 132 EXPECT_EQ(chassis[1]->getNumber(), 2); 133 EXPECT_EQ(chassis[1]->getInventoryPath(), 134 "/xyz/openbmc_project/inventory/system/chassis2"); 135 EXPECT_EQ(chassis[2]->getNumber(), 3); 136 EXPECT_EQ(chassis[2]->getInventoryPath(), 137 "/xyz/openbmc_project/inventory/system/chassis3"); 138 } 139 140 // Test where fails: File does not exist 141 try 142 { 143 std::filesystem::path pathName{"/tmp/non_existent_file"}; 144 parse(pathName); 145 ADD_FAILURE() << "Should not have reached this line."; 146 } 147 catch (const ConfigFileParserError& e) 148 { 149 // Expected exception; what() message will vary 150 } 151 152 // Test where fails: File is not readable 153 try 154 { 155 const json configFileContents = R"( 156 { 157 "chassis": [ 158 { "number": 1, "inventory_path": "system/chassis1" } 159 ] 160 } 161 )"_json; 162 163 TemporaryFile configFile; 164 std::filesystem::path pathName{configFile.getPath()}; 165 writeConfigFile(pathName, configFileContents); 166 167 chmod(pathName.c_str(), 0222); 168 169 parse(pathName); 170 ADD_FAILURE() << "Should not have reached this line."; 171 } 172 catch (const ConfigFileParserError& e) 173 { 174 // Expected exception; what() message will vary 175 } 176 177 // Test where fails: File is not valid JSON 178 try 179 { 180 const std::string configFileContents = "] foo ["; 181 182 TemporaryFile configFile; 183 std::filesystem::path pathName{configFile.getPath()}; 184 writeConfigFile(pathName, configFileContents); 185 186 parse(pathName); 187 ADD_FAILURE() << "Should not have reached this line."; 188 } 189 catch (const ConfigFileParserError& e) 190 { 191 // Expected exception; what() message will vary 192 } 193 194 // Test where fails: Error when parsing JSON elements 195 try 196 { 197 const json configFileContents = R"( { "foo": "bar" } )"_json; 198 199 TemporaryFile configFile; 200 std::filesystem::path pathName{configFile.getPath()}; 201 writeConfigFile(pathName, configFileContents); 202 203 parse(pathName); 204 ADD_FAILURE() << "Should not have reached this line."; 205 } 206 catch (const ConfigFileParserError& e) 207 { 208 // Expected exception; what() message will vary 209 } 210 } 211 212 TEST(ConfigFileParserTests, GetRequiredProperty) 213 { 214 // Test where property exists 215 { 216 const json element = R"( { "format": "linear" } )"_json; 217 const json& propertyElement = getRequiredProperty(element, "format"); 218 EXPECT_EQ(propertyElement.get<std::string>(), "linear"); 219 } 220 221 // Test where property does not exist 222 try 223 { 224 const json element = R"( { "volts": 1.03 } )"_json; 225 getRequiredProperty(element, "format"); 226 ADD_FAILURE() << "Should not have reached this line."; 227 } 228 catch (const std::invalid_argument& e) 229 { 230 EXPECT_STREQ(e.what(), "Required property missing: format"); 231 } 232 } 233 234 TEST(ConfigFileParserTests, ParseAction) 235 { 236 // Test where works: comments property specified 237 { 238 const json element = R"( 239 { 240 "comments": [ "Set output voltage." ], 241 "pmbus_write_vout_command": { 242 "format": "linear" 243 } 244 } 245 )"_json; 246 std::unique_ptr<Action> action = parseAction(element); 247 EXPECT_NE(action.get(), nullptr); 248 } 249 250 // Test where works: comments property not specified 251 { 252 const json element = R"( 253 { 254 "pmbus_write_vout_command": { 255 "format": "linear" 256 } 257 } 258 )"_json; 259 std::unique_ptr<Action> action = parseAction(element); 260 EXPECT_NE(action.get(), nullptr); 261 } 262 263 // Test where works: and action type specified 264 { 265 const json element = R"( 266 { 267 "and": [ 268 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 269 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 270 ] 271 } 272 )"_json; 273 std::unique_ptr<Action> action = parseAction(element); 274 EXPECT_NE(action.get(), nullptr); 275 } 276 277 // Test where works: compare_presence action type specified 278 { 279 const json element = R"( 280 { 281 "compare_presence": 282 { 283 "fru": "system/chassis/motherboard/cpu3", 284 "value": true 285 } 286 } 287 )"_json; 288 std::unique_ptr<Action> action = parseAction(element); 289 EXPECT_NE(action.get(), nullptr); 290 } 291 292 // Test where works: compare_vpd action type specified 293 { 294 const json element = R"( 295 { 296 "compare_vpd": 297 { 298 "fru": "system/chassis/disk_backplane", 299 "keyword": "CCIN", 300 "value": "2D35" 301 } 302 } 303 )"_json; 304 std::unique_ptr<Action> action = parseAction(element); 305 EXPECT_NE(action.get(), nullptr); 306 } 307 308 // Test where works: i2c_capture_bytes action type specified 309 { 310 const json element = R"( 311 { 312 "i2c_capture_bytes": { 313 "register": "0xA0", 314 "count": 2 315 } 316 } 317 )"_json; 318 std::unique_ptr<Action> action = parseAction(element); 319 EXPECT_NE(action.get(), nullptr); 320 } 321 322 // Test where works: i2c_compare_bit action type specified 323 { 324 const json element = R"( 325 { 326 "i2c_compare_bit": { 327 "register": "0xA0", 328 "position": 3, 329 "value": 0 330 } 331 } 332 )"_json; 333 std::unique_ptr<Action> action = parseAction(element); 334 EXPECT_NE(action.get(), nullptr); 335 } 336 337 // Test where works: i2c_compare_byte action type specified 338 { 339 const json element = R"( 340 { 341 "i2c_compare_byte": { 342 "register": "0x0A", 343 "value": "0xCC" 344 } 345 } 346 )"_json; 347 std::unique_ptr<Action> action = parseAction(element); 348 EXPECT_NE(action.get(), nullptr); 349 } 350 351 // Test where works: i2c_compare_bytes action type specified 352 { 353 const json element = R"( 354 { 355 "i2c_compare_bytes": { 356 "register": "0x0A", 357 "values": [ "0xCC", "0xFF" ] 358 } 359 } 360 )"_json; 361 std::unique_ptr<Action> action = parseAction(element); 362 EXPECT_NE(action.get(), nullptr); 363 } 364 365 // Test where works: i2c_write_bit action type specified 366 { 367 const json element = R"( 368 { 369 "i2c_write_bit": { 370 "register": "0xA0", 371 "position": 3, 372 "value": 0 373 } 374 } 375 )"_json; 376 std::unique_ptr<Action> action = parseAction(element); 377 EXPECT_NE(action.get(), nullptr); 378 } 379 380 // Test where works: i2c_write_byte action type specified 381 { 382 const json element = R"( 383 { 384 "i2c_write_byte": { 385 "register": "0x0A", 386 "value": "0xCC" 387 } 388 } 389 )"_json; 390 std::unique_ptr<Action> action = parseAction(element); 391 EXPECT_NE(action.get(), nullptr); 392 } 393 394 // Test where works: i2c_write_bytes action type specified 395 { 396 const json element = R"( 397 { 398 "i2c_write_bytes": { 399 "register": "0x0A", 400 "values": [ "0xCC", "0xFF" ] 401 } 402 } 403 )"_json; 404 std::unique_ptr<Action> action = parseAction(element); 405 EXPECT_NE(action.get(), nullptr); 406 } 407 408 // Test where works: if action type specified 409 { 410 const json element = R"( 411 { 412 "if": 413 { 414 "condition": { "run_rule": "is_downlevel_regulator" }, 415 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 416 "else": [ { "run_rule": "configure_standard_regulator" } ] 417 } 418 } 419 )"_json; 420 std::unique_ptr<Action> action = parseAction(element); 421 EXPECT_NE(action.get(), nullptr); 422 } 423 424 // Test where works: log_phase_fault action type specified 425 { 426 const json element = R"( 427 { 428 "log_phase_fault": { 429 "type": "n+1" 430 } 431 } 432 )"_json; 433 std::unique_ptr<Action> action = parseAction(element); 434 EXPECT_NE(action.get(), nullptr); 435 } 436 437 // Test where works: not action type specified 438 { 439 const json element = R"( 440 { 441 "not": 442 { "i2c_compare_byte": { "register": "0xA0", "value": "0xFF" } } 443 } 444 )"_json; 445 std::unique_ptr<Action> action = parseAction(element); 446 EXPECT_NE(action.get(), nullptr); 447 } 448 449 // Test where works: or action type specified 450 { 451 const json element = R"( 452 { 453 "or": [ 454 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 455 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 456 ] 457 } 458 )"_json; 459 std::unique_ptr<Action> action = parseAction(element); 460 EXPECT_NE(action.get(), nullptr); 461 } 462 463 // Test where works: pmbus_read_sensor action type specified 464 { 465 const json element = R"( 466 { 467 "pmbus_read_sensor": { 468 "type": "iout", 469 "command": "0x8C", 470 "format": "linear_11" 471 } 472 } 473 )"_json; 474 std::unique_ptr<Action> action = parseAction(element); 475 EXPECT_NE(action.get(), nullptr); 476 } 477 478 // Test where works: pmbus_write_vout_command action type specified 479 { 480 const json element = R"( 481 { 482 "pmbus_write_vout_command": { 483 "format": "linear" 484 } 485 } 486 )"_json; 487 std::unique_ptr<Action> action = parseAction(element); 488 EXPECT_NE(action.get(), nullptr); 489 } 490 491 // Test where works: run_rule action type specified 492 { 493 const json element = R"( 494 { 495 "run_rule": "set_voltage_rule" 496 } 497 )"_json; 498 std::unique_ptr<Action> action = parseAction(element); 499 EXPECT_NE(action.get(), nullptr); 500 } 501 502 // Test where works: set_device action type specified 503 { 504 const json element = R"( 505 { 506 "set_device": "io_expander2" 507 } 508 )"_json; 509 std::unique_ptr<Action> action = parseAction(element); 510 EXPECT_NE(action.get(), nullptr); 511 } 512 513 // Test where fails: Element is not an object 514 try 515 { 516 const json element = R"( [ "0xFF", "0x01" ] )"_json; 517 parseAction(element); 518 ADD_FAILURE() << "Should not have reached this line."; 519 } 520 catch (const std::invalid_argument& e) 521 { 522 EXPECT_STREQ(e.what(), "Element is not an object"); 523 } 524 525 // Test where fails: No action type specified 526 try 527 { 528 const json element = R"( 529 { 530 "comments": [ "Set output voltage." ] 531 } 532 )"_json; 533 parseAction(element); 534 ADD_FAILURE() << "Should not have reached this line."; 535 } 536 catch (const std::invalid_argument& e) 537 { 538 EXPECT_STREQ(e.what(), "Required action type property missing"); 539 } 540 541 // Test where fails: Multiple action types specified 542 try 543 { 544 const json element = R"( 545 { 546 "pmbus_write_vout_command": { "format": "linear" }, 547 "run_rule": "set_voltage_rule" 548 } 549 )"_json; 550 parseAction(element); 551 ADD_FAILURE() << "Should not have reached this line."; 552 } 553 catch (const std::invalid_argument& e) 554 { 555 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 556 } 557 558 // Test where fails: Invalid property specified 559 try 560 { 561 const json element = R"( 562 { 563 "remarks": [ "Set output voltage." ], 564 "pmbus_write_vout_command": { 565 "format": "linear" 566 } 567 } 568 )"_json; 569 parseAction(element); 570 ADD_FAILURE() << "Should not have reached this line."; 571 } 572 catch (const std::invalid_argument& e) 573 { 574 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 575 } 576 } 577 578 TEST(ConfigFileParserTests, ParseActionArray) 579 { 580 // Test where works 581 { 582 const json element = R"( 583 [ 584 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 585 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 586 ] 587 )"_json; 588 std::vector<std::unique_ptr<Action>> actions = 589 parseActionArray(element); 590 EXPECT_EQ(actions.size(), 2); 591 } 592 593 // Test where fails: Element is not an array 594 try 595 { 596 const json element = R"( 597 { 598 "foo": "bar" 599 } 600 )"_json; 601 parseActionArray(element); 602 ADD_FAILURE() << "Should not have reached this line."; 603 } 604 catch (const std::invalid_argument& e) 605 { 606 EXPECT_STREQ(e.what(), "Element is not an array"); 607 } 608 } 609 610 TEST(ConfigFileParserTests, ParseAnd) 611 { 612 // Test where works: Element is an array with 2 actions 613 { 614 const json element = R"( 615 [ 616 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 617 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 618 ] 619 )"_json; 620 std::unique_ptr<AndAction> action = parseAnd(element); 621 EXPECT_EQ(action->getActions().size(), 2); 622 } 623 624 // Test where fails: Element is an array with 1 action 625 try 626 { 627 const json element = R"( 628 [ 629 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } } 630 ] 631 )"_json; 632 parseAnd(element); 633 ADD_FAILURE() << "Should not have reached this line."; 634 } 635 catch (const std::invalid_argument& e) 636 { 637 EXPECT_STREQ(e.what(), "Array must contain two or more actions"); 638 } 639 640 // Test where fails: Element is not an array 641 try 642 { 643 const json element = R"( 644 { 645 "foo": "bar" 646 } 647 )"_json; 648 parseAnd(element); 649 ADD_FAILURE() << "Should not have reached this line."; 650 } 651 catch (const std::invalid_argument& e) 652 { 653 EXPECT_STREQ(e.what(), "Element is not an array"); 654 } 655 } 656 657 TEST(ConfigFileParserTests, ParseBitPosition) 658 { 659 // Test where works: 0 660 { 661 const json element = R"( 0 )"_json; 662 uint8_t value = parseBitPosition(element); 663 EXPECT_EQ(value, 0); 664 } 665 666 // Test where works: 7 667 { 668 const json element = R"( 7 )"_json; 669 uint8_t value = parseBitPosition(element); 670 EXPECT_EQ(value, 7); 671 } 672 673 // Test where fails: Element is not an integer 674 try 675 { 676 const json element = R"( 1.03 )"_json; 677 parseBitPosition(element); 678 ADD_FAILURE() << "Should not have reached this line."; 679 } 680 catch (const std::invalid_argument& e) 681 { 682 EXPECT_STREQ(e.what(), "Element is not an integer"); 683 } 684 685 // Test where fails: Value < 0 686 try 687 { 688 const json element = R"( -1 )"_json; 689 parseBitPosition(element); 690 ADD_FAILURE() << "Should not have reached this line."; 691 } 692 catch (const std::invalid_argument& e) 693 { 694 EXPECT_STREQ(e.what(), "Element is not a bit position"); 695 } 696 697 // Test where fails: Value > 7 698 try 699 { 700 const json element = R"( 8 )"_json; 701 parseBitPosition(element); 702 ADD_FAILURE() << "Should not have reached this line."; 703 } 704 catch (const std::invalid_argument& e) 705 { 706 EXPECT_STREQ(e.what(), "Element is not a bit position"); 707 } 708 } 709 710 TEST(ConfigFileParserTests, ParseBitValue) 711 { 712 // Test where works: 0 713 { 714 const json element = R"( 0 )"_json; 715 uint8_t value = parseBitValue(element); 716 EXPECT_EQ(value, 0); 717 } 718 719 // Test where works: 1 720 { 721 const json element = R"( 1 )"_json; 722 uint8_t value = parseBitValue(element); 723 EXPECT_EQ(value, 1); 724 } 725 726 // Test where fails: Element is not an integer 727 try 728 { 729 const json element = R"( 0.5 )"_json; 730 parseBitValue(element); 731 ADD_FAILURE() << "Should not have reached this line."; 732 } 733 catch (const std::invalid_argument& e) 734 { 735 EXPECT_STREQ(e.what(), "Element is not an integer"); 736 } 737 738 // Test where fails: Value < 0 739 try 740 { 741 const json element = R"( -1 )"_json; 742 parseBitValue(element); 743 ADD_FAILURE() << "Should not have reached this line."; 744 } 745 catch (const std::invalid_argument& e) 746 { 747 EXPECT_STREQ(e.what(), "Element is not a bit value"); 748 } 749 750 // Test where fails: Value > 1 751 try 752 { 753 const json element = R"( 2 )"_json; 754 parseBitValue(element); 755 ADD_FAILURE() << "Should not have reached this line."; 756 } 757 catch (const std::invalid_argument& e) 758 { 759 EXPECT_STREQ(e.what(), "Element is not a bit value"); 760 } 761 } 762 763 TEST(ConfigFileParserTests, ParseBoolean) 764 { 765 // Test where works: true 766 { 767 const json element = R"( true )"_json; 768 bool value = parseBoolean(element); 769 EXPECT_EQ(value, true); 770 } 771 772 // Test where works: false 773 { 774 const json element = R"( false )"_json; 775 bool value = parseBoolean(element); 776 EXPECT_EQ(value, false); 777 } 778 779 // Test where fails: Element is not a boolean 780 try 781 { 782 const json element = R"( 1 )"_json; 783 parseBoolean(element); 784 ADD_FAILURE() << "Should not have reached this line."; 785 } 786 catch (const std::invalid_argument& e) 787 { 788 EXPECT_STREQ(e.what(), "Element is not a boolean"); 789 } 790 } 791 792 TEST(ConfigFileParserTests, ParseChassis) 793 { 794 // Test where works: Only required properties specified 795 { 796 const json element = R"( 797 { 798 "number": 1, 799 "inventory_path": "system/chassis1" 800 } 801 )"_json; 802 std::unique_ptr<Chassis> chassis = parseChassis(element); 803 EXPECT_EQ(chassis->getNumber(), 1); 804 EXPECT_EQ(chassis->getInventoryPath(), 805 "/xyz/openbmc_project/inventory/system/chassis1"); 806 EXPECT_EQ(chassis->getDevices().size(), 0); 807 } 808 809 // Test where works: All properties specified 810 { 811 const json element = R"( 812 { 813 "comments": [ "comments property" ], 814 "number": 2, 815 "inventory_path": "system/chassis2", 816 "devices": [ 817 { 818 "id": "vdd_regulator", 819 "is_regulator": true, 820 "fru": "system/chassis/motherboard/regulator2", 821 "i2c_interface": 822 { 823 "bus": 1, 824 "address": "0x70" 825 } 826 } 827 ] 828 } 829 )"_json; 830 std::unique_ptr<Chassis> chassis = parseChassis(element); 831 EXPECT_EQ(chassis->getNumber(), 2); 832 EXPECT_EQ(chassis->getInventoryPath(), 833 "/xyz/openbmc_project/inventory/system/chassis2"); 834 EXPECT_EQ(chassis->getDevices().size(), 1); 835 EXPECT_EQ(chassis->getDevices()[0]->getID(), "vdd_regulator"); 836 } 837 838 // Test where fails: number value is invalid 839 try 840 { 841 const json element = R"( 842 { 843 "number": 0.5, 844 "inventory_path": "system/chassis" 845 } 846 )"_json; 847 parseChassis(element); 848 ADD_FAILURE() << "Should not have reached this line."; 849 } 850 catch (const std::invalid_argument& e) 851 { 852 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 853 } 854 855 // Test where fails: inventory_path is invalid: Not a string 856 try 857 { 858 const json element = R"( 859 { 860 "number": 2, 861 "inventory_path": true 862 } 863 )"_json; 864 parseChassis(element); 865 ADD_FAILURE() << "Should not have reached this line."; 866 } 867 catch (const std::invalid_argument& e) 868 { 869 EXPECT_STREQ(e.what(), "Element is not a string"); 870 } 871 872 // Test where fails: inventory_path is invalid: Empty string 873 try 874 { 875 const json element = R"( 876 { 877 "number": 2, 878 "inventory_path": "" 879 } 880 )"_json; 881 parseChassis(element); 882 ADD_FAILURE() << "Should not have reached this line."; 883 } 884 catch (const std::invalid_argument& e) 885 { 886 EXPECT_STREQ(e.what(), "Element contains an empty string"); 887 } 888 889 // Test where fails: Invalid property specified 890 try 891 { 892 const json element = R"( 893 { 894 "number": 1, 895 "inventory_path": "system/chassis", 896 "foo": 2 897 } 898 )"_json; 899 parseChassis(element); 900 ADD_FAILURE() << "Should not have reached this line."; 901 } 902 catch (const std::invalid_argument& e) 903 { 904 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 905 } 906 907 // Test where fails: Required number property not specified 908 try 909 { 910 const json element = R"( 911 { 912 "inventory_path": "system/chassis" 913 } 914 )"_json; 915 parseChassis(element); 916 ADD_FAILURE() << "Should not have reached this line."; 917 } 918 catch (const std::invalid_argument& e) 919 { 920 EXPECT_STREQ(e.what(), "Required property missing: number"); 921 } 922 923 // Test where fails: Required inventory_path property not specified 924 try 925 { 926 const json element = R"( 927 { 928 "number": 1 929 } 930 )"_json; 931 parseChassis(element); 932 ADD_FAILURE() << "Should not have reached this line."; 933 } 934 catch (const std::invalid_argument& e) 935 { 936 EXPECT_STREQ(e.what(), "Required property missing: inventory_path"); 937 } 938 939 // Test where fails: Element is not an object 940 try 941 { 942 const json element = R"( [ "0xFF", "0x01" ] )"_json; 943 parseChassis(element); 944 ADD_FAILURE() << "Should not have reached this line."; 945 } 946 catch (const std::invalid_argument& e) 947 { 948 EXPECT_STREQ(e.what(), "Element is not an object"); 949 } 950 951 // Test where fails: number value is < 1 952 try 953 { 954 const json element = R"( 955 { 956 "number": 0, 957 "inventory_path": "system/chassis" 958 } 959 )"_json; 960 parseChassis(element); 961 ADD_FAILURE() << "Should not have reached this line."; 962 } 963 catch (const std::invalid_argument& e) 964 { 965 EXPECT_STREQ(e.what(), "Invalid chassis number: Must be > 0"); 966 } 967 968 // Test where fails: devices value is invalid 969 try 970 { 971 const json element = R"( 972 { 973 "number": 1, 974 "inventory_path": "system/chassis", 975 "devices": 2 976 } 977 )"_json; 978 parseChassis(element); 979 ADD_FAILURE() << "Should not have reached this line."; 980 } 981 catch (const std::invalid_argument& e) 982 { 983 EXPECT_STREQ(e.what(), "Element is not an array"); 984 } 985 } 986 987 TEST(ConfigFileParserTests, ParseChassisArray) 988 { 989 // Test where works 990 { 991 const json element = R"( 992 [ 993 { "number": 1, "inventory_path": "system/chassis1" }, 994 { "number": 2, "inventory_path": "system/chassis2" } 995 ] 996 )"_json; 997 std::vector<std::unique_ptr<Chassis>> chassis = 998 parseChassisArray(element); 999 EXPECT_EQ(chassis.size(), 2); 1000 EXPECT_EQ(chassis[0]->getNumber(), 1); 1001 EXPECT_EQ(chassis[0]->getInventoryPath(), 1002 "/xyz/openbmc_project/inventory/system/chassis1"); 1003 EXPECT_EQ(chassis[1]->getNumber(), 2); 1004 EXPECT_EQ(chassis[1]->getInventoryPath(), 1005 "/xyz/openbmc_project/inventory/system/chassis2"); 1006 } 1007 1008 // Test where fails: Element is not an array 1009 try 1010 { 1011 const json element = R"( 1012 { 1013 "foo": "bar" 1014 } 1015 )"_json; 1016 parseChassisArray(element); 1017 ADD_FAILURE() << "Should not have reached this line."; 1018 } 1019 catch (const std::invalid_argument& e) 1020 { 1021 EXPECT_STREQ(e.what(), "Element is not an array"); 1022 } 1023 } 1024 1025 TEST(ConfigFileParserTests, ParseComparePresence) 1026 { 1027 // Test where works 1028 { 1029 const json element = R"( 1030 { 1031 "fru": "system/chassis/motherboard/cpu3", 1032 "value": true 1033 } 1034 )"_json; 1035 std::unique_ptr<ComparePresenceAction> action = 1036 parseComparePresence(element); 1037 EXPECT_EQ( 1038 action->getFRU(), 1039 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu3"); 1040 EXPECT_EQ(action->getValue(), true); 1041 } 1042 1043 // Test where fails: Element is not an object 1044 try 1045 { 1046 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1047 parseComparePresence(element); 1048 ADD_FAILURE() << "Should not have reached this line."; 1049 } 1050 catch (const std::invalid_argument& e) 1051 { 1052 EXPECT_STREQ(e.what(), "Element is not an object"); 1053 } 1054 1055 // Test where fails: Invalid property specified 1056 try 1057 { 1058 const json element = R"( 1059 { 1060 "fru": "system/chassis/motherboard/cpu3", 1061 "value": true, 1062 "foo" : true 1063 } 1064 )"_json; 1065 parseComparePresence(element); 1066 ADD_FAILURE() << "Should not have reached this line."; 1067 } 1068 catch (const std::invalid_argument& e) 1069 { 1070 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1071 } 1072 1073 // Test where fails: Required fru property not specified 1074 try 1075 { 1076 const json element = R"( 1077 { 1078 "value": true 1079 } 1080 )"_json; 1081 parseComparePresence(element); 1082 ADD_FAILURE() << "Should not have reached this line."; 1083 } 1084 catch (const std::invalid_argument& e) 1085 { 1086 EXPECT_STREQ(e.what(), "Required property missing: fru"); 1087 } 1088 1089 // Test where fails: Required value property not specified 1090 try 1091 { 1092 const json element = R"( 1093 { 1094 "fru": "system/chassis/motherboard/cpu3" 1095 } 1096 )"_json; 1097 parseComparePresence(element); 1098 ADD_FAILURE() << "Should not have reached this line."; 1099 } 1100 catch (const std::invalid_argument& e) 1101 { 1102 EXPECT_STREQ(e.what(), "Required property missing: value"); 1103 } 1104 1105 // Test where fails: fru value is invalid 1106 try 1107 { 1108 const json element = R"( 1109 { 1110 "fru": 1, 1111 "value": true 1112 } 1113 )"_json; 1114 parseComparePresence(element); 1115 ADD_FAILURE() << "Should not have reached this line."; 1116 } 1117 catch (const std::invalid_argument& e) 1118 { 1119 EXPECT_STREQ(e.what(), "Element is not a string"); 1120 } 1121 1122 // Test where fails: value value is invalid 1123 try 1124 { 1125 const json element = R"( 1126 { 1127 "fru": "system/chassis/motherboard/cpu3", 1128 "value": 1 1129 } 1130 )"_json; 1131 parseComparePresence(element); 1132 ADD_FAILURE() << "Should not have reached this line."; 1133 } 1134 catch (const std::invalid_argument& e) 1135 { 1136 EXPECT_STREQ(e.what(), "Element is not a boolean"); 1137 } 1138 } 1139 1140 TEST(ConfigFileParserTests, ParseCompareVPD) 1141 { 1142 // Test where works: value property: Not empty 1143 { 1144 const json element = R"( 1145 { 1146 "fru": "system/chassis/disk_backplane", 1147 "keyword": "CCIN", 1148 "value": "2D35" 1149 } 1150 )"_json; 1151 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 1152 EXPECT_EQ( 1153 action->getFRU(), 1154 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane"); 1155 EXPECT_EQ(action->getKeyword(), "CCIN"); 1156 EXPECT_EQ(action->getValue(), 1157 (std::vector<uint8_t>{0x32, 0x44, 0x33, 0x35})); 1158 } 1159 1160 // Test where works: value property: Empty 1161 { 1162 const json element = R"( 1163 { 1164 "fru": "system/chassis/disk_backplane", 1165 "keyword": "CCIN", 1166 "value": "" 1167 } 1168 )"_json; 1169 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 1170 EXPECT_EQ( 1171 action->getFRU(), 1172 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane"); 1173 EXPECT_EQ(action->getKeyword(), "CCIN"); 1174 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{})); 1175 } 1176 1177 // Test where works: byte_values property: Not empty 1178 { 1179 const json element = R"( 1180 { 1181 "fru": "system/chassis/disk_backplane", 1182 "keyword": "CCIN", 1183 "byte_values": ["0x11", "0x22", "0x33"] 1184 } 1185 )"_json; 1186 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 1187 EXPECT_EQ( 1188 action->getFRU(), 1189 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane"); 1190 EXPECT_EQ(action->getKeyword(), "CCIN"); 1191 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{0x11, 0x22, 0x33})); 1192 } 1193 1194 // Test where works: byte_values property: Empty 1195 { 1196 const json element = R"( 1197 { 1198 "fru": "system/chassis/disk_backplane", 1199 "keyword": "CCIN", 1200 "byte_values": [] 1201 } 1202 )"_json; 1203 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 1204 EXPECT_EQ( 1205 action->getFRU(), 1206 "/xyz/openbmc_project/inventory/system/chassis/disk_backplane"); 1207 EXPECT_EQ(action->getKeyword(), "CCIN"); 1208 EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{})); 1209 } 1210 1211 // Test where fails: Element is not an object 1212 try 1213 { 1214 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1215 parseCompareVPD(element); 1216 ADD_FAILURE() << "Should not have reached this line."; 1217 } 1218 catch (const std::invalid_argument& e) 1219 { 1220 EXPECT_STREQ(e.what(), "Element is not an object"); 1221 } 1222 1223 // Test where fails: Invalid property specified 1224 try 1225 { 1226 const json element = R"( 1227 { 1228 "fru": "system/chassis/disk_backplane", 1229 "keyword": "CCIN", 1230 "value": "2D35", 1231 "foo" : true 1232 } 1233 )"_json; 1234 parseCompareVPD(element); 1235 ADD_FAILURE() << "Should not have reached this line."; 1236 } 1237 catch (const std::invalid_argument& e) 1238 { 1239 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1240 } 1241 1242 // Test where fails: Required fru property not specified 1243 try 1244 { 1245 const json element = R"( 1246 { 1247 "keyword": "CCIN", 1248 "value": "2D35" 1249 } 1250 )"_json; 1251 parseCompareVPD(element); 1252 ADD_FAILURE() << "Should not have reached this line."; 1253 } 1254 catch (const std::invalid_argument& e) 1255 { 1256 EXPECT_STREQ(e.what(), "Required property missing: fru"); 1257 } 1258 1259 // Test where fails: Required keyword property not specified 1260 try 1261 { 1262 const json element = R"( 1263 { 1264 "fru": "system/chassis/disk_backplane", 1265 "value": "2D35" 1266 } 1267 )"_json; 1268 parseCompareVPD(element); 1269 ADD_FAILURE() << "Should not have reached this line."; 1270 } 1271 catch (const std::invalid_argument& e) 1272 { 1273 EXPECT_STREQ(e.what(), "Required property missing: keyword"); 1274 } 1275 1276 // Test where fails: Required value property not specified 1277 try 1278 { 1279 const json element = R"( 1280 { 1281 "fru": "system/chassis/disk_backplane", 1282 "keyword": "CCIN" 1283 } 1284 )"_json; 1285 parseCompareVPD(element); 1286 ADD_FAILURE() << "Should not have reached this line."; 1287 } 1288 catch (const std::invalid_argument& e) 1289 { 1290 EXPECT_STREQ(e.what(), "Invalid property: Must contain " 1291 "either value or byte_values"); 1292 } 1293 1294 // Test where fails: both value and byte_values specified 1295 try 1296 { 1297 const json element = R"( 1298 { 1299 "fru": "system/chassis/disk_backplane", 1300 "keyword": "CCIN", 1301 "value": "2D35", 1302 "byte_values": [ "0x01", "0x02" ] 1303 } 1304 )"_json; 1305 parseCompareVPD(element); 1306 ADD_FAILURE() << "Should not have reached this line."; 1307 } 1308 catch (const std::invalid_argument& e) 1309 { 1310 EXPECT_STREQ(e.what(), "Invalid property: Must contain " 1311 "either value or byte_values"); 1312 } 1313 1314 // Test where fails: fru value is invalid 1315 try 1316 { 1317 const json element = R"( 1318 { 1319 "fru": 1, 1320 "keyword": "CCIN", 1321 "value": "2D35" 1322 } 1323 )"_json; 1324 parseCompareVPD(element); 1325 ADD_FAILURE() << "Should not have reached this line."; 1326 } 1327 catch (const std::invalid_argument& e) 1328 { 1329 EXPECT_STREQ(e.what(), "Element is not a string"); 1330 } 1331 1332 // Test where fails: keyword value is invalid 1333 try 1334 { 1335 const json element = R"( 1336 { 1337 "fru": "system/chassis/disk_backplane", 1338 "keyword": 1, 1339 "value": "2D35" 1340 } 1341 )"_json; 1342 parseCompareVPD(element); 1343 ADD_FAILURE() << "Should not have reached this line."; 1344 } 1345 catch (const std::invalid_argument& e) 1346 { 1347 EXPECT_STREQ(e.what(), "Element is not a string"); 1348 } 1349 1350 // Test where fails: value value is invalid 1351 try 1352 { 1353 const json element = R"( 1354 { 1355 "fru": "system/chassis/disk_backplane", 1356 "keyword": "CCIN", 1357 "value": 1 1358 } 1359 )"_json; 1360 parseCompareVPD(element); 1361 ADD_FAILURE() << "Should not have reached this line."; 1362 } 1363 catch (const std::invalid_argument& e) 1364 { 1365 EXPECT_STREQ(e.what(), "Element is not a string"); 1366 } 1367 1368 // Test where fails: byte_values is wrong format 1369 try 1370 { 1371 const json element = R"( 1372 { 1373 "fru": "system/chassis/disk_backplane", 1374 "keyword": "CCIN", 1375 "byte_values": [1, 2, 3] 1376 } 1377 )"_json; 1378 parseCompareVPD(element); 1379 ADD_FAILURE() << "Should not have reached this line."; 1380 } 1381 catch (const std::invalid_argument& e) 1382 { 1383 EXPECT_STREQ(e.what(), "Element is not a string"); 1384 } 1385 } 1386 1387 TEST(ConfigFileParserTests, ParseConfiguration) 1388 { 1389 // Test where works: actions required property specified 1390 { 1391 const json element = R"( 1392 { 1393 "actions": [ 1394 { 1395 "pmbus_write_vout_command": { 1396 "format": "linear" 1397 } 1398 } 1399 ] 1400 } 1401 )"_json; 1402 std::unique_ptr<Configuration> configuration = 1403 parseConfiguration(element); 1404 EXPECT_EQ(configuration->getActions().size(), 1); 1405 EXPECT_EQ(configuration->getVolts().has_value(), false); 1406 } 1407 1408 // Test where works: volts and actions properties specified 1409 { 1410 const json element = R"( 1411 { 1412 "comments": [ "comments property" ], 1413 "volts": 1.03, 1414 "actions": [ 1415 { "pmbus_write_vout_command": { "format": "linear" } }, 1416 { "run_rule": "set_voltage_rule" } 1417 ] 1418 } 1419 )"_json; 1420 std::unique_ptr<Configuration> configuration = 1421 parseConfiguration(element); 1422 EXPECT_EQ(configuration->getVolts().has_value(), true); 1423 EXPECT_EQ(configuration->getVolts().value(), 1.03); 1424 EXPECT_EQ(configuration->getActions().size(), 2); 1425 } 1426 1427 // Test where works: volts and rule_id properties specified 1428 { 1429 const json element = R"( 1430 { 1431 "volts": 1.05, 1432 "rule_id": "set_voltage_rule" 1433 } 1434 )"_json; 1435 std::unique_ptr<Configuration> configuration = 1436 parseConfiguration(element); 1437 EXPECT_EQ(configuration->getVolts().has_value(), true); 1438 EXPECT_EQ(configuration->getVolts().value(), 1.05); 1439 EXPECT_EQ(configuration->getActions().size(), 1); 1440 } 1441 1442 // Test where fails: volts value is invalid 1443 try 1444 { 1445 const json element = R"( 1446 { 1447 "volts": "foo", 1448 "actions": [ 1449 { 1450 "pmbus_write_vout_command": { 1451 "format": "linear" 1452 } 1453 } 1454 ] 1455 } 1456 )"_json; 1457 parseConfiguration(element); 1458 ADD_FAILURE() << "Should not have reached this line."; 1459 } 1460 catch (const std::invalid_argument& e) 1461 { 1462 EXPECT_STREQ(e.what(), "Element is not a number"); 1463 } 1464 1465 // Test where fails: actions object is invalid 1466 try 1467 { 1468 const json element = R"( 1469 { 1470 "volts": 1.03, 1471 "actions": 1 1472 } 1473 )"_json; 1474 parseConfiguration(element); 1475 ADD_FAILURE() << "Should not have reached this line."; 1476 } 1477 catch (const std::invalid_argument& e) 1478 { 1479 EXPECT_STREQ(e.what(), "Element is not an array"); 1480 } 1481 1482 // Test where fails: rule_id value is invalid 1483 try 1484 { 1485 const json element = R"( 1486 { 1487 "volts": 1.05, 1488 "rule_id": 1 1489 } 1490 )"_json; 1491 parseConfiguration(element); 1492 ADD_FAILURE() << "Should not have reached this line."; 1493 } 1494 catch (const std::invalid_argument& e) 1495 { 1496 EXPECT_STREQ(e.what(), "Element is not a string"); 1497 } 1498 1499 // Test where fails: Required actions or rule_id property not specified 1500 try 1501 { 1502 const json element = R"( 1503 { 1504 "volts": 1.03 1505 } 1506 )"_json; 1507 parseConfiguration(element); 1508 ADD_FAILURE() << "Should not have reached this line."; 1509 } 1510 catch (const std::invalid_argument& e) 1511 { 1512 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 1513 "either rule_id or actions"); 1514 } 1515 1516 // Test where fails: Required actions or rule_id property both specified 1517 try 1518 { 1519 const json element = R"( 1520 { 1521 "volts": 1.03, 1522 "rule_id": "set_voltage_rule", 1523 "actions": [ 1524 { 1525 "pmbus_write_vout_command": { 1526 "format": "linear" 1527 } 1528 } 1529 ] 1530 } 1531 )"_json; 1532 parseConfiguration(element); 1533 ADD_FAILURE() << "Should not have reached this line."; 1534 } 1535 catch (const std::invalid_argument& e) 1536 { 1537 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 1538 "either rule_id or actions"); 1539 } 1540 1541 // Test where fails: Element is not an object 1542 try 1543 { 1544 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1545 parseConfiguration(element); 1546 ADD_FAILURE() << "Should not have reached this line."; 1547 } 1548 catch (const std::invalid_argument& e) 1549 { 1550 EXPECT_STREQ(e.what(), "Element is not an object"); 1551 } 1552 1553 // Test where fails: Invalid property specified 1554 try 1555 { 1556 const json element = R"( 1557 { 1558 "volts": 1.03, 1559 "rule_id": "set_voltage_rule", 1560 "foo": 1 1561 } 1562 )"_json; 1563 parseConfiguration(element); 1564 ADD_FAILURE() << "Should not have reached this line."; 1565 } 1566 catch (const std::invalid_argument& e) 1567 { 1568 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1569 } 1570 } 1571 1572 TEST(ConfigFileParserTests, ParseDevice) 1573 { 1574 // Test where works: Only required properties specified 1575 { 1576 const json element = R"( 1577 { 1578 "id": "vdd_regulator", 1579 "is_regulator": true, 1580 "fru": "system/chassis/motherboard/regulator2", 1581 "i2c_interface": { "bus": 1, "address": "0x70" } 1582 } 1583 )"_json; 1584 std::unique_ptr<Device> device = parseDevice(element); 1585 EXPECT_EQ(device->getID(), "vdd_regulator"); 1586 EXPECT_EQ(device->isRegulator(), true); 1587 EXPECT_EQ(device->getFRU(), "/xyz/openbmc_project/inventory/system/" 1588 "chassis/motherboard/regulator2"); 1589 EXPECT_NE(&(device->getI2CInterface()), nullptr); 1590 EXPECT_EQ(device->getPresenceDetection(), nullptr); 1591 EXPECT_EQ(device->getConfiguration(), nullptr); 1592 EXPECT_EQ(device->getPhaseFaultDetection(), nullptr); 1593 EXPECT_EQ(device->getRails().size(), 0); 1594 } 1595 1596 // Test where works: All properties specified 1597 { 1598 const json element = R"( 1599 { 1600 "comments": [ "VDD Regulator" ], 1601 "id": "vdd_regulator", 1602 "is_regulator": true, 1603 "fru": "system/chassis/motherboard/regulator2", 1604 "i2c_interface": 1605 { 1606 "bus": 1, 1607 "address": "0x70" 1608 }, 1609 "presence_detection": 1610 { 1611 "rule_id": "is_foobar_backplane_installed_rule" 1612 }, 1613 "configuration": 1614 { 1615 "rule_id": "configure_ir35221_rule" 1616 }, 1617 "phase_fault_detection": 1618 { 1619 "rule_id": "detect_phase_fault_rule" 1620 }, 1621 "rails": 1622 [ 1623 { 1624 "id": "vdd" 1625 } 1626 ] 1627 } 1628 )"_json; 1629 std::unique_ptr<Device> device = parseDevice(element); 1630 EXPECT_EQ(device->getID(), "vdd_regulator"); 1631 EXPECT_EQ(device->isRegulator(), true); 1632 EXPECT_EQ(device->getFRU(), "/xyz/openbmc_project/inventory/system/" 1633 "chassis/motherboard/regulator2"); 1634 EXPECT_NE(&(device->getI2CInterface()), nullptr); 1635 EXPECT_NE(device->getPresenceDetection(), nullptr); 1636 EXPECT_NE(device->getConfiguration(), nullptr); 1637 EXPECT_NE(device->getPhaseFaultDetection(), nullptr); 1638 EXPECT_EQ(device->getRails().size(), 1); 1639 } 1640 1641 // Test where fails: phase_fault_detection property exists and is_regulator 1642 // is false 1643 try 1644 { 1645 const json element = R"( 1646 { 1647 "id": "vdd_regulator", 1648 "is_regulator": false, 1649 "fru": "system/chassis/motherboard/regulator2", 1650 "i2c_interface": 1651 { 1652 "bus": 1, 1653 "address": "0x70" 1654 }, 1655 "phase_fault_detection": 1656 { 1657 "rule_id": "detect_phase_fault_rule" 1658 } 1659 } 1660 )"_json; 1661 parseDevice(element); 1662 ADD_FAILURE() << "Should not have reached this line."; 1663 } 1664 catch (const std::invalid_argument& e) 1665 { 1666 EXPECT_STREQ(e.what(), "Invalid phase_fault_detection property when " 1667 "is_regulator is false"); 1668 } 1669 1670 // Test where fails: rails property exists and is_regulator is false 1671 try 1672 { 1673 const json element = R"( 1674 { 1675 "id": "vdd_regulator", 1676 "is_regulator": false, 1677 "fru": "system/chassis/motherboard/regulator2", 1678 "i2c_interface": 1679 { 1680 "bus": 1, 1681 "address": "0x70" 1682 }, 1683 "configuration": 1684 { 1685 "rule_id": "configure_ir35221_rule" 1686 }, 1687 "rails": 1688 [ 1689 { 1690 "id": "vdd" 1691 } 1692 ] 1693 } 1694 )"_json; 1695 parseDevice(element); 1696 ADD_FAILURE() << "Should not have reached this line."; 1697 } 1698 catch (const std::invalid_argument& e) 1699 { 1700 EXPECT_STREQ(e.what(), 1701 "Invalid rails property when is_regulator is false"); 1702 } 1703 1704 // Test where fails: id value is invalid 1705 try 1706 { 1707 const json element = R"( 1708 { 1709 "id": 3, 1710 "is_regulator": true, 1711 "fru": "system/chassis/motherboard/regulator2", 1712 "i2c_interface": 1713 { 1714 "bus": 1, 1715 "address": "0x70" 1716 } 1717 } 1718 )"_json; 1719 parseDevice(element); 1720 ADD_FAILURE() << "Should not have reached this line."; 1721 } 1722 catch (const std::invalid_argument& e) 1723 { 1724 EXPECT_STREQ(e.what(), "Element is not a string"); 1725 } 1726 1727 // Test where fails: is_regulator value is invalid 1728 try 1729 { 1730 const json element = R"( 1731 { 1732 "id": "vdd_regulator", 1733 "is_regulator": 3, 1734 "fru": "system/chassis/motherboard/regulator2", 1735 "i2c_interface": 1736 { 1737 "bus": 1, 1738 "address": "0x70" 1739 } 1740 } 1741 )"_json; 1742 parseDevice(element); 1743 ADD_FAILURE() << "Should not have reached this line."; 1744 } 1745 catch (const std::invalid_argument& e) 1746 { 1747 EXPECT_STREQ(e.what(), "Element is not a boolean"); 1748 } 1749 1750 // Test where fails: fru value is invalid 1751 try 1752 { 1753 const json element = R"( 1754 { 1755 "id": "vdd_regulator", 1756 "is_regulator": true, 1757 "fru": 2, 1758 "i2c_interface": 1759 { 1760 "bus": 1, 1761 "address": "0x70" 1762 } 1763 } 1764 )"_json; 1765 parseDevice(element); 1766 ADD_FAILURE() << "Should not have reached this line."; 1767 } 1768 catch (const std::invalid_argument& e) 1769 { 1770 EXPECT_STREQ(e.what(), "Element is not a string"); 1771 } 1772 1773 // Test where fails: i2c_interface value is invalid 1774 try 1775 { 1776 const json element = R"( 1777 { 1778 "id": "vdd_regulator", 1779 "is_regulator": true, 1780 "fru": "system/chassis/motherboard/regulator2", 1781 "i2c_interface": 3 1782 } 1783 )"_json; 1784 parseDevice(element); 1785 ADD_FAILURE() << "Should not have reached this line."; 1786 } 1787 catch (const std::invalid_argument& e) 1788 { 1789 EXPECT_STREQ(e.what(), "Element is not an object"); 1790 } 1791 1792 // Test where fails: Required id property not specified 1793 try 1794 { 1795 const json element = R"( 1796 { 1797 "is_regulator": true, 1798 "fru": "system/chassis/motherboard/regulator2", 1799 "i2c_interface": 1800 { 1801 "bus": 1, 1802 "address": "0x70" 1803 } 1804 } 1805 )"_json; 1806 parseDevice(element); 1807 ADD_FAILURE() << "Should not have reached this line."; 1808 } 1809 catch (const std::invalid_argument& e) 1810 { 1811 EXPECT_STREQ(e.what(), "Required property missing: id"); 1812 } 1813 1814 // Test where fails: Required is_regulator property not specified 1815 try 1816 { 1817 const json element = R"( 1818 { 1819 "id": "vdd_regulator", 1820 "fru": "system/chassis/motherboard/regulator2", 1821 "i2c_interface": 1822 { 1823 "bus": 1, 1824 "address": "0x70" 1825 } 1826 } 1827 )"_json; 1828 parseDevice(element); 1829 ADD_FAILURE() << "Should not have reached this line."; 1830 } 1831 catch (const std::invalid_argument& e) 1832 { 1833 EXPECT_STREQ(e.what(), "Required property missing: is_regulator"); 1834 } 1835 1836 // Test where fails: Required fru property not specified 1837 try 1838 { 1839 const json element = R"( 1840 { 1841 "id": "vdd_regulator", 1842 "is_regulator": true, 1843 "i2c_interface": 1844 { 1845 "bus": 1, 1846 "address": "0x70" 1847 } 1848 } 1849 )"_json; 1850 parseDevice(element); 1851 ADD_FAILURE() << "Should not have reached this line."; 1852 } 1853 catch (const std::invalid_argument& e) 1854 { 1855 EXPECT_STREQ(e.what(), "Required property missing: fru"); 1856 } 1857 1858 // Test where fails: Required i2c_interface property not specified 1859 try 1860 { 1861 const json element = R"( 1862 { 1863 "id": "vdd_regulator", 1864 "is_regulator": true, 1865 "fru": "system/chassis/motherboard/regulator2" 1866 } 1867 )"_json; 1868 parseDevice(element); 1869 ADD_FAILURE() << "Should not have reached this line."; 1870 } 1871 catch (const std::invalid_argument& e) 1872 { 1873 EXPECT_STREQ(e.what(), "Required property missing: i2c_interface"); 1874 } 1875 1876 // Test where fails: Element is not an object 1877 try 1878 { 1879 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1880 parseDevice(element); 1881 ADD_FAILURE() << "Should not have reached this line."; 1882 } 1883 catch (const std::invalid_argument& e) 1884 { 1885 EXPECT_STREQ(e.what(), "Element is not an object"); 1886 } 1887 1888 // Test where fails: Invalid property specified 1889 try 1890 { 1891 const json element = R"( 1892 { 1893 "id": "vdd_regulator", 1894 "is_regulator": true, 1895 "fru": "system/chassis/motherboard/regulator2", 1896 "i2c_interface": { "bus": 1, "address": "0x70" }, 1897 "foo" : true 1898 } 1899 )"_json; 1900 parseDevice(element); 1901 ADD_FAILURE() << "Should not have reached this line."; 1902 } 1903 catch (const std::invalid_argument& e) 1904 { 1905 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1906 } 1907 } 1908 1909 TEST(ConfigFileParserTests, ParseDeviceArray) 1910 { 1911 // Test where works 1912 { 1913 const json element = R"( 1914 [ 1915 { 1916 "id": "vdd_regulator", 1917 "is_regulator": true, 1918 "fru": "system/chassis/motherboard/regulator2", 1919 "i2c_interface": { "bus": 1, "address": "0x70" } 1920 }, 1921 { 1922 "id": "vio_regulator", 1923 "is_regulator": true, 1924 "fru": "system/chassis/motherboard/regulator2", 1925 "i2c_interface": { "bus": 1, "address": "0x71" } 1926 } 1927 ] 1928 )"_json; 1929 std::vector<std::unique_ptr<Device>> devices = 1930 parseDeviceArray(element); 1931 EXPECT_EQ(devices.size(), 2); 1932 EXPECT_EQ(devices[0]->getID(), "vdd_regulator"); 1933 EXPECT_EQ(devices[1]->getID(), "vio_regulator"); 1934 } 1935 1936 // Test where fails: Element is not an array 1937 try 1938 { 1939 const json element = R"( 1940 { 1941 "foo": "bar" 1942 } 1943 )"_json; 1944 parseDeviceArray(element); 1945 ADD_FAILURE() << "Should not have reached this line."; 1946 } 1947 catch (const std::invalid_argument& e) 1948 { 1949 EXPECT_STREQ(e.what(), "Element is not an array"); 1950 } 1951 } 1952 1953 TEST(ConfigFileParserTests, ParseDouble) 1954 { 1955 // Test where works: floating point value 1956 { 1957 const json element = R"( 1.03 )"_json; 1958 double value = parseDouble(element); 1959 EXPECT_EQ(value, 1.03); 1960 } 1961 1962 // Test where works: integer value 1963 { 1964 const json element = R"( 24 )"_json; 1965 double value = parseDouble(element); 1966 EXPECT_EQ(value, 24.0); 1967 } 1968 1969 // Test where fails: Element is not a number 1970 try 1971 { 1972 const json element = R"( true )"_json; 1973 parseDouble(element); 1974 ADD_FAILURE() << "Should not have reached this line."; 1975 } 1976 catch (const std::invalid_argument& e) 1977 { 1978 EXPECT_STREQ(e.what(), "Element is not a number"); 1979 } 1980 } 1981 1982 TEST(ConfigFileParserTests, ParseHexByte) 1983 { 1984 // Test where works: "0xFF" 1985 { 1986 const json element = R"( "0xFF" )"_json; 1987 uint8_t value = parseHexByte(element); 1988 EXPECT_EQ(value, 0xFF); 1989 } 1990 1991 // Test where works: "0xff" 1992 { 1993 const json element = R"( "0xff" )"_json; 1994 uint8_t value = parseHexByte(element); 1995 EXPECT_EQ(value, 0xff); 1996 } 1997 1998 // Test where works: "0xf" 1999 { 2000 const json element = R"( "0xf" )"_json; 2001 uint8_t value = parseHexByte(element); 2002 EXPECT_EQ(value, 0xf); 2003 } 2004 2005 // Test where fails: "0xfff" 2006 try 2007 { 2008 const json element = R"( "0xfff" )"_json; 2009 parseHexByte(element); 2010 ADD_FAILURE() << "Should not have reached this line."; 2011 } 2012 catch (const std::invalid_argument& e) 2013 { 2014 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2015 } 2016 2017 // Test where fails: "0xAG" 2018 try 2019 { 2020 const json element = R"( "0xAG" )"_json; 2021 parseHexByte(element); 2022 ADD_FAILURE() << "Should not have reached this line."; 2023 } 2024 catch (const std::invalid_argument& e) 2025 { 2026 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2027 } 2028 2029 // Test where fails: "ff" 2030 try 2031 { 2032 const json element = R"( "ff" )"_json; 2033 parseHexByte(element); 2034 ADD_FAILURE() << "Should not have reached this line."; 2035 } 2036 catch (const std::invalid_argument& e) 2037 { 2038 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2039 } 2040 2041 // Test where fails: "" 2042 try 2043 { 2044 const json element = ""; 2045 parseHexByte(element); 2046 ADD_FAILURE() << "Should not have reached this line."; 2047 } 2048 catch (const std::invalid_argument& e) 2049 { 2050 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2051 } 2052 2053 // Test where fails: "f" 2054 try 2055 { 2056 const json element = R"( "f" )"_json; 2057 parseHexByte(element); 2058 ADD_FAILURE() << "Should not have reached this line."; 2059 } 2060 catch (const std::invalid_argument& e) 2061 { 2062 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2063 } 2064 2065 // Test where fails: "0x" 2066 try 2067 { 2068 const json element = R"( "0x" )"_json; 2069 parseHexByte(element); 2070 ADD_FAILURE() << "Should not have reached this line."; 2071 } 2072 catch (const std::invalid_argument& e) 2073 { 2074 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2075 } 2076 2077 // Test where fails: "0Xff" 2078 try 2079 { 2080 const json element = R"( "0XFF" )"_json; 2081 parseHexByte(element); 2082 ADD_FAILURE() << "Should not have reached this line."; 2083 } 2084 catch (const std::invalid_argument& e) 2085 { 2086 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2087 } 2088 } 2089 2090 TEST(ConfigFileParserTests, ParseHexByteArray) 2091 { 2092 // Test where works 2093 { 2094 const json element = R"( [ "0xCC", "0xFF" ] )"_json; 2095 std::vector<uint8_t> hexBytes = parseHexByteArray(element); 2096 std::vector<uint8_t> expected = {0xcc, 0xff}; 2097 EXPECT_EQ(hexBytes, expected); 2098 } 2099 2100 // Test where fails: Element is not an array 2101 try 2102 { 2103 const json element = 0; 2104 parseHexByteArray(element); 2105 ADD_FAILURE() << "Should not have reached this line."; 2106 } 2107 catch (const std::invalid_argument& e) 2108 { 2109 EXPECT_STREQ(e.what(), "Element is not an array"); 2110 } 2111 } 2112 2113 TEST(ConfigFileParserTests, ParseI2CCaptureBytes) 2114 { 2115 // Test where works 2116 { 2117 const json element = R"( 2118 { 2119 "register": "0xA0", 2120 "count": 2 2121 } 2122 )"_json; 2123 std::unique_ptr<I2CCaptureBytesAction> action = 2124 parseI2CCaptureBytes(element); 2125 EXPECT_EQ(action->getRegister(), 0xA0); 2126 EXPECT_EQ(action->getCount(), 2); 2127 } 2128 2129 // Test where fails: Element is not an object 2130 try 2131 { 2132 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2133 parseI2CCaptureBytes(element); 2134 ADD_FAILURE() << "Should not have reached this line."; 2135 } 2136 catch (const std::invalid_argument& e) 2137 { 2138 EXPECT_STREQ(e.what(), "Element is not an object"); 2139 } 2140 2141 // Test where fails: register value is invalid 2142 try 2143 { 2144 const json element = R"( 2145 { 2146 "register": "0x0Z", 2147 "count": 2 2148 } 2149 )"_json; 2150 parseI2CCaptureBytes(element); 2151 ADD_FAILURE() << "Should not have reached this line."; 2152 } 2153 catch (const std::invalid_argument& e) 2154 { 2155 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2156 } 2157 2158 // Test where fails: count value is invalid 2159 try 2160 { 2161 const json element = R"( 2162 { 2163 "register": "0xA0", 2164 "count": 0 2165 } 2166 )"_json; 2167 parseI2CCaptureBytes(element); 2168 ADD_FAILURE() << "Should not have reached this line."; 2169 } 2170 catch (const std::invalid_argument& e) 2171 { 2172 EXPECT_STREQ(e.what(), "Invalid byte count: Must be > 0"); 2173 } 2174 2175 // Test where fails: Required register property not specified 2176 try 2177 { 2178 const json element = R"( 2179 { 2180 "count": 2 2181 } 2182 )"_json; 2183 parseI2CCaptureBytes(element); 2184 ADD_FAILURE() << "Should not have reached this line."; 2185 } 2186 catch (const std::invalid_argument& e) 2187 { 2188 EXPECT_STREQ(e.what(), "Required property missing: register"); 2189 } 2190 2191 // Test where fails: Required count property not specified 2192 try 2193 { 2194 const json element = R"( 2195 { 2196 "register": "0xA0" 2197 } 2198 )"_json; 2199 parseI2CCaptureBytes(element); 2200 ADD_FAILURE() << "Should not have reached this line."; 2201 } 2202 catch (const std::invalid_argument& e) 2203 { 2204 EXPECT_STREQ(e.what(), "Required property missing: count"); 2205 } 2206 2207 // Test where fails: Invalid property specified 2208 try 2209 { 2210 const json element = R"( 2211 { 2212 "register": "0xA0", 2213 "count": 2, 2214 "foo": 3 2215 } 2216 )"_json; 2217 parseI2CCaptureBytes(element); 2218 ADD_FAILURE() << "Should not have reached this line."; 2219 } 2220 catch (const std::invalid_argument& e) 2221 { 2222 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2223 } 2224 } 2225 2226 TEST(ConfigFileParserTests, ParseI2CCompareBit) 2227 { 2228 // Test where works 2229 { 2230 const json element = R"( 2231 { 2232 "register": "0xA0", 2233 "position": 3, 2234 "value": 0 2235 } 2236 )"_json; 2237 std::unique_ptr<I2CCompareBitAction> action = 2238 parseI2CCompareBit(element); 2239 EXPECT_EQ(action->getRegister(), 0xA0); 2240 EXPECT_EQ(action->getPosition(), 3); 2241 EXPECT_EQ(action->getValue(), 0); 2242 } 2243 2244 // Test where fails: Invalid property specified 2245 try 2246 { 2247 const json element = R"( 2248 { 2249 "register": "0xA0", 2250 "position": 3, 2251 "value": 0, 2252 "foo": 3 2253 } 2254 )"_json; 2255 parseI2CCompareBit(element); 2256 ADD_FAILURE() << "Should not have reached this line."; 2257 } 2258 catch (const std::invalid_argument& e) 2259 { 2260 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2261 } 2262 2263 // Test where fails: Element is not an object 2264 try 2265 { 2266 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2267 parseI2CCompareBit(element); 2268 ADD_FAILURE() << "Should not have reached this line."; 2269 } 2270 catch (const std::invalid_argument& e) 2271 { 2272 EXPECT_STREQ(e.what(), "Element is not an object"); 2273 } 2274 2275 // Test where fails: register value is invalid 2276 try 2277 { 2278 const json element = R"( 2279 { 2280 "register": "0xAG", 2281 "position": 3, 2282 "value": 0 2283 } 2284 )"_json; 2285 parseI2CCompareBit(element); 2286 ADD_FAILURE() << "Should not have reached this line."; 2287 } 2288 catch (const std::invalid_argument& e) 2289 { 2290 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2291 } 2292 2293 // Test where fails: position value is invalid 2294 try 2295 { 2296 const json element = R"( 2297 { 2298 "register": "0xA0", 2299 "position": 8, 2300 "value": 0 2301 } 2302 )"_json; 2303 parseI2CCompareBit(element); 2304 ADD_FAILURE() << "Should not have reached this line."; 2305 } 2306 catch (const std::invalid_argument& e) 2307 { 2308 EXPECT_STREQ(e.what(), "Element is not a bit position"); 2309 } 2310 2311 // Test where fails: value value is invalid 2312 try 2313 { 2314 const json element = R"( 2315 { 2316 "register": "0xA0", 2317 "position": 3, 2318 "value": 2 2319 } 2320 )"_json; 2321 parseI2CCompareBit(element); 2322 ADD_FAILURE() << "Should not have reached this line."; 2323 } 2324 catch (const std::invalid_argument& e) 2325 { 2326 EXPECT_STREQ(e.what(), "Element is not a bit value"); 2327 } 2328 2329 // Test where fails: Required register property not specified 2330 try 2331 { 2332 const json element = R"( 2333 { 2334 "position": 3, 2335 "value": 0 2336 } 2337 )"_json; 2338 parseI2CCompareBit(element); 2339 ADD_FAILURE() << "Should not have reached this line."; 2340 } 2341 catch (const std::invalid_argument& e) 2342 { 2343 EXPECT_STREQ(e.what(), "Required property missing: register"); 2344 } 2345 2346 // Test where fails: Required position property not specified 2347 try 2348 { 2349 const json element = R"( 2350 { 2351 "register": "0xA0", 2352 "value": 0 2353 } 2354 )"_json; 2355 parseI2CCompareBit(element); 2356 ADD_FAILURE() << "Should not have reached this line."; 2357 } 2358 catch (const std::invalid_argument& e) 2359 { 2360 EXPECT_STREQ(e.what(), "Required property missing: position"); 2361 } 2362 2363 // Test where fails: Required value property not specified 2364 try 2365 { 2366 const json element = R"( 2367 { 2368 "register": "0xA0", 2369 "position": 3 2370 } 2371 )"_json; 2372 parseI2CCompareBit(element); 2373 ADD_FAILURE() << "Should not have reached this line."; 2374 } 2375 catch (const std::invalid_argument& e) 2376 { 2377 EXPECT_STREQ(e.what(), "Required property missing: value"); 2378 } 2379 } 2380 2381 TEST(ConfigFileParserTests, ParseI2CCompareByte) 2382 { 2383 // Test where works: Only required properties specified 2384 { 2385 const json element = R"( 2386 { 2387 "register": "0x0A", 2388 "value": "0xCC" 2389 } 2390 )"_json; 2391 std::unique_ptr<I2CCompareByteAction> action = 2392 parseI2CCompareByte(element); 2393 EXPECT_EQ(action->getRegister(), 0x0A); 2394 EXPECT_EQ(action->getValue(), 0xCC); 2395 EXPECT_EQ(action->getMask(), 0xFF); 2396 } 2397 2398 // Test where works: All properties specified 2399 { 2400 const json element = R"( 2401 { 2402 "register": "0x0A", 2403 "value": "0xCC", 2404 "mask": "0xF7" 2405 } 2406 )"_json; 2407 std::unique_ptr<I2CCompareByteAction> action = 2408 parseI2CCompareByte(element); 2409 EXPECT_EQ(action->getRegister(), 0x0A); 2410 EXPECT_EQ(action->getValue(), 0xCC); 2411 EXPECT_EQ(action->getMask(), 0xF7); 2412 } 2413 2414 // Test where fails: Element is not an object 2415 try 2416 { 2417 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2418 parseI2CCompareByte(element); 2419 ADD_FAILURE() << "Should not have reached this line."; 2420 } 2421 catch (const std::invalid_argument& e) 2422 { 2423 EXPECT_STREQ(e.what(), "Element is not an object"); 2424 } 2425 2426 // Test where fails: Invalid property specified 2427 try 2428 { 2429 const json element = R"( 2430 { 2431 "register": "0x0A", 2432 "value": "0xCC", 2433 "mask": "0xF7", 2434 "foo": 1 2435 } 2436 )"_json; 2437 parseI2CCompareByte(element); 2438 ADD_FAILURE() << "Should not have reached this line."; 2439 } 2440 catch (const std::invalid_argument& e) 2441 { 2442 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2443 } 2444 2445 // Test where fails: register value is invalid 2446 try 2447 { 2448 const json element = R"( 2449 { 2450 "register": "0x0Z", 2451 "value": "0xCC", 2452 "mask": "0xF7" 2453 } 2454 )"_json; 2455 parseI2CCompareByte(element); 2456 ADD_FAILURE() << "Should not have reached this line."; 2457 } 2458 catch (const std::invalid_argument& e) 2459 { 2460 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2461 } 2462 2463 // Test where fails: value value is invalid 2464 try 2465 { 2466 const json element = R"( 2467 { 2468 "register": "0x0A", 2469 "value": "0xCCC", 2470 "mask": "0xF7" 2471 } 2472 )"_json; 2473 parseI2CCompareByte(element); 2474 ADD_FAILURE() << "Should not have reached this line."; 2475 } 2476 catch (const std::invalid_argument& e) 2477 { 2478 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2479 } 2480 2481 // Test where fails: mask value is invalid 2482 try 2483 { 2484 const json element = R"( 2485 { 2486 "register": "0x0A", 2487 "value": "0xCC", 2488 "mask": "F7" 2489 } 2490 )"_json; 2491 parseI2CCompareByte(element); 2492 ADD_FAILURE() << "Should not have reached this line."; 2493 } 2494 catch (const std::invalid_argument& e) 2495 { 2496 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2497 } 2498 2499 // Test where fails: Required register property not specified 2500 try 2501 { 2502 const json element = R"( 2503 { 2504 "value": "0xCC", 2505 "mask": "0xF7" 2506 } 2507 )"_json; 2508 parseI2CCompareByte(element); 2509 ADD_FAILURE() << "Should not have reached this line."; 2510 } 2511 catch (const std::invalid_argument& e) 2512 { 2513 EXPECT_STREQ(e.what(), "Required property missing: register"); 2514 } 2515 2516 // Test where fails: Required value property not specified 2517 try 2518 { 2519 const json element = R"( 2520 { 2521 "register": "0x0A", 2522 "mask": "0xF7" 2523 } 2524 )"_json; 2525 parseI2CCompareByte(element); 2526 ADD_FAILURE() << "Should not have reached this line."; 2527 } 2528 catch (const std::invalid_argument& e) 2529 { 2530 EXPECT_STREQ(e.what(), "Required property missing: value"); 2531 } 2532 } 2533 2534 TEST(ConfigFileParserTests, ParseI2CCompareBytes) 2535 { 2536 // Test where works: Only required properties specified 2537 { 2538 const json element = R"( 2539 { 2540 "register": "0x0A", 2541 "values": [ "0xCC", "0xFF" ] 2542 } 2543 )"_json; 2544 std::unique_ptr<I2CCompareBytesAction> action = 2545 parseI2CCompareBytes(element); 2546 EXPECT_EQ(action->getRegister(), 0x0A); 2547 EXPECT_EQ(action->getValues().size(), 2); 2548 EXPECT_EQ(action->getValues()[0], 0xCC); 2549 EXPECT_EQ(action->getValues()[1], 0xFF); 2550 EXPECT_EQ(action->getMasks().size(), 2); 2551 EXPECT_EQ(action->getMasks()[0], 0xFF); 2552 EXPECT_EQ(action->getMasks()[1], 0xFF); 2553 } 2554 2555 // Test where works: All properties specified 2556 { 2557 const json element = R"( 2558 { 2559 "register": "0x0A", 2560 "values": [ "0xCC", "0xFF" ], 2561 "masks": [ "0x7F", "0x77" ] 2562 } 2563 )"_json; 2564 std::unique_ptr<I2CCompareBytesAction> action = 2565 parseI2CCompareBytes(element); 2566 EXPECT_EQ(action->getRegister(), 0x0A); 2567 EXPECT_EQ(action->getValues().size(), 2); 2568 EXPECT_EQ(action->getValues()[0], 0xCC); 2569 EXPECT_EQ(action->getValues()[1], 0xFF); 2570 EXPECT_EQ(action->getMasks().size(), 2); 2571 EXPECT_EQ(action->getMasks()[0], 0x7F); 2572 EXPECT_EQ(action->getMasks()[1], 0x77); 2573 } 2574 2575 // Test where fails: Element is not an object 2576 try 2577 { 2578 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2579 parseI2CCompareBytes(element); 2580 ADD_FAILURE() << "Should not have reached this line."; 2581 } 2582 catch (const std::invalid_argument& e) 2583 { 2584 EXPECT_STREQ(e.what(), "Element is not an object"); 2585 } 2586 2587 // Test where fails: Invalid property specified 2588 try 2589 { 2590 const json element = R"( 2591 { 2592 "register": "0x0A", 2593 "values": [ "0xCC", "0xFF" ], 2594 "masks": [ "0x7F", "0x7F" ], 2595 "foo": 1 2596 } 2597 )"_json; 2598 parseI2CCompareBytes(element); 2599 ADD_FAILURE() << "Should not have reached this line."; 2600 } 2601 catch (const std::invalid_argument& e) 2602 { 2603 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2604 } 2605 2606 // Test where fails: register value is invalid 2607 try 2608 { 2609 const json element = R"( 2610 { 2611 "register": "0x0Z", 2612 "values": [ "0xCC", "0xFF" ], 2613 "masks": [ "0x7F", "0x7F" ] 2614 } 2615 )"_json; 2616 parseI2CCompareBytes(element); 2617 ADD_FAILURE() << "Should not have reached this line."; 2618 } 2619 catch (const std::invalid_argument& e) 2620 { 2621 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2622 } 2623 2624 // Test where fails: values value is invalid 2625 try 2626 { 2627 const json element = R"( 2628 { 2629 "register": "0x0A", 2630 "values": [ "0xCCC", "0xFF" ], 2631 "masks": [ "0x7F", "0x7F" ] 2632 } 2633 )"_json; 2634 parseI2CCompareBytes(element); 2635 ADD_FAILURE() << "Should not have reached this line."; 2636 } 2637 catch (const std::invalid_argument& e) 2638 { 2639 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2640 } 2641 2642 // Test where fails: masks value is invalid 2643 try 2644 { 2645 const json element = R"( 2646 { 2647 "register": "0x0A", 2648 "values": [ "0xCC", "0xFF" ], 2649 "masks": [ "F", "0x7F" ] 2650 } 2651 )"_json; 2652 parseI2CCompareBytes(element); 2653 ADD_FAILURE() << "Should not have reached this line."; 2654 } 2655 catch (const std::invalid_argument& e) 2656 { 2657 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2658 } 2659 2660 // Test where fails: number of elements in masks is invalid 2661 try 2662 { 2663 const json element = R"( 2664 { 2665 "register": "0x0A", 2666 "values": [ "0xCC", "0xFF" ], 2667 "masks": [ "0x7F" ] 2668 } 2669 )"_json; 2670 parseI2CCompareBytes(element); 2671 ADD_FAILURE() << "Should not have reached this line."; 2672 } 2673 catch (const std::invalid_argument& e) 2674 { 2675 EXPECT_STREQ(e.what(), "Invalid number of elements in masks"); 2676 } 2677 2678 // Test where fails: Required register property not specified 2679 try 2680 { 2681 const json element = R"( 2682 { 2683 "values": [ "0xCC", "0xFF" ] 2684 } 2685 )"_json; 2686 parseI2CCompareBytes(element); 2687 ADD_FAILURE() << "Should not have reached this line."; 2688 } 2689 catch (const std::invalid_argument& e) 2690 { 2691 EXPECT_STREQ(e.what(), "Required property missing: register"); 2692 } 2693 2694 // Test where fails: Required values property not specified 2695 try 2696 { 2697 const json element = R"( 2698 { 2699 "register": "0x0A" 2700 } 2701 )"_json; 2702 parseI2CCompareBytes(element); 2703 ADD_FAILURE() << "Should not have reached this line."; 2704 } 2705 catch (const std::invalid_argument& e) 2706 { 2707 EXPECT_STREQ(e.what(), "Required property missing: values"); 2708 } 2709 } 2710 2711 TEST(ConfigFileParserTests, ParseI2CWriteBit) 2712 { 2713 // Test where works 2714 { 2715 const json element = R"( 2716 { 2717 "register": "0xA0", 2718 "position": 3, 2719 "value": 0 2720 } 2721 )"_json; 2722 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element); 2723 EXPECT_EQ(action->getRegister(), 0xA0); 2724 EXPECT_EQ(action->getPosition(), 3); 2725 EXPECT_EQ(action->getValue(), 0); 2726 } 2727 2728 // Test where fails: Invalid property specified 2729 try 2730 { 2731 const json element = R"( 2732 { 2733 "register": "0xA0", 2734 "position": 3, 2735 "value": 0, 2736 "foo": 3 2737 } 2738 )"_json; 2739 parseI2CWriteBit(element); 2740 ADD_FAILURE() << "Should not have reached this line."; 2741 } 2742 catch (const std::invalid_argument& e) 2743 { 2744 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2745 } 2746 2747 // Test where fails: Element is not an object 2748 try 2749 { 2750 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2751 parseI2CWriteBit(element); 2752 ADD_FAILURE() << "Should not have reached this line."; 2753 } 2754 catch (const std::invalid_argument& e) 2755 { 2756 EXPECT_STREQ(e.what(), "Element is not an object"); 2757 } 2758 2759 // Test where fails: register value is invalid 2760 try 2761 { 2762 const json element = R"( 2763 { 2764 "register": "0xAG", 2765 "position": 3, 2766 "value": 0 2767 } 2768 )"_json; 2769 parseI2CWriteBit(element); 2770 ADD_FAILURE() << "Should not have reached this line."; 2771 } 2772 catch (const std::invalid_argument& e) 2773 { 2774 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2775 } 2776 2777 // Test where fails: position value is invalid 2778 try 2779 { 2780 const json element = R"( 2781 { 2782 "register": "0xA0", 2783 "position": 8, 2784 "value": 0 2785 } 2786 )"_json; 2787 parseI2CWriteBit(element); 2788 ADD_FAILURE() << "Should not have reached this line."; 2789 } 2790 catch (const std::invalid_argument& e) 2791 { 2792 EXPECT_STREQ(e.what(), "Element is not a bit position"); 2793 } 2794 2795 // Test where fails: value value is invalid 2796 try 2797 { 2798 const json element = R"( 2799 { 2800 "register": "0xA0", 2801 "position": 3, 2802 "value": 2 2803 } 2804 )"_json; 2805 parseI2CWriteBit(element); 2806 ADD_FAILURE() << "Should not have reached this line."; 2807 } 2808 catch (const std::invalid_argument& e) 2809 { 2810 EXPECT_STREQ(e.what(), "Element is not a bit value"); 2811 } 2812 2813 // Test where fails: Required register property not specified 2814 try 2815 { 2816 const json element = R"( 2817 { 2818 "position": 3, 2819 "value": 0 2820 } 2821 )"_json; 2822 parseI2CWriteBit(element); 2823 ADD_FAILURE() << "Should not have reached this line."; 2824 } 2825 catch (const std::invalid_argument& e) 2826 { 2827 EXPECT_STREQ(e.what(), "Required property missing: register"); 2828 } 2829 2830 // Test where fails: Required position property not specified 2831 try 2832 { 2833 const json element = R"( 2834 { 2835 "register": "0xA0", 2836 "value": 0 2837 } 2838 )"_json; 2839 parseI2CWriteBit(element); 2840 ADD_FAILURE() << "Should not have reached this line."; 2841 } 2842 catch (const std::invalid_argument& e) 2843 { 2844 EXPECT_STREQ(e.what(), "Required property missing: position"); 2845 } 2846 2847 // Test where fails: Required value property not specified 2848 try 2849 { 2850 const json element = R"( 2851 { 2852 "register": "0xA0", 2853 "position": 3 2854 } 2855 )"_json; 2856 parseI2CWriteBit(element); 2857 ADD_FAILURE() << "Should not have reached this line."; 2858 } 2859 catch (const std::invalid_argument& e) 2860 { 2861 EXPECT_STREQ(e.what(), "Required property missing: value"); 2862 } 2863 } 2864 2865 TEST(ConfigFileParserTests, ParseI2CWriteByte) 2866 { 2867 // Test where works: Only required properties specified 2868 { 2869 const json element = R"( 2870 { 2871 "register": "0x0A", 2872 "value": "0xCC" 2873 } 2874 )"_json; 2875 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element); 2876 EXPECT_EQ(action->getRegister(), 0x0A); 2877 EXPECT_EQ(action->getValue(), 0xCC); 2878 EXPECT_EQ(action->getMask(), 0xFF); 2879 } 2880 2881 // Test where works: All properties specified 2882 { 2883 const json element = R"( 2884 { 2885 "register": "0x0A", 2886 "value": "0xCC", 2887 "mask": "0xF7" 2888 } 2889 )"_json; 2890 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element); 2891 EXPECT_EQ(action->getRegister(), 0x0A); 2892 EXPECT_EQ(action->getValue(), 0xCC); 2893 EXPECT_EQ(action->getMask(), 0xF7); 2894 } 2895 2896 // Test where fails: Element is not an object 2897 try 2898 { 2899 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2900 parseI2CWriteByte(element); 2901 ADD_FAILURE() << "Should not have reached this line."; 2902 } 2903 catch (const std::invalid_argument& e) 2904 { 2905 EXPECT_STREQ(e.what(), "Element is not an object"); 2906 } 2907 2908 // Test where fails: Invalid property specified 2909 try 2910 { 2911 const json element = R"( 2912 { 2913 "register": "0x0A", 2914 "value": "0xCC", 2915 "mask": "0xF7", 2916 "foo": 1 2917 } 2918 )"_json; 2919 parseI2CWriteByte(element); 2920 ADD_FAILURE() << "Should not have reached this line."; 2921 } 2922 catch (const std::invalid_argument& e) 2923 { 2924 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2925 } 2926 2927 // Test where fails: register value is invalid 2928 try 2929 { 2930 const json element = R"( 2931 { 2932 "register": "0x0Z", 2933 "value": "0xCC", 2934 "mask": "0xF7" 2935 } 2936 )"_json; 2937 parseI2CWriteByte(element); 2938 ADD_FAILURE() << "Should not have reached this line."; 2939 } 2940 catch (const std::invalid_argument& e) 2941 { 2942 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2943 } 2944 2945 // Test where fails: value value is invalid 2946 try 2947 { 2948 const json element = R"( 2949 { 2950 "register": "0x0A", 2951 "value": "0xCCC", 2952 "mask": "0xF7" 2953 } 2954 )"_json; 2955 parseI2CWriteByte(element); 2956 ADD_FAILURE() << "Should not have reached this line."; 2957 } 2958 catch (const std::invalid_argument& e) 2959 { 2960 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2961 } 2962 2963 // Test where fails: mask value is invalid 2964 try 2965 { 2966 const json element = R"( 2967 { 2968 "register": "0x0A", 2969 "value": "0xCC", 2970 "mask": "F7" 2971 } 2972 )"_json; 2973 parseI2CWriteByte(element); 2974 ADD_FAILURE() << "Should not have reached this line."; 2975 } 2976 catch (const std::invalid_argument& e) 2977 { 2978 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2979 } 2980 2981 // Test where fails: Required register property not specified 2982 try 2983 { 2984 const json element = R"( 2985 { 2986 "value": "0xCC", 2987 "mask": "0xF7" 2988 } 2989 )"_json; 2990 parseI2CWriteByte(element); 2991 ADD_FAILURE() << "Should not have reached this line."; 2992 } 2993 catch (const std::invalid_argument& e) 2994 { 2995 EXPECT_STREQ(e.what(), "Required property missing: register"); 2996 } 2997 2998 // Test where fails: Required value property not specified 2999 try 3000 { 3001 const json element = R"( 3002 { 3003 "register": "0x0A", 3004 "mask": "0xF7" 3005 } 3006 )"_json; 3007 parseI2CWriteByte(element); 3008 ADD_FAILURE() << "Should not have reached this line."; 3009 } 3010 catch (const std::invalid_argument& e) 3011 { 3012 EXPECT_STREQ(e.what(), "Required property missing: value"); 3013 } 3014 } 3015 3016 TEST(ConfigFileParserTests, ParseI2CWriteBytes) 3017 { 3018 // Test where works: Only required properties specified 3019 { 3020 const json element = R"( 3021 { 3022 "register": "0x0A", 3023 "values": [ "0xCC", "0xFF" ] 3024 } 3025 )"_json; 3026 std::unique_ptr<I2CWriteBytesAction> action = 3027 parseI2CWriteBytes(element); 3028 EXPECT_EQ(action->getRegister(), 0x0A); 3029 EXPECT_EQ(action->getValues().size(), 2); 3030 EXPECT_EQ(action->getValues()[0], 0xCC); 3031 EXPECT_EQ(action->getValues()[1], 0xFF); 3032 EXPECT_EQ(action->getMasks().size(), 0); 3033 } 3034 3035 // Test where works: All properties specified 3036 { 3037 const json element = R"( 3038 { 3039 "register": "0x0A", 3040 "values": [ "0xCC", "0xFF" ], 3041 "masks": [ "0x7F", "0x77" ] 3042 } 3043 )"_json; 3044 std::unique_ptr<I2CWriteBytesAction> action = 3045 parseI2CWriteBytes(element); 3046 EXPECT_EQ(action->getRegister(), 0x0A); 3047 EXPECT_EQ(action->getValues().size(), 2); 3048 EXPECT_EQ(action->getValues()[0], 0xCC); 3049 EXPECT_EQ(action->getValues()[1], 0xFF); 3050 EXPECT_EQ(action->getMasks().size(), 2); 3051 EXPECT_EQ(action->getMasks()[0], 0x7F); 3052 EXPECT_EQ(action->getMasks()[1], 0x77); 3053 } 3054 3055 // Test where fails: Element is not an object 3056 try 3057 { 3058 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3059 parseI2CWriteBytes(element); 3060 ADD_FAILURE() << "Should not have reached this line."; 3061 } 3062 catch (const std::invalid_argument& e) 3063 { 3064 EXPECT_STREQ(e.what(), "Element is not an object"); 3065 } 3066 3067 // Test where fails: Invalid property specified 3068 try 3069 { 3070 const json element = R"( 3071 { 3072 "register": "0x0A", 3073 "values": [ "0xCC", "0xFF" ], 3074 "masks": [ "0x7F", "0x7F" ], 3075 "foo": 1 3076 } 3077 )"_json; 3078 parseI2CWriteBytes(element); 3079 ADD_FAILURE() << "Should not have reached this line."; 3080 } 3081 catch (const std::invalid_argument& e) 3082 { 3083 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3084 } 3085 3086 // Test where fails: register value is invalid 3087 try 3088 { 3089 const json element = R"( 3090 { 3091 "register": "0x0Z", 3092 "values": [ "0xCC", "0xFF" ], 3093 "masks": [ "0x7F", "0x7F" ] 3094 } 3095 )"_json; 3096 parseI2CWriteBytes(element); 3097 ADD_FAILURE() << "Should not have reached this line."; 3098 } 3099 catch (const std::invalid_argument& e) 3100 { 3101 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 3102 } 3103 3104 // Test where fails: values value is invalid 3105 try 3106 { 3107 const json element = R"( 3108 { 3109 "register": "0x0A", 3110 "values": [ "0xCCC", "0xFF" ], 3111 "masks": [ "0x7F", "0x7F" ] 3112 } 3113 )"_json; 3114 parseI2CWriteBytes(element); 3115 ADD_FAILURE() << "Should not have reached this line."; 3116 } 3117 catch (const std::invalid_argument& e) 3118 { 3119 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 3120 } 3121 3122 // Test where fails: masks value is invalid 3123 try 3124 { 3125 const json element = R"( 3126 { 3127 "register": "0x0A", 3128 "values": [ "0xCC", "0xFF" ], 3129 "masks": [ "F", "0x7F" ] 3130 } 3131 )"_json; 3132 parseI2CWriteBytes(element); 3133 ADD_FAILURE() << "Should not have reached this line."; 3134 } 3135 catch (const std::invalid_argument& e) 3136 { 3137 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 3138 } 3139 3140 // Test where fails: number of elements in masks is invalid 3141 try 3142 { 3143 const json element = R"( 3144 { 3145 "register": "0x0A", 3146 "values": [ "0xCC", "0xFF" ], 3147 "masks": [ "0x7F" ] 3148 } 3149 )"_json; 3150 parseI2CWriteBytes(element); 3151 ADD_FAILURE() << "Should not have reached this line."; 3152 } 3153 catch (const std::invalid_argument& e) 3154 { 3155 EXPECT_STREQ(e.what(), "Invalid number of elements in masks"); 3156 } 3157 3158 // Test where fails: Required register property not specified 3159 try 3160 { 3161 const json element = R"( 3162 { 3163 "values": [ "0xCC", "0xFF" ] 3164 } 3165 )"_json; 3166 parseI2CWriteBytes(element); 3167 ADD_FAILURE() << "Should not have reached this line."; 3168 } 3169 catch (const std::invalid_argument& e) 3170 { 3171 EXPECT_STREQ(e.what(), "Required property missing: register"); 3172 } 3173 3174 // Test where fails: Required values property not specified 3175 try 3176 { 3177 const json element = R"( 3178 { 3179 "register": "0x0A" 3180 } 3181 )"_json; 3182 parseI2CWriteBytes(element); 3183 ADD_FAILURE() << "Should not have reached this line."; 3184 } 3185 catch (const std::invalid_argument& e) 3186 { 3187 EXPECT_STREQ(e.what(), "Required property missing: values"); 3188 } 3189 } 3190 3191 TEST(ConfigFileParserTests, ParseIf) 3192 { 3193 // Test where works: Only required properties specified 3194 { 3195 const json element = R"( 3196 { 3197 "condition": { "run_rule": "is_downlevel_regulator" }, 3198 "then": [ { "run_rule": "configure_downlevel_regulator" }, 3199 { "run_rule": "configure_standard_regulator" } ] 3200 } 3201 )"_json; 3202 std::unique_ptr<IfAction> action = parseIf(element); 3203 EXPECT_NE(action->getConditionAction().get(), nullptr); 3204 EXPECT_EQ(action->getThenActions().size(), 2); 3205 EXPECT_EQ(action->getElseActions().size(), 0); 3206 } 3207 3208 // Test where works: All properties specified 3209 { 3210 const json element = R"( 3211 { 3212 "condition": { "run_rule": "is_downlevel_regulator" }, 3213 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 3214 "else": [ { "run_rule": "configure_standard_regulator" } ] 3215 } 3216 )"_json; 3217 std::unique_ptr<IfAction> action = parseIf(element); 3218 EXPECT_NE(action->getConditionAction().get(), nullptr); 3219 EXPECT_EQ(action->getThenActions().size(), 1); 3220 EXPECT_EQ(action->getElseActions().size(), 1); 3221 } 3222 3223 // Test where fails: Required condition property not specified 3224 try 3225 { 3226 const json element = R"( 3227 { 3228 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 3229 "else": [ { "run_rule": "configure_standard_regulator" } ] 3230 } 3231 )"_json; 3232 parseIf(element); 3233 ADD_FAILURE() << "Should not have reached this line."; 3234 } 3235 catch (const std::invalid_argument& e) 3236 { 3237 EXPECT_STREQ(e.what(), "Required property missing: condition"); 3238 } 3239 3240 // Test where fails: Required then property not specified 3241 try 3242 { 3243 const json element = R"( 3244 { 3245 "condition": { "run_rule": "is_downlevel_regulator" }, 3246 "else": [ { "run_rule": "configure_standard_regulator" } ] 3247 } 3248 )"_json; 3249 parseIf(element); 3250 ADD_FAILURE() << "Should not have reached this line."; 3251 } 3252 catch (const std::invalid_argument& e) 3253 { 3254 EXPECT_STREQ(e.what(), "Required property missing: then"); 3255 } 3256 3257 // Test where fails: condition value is invalid 3258 try 3259 { 3260 const json element = R"( 3261 { 3262 "condition": 1, 3263 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 3264 "else": [ { "run_rule": "configure_standard_regulator" } ] 3265 } 3266 )"_json; 3267 parseIf(element); 3268 ADD_FAILURE() << "Should not have reached this line."; 3269 } 3270 catch (const std::invalid_argument& e) 3271 { 3272 EXPECT_STREQ(e.what(), "Element is not an object"); 3273 } 3274 3275 // Test where fails: then value is invalid 3276 try 3277 { 3278 const json element = R"( 3279 { 3280 "condition": { "run_rule": "is_downlevel_regulator" }, 3281 "then": "foo", 3282 "else": [ { "run_rule": "configure_standard_regulator" } ] 3283 } 3284 )"_json; 3285 parseIf(element); 3286 ADD_FAILURE() << "Should not have reached this line."; 3287 } 3288 catch (const std::invalid_argument& e) 3289 { 3290 EXPECT_STREQ(e.what(), "Element is not an array"); 3291 } 3292 3293 // Test where fails: else value is invalid 3294 try 3295 { 3296 const json element = R"( 3297 { 3298 "condition": { "run_rule": "is_downlevel_regulator" }, 3299 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 3300 "else": 1 3301 } 3302 )"_json; 3303 parseIf(element); 3304 ADD_FAILURE() << "Should not have reached this line."; 3305 } 3306 catch (const std::invalid_argument& e) 3307 { 3308 EXPECT_STREQ(e.what(), "Element is not an array"); 3309 } 3310 3311 // Test where fails: Invalid property specified 3312 try 3313 { 3314 const json element = R"( 3315 { 3316 "condition": { "run_rule": "is_downlevel_regulator" }, 3317 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 3318 "foo": "bar" 3319 } 3320 )"_json; 3321 parseIf(element); 3322 ADD_FAILURE() << "Should not have reached this line."; 3323 } 3324 catch (const std::invalid_argument& e) 3325 { 3326 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3327 } 3328 3329 // Test where fails: Element is not an object 3330 try 3331 { 3332 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3333 parseIf(element); 3334 ADD_FAILURE() << "Should not have reached this line."; 3335 } 3336 catch (const std::invalid_argument& e) 3337 { 3338 EXPECT_STREQ(e.what(), "Element is not an object"); 3339 } 3340 } 3341 3342 TEST(ConfigFileParserTests, ParseInt8) 3343 { 3344 // Test where works: INT8_MIN 3345 { 3346 const json element = R"( -128 )"_json; 3347 int8_t value = parseInt8(element); 3348 EXPECT_EQ(value, -128); 3349 } 3350 3351 // Test where works: INT8_MAX 3352 { 3353 const json element = R"( 127 )"_json; 3354 int8_t value = parseInt8(element); 3355 EXPECT_EQ(value, 127); 3356 } 3357 3358 // Test where fails: Element is not an integer 3359 try 3360 { 3361 const json element = R"( 1.03 )"_json; 3362 parseInt8(element); 3363 ADD_FAILURE() << "Should not have reached this line."; 3364 } 3365 catch (const std::invalid_argument& e) 3366 { 3367 EXPECT_STREQ(e.what(), "Element is not an integer"); 3368 } 3369 3370 // Test where fails: Value < INT8_MIN 3371 try 3372 { 3373 const json element = R"( -129 )"_json; 3374 parseInt8(element); 3375 ADD_FAILURE() << "Should not have reached this line."; 3376 } 3377 catch (const std::invalid_argument& e) 3378 { 3379 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 3380 } 3381 3382 // Test where fails: Value > INT8_MAX 3383 try 3384 { 3385 const json element = R"( 128 )"_json; 3386 parseInt8(element); 3387 ADD_FAILURE() << "Should not have reached this line."; 3388 } 3389 catch (const std::invalid_argument& e) 3390 { 3391 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 3392 } 3393 } 3394 3395 TEST(ConfigFileParserTests, ParseInventoryPath) 3396 { 3397 // Test where works: Inventory path has a leading '/' 3398 { 3399 const json element = "/system/chassis/motherboard/cpu3"; 3400 std::string value = parseInventoryPath(element); 3401 EXPECT_EQ( 3402 value, 3403 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu3"); 3404 } 3405 3406 // Test where works: Inventory path does not have a leading '/' 3407 { 3408 const json element = "system/chassis/motherboard/cpu1"; 3409 std::string value = parseInventoryPath(element); 3410 EXPECT_EQ( 3411 value, 3412 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1"); 3413 } 3414 3415 // Test where fails: JSON element is not a string 3416 try 3417 { 3418 const json element = R"( { "foo": "bar" } )"_json; 3419 parseInventoryPath(element); 3420 ADD_FAILURE() << "Should not have reached this line."; 3421 } 3422 catch (const std::invalid_argument& e) 3423 { 3424 EXPECT_STREQ(e.what(), "Element is not a string"); 3425 } 3426 3427 // Test where fails: JSON element contains an empty string 3428 try 3429 { 3430 const json element = ""; 3431 parseInventoryPath(element); 3432 ADD_FAILURE() << "Should not have reached this line."; 3433 } 3434 catch (const std::invalid_argument& e) 3435 { 3436 EXPECT_STREQ(e.what(), "Element contains an empty string"); 3437 } 3438 } 3439 3440 TEST(ConfigFileParserTests, ParseLogPhaseFault) 3441 { 3442 // Test where works 3443 { 3444 const json element = R"( 3445 { 3446 "type": "n+1" 3447 } 3448 )"_json; 3449 std::unique_ptr<LogPhaseFaultAction> action = 3450 parseLogPhaseFault(element); 3451 EXPECT_EQ(action->getType(), PhaseFaultType::n_plus_1); 3452 } 3453 3454 // Test where fails: Element is not an object 3455 try 3456 { 3457 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3458 parseLogPhaseFault(element); 3459 ADD_FAILURE() << "Should not have reached this line."; 3460 } 3461 catch (const std::invalid_argument& e) 3462 { 3463 EXPECT_STREQ(e.what(), "Element is not an object"); 3464 } 3465 3466 // Test where fails: Required type property not specified 3467 try 3468 { 3469 const json element = R"( 3470 { 3471 } 3472 )"_json; 3473 parseLogPhaseFault(element); 3474 ADD_FAILURE() << "Should not have reached this line."; 3475 } 3476 catch (const std::invalid_argument& e) 3477 { 3478 EXPECT_STREQ(e.what(), "Required property missing: type"); 3479 } 3480 3481 // Test where fails: type value is invalid 3482 try 3483 { 3484 const json element = R"( 3485 { 3486 "type": "n+2" 3487 } 3488 )"_json; 3489 parseLogPhaseFault(element); 3490 ADD_FAILURE() << "Should not have reached this line."; 3491 } 3492 catch (const std::invalid_argument& e) 3493 { 3494 EXPECT_STREQ(e.what(), "Element is not a phase fault type"); 3495 } 3496 3497 // Test where fails: Invalid property specified 3498 try 3499 { 3500 const json element = R"( 3501 { 3502 "type": "n+1", 3503 "foo": 1 3504 } 3505 )"_json; 3506 parseLogPhaseFault(element); 3507 ADD_FAILURE() << "Should not have reached this line."; 3508 } 3509 catch (const std::invalid_argument& e) 3510 { 3511 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3512 } 3513 } 3514 3515 TEST(ConfigFileParserTests, ParseNot) 3516 { 3517 // Test where works 3518 { 3519 const json element = R"( 3520 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } } 3521 )"_json; 3522 std::unique_ptr<NotAction> action = parseNot(element); 3523 EXPECT_NE(action->getAction().get(), nullptr); 3524 } 3525 3526 // Test where fails: Element is not an object 3527 try 3528 { 3529 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3530 parseNot(element); 3531 ADD_FAILURE() << "Should not have reached this line."; 3532 } 3533 catch (const std::invalid_argument& e) 3534 { 3535 EXPECT_STREQ(e.what(), "Element is not an object"); 3536 } 3537 } 3538 3539 TEST(ConfigFileParserTests, ParseOr) 3540 { 3541 // Test where works: Element is an array with 2 actions 3542 { 3543 const json element = R"( 3544 [ 3545 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 3546 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 3547 ] 3548 )"_json; 3549 std::unique_ptr<OrAction> action = parseOr(element); 3550 EXPECT_EQ(action->getActions().size(), 2); 3551 } 3552 3553 // Test where fails: Element is an array with 1 action 3554 try 3555 { 3556 const json element = R"( 3557 [ 3558 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } } 3559 ] 3560 )"_json; 3561 parseOr(element); 3562 ADD_FAILURE() << "Should not have reached this line."; 3563 } 3564 catch (const std::invalid_argument& e) 3565 { 3566 EXPECT_STREQ(e.what(), "Array must contain two or more actions"); 3567 } 3568 3569 // Test where fails: Element is not an array 3570 try 3571 { 3572 const json element = R"( 3573 { 3574 "foo": "bar" 3575 } 3576 )"_json; 3577 parseOr(element); 3578 ADD_FAILURE() << "Should not have reached this line."; 3579 } 3580 catch (const std::invalid_argument& e) 3581 { 3582 EXPECT_STREQ(e.what(), "Element is not an array"); 3583 } 3584 } 3585 3586 TEST(ConfigFileParserTests, ParsePhaseFaultDetection) 3587 { 3588 // Test where works: actions specified: optional properties not specified 3589 { 3590 const json element = R"( 3591 { 3592 "actions": [ 3593 { "run_rule": "detect_phase_fault_rule" } 3594 ] 3595 } 3596 )"_json; 3597 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection = 3598 parsePhaseFaultDetection(element); 3599 EXPECT_EQ(phaseFaultDetection->getActions().size(), 1); 3600 EXPECT_EQ(phaseFaultDetection->getDeviceID(), ""); 3601 } 3602 3603 // Test where works: rule_id specified: optional properties specified 3604 { 3605 const json element = R"( 3606 { 3607 "comments": [ "Detect phase fault using I/O expander" ], 3608 "device_id": "io_expander", 3609 "rule_id": "detect_phase_fault_rule" 3610 } 3611 )"_json; 3612 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection = 3613 parsePhaseFaultDetection(element); 3614 EXPECT_EQ(phaseFaultDetection->getActions().size(), 1); 3615 EXPECT_EQ(phaseFaultDetection->getDeviceID(), "io_expander"); 3616 } 3617 3618 // Test where fails: Element is not an object 3619 try 3620 { 3621 const json element = R"( [ "foo", "bar" ] )"_json; 3622 parsePhaseFaultDetection(element); 3623 ADD_FAILURE() << "Should not have reached this line."; 3624 } 3625 catch (const std::invalid_argument& e) 3626 { 3627 EXPECT_STREQ(e.what(), "Element is not an object"); 3628 } 3629 3630 // Test where fails: device_id value is invalid 3631 try 3632 { 3633 const json element = R"( 3634 { 3635 "device_id": 1, 3636 "rule_id": "detect_phase_fault_rule" 3637 } 3638 )"_json; 3639 parsePhaseFaultDetection(element); 3640 ADD_FAILURE() << "Should not have reached this line."; 3641 } 3642 catch (const std::invalid_argument& e) 3643 { 3644 EXPECT_STREQ(e.what(), "Element is not a string"); 3645 } 3646 3647 // Test where fails: rule_id value is invalid 3648 try 3649 { 3650 const json element = R"( 3651 { 3652 "rule_id": 1 3653 } 3654 )"_json; 3655 parsePhaseFaultDetection(element); 3656 ADD_FAILURE() << "Should not have reached this line."; 3657 } 3658 catch (const std::invalid_argument& e) 3659 { 3660 EXPECT_STREQ(e.what(), "Element is not a string"); 3661 } 3662 3663 // Test where fails: actions object is invalid 3664 try 3665 { 3666 const json element = R"( 3667 { 3668 "actions": 1 3669 } 3670 )"_json; 3671 parsePhaseFaultDetection(element); 3672 ADD_FAILURE() << "Should not have reached this line."; 3673 } 3674 catch (const std::invalid_argument& e) 3675 { 3676 EXPECT_STREQ(e.what(), "Element is not an array"); 3677 } 3678 3679 // Test where fails: Required actions or rule_id property not specified 3680 try 3681 { 3682 const json element = R"( 3683 { 3684 "device_id": "io_expander" 3685 } 3686 )"_json; 3687 parsePhaseFaultDetection(element); 3688 ADD_FAILURE() << "Should not have reached this line."; 3689 } 3690 catch (const std::invalid_argument& e) 3691 { 3692 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 3693 "either rule_id or actions"); 3694 } 3695 3696 // Test where fails: Required actions or rule_id property both specified 3697 try 3698 { 3699 const json element = R"( 3700 { 3701 "rule_id": "detect_phase_fault_rule", 3702 "actions": [ 3703 { "run_rule": "detect_phase_fault_rule" } 3704 ] 3705 } 3706 )"_json; 3707 parsePhaseFaultDetection(element); 3708 ADD_FAILURE() << "Should not have reached this line."; 3709 } 3710 catch (const std::invalid_argument& e) 3711 { 3712 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 3713 "either rule_id or actions"); 3714 } 3715 3716 // Test where fails: Invalid property specified 3717 try 3718 { 3719 const json element = R"( 3720 { 3721 "foo": "bar", 3722 "actions": [ 3723 { "run_rule": "detect_phase_fault_rule" } 3724 ] 3725 } 3726 )"_json; 3727 parsePhaseFaultDetection(element); 3728 ADD_FAILURE() << "Should not have reached this line."; 3729 } 3730 catch (const std::invalid_argument& e) 3731 { 3732 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3733 } 3734 } 3735 3736 TEST(ConfigFileParserTests, ParsePhaseFaultType) 3737 { 3738 // Test where works: n 3739 { 3740 const json element = "n"; 3741 PhaseFaultType type = parsePhaseFaultType(element); 3742 EXPECT_EQ(type, PhaseFaultType::n); 3743 } 3744 3745 // Test where works: n+1 3746 { 3747 const json element = "n+1"; 3748 PhaseFaultType type = parsePhaseFaultType(element); 3749 EXPECT_EQ(type, PhaseFaultType::n_plus_1); 3750 } 3751 3752 // Test where fails: Element is not a phase fault type 3753 try 3754 { 3755 const json element = "n+2"; 3756 parsePhaseFaultType(element); 3757 ADD_FAILURE() << "Should not have reached this line."; 3758 } 3759 catch (const std::invalid_argument& e) 3760 { 3761 EXPECT_STREQ(e.what(), "Element is not a phase fault type"); 3762 } 3763 3764 // Test where fails: Element is not a string 3765 try 3766 { 3767 const json element = R"( { "foo": "bar" } )"_json; 3768 parsePhaseFaultType(element); 3769 ADD_FAILURE() << "Should not have reached this line."; 3770 } 3771 catch (const std::invalid_argument& e) 3772 { 3773 EXPECT_STREQ(e.what(), "Element is not a string"); 3774 } 3775 } 3776 3777 TEST(ConfigFileParserTests, ParsePMBusReadSensor) 3778 { 3779 // Test where works: Only required properties specified 3780 { 3781 const json element = R"( 3782 { 3783 "type": "iout", 3784 "command": "0x8C", 3785 "format": "linear_11" 3786 } 3787 )"_json; 3788 std::unique_ptr<PMBusReadSensorAction> action = 3789 parsePMBusReadSensor(element); 3790 EXPECT_EQ(action->getType(), SensorType::iout); 3791 EXPECT_EQ(action->getCommand(), 0x8C); 3792 EXPECT_EQ(action->getFormat(), 3793 pmbus_utils::SensorDataFormat::linear_11); 3794 EXPECT_EQ(action->getExponent().has_value(), false); 3795 } 3796 3797 // Test where works: All properties specified 3798 { 3799 const json element = R"( 3800 { 3801 "type": "temperature", 3802 "command": "0x7A", 3803 "format": "linear_16", 3804 "exponent": -8 3805 } 3806 )"_json; 3807 std::unique_ptr<PMBusReadSensorAction> action = 3808 parsePMBusReadSensor(element); 3809 EXPECT_EQ(action->getType(), SensorType::temperature); 3810 EXPECT_EQ(action->getCommand(), 0x7A); 3811 EXPECT_EQ(action->getFormat(), 3812 pmbus_utils::SensorDataFormat::linear_16); 3813 EXPECT_EQ(action->getExponent().has_value(), true); 3814 EXPECT_EQ(action->getExponent().value(), -8); 3815 } 3816 3817 // Test where fails: Element is not an object 3818 try 3819 { 3820 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3821 parsePMBusReadSensor(element); 3822 ADD_FAILURE() << "Should not have reached this line."; 3823 } 3824 catch (const std::invalid_argument& e) 3825 { 3826 EXPECT_STREQ(e.what(), "Element is not an object"); 3827 } 3828 3829 // Test where fails: Invalid property specified 3830 try 3831 { 3832 const json element = R"( 3833 { 3834 "type": "iout", 3835 "command": "0x8C", 3836 "format": "linear_11", 3837 "foo": 1 3838 } 3839 )"_json; 3840 parsePMBusReadSensor(element); 3841 ADD_FAILURE() << "Should not have reached this line."; 3842 } 3843 catch (const std::invalid_argument& e) 3844 { 3845 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3846 } 3847 3848 // Test where fails: Required type property not specified 3849 try 3850 { 3851 const json element = R"( 3852 { 3853 "command": "0x8C", 3854 "format": "linear_11" 3855 } 3856 )"_json; 3857 parsePMBusReadSensor(element); 3858 ADD_FAILURE() << "Should not have reached this line."; 3859 } 3860 catch (const std::invalid_argument& e) 3861 { 3862 EXPECT_STREQ(e.what(), "Required property missing: type"); 3863 } 3864 3865 // Test where fails: Required command property not specified 3866 try 3867 { 3868 const json element = R"( 3869 { 3870 "type": "iout", 3871 "format": "linear_11" 3872 } 3873 )"_json; 3874 parsePMBusReadSensor(element); 3875 ADD_FAILURE() << "Should not have reached this line."; 3876 } 3877 catch (const std::invalid_argument& e) 3878 { 3879 EXPECT_STREQ(e.what(), "Required property missing: command"); 3880 } 3881 3882 // Test where fails: Required format property not specified 3883 try 3884 { 3885 const json element = R"( 3886 { 3887 "type": "iout", 3888 "command": "0x8C" 3889 } 3890 )"_json; 3891 parsePMBusReadSensor(element); 3892 ADD_FAILURE() << "Should not have reached this line."; 3893 } 3894 catch (const std::invalid_argument& e) 3895 { 3896 EXPECT_STREQ(e.what(), "Required property missing: format"); 3897 } 3898 3899 // Test where fails: type value is invalid 3900 try 3901 { 3902 const json element = R"( 3903 { 3904 "type": 1, 3905 "command": "0x7A", 3906 "format": "linear_16" 3907 } 3908 )"_json; 3909 parsePMBusReadSensor(element); 3910 ADD_FAILURE() << "Should not have reached this line."; 3911 } 3912 catch (const std::invalid_argument& e) 3913 { 3914 EXPECT_STREQ(e.what(), "Element is not a string"); 3915 } 3916 3917 // Test where fails: command value is invalid 3918 try 3919 { 3920 const json element = R"( 3921 { 3922 "type": "temperature", 3923 "command": 0, 3924 "format": "linear_16" 3925 } 3926 )"_json; 3927 parsePMBusReadSensor(element); 3928 ADD_FAILURE() << "Should not have reached this line."; 3929 } 3930 catch (const std::invalid_argument& e) 3931 { 3932 EXPECT_STREQ(e.what(), "Element is not a string"); 3933 } 3934 3935 // Test where fails: format value is invalid 3936 try 3937 { 3938 const json element = R"( 3939 { 3940 "type": "temperature", 3941 "command": "0x7A", 3942 "format": 1 3943 } 3944 )"_json; 3945 parsePMBusReadSensor(element); 3946 ADD_FAILURE() << "Should not have reached this line."; 3947 } 3948 catch (const std::invalid_argument& e) 3949 { 3950 EXPECT_STREQ(e.what(), "Element is not a string"); 3951 } 3952 3953 // Test where fails: exponent value is invalid 3954 try 3955 { 3956 const json element = R"( 3957 { 3958 "type": "temperature", 3959 "command": "0x7A", 3960 "format": "linear_16", 3961 "exponent": 1.3 3962 } 3963 )"_json; 3964 parsePMBusReadSensor(element); 3965 ADD_FAILURE() << "Should not have reached this line."; 3966 } 3967 catch (const std::invalid_argument& e) 3968 { 3969 EXPECT_STREQ(e.what(), "Element is not an integer"); 3970 } 3971 } 3972 3973 TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand) 3974 { 3975 // Test where works: Only required properties specified 3976 { 3977 const json element = R"( 3978 { 3979 "format": "linear" 3980 } 3981 )"_json; 3982 std::unique_ptr<PMBusWriteVoutCommandAction> action = 3983 parsePMBusWriteVoutCommand(element); 3984 EXPECT_EQ(action->getVolts().has_value(), false); 3985 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 3986 EXPECT_EQ(action->getExponent().has_value(), false); 3987 EXPECT_EQ(action->isVerified(), false); 3988 } 3989 3990 // Test where works: All properties specified 3991 { 3992 const json element = R"( 3993 { 3994 "volts": 1.03, 3995 "format": "linear", 3996 "exponent": -8, 3997 "is_verified": true 3998 } 3999 )"_json; 4000 std::unique_ptr<PMBusWriteVoutCommandAction> action = 4001 parsePMBusWriteVoutCommand(element); 4002 EXPECT_EQ(action->getVolts().has_value(), true); 4003 EXPECT_EQ(action->getVolts().value(), 1.03); 4004 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 4005 EXPECT_EQ(action->getExponent().has_value(), true); 4006 EXPECT_EQ(action->getExponent().value(), -8); 4007 EXPECT_EQ(action->isVerified(), true); 4008 } 4009 4010 // Test where fails: Element is not an object 4011 try 4012 { 4013 const json element = R"( [ "0xFF", "0x01" ] )"_json; 4014 parsePMBusWriteVoutCommand(element); 4015 ADD_FAILURE() << "Should not have reached this line."; 4016 } 4017 catch (const std::invalid_argument& e) 4018 { 4019 EXPECT_STREQ(e.what(), "Element is not an object"); 4020 } 4021 4022 // Test where fails: volts value is invalid 4023 try 4024 { 4025 const json element = R"( 4026 { 4027 "volts": "foo", 4028 "format": "linear" 4029 } 4030 )"_json; 4031 parsePMBusWriteVoutCommand(element); 4032 ADD_FAILURE() << "Should not have reached this line."; 4033 } 4034 catch (const std::invalid_argument& e) 4035 { 4036 EXPECT_STREQ(e.what(), "Element is not a number"); 4037 } 4038 4039 // Test where fails: Required format property not specified 4040 try 4041 { 4042 const json element = R"( 4043 { 4044 "volts": 1.03, 4045 "is_verified": true 4046 } 4047 )"_json; 4048 parsePMBusWriteVoutCommand(element); 4049 ADD_FAILURE() << "Should not have reached this line."; 4050 } 4051 catch (const std::invalid_argument& e) 4052 { 4053 EXPECT_STREQ(e.what(), "Required property missing: format"); 4054 } 4055 4056 // Test where fails: format value is invalid 4057 try 4058 { 4059 const json element = R"( 4060 { 4061 "format": "linear_11" 4062 } 4063 )"_json; 4064 parsePMBusWriteVoutCommand(element); 4065 ADD_FAILURE() << "Should not have reached this line."; 4066 } 4067 catch (const std::invalid_argument& e) 4068 { 4069 EXPECT_STREQ(e.what(), "Invalid format value: linear_11"); 4070 } 4071 4072 // Test where fails: exponent value is invalid 4073 try 4074 { 4075 const json element = R"( 4076 { 4077 "format": "linear", 4078 "exponent": 1.3 4079 } 4080 )"_json; 4081 parsePMBusWriteVoutCommand(element); 4082 ADD_FAILURE() << "Should not have reached this line."; 4083 } 4084 catch (const std::invalid_argument& e) 4085 { 4086 EXPECT_STREQ(e.what(), "Element is not an integer"); 4087 } 4088 4089 // Test where fails: is_verified value is invalid 4090 try 4091 { 4092 const json element = R"( 4093 { 4094 "format": "linear", 4095 "is_verified": "true" 4096 } 4097 )"_json; 4098 parsePMBusWriteVoutCommand(element); 4099 ADD_FAILURE() << "Should not have reached this line."; 4100 } 4101 catch (const std::invalid_argument& e) 4102 { 4103 EXPECT_STREQ(e.what(), "Element is not a boolean"); 4104 } 4105 4106 // Test where fails: Invalid property specified 4107 try 4108 { 4109 const json element = R"( 4110 { 4111 "format": "linear", 4112 "foo": "bar" 4113 } 4114 )"_json; 4115 parsePMBusWriteVoutCommand(element); 4116 ADD_FAILURE() << "Should not have reached this line."; 4117 } 4118 catch (const std::invalid_argument& e) 4119 { 4120 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4121 } 4122 } 4123 4124 TEST(ConfigFileParserTests, ParsePresenceDetection) 4125 { 4126 // Test where works: actions property specified 4127 { 4128 const json element = R"( 4129 { 4130 "actions": [ 4131 { "run_rule": "read_sensors_rule" } 4132 ] 4133 } 4134 )"_json; 4135 std::unique_ptr<PresenceDetection> presenceDetection = 4136 parsePresenceDetection(element); 4137 EXPECT_EQ(presenceDetection->getActions().size(), 1); 4138 } 4139 4140 // Test where works: rule_id property specified 4141 { 4142 const json element = R"( 4143 { 4144 "comments": [ "comments property" ], 4145 "rule_id": "set_voltage_rule" 4146 } 4147 )"_json; 4148 std::unique_ptr<PresenceDetection> presenceDetection = 4149 parsePresenceDetection(element); 4150 EXPECT_EQ(presenceDetection->getActions().size(), 1); 4151 } 4152 4153 // Test where fails: actions object is invalid 4154 try 4155 { 4156 const json element = R"( 4157 { 4158 "actions": 1 4159 } 4160 )"_json; 4161 parsePresenceDetection(element); 4162 ADD_FAILURE() << "Should not have reached this line."; 4163 } 4164 catch (const std::invalid_argument& e) 4165 { 4166 EXPECT_STREQ(e.what(), "Element is not an array"); 4167 } 4168 4169 // Test where fails: rule_id value is invalid 4170 try 4171 { 4172 const json element = R"( 4173 { 4174 "rule_id": 1 4175 } 4176 )"_json; 4177 parsePresenceDetection(element); 4178 ADD_FAILURE() << "Should not have reached this line."; 4179 } 4180 catch (const std::invalid_argument& e) 4181 { 4182 EXPECT_STREQ(e.what(), "Element is not a string"); 4183 } 4184 4185 // Test where fails: Required actions or rule_id property not specified 4186 try 4187 { 4188 const json element = R"( 4189 { 4190 "comments": [ "comments property" ] 4191 } 4192 )"_json; 4193 parsePresenceDetection(element); 4194 ADD_FAILURE() << "Should not have reached this line."; 4195 } 4196 catch (const std::invalid_argument& e) 4197 { 4198 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4199 "either rule_id or actions"); 4200 } 4201 4202 // Test where fails: Required actions or rule_id property both specified 4203 try 4204 { 4205 const json element = R"( 4206 { 4207 "rule_id": "set_voltage_rule", 4208 "actions": [ 4209 { "run_rule": "read_sensors_rule" } 4210 ] 4211 } 4212 )"_json; 4213 parsePresenceDetection(element); 4214 ADD_FAILURE() << "Should not have reached this line."; 4215 } 4216 catch (const std::invalid_argument& e) 4217 { 4218 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4219 "either rule_id or actions"); 4220 } 4221 4222 // Test where fails: Element is not an object 4223 try 4224 { 4225 const json element = R"( [ "foo", "bar" ] )"_json; 4226 parsePresenceDetection(element); 4227 ADD_FAILURE() << "Should not have reached this line."; 4228 } 4229 catch (const std::invalid_argument& e) 4230 { 4231 EXPECT_STREQ(e.what(), "Element is not an object"); 4232 } 4233 4234 // Test where fails: Invalid property specified 4235 try 4236 { 4237 const json element = R"( 4238 { 4239 "foo": "bar", 4240 "actions": [ 4241 { "run_rule": "read_sensors_rule" } 4242 ] 4243 } 4244 )"_json; 4245 parsePresenceDetection(element); 4246 ADD_FAILURE() << "Should not have reached this line."; 4247 } 4248 catch (const std::invalid_argument& e) 4249 { 4250 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4251 } 4252 } 4253 4254 TEST(ConfigFileParserTests, ParseRail) 4255 { 4256 // Test where works: Only required properties specified 4257 { 4258 const json element = R"( 4259 { 4260 "id": "vdd" 4261 } 4262 )"_json; 4263 std::unique_ptr<Rail> rail = parseRail(element); 4264 EXPECT_EQ(rail->getID(), "vdd"); 4265 EXPECT_EQ(rail->getConfiguration(), nullptr); 4266 EXPECT_EQ(rail->getSensorMonitoring(), nullptr); 4267 } 4268 4269 // Test where works: All properties specified 4270 { 4271 const json element = R"( 4272 { 4273 "comments": [ "comments property" ], 4274 "id": "vdd", 4275 "configuration": { 4276 "volts": 1.1, 4277 "actions": [ 4278 { 4279 "pmbus_write_vout_command": { 4280 "format": "linear" 4281 } 4282 } 4283 ] 4284 }, 4285 "sensor_monitoring": { 4286 "actions": [ 4287 { "run_rule": "read_sensors_rule" } 4288 ] 4289 } 4290 } 4291 )"_json; 4292 std::unique_ptr<Rail> rail = parseRail(element); 4293 EXPECT_EQ(rail->getID(), "vdd"); 4294 EXPECT_NE(rail->getConfiguration(), nullptr); 4295 EXPECT_NE(rail->getSensorMonitoring(), nullptr); 4296 } 4297 4298 // Test where fails: id property not specified 4299 try 4300 { 4301 const json element = R"( 4302 { 4303 "configuration": { 4304 "volts": 1.1, 4305 "actions": [ 4306 { 4307 "pmbus_write_vout_command": { 4308 "format": "linear" 4309 } 4310 } 4311 ] 4312 } 4313 } 4314 )"_json; 4315 parseRail(element); 4316 ADD_FAILURE() << "Should not have reached this line."; 4317 } 4318 catch (const std::invalid_argument& e) 4319 { 4320 EXPECT_STREQ(e.what(), "Required property missing: id"); 4321 } 4322 4323 // Test where fails: id property is invalid 4324 try 4325 { 4326 const json element = R"( 4327 { 4328 "id": "", 4329 "configuration": { 4330 "volts": 1.1, 4331 "actions": [ 4332 { 4333 "pmbus_write_vout_command": { 4334 "format": "linear" 4335 } 4336 } 4337 ] 4338 } 4339 } 4340 )"_json; 4341 parseRail(element); 4342 ADD_FAILURE() << "Should not have reached this line."; 4343 } 4344 catch (const std::invalid_argument& e) 4345 { 4346 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4347 } 4348 4349 // Test where fails: Element is not an object 4350 try 4351 { 4352 const json element = R"( [ "0xFF", "0x01" ] )"_json; 4353 parseRail(element); 4354 ADD_FAILURE() << "Should not have reached this line."; 4355 } 4356 catch (const std::invalid_argument& e) 4357 { 4358 EXPECT_STREQ(e.what(), "Element is not an object"); 4359 } 4360 4361 // Test where fails: configuration value is invalid 4362 try 4363 { 4364 const json element = R"( 4365 { 4366 "id": "vdd", 4367 "configuration": "config" 4368 } 4369 )"_json; 4370 parseRail(element); 4371 ADD_FAILURE() << "Should not have reached this line."; 4372 } 4373 catch (const std::invalid_argument& e) 4374 { 4375 EXPECT_STREQ(e.what(), "Element is not an object"); 4376 } 4377 4378 // Test where fails: sensor_monitoring value is invalid 4379 try 4380 { 4381 const json element = R"( 4382 { 4383 "comments": [ "comments property" ], 4384 "id": "vdd", 4385 "configuration": { 4386 "volts": 1.1, 4387 "actions": [ 4388 { 4389 "pmbus_write_vout_command": { 4390 "format": "linear" 4391 } 4392 } 4393 ] 4394 }, 4395 "sensor_monitoring": 1 4396 } 4397 )"_json; 4398 parseRail(element); 4399 ADD_FAILURE() << "Should not have reached this line."; 4400 } 4401 catch (const std::invalid_argument& e) 4402 { 4403 EXPECT_STREQ(e.what(), "Element is not an object"); 4404 } 4405 4406 // Test where fails: Invalid property specified 4407 try 4408 { 4409 const json element = R"( 4410 { 4411 "id": "vdd", 4412 "foo" : true 4413 } 4414 )"_json; 4415 parseRail(element); 4416 ADD_FAILURE() << "Should not have reached this line."; 4417 } 4418 catch (const std::invalid_argument& e) 4419 { 4420 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4421 } 4422 } 4423 4424 TEST(ConfigFileParserTests, ParseRailArray) 4425 { 4426 // Test where works 4427 { 4428 const json element = R"( 4429 [ 4430 { "id": "vdd" }, 4431 { "id": "vio" } 4432 ] 4433 )"_json; 4434 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element); 4435 EXPECT_EQ(rails.size(), 2); 4436 EXPECT_EQ(rails[0]->getID(), "vdd"); 4437 EXPECT_EQ(rails[1]->getID(), "vio"); 4438 } 4439 4440 // Test where fails: Element is not an array 4441 try 4442 { 4443 const json element = R"( 4444 { 4445 "foo": "bar" 4446 } 4447 )"_json; 4448 parseRailArray(element); 4449 ADD_FAILURE() << "Should not have reached this line."; 4450 } 4451 catch (const std::invalid_argument& e) 4452 { 4453 EXPECT_STREQ(e.what(), "Element is not an array"); 4454 } 4455 } 4456 4457 TEST(ConfigFileParserTests, ParseRoot) 4458 { 4459 // Test where works: Only required properties specified 4460 { 4461 const json element = R"( 4462 { 4463 "chassis": [ 4464 { "number": 1, "inventory_path": "system/chassis" } 4465 ] 4466 } 4467 )"_json; 4468 std::vector<std::unique_ptr<Rule>> rules{}; 4469 std::vector<std::unique_ptr<Chassis>> chassis{}; 4470 std::tie(rules, chassis) = parseRoot(element); 4471 EXPECT_EQ(rules.size(), 0); 4472 EXPECT_EQ(chassis.size(), 1); 4473 } 4474 4475 // Test where works: All properties specified 4476 { 4477 const json element = R"( 4478 { 4479 "comments": [ "Config file for a FooBar one-chassis system" ], 4480 "rules": [ 4481 { 4482 "id": "set_voltage_rule", 4483 "actions": [ 4484 { "pmbus_write_vout_command": { "format": "linear" } } 4485 ] 4486 } 4487 ], 4488 "chassis": [ 4489 { "number": 1, "inventory_path": "system/chassis1" }, 4490 { "number": 3, "inventory_path": "system/chassis3" } 4491 ] 4492 } 4493 )"_json; 4494 std::vector<std::unique_ptr<Rule>> rules{}; 4495 std::vector<std::unique_ptr<Chassis>> chassis{}; 4496 std::tie(rules, chassis) = parseRoot(element); 4497 EXPECT_EQ(rules.size(), 1); 4498 EXPECT_EQ(chassis.size(), 2); 4499 } 4500 4501 // Test where fails: Element is not an object 4502 try 4503 { 4504 const json element = R"( [ "0xFF", "0x01" ] )"_json; 4505 parseRoot(element); 4506 ADD_FAILURE() << "Should not have reached this line."; 4507 } 4508 catch (const std::invalid_argument& e) 4509 { 4510 EXPECT_STREQ(e.what(), "Element is not an object"); 4511 } 4512 4513 // Test where fails: chassis property not specified 4514 try 4515 { 4516 const json element = R"( 4517 { 4518 "rules": [ 4519 { 4520 "id": "set_voltage_rule", 4521 "actions": [ 4522 { "pmbus_write_vout_command": { "format": "linear" } } 4523 ] 4524 } 4525 ] 4526 } 4527 )"_json; 4528 parseRoot(element); 4529 ADD_FAILURE() << "Should not have reached this line."; 4530 } 4531 catch (const std::invalid_argument& e) 4532 { 4533 EXPECT_STREQ(e.what(), "Required property missing: chassis"); 4534 } 4535 4536 // Test where fails: Invalid property specified 4537 try 4538 { 4539 const json element = R"( 4540 { 4541 "remarks": [ "Config file for a FooBar one-chassis system" ], 4542 "chassis": [ 4543 { "number": 1, "inventory_path": "system/chassis" } 4544 ] 4545 } 4546 )"_json; 4547 parseRoot(element); 4548 ADD_FAILURE() << "Should not have reached this line."; 4549 } 4550 catch (const std::invalid_argument& e) 4551 { 4552 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4553 } 4554 } 4555 4556 TEST(ConfigFileParserTests, ParseRule) 4557 { 4558 // Test where works: comments property specified 4559 { 4560 const json element = R"( 4561 { 4562 "comments": [ "Set voltage rule" ], 4563 "id": "set_voltage_rule", 4564 "actions": [ 4565 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 4566 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 4567 ] 4568 } 4569 )"_json; 4570 std::unique_ptr<Rule> rule = parseRule(element); 4571 EXPECT_EQ(rule->getID(), "set_voltage_rule"); 4572 EXPECT_EQ(rule->getActions().size(), 2); 4573 } 4574 4575 // Test where works: comments property not specified 4576 { 4577 const json element = R"( 4578 { 4579 "id": "set_voltage_rule", 4580 "actions": [ 4581 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 4582 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }, 4583 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } } 4584 ] 4585 } 4586 )"_json; 4587 std::unique_ptr<Rule> rule = parseRule(element); 4588 EXPECT_EQ(rule->getID(), "set_voltage_rule"); 4589 EXPECT_EQ(rule->getActions().size(), 3); 4590 } 4591 4592 // Test where fails: Element is not an object 4593 try 4594 { 4595 const json element = R"( [ "0xFF", "0x01" ] )"_json; 4596 parseRule(element); 4597 ADD_FAILURE() << "Should not have reached this line."; 4598 } 4599 catch (const std::invalid_argument& e) 4600 { 4601 EXPECT_STREQ(e.what(), "Element is not an object"); 4602 } 4603 4604 // Test where fails: id property not specified 4605 try 4606 { 4607 const json element = R"( 4608 { 4609 "actions": [ 4610 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4611 ] 4612 } 4613 )"_json; 4614 parseRule(element); 4615 ADD_FAILURE() << "Should not have reached this line."; 4616 } 4617 catch (const std::invalid_argument& e) 4618 { 4619 EXPECT_STREQ(e.what(), "Required property missing: id"); 4620 } 4621 4622 // Test where fails: id property is invalid 4623 try 4624 { 4625 const json element = R"( 4626 { 4627 "id": "", 4628 "actions": [ 4629 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4630 ] 4631 } 4632 )"_json; 4633 parseRule(element); 4634 ADD_FAILURE() << "Should not have reached this line."; 4635 } 4636 catch (const std::invalid_argument& e) 4637 { 4638 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4639 } 4640 4641 // Test where fails: actions property not specified 4642 try 4643 { 4644 const json element = R"( 4645 { 4646 "comments": [ "Set voltage rule" ], 4647 "id": "set_voltage_rule" 4648 } 4649 )"_json; 4650 parseRule(element); 4651 ADD_FAILURE() << "Should not have reached this line."; 4652 } 4653 catch (const std::invalid_argument& e) 4654 { 4655 EXPECT_STREQ(e.what(), "Required property missing: actions"); 4656 } 4657 4658 // Test where fails: actions property is invalid 4659 try 4660 { 4661 const json element = R"( 4662 { 4663 "id": "set_voltage_rule", 4664 "actions": true 4665 } 4666 )"_json; 4667 parseRule(element); 4668 ADD_FAILURE() << "Should not have reached this line."; 4669 } 4670 catch (const std::invalid_argument& e) 4671 { 4672 EXPECT_STREQ(e.what(), "Element is not an array"); 4673 } 4674 4675 // Test where fails: Invalid property specified 4676 try 4677 { 4678 const json element = R"( 4679 { 4680 "remarks": [ "Set voltage rule" ], 4681 "id": "set_voltage_rule", 4682 "actions": [ 4683 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4684 ] 4685 } 4686 )"_json; 4687 parseRule(element); 4688 ADD_FAILURE() << "Should not have reached this line."; 4689 } 4690 catch (const std::invalid_argument& e) 4691 { 4692 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4693 } 4694 } 4695 4696 TEST(ConfigFileParserTests, ParseRuleArray) 4697 { 4698 // Test where works 4699 { 4700 const json element = R"( 4701 [ 4702 { 4703 "id": "set_voltage_rule1", 4704 "actions": [ 4705 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4706 ] 4707 }, 4708 { 4709 "id": "set_voltage_rule2", 4710 "actions": [ 4711 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 4712 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } } 4713 ] 4714 } 4715 ] 4716 )"_json; 4717 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element); 4718 EXPECT_EQ(rules.size(), 2); 4719 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 4720 EXPECT_EQ(rules[0]->getActions().size(), 1); 4721 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 4722 EXPECT_EQ(rules[1]->getActions().size(), 2); 4723 } 4724 4725 // Test where fails: Element is not an array 4726 try 4727 { 4728 const json element = R"( { "id": "set_voltage_rule" } )"_json; 4729 parseRuleArray(element); 4730 ADD_FAILURE() << "Should not have reached this line."; 4731 } 4732 catch (const std::invalid_argument& e) 4733 { 4734 EXPECT_STREQ(e.what(), "Element is not an array"); 4735 } 4736 } 4737 4738 TEST(ConfigFileParserTests, ParseRuleIDOrActionsProperty) 4739 { 4740 // Test where works: actions specified 4741 { 4742 const json element = R"( 4743 { 4744 "actions": [ 4745 { "pmbus_write_vout_command": { "format": "linear" } }, 4746 { "run_rule": "set_voltage_rule" } 4747 ] 4748 } 4749 )"_json; 4750 std::vector<std::unique_ptr<Action>> actions = 4751 parseRuleIDOrActionsProperty(element); 4752 EXPECT_EQ(actions.size(), 2); 4753 } 4754 4755 // Test where works: rule_id specified 4756 { 4757 const json element = R"( 4758 { 4759 "rule_id": "set_voltage_rule" 4760 } 4761 )"_json; 4762 std::vector<std::unique_ptr<Action>> actions = 4763 parseRuleIDOrActionsProperty(element); 4764 EXPECT_EQ(actions.size(), 1); 4765 } 4766 4767 // Test where fails: Element is not an object 4768 try 4769 { 4770 const json element = R"( [ "foo", "bar" ] )"_json; 4771 parseRuleIDOrActionsProperty(element); 4772 ADD_FAILURE() << "Should not have reached this line."; 4773 } 4774 catch (const std::invalid_argument& e) 4775 { 4776 EXPECT_STREQ(e.what(), "Element is not an object"); 4777 } 4778 4779 // Test where fails: rule_id is invalid 4780 try 4781 { 4782 const json element = R"( 4783 { "rule_id": 1 } 4784 )"_json; 4785 parseRuleIDOrActionsProperty(element); 4786 ADD_FAILURE() << "Should not have reached this line."; 4787 } 4788 catch (const std::invalid_argument& e) 4789 { 4790 EXPECT_STREQ(e.what(), "Element is not a string"); 4791 } 4792 4793 // Test where fails: actions is invalid 4794 try 4795 { 4796 const json element = R"( 4797 { "actions": 1 } 4798 )"_json; 4799 parseRuleIDOrActionsProperty(element); 4800 ADD_FAILURE() << "Should not have reached this line."; 4801 } 4802 catch (const std::invalid_argument& e) 4803 { 4804 EXPECT_STREQ(e.what(), "Element is not an array"); 4805 } 4806 4807 // Test where fails: Neither rule_id nor actions specified 4808 try 4809 { 4810 const json element = R"( 4811 { 4812 "volts": 1.03 4813 } 4814 )"_json; 4815 parseRuleIDOrActionsProperty(element); 4816 ADD_FAILURE() << "Should not have reached this line."; 4817 } 4818 catch (const std::invalid_argument& e) 4819 { 4820 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4821 "either rule_id or actions"); 4822 } 4823 4824 // Test where fails: Both rule_id and actions specified 4825 try 4826 { 4827 const json element = R"( 4828 { 4829 "volts": 1.03, 4830 "rule_id": "set_voltage_rule", 4831 "actions": [ 4832 { 4833 "pmbus_write_vout_command": { 4834 "format": "linear" 4835 } 4836 } 4837 ] 4838 } 4839 )"_json; 4840 parseRuleIDOrActionsProperty(element); 4841 ADD_FAILURE() << "Should not have reached this line."; 4842 } 4843 catch (const std::invalid_argument& e) 4844 { 4845 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4846 "either rule_id or actions"); 4847 } 4848 } 4849 4850 TEST(ConfigFileParserTests, ParseRunRule) 4851 { 4852 // Test where works 4853 { 4854 const json element = "vdd_regulator"; 4855 std::unique_ptr<RunRuleAction> action = parseRunRule(element); 4856 EXPECT_EQ(action->getRuleID(), "vdd_regulator"); 4857 } 4858 4859 // Test where fails: Element is not a string 4860 try 4861 { 4862 const json element = 1; 4863 parseRunRule(element); 4864 ADD_FAILURE() << "Should not have reached this line."; 4865 } 4866 catch (const std::invalid_argument& e) 4867 { 4868 EXPECT_STREQ(e.what(), "Element is not a string"); 4869 } 4870 4871 // Test where fails: Empty string 4872 try 4873 { 4874 const json element = ""; 4875 parseRunRule(element); 4876 ADD_FAILURE() << "Should not have reached this line."; 4877 } 4878 catch (const std::invalid_argument& e) 4879 { 4880 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4881 } 4882 } 4883 4884 TEST(ConfigFileParserTests, ParseSensorDataFormat) 4885 { 4886 // Test where works: linear_11 4887 { 4888 const json element = "linear_11"; 4889 pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element); 4890 pmbus_utils::SensorDataFormat format = 4891 pmbus_utils::SensorDataFormat::linear_11; 4892 EXPECT_EQ(value, format); 4893 } 4894 4895 // Test where works: linear_16 4896 { 4897 const json element = "linear_16"; 4898 pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element); 4899 pmbus_utils::SensorDataFormat format = 4900 pmbus_utils::SensorDataFormat::linear_16; 4901 EXPECT_EQ(value, format); 4902 } 4903 4904 // Test where fails: Element is not a sensor data format 4905 try 4906 { 4907 const json element = "foo"; 4908 parseSensorDataFormat(element); 4909 ADD_FAILURE() << "Should not have reached this line."; 4910 } 4911 catch (const std::invalid_argument& e) 4912 { 4913 EXPECT_STREQ(e.what(), "Element is not a sensor data format"); 4914 } 4915 4916 // Test where fails: Element is not a string 4917 try 4918 { 4919 const json element = R"( { "foo": "bar" } )"_json; 4920 parseSensorDataFormat(element); 4921 ADD_FAILURE() << "Should not have reached this line."; 4922 } 4923 catch (const std::invalid_argument& e) 4924 { 4925 EXPECT_STREQ(e.what(), "Element is not a string"); 4926 } 4927 } 4928 4929 TEST(ConfigFileParserTests, ParseSensorMonitoring) 4930 { 4931 // Test where works: actions property specified 4932 { 4933 const json element = R"( 4934 { 4935 "actions": [ 4936 { "run_rule": "read_sensors_rule" } 4937 ] 4938 } 4939 )"_json; 4940 std::unique_ptr<SensorMonitoring> sensorMonitoring = 4941 parseSensorMonitoring(element); 4942 EXPECT_EQ(sensorMonitoring->getActions().size(), 1); 4943 } 4944 4945 // Test where works: rule_id property specified 4946 { 4947 const json element = R"( 4948 { 4949 "comments": [ "comments property" ], 4950 "rule_id": "set_voltage_rule" 4951 } 4952 )"_json; 4953 std::unique_ptr<SensorMonitoring> sensorMonitoring = 4954 parseSensorMonitoring(element); 4955 EXPECT_EQ(sensorMonitoring->getActions().size(), 1); 4956 } 4957 4958 // Test where fails: actions object is invalid 4959 try 4960 { 4961 const json element = R"( 4962 { 4963 "actions": 1 4964 } 4965 )"_json; 4966 parseSensorMonitoring(element); 4967 ADD_FAILURE() << "Should not have reached this line."; 4968 } 4969 catch (const std::invalid_argument& e) 4970 { 4971 EXPECT_STREQ(e.what(), "Element is not an array"); 4972 } 4973 4974 // Test where fails: rule_id value is invalid 4975 try 4976 { 4977 const json element = R"( 4978 { 4979 "rule_id": 1 4980 } 4981 )"_json; 4982 parseSensorMonitoring(element); 4983 ADD_FAILURE() << "Should not have reached this line."; 4984 } 4985 catch (const std::invalid_argument& e) 4986 { 4987 EXPECT_STREQ(e.what(), "Element is not a string"); 4988 } 4989 4990 // Test where fails: Required actions or rule_id property not specified 4991 try 4992 { 4993 const json element = R"( 4994 { 4995 "comments": [ "comments property" ] 4996 } 4997 )"_json; 4998 parseSensorMonitoring(element); 4999 ADD_FAILURE() << "Should not have reached this line."; 5000 } 5001 catch (const std::invalid_argument& e) 5002 { 5003 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 5004 "either rule_id or actions"); 5005 } 5006 5007 // Test where fails: Required actions or rule_id property both specified 5008 try 5009 { 5010 const json element = R"( 5011 { 5012 "rule_id": "set_voltage_rule", 5013 "actions": [ 5014 { "run_rule": "read_sensors_rule" } 5015 ] 5016 } 5017 )"_json; 5018 parseSensorMonitoring(element); 5019 ADD_FAILURE() << "Should not have reached this line."; 5020 } 5021 catch (const std::invalid_argument& e) 5022 { 5023 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 5024 "either rule_id or actions"); 5025 } 5026 5027 // Test where fails: Element is not an object 5028 try 5029 { 5030 const json element = R"( [ "foo", "bar" ] )"_json; 5031 parseSensorMonitoring(element); 5032 ADD_FAILURE() << "Should not have reached this line."; 5033 } 5034 catch (const std::invalid_argument& e) 5035 { 5036 EXPECT_STREQ(e.what(), "Element is not an object"); 5037 } 5038 5039 // Test where fails: Invalid property specified 5040 try 5041 { 5042 const json element = R"( 5043 { 5044 "foo": "bar", 5045 "actions": [ 5046 { "run_rule": "read_sensors_rule" } 5047 ] 5048 } 5049 )"_json; 5050 parseSensorMonitoring(element); 5051 ADD_FAILURE() << "Should not have reached this line."; 5052 } 5053 catch (const std::invalid_argument& e) 5054 { 5055 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 5056 } 5057 } 5058 5059 TEST(ConfigFileParserTests, ParseSensorType) 5060 { 5061 // Test where works: iout 5062 { 5063 const json element = "iout"; 5064 SensorType type = parseSensorType(element); 5065 EXPECT_EQ(type, SensorType::iout); 5066 } 5067 5068 // Test where works: iout_peak 5069 { 5070 const json element = "iout_peak"; 5071 SensorType type = parseSensorType(element); 5072 EXPECT_EQ(type, SensorType::iout_peak); 5073 } 5074 5075 // Test where works: iout_valley 5076 { 5077 const json element = "iout_valley"; 5078 SensorType type = parseSensorType(element); 5079 EXPECT_EQ(type, SensorType::iout_valley); 5080 } 5081 5082 // Test where works: pout 5083 { 5084 const json element = "pout"; 5085 SensorType type = parseSensorType(element); 5086 EXPECT_EQ(type, SensorType::pout); 5087 } 5088 5089 // Test where works: temperature 5090 { 5091 const json element = "temperature"; 5092 SensorType type = parseSensorType(element); 5093 EXPECT_EQ(type, SensorType::temperature); 5094 } 5095 5096 // Test where works: temperature_peak 5097 { 5098 const json element = "temperature_peak"; 5099 SensorType type = parseSensorType(element); 5100 EXPECT_EQ(type, SensorType::temperature_peak); 5101 } 5102 5103 // Test where works: vout 5104 { 5105 const json element = "vout"; 5106 SensorType type = parseSensorType(element); 5107 EXPECT_EQ(type, SensorType::vout); 5108 } 5109 5110 // Test where works: vout_peak 5111 { 5112 const json element = "vout_peak"; 5113 SensorType type = parseSensorType(element); 5114 EXPECT_EQ(type, SensorType::vout_peak); 5115 } 5116 5117 // Test where works: vout_valley 5118 { 5119 const json element = "vout_valley"; 5120 SensorType type = parseSensorType(element); 5121 EXPECT_EQ(type, SensorType::vout_valley); 5122 } 5123 5124 // Test where fails: Element is not a sensor type 5125 try 5126 { 5127 const json element = "foo"; 5128 parseSensorType(element); 5129 ADD_FAILURE() << "Should not have reached this line."; 5130 } 5131 catch (const std::invalid_argument& e) 5132 { 5133 EXPECT_STREQ(e.what(), "Element is not a sensor type"); 5134 } 5135 5136 // Test where fails: Element is not a string 5137 try 5138 { 5139 const json element = R"( { "foo": "bar" } )"_json; 5140 parseSensorType(element); 5141 ADD_FAILURE() << "Should not have reached this line."; 5142 } 5143 catch (const std::invalid_argument& e) 5144 { 5145 EXPECT_STREQ(e.what(), "Element is not a string"); 5146 } 5147 } 5148 5149 TEST(ConfigFileParserTests, ParseSetDevice) 5150 { 5151 // Test where works 5152 { 5153 const json element = "regulator1"; 5154 std::unique_ptr<SetDeviceAction> action = parseSetDevice(element); 5155 EXPECT_EQ(action->getDeviceID(), "regulator1"); 5156 } 5157 5158 // Test where fails: Element is not a string 5159 try 5160 { 5161 const json element = 1; 5162 parseSetDevice(element); 5163 ADD_FAILURE() << "Should not have reached this line."; 5164 } 5165 catch (const std::invalid_argument& e) 5166 { 5167 EXPECT_STREQ(e.what(), "Element is not a string"); 5168 } 5169 5170 // Test where fails: Empty string 5171 try 5172 { 5173 const json element = ""; 5174 parseSetDevice(element); 5175 ADD_FAILURE() << "Should not have reached this line."; 5176 } 5177 catch (const std::invalid_argument& e) 5178 { 5179 EXPECT_STREQ(e.what(), "Element contains an empty string"); 5180 } 5181 } 5182 5183 TEST(ConfigFileParserTests, ParseString) 5184 { 5185 // Test where works: Empty string 5186 { 5187 const json element = ""; 5188 std::string value = parseString(element, true); 5189 EXPECT_EQ(value, ""); 5190 } 5191 5192 // Test where works: Non-empty string 5193 { 5194 const json element = "vdd_regulator"; 5195 std::string value = parseString(element, false); 5196 EXPECT_EQ(value, "vdd_regulator"); 5197 } 5198 5199 // Test where fails: Element is not a string 5200 try 5201 { 5202 const json element = R"( { "foo": "bar" } )"_json; 5203 parseString(element); 5204 ADD_FAILURE() << "Should not have reached this line."; 5205 } 5206 catch (const std::invalid_argument& e) 5207 { 5208 EXPECT_STREQ(e.what(), "Element is not a string"); 5209 } 5210 5211 // Test where fails: Empty string 5212 try 5213 { 5214 const json element = ""; 5215 parseString(element); 5216 ADD_FAILURE() << "Should not have reached this line."; 5217 } 5218 catch (const std::invalid_argument& e) 5219 { 5220 EXPECT_STREQ(e.what(), "Element contains an empty string"); 5221 } 5222 } 5223 5224 TEST(ConfigFileParserTests, ParseUint8) 5225 { 5226 // Test where works: 0 5227 { 5228 const json element = R"( 0 )"_json; 5229 uint8_t value = parseUint8(element); 5230 EXPECT_EQ(value, 0); 5231 } 5232 5233 // Test where works: UINT8_MAX 5234 { 5235 const json element = R"( 255 )"_json; 5236 uint8_t value = parseUint8(element); 5237 EXPECT_EQ(value, 255); 5238 } 5239 5240 // Test where fails: Element is not an integer 5241 try 5242 { 5243 const json element = R"( 1.03 )"_json; 5244 parseUint8(element); 5245 ADD_FAILURE() << "Should not have reached this line."; 5246 } 5247 catch (const std::invalid_argument& e) 5248 { 5249 EXPECT_STREQ(e.what(), "Element is not an integer"); 5250 } 5251 5252 // Test where fails: Value < 0 5253 try 5254 { 5255 const json element = R"( -1 )"_json; 5256 parseUint8(element); 5257 ADD_FAILURE() << "Should not have reached this line."; 5258 } 5259 catch (const std::invalid_argument& e) 5260 { 5261 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); 5262 } 5263 5264 // Test where fails: Value > UINT8_MAX 5265 try 5266 { 5267 const json element = R"( 256 )"_json; 5268 parseUint8(element); 5269 ADD_FAILURE() << "Should not have reached this line."; 5270 } 5271 catch (const std::invalid_argument& e) 5272 { 5273 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); 5274 } 5275 } 5276 5277 TEST(ConfigFileParserTests, ParseUnsignedInteger) 5278 { 5279 // Test where works: 1 5280 { 5281 const json element = R"( 1 )"_json; 5282 unsigned int value = parseUnsignedInteger(element); 5283 EXPECT_EQ(value, 1); 5284 } 5285 5286 // Test where fails: Element is not an integer 5287 try 5288 { 5289 const json element = R"( 1.5 )"_json; 5290 parseUnsignedInteger(element); 5291 ADD_FAILURE() << "Should not have reached this line."; 5292 } 5293 catch (const std::invalid_argument& e) 5294 { 5295 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 5296 } 5297 5298 // Test where fails: Value < 0 5299 try 5300 { 5301 const json element = R"( -1 )"_json; 5302 parseUnsignedInteger(element); 5303 ADD_FAILURE() << "Should not have reached this line."; 5304 } 5305 catch (const std::invalid_argument& e) 5306 { 5307 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 5308 } 5309 } 5310 5311 TEST(ConfigFileParserTests, ParseVoutDataFormat) 5312 { 5313 // Test where works: linear 5314 { 5315 const json element = "linear"; 5316 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 5317 pmbus_utils::VoutDataFormat format = 5318 pmbus_utils::VoutDataFormat::linear; 5319 EXPECT_EQ(value, format); 5320 } 5321 5322 // Test where works: vid 5323 { 5324 const json element = "vid"; 5325 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 5326 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::vid; 5327 EXPECT_EQ(value, format); 5328 } 5329 5330 // Test where works: direct 5331 { 5332 const json element = "direct"; 5333 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 5334 pmbus_utils::VoutDataFormat format = 5335 pmbus_utils::VoutDataFormat::direct; 5336 EXPECT_EQ(value, format); 5337 } 5338 5339 // Test where works: ieee 5340 { 5341 const json element = "ieee"; 5342 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 5343 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::ieee; 5344 EXPECT_EQ(value, format); 5345 } 5346 5347 // Test where fails: Element is not a vout data format 5348 try 5349 { 5350 const json element = "foo"; 5351 parseVoutDataFormat(element); 5352 ADD_FAILURE() << "Should not have reached this line."; 5353 } 5354 catch (const std::invalid_argument& e) 5355 { 5356 EXPECT_STREQ(e.what(), "Element is not a vout data format"); 5357 } 5358 5359 // Test where fails: Element is not a string 5360 try 5361 { 5362 const json element = R"( { "foo": "bar" } )"_json; 5363 parseVoutDataFormat(element); 5364 ADD_FAILURE() << "Should not have reached this line."; 5365 } 5366 catch (const std::invalid_argument& e) 5367 { 5368 EXPECT_STREQ(e.what(), "Element is not a string"); 5369 } 5370 } 5371 5372 TEST(ConfigFileParserTests, VerifyIsArray) 5373 { 5374 // Test where element is an array 5375 try 5376 { 5377 const json element = R"( [ "foo", "bar" ] )"_json; 5378 verifyIsArray(element); 5379 } 5380 catch (const std::exception& e) 5381 { 5382 ADD_FAILURE() << "Should not have caught exception."; 5383 } 5384 5385 // Test where element is not an array 5386 try 5387 { 5388 const json element = R"( { "foo": "bar" } )"_json; 5389 verifyIsArray(element); 5390 ADD_FAILURE() << "Should not have reached this line."; 5391 } 5392 catch (const std::invalid_argument& e) 5393 { 5394 EXPECT_STREQ(e.what(), "Element is not an array"); 5395 } 5396 } 5397 5398 TEST(ConfigFileParserTests, VerifyIsObject) 5399 { 5400 // Test where element is an object 5401 try 5402 { 5403 const json element = R"( { "foo": "bar" } )"_json; 5404 verifyIsObject(element); 5405 } 5406 catch (const std::exception& e) 5407 { 5408 ADD_FAILURE() << "Should not have caught exception."; 5409 } 5410 5411 // Test where element is not an object 5412 try 5413 { 5414 const json element = R"( [ "foo", "bar" ] )"_json; 5415 verifyIsObject(element); 5416 ADD_FAILURE() << "Should not have reached this line."; 5417 } 5418 catch (const std::invalid_argument& e) 5419 { 5420 EXPECT_STREQ(e.what(), "Element is not an object"); 5421 } 5422 } 5423 5424 TEST(ConfigFileParserTests, VerifyPropertyCount) 5425 { 5426 // Test where element has expected number of properties 5427 try 5428 { 5429 const json element = R"( 5430 { 5431 "comments": [ "Set voltage rule" ], 5432 "id": "set_voltage_rule" 5433 } 5434 )"_json; 5435 verifyPropertyCount(element, 2); 5436 } 5437 catch (const std::exception& e) 5438 { 5439 ADD_FAILURE() << "Should not have caught exception."; 5440 } 5441 5442 // Test where element has unexpected number of properties 5443 try 5444 { 5445 const json element = R"( 5446 { 5447 "comments": [ "Set voltage rule" ], 5448 "id": "set_voltage_rule", 5449 "foo": 1.3 5450 } 5451 )"_json; 5452 verifyPropertyCount(element, 2); 5453 ADD_FAILURE() << "Should not have reached this line."; 5454 } 5455 catch (const std::invalid_argument& e) 5456 { 5457 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 5458 } 5459 } 5460