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