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