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