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 "chassis.hpp" 18 #include "config_file_parser.hpp" 19 #include "config_file_parser_error.hpp" 20 #include "configuration.hpp" 21 #include "device.hpp" 22 #include "i2c_interface.hpp" 23 #include "i2c_write_bit_action.hpp" 24 #include "i2c_write_byte_action.hpp" 25 #include "i2c_write_bytes_action.hpp" 26 #include "pmbus_utils.hpp" 27 #include "pmbus_write_vout_command_action.hpp" 28 #include "presence_detection.hpp" 29 #include "rail.hpp" 30 #include "rule.hpp" 31 #include "run_rule_action.hpp" 32 #include "sensor_monitoring.hpp" 33 #include "tmp_file.hpp" 34 35 #include <sys/stat.h> // for chmod() 36 37 #include <nlohmann/json.hpp> 38 39 #include <cstdint> 40 #include <cstring> 41 #include <exception> 42 #include <filesystem> 43 #include <fstream> 44 #include <memory> 45 #include <optional> 46 #include <stdexcept> 47 #include <string> 48 #include <tuple> 49 #include <vector> 50 51 #include <gtest/gtest.h> 52 53 using namespace phosphor::power::regulators; 54 using namespace phosphor::power::regulators::config_file_parser; 55 using namespace phosphor::power::regulators::config_file_parser::internal; 56 using json = nlohmann::json; 57 58 void writeConfigFile(const std::filesystem::path& pathName, 59 const std::string& contents) 60 { 61 std::ofstream file{pathName}; 62 file << contents; 63 } 64 65 void writeConfigFile(const std::filesystem::path& pathName, 66 const json& contents) 67 { 68 std::ofstream file{pathName}; 69 file << contents; 70 } 71 72 TEST(ConfigFileParserTests, Parse) 73 { 74 // Test where works 75 { 76 const json configFileContents = R"( 77 { 78 "rules": [ 79 { 80 "id": "set_voltage_rule1", 81 "actions": [ 82 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 83 ] 84 }, 85 { 86 "id": "set_voltage_rule2", 87 "actions": [ 88 { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } } 89 ] 90 } 91 ], 92 "chassis": [ 93 { "number": 1 }, 94 { "number": 2 }, 95 { "number": 3 } 96 ] 97 } 98 )"_json; 99 100 TmpFile configFile; 101 std::filesystem::path pathName{configFile.getName()}; 102 writeConfigFile(pathName, configFileContents); 103 104 std::vector<std::unique_ptr<Rule>> rules{}; 105 std::vector<std::unique_ptr<Chassis>> chassis{}; 106 std::tie(rules, chassis) = parse(pathName); 107 108 EXPECT_EQ(rules.size(), 2); 109 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 110 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 111 112 EXPECT_EQ(chassis.size(), 3); 113 EXPECT_EQ(chassis[0]->getNumber(), 1); 114 EXPECT_EQ(chassis[1]->getNumber(), 2); 115 EXPECT_EQ(chassis[2]->getNumber(), 3); 116 } 117 118 // Test where fails: File does not exist 119 try 120 { 121 std::filesystem::path pathName{"/tmp/non_existent_file"}; 122 parse(pathName); 123 ADD_FAILURE() << "Should not have reached this line."; 124 } 125 catch (const ConfigFileParserError& e) 126 { 127 // Expected exception; what() message will vary 128 } 129 130 // Test where fails: File is not readable 131 try 132 { 133 const json configFileContents = R"( 134 { 135 "chassis": [ { "number": 1 } ] 136 } 137 )"_json; 138 139 TmpFile configFile; 140 std::filesystem::path pathName{configFile.getName()}; 141 writeConfigFile(pathName, configFileContents); 142 143 chmod(pathName.c_str(), 0222); 144 145 parse(pathName); 146 ADD_FAILURE() << "Should not have reached this line."; 147 } 148 catch (const ConfigFileParserError& e) 149 { 150 // Expected exception; what() message will vary 151 } 152 153 // Test where fails: File is not valid JSON 154 try 155 { 156 const std::string configFileContents = "] foo ["; 157 158 TmpFile configFile; 159 std::filesystem::path pathName{configFile.getName()}; 160 writeConfigFile(pathName, configFileContents); 161 162 parse(pathName); 163 ADD_FAILURE() << "Should not have reached this line."; 164 } 165 catch (const ConfigFileParserError& e) 166 { 167 // Expected exception; what() message will vary 168 } 169 170 // Test where fails: Error when parsing JSON elements 171 try 172 { 173 const json configFileContents = R"( { "foo": "bar" } )"_json; 174 175 TmpFile configFile; 176 std::filesystem::path pathName{configFile.getName()}; 177 writeConfigFile(pathName, configFileContents); 178 179 parse(pathName); 180 ADD_FAILURE() << "Should not have reached this line."; 181 } 182 catch (const ConfigFileParserError& e) 183 { 184 // Expected exception; what() message will vary 185 } 186 } 187 188 TEST(ConfigFileParserTests, GetRequiredProperty) 189 { 190 // Test where property exists 191 { 192 const json element = R"( { "format": "linear" } )"_json; 193 const json& propertyElement = getRequiredProperty(element, "format"); 194 EXPECT_EQ(propertyElement.get<std::string>(), "linear"); 195 } 196 197 // Test where property does not exist 198 try 199 { 200 const json element = R"( { "volts": 1.03 } )"_json; 201 getRequiredProperty(element, "format"); 202 ADD_FAILURE() << "Should not have reached this line."; 203 } 204 catch (const std::invalid_argument& e) 205 { 206 EXPECT_STREQ(e.what(), "Required property missing: format"); 207 } 208 } 209 210 TEST(ConfigFileParserTests, ParseAction) 211 { 212 // Test where works: comments property specified 213 { 214 const json element = R"( 215 { 216 "comments": [ "Set output voltage." ], 217 "pmbus_write_vout_command": { 218 "format": "linear" 219 } 220 } 221 )"_json; 222 std::unique_ptr<Action> action = parseAction(element); 223 EXPECT_NE(action.get(), nullptr); 224 } 225 226 // Test where works: comments property not specified 227 { 228 const json element = R"( 229 { 230 "pmbus_write_vout_command": { 231 "format": "linear" 232 } 233 } 234 )"_json; 235 std::unique_ptr<Action> action = parseAction(element); 236 EXPECT_NE(action.get(), nullptr); 237 } 238 239 // Test where works: and action type specified 240 // TODO: Not implemented yet 241 242 // Test where works: compare_presence action type specified 243 // TODO: Not implemented yet 244 245 // Test where works: compare_vpd action type specified 246 // TODO: Not implemented yet 247 248 // Test where works: i2c_compare_bit action type specified 249 // TODO: Not implemented yet 250 251 // Test where works: i2c_compare_byte action type specified 252 // TODO: Not implemented yet 253 254 // Test where works: i2c_compare_bytes action type specified 255 // TODO: Not implemented yet 256 257 // Test where works: i2c_write_bit action type specified 258 { 259 const json element = R"( 260 { 261 "i2c_write_bit": { 262 "register": "0xA0", 263 "position": 3, 264 "value": 0 265 } 266 } 267 )"_json; 268 std::unique_ptr<Action> action = parseAction(element); 269 EXPECT_NE(action.get(), nullptr); 270 } 271 272 // Test where works: i2c_write_byte action type specified 273 { 274 const json element = R"( 275 { 276 "i2c_write_byte": { 277 "register": "0x0A", 278 "value": "0xCC" 279 } 280 } 281 )"_json; 282 std::unique_ptr<Action> action = parseAction(element); 283 EXPECT_NE(action.get(), nullptr); 284 } 285 286 // Test where works: i2c_write_bytes action type specified 287 { 288 const json element = R"( 289 { 290 "i2c_write_bytes": { 291 "register": "0x0A", 292 "values": [ "0xCC", "0xFF" ] 293 } 294 } 295 )"_json; 296 std::unique_ptr<Action> action = parseAction(element); 297 EXPECT_NE(action.get(), nullptr); 298 } 299 300 // Test where works: if action type specified 301 // TODO: Not implemented yet 302 303 // Test where works: not action type specified 304 // TODO: Not implemented yet 305 306 // Test where works: or action type specified 307 // TODO: Not implemented yet 308 309 // Test where works: pmbus_read_sensor action type specified 310 // TODO: Not implemented yet 311 312 // Test where works: pmbus_write_vout_command action type specified 313 { 314 const json element = R"( 315 { 316 "pmbus_write_vout_command": { 317 "format": "linear" 318 } 319 } 320 )"_json; 321 std::unique_ptr<Action> action = parseAction(element); 322 EXPECT_NE(action.get(), nullptr); 323 } 324 325 // Test where works: run_rule action type specified 326 { 327 const json element = R"( 328 { 329 "run_rule": "set_voltage_rule" 330 } 331 )"_json; 332 std::unique_ptr<Action> action = parseAction(element); 333 EXPECT_NE(action.get(), nullptr); 334 } 335 336 // Test where works: set_device action type specified 337 // TODO: Not implemented yet 338 339 // Test where fails: Element is not an object 340 try 341 { 342 const json element = R"( [ "0xFF", "0x01" ] )"_json; 343 parseAction(element); 344 ADD_FAILURE() << "Should not have reached this line."; 345 } 346 catch (const std::invalid_argument& e) 347 { 348 EXPECT_STREQ(e.what(), "Element is not an object"); 349 } 350 351 // Test where fails: No action type specified 352 try 353 { 354 const json element = R"( 355 { 356 "comments": [ "Set output voltage." ] 357 } 358 )"_json; 359 parseAction(element); 360 ADD_FAILURE() << "Should not have reached this line."; 361 } 362 catch (const std::invalid_argument& e) 363 { 364 EXPECT_STREQ(e.what(), "Required action type property missing"); 365 } 366 367 // Test where fails: Multiple action types specified 368 try 369 { 370 const json element = R"( 371 { 372 "pmbus_write_vout_command": { "format": "linear" }, 373 "run_rule": "set_voltage_rule" 374 } 375 )"_json; 376 parseAction(element); 377 ADD_FAILURE() << "Should not have reached this line."; 378 } 379 catch (const std::invalid_argument& e) 380 { 381 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 382 } 383 384 // Test where fails: Invalid property specified 385 try 386 { 387 const json element = R"( 388 { 389 "remarks": [ "Set output voltage." ], 390 "pmbus_write_vout_command": { 391 "format": "linear" 392 } 393 } 394 )"_json; 395 parseAction(element); 396 ADD_FAILURE() << "Should not have reached this line."; 397 } 398 catch (const std::invalid_argument& e) 399 { 400 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 401 } 402 } 403 404 TEST(ConfigFileParserTests, ParseActionArray) 405 { 406 // Test where works 407 { 408 const json element = R"( 409 [ 410 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 411 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 412 ] 413 )"_json; 414 std::vector<std::unique_ptr<Action>> actions = 415 parseActionArray(element); 416 EXPECT_EQ(actions.size(), 2); 417 } 418 419 // Test where fails: Element is not an array 420 try 421 { 422 const json element = R"( 423 { 424 "foo": "bar" 425 } 426 )"_json; 427 parseActionArray(element); 428 ADD_FAILURE() << "Should not have reached this line."; 429 } 430 catch (const std::invalid_argument& e) 431 { 432 EXPECT_STREQ(e.what(), "Element is not an array"); 433 } 434 } 435 436 TEST(ConfigFileParserTests, ParseBitPosition) 437 { 438 // Test where works: 0 439 { 440 const json element = R"( 0 )"_json; 441 uint8_t value = parseBitPosition(element); 442 EXPECT_EQ(value, 0); 443 } 444 445 // Test where works: 7 446 { 447 const json element = R"( 7 )"_json; 448 uint8_t value = parseBitPosition(element); 449 EXPECT_EQ(value, 7); 450 } 451 452 // Test where fails: Element is not an integer 453 try 454 { 455 const json element = R"( 1.03 )"_json; 456 parseBitPosition(element); 457 ADD_FAILURE() << "Should not have reached this line."; 458 } 459 catch (const std::invalid_argument& e) 460 { 461 EXPECT_STREQ(e.what(), "Element is not an integer"); 462 } 463 464 // Test where fails: Value < 0 465 try 466 { 467 const json element = R"( -1 )"_json; 468 parseBitPosition(element); 469 ADD_FAILURE() << "Should not have reached this line."; 470 } 471 catch (const std::invalid_argument& e) 472 { 473 EXPECT_STREQ(e.what(), "Element is not a bit position"); 474 } 475 476 // Test where fails: Value > 7 477 try 478 { 479 const json element = R"( 8 )"_json; 480 parseBitPosition(element); 481 ADD_FAILURE() << "Should not have reached this line."; 482 } 483 catch (const std::invalid_argument& e) 484 { 485 EXPECT_STREQ(e.what(), "Element is not a bit position"); 486 } 487 } 488 489 TEST(ConfigFileParserTests, ParseBitValue) 490 { 491 // Test where works: 0 492 { 493 const json element = R"( 0 )"_json; 494 uint8_t value = parseBitValue(element); 495 EXPECT_EQ(value, 0); 496 } 497 498 // Test where works: 1 499 { 500 const json element = R"( 1 )"_json; 501 uint8_t value = parseBitValue(element); 502 EXPECT_EQ(value, 1); 503 } 504 505 // Test where fails: Element is not an integer 506 try 507 { 508 const json element = R"( 0.5 )"_json; 509 parseBitValue(element); 510 ADD_FAILURE() << "Should not have reached this line."; 511 } 512 catch (const std::invalid_argument& e) 513 { 514 EXPECT_STREQ(e.what(), "Element is not an integer"); 515 } 516 517 // Test where fails: Value < 0 518 try 519 { 520 const json element = R"( -1 )"_json; 521 parseBitValue(element); 522 ADD_FAILURE() << "Should not have reached this line."; 523 } 524 catch (const std::invalid_argument& e) 525 { 526 EXPECT_STREQ(e.what(), "Element is not a bit value"); 527 } 528 529 // Test where fails: Value > 1 530 try 531 { 532 const json element = R"( 2 )"_json; 533 parseBitValue(element); 534 ADD_FAILURE() << "Should not have reached this line."; 535 } 536 catch (const std::invalid_argument& e) 537 { 538 EXPECT_STREQ(e.what(), "Element is not a bit value"); 539 } 540 } 541 542 TEST(ConfigFileParserTests, ParseBoolean) 543 { 544 // Test where works: true 545 { 546 const json element = R"( true )"_json; 547 bool value = parseBoolean(element); 548 EXPECT_EQ(value, true); 549 } 550 551 // Test where works: false 552 { 553 const json element = R"( false )"_json; 554 bool value = parseBoolean(element); 555 EXPECT_EQ(value, false); 556 } 557 558 // Test where fails: Element is not a boolean 559 try 560 { 561 const json element = R"( 1 )"_json; 562 parseBoolean(element); 563 ADD_FAILURE() << "Should not have reached this line."; 564 } 565 catch (const std::invalid_argument& e) 566 { 567 EXPECT_STREQ(e.what(), "Element is not a boolean"); 568 } 569 } 570 571 TEST(ConfigFileParserTests, ParseChassis) 572 { 573 // Test where works: Only required properties specified 574 { 575 const json element = R"( 576 { 577 "number": 1 578 } 579 )"_json; 580 std::unique_ptr<Chassis> chassis = parseChassis(element); 581 EXPECT_EQ(chassis->getNumber(), 1); 582 EXPECT_EQ(chassis->getDevices().size(), 0); 583 } 584 585 // Test where works: All properties specified 586 { 587 const json element = R"( 588 { 589 "comments": [ "comments property" ], 590 "number": 2, 591 "devices": [ 592 { 593 "id": "vdd_regulator", 594 "is_regulator": true, 595 "fru": "/system/chassis/motherboard/regulator2", 596 "i2c_interface": 597 { 598 "bus": 1, 599 "address": "0x70" 600 } 601 } 602 ] 603 } 604 )"_json; 605 std::unique_ptr<Chassis> chassis = parseChassis(element); 606 EXPECT_EQ(chassis->getNumber(), 2); 607 EXPECT_EQ(chassis->getDevices().size(), 1); 608 EXPECT_EQ(chassis->getDevices()[0]->getID(), "vdd_regulator"); 609 } 610 611 // Test where fails: number value is invalid 612 try 613 { 614 const json element = R"( 615 { 616 "number": 0.5 617 } 618 )"_json; 619 parseChassis(element); 620 ADD_FAILURE() << "Should not have reached this line."; 621 } 622 catch (const std::invalid_argument& e) 623 { 624 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 625 } 626 627 // Test where fails: Invalid property specified 628 try 629 { 630 const json element = R"( 631 { 632 "number": 1, 633 "foo": 2 634 } 635 )"_json; 636 parseChassis(element); 637 ADD_FAILURE() << "Should not have reached this line."; 638 } 639 catch (const std::invalid_argument& e) 640 { 641 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 642 } 643 644 // Test where fails: Required number property not specified 645 try 646 { 647 const json element = R"( 648 { 649 "devices": [ 650 { 651 "id": "vdd_regulator", 652 "is_regulator": true, 653 "fru": "/system/chassis/motherboard/regulator2", 654 "i2c_interface": 655 { 656 "bus": 1, 657 "address": "0x70" 658 } 659 } 660 ] 661 } 662 )"_json; 663 parseChassis(element); 664 ADD_FAILURE() << "Should not have reached this line."; 665 } 666 catch (const std::invalid_argument& e) 667 { 668 EXPECT_STREQ(e.what(), "Required property missing: number"); 669 } 670 671 // Test where fails: Element is not an object 672 try 673 { 674 const json element = R"( [ "0xFF", "0x01" ] )"_json; 675 parseChassis(element); 676 ADD_FAILURE() << "Should not have reached this line."; 677 } 678 catch (const std::invalid_argument& e) 679 { 680 EXPECT_STREQ(e.what(), "Element is not an object"); 681 } 682 683 // Test where fails: number value is < 1 684 try 685 { 686 const json element = R"( 687 { 688 "number": 0 689 } 690 )"_json; 691 parseChassis(element); 692 ADD_FAILURE() << "Should not have reached this line."; 693 } 694 catch (const std::invalid_argument& e) 695 { 696 EXPECT_STREQ(e.what(), "Invalid chassis number: Must be > 0"); 697 } 698 699 // Test where fails: devices value is invalid 700 try 701 { 702 const json element = R"( 703 { 704 "number": 1, 705 "devices": 2 706 } 707 )"_json; 708 parseChassis(element); 709 ADD_FAILURE() << "Should not have reached this line."; 710 } 711 catch (const std::invalid_argument& e) 712 { 713 EXPECT_STREQ(e.what(), "Element is not an array"); 714 } 715 } 716 717 TEST(ConfigFileParserTests, ParseChassisArray) 718 { 719 // Test where works 720 { 721 const json element = R"( 722 [ 723 { "number": 1 }, 724 { "number": 2 } 725 ] 726 )"_json; 727 std::vector<std::unique_ptr<Chassis>> chassis = 728 parseChassisArray(element); 729 EXPECT_EQ(chassis.size(), 2); 730 EXPECT_EQ(chassis[0]->getNumber(), 1); 731 EXPECT_EQ(chassis[1]->getNumber(), 2); 732 } 733 734 // Test where fails: Element is not an array 735 try 736 { 737 const json element = R"( 738 { 739 "foo": "bar" 740 } 741 )"_json; 742 parseChassisArray(element); 743 ADD_FAILURE() << "Should not have reached this line."; 744 } 745 catch (const std::invalid_argument& e) 746 { 747 EXPECT_STREQ(e.what(), "Element is not an array"); 748 } 749 } 750 751 TEST(ConfigFileParserTests, ParseConfiguration) 752 { 753 // Test where works: actions required property specified 754 { 755 const json element = R"( 756 { 757 "actions": [ 758 { 759 "pmbus_write_vout_command": { 760 "format": "linear" 761 } 762 } 763 ] 764 } 765 )"_json; 766 std::unique_ptr<Configuration> configuration = 767 parseConfiguration(element); 768 EXPECT_EQ(configuration->getActions().size(), 1); 769 EXPECT_EQ(configuration->getVolts().has_value(), false); 770 } 771 772 // Test where works: volts and actions properties specified 773 { 774 const json element = R"( 775 { 776 "comments": [ "comments property" ], 777 "volts": 1.03, 778 "actions": [ 779 { "pmbus_write_vout_command": { "format": "linear" } }, 780 { "run_rule": "set_voltage_rule" } 781 ] 782 } 783 )"_json; 784 std::unique_ptr<Configuration> configuration = 785 parseConfiguration(element); 786 EXPECT_EQ(configuration->getVolts().has_value(), true); 787 EXPECT_EQ(configuration->getVolts().value(), 1.03); 788 EXPECT_EQ(configuration->getActions().size(), 2); 789 } 790 791 // Test where works: volts and rule_id properties specified 792 { 793 const json element = R"( 794 { 795 "volts": 1.05, 796 "rule_id": "set_voltage_rule" 797 } 798 )"_json; 799 std::unique_ptr<Configuration> configuration = 800 parseConfiguration(element); 801 EXPECT_EQ(configuration->getVolts().has_value(), true); 802 EXPECT_EQ(configuration->getVolts().value(), 1.05); 803 EXPECT_EQ(configuration->getActions().size(), 1); 804 } 805 806 // Test where fails: volts value is invalid 807 try 808 { 809 const json element = R"( 810 { 811 "volts": "foo", 812 "actions": [ 813 { 814 "pmbus_write_vout_command": { 815 "format": "linear" 816 } 817 } 818 ] 819 } 820 )"_json; 821 parseConfiguration(element); 822 ADD_FAILURE() << "Should not have reached this line."; 823 } 824 catch (const std::invalid_argument& e) 825 { 826 EXPECT_STREQ(e.what(), "Element is not a number"); 827 } 828 829 // Test where fails: actions object is invalid 830 try 831 { 832 const json element = R"( 833 { 834 "volts": 1.03, 835 "actions": 1 836 } 837 )"_json; 838 parseConfiguration(element); 839 ADD_FAILURE() << "Should not have reached this line."; 840 } 841 catch (const std::invalid_argument& e) 842 { 843 EXPECT_STREQ(e.what(), "Element is not an array"); 844 } 845 846 // Test where fails: rule_id value is invalid 847 try 848 { 849 const json element = R"( 850 { 851 "volts": 1.05, 852 "rule_id": 1 853 } 854 )"_json; 855 parseConfiguration(element); 856 ADD_FAILURE() << "Should not have reached this line."; 857 } 858 catch (const std::invalid_argument& e) 859 { 860 EXPECT_STREQ(e.what(), "Element is not a string"); 861 } 862 863 // Test where fails: Required actions or rule_id property not specified 864 try 865 { 866 const json element = R"( 867 { 868 "volts": 1.03 869 } 870 )"_json; 871 parseConfiguration(element); 872 ADD_FAILURE() << "Should not have reached this line."; 873 } 874 catch (const std::invalid_argument& e) 875 { 876 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 877 "either rule_id or actions"); 878 } 879 880 // Test where fails: Required actions or rule_id property both specified 881 try 882 { 883 const json element = R"( 884 { 885 "volts": 1.03, 886 "rule_id": "set_voltage_rule", 887 "actions": [ 888 { 889 "pmbus_write_vout_command": { 890 "format": "linear" 891 } 892 } 893 ] 894 } 895 )"_json; 896 parseConfiguration(element); 897 ADD_FAILURE() << "Should not have reached this line."; 898 } 899 catch (const std::invalid_argument& e) 900 { 901 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 902 "either rule_id or actions"); 903 } 904 905 // Test where fails: Element is not an object 906 try 907 { 908 const json element = R"( [ "0xFF", "0x01" ] )"_json; 909 parseConfiguration(element); 910 ADD_FAILURE() << "Should not have reached this line."; 911 } 912 catch (const std::invalid_argument& e) 913 { 914 EXPECT_STREQ(e.what(), "Element is not an object"); 915 } 916 917 // Test where fails: Invalid property specified 918 try 919 { 920 const json element = R"( 921 { 922 "volts": 1.03, 923 "rule_id": "set_voltage_rule", 924 "foo": 1 925 } 926 )"_json; 927 parseConfiguration(element); 928 ADD_FAILURE() << "Should not have reached this line."; 929 } 930 catch (const std::invalid_argument& e) 931 { 932 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 933 } 934 } 935 936 TEST(ConfigFileParserTests, ParseDevice) 937 { 938 // Test where works: Only required properties specified 939 { 940 const json element = R"( 941 { 942 "id": "vdd_regulator", 943 "is_regulator": true, 944 "fru": "/system/chassis/motherboard/regulator2", 945 "i2c_interface": { "bus": 1, "address": "0x70" } 946 } 947 )"_json; 948 std::unique_ptr<Device> device = parseDevice(element); 949 EXPECT_EQ(device->getID(), "vdd_regulator"); 950 EXPECT_EQ(device->isRegulator(), true); 951 EXPECT_EQ(device->getFRU(), "/system/chassis/motherboard/regulator2"); 952 EXPECT_NE(&(device->getI2CInterface()), nullptr); 953 EXPECT_EQ(device->getPresenceDetection(), nullptr); 954 EXPECT_EQ(device->getConfiguration(), nullptr); 955 EXPECT_EQ(device->getRails().size(), 0); 956 } 957 958 // Test where works: All properties specified 959 { 960 // TODO : add presence_detection property 961 const json element = R"( 962 { 963 "id": "vdd_regulator", 964 "is_regulator": true, 965 "fru": "/system/chassis/motherboard/regulator2", 966 "i2c_interface": 967 { 968 "bus": 1, 969 "address": "0x70" 970 }, 971 "configuration": 972 { 973 "rule_id": "configure_ir35221_rule" 974 }, 975 "rails": 976 [ 977 { 978 "id": "vdd" 979 } 980 ] 981 } 982 )"_json; 983 std::unique_ptr<Device> device = parseDevice(element); 984 EXPECT_EQ(device->getID(), "vdd_regulator"); 985 EXPECT_EQ(device->isRegulator(), true); 986 EXPECT_EQ(device->getFRU(), "/system/chassis/motherboard/regulator2"); 987 EXPECT_NE(&(device->getI2CInterface()), nullptr); 988 // EXPECT_NE(device->getPresenceDetection(), nullptr); 989 EXPECT_NE(device->getConfiguration(), nullptr); 990 EXPECT_EQ(device->getRails().size(), 1); 991 } 992 993 // Test where fails: rails property exists and is_regulator is false 994 try 995 { 996 const json element = R"( 997 { 998 "id": "vdd_regulator", 999 "is_regulator": false, 1000 "fru": "/system/chassis/motherboard/regulator2", 1001 "i2c_interface": 1002 { 1003 "bus": 1, 1004 "address": "0x70" 1005 }, 1006 "configuration": 1007 { 1008 "rule_id": "configure_ir35221_rule" 1009 }, 1010 "rails": 1011 [ 1012 { 1013 "id": "vdd" 1014 } 1015 ] 1016 } 1017 )"_json; 1018 parseDevice(element); 1019 ADD_FAILURE() << "Should not have reached this line."; 1020 } 1021 catch (const std::invalid_argument& e) 1022 { 1023 EXPECT_STREQ(e.what(), 1024 "Invalid rails property when is_regulator is false"); 1025 } 1026 1027 // Test where fails: id value is invalid 1028 try 1029 { 1030 const json element = R"( 1031 { 1032 "id": 3, 1033 "is_regulator": true, 1034 "fru": "/system/chassis/motherboard/regulator2", 1035 "i2c_interface": 1036 { 1037 "bus": 1, 1038 "address": "0x70" 1039 } 1040 } 1041 )"_json; 1042 parseDevice(element); 1043 ADD_FAILURE() << "Should not have reached this line."; 1044 } 1045 catch (const std::invalid_argument& e) 1046 { 1047 EXPECT_STREQ(e.what(), "Element is not a string"); 1048 } 1049 1050 // Test where fails: is_regulator value is invalid 1051 try 1052 { 1053 const json element = R"( 1054 { 1055 "id": "vdd_regulator", 1056 "is_regulator": 3, 1057 "fru": "/system/chassis/motherboard/regulator2", 1058 "i2c_interface": 1059 { 1060 "bus": 1, 1061 "address": "0x70" 1062 } 1063 } 1064 )"_json; 1065 parseDevice(element); 1066 ADD_FAILURE() << "Should not have reached this line."; 1067 } 1068 catch (const std::invalid_argument& e) 1069 { 1070 EXPECT_STREQ(e.what(), "Element is not a boolean"); 1071 } 1072 1073 // Test where fails: fru value is invalid 1074 try 1075 { 1076 const json element = R"( 1077 { 1078 "id": "vdd_regulator", 1079 "is_regulator": true, 1080 "fru": 2, 1081 "i2c_interface": 1082 { 1083 "bus": 1, 1084 "address": "0x70" 1085 } 1086 } 1087 )"_json; 1088 parseDevice(element); 1089 ADD_FAILURE() << "Should not have reached this line."; 1090 } 1091 catch (const std::invalid_argument& e) 1092 { 1093 EXPECT_STREQ(e.what(), "Element is not a string"); 1094 } 1095 1096 // Test where fails: i2c_interface value is invalid 1097 try 1098 { 1099 const json element = R"( 1100 { 1101 "id": "vdd_regulator", 1102 "is_regulator": true, 1103 "fru": "/system/chassis/motherboard/regulator2", 1104 "i2c_interface": 3 1105 } 1106 )"_json; 1107 parseDevice(element); 1108 ADD_FAILURE() << "Should not have reached this line."; 1109 } 1110 catch (const std::invalid_argument& e) 1111 { 1112 EXPECT_STREQ(e.what(), "Element is not an object"); 1113 } 1114 1115 // Test where fails: Required id property not specified 1116 try 1117 { 1118 const json element = R"( 1119 { 1120 "is_regulator": true, 1121 "fru": "/system/chassis/motherboard/regulator2", 1122 "i2c_interface": 1123 { 1124 "bus": 1, 1125 "address": "0x70" 1126 } 1127 } 1128 )"_json; 1129 parseDevice(element); 1130 ADD_FAILURE() << "Should not have reached this line."; 1131 } 1132 catch (const std::invalid_argument& e) 1133 { 1134 EXPECT_STREQ(e.what(), "Required property missing: id"); 1135 } 1136 1137 // Test where fails: Required is_regulator property not specified 1138 try 1139 { 1140 const json element = R"( 1141 { 1142 "id": "vdd_regulator", 1143 "fru": "/system/chassis/motherboard/regulator2", 1144 "i2c_interface": 1145 { 1146 "bus": 1, 1147 "address": "0x70" 1148 } 1149 } 1150 )"_json; 1151 parseDevice(element); 1152 ADD_FAILURE() << "Should not have reached this line."; 1153 } 1154 catch (const std::invalid_argument& e) 1155 { 1156 EXPECT_STREQ(e.what(), "Required property missing: is_regulator"); 1157 } 1158 1159 // Test where fails: Required fru property not specified 1160 try 1161 { 1162 const json element = R"( 1163 { 1164 "id": "vdd_regulator", 1165 "is_regulator": true, 1166 "i2c_interface": 1167 { 1168 "bus": 1, 1169 "address": "0x70" 1170 } 1171 } 1172 )"_json; 1173 parseDevice(element); 1174 ADD_FAILURE() << "Should not have reached this line."; 1175 } 1176 catch (const std::invalid_argument& e) 1177 { 1178 EXPECT_STREQ(e.what(), "Required property missing: fru"); 1179 } 1180 1181 // Test where fails: Required i2c_interface property not specified 1182 try 1183 { 1184 const json element = R"( 1185 { 1186 "id": "vdd_regulator", 1187 "is_regulator": true, 1188 "fru": "/system/chassis/motherboard/regulator2" 1189 } 1190 )"_json; 1191 parseDevice(element); 1192 ADD_FAILURE() << "Should not have reached this line."; 1193 } 1194 catch (const std::invalid_argument& e) 1195 { 1196 EXPECT_STREQ(e.what(), "Required property missing: i2c_interface"); 1197 } 1198 1199 // Test where fails: Element is not an object 1200 try 1201 { 1202 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1203 parseDevice(element); 1204 ADD_FAILURE() << "Should not have reached this line."; 1205 } 1206 catch (const std::invalid_argument& e) 1207 { 1208 EXPECT_STREQ(e.what(), "Element is not an object"); 1209 } 1210 1211 // Test where fails: Invalid property specified 1212 try 1213 { 1214 const json element = R"( 1215 { 1216 "id": "vdd_regulator", 1217 "is_regulator": true, 1218 "fru": "/system/chassis/motherboard/regulator2", 1219 "i2c_interface": { "bus": 1, "address": "0x70" }, 1220 "foo" : true 1221 } 1222 )"_json; 1223 parseDevice(element); 1224 ADD_FAILURE() << "Should not have reached this line."; 1225 } 1226 catch (const std::invalid_argument& e) 1227 { 1228 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1229 } 1230 } 1231 1232 TEST(ConfigFileParserTests, ParseDeviceArray) 1233 { 1234 // Test where works 1235 { 1236 const json element = R"( 1237 [ 1238 { 1239 "id": "vdd_regulator", 1240 "is_regulator": true, 1241 "fru": "/system/chassis/motherboard/regulator2", 1242 "i2c_interface": { "bus": 1, "address": "0x70" } 1243 }, 1244 { 1245 "id": "vio_regulator", 1246 "is_regulator": true, 1247 "fru": "/system/chassis/motherboard/regulator2", 1248 "i2c_interface": { "bus": 1, "address": "0x71" } 1249 } 1250 ] 1251 )"_json; 1252 std::vector<std::unique_ptr<Device>> devices = 1253 parseDeviceArray(element); 1254 EXPECT_EQ(devices.size(), 2); 1255 EXPECT_EQ(devices[0]->getID(), "vdd_regulator"); 1256 EXPECT_EQ(devices[1]->getID(), "vio_regulator"); 1257 } 1258 1259 // Test where fails: Element is not an array 1260 try 1261 { 1262 const json element = R"( 1263 { 1264 "foo": "bar" 1265 } 1266 )"_json; 1267 parseDeviceArray(element); 1268 ADD_FAILURE() << "Should not have reached this line."; 1269 } 1270 catch (const std::invalid_argument& e) 1271 { 1272 EXPECT_STREQ(e.what(), "Element is not an array"); 1273 } 1274 } 1275 1276 TEST(ConfigFileParserTests, ParseDouble) 1277 { 1278 // Test where works: floating point value 1279 { 1280 const json element = R"( 1.03 )"_json; 1281 double value = parseDouble(element); 1282 EXPECT_EQ(value, 1.03); 1283 } 1284 1285 // Test where works: integer value 1286 { 1287 const json element = R"( 24 )"_json; 1288 double value = parseDouble(element); 1289 EXPECT_EQ(value, 24.0); 1290 } 1291 1292 // Test where fails: Element is not a number 1293 try 1294 { 1295 const json element = R"( true )"_json; 1296 parseDouble(element); 1297 ADD_FAILURE() << "Should not have reached this line."; 1298 } 1299 catch (const std::invalid_argument& e) 1300 { 1301 EXPECT_STREQ(e.what(), "Element is not a number"); 1302 } 1303 } 1304 1305 TEST(ConfigFileParserTests, ParseHexByte) 1306 { 1307 // Test where works: "0xFF" 1308 { 1309 const json element = R"( "0xFF" )"_json; 1310 uint8_t value = parseHexByte(element); 1311 EXPECT_EQ(value, 0xFF); 1312 } 1313 1314 // Test where works: "0xff" 1315 { 1316 const json element = R"( "0xff" )"_json; 1317 uint8_t value = parseHexByte(element); 1318 EXPECT_EQ(value, 0xff); 1319 } 1320 1321 // Test where works: "0xf" 1322 { 1323 const json element = R"( "0xf" )"_json; 1324 uint8_t value = parseHexByte(element); 1325 EXPECT_EQ(value, 0xf); 1326 } 1327 1328 // Test where fails: "0xfff" 1329 try 1330 { 1331 const json element = R"( "0xfff" )"_json; 1332 parseHexByte(element); 1333 ADD_FAILURE() << "Should not have reached this line."; 1334 } 1335 catch (const std::invalid_argument& e) 1336 { 1337 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1338 } 1339 1340 // Test where fails: "0xAG" 1341 try 1342 { 1343 const json element = R"( "0xAG" )"_json; 1344 parseHexByte(element); 1345 ADD_FAILURE() << "Should not have reached this line."; 1346 } 1347 catch (const std::invalid_argument& e) 1348 { 1349 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1350 } 1351 1352 // Test where fails: "ff" 1353 try 1354 { 1355 const json element = R"( "ff" )"_json; 1356 parseHexByte(element); 1357 ADD_FAILURE() << "Should not have reached this line."; 1358 } 1359 catch (const std::invalid_argument& e) 1360 { 1361 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1362 } 1363 1364 // Test where fails: "" 1365 try 1366 { 1367 const json element = ""; 1368 parseHexByte(element); 1369 ADD_FAILURE() << "Should not have reached this line."; 1370 } 1371 catch (const std::invalid_argument& e) 1372 { 1373 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1374 } 1375 1376 // Test where fails: "f" 1377 try 1378 { 1379 const json element = R"( "f" )"_json; 1380 parseHexByte(element); 1381 ADD_FAILURE() << "Should not have reached this line."; 1382 } 1383 catch (const std::invalid_argument& e) 1384 { 1385 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1386 } 1387 1388 // Test where fails: "0x" 1389 try 1390 { 1391 const json element = R"( "0x" )"_json; 1392 parseHexByte(element); 1393 ADD_FAILURE() << "Should not have reached this line."; 1394 } 1395 catch (const std::invalid_argument& e) 1396 { 1397 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1398 } 1399 1400 // Test where fails: "0Xff" 1401 try 1402 { 1403 const json element = R"( "0XFF" )"_json; 1404 parseHexByte(element); 1405 ADD_FAILURE() << "Should not have reached this line."; 1406 } 1407 catch (const std::invalid_argument& e) 1408 { 1409 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1410 } 1411 } 1412 1413 TEST(ConfigFileParserTests, ParseHexByteArray) 1414 { 1415 // Test where works 1416 { 1417 const json element = R"( [ "0xCC", "0xFF" ] )"_json; 1418 std::vector<uint8_t> hexBytes = parseHexByteArray(element); 1419 std::vector<uint8_t> expected = {0xcc, 0xff}; 1420 EXPECT_EQ(hexBytes, expected); 1421 } 1422 1423 // Test where fails: Element is not an array 1424 try 1425 { 1426 const json element = 0; 1427 parseHexByteArray(element); 1428 ADD_FAILURE() << "Should not have reached this line."; 1429 } 1430 catch (const std::invalid_argument& e) 1431 { 1432 EXPECT_STREQ(e.what(), "Element is not an array"); 1433 } 1434 } 1435 1436 TEST(ConfigFileParserTests, ParseI2CWriteBit) 1437 { 1438 // Test where works 1439 { 1440 const json element = R"( 1441 { 1442 "register": "0xA0", 1443 "position": 3, 1444 "value": 0 1445 } 1446 )"_json; 1447 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element); 1448 EXPECT_EQ(action->getRegister(), 0xA0); 1449 EXPECT_EQ(action->getPosition(), 3); 1450 EXPECT_EQ(action->getValue(), 0); 1451 } 1452 1453 // Test where fails: Invalid property specified 1454 try 1455 { 1456 const json element = R"( 1457 { 1458 "register": "0xA0", 1459 "position": 3, 1460 "value": 0, 1461 "foo": 3 1462 } 1463 )"_json; 1464 parseI2CWriteBit(element); 1465 ADD_FAILURE() << "Should not have reached this line."; 1466 } 1467 catch (const std::invalid_argument& e) 1468 { 1469 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1470 } 1471 1472 // Test where fails: Element is not an object 1473 try 1474 { 1475 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1476 parseI2CWriteBit(element); 1477 ADD_FAILURE() << "Should not have reached this line."; 1478 } 1479 catch (const std::invalid_argument& e) 1480 { 1481 EXPECT_STREQ(e.what(), "Element is not an object"); 1482 } 1483 1484 // Test where fails: register value is invalid 1485 try 1486 { 1487 const json element = R"( 1488 { 1489 "register": "0xAG", 1490 "position": 3, 1491 "value": 0 1492 } 1493 )"_json; 1494 parseI2CWriteBit(element); 1495 ADD_FAILURE() << "Should not have reached this line."; 1496 } 1497 catch (const std::invalid_argument& e) 1498 { 1499 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1500 } 1501 1502 // Test where fails: position value is invalid 1503 try 1504 { 1505 const json element = R"( 1506 { 1507 "register": "0xA0", 1508 "position": 8, 1509 "value": 0 1510 } 1511 )"_json; 1512 parseI2CWriteBit(element); 1513 ADD_FAILURE() << "Should not have reached this line."; 1514 } 1515 catch (const std::invalid_argument& e) 1516 { 1517 EXPECT_STREQ(e.what(), "Element is not a bit position"); 1518 } 1519 1520 // Test where fails: value value is invalid 1521 try 1522 { 1523 const json element = R"( 1524 { 1525 "register": "0xA0", 1526 "position": 3, 1527 "value": 2 1528 } 1529 )"_json; 1530 parseI2CWriteBit(element); 1531 ADD_FAILURE() << "Should not have reached this line."; 1532 } 1533 catch (const std::invalid_argument& e) 1534 { 1535 EXPECT_STREQ(e.what(), "Element is not a bit value"); 1536 } 1537 1538 // Test where fails: Required register property not specified 1539 try 1540 { 1541 const json element = R"( 1542 { 1543 "position": 3, 1544 "value": 0 1545 } 1546 )"_json; 1547 parseI2CWriteBit(element); 1548 ADD_FAILURE() << "Should not have reached this line."; 1549 } 1550 catch (const std::invalid_argument& e) 1551 { 1552 EXPECT_STREQ(e.what(), "Required property missing: register"); 1553 } 1554 1555 // Test where fails: Required position property not specified 1556 try 1557 { 1558 const json element = R"( 1559 { 1560 "register": "0xA0", 1561 "value": 0 1562 } 1563 )"_json; 1564 parseI2CWriteBit(element); 1565 ADD_FAILURE() << "Should not have reached this line."; 1566 } 1567 catch (const std::invalid_argument& e) 1568 { 1569 EXPECT_STREQ(e.what(), "Required property missing: position"); 1570 } 1571 1572 // Test where fails: Required value property not specified 1573 try 1574 { 1575 const json element = R"( 1576 { 1577 "register": "0xA0", 1578 "position": 3 1579 } 1580 )"_json; 1581 parseI2CWriteBit(element); 1582 ADD_FAILURE() << "Should not have reached this line."; 1583 } 1584 catch (const std::invalid_argument& e) 1585 { 1586 EXPECT_STREQ(e.what(), "Required property missing: value"); 1587 } 1588 } 1589 1590 TEST(ConfigFileParserTests, ParseI2CWriteByte) 1591 { 1592 // Test where works: Only required properties specified 1593 { 1594 const json element = R"( 1595 { 1596 "register": "0x0A", 1597 "value": "0xCC" 1598 } 1599 )"_json; 1600 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element); 1601 EXPECT_EQ(action->getRegister(), 0x0A); 1602 EXPECT_EQ(action->getValue(), 0xCC); 1603 EXPECT_EQ(action->getMask(), 0xFF); 1604 } 1605 1606 // Test where works: All properties specified 1607 { 1608 const json element = R"( 1609 { 1610 "register": "0x0A", 1611 "value": "0xCC", 1612 "mask": "0xF7" 1613 } 1614 )"_json; 1615 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element); 1616 EXPECT_EQ(action->getRegister(), 0x0A); 1617 EXPECT_EQ(action->getValue(), 0xCC); 1618 EXPECT_EQ(action->getMask(), 0xF7); 1619 } 1620 1621 // Test where fails: Element is not an object 1622 try 1623 { 1624 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1625 parseI2CWriteByte(element); 1626 ADD_FAILURE() << "Should not have reached this line."; 1627 } 1628 catch (const std::invalid_argument& e) 1629 { 1630 EXPECT_STREQ(e.what(), "Element is not an object"); 1631 } 1632 1633 // Test where fails: Invalid property specified 1634 try 1635 { 1636 const json element = R"( 1637 { 1638 "register": "0x0A", 1639 "value": "0xCC", 1640 "mask": "0xF7", 1641 "foo": 1 1642 } 1643 )"_json; 1644 parseI2CWriteByte(element); 1645 ADD_FAILURE() << "Should not have reached this line."; 1646 } 1647 catch (const std::invalid_argument& e) 1648 { 1649 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1650 } 1651 1652 // Test where fails: register value is invalid 1653 try 1654 { 1655 const json element = R"( 1656 { 1657 "register": "0x0Z", 1658 "value": "0xCC", 1659 "mask": "0xF7" 1660 } 1661 )"_json; 1662 parseI2CWriteByte(element); 1663 ADD_FAILURE() << "Should not have reached this line."; 1664 } 1665 catch (const std::invalid_argument& e) 1666 { 1667 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1668 } 1669 1670 // Test where fails: value value is invalid 1671 try 1672 { 1673 const json element = R"( 1674 { 1675 "register": "0x0A", 1676 "value": "0xCCC", 1677 "mask": "0xF7" 1678 } 1679 )"_json; 1680 parseI2CWriteByte(element); 1681 ADD_FAILURE() << "Should not have reached this line."; 1682 } 1683 catch (const std::invalid_argument& e) 1684 { 1685 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1686 } 1687 1688 // Test where fails: mask value is invalid 1689 try 1690 { 1691 const json element = R"( 1692 { 1693 "register": "0x0A", 1694 "value": "0xCC", 1695 "mask": "F7" 1696 } 1697 )"_json; 1698 parseI2CWriteByte(element); 1699 ADD_FAILURE() << "Should not have reached this line."; 1700 } 1701 catch (const std::invalid_argument& e) 1702 { 1703 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1704 } 1705 1706 // Test where fails: Required register property not specified 1707 try 1708 { 1709 const json element = R"( 1710 { 1711 "value": "0xCC", 1712 "mask": "0xF7" 1713 } 1714 )"_json; 1715 parseI2CWriteByte(element); 1716 ADD_FAILURE() << "Should not have reached this line."; 1717 } 1718 catch (const std::invalid_argument& e) 1719 { 1720 EXPECT_STREQ(e.what(), "Required property missing: register"); 1721 } 1722 1723 // Test where fails: Required value property not specified 1724 try 1725 { 1726 const json element = R"( 1727 { 1728 "register": "0x0A", 1729 "mask": "0xF7" 1730 } 1731 )"_json; 1732 parseI2CWriteByte(element); 1733 ADD_FAILURE() << "Should not have reached this line."; 1734 } 1735 catch (const std::invalid_argument& e) 1736 { 1737 EXPECT_STREQ(e.what(), "Required property missing: value"); 1738 } 1739 } 1740 1741 TEST(ConfigFileParserTests, ParseI2CWriteBytes) 1742 { 1743 // Test where works: Only required properties specified 1744 { 1745 const json element = R"( 1746 { 1747 "register": "0x0A", 1748 "values": [ "0xCC", "0xFF" ] 1749 } 1750 )"_json; 1751 std::unique_ptr<I2CWriteBytesAction> action = 1752 parseI2CWriteBytes(element); 1753 EXPECT_EQ(action->getRegister(), 0x0A); 1754 EXPECT_EQ(action->getValues().size(), 2); 1755 EXPECT_EQ(action->getValues()[0], 0xCC); 1756 EXPECT_EQ(action->getValues()[1], 0xFF); 1757 EXPECT_EQ(action->getMasks().size(), 0); 1758 } 1759 1760 // Test where works: All properties specified 1761 { 1762 const json element = R"( 1763 { 1764 "register": "0x0A", 1765 "values": [ "0xCC", "0xFF" ], 1766 "masks": [ "0x7F", "0x77" ] 1767 } 1768 )"_json; 1769 std::unique_ptr<I2CWriteBytesAction> action = 1770 parseI2CWriteBytes(element); 1771 EXPECT_EQ(action->getRegister(), 0x0A); 1772 EXPECT_EQ(action->getValues().size(), 2); 1773 EXPECT_EQ(action->getValues()[0], 0xCC); 1774 EXPECT_EQ(action->getValues()[1], 0xFF); 1775 EXPECT_EQ(action->getMasks().size(), 2); 1776 EXPECT_EQ(action->getMasks()[0], 0x7F); 1777 EXPECT_EQ(action->getMasks()[1], 0x77); 1778 } 1779 1780 // Test where fails: Element is not an object 1781 try 1782 { 1783 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1784 parseI2CWriteBytes(element); 1785 ADD_FAILURE() << "Should not have reached this line."; 1786 } 1787 catch (const std::invalid_argument& e) 1788 { 1789 EXPECT_STREQ(e.what(), "Element is not an object"); 1790 } 1791 1792 // Test where fails: Invalid property specified 1793 try 1794 { 1795 const json element = R"( 1796 { 1797 "register": "0x0A", 1798 "values": [ "0xCC", "0xFF" ], 1799 "masks": [ "0x7F", "0x7F" ], 1800 "foo": 1 1801 } 1802 )"_json; 1803 parseI2CWriteBytes(element); 1804 ADD_FAILURE() << "Should not have reached this line."; 1805 } 1806 catch (const std::invalid_argument& e) 1807 { 1808 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1809 } 1810 1811 // Test where fails: register value is invalid 1812 try 1813 { 1814 const json element = R"( 1815 { 1816 "register": "0x0Z", 1817 "values": [ "0xCC", "0xFF" ], 1818 "masks": [ "0x7F", "0x7F" ] 1819 } 1820 )"_json; 1821 parseI2CWriteBytes(element); 1822 ADD_FAILURE() << "Should not have reached this line."; 1823 } 1824 catch (const std::invalid_argument& e) 1825 { 1826 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1827 } 1828 1829 // Test where fails: values value is invalid 1830 try 1831 { 1832 const json element = R"( 1833 { 1834 "register": "0x0A", 1835 "values": [ "0xCCC", "0xFF" ], 1836 "masks": [ "0x7F", "0x7F" ] 1837 } 1838 )"_json; 1839 parseI2CWriteBytes(element); 1840 ADD_FAILURE() << "Should not have reached this line."; 1841 } 1842 catch (const std::invalid_argument& e) 1843 { 1844 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1845 } 1846 1847 // Test where fails: masks value is invalid 1848 try 1849 { 1850 const json element = R"( 1851 { 1852 "register": "0x0A", 1853 "values": [ "0xCC", "0xFF" ], 1854 "masks": [ "F", "0x7F" ] 1855 } 1856 )"_json; 1857 parseI2CWriteBytes(element); 1858 ADD_FAILURE() << "Should not have reached this line."; 1859 } 1860 catch (const std::invalid_argument& e) 1861 { 1862 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1863 } 1864 1865 // Test where fails: number of elements in masks is invalid 1866 try 1867 { 1868 const json element = R"( 1869 { 1870 "register": "0x0A", 1871 "values": [ "0xCC", "0xFF" ], 1872 "masks": [ "0x7F" ] 1873 } 1874 )"_json; 1875 parseI2CWriteBytes(element); 1876 ADD_FAILURE() << "Should not have reached this line."; 1877 } 1878 catch (const std::invalid_argument& e) 1879 { 1880 EXPECT_STREQ(e.what(), "Invalid number of elements in masks"); 1881 } 1882 1883 // Test where fails: Required register property not specified 1884 try 1885 { 1886 const json element = R"( 1887 { 1888 "values": [ "0xCC", "0xFF" ] 1889 } 1890 )"_json; 1891 parseI2CWriteBytes(element); 1892 ADD_FAILURE() << "Should not have reached this line."; 1893 } 1894 catch (const std::invalid_argument& e) 1895 { 1896 EXPECT_STREQ(e.what(), "Required property missing: register"); 1897 } 1898 1899 // Test where fails: Required values property not specified 1900 try 1901 { 1902 const json element = R"( 1903 { 1904 "register": "0x0A" 1905 } 1906 )"_json; 1907 parseI2CWriteBytes(element); 1908 ADD_FAILURE() << "Should not have reached this line."; 1909 } 1910 catch (const std::invalid_argument& e) 1911 { 1912 EXPECT_STREQ(e.what(), "Required property missing: values"); 1913 } 1914 } 1915 1916 TEST(ConfigFileParserTests, ParseInt8) 1917 { 1918 // Test where works: INT8_MIN 1919 { 1920 const json element = R"( -128 )"_json; 1921 int8_t value = parseInt8(element); 1922 EXPECT_EQ(value, -128); 1923 } 1924 1925 // Test where works: INT8_MAX 1926 { 1927 const json element = R"( 127 )"_json; 1928 int8_t value = parseInt8(element); 1929 EXPECT_EQ(value, 127); 1930 } 1931 1932 // Test where fails: Element is not an integer 1933 try 1934 { 1935 const json element = R"( 1.03 )"_json; 1936 parseInt8(element); 1937 ADD_FAILURE() << "Should not have reached this line."; 1938 } 1939 catch (const std::invalid_argument& e) 1940 { 1941 EXPECT_STREQ(e.what(), "Element is not an integer"); 1942 } 1943 1944 // Test where fails: Value < INT8_MIN 1945 try 1946 { 1947 const json element = R"( -129 )"_json; 1948 parseInt8(element); 1949 ADD_FAILURE() << "Should not have reached this line."; 1950 } 1951 catch (const std::invalid_argument& e) 1952 { 1953 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 1954 } 1955 1956 // Test where fails: Value > INT8_MAX 1957 try 1958 { 1959 const json element = R"( 128 )"_json; 1960 parseInt8(element); 1961 ADD_FAILURE() << "Should not have reached this line."; 1962 } 1963 catch (const std::invalid_argument& e) 1964 { 1965 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 1966 } 1967 } 1968 1969 TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand) 1970 { 1971 // Test where works: Only required properties specified 1972 { 1973 const json element = R"( 1974 { 1975 "format": "linear" 1976 } 1977 )"_json; 1978 std::unique_ptr<PMBusWriteVoutCommandAction> action = 1979 parsePMBusWriteVoutCommand(element); 1980 EXPECT_EQ(action->getVolts().has_value(), false); 1981 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 1982 EXPECT_EQ(action->getExponent().has_value(), false); 1983 EXPECT_EQ(action->isVerified(), false); 1984 } 1985 1986 // Test where works: All properties specified 1987 { 1988 const json element = R"( 1989 { 1990 "volts": 1.03, 1991 "format": "linear", 1992 "exponent": -8, 1993 "is_verified": true 1994 } 1995 )"_json; 1996 std::unique_ptr<PMBusWriteVoutCommandAction> action = 1997 parsePMBusWriteVoutCommand(element); 1998 EXPECT_EQ(action->getVolts().has_value(), true); 1999 EXPECT_EQ(action->getVolts().value(), 1.03); 2000 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 2001 EXPECT_EQ(action->getExponent().has_value(), true); 2002 EXPECT_EQ(action->getExponent().value(), -8); 2003 EXPECT_EQ(action->isVerified(), true); 2004 } 2005 2006 // Test where fails: Element is not an object 2007 try 2008 { 2009 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2010 parsePMBusWriteVoutCommand(element); 2011 ADD_FAILURE() << "Should not have reached this line."; 2012 } 2013 catch (const std::invalid_argument& e) 2014 { 2015 EXPECT_STREQ(e.what(), "Element is not an object"); 2016 } 2017 2018 // Test where fails: volts value is invalid 2019 try 2020 { 2021 const json element = R"( 2022 { 2023 "volts": "foo", 2024 "format": "linear" 2025 } 2026 )"_json; 2027 parsePMBusWriteVoutCommand(element); 2028 ADD_FAILURE() << "Should not have reached this line."; 2029 } 2030 catch (const std::invalid_argument& e) 2031 { 2032 EXPECT_STREQ(e.what(), "Element is not a number"); 2033 } 2034 2035 // Test where fails: Required format property not specified 2036 try 2037 { 2038 const json element = R"( 2039 { 2040 "volts": 1.03, 2041 "is_verified": true 2042 } 2043 )"_json; 2044 parsePMBusWriteVoutCommand(element); 2045 ADD_FAILURE() << "Should not have reached this line."; 2046 } 2047 catch (const std::invalid_argument& e) 2048 { 2049 EXPECT_STREQ(e.what(), "Required property missing: format"); 2050 } 2051 2052 // Test where fails: format value is invalid 2053 try 2054 { 2055 const json element = R"( 2056 { 2057 "format": "linear_11" 2058 } 2059 )"_json; 2060 parsePMBusWriteVoutCommand(element); 2061 ADD_FAILURE() << "Should not have reached this line."; 2062 } 2063 catch (const std::invalid_argument& e) 2064 { 2065 EXPECT_STREQ(e.what(), "Invalid format value: linear_11"); 2066 } 2067 2068 // Test where fails: exponent value is invalid 2069 try 2070 { 2071 const json element = R"( 2072 { 2073 "format": "linear", 2074 "exponent": 1.3 2075 } 2076 )"_json; 2077 parsePMBusWriteVoutCommand(element); 2078 ADD_FAILURE() << "Should not have reached this line."; 2079 } 2080 catch (const std::invalid_argument& e) 2081 { 2082 EXPECT_STREQ(e.what(), "Element is not an integer"); 2083 } 2084 2085 // Test where fails: is_verified value is invalid 2086 try 2087 { 2088 const json element = R"( 2089 { 2090 "format": "linear", 2091 "is_verified": "true" 2092 } 2093 )"_json; 2094 parsePMBusWriteVoutCommand(element); 2095 ADD_FAILURE() << "Should not have reached this line."; 2096 } 2097 catch (const std::invalid_argument& e) 2098 { 2099 EXPECT_STREQ(e.what(), "Element is not a boolean"); 2100 } 2101 2102 // Test where fails: Invalid property specified 2103 try 2104 { 2105 const json element = R"( 2106 { 2107 "format": "linear", 2108 "foo": "bar" 2109 } 2110 )"_json; 2111 parsePMBusWriteVoutCommand(element); 2112 ADD_FAILURE() << "Should not have reached this line."; 2113 } 2114 catch (const std::invalid_argument& e) 2115 { 2116 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2117 } 2118 } 2119 2120 TEST(ConfigFileParserTests, ParseRail) 2121 { 2122 // Test where works: Only required properties specified 2123 { 2124 const json element = R"( 2125 { 2126 "id": "vdd" 2127 } 2128 )"_json; 2129 std::unique_ptr<Rail> rail = parseRail(element); 2130 EXPECT_EQ(rail->getID(), "vdd"); 2131 EXPECT_EQ(rail->getConfiguration(), nullptr); 2132 EXPECT_EQ(rail->getSensorMonitoring(), nullptr); 2133 } 2134 2135 // Test where works: All properties specified 2136 { 2137 const json element = R"( 2138 { 2139 "comments": [ "comments property" ], 2140 "id": "vdd", 2141 "configuration": { 2142 "volts": 1.1, 2143 "actions": [ 2144 { 2145 "pmbus_write_vout_command": { 2146 "format": "linear" 2147 } 2148 } 2149 ] 2150 }, 2151 "sensor_monitoring": { 2152 "actions": [ 2153 { "run_rule": "read_sensors_rule" } 2154 ] 2155 } 2156 } 2157 )"_json; 2158 std::unique_ptr<Rail> rail = parseRail(element); 2159 EXPECT_EQ(rail->getID(), "vdd"); 2160 EXPECT_NE(rail->getConfiguration(), nullptr); 2161 EXPECT_NE(rail->getSensorMonitoring(), nullptr); 2162 } 2163 2164 // Test where fails: id property not specified 2165 try 2166 { 2167 const json element = R"( 2168 { 2169 "configuration": { 2170 "volts": 1.1, 2171 "actions": [ 2172 { 2173 "pmbus_write_vout_command": { 2174 "format": "linear" 2175 } 2176 } 2177 ] 2178 } 2179 } 2180 )"_json; 2181 parseRail(element); 2182 ADD_FAILURE() << "Should not have reached this line."; 2183 } 2184 catch (const std::invalid_argument& e) 2185 { 2186 EXPECT_STREQ(e.what(), "Required property missing: id"); 2187 } 2188 2189 // Test where fails: id property is invalid 2190 try 2191 { 2192 const json element = R"( 2193 { 2194 "id": "", 2195 "configuration": { 2196 "volts": 1.1, 2197 "actions": [ 2198 { 2199 "pmbus_write_vout_command": { 2200 "format": "linear" 2201 } 2202 } 2203 ] 2204 } 2205 } 2206 )"_json; 2207 parseRail(element); 2208 ADD_FAILURE() << "Should not have reached this line."; 2209 } 2210 catch (const std::invalid_argument& e) 2211 { 2212 EXPECT_STREQ(e.what(), "Element contains an empty string"); 2213 } 2214 2215 // Test where fails: Element is not an object 2216 try 2217 { 2218 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2219 parseRail(element); 2220 ADD_FAILURE() << "Should not have reached this line."; 2221 } 2222 catch (const std::invalid_argument& e) 2223 { 2224 EXPECT_STREQ(e.what(), "Element is not an object"); 2225 } 2226 2227 // Test where fails: configuration value is invalid 2228 try 2229 { 2230 const json element = R"( 2231 { 2232 "id": "vdd", 2233 "configuration": "config" 2234 } 2235 )"_json; 2236 parseRail(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 an object"); 2242 } 2243 2244 // Test where fails: sensor_monitoring value is invalid 2245 try 2246 { 2247 const json element = R"( 2248 { 2249 "comments": [ "comments property" ], 2250 "id": "vdd", 2251 "configuration": { 2252 "volts": 1.1, 2253 "actions": [ 2254 { 2255 "pmbus_write_vout_command": { 2256 "format": "linear" 2257 } 2258 } 2259 ] 2260 }, 2261 "sensor_monitoring": 1 2262 } 2263 )"_json; 2264 parseRail(element); 2265 ADD_FAILURE() << "Should not have reached this line."; 2266 } 2267 catch (const std::invalid_argument& e) 2268 { 2269 EXPECT_STREQ(e.what(), "Element is not an object"); 2270 } 2271 2272 // Test where fails: Invalid property specified 2273 try 2274 { 2275 const json element = R"( 2276 { 2277 "id": "vdd", 2278 "foo" : true 2279 } 2280 )"_json; 2281 parseRail(element); 2282 ADD_FAILURE() << "Should not have reached this line."; 2283 } 2284 catch (const std::invalid_argument& e) 2285 { 2286 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2287 } 2288 } 2289 2290 TEST(ConfigFileParserTests, ParseRailArray) 2291 { 2292 // Test where works 2293 { 2294 const json element = R"( 2295 [ 2296 { "id": "vdd" }, 2297 { "id": "vio" } 2298 ] 2299 )"_json; 2300 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element); 2301 EXPECT_EQ(rails.size(), 2); 2302 EXPECT_EQ(rails[0]->getID(), "vdd"); 2303 EXPECT_EQ(rails[1]->getID(), "vio"); 2304 } 2305 2306 // Test where fails: Element is not an array 2307 try 2308 { 2309 const json element = R"( 2310 { 2311 "foo": "bar" 2312 } 2313 )"_json; 2314 parseRailArray(element); 2315 ADD_FAILURE() << "Should not have reached this line."; 2316 } 2317 catch (const std::invalid_argument& e) 2318 { 2319 EXPECT_STREQ(e.what(), "Element is not an array"); 2320 } 2321 } 2322 2323 TEST(ConfigFileParserTests, ParseRoot) 2324 { 2325 // Test where works: Only required properties specified 2326 { 2327 const json element = R"( 2328 { 2329 "chassis": [ 2330 { "number": 1 } 2331 ] 2332 } 2333 )"_json; 2334 std::vector<std::unique_ptr<Rule>> rules{}; 2335 std::vector<std::unique_ptr<Chassis>> chassis{}; 2336 std::tie(rules, chassis) = parseRoot(element); 2337 EXPECT_EQ(rules.size(), 0); 2338 EXPECT_EQ(chassis.size(), 1); 2339 } 2340 2341 // Test where works: All properties specified 2342 { 2343 const json element = R"( 2344 { 2345 "comments": [ "Config file for a FooBar one-chassis system" ], 2346 "rules": [ 2347 { 2348 "id": "set_voltage_rule", 2349 "actions": [ 2350 { "pmbus_write_vout_command": { "format": "linear" } } 2351 ] 2352 } 2353 ], 2354 "chassis": [ 2355 { "number": 1 }, 2356 { "number": 3 } 2357 ] 2358 } 2359 )"_json; 2360 std::vector<std::unique_ptr<Rule>> rules{}; 2361 std::vector<std::unique_ptr<Chassis>> chassis{}; 2362 std::tie(rules, chassis) = parseRoot(element); 2363 EXPECT_EQ(rules.size(), 1); 2364 EXPECT_EQ(chassis.size(), 2); 2365 } 2366 2367 // Test where fails: Element is not an object 2368 try 2369 { 2370 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2371 parseRoot(element); 2372 ADD_FAILURE() << "Should not have reached this line."; 2373 } 2374 catch (const std::invalid_argument& e) 2375 { 2376 EXPECT_STREQ(e.what(), "Element is not an object"); 2377 } 2378 2379 // Test where fails: chassis property not specified 2380 try 2381 { 2382 const json element = R"( 2383 { 2384 "rules": [ 2385 { 2386 "id": "set_voltage_rule", 2387 "actions": [ 2388 { "pmbus_write_vout_command": { "format": "linear" } } 2389 ] 2390 } 2391 ] 2392 } 2393 )"_json; 2394 parseRoot(element); 2395 ADD_FAILURE() << "Should not have reached this line."; 2396 } 2397 catch (const std::invalid_argument& e) 2398 { 2399 EXPECT_STREQ(e.what(), "Required property missing: chassis"); 2400 } 2401 2402 // Test where fails: Invalid property specified 2403 try 2404 { 2405 const json element = R"( 2406 { 2407 "remarks": [ "Config file for a FooBar one-chassis system" ], 2408 "chassis": [ 2409 { "number": 1 } 2410 ] 2411 } 2412 )"_json; 2413 parseRoot(element); 2414 ADD_FAILURE() << "Should not have reached this line."; 2415 } 2416 catch (const std::invalid_argument& e) 2417 { 2418 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2419 } 2420 } 2421 2422 TEST(ConfigFileParserTests, ParseRule) 2423 { 2424 // Test where works: comments property specified 2425 { 2426 const json element = R"( 2427 { 2428 "comments": [ "Set voltage rule" ], 2429 "id": "set_voltage_rule", 2430 "actions": [ 2431 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 2432 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 2433 ] 2434 } 2435 )"_json; 2436 std::unique_ptr<Rule> rule = parseRule(element); 2437 EXPECT_EQ(rule->getID(), "set_voltage_rule"); 2438 EXPECT_EQ(rule->getActions().size(), 2); 2439 } 2440 2441 // Test where works: comments property not specified 2442 { 2443 const json element = R"( 2444 { 2445 "id": "set_voltage_rule", 2446 "actions": [ 2447 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 2448 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }, 2449 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } } 2450 ] 2451 } 2452 )"_json; 2453 std::unique_ptr<Rule> rule = parseRule(element); 2454 EXPECT_EQ(rule->getID(), "set_voltage_rule"); 2455 EXPECT_EQ(rule->getActions().size(), 3); 2456 } 2457 2458 // Test where fails: Element is not an object 2459 try 2460 { 2461 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2462 parseRule(element); 2463 ADD_FAILURE() << "Should not have reached this line."; 2464 } 2465 catch (const std::invalid_argument& e) 2466 { 2467 EXPECT_STREQ(e.what(), "Element is not an object"); 2468 } 2469 2470 // Test where fails: id property not specified 2471 try 2472 { 2473 const json element = R"( 2474 { 2475 "actions": [ 2476 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 2477 ] 2478 } 2479 )"_json; 2480 parseRule(element); 2481 ADD_FAILURE() << "Should not have reached this line."; 2482 } 2483 catch (const std::invalid_argument& e) 2484 { 2485 EXPECT_STREQ(e.what(), "Required property missing: id"); 2486 } 2487 2488 // Test where fails: id property is invalid 2489 try 2490 { 2491 const json element = R"( 2492 { 2493 "id": "", 2494 "actions": [ 2495 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 2496 ] 2497 } 2498 )"_json; 2499 parseRule(element); 2500 ADD_FAILURE() << "Should not have reached this line."; 2501 } 2502 catch (const std::invalid_argument& e) 2503 { 2504 EXPECT_STREQ(e.what(), "Element contains an empty string"); 2505 } 2506 2507 // Test where fails: actions property not specified 2508 try 2509 { 2510 const json element = R"( 2511 { 2512 "comments": [ "Set voltage rule" ], 2513 "id": "set_voltage_rule" 2514 } 2515 )"_json; 2516 parseRule(element); 2517 ADD_FAILURE() << "Should not have reached this line."; 2518 } 2519 catch (const std::invalid_argument& e) 2520 { 2521 EXPECT_STREQ(e.what(), "Required property missing: actions"); 2522 } 2523 2524 // Test where fails: actions property is invalid 2525 try 2526 { 2527 const json element = R"( 2528 { 2529 "id": "set_voltage_rule", 2530 "actions": true 2531 } 2532 )"_json; 2533 parseRule(element); 2534 ADD_FAILURE() << "Should not have reached this line."; 2535 } 2536 catch (const std::invalid_argument& e) 2537 { 2538 EXPECT_STREQ(e.what(), "Element is not an array"); 2539 } 2540 2541 // Test where fails: Invalid property specified 2542 try 2543 { 2544 const json element = R"( 2545 { 2546 "remarks": [ "Set voltage rule" ], 2547 "id": "set_voltage_rule", 2548 "actions": [ 2549 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 2550 ] 2551 } 2552 )"_json; 2553 parseRule(element); 2554 ADD_FAILURE() << "Should not have reached this line."; 2555 } 2556 catch (const std::invalid_argument& e) 2557 { 2558 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2559 } 2560 } 2561 2562 TEST(ConfigFileParserTests, ParseRuleArray) 2563 { 2564 // Test where works 2565 { 2566 const json element = R"( 2567 [ 2568 { 2569 "id": "set_voltage_rule1", 2570 "actions": [ 2571 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 2572 ] 2573 }, 2574 { 2575 "id": "set_voltage_rule2", 2576 "actions": [ 2577 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 2578 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } } 2579 ] 2580 } 2581 ] 2582 )"_json; 2583 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element); 2584 EXPECT_EQ(rules.size(), 2); 2585 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 2586 EXPECT_EQ(rules[0]->getActions().size(), 1); 2587 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 2588 EXPECT_EQ(rules[1]->getActions().size(), 2); 2589 } 2590 2591 // Test where fails: Element is not an array 2592 try 2593 { 2594 const json element = R"( { "id": "set_voltage_rule" } )"_json; 2595 parseRuleArray(element); 2596 ADD_FAILURE() << "Should not have reached this line."; 2597 } 2598 catch (const std::invalid_argument& e) 2599 { 2600 EXPECT_STREQ(e.what(), "Element is not an array"); 2601 } 2602 } 2603 2604 TEST(ConfigFileParserTests, ParseRuleIDOrActionsProperty) 2605 { 2606 // Test where works: actions specified 2607 { 2608 const json element = R"( 2609 { 2610 "actions": [ 2611 { "pmbus_write_vout_command": { "format": "linear" } }, 2612 { "run_rule": "set_voltage_rule" } 2613 ] 2614 } 2615 )"_json; 2616 std::vector<std::unique_ptr<Action>> actions = 2617 parseRuleIDOrActionsProperty(element); 2618 EXPECT_EQ(actions.size(), 2); 2619 } 2620 2621 // Test where works: rule_id specified 2622 { 2623 const json element = R"( 2624 { 2625 "rule_id": "set_voltage_rule" 2626 } 2627 )"_json; 2628 std::vector<std::unique_ptr<Action>> actions = 2629 parseRuleIDOrActionsProperty(element); 2630 EXPECT_EQ(actions.size(), 1); 2631 } 2632 2633 // Test where fails: Element is not an object 2634 try 2635 { 2636 const json element = R"( [ "foo", "bar" ] )"_json; 2637 parseRuleIDOrActionsProperty(element); 2638 ADD_FAILURE() << "Should not have reached this line."; 2639 } 2640 catch (const std::invalid_argument& e) 2641 { 2642 EXPECT_STREQ(e.what(), "Element is not an object"); 2643 } 2644 2645 // Test where fails: rule_id is invalid 2646 try 2647 { 2648 const json element = R"( 2649 { "rule_id": 1 } 2650 )"_json; 2651 parseRuleIDOrActionsProperty(element); 2652 ADD_FAILURE() << "Should not have reached this line."; 2653 } 2654 catch (const std::invalid_argument& e) 2655 { 2656 EXPECT_STREQ(e.what(), "Element is not a string"); 2657 } 2658 2659 // Test where fails: actions is invalid 2660 try 2661 { 2662 const json element = R"( 2663 { "actions": 1 } 2664 )"_json; 2665 parseRuleIDOrActionsProperty(element); 2666 ADD_FAILURE() << "Should not have reached this line."; 2667 } 2668 catch (const std::invalid_argument& e) 2669 { 2670 EXPECT_STREQ(e.what(), "Element is not an array"); 2671 } 2672 2673 // Test where fails: Neither rule_id nor actions specified 2674 try 2675 { 2676 const json element = R"( 2677 { 2678 "volts": 1.03 2679 } 2680 )"_json; 2681 parseRuleIDOrActionsProperty(element); 2682 ADD_FAILURE() << "Should not have reached this line."; 2683 } 2684 catch (const std::invalid_argument& e) 2685 { 2686 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 2687 "either rule_id or actions"); 2688 } 2689 2690 // Test where fails: Both rule_id and actions specified 2691 try 2692 { 2693 const json element = R"( 2694 { 2695 "volts": 1.03, 2696 "rule_id": "set_voltage_rule", 2697 "actions": [ 2698 { 2699 "pmbus_write_vout_command": { 2700 "format": "linear" 2701 } 2702 } 2703 ] 2704 } 2705 )"_json; 2706 parseRuleIDOrActionsProperty(element); 2707 ADD_FAILURE() << "Should not have reached this line."; 2708 } 2709 catch (const std::invalid_argument& e) 2710 { 2711 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 2712 "either rule_id or actions"); 2713 } 2714 } 2715 2716 TEST(ConfigFileParserTests, ParseRunRule) 2717 { 2718 // Test where works 2719 { 2720 const json element = "vdd_regulator"; 2721 std::unique_ptr<RunRuleAction> action = parseRunRule(element); 2722 EXPECT_EQ(action->getRuleID(), "vdd_regulator"); 2723 } 2724 2725 // Test where fails: Element is not a string 2726 try 2727 { 2728 const json element = 1; 2729 parseRunRule(element); 2730 ADD_FAILURE() << "Should not have reached this line."; 2731 } 2732 catch (const std::invalid_argument& e) 2733 { 2734 EXPECT_STREQ(e.what(), "Element is not a string"); 2735 } 2736 2737 // Test where fails: Empty string 2738 try 2739 { 2740 const json element = ""; 2741 parseRunRule(element); 2742 ADD_FAILURE() << "Should not have reached this line."; 2743 } 2744 catch (const std::invalid_argument& e) 2745 { 2746 EXPECT_STREQ(e.what(), "Element contains an empty string"); 2747 } 2748 } 2749 2750 TEST(ConfigFileParserTests, ParseSensorMonitoring) 2751 { 2752 // Test where works: actions property specified 2753 { 2754 const json element = R"( 2755 { 2756 "actions": [ 2757 { "run_rule": "read_sensors_rule" } 2758 ] 2759 } 2760 )"_json; 2761 std::unique_ptr<SensorMonitoring> sensorMonitoring = 2762 parseSensorMonitoring(element); 2763 EXPECT_EQ(sensorMonitoring->getActions().size(), 1); 2764 } 2765 2766 // Test where works: rule_id property specified 2767 { 2768 const json element = R"( 2769 { 2770 "comments": [ "comments property" ], 2771 "rule_id": "set_voltage_rule" 2772 } 2773 )"_json; 2774 std::unique_ptr<SensorMonitoring> sensorMonitoring = 2775 parseSensorMonitoring(element); 2776 EXPECT_EQ(sensorMonitoring->getActions().size(), 1); 2777 } 2778 2779 // Test where fails: actions object is invalid 2780 try 2781 { 2782 const json element = R"( 2783 { 2784 "actions": 1 2785 } 2786 )"_json; 2787 parseSensorMonitoring(element); 2788 ADD_FAILURE() << "Should not have reached this line."; 2789 } 2790 catch (const std::invalid_argument& e) 2791 { 2792 EXPECT_STREQ(e.what(), "Element is not an array"); 2793 } 2794 2795 // Test where fails: rule_id value is invalid 2796 try 2797 { 2798 const json element = R"( 2799 { 2800 "rule_id": 1 2801 } 2802 )"_json; 2803 parseSensorMonitoring(element); 2804 ADD_FAILURE() << "Should not have reached this line."; 2805 } 2806 catch (const std::invalid_argument& e) 2807 { 2808 EXPECT_STREQ(e.what(), "Element is not a string"); 2809 } 2810 2811 // Test where fails: Required actions or rule_id property not specified 2812 try 2813 { 2814 const json element = R"( 2815 { 2816 "comments": [ "comments property" ] 2817 } 2818 )"_json; 2819 parseSensorMonitoring(element); 2820 ADD_FAILURE() << "Should not have reached this line."; 2821 } 2822 catch (const std::invalid_argument& e) 2823 { 2824 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 2825 "either rule_id or actions"); 2826 } 2827 2828 // Test where fails: Required actions or rule_id property both specified 2829 try 2830 { 2831 const json element = R"( 2832 { 2833 "rule_id": "set_voltage_rule", 2834 "actions": [ 2835 { "run_rule": "read_sensors_rule" } 2836 ] 2837 } 2838 )"_json; 2839 parseSensorMonitoring(element); 2840 ADD_FAILURE() << "Should not have reached this line."; 2841 } 2842 catch (const std::invalid_argument& e) 2843 { 2844 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 2845 "either rule_id or actions"); 2846 } 2847 2848 // Test where fails: Element is not an object 2849 try 2850 { 2851 const json element = R"( [ "foo", "bar" ] )"_json; 2852 parseSensorMonitoring(element); 2853 ADD_FAILURE() << "Should not have reached this line."; 2854 } 2855 catch (const std::invalid_argument& e) 2856 { 2857 EXPECT_STREQ(e.what(), "Element is not an object"); 2858 } 2859 2860 // Test where fails: Invalid property specified 2861 try 2862 { 2863 const json element = R"( 2864 { 2865 "foo": "bar", 2866 "actions": [ 2867 { "run_rule": "read_sensors_rule" } 2868 ] 2869 } 2870 )"_json; 2871 parseSensorMonitoring(element); 2872 ADD_FAILURE() << "Should not have reached this line."; 2873 } 2874 catch (const std::invalid_argument& e) 2875 { 2876 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2877 } 2878 } 2879 2880 TEST(ConfigFileParserTests, ParseString) 2881 { 2882 // Test where works: Empty string 2883 { 2884 const json element = ""; 2885 std::string value = parseString(element, true); 2886 EXPECT_EQ(value, ""); 2887 } 2888 2889 // Test where works: Non-empty string 2890 { 2891 const json element = "vdd_regulator"; 2892 std::string value = parseString(element, false); 2893 EXPECT_EQ(value, "vdd_regulator"); 2894 } 2895 2896 // Test where fails: Element is not a string 2897 try 2898 { 2899 const json element = R"( { "foo": "bar" } )"_json; 2900 parseString(element); 2901 ADD_FAILURE() << "Should not have reached this line."; 2902 } 2903 catch (const std::invalid_argument& e) 2904 { 2905 EXPECT_STREQ(e.what(), "Element is not a string"); 2906 } 2907 2908 // Test where fails: Empty string 2909 try 2910 { 2911 const json element = ""; 2912 parseString(element); 2913 ADD_FAILURE() << "Should not have reached this line."; 2914 } 2915 catch (const std::invalid_argument& e) 2916 { 2917 EXPECT_STREQ(e.what(), "Element contains an empty string"); 2918 } 2919 } 2920 2921 TEST(ConfigFileParserTests, ParseUint8) 2922 { 2923 // Test where works: 0 2924 { 2925 const json element = R"( 0 )"_json; 2926 uint8_t value = parseUint8(element); 2927 EXPECT_EQ(value, 0); 2928 } 2929 2930 // Test where works: UINT8_MAX 2931 { 2932 const json element = R"( 255 )"_json; 2933 uint8_t value = parseUint8(element); 2934 EXPECT_EQ(value, 255); 2935 } 2936 2937 // Test where fails: Element is not an integer 2938 try 2939 { 2940 const json element = R"( 1.03 )"_json; 2941 parseUint8(element); 2942 ADD_FAILURE() << "Should not have reached this line."; 2943 } 2944 catch (const std::invalid_argument& e) 2945 { 2946 EXPECT_STREQ(e.what(), "Element is not an integer"); 2947 } 2948 2949 // Test where fails: Value < 0 2950 try 2951 { 2952 const json element = R"( -1 )"_json; 2953 parseUint8(element); 2954 ADD_FAILURE() << "Should not have reached this line."; 2955 } 2956 catch (const std::invalid_argument& e) 2957 { 2958 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); 2959 } 2960 2961 // Test where fails: Value > UINT8_MAX 2962 try 2963 { 2964 const json element = R"( 256 )"_json; 2965 parseUint8(element); 2966 ADD_FAILURE() << "Should not have reached this line."; 2967 } 2968 catch (const std::invalid_argument& e) 2969 { 2970 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); 2971 } 2972 } 2973 2974 TEST(ConfigFileParserTests, ParseUnsignedInteger) 2975 { 2976 // Test where works: 1 2977 { 2978 const json element = R"( 1 )"_json; 2979 unsigned int value = parseUnsignedInteger(element); 2980 EXPECT_EQ(value, 1); 2981 } 2982 2983 // Test where fails: Element is not an integer 2984 try 2985 { 2986 const json element = R"( 1.5 )"_json; 2987 parseUnsignedInteger(element); 2988 ADD_FAILURE() << "Should not have reached this line."; 2989 } 2990 catch (const std::invalid_argument& e) 2991 { 2992 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 2993 } 2994 2995 // Test where fails: Value < 0 2996 try 2997 { 2998 const json element = R"( -1 )"_json; 2999 parseUnsignedInteger(element); 3000 ADD_FAILURE() << "Should not have reached this line."; 3001 } 3002 catch (const std::invalid_argument& e) 3003 { 3004 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 3005 } 3006 } 3007 3008 TEST(ConfigFileParserTests, VerifyIsArray) 3009 { 3010 // Test where element is an array 3011 try 3012 { 3013 const json element = R"( [ "foo", "bar" ] )"_json; 3014 verifyIsArray(element); 3015 } 3016 catch (const std::exception& e) 3017 { 3018 ADD_FAILURE() << "Should not have caught exception."; 3019 } 3020 3021 // Test where element is not an array 3022 try 3023 { 3024 const json element = R"( { "foo": "bar" } )"_json; 3025 verifyIsArray(element); 3026 ADD_FAILURE() << "Should not have reached this line."; 3027 } 3028 catch (const std::invalid_argument& e) 3029 { 3030 EXPECT_STREQ(e.what(), "Element is not an array"); 3031 } 3032 } 3033 3034 TEST(ConfigFileParserTests, VerifyIsObject) 3035 { 3036 // Test where element is an object 3037 try 3038 { 3039 const json element = R"( { "foo": "bar" } )"_json; 3040 verifyIsObject(element); 3041 } 3042 catch (const std::exception& e) 3043 { 3044 ADD_FAILURE() << "Should not have caught exception."; 3045 } 3046 3047 // Test where element is not an object 3048 try 3049 { 3050 const json element = R"( [ "foo", "bar" ] )"_json; 3051 verifyIsObject(element); 3052 ADD_FAILURE() << "Should not have reached this line."; 3053 } 3054 catch (const std::invalid_argument& e) 3055 { 3056 EXPECT_STREQ(e.what(), "Element is not an object"); 3057 } 3058 } 3059 3060 TEST(ConfigFileParserTests, VerifyPropertyCount) 3061 { 3062 // Test where element has expected number of properties 3063 try 3064 { 3065 const json element = R"( 3066 { 3067 "comments": [ "Set voltage rule" ], 3068 "id": "set_voltage_rule" 3069 } 3070 )"_json; 3071 verifyPropertyCount(element, 2); 3072 } 3073 catch (const std::exception& e) 3074 { 3075 ADD_FAILURE() << "Should not have caught exception."; 3076 } 3077 3078 // Test where element has unexpected number of properties 3079 try 3080 { 3081 const json element = R"( 3082 { 3083 "comments": [ "Set voltage rule" ], 3084 "id": "set_voltage_rule", 3085 "foo": 1.3 3086 } 3087 )"_json; 3088 verifyPropertyCount(element, 2); 3089 ADD_FAILURE() << "Should not have reached this line."; 3090 } 3091 catch (const std::invalid_argument& e) 3092 { 3093 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3094 } 3095 } 3096