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(action->getFRU(), "/system/chassis/motherboard/cpu3"); 944 EXPECT_EQ(action->getValue(), true); 945 } 946 947 // Test where fails: Element is not an object 948 try 949 { 950 const json element = R"( [ "0xFF", "0x01" ] )"_json; 951 parseComparePresence(element); 952 ADD_FAILURE() << "Should not have reached this line."; 953 } 954 catch (const std::invalid_argument& e) 955 { 956 EXPECT_STREQ(e.what(), "Element is not an object"); 957 } 958 959 // Test where fails: Invalid property specified 960 try 961 { 962 const json element = R"( 963 { 964 "fru": "/system/chassis/motherboard/cpu3", 965 "value": true, 966 "foo" : true 967 } 968 )"_json; 969 parseComparePresence(element); 970 ADD_FAILURE() << "Should not have reached this line."; 971 } 972 catch (const std::invalid_argument& e) 973 { 974 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 975 } 976 977 // Test where fails: Required fru property not specified 978 try 979 { 980 const json element = R"( 981 { 982 "value": true 983 } 984 )"_json; 985 parseComparePresence(element); 986 ADD_FAILURE() << "Should not have reached this line."; 987 } 988 catch (const std::invalid_argument& e) 989 { 990 EXPECT_STREQ(e.what(), "Required property missing: fru"); 991 } 992 993 // Test where fails: Required value property not specified 994 try 995 { 996 const json element = R"( 997 { 998 "fru": "/system/chassis/motherboard/cpu3" 999 } 1000 )"_json; 1001 parseComparePresence(element); 1002 ADD_FAILURE() << "Should not have reached this line."; 1003 } 1004 catch (const std::invalid_argument& e) 1005 { 1006 EXPECT_STREQ(e.what(), "Required property missing: value"); 1007 } 1008 1009 // Test where fails: fru value is invalid 1010 try 1011 { 1012 const json element = R"( 1013 { 1014 "fru": 1, 1015 "value": true 1016 } 1017 )"_json; 1018 parseComparePresence(element); 1019 ADD_FAILURE() << "Should not have reached this line."; 1020 } 1021 catch (const std::invalid_argument& e) 1022 { 1023 EXPECT_STREQ(e.what(), "Element is not a string"); 1024 } 1025 1026 // Test where fails: value value is invalid 1027 try 1028 { 1029 const json element = R"( 1030 { 1031 "fru": "/system/chassis/motherboard/cpu3", 1032 "value": 1 1033 } 1034 )"_json; 1035 parseComparePresence(element); 1036 ADD_FAILURE() << "Should not have reached this line."; 1037 } 1038 catch (const std::invalid_argument& e) 1039 { 1040 EXPECT_STREQ(e.what(), "Element is not a boolean"); 1041 } 1042 } 1043 1044 TEST(ConfigFileParserTests, ParseCompareVPD) 1045 { 1046 // Test where works 1047 { 1048 const json element = R"( 1049 { 1050 "fru": "/system/chassis/disk_backplane", 1051 "keyword": "CCIN", 1052 "value": "2D35" 1053 } 1054 )"_json; 1055 std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element); 1056 EXPECT_EQ(action->getFRU(), "/system/chassis/disk_backplane"); 1057 EXPECT_EQ(action->getKeyword(), "CCIN"); 1058 EXPECT_EQ(action->getValue(), "2D35"); 1059 } 1060 1061 // Test where fails: Element is not an object 1062 try 1063 { 1064 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1065 parseCompareVPD(element); 1066 ADD_FAILURE() << "Should not have reached this line."; 1067 } 1068 catch (const std::invalid_argument& e) 1069 { 1070 EXPECT_STREQ(e.what(), "Element is not an object"); 1071 } 1072 1073 // Test where fails: Invalid property specified 1074 try 1075 { 1076 const json element = R"( 1077 { 1078 "fru": "/system/chassis/disk_backplane", 1079 "keyword": "CCIN", 1080 "value": "2D35", 1081 "foo" : true 1082 } 1083 )"_json; 1084 parseCompareVPD(element); 1085 ADD_FAILURE() << "Should not have reached this line."; 1086 } 1087 catch (const std::invalid_argument& e) 1088 { 1089 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1090 } 1091 1092 // Test where fails: Required fru property not specified 1093 try 1094 { 1095 const json element = R"( 1096 { 1097 "keyword": "CCIN", 1098 "value": "2D35" 1099 } 1100 )"_json; 1101 parseCompareVPD(element); 1102 ADD_FAILURE() << "Should not have reached this line."; 1103 } 1104 catch (const std::invalid_argument& e) 1105 { 1106 EXPECT_STREQ(e.what(), "Required property missing: fru"); 1107 } 1108 1109 // Test where fails: Required keyword property not specified 1110 try 1111 { 1112 const json element = R"( 1113 { 1114 "fru": "/system/chassis/disk_backplane", 1115 "value": "2D35" 1116 } 1117 )"_json; 1118 parseCompareVPD(element); 1119 ADD_FAILURE() << "Should not have reached this line."; 1120 } 1121 catch (const std::invalid_argument& e) 1122 { 1123 EXPECT_STREQ(e.what(), "Required property missing: keyword"); 1124 } 1125 1126 // Test where fails: Required value property not specified 1127 try 1128 { 1129 const json element = R"( 1130 { 1131 "fru": "/system/chassis/disk_backplane", 1132 "keyword": "CCIN" 1133 } 1134 )"_json; 1135 parseCompareVPD(element); 1136 ADD_FAILURE() << "Should not have reached this line."; 1137 } 1138 catch (const std::invalid_argument& e) 1139 { 1140 EXPECT_STREQ(e.what(), "Required property missing: value"); 1141 } 1142 1143 // Test where fails: fru value is invalid 1144 try 1145 { 1146 const json element = R"( 1147 { 1148 "fru": 1, 1149 "keyword": "CCIN", 1150 "value": "2D35" 1151 } 1152 )"_json; 1153 parseCompareVPD(element); 1154 ADD_FAILURE() << "Should not have reached this line."; 1155 } 1156 catch (const std::invalid_argument& e) 1157 { 1158 EXPECT_STREQ(e.what(), "Element is not a string"); 1159 } 1160 1161 // Test where fails: keyword value is invalid 1162 try 1163 { 1164 const json element = R"( 1165 { 1166 "fru": "/system/chassis/disk_backplane", 1167 "keyword": 1, 1168 "value": "2D35" 1169 } 1170 )"_json; 1171 parseCompareVPD(element); 1172 ADD_FAILURE() << "Should not have reached this line."; 1173 } 1174 catch (const std::invalid_argument& e) 1175 { 1176 EXPECT_STREQ(e.what(), "Element is not a string"); 1177 } 1178 1179 // Test where fails: value value is invalid 1180 try 1181 { 1182 const json element = R"( 1183 { 1184 "fru": "/system/chassis/disk_backplane", 1185 "keyword": "CCIN", 1186 "value": 1 1187 } 1188 )"_json; 1189 parseCompareVPD(element); 1190 ADD_FAILURE() << "Should not have reached this line."; 1191 } 1192 catch (const std::invalid_argument& e) 1193 { 1194 EXPECT_STREQ(e.what(), "Element is not a string"); 1195 } 1196 } 1197 1198 TEST(ConfigFileParserTests, ParseConfiguration) 1199 { 1200 // Test where works: actions required property specified 1201 { 1202 const json element = R"( 1203 { 1204 "actions": [ 1205 { 1206 "pmbus_write_vout_command": { 1207 "format": "linear" 1208 } 1209 } 1210 ] 1211 } 1212 )"_json; 1213 std::unique_ptr<Configuration> configuration = 1214 parseConfiguration(element); 1215 EXPECT_EQ(configuration->getActions().size(), 1); 1216 EXPECT_EQ(configuration->getVolts().has_value(), false); 1217 } 1218 1219 // Test where works: volts and actions properties specified 1220 { 1221 const json element = R"( 1222 { 1223 "comments": [ "comments property" ], 1224 "volts": 1.03, 1225 "actions": [ 1226 { "pmbus_write_vout_command": { "format": "linear" } }, 1227 { "run_rule": "set_voltage_rule" } 1228 ] 1229 } 1230 )"_json; 1231 std::unique_ptr<Configuration> configuration = 1232 parseConfiguration(element); 1233 EXPECT_EQ(configuration->getVolts().has_value(), true); 1234 EXPECT_EQ(configuration->getVolts().value(), 1.03); 1235 EXPECT_EQ(configuration->getActions().size(), 2); 1236 } 1237 1238 // Test where works: volts and rule_id properties specified 1239 { 1240 const json element = R"( 1241 { 1242 "volts": 1.05, 1243 "rule_id": "set_voltage_rule" 1244 } 1245 )"_json; 1246 std::unique_ptr<Configuration> configuration = 1247 parseConfiguration(element); 1248 EXPECT_EQ(configuration->getVolts().has_value(), true); 1249 EXPECT_EQ(configuration->getVolts().value(), 1.05); 1250 EXPECT_EQ(configuration->getActions().size(), 1); 1251 } 1252 1253 // Test where fails: volts value is invalid 1254 try 1255 { 1256 const json element = R"( 1257 { 1258 "volts": "foo", 1259 "actions": [ 1260 { 1261 "pmbus_write_vout_command": { 1262 "format": "linear" 1263 } 1264 } 1265 ] 1266 } 1267 )"_json; 1268 parseConfiguration(element); 1269 ADD_FAILURE() << "Should not have reached this line."; 1270 } 1271 catch (const std::invalid_argument& e) 1272 { 1273 EXPECT_STREQ(e.what(), "Element is not a number"); 1274 } 1275 1276 // Test where fails: actions object is invalid 1277 try 1278 { 1279 const json element = R"( 1280 { 1281 "volts": 1.03, 1282 "actions": 1 1283 } 1284 )"_json; 1285 parseConfiguration(element); 1286 ADD_FAILURE() << "Should not have reached this line."; 1287 } 1288 catch (const std::invalid_argument& e) 1289 { 1290 EXPECT_STREQ(e.what(), "Element is not an array"); 1291 } 1292 1293 // Test where fails: rule_id value is invalid 1294 try 1295 { 1296 const json element = R"( 1297 { 1298 "volts": 1.05, 1299 "rule_id": 1 1300 } 1301 )"_json; 1302 parseConfiguration(element); 1303 ADD_FAILURE() << "Should not have reached this line."; 1304 } 1305 catch (const std::invalid_argument& e) 1306 { 1307 EXPECT_STREQ(e.what(), "Element is not a string"); 1308 } 1309 1310 // Test where fails: Required actions or rule_id property not specified 1311 try 1312 { 1313 const json element = R"( 1314 { 1315 "volts": 1.03 1316 } 1317 )"_json; 1318 parseConfiguration(element); 1319 ADD_FAILURE() << "Should not have reached this line."; 1320 } 1321 catch (const std::invalid_argument& e) 1322 { 1323 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 1324 "either rule_id or actions"); 1325 } 1326 1327 // Test where fails: Required actions or rule_id property both specified 1328 try 1329 { 1330 const json element = R"( 1331 { 1332 "volts": 1.03, 1333 "rule_id": "set_voltage_rule", 1334 "actions": [ 1335 { 1336 "pmbus_write_vout_command": { 1337 "format": "linear" 1338 } 1339 } 1340 ] 1341 } 1342 )"_json; 1343 parseConfiguration(element); 1344 ADD_FAILURE() << "Should not have reached this line."; 1345 } 1346 catch (const std::invalid_argument& e) 1347 { 1348 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 1349 "either rule_id or actions"); 1350 } 1351 1352 // Test where fails: Element is not an object 1353 try 1354 { 1355 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1356 parseConfiguration(element); 1357 ADD_FAILURE() << "Should not have reached this line."; 1358 } 1359 catch (const std::invalid_argument& e) 1360 { 1361 EXPECT_STREQ(e.what(), "Element is not an object"); 1362 } 1363 1364 // Test where fails: Invalid property specified 1365 try 1366 { 1367 const json element = R"( 1368 { 1369 "volts": 1.03, 1370 "rule_id": "set_voltage_rule", 1371 "foo": 1 1372 } 1373 )"_json; 1374 parseConfiguration(element); 1375 ADD_FAILURE() << "Should not have reached this line."; 1376 } 1377 catch (const std::invalid_argument& e) 1378 { 1379 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1380 } 1381 } 1382 1383 TEST(ConfigFileParserTests, ParseDevice) 1384 { 1385 // Test where works: Only required properties specified 1386 { 1387 const json element = R"( 1388 { 1389 "id": "vdd_regulator", 1390 "is_regulator": true, 1391 "fru": "/system/chassis/motherboard/regulator2", 1392 "i2c_interface": { "bus": 1, "address": "0x70" } 1393 } 1394 )"_json; 1395 std::unique_ptr<Device> device = parseDevice(element); 1396 EXPECT_EQ(device->getID(), "vdd_regulator"); 1397 EXPECT_EQ(device->isRegulator(), true); 1398 EXPECT_EQ(device->getFRU(), "/system/chassis/motherboard/regulator2"); 1399 EXPECT_NE(&(device->getI2CInterface()), nullptr); 1400 EXPECT_EQ(device->getPresenceDetection(), nullptr); 1401 EXPECT_EQ(device->getConfiguration(), nullptr); 1402 EXPECT_EQ(device->getRails().size(), 0); 1403 } 1404 1405 // Test where works: All properties specified 1406 { 1407 const json element = R"( 1408 { 1409 "id": "vdd_regulator", 1410 "is_regulator": true, 1411 "fru": "/system/chassis/motherboard/regulator2", 1412 "i2c_interface": 1413 { 1414 "bus": 1, 1415 "address": "0x70" 1416 }, 1417 "configuration": 1418 { 1419 "rule_id": "configure_ir35221_rule" 1420 }, 1421 "presence_detection": 1422 { 1423 "rule_id": "is_foobar_backplane_installed_rule" 1424 }, 1425 "rails": 1426 [ 1427 { 1428 "id": "vdd" 1429 } 1430 ] 1431 } 1432 )"_json; 1433 std::unique_ptr<Device> device = parseDevice(element); 1434 EXPECT_EQ(device->getID(), "vdd_regulator"); 1435 EXPECT_EQ(device->isRegulator(), true); 1436 EXPECT_EQ(device->getFRU(), "/system/chassis/motherboard/regulator2"); 1437 EXPECT_NE(&(device->getI2CInterface()), nullptr); 1438 EXPECT_NE(device->getPresenceDetection(), nullptr); 1439 EXPECT_NE(device->getConfiguration(), nullptr); 1440 EXPECT_EQ(device->getRails().size(), 1); 1441 } 1442 1443 // Test where fails: rails property exists and is_regulator is false 1444 try 1445 { 1446 const json element = R"( 1447 { 1448 "id": "vdd_regulator", 1449 "is_regulator": false, 1450 "fru": "/system/chassis/motherboard/regulator2", 1451 "i2c_interface": 1452 { 1453 "bus": 1, 1454 "address": "0x70" 1455 }, 1456 "configuration": 1457 { 1458 "rule_id": "configure_ir35221_rule" 1459 }, 1460 "rails": 1461 [ 1462 { 1463 "id": "vdd" 1464 } 1465 ] 1466 } 1467 )"_json; 1468 parseDevice(element); 1469 ADD_FAILURE() << "Should not have reached this line."; 1470 } 1471 catch (const std::invalid_argument& e) 1472 { 1473 EXPECT_STREQ(e.what(), 1474 "Invalid rails property when is_regulator is false"); 1475 } 1476 1477 // Test where fails: id value is invalid 1478 try 1479 { 1480 const json element = R"( 1481 { 1482 "id": 3, 1483 "is_regulator": true, 1484 "fru": "/system/chassis/motherboard/regulator2", 1485 "i2c_interface": 1486 { 1487 "bus": 1, 1488 "address": "0x70" 1489 } 1490 } 1491 )"_json; 1492 parseDevice(element); 1493 ADD_FAILURE() << "Should not have reached this line."; 1494 } 1495 catch (const std::invalid_argument& e) 1496 { 1497 EXPECT_STREQ(e.what(), "Element is not a string"); 1498 } 1499 1500 // Test where fails: is_regulator value is invalid 1501 try 1502 { 1503 const json element = R"( 1504 { 1505 "id": "vdd_regulator", 1506 "is_regulator": 3, 1507 "fru": "/system/chassis/motherboard/regulator2", 1508 "i2c_interface": 1509 { 1510 "bus": 1, 1511 "address": "0x70" 1512 } 1513 } 1514 )"_json; 1515 parseDevice(element); 1516 ADD_FAILURE() << "Should not have reached this line."; 1517 } 1518 catch (const std::invalid_argument& e) 1519 { 1520 EXPECT_STREQ(e.what(), "Element is not a boolean"); 1521 } 1522 1523 // Test where fails: fru value is invalid 1524 try 1525 { 1526 const json element = R"( 1527 { 1528 "id": "vdd_regulator", 1529 "is_regulator": true, 1530 "fru": 2, 1531 "i2c_interface": 1532 { 1533 "bus": 1, 1534 "address": "0x70" 1535 } 1536 } 1537 )"_json; 1538 parseDevice(element); 1539 ADD_FAILURE() << "Should not have reached this line."; 1540 } 1541 catch (const std::invalid_argument& e) 1542 { 1543 EXPECT_STREQ(e.what(), "Element is not a string"); 1544 } 1545 1546 // Test where fails: i2c_interface value is invalid 1547 try 1548 { 1549 const json element = R"( 1550 { 1551 "id": "vdd_regulator", 1552 "is_regulator": true, 1553 "fru": "/system/chassis/motherboard/regulator2", 1554 "i2c_interface": 3 1555 } 1556 )"_json; 1557 parseDevice(element); 1558 ADD_FAILURE() << "Should not have reached this line."; 1559 } 1560 catch (const std::invalid_argument& e) 1561 { 1562 EXPECT_STREQ(e.what(), "Element is not an object"); 1563 } 1564 1565 // Test where fails: Required id property not specified 1566 try 1567 { 1568 const json element = R"( 1569 { 1570 "is_regulator": true, 1571 "fru": "/system/chassis/motherboard/regulator2", 1572 "i2c_interface": 1573 { 1574 "bus": 1, 1575 "address": "0x70" 1576 } 1577 } 1578 )"_json; 1579 parseDevice(element); 1580 ADD_FAILURE() << "Should not have reached this line."; 1581 } 1582 catch (const std::invalid_argument& e) 1583 { 1584 EXPECT_STREQ(e.what(), "Required property missing: id"); 1585 } 1586 1587 // Test where fails: Required is_regulator property not specified 1588 try 1589 { 1590 const json element = R"( 1591 { 1592 "id": "vdd_regulator", 1593 "fru": "/system/chassis/motherboard/regulator2", 1594 "i2c_interface": 1595 { 1596 "bus": 1, 1597 "address": "0x70" 1598 } 1599 } 1600 )"_json; 1601 parseDevice(element); 1602 ADD_FAILURE() << "Should not have reached this line."; 1603 } 1604 catch (const std::invalid_argument& e) 1605 { 1606 EXPECT_STREQ(e.what(), "Required property missing: is_regulator"); 1607 } 1608 1609 // Test where fails: Required fru property not specified 1610 try 1611 { 1612 const json element = R"( 1613 { 1614 "id": "vdd_regulator", 1615 "is_regulator": true, 1616 "i2c_interface": 1617 { 1618 "bus": 1, 1619 "address": "0x70" 1620 } 1621 } 1622 )"_json; 1623 parseDevice(element); 1624 ADD_FAILURE() << "Should not have reached this line."; 1625 } 1626 catch (const std::invalid_argument& e) 1627 { 1628 EXPECT_STREQ(e.what(), "Required property missing: fru"); 1629 } 1630 1631 // Test where fails: Required i2c_interface property not specified 1632 try 1633 { 1634 const json element = R"( 1635 { 1636 "id": "vdd_regulator", 1637 "is_regulator": true, 1638 "fru": "/system/chassis/motherboard/regulator2" 1639 } 1640 )"_json; 1641 parseDevice(element); 1642 ADD_FAILURE() << "Should not have reached this line."; 1643 } 1644 catch (const std::invalid_argument& e) 1645 { 1646 EXPECT_STREQ(e.what(), "Required property missing: i2c_interface"); 1647 } 1648 1649 // Test where fails: Element is not an object 1650 try 1651 { 1652 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1653 parseDevice(element); 1654 ADD_FAILURE() << "Should not have reached this line."; 1655 } 1656 catch (const std::invalid_argument& e) 1657 { 1658 EXPECT_STREQ(e.what(), "Element is not an object"); 1659 } 1660 1661 // Test where fails: Invalid property specified 1662 try 1663 { 1664 const json element = R"( 1665 { 1666 "id": "vdd_regulator", 1667 "is_regulator": true, 1668 "fru": "/system/chassis/motherboard/regulator2", 1669 "i2c_interface": { "bus": 1, "address": "0x70" }, 1670 "foo" : true 1671 } 1672 )"_json; 1673 parseDevice(element); 1674 ADD_FAILURE() << "Should not have reached this line."; 1675 } 1676 catch (const std::invalid_argument& e) 1677 { 1678 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1679 } 1680 } 1681 1682 TEST(ConfigFileParserTests, ParseDeviceArray) 1683 { 1684 // Test where works 1685 { 1686 const json element = R"( 1687 [ 1688 { 1689 "id": "vdd_regulator", 1690 "is_regulator": true, 1691 "fru": "/system/chassis/motherboard/regulator2", 1692 "i2c_interface": { "bus": 1, "address": "0x70" } 1693 }, 1694 { 1695 "id": "vio_regulator", 1696 "is_regulator": true, 1697 "fru": "/system/chassis/motherboard/regulator2", 1698 "i2c_interface": { "bus": 1, "address": "0x71" } 1699 } 1700 ] 1701 )"_json; 1702 std::vector<std::unique_ptr<Device>> devices = 1703 parseDeviceArray(element); 1704 EXPECT_EQ(devices.size(), 2); 1705 EXPECT_EQ(devices[0]->getID(), "vdd_regulator"); 1706 EXPECT_EQ(devices[1]->getID(), "vio_regulator"); 1707 } 1708 1709 // Test where fails: Element is not an array 1710 try 1711 { 1712 const json element = R"( 1713 { 1714 "foo": "bar" 1715 } 1716 )"_json; 1717 parseDeviceArray(element); 1718 ADD_FAILURE() << "Should not have reached this line."; 1719 } 1720 catch (const std::invalid_argument& e) 1721 { 1722 EXPECT_STREQ(e.what(), "Element is not an array"); 1723 } 1724 } 1725 1726 TEST(ConfigFileParserTests, ParseDouble) 1727 { 1728 // Test where works: floating point value 1729 { 1730 const json element = R"( 1.03 )"_json; 1731 double value = parseDouble(element); 1732 EXPECT_EQ(value, 1.03); 1733 } 1734 1735 // Test where works: integer value 1736 { 1737 const json element = R"( 24 )"_json; 1738 double value = parseDouble(element); 1739 EXPECT_EQ(value, 24.0); 1740 } 1741 1742 // Test where fails: Element is not a number 1743 try 1744 { 1745 const json element = R"( true )"_json; 1746 parseDouble(element); 1747 ADD_FAILURE() << "Should not have reached this line."; 1748 } 1749 catch (const std::invalid_argument& e) 1750 { 1751 EXPECT_STREQ(e.what(), "Element is not a number"); 1752 } 1753 } 1754 1755 TEST(ConfigFileParserTests, ParseHexByte) 1756 { 1757 // Test where works: "0xFF" 1758 { 1759 const json element = R"( "0xFF" )"_json; 1760 uint8_t value = parseHexByte(element); 1761 EXPECT_EQ(value, 0xFF); 1762 } 1763 1764 // Test where works: "0xff" 1765 { 1766 const json element = R"( "0xff" )"_json; 1767 uint8_t value = parseHexByte(element); 1768 EXPECT_EQ(value, 0xff); 1769 } 1770 1771 // Test where works: "0xf" 1772 { 1773 const json element = R"( "0xf" )"_json; 1774 uint8_t value = parseHexByte(element); 1775 EXPECT_EQ(value, 0xf); 1776 } 1777 1778 // Test where fails: "0xfff" 1779 try 1780 { 1781 const json element = R"( "0xfff" )"_json; 1782 parseHexByte(element); 1783 ADD_FAILURE() << "Should not have reached this line."; 1784 } 1785 catch (const std::invalid_argument& e) 1786 { 1787 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1788 } 1789 1790 // Test where fails: "0xAG" 1791 try 1792 { 1793 const json element = R"( "0xAG" )"_json; 1794 parseHexByte(element); 1795 ADD_FAILURE() << "Should not have reached this line."; 1796 } 1797 catch (const std::invalid_argument& e) 1798 { 1799 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1800 } 1801 1802 // Test where fails: "ff" 1803 try 1804 { 1805 const json element = R"( "ff" )"_json; 1806 parseHexByte(element); 1807 ADD_FAILURE() << "Should not have reached this line."; 1808 } 1809 catch (const std::invalid_argument& e) 1810 { 1811 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1812 } 1813 1814 // Test where fails: "" 1815 try 1816 { 1817 const json element = ""; 1818 parseHexByte(element); 1819 ADD_FAILURE() << "Should not have reached this line."; 1820 } 1821 catch (const std::invalid_argument& e) 1822 { 1823 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1824 } 1825 1826 // Test where fails: "f" 1827 try 1828 { 1829 const json element = R"( "f" )"_json; 1830 parseHexByte(element); 1831 ADD_FAILURE() << "Should not have reached this line."; 1832 } 1833 catch (const std::invalid_argument& e) 1834 { 1835 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1836 } 1837 1838 // Test where fails: "0x" 1839 try 1840 { 1841 const json element = R"( "0x" )"_json; 1842 parseHexByte(element); 1843 ADD_FAILURE() << "Should not have reached this line."; 1844 } 1845 catch (const std::invalid_argument& e) 1846 { 1847 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1848 } 1849 1850 // Test where fails: "0Xff" 1851 try 1852 { 1853 const json element = R"( "0XFF" )"_json; 1854 parseHexByte(element); 1855 ADD_FAILURE() << "Should not have reached this line."; 1856 } 1857 catch (const std::invalid_argument& e) 1858 { 1859 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1860 } 1861 } 1862 1863 TEST(ConfigFileParserTests, ParseHexByteArray) 1864 { 1865 // Test where works 1866 { 1867 const json element = R"( [ "0xCC", "0xFF" ] )"_json; 1868 std::vector<uint8_t> hexBytes = parseHexByteArray(element); 1869 std::vector<uint8_t> expected = {0xcc, 0xff}; 1870 EXPECT_EQ(hexBytes, expected); 1871 } 1872 1873 // Test where fails: Element is not an array 1874 try 1875 { 1876 const json element = 0; 1877 parseHexByteArray(element); 1878 ADD_FAILURE() << "Should not have reached this line."; 1879 } 1880 catch (const std::invalid_argument& e) 1881 { 1882 EXPECT_STREQ(e.what(), "Element is not an array"); 1883 } 1884 } 1885 1886 TEST(ConfigFileParserTests, ParseI2CCompareBit) 1887 { 1888 // Test where works 1889 { 1890 const json element = R"( 1891 { 1892 "register": "0xA0", 1893 "position": 3, 1894 "value": 0 1895 } 1896 )"_json; 1897 std::unique_ptr<I2CCompareBitAction> action = 1898 parseI2CCompareBit(element); 1899 EXPECT_EQ(action->getRegister(), 0xA0); 1900 EXPECT_EQ(action->getPosition(), 3); 1901 EXPECT_EQ(action->getValue(), 0); 1902 } 1903 1904 // Test where fails: Invalid property specified 1905 try 1906 { 1907 const json element = R"( 1908 { 1909 "register": "0xA0", 1910 "position": 3, 1911 "value": 0, 1912 "foo": 3 1913 } 1914 )"_json; 1915 parseI2CCompareBit(element); 1916 ADD_FAILURE() << "Should not have reached this line."; 1917 } 1918 catch (const std::invalid_argument& e) 1919 { 1920 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1921 } 1922 1923 // Test where fails: Element is not an object 1924 try 1925 { 1926 const json element = R"( [ "0xFF", "0x01" ] )"_json; 1927 parseI2CCompareBit(element); 1928 ADD_FAILURE() << "Should not have reached this line."; 1929 } 1930 catch (const std::invalid_argument& e) 1931 { 1932 EXPECT_STREQ(e.what(), "Element is not an object"); 1933 } 1934 1935 // Test where fails: register value is invalid 1936 try 1937 { 1938 const json element = R"( 1939 { 1940 "register": "0xAG", 1941 "position": 3, 1942 "value": 0 1943 } 1944 )"_json; 1945 parseI2CCompareBit(element); 1946 ADD_FAILURE() << "Should not have reached this line."; 1947 } 1948 catch (const std::invalid_argument& e) 1949 { 1950 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 1951 } 1952 1953 // Test where fails: position value is invalid 1954 try 1955 { 1956 const json element = R"( 1957 { 1958 "register": "0xA0", 1959 "position": 8, 1960 "value": 0 1961 } 1962 )"_json; 1963 parseI2CCompareBit(element); 1964 ADD_FAILURE() << "Should not have reached this line."; 1965 } 1966 catch (const std::invalid_argument& e) 1967 { 1968 EXPECT_STREQ(e.what(), "Element is not a bit position"); 1969 } 1970 1971 // Test where fails: value value is invalid 1972 try 1973 { 1974 const json element = R"( 1975 { 1976 "register": "0xA0", 1977 "position": 3, 1978 "value": 2 1979 } 1980 )"_json; 1981 parseI2CCompareBit(element); 1982 ADD_FAILURE() << "Should not have reached this line."; 1983 } 1984 catch (const std::invalid_argument& e) 1985 { 1986 EXPECT_STREQ(e.what(), "Element is not a bit value"); 1987 } 1988 1989 // Test where fails: Required register property not specified 1990 try 1991 { 1992 const json element = R"( 1993 { 1994 "position": 3, 1995 "value": 0 1996 } 1997 )"_json; 1998 parseI2CCompareBit(element); 1999 ADD_FAILURE() << "Should not have reached this line."; 2000 } 2001 catch (const std::invalid_argument& e) 2002 { 2003 EXPECT_STREQ(e.what(), "Required property missing: register"); 2004 } 2005 2006 // Test where fails: Required position property not specified 2007 try 2008 { 2009 const json element = R"( 2010 { 2011 "register": "0xA0", 2012 "value": 0 2013 } 2014 )"_json; 2015 parseI2CCompareBit(element); 2016 ADD_FAILURE() << "Should not have reached this line."; 2017 } 2018 catch (const std::invalid_argument& e) 2019 { 2020 EXPECT_STREQ(e.what(), "Required property missing: position"); 2021 } 2022 2023 // Test where fails: Required value property not specified 2024 try 2025 { 2026 const json element = R"( 2027 { 2028 "register": "0xA0", 2029 "position": 3 2030 } 2031 )"_json; 2032 parseI2CCompareBit(element); 2033 ADD_FAILURE() << "Should not have reached this line."; 2034 } 2035 catch (const std::invalid_argument& e) 2036 { 2037 EXPECT_STREQ(e.what(), "Required property missing: value"); 2038 } 2039 } 2040 2041 TEST(ConfigFileParserTests, ParseI2CCompareByte) 2042 { 2043 // Test where works: Only required properties specified 2044 { 2045 const json element = R"( 2046 { 2047 "register": "0x0A", 2048 "value": "0xCC" 2049 } 2050 )"_json; 2051 std::unique_ptr<I2CCompareByteAction> action = 2052 parseI2CCompareByte(element); 2053 EXPECT_EQ(action->getRegister(), 0x0A); 2054 EXPECT_EQ(action->getValue(), 0xCC); 2055 EXPECT_EQ(action->getMask(), 0xFF); 2056 } 2057 2058 // Test where works: All properties specified 2059 { 2060 const json element = R"( 2061 { 2062 "register": "0x0A", 2063 "value": "0xCC", 2064 "mask": "0xF7" 2065 } 2066 )"_json; 2067 std::unique_ptr<I2CCompareByteAction> action = 2068 parseI2CCompareByte(element); 2069 EXPECT_EQ(action->getRegister(), 0x0A); 2070 EXPECT_EQ(action->getValue(), 0xCC); 2071 EXPECT_EQ(action->getMask(), 0xF7); 2072 } 2073 2074 // Test where fails: Element is not an object 2075 try 2076 { 2077 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2078 parseI2CCompareByte(element); 2079 ADD_FAILURE() << "Should not have reached this line."; 2080 } 2081 catch (const std::invalid_argument& e) 2082 { 2083 EXPECT_STREQ(e.what(), "Element is not an object"); 2084 } 2085 2086 // Test where fails: Invalid property specified 2087 try 2088 { 2089 const json element = R"( 2090 { 2091 "register": "0x0A", 2092 "value": "0xCC", 2093 "mask": "0xF7", 2094 "foo": 1 2095 } 2096 )"_json; 2097 parseI2CCompareByte(element); 2098 ADD_FAILURE() << "Should not have reached this line."; 2099 } 2100 catch (const std::invalid_argument& e) 2101 { 2102 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2103 } 2104 2105 // Test where fails: register value is invalid 2106 try 2107 { 2108 const json element = R"( 2109 { 2110 "register": "0x0Z", 2111 "value": "0xCC", 2112 "mask": "0xF7" 2113 } 2114 )"_json; 2115 parseI2CCompareByte(element); 2116 ADD_FAILURE() << "Should not have reached this line."; 2117 } 2118 catch (const std::invalid_argument& e) 2119 { 2120 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2121 } 2122 2123 // Test where fails: value value is invalid 2124 try 2125 { 2126 const json element = R"( 2127 { 2128 "register": "0x0A", 2129 "value": "0xCCC", 2130 "mask": "0xF7" 2131 } 2132 )"_json; 2133 parseI2CCompareByte(element); 2134 ADD_FAILURE() << "Should not have reached this line."; 2135 } 2136 catch (const std::invalid_argument& e) 2137 { 2138 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2139 } 2140 2141 // Test where fails: mask value is invalid 2142 try 2143 { 2144 const json element = R"( 2145 { 2146 "register": "0x0A", 2147 "value": "0xCC", 2148 "mask": "F7" 2149 } 2150 )"_json; 2151 parseI2CCompareByte(element); 2152 ADD_FAILURE() << "Should not have reached this line."; 2153 } 2154 catch (const std::invalid_argument& e) 2155 { 2156 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2157 } 2158 2159 // Test where fails: Required register property not specified 2160 try 2161 { 2162 const json element = R"( 2163 { 2164 "value": "0xCC", 2165 "mask": "0xF7" 2166 } 2167 )"_json; 2168 parseI2CCompareByte(element); 2169 ADD_FAILURE() << "Should not have reached this line."; 2170 } 2171 catch (const std::invalid_argument& e) 2172 { 2173 EXPECT_STREQ(e.what(), "Required property missing: register"); 2174 } 2175 2176 // Test where fails: Required value property not specified 2177 try 2178 { 2179 const json element = R"( 2180 { 2181 "register": "0x0A", 2182 "mask": "0xF7" 2183 } 2184 )"_json; 2185 parseI2CCompareByte(element); 2186 ADD_FAILURE() << "Should not have reached this line."; 2187 } 2188 catch (const std::invalid_argument& e) 2189 { 2190 EXPECT_STREQ(e.what(), "Required property missing: value"); 2191 } 2192 } 2193 2194 TEST(ConfigFileParserTests, ParseI2CCompareBytes) 2195 { 2196 // Test where works: Only required properties specified 2197 { 2198 const json element = R"( 2199 { 2200 "register": "0x0A", 2201 "values": [ "0xCC", "0xFF" ] 2202 } 2203 )"_json; 2204 std::unique_ptr<I2CCompareBytesAction> action = 2205 parseI2CCompareBytes(element); 2206 EXPECT_EQ(action->getRegister(), 0x0A); 2207 EXPECT_EQ(action->getValues().size(), 2); 2208 EXPECT_EQ(action->getValues()[0], 0xCC); 2209 EXPECT_EQ(action->getValues()[1], 0xFF); 2210 EXPECT_EQ(action->getMasks().size(), 2); 2211 EXPECT_EQ(action->getMasks()[0], 0xFF); 2212 EXPECT_EQ(action->getMasks()[1], 0xFF); 2213 } 2214 2215 // Test where works: All properties specified 2216 { 2217 const json element = R"( 2218 { 2219 "register": "0x0A", 2220 "values": [ "0xCC", "0xFF" ], 2221 "masks": [ "0x7F", "0x77" ] 2222 } 2223 )"_json; 2224 std::unique_ptr<I2CCompareBytesAction> action = 2225 parseI2CCompareBytes(element); 2226 EXPECT_EQ(action->getRegister(), 0x0A); 2227 EXPECT_EQ(action->getValues().size(), 2); 2228 EXPECT_EQ(action->getValues()[0], 0xCC); 2229 EXPECT_EQ(action->getValues()[1], 0xFF); 2230 EXPECT_EQ(action->getMasks().size(), 2); 2231 EXPECT_EQ(action->getMasks()[0], 0x7F); 2232 EXPECT_EQ(action->getMasks()[1], 0x77); 2233 } 2234 2235 // Test where fails: Element is not an object 2236 try 2237 { 2238 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2239 parseI2CCompareBytes(element); 2240 ADD_FAILURE() << "Should not have reached this line."; 2241 } 2242 catch (const std::invalid_argument& e) 2243 { 2244 EXPECT_STREQ(e.what(), "Element is not an object"); 2245 } 2246 2247 // Test where fails: Invalid property specified 2248 try 2249 { 2250 const json element = R"( 2251 { 2252 "register": "0x0A", 2253 "values": [ "0xCC", "0xFF" ], 2254 "masks": [ "0x7F", "0x7F" ], 2255 "foo": 1 2256 } 2257 )"_json; 2258 parseI2CCompareBytes(element); 2259 ADD_FAILURE() << "Should not have reached this line."; 2260 } 2261 catch (const std::invalid_argument& e) 2262 { 2263 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2264 } 2265 2266 // Test where fails: register value is invalid 2267 try 2268 { 2269 const json element = R"( 2270 { 2271 "register": "0x0Z", 2272 "values": [ "0xCC", "0xFF" ], 2273 "masks": [ "0x7F", "0x7F" ] 2274 } 2275 )"_json; 2276 parseI2CCompareBytes(element); 2277 ADD_FAILURE() << "Should not have reached this line."; 2278 } 2279 catch (const std::invalid_argument& e) 2280 { 2281 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2282 } 2283 2284 // Test where fails: values value is invalid 2285 try 2286 { 2287 const json element = R"( 2288 { 2289 "register": "0x0A", 2290 "values": [ "0xCCC", "0xFF" ], 2291 "masks": [ "0x7F", "0x7F" ] 2292 } 2293 )"_json; 2294 parseI2CCompareBytes(element); 2295 ADD_FAILURE() << "Should not have reached this line."; 2296 } 2297 catch (const std::invalid_argument& e) 2298 { 2299 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2300 } 2301 2302 // Test where fails: masks value is invalid 2303 try 2304 { 2305 const json element = R"( 2306 { 2307 "register": "0x0A", 2308 "values": [ "0xCC", "0xFF" ], 2309 "masks": [ "F", "0x7F" ] 2310 } 2311 )"_json; 2312 parseI2CCompareBytes(element); 2313 ADD_FAILURE() << "Should not have reached this line."; 2314 } 2315 catch (const std::invalid_argument& e) 2316 { 2317 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2318 } 2319 2320 // Test where fails: number of elements in masks is invalid 2321 try 2322 { 2323 const json element = R"( 2324 { 2325 "register": "0x0A", 2326 "values": [ "0xCC", "0xFF" ], 2327 "masks": [ "0x7F" ] 2328 } 2329 )"_json; 2330 parseI2CCompareBytes(element); 2331 ADD_FAILURE() << "Should not have reached this line."; 2332 } 2333 catch (const std::invalid_argument& e) 2334 { 2335 EXPECT_STREQ(e.what(), "Invalid number of elements in masks"); 2336 } 2337 2338 // Test where fails: Required register property not specified 2339 try 2340 { 2341 const json element = R"( 2342 { 2343 "values": [ "0xCC", "0xFF" ] 2344 } 2345 )"_json; 2346 parseI2CCompareBytes(element); 2347 ADD_FAILURE() << "Should not have reached this line."; 2348 } 2349 catch (const std::invalid_argument& e) 2350 { 2351 EXPECT_STREQ(e.what(), "Required property missing: register"); 2352 } 2353 2354 // Test where fails: Required values property not specified 2355 try 2356 { 2357 const json element = R"( 2358 { 2359 "register": "0x0A" 2360 } 2361 )"_json; 2362 parseI2CCompareBytes(element); 2363 ADD_FAILURE() << "Should not have reached this line."; 2364 } 2365 catch (const std::invalid_argument& e) 2366 { 2367 EXPECT_STREQ(e.what(), "Required property missing: values"); 2368 } 2369 } 2370 2371 TEST(ConfigFileParserTests, ParseI2CWriteBit) 2372 { 2373 // Test where works 2374 { 2375 const json element = R"( 2376 { 2377 "register": "0xA0", 2378 "position": 3, 2379 "value": 0 2380 } 2381 )"_json; 2382 std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element); 2383 EXPECT_EQ(action->getRegister(), 0xA0); 2384 EXPECT_EQ(action->getPosition(), 3); 2385 EXPECT_EQ(action->getValue(), 0); 2386 } 2387 2388 // Test where fails: Invalid property specified 2389 try 2390 { 2391 const json element = R"( 2392 { 2393 "register": "0xA0", 2394 "position": 3, 2395 "value": 0, 2396 "foo": 3 2397 } 2398 )"_json; 2399 parseI2CWriteBit(element); 2400 ADD_FAILURE() << "Should not have reached this line."; 2401 } 2402 catch (const std::invalid_argument& e) 2403 { 2404 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2405 } 2406 2407 // Test where fails: Element is not an object 2408 try 2409 { 2410 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2411 parseI2CWriteBit(element); 2412 ADD_FAILURE() << "Should not have reached this line."; 2413 } 2414 catch (const std::invalid_argument& e) 2415 { 2416 EXPECT_STREQ(e.what(), "Element is not an object"); 2417 } 2418 2419 // Test where fails: register value is invalid 2420 try 2421 { 2422 const json element = R"( 2423 { 2424 "register": "0xAG", 2425 "position": 3, 2426 "value": 0 2427 } 2428 )"_json; 2429 parseI2CWriteBit(element); 2430 ADD_FAILURE() << "Should not have reached this line."; 2431 } 2432 catch (const std::invalid_argument& e) 2433 { 2434 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2435 } 2436 2437 // Test where fails: position value is invalid 2438 try 2439 { 2440 const json element = R"( 2441 { 2442 "register": "0xA0", 2443 "position": 8, 2444 "value": 0 2445 } 2446 )"_json; 2447 parseI2CWriteBit(element); 2448 ADD_FAILURE() << "Should not have reached this line."; 2449 } 2450 catch (const std::invalid_argument& e) 2451 { 2452 EXPECT_STREQ(e.what(), "Element is not a bit position"); 2453 } 2454 2455 // Test where fails: value value is invalid 2456 try 2457 { 2458 const json element = R"( 2459 { 2460 "register": "0xA0", 2461 "position": 3, 2462 "value": 2 2463 } 2464 )"_json; 2465 parseI2CWriteBit(element); 2466 ADD_FAILURE() << "Should not have reached this line."; 2467 } 2468 catch (const std::invalid_argument& e) 2469 { 2470 EXPECT_STREQ(e.what(), "Element is not a bit value"); 2471 } 2472 2473 // Test where fails: Required register property not specified 2474 try 2475 { 2476 const json element = R"( 2477 { 2478 "position": 3, 2479 "value": 0 2480 } 2481 )"_json; 2482 parseI2CWriteBit(element); 2483 ADD_FAILURE() << "Should not have reached this line."; 2484 } 2485 catch (const std::invalid_argument& e) 2486 { 2487 EXPECT_STREQ(e.what(), "Required property missing: register"); 2488 } 2489 2490 // Test where fails: Required position property not specified 2491 try 2492 { 2493 const json element = R"( 2494 { 2495 "register": "0xA0", 2496 "value": 0 2497 } 2498 )"_json; 2499 parseI2CWriteBit(element); 2500 ADD_FAILURE() << "Should not have reached this line."; 2501 } 2502 catch (const std::invalid_argument& e) 2503 { 2504 EXPECT_STREQ(e.what(), "Required property missing: position"); 2505 } 2506 2507 // Test where fails: Required value property not specified 2508 try 2509 { 2510 const json element = R"( 2511 { 2512 "register": "0xA0", 2513 "position": 3 2514 } 2515 )"_json; 2516 parseI2CWriteBit(element); 2517 ADD_FAILURE() << "Should not have reached this line."; 2518 } 2519 catch (const std::invalid_argument& e) 2520 { 2521 EXPECT_STREQ(e.what(), "Required property missing: value"); 2522 } 2523 } 2524 2525 TEST(ConfigFileParserTests, ParseI2CWriteByte) 2526 { 2527 // Test where works: Only required properties specified 2528 { 2529 const json element = R"( 2530 { 2531 "register": "0x0A", 2532 "value": "0xCC" 2533 } 2534 )"_json; 2535 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element); 2536 EXPECT_EQ(action->getRegister(), 0x0A); 2537 EXPECT_EQ(action->getValue(), 0xCC); 2538 EXPECT_EQ(action->getMask(), 0xFF); 2539 } 2540 2541 // Test where works: All properties specified 2542 { 2543 const json element = R"( 2544 { 2545 "register": "0x0A", 2546 "value": "0xCC", 2547 "mask": "0xF7" 2548 } 2549 )"_json; 2550 std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element); 2551 EXPECT_EQ(action->getRegister(), 0x0A); 2552 EXPECT_EQ(action->getValue(), 0xCC); 2553 EXPECT_EQ(action->getMask(), 0xF7); 2554 } 2555 2556 // Test where fails: Element is not an object 2557 try 2558 { 2559 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2560 parseI2CWriteByte(element); 2561 ADD_FAILURE() << "Should not have reached this line."; 2562 } 2563 catch (const std::invalid_argument& e) 2564 { 2565 EXPECT_STREQ(e.what(), "Element is not an object"); 2566 } 2567 2568 // Test where fails: Invalid property specified 2569 try 2570 { 2571 const json element = R"( 2572 { 2573 "register": "0x0A", 2574 "value": "0xCC", 2575 "mask": "0xF7", 2576 "foo": 1 2577 } 2578 )"_json; 2579 parseI2CWriteByte(element); 2580 ADD_FAILURE() << "Should not have reached this line."; 2581 } 2582 catch (const std::invalid_argument& e) 2583 { 2584 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2585 } 2586 2587 // Test where fails: register value is invalid 2588 try 2589 { 2590 const json element = R"( 2591 { 2592 "register": "0x0Z", 2593 "value": "0xCC", 2594 "mask": "0xF7" 2595 } 2596 )"_json; 2597 parseI2CWriteByte(element); 2598 ADD_FAILURE() << "Should not have reached this line."; 2599 } 2600 catch (const std::invalid_argument& e) 2601 { 2602 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2603 } 2604 2605 // Test where fails: value value is invalid 2606 try 2607 { 2608 const json element = R"( 2609 { 2610 "register": "0x0A", 2611 "value": "0xCCC", 2612 "mask": "0xF7" 2613 } 2614 )"_json; 2615 parseI2CWriteByte(element); 2616 ADD_FAILURE() << "Should not have reached this line."; 2617 } 2618 catch (const std::invalid_argument& e) 2619 { 2620 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2621 } 2622 2623 // Test where fails: mask value is invalid 2624 try 2625 { 2626 const json element = R"( 2627 { 2628 "register": "0x0A", 2629 "value": "0xCC", 2630 "mask": "F7" 2631 } 2632 )"_json; 2633 parseI2CWriteByte(element); 2634 ADD_FAILURE() << "Should not have reached this line."; 2635 } 2636 catch (const std::invalid_argument& e) 2637 { 2638 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2639 } 2640 2641 // Test where fails: Required register property not specified 2642 try 2643 { 2644 const json element = R"( 2645 { 2646 "value": "0xCC", 2647 "mask": "0xF7" 2648 } 2649 )"_json; 2650 parseI2CWriteByte(element); 2651 ADD_FAILURE() << "Should not have reached this line."; 2652 } 2653 catch (const std::invalid_argument& e) 2654 { 2655 EXPECT_STREQ(e.what(), "Required property missing: register"); 2656 } 2657 2658 // Test where fails: Required value property not specified 2659 try 2660 { 2661 const json element = R"( 2662 { 2663 "register": "0x0A", 2664 "mask": "0xF7" 2665 } 2666 )"_json; 2667 parseI2CWriteByte(element); 2668 ADD_FAILURE() << "Should not have reached this line."; 2669 } 2670 catch (const std::invalid_argument& e) 2671 { 2672 EXPECT_STREQ(e.what(), "Required property missing: value"); 2673 } 2674 } 2675 2676 TEST(ConfigFileParserTests, ParseI2CWriteBytes) 2677 { 2678 // Test where works: Only required properties specified 2679 { 2680 const json element = R"( 2681 { 2682 "register": "0x0A", 2683 "values": [ "0xCC", "0xFF" ] 2684 } 2685 )"_json; 2686 std::unique_ptr<I2CWriteBytesAction> action = 2687 parseI2CWriteBytes(element); 2688 EXPECT_EQ(action->getRegister(), 0x0A); 2689 EXPECT_EQ(action->getValues().size(), 2); 2690 EXPECT_EQ(action->getValues()[0], 0xCC); 2691 EXPECT_EQ(action->getValues()[1], 0xFF); 2692 EXPECT_EQ(action->getMasks().size(), 0); 2693 } 2694 2695 // Test where works: All properties specified 2696 { 2697 const json element = R"( 2698 { 2699 "register": "0x0A", 2700 "values": [ "0xCC", "0xFF" ], 2701 "masks": [ "0x7F", "0x77" ] 2702 } 2703 )"_json; 2704 std::unique_ptr<I2CWriteBytesAction> action = 2705 parseI2CWriteBytes(element); 2706 EXPECT_EQ(action->getRegister(), 0x0A); 2707 EXPECT_EQ(action->getValues().size(), 2); 2708 EXPECT_EQ(action->getValues()[0], 0xCC); 2709 EXPECT_EQ(action->getValues()[1], 0xFF); 2710 EXPECT_EQ(action->getMasks().size(), 2); 2711 EXPECT_EQ(action->getMasks()[0], 0x7F); 2712 EXPECT_EQ(action->getMasks()[1], 0x77); 2713 } 2714 2715 // Test where fails: Element is not an object 2716 try 2717 { 2718 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2719 parseI2CWriteBytes(element); 2720 ADD_FAILURE() << "Should not have reached this line."; 2721 } 2722 catch (const std::invalid_argument& e) 2723 { 2724 EXPECT_STREQ(e.what(), "Element is not an object"); 2725 } 2726 2727 // Test where fails: Invalid property specified 2728 try 2729 { 2730 const json element = R"( 2731 { 2732 "register": "0x0A", 2733 "values": [ "0xCC", "0xFF" ], 2734 "masks": [ "0x7F", "0x7F" ], 2735 "foo": 1 2736 } 2737 )"_json; 2738 parseI2CWriteBytes(element); 2739 ADD_FAILURE() << "Should not have reached this line."; 2740 } 2741 catch (const std::invalid_argument& e) 2742 { 2743 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2744 } 2745 2746 // Test where fails: register value is invalid 2747 try 2748 { 2749 const json element = R"( 2750 { 2751 "register": "0x0Z", 2752 "values": [ "0xCC", "0xFF" ], 2753 "masks": [ "0x7F", "0x7F" ] 2754 } 2755 )"_json; 2756 parseI2CWriteBytes(element); 2757 ADD_FAILURE() << "Should not have reached this line."; 2758 } 2759 catch (const std::invalid_argument& e) 2760 { 2761 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2762 } 2763 2764 // Test where fails: values value is invalid 2765 try 2766 { 2767 const json element = R"( 2768 { 2769 "register": "0x0A", 2770 "values": [ "0xCCC", "0xFF" ], 2771 "masks": [ "0x7F", "0x7F" ] 2772 } 2773 )"_json; 2774 parseI2CWriteBytes(element); 2775 ADD_FAILURE() << "Should not have reached this line."; 2776 } 2777 catch (const std::invalid_argument& e) 2778 { 2779 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2780 } 2781 2782 // Test where fails: masks value is invalid 2783 try 2784 { 2785 const json element = R"( 2786 { 2787 "register": "0x0A", 2788 "values": [ "0xCC", "0xFF" ], 2789 "masks": [ "F", "0x7F" ] 2790 } 2791 )"_json; 2792 parseI2CWriteBytes(element); 2793 ADD_FAILURE() << "Should not have reached this line."; 2794 } 2795 catch (const std::invalid_argument& e) 2796 { 2797 EXPECT_STREQ(e.what(), "Element is not hexadecimal string"); 2798 } 2799 2800 // Test where fails: number of elements in masks is invalid 2801 try 2802 { 2803 const json element = R"( 2804 { 2805 "register": "0x0A", 2806 "values": [ "0xCC", "0xFF" ], 2807 "masks": [ "0x7F" ] 2808 } 2809 )"_json; 2810 parseI2CWriteBytes(element); 2811 ADD_FAILURE() << "Should not have reached this line."; 2812 } 2813 catch (const std::invalid_argument& e) 2814 { 2815 EXPECT_STREQ(e.what(), "Invalid number of elements in masks"); 2816 } 2817 2818 // Test where fails: Required register property not specified 2819 try 2820 { 2821 const json element = R"( 2822 { 2823 "values": [ "0xCC", "0xFF" ] 2824 } 2825 )"_json; 2826 parseI2CWriteBytes(element); 2827 ADD_FAILURE() << "Should not have reached this line."; 2828 } 2829 catch (const std::invalid_argument& e) 2830 { 2831 EXPECT_STREQ(e.what(), "Required property missing: register"); 2832 } 2833 2834 // Test where fails: Required values property not specified 2835 try 2836 { 2837 const json element = R"( 2838 { 2839 "register": "0x0A" 2840 } 2841 )"_json; 2842 parseI2CWriteBytes(element); 2843 ADD_FAILURE() << "Should not have reached this line."; 2844 } 2845 catch (const std::invalid_argument& e) 2846 { 2847 EXPECT_STREQ(e.what(), "Required property missing: values"); 2848 } 2849 } 2850 2851 TEST(ConfigFileParserTests, ParseIf) 2852 { 2853 // Test where works: Only required properties specified 2854 { 2855 const json element = R"( 2856 { 2857 "condition": { "run_rule": "is_downlevel_regulator" }, 2858 "then": [ { "run_rule": "configure_downlevel_regulator" }, 2859 { "run_rule": "configure_standard_regulator" } ] 2860 } 2861 )"_json; 2862 std::unique_ptr<IfAction> action = parseIf(element); 2863 EXPECT_NE(action->getConditionAction().get(), nullptr); 2864 EXPECT_EQ(action->getThenActions().size(), 2); 2865 EXPECT_EQ(action->getElseActions().size(), 0); 2866 } 2867 2868 // Test where works: All properties specified 2869 { 2870 const json element = R"( 2871 { 2872 "condition": { "run_rule": "is_downlevel_regulator" }, 2873 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2874 "else": [ { "run_rule": "configure_standard_regulator" } ] 2875 } 2876 )"_json; 2877 std::unique_ptr<IfAction> action = parseIf(element); 2878 EXPECT_NE(action->getConditionAction().get(), nullptr); 2879 EXPECT_EQ(action->getThenActions().size(), 1); 2880 EXPECT_EQ(action->getElseActions().size(), 1); 2881 } 2882 2883 // Test where fails: Required condition property not specified 2884 try 2885 { 2886 const json element = R"( 2887 { 2888 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2889 "else": [ { "run_rule": "configure_standard_regulator" } ] 2890 } 2891 )"_json; 2892 parseIf(element); 2893 ADD_FAILURE() << "Should not have reached this line."; 2894 } 2895 catch (const std::invalid_argument& e) 2896 { 2897 EXPECT_STREQ(e.what(), "Required property missing: condition"); 2898 } 2899 2900 // Test where fails: Required then property not specified 2901 try 2902 { 2903 const json element = R"( 2904 { 2905 "condition": { "run_rule": "is_downlevel_regulator" }, 2906 "else": [ { "run_rule": "configure_standard_regulator" } ] 2907 } 2908 )"_json; 2909 parseIf(element); 2910 ADD_FAILURE() << "Should not have reached this line."; 2911 } 2912 catch (const std::invalid_argument& e) 2913 { 2914 EXPECT_STREQ(e.what(), "Required property missing: then"); 2915 } 2916 2917 // Test where fails: condition value is invalid 2918 try 2919 { 2920 const json element = R"( 2921 { 2922 "condition": 1, 2923 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2924 "else": [ { "run_rule": "configure_standard_regulator" } ] 2925 } 2926 )"_json; 2927 parseIf(element); 2928 ADD_FAILURE() << "Should not have reached this line."; 2929 } 2930 catch (const std::invalid_argument& e) 2931 { 2932 EXPECT_STREQ(e.what(), "Element is not an object"); 2933 } 2934 2935 // Test where fails: then value is invalid 2936 try 2937 { 2938 const json element = R"( 2939 { 2940 "condition": { "run_rule": "is_downlevel_regulator" }, 2941 "then": "foo", 2942 "else": [ { "run_rule": "configure_standard_regulator" } ] 2943 } 2944 )"_json; 2945 parseIf(element); 2946 ADD_FAILURE() << "Should not have reached this line."; 2947 } 2948 catch (const std::invalid_argument& e) 2949 { 2950 EXPECT_STREQ(e.what(), "Element is not an array"); 2951 } 2952 2953 // Test where fails: else value is invalid 2954 try 2955 { 2956 const json element = R"( 2957 { 2958 "condition": { "run_rule": "is_downlevel_regulator" }, 2959 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2960 "else": 1 2961 } 2962 )"_json; 2963 parseIf(element); 2964 ADD_FAILURE() << "Should not have reached this line."; 2965 } 2966 catch (const std::invalid_argument& e) 2967 { 2968 EXPECT_STREQ(e.what(), "Element is not an array"); 2969 } 2970 2971 // Test where fails: Invalid property specified 2972 try 2973 { 2974 const json element = R"( 2975 { 2976 "condition": { "run_rule": "is_downlevel_regulator" }, 2977 "then": [ { "run_rule": "configure_downlevel_regulator" } ], 2978 "foo": "bar" 2979 } 2980 )"_json; 2981 parseIf(element); 2982 ADD_FAILURE() << "Should not have reached this line."; 2983 } 2984 catch (const std::invalid_argument& e) 2985 { 2986 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 2987 } 2988 2989 // Test where fails: Element is not an object 2990 try 2991 { 2992 const json element = R"( [ "0xFF", "0x01" ] )"_json; 2993 parseIf(element); 2994 ADD_FAILURE() << "Should not have reached this line."; 2995 } 2996 catch (const std::invalid_argument& e) 2997 { 2998 EXPECT_STREQ(e.what(), "Element is not an object"); 2999 } 3000 } 3001 3002 TEST(ConfigFileParserTests, ParseInt8) 3003 { 3004 // Test where works: INT8_MIN 3005 { 3006 const json element = R"( -128 )"_json; 3007 int8_t value = parseInt8(element); 3008 EXPECT_EQ(value, -128); 3009 } 3010 3011 // Test where works: INT8_MAX 3012 { 3013 const json element = R"( 127 )"_json; 3014 int8_t value = parseInt8(element); 3015 EXPECT_EQ(value, 127); 3016 } 3017 3018 // Test where fails: Element is not an integer 3019 try 3020 { 3021 const json element = R"( 1.03 )"_json; 3022 parseInt8(element); 3023 ADD_FAILURE() << "Should not have reached this line."; 3024 } 3025 catch (const std::invalid_argument& e) 3026 { 3027 EXPECT_STREQ(e.what(), "Element is not an integer"); 3028 } 3029 3030 // Test where fails: Value < INT8_MIN 3031 try 3032 { 3033 const json element = R"( -129 )"_json; 3034 parseInt8(element); 3035 ADD_FAILURE() << "Should not have reached this line."; 3036 } 3037 catch (const std::invalid_argument& e) 3038 { 3039 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 3040 } 3041 3042 // Test where fails: Value > INT8_MAX 3043 try 3044 { 3045 const json element = R"( 128 )"_json; 3046 parseInt8(element); 3047 ADD_FAILURE() << "Should not have reached this line."; 3048 } 3049 catch (const std::invalid_argument& e) 3050 { 3051 EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 3052 } 3053 } 3054 3055 TEST(ConfigFileParserTests, ParseNot) 3056 { 3057 // Test where works 3058 { 3059 const json element = R"( 3060 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } } 3061 )"_json; 3062 std::unique_ptr<NotAction> action = parseNot(element); 3063 EXPECT_NE(action->getAction().get(), nullptr); 3064 } 3065 3066 // Test where fails: Element is not an object 3067 try 3068 { 3069 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3070 parseNot(element); 3071 ADD_FAILURE() << "Should not have reached this line."; 3072 } 3073 catch (const std::invalid_argument& e) 3074 { 3075 EXPECT_STREQ(e.what(), "Element is not an object"); 3076 } 3077 } 3078 3079 TEST(ConfigFileParserTests, ParseOr) 3080 { 3081 // Test where works: Element is an array with 2 actions 3082 { 3083 const json element = R"( 3084 [ 3085 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }, 3086 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } } 3087 ] 3088 )"_json; 3089 std::unique_ptr<OrAction> action = parseOr(element); 3090 EXPECT_EQ(action->getActions().size(), 2); 3091 } 3092 3093 // Test where fails: Element is an array with 1 action 3094 try 3095 { 3096 const json element = R"( 3097 [ 3098 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } } 3099 ] 3100 )"_json; 3101 parseOr(element); 3102 ADD_FAILURE() << "Should not have reached this line."; 3103 } 3104 catch (const std::invalid_argument& e) 3105 { 3106 EXPECT_STREQ(e.what(), "Array must contain two or more actions"); 3107 } 3108 3109 // Test where fails: Element is not an array 3110 try 3111 { 3112 const json element = R"( 3113 { 3114 "foo": "bar" 3115 } 3116 )"_json; 3117 parseOr(element); 3118 ADD_FAILURE() << "Should not have reached this line."; 3119 } 3120 catch (const std::invalid_argument& e) 3121 { 3122 EXPECT_STREQ(e.what(), "Element is not an array"); 3123 } 3124 } 3125 3126 TEST(ConfigFileParserTests, ParsePMBusReadSensor) 3127 { 3128 // Test where works: Only required properties specified 3129 { 3130 const json element = R"( 3131 { 3132 "type": "iout", 3133 "command": "0x8C", 3134 "format": "linear_11" 3135 } 3136 )"_json; 3137 std::unique_ptr<PMBusReadSensorAction> action = 3138 parsePMBusReadSensor(element); 3139 EXPECT_EQ(action->getType(), pmbus_utils::SensorValueType::iout); 3140 EXPECT_EQ(action->getCommand(), 0x8C); 3141 EXPECT_EQ(action->getFormat(), 3142 pmbus_utils::SensorDataFormat::linear_11); 3143 EXPECT_EQ(action->getExponent().has_value(), false); 3144 } 3145 3146 // Test where works: All properties specified 3147 { 3148 const json element = R"( 3149 { 3150 "type": "temperature", 3151 "command": "0x7A", 3152 "format": "linear_16", 3153 "exponent": -8 3154 } 3155 )"_json; 3156 std::unique_ptr<PMBusReadSensorAction> action = 3157 parsePMBusReadSensor(element); 3158 EXPECT_EQ(action->getType(), pmbus_utils::SensorValueType::temperature); 3159 EXPECT_EQ(action->getCommand(), 0x7A); 3160 EXPECT_EQ(action->getFormat(), 3161 pmbus_utils::SensorDataFormat::linear_16); 3162 EXPECT_EQ(action->getExponent().has_value(), true); 3163 EXPECT_EQ(action->getExponent().value(), -8); 3164 } 3165 3166 // Test where fails: Element is not an object 3167 try 3168 { 3169 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3170 parsePMBusReadSensor(element); 3171 ADD_FAILURE() << "Should not have reached this line."; 3172 } 3173 catch (const std::invalid_argument& e) 3174 { 3175 EXPECT_STREQ(e.what(), "Element is not an object"); 3176 } 3177 3178 // Test where fails: Invalid property specified 3179 try 3180 { 3181 const json element = R"( 3182 { 3183 "type": "iout", 3184 "command": "0x8C", 3185 "format": "linear_11", 3186 "foo": 1 3187 } 3188 )"_json; 3189 parsePMBusReadSensor(element); 3190 ADD_FAILURE() << "Should not have reached this line."; 3191 } 3192 catch (const std::invalid_argument& e) 3193 { 3194 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3195 } 3196 3197 // Test where fails: Required type property not specified 3198 try 3199 { 3200 const json element = R"( 3201 { 3202 "command": "0x8C", 3203 "format": "linear_11" 3204 } 3205 )"_json; 3206 parsePMBusReadSensor(element); 3207 ADD_FAILURE() << "Should not have reached this line."; 3208 } 3209 catch (const std::invalid_argument& e) 3210 { 3211 EXPECT_STREQ(e.what(), "Required property missing: type"); 3212 } 3213 3214 // Test where fails: Required command property not specified 3215 try 3216 { 3217 const json element = R"( 3218 { 3219 "type": "iout", 3220 "format": "linear_11" 3221 } 3222 )"_json; 3223 parsePMBusReadSensor(element); 3224 ADD_FAILURE() << "Should not have reached this line."; 3225 } 3226 catch (const std::invalid_argument& e) 3227 { 3228 EXPECT_STREQ(e.what(), "Required property missing: command"); 3229 } 3230 3231 // Test where fails: Required format property not specified 3232 try 3233 { 3234 const json element = R"( 3235 { 3236 "type": "iout", 3237 "command": "0x8C" 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(), "Required property missing: format"); 3246 } 3247 3248 // Test where fails: type value is invalid 3249 try 3250 { 3251 const json element = R"( 3252 { 3253 "type": 1, 3254 "command": "0x7A", 3255 "format": "linear_16" 3256 } 3257 )"_json; 3258 parsePMBusReadSensor(element); 3259 ADD_FAILURE() << "Should not have reached this line."; 3260 } 3261 catch (const std::invalid_argument& e) 3262 { 3263 EXPECT_STREQ(e.what(), "Element is not a string"); 3264 } 3265 3266 // Test where fails: command value is invalid 3267 try 3268 { 3269 const json element = R"( 3270 { 3271 "type": "temperature", 3272 "command": 0, 3273 "format": "linear_16" 3274 } 3275 )"_json; 3276 parsePMBusReadSensor(element); 3277 ADD_FAILURE() << "Should not have reached this line."; 3278 } 3279 catch (const std::invalid_argument& e) 3280 { 3281 EXPECT_STREQ(e.what(), "Element is not a string"); 3282 } 3283 3284 // Test where fails: format value is invalid 3285 try 3286 { 3287 const json element = R"( 3288 { 3289 "type": "temperature", 3290 "command": "0x7A", 3291 "format": 1 3292 } 3293 )"_json; 3294 parsePMBusReadSensor(element); 3295 ADD_FAILURE() << "Should not have reached this line."; 3296 } 3297 catch (const std::invalid_argument& e) 3298 { 3299 EXPECT_STREQ(e.what(), "Element is not a string"); 3300 } 3301 3302 // Test where fails: exponent value is invalid 3303 try 3304 { 3305 const json element = R"( 3306 { 3307 "type": "temperature", 3308 "command": "0x7A", 3309 "format": "linear_16", 3310 "exponent": 1.3 3311 } 3312 )"_json; 3313 parsePMBusReadSensor(element); 3314 ADD_FAILURE() << "Should not have reached this line."; 3315 } 3316 catch (const std::invalid_argument& e) 3317 { 3318 EXPECT_STREQ(e.what(), "Element is not an integer"); 3319 } 3320 } 3321 3322 TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand) 3323 { 3324 // Test where works: Only required properties specified 3325 { 3326 const json element = R"( 3327 { 3328 "format": "linear" 3329 } 3330 )"_json; 3331 std::unique_ptr<PMBusWriteVoutCommandAction> action = 3332 parsePMBusWriteVoutCommand(element); 3333 EXPECT_EQ(action->getVolts().has_value(), false); 3334 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 3335 EXPECT_EQ(action->getExponent().has_value(), false); 3336 EXPECT_EQ(action->isVerified(), false); 3337 } 3338 3339 // Test where works: All properties specified 3340 { 3341 const json element = R"( 3342 { 3343 "volts": 1.03, 3344 "format": "linear", 3345 "exponent": -8, 3346 "is_verified": true 3347 } 3348 )"_json; 3349 std::unique_ptr<PMBusWriteVoutCommandAction> action = 3350 parsePMBusWriteVoutCommand(element); 3351 EXPECT_EQ(action->getVolts().has_value(), true); 3352 EXPECT_EQ(action->getVolts().value(), 1.03); 3353 EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 3354 EXPECT_EQ(action->getExponent().has_value(), true); 3355 EXPECT_EQ(action->getExponent().value(), -8); 3356 EXPECT_EQ(action->isVerified(), true); 3357 } 3358 3359 // Test where fails: Element is not an object 3360 try 3361 { 3362 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3363 parsePMBusWriteVoutCommand(element); 3364 ADD_FAILURE() << "Should not have reached this line."; 3365 } 3366 catch (const std::invalid_argument& e) 3367 { 3368 EXPECT_STREQ(e.what(), "Element is not an object"); 3369 } 3370 3371 // Test where fails: volts value is invalid 3372 try 3373 { 3374 const json element = R"( 3375 { 3376 "volts": "foo", 3377 "format": "linear" 3378 } 3379 )"_json; 3380 parsePMBusWriteVoutCommand(element); 3381 ADD_FAILURE() << "Should not have reached this line."; 3382 } 3383 catch (const std::invalid_argument& e) 3384 { 3385 EXPECT_STREQ(e.what(), "Element is not a number"); 3386 } 3387 3388 // Test where fails: Required format property not specified 3389 try 3390 { 3391 const json element = R"( 3392 { 3393 "volts": 1.03, 3394 "is_verified": true 3395 } 3396 )"_json; 3397 parsePMBusWriteVoutCommand(element); 3398 ADD_FAILURE() << "Should not have reached this line."; 3399 } 3400 catch (const std::invalid_argument& e) 3401 { 3402 EXPECT_STREQ(e.what(), "Required property missing: format"); 3403 } 3404 3405 // Test where fails: format value is invalid 3406 try 3407 { 3408 const json element = R"( 3409 { 3410 "format": "linear_11" 3411 } 3412 )"_json; 3413 parsePMBusWriteVoutCommand(element); 3414 ADD_FAILURE() << "Should not have reached this line."; 3415 } 3416 catch (const std::invalid_argument& e) 3417 { 3418 EXPECT_STREQ(e.what(), "Invalid format value: linear_11"); 3419 } 3420 3421 // Test where fails: exponent value is invalid 3422 try 3423 { 3424 const json element = R"( 3425 { 3426 "format": "linear", 3427 "exponent": 1.3 3428 } 3429 )"_json; 3430 parsePMBusWriteVoutCommand(element); 3431 ADD_FAILURE() << "Should not have reached this line."; 3432 } 3433 catch (const std::invalid_argument& e) 3434 { 3435 EXPECT_STREQ(e.what(), "Element is not an integer"); 3436 } 3437 3438 // Test where fails: is_verified value is invalid 3439 try 3440 { 3441 const json element = R"( 3442 { 3443 "format": "linear", 3444 "is_verified": "true" 3445 } 3446 )"_json; 3447 parsePMBusWriteVoutCommand(element); 3448 ADD_FAILURE() << "Should not have reached this line."; 3449 } 3450 catch (const std::invalid_argument& e) 3451 { 3452 EXPECT_STREQ(e.what(), "Element is not a boolean"); 3453 } 3454 3455 // Test where fails: Invalid property specified 3456 try 3457 { 3458 const json element = R"( 3459 { 3460 "format": "linear", 3461 "foo": "bar" 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(), "Element contains an invalid property"); 3470 } 3471 } 3472 3473 TEST(ConfigFileParserTests, ParsePresenceDetection) 3474 { 3475 // Test where works: actions property specified 3476 { 3477 const json element = R"( 3478 { 3479 "actions": [ 3480 { "run_rule": "read_sensors_rule" } 3481 ] 3482 } 3483 )"_json; 3484 std::unique_ptr<PresenceDetection> presenceDetection = 3485 parsePresenceDetection(element); 3486 EXPECT_EQ(presenceDetection->getActions().size(), 1); 3487 } 3488 3489 // Test where works: rule_id property specified 3490 { 3491 const json element = R"( 3492 { 3493 "comments": [ "comments property" ], 3494 "rule_id": "set_voltage_rule" 3495 } 3496 )"_json; 3497 std::unique_ptr<PresenceDetection> presenceDetection = 3498 parsePresenceDetection(element); 3499 EXPECT_EQ(presenceDetection->getActions().size(), 1); 3500 } 3501 3502 // Test where fails: actions object is invalid 3503 try 3504 { 3505 const json element = R"( 3506 { 3507 "actions": 1 3508 } 3509 )"_json; 3510 parsePresenceDetection(element); 3511 ADD_FAILURE() << "Should not have reached this line."; 3512 } 3513 catch (const std::invalid_argument& e) 3514 { 3515 EXPECT_STREQ(e.what(), "Element is not an array"); 3516 } 3517 3518 // Test where fails: rule_id value is invalid 3519 try 3520 { 3521 const json element = R"( 3522 { 3523 "rule_id": 1 3524 } 3525 )"_json; 3526 parsePresenceDetection(element); 3527 ADD_FAILURE() << "Should not have reached this line."; 3528 } 3529 catch (const std::invalid_argument& e) 3530 { 3531 EXPECT_STREQ(e.what(), "Element is not a string"); 3532 } 3533 3534 // Test where fails: Required actions or rule_id property not specified 3535 try 3536 { 3537 const json element = R"( 3538 { 3539 "comments": [ "comments property" ] 3540 } 3541 )"_json; 3542 parsePresenceDetection(element); 3543 ADD_FAILURE() << "Should not have reached this line."; 3544 } 3545 catch (const std::invalid_argument& e) 3546 { 3547 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 3548 "either rule_id or actions"); 3549 } 3550 3551 // Test where fails: Required actions or rule_id property both specified 3552 try 3553 { 3554 const json element = R"( 3555 { 3556 "rule_id": "set_voltage_rule", 3557 "actions": [ 3558 { "run_rule": "read_sensors_rule" } 3559 ] 3560 } 3561 )"_json; 3562 parsePresenceDetection(element); 3563 ADD_FAILURE() << "Should not have reached this line."; 3564 } 3565 catch (const std::invalid_argument& e) 3566 { 3567 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 3568 "either rule_id or actions"); 3569 } 3570 3571 // Test where fails: Element is not an object 3572 try 3573 { 3574 const json element = R"( [ "foo", "bar" ] )"_json; 3575 parsePresenceDetection(element); 3576 ADD_FAILURE() << "Should not have reached this line."; 3577 } 3578 catch (const std::invalid_argument& e) 3579 { 3580 EXPECT_STREQ(e.what(), "Element is not an object"); 3581 } 3582 3583 // Test where fails: Invalid property specified 3584 try 3585 { 3586 const json element = R"( 3587 { 3588 "foo": "bar", 3589 "actions": [ 3590 { "run_rule": "read_sensors_rule" } 3591 ] 3592 } 3593 )"_json; 3594 parsePresenceDetection(element); 3595 ADD_FAILURE() << "Should not have reached this line."; 3596 } 3597 catch (const std::invalid_argument& e) 3598 { 3599 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3600 } 3601 } 3602 3603 TEST(ConfigFileParserTests, ParseRail) 3604 { 3605 // Test where works: Only required properties specified 3606 { 3607 const json element = R"( 3608 { 3609 "id": "vdd" 3610 } 3611 )"_json; 3612 std::unique_ptr<Rail> rail = parseRail(element); 3613 EXPECT_EQ(rail->getID(), "vdd"); 3614 EXPECT_EQ(rail->getConfiguration(), nullptr); 3615 EXPECT_EQ(rail->getSensorMonitoring(), nullptr); 3616 } 3617 3618 // Test where works: All properties specified 3619 { 3620 const json element = R"( 3621 { 3622 "comments": [ "comments property" ], 3623 "id": "vdd", 3624 "configuration": { 3625 "volts": 1.1, 3626 "actions": [ 3627 { 3628 "pmbus_write_vout_command": { 3629 "format": "linear" 3630 } 3631 } 3632 ] 3633 }, 3634 "sensor_monitoring": { 3635 "actions": [ 3636 { "run_rule": "read_sensors_rule" } 3637 ] 3638 } 3639 } 3640 )"_json; 3641 std::unique_ptr<Rail> rail = parseRail(element); 3642 EXPECT_EQ(rail->getID(), "vdd"); 3643 EXPECT_NE(rail->getConfiguration(), nullptr); 3644 EXPECT_NE(rail->getSensorMonitoring(), nullptr); 3645 } 3646 3647 // Test where fails: id property not specified 3648 try 3649 { 3650 const json element = R"( 3651 { 3652 "configuration": { 3653 "volts": 1.1, 3654 "actions": [ 3655 { 3656 "pmbus_write_vout_command": { 3657 "format": "linear" 3658 } 3659 } 3660 ] 3661 } 3662 } 3663 )"_json; 3664 parseRail(element); 3665 ADD_FAILURE() << "Should not have reached this line."; 3666 } 3667 catch (const std::invalid_argument& e) 3668 { 3669 EXPECT_STREQ(e.what(), "Required property missing: id"); 3670 } 3671 3672 // Test where fails: id property is invalid 3673 try 3674 { 3675 const json element = R"( 3676 { 3677 "id": "", 3678 "configuration": { 3679 "volts": 1.1, 3680 "actions": [ 3681 { 3682 "pmbus_write_vout_command": { 3683 "format": "linear" 3684 } 3685 } 3686 ] 3687 } 3688 } 3689 )"_json; 3690 parseRail(element); 3691 ADD_FAILURE() << "Should not have reached this line."; 3692 } 3693 catch (const std::invalid_argument& e) 3694 { 3695 EXPECT_STREQ(e.what(), "Element contains an empty string"); 3696 } 3697 3698 // Test where fails: Element is not an object 3699 try 3700 { 3701 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3702 parseRail(element); 3703 ADD_FAILURE() << "Should not have reached this line."; 3704 } 3705 catch (const std::invalid_argument& e) 3706 { 3707 EXPECT_STREQ(e.what(), "Element is not an object"); 3708 } 3709 3710 // Test where fails: configuration value is invalid 3711 try 3712 { 3713 const json element = R"( 3714 { 3715 "id": "vdd", 3716 "configuration": "config" 3717 } 3718 )"_json; 3719 parseRail(element); 3720 ADD_FAILURE() << "Should not have reached this line."; 3721 } 3722 catch (const std::invalid_argument& e) 3723 { 3724 EXPECT_STREQ(e.what(), "Element is not an object"); 3725 } 3726 3727 // Test where fails: sensor_monitoring value is invalid 3728 try 3729 { 3730 const json element = R"( 3731 { 3732 "comments": [ "comments property" ], 3733 "id": "vdd", 3734 "configuration": { 3735 "volts": 1.1, 3736 "actions": [ 3737 { 3738 "pmbus_write_vout_command": { 3739 "format": "linear" 3740 } 3741 } 3742 ] 3743 }, 3744 "sensor_monitoring": 1 3745 } 3746 )"_json; 3747 parseRail(element); 3748 ADD_FAILURE() << "Should not have reached this line."; 3749 } 3750 catch (const std::invalid_argument& e) 3751 { 3752 EXPECT_STREQ(e.what(), "Element is not an object"); 3753 } 3754 3755 // Test where fails: Invalid property specified 3756 try 3757 { 3758 const json element = R"( 3759 { 3760 "id": "vdd", 3761 "foo" : true 3762 } 3763 )"_json; 3764 parseRail(element); 3765 ADD_FAILURE() << "Should not have reached this line."; 3766 } 3767 catch (const std::invalid_argument& e) 3768 { 3769 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3770 } 3771 } 3772 3773 TEST(ConfigFileParserTests, ParseRailArray) 3774 { 3775 // Test where works 3776 { 3777 const json element = R"( 3778 [ 3779 { "id": "vdd" }, 3780 { "id": "vio" } 3781 ] 3782 )"_json; 3783 std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element); 3784 EXPECT_EQ(rails.size(), 2); 3785 EXPECT_EQ(rails[0]->getID(), "vdd"); 3786 EXPECT_EQ(rails[1]->getID(), "vio"); 3787 } 3788 3789 // Test where fails: Element is not an array 3790 try 3791 { 3792 const json element = R"( 3793 { 3794 "foo": "bar" 3795 } 3796 )"_json; 3797 parseRailArray(element); 3798 ADD_FAILURE() << "Should not have reached this line."; 3799 } 3800 catch (const std::invalid_argument& e) 3801 { 3802 EXPECT_STREQ(e.what(), "Element is not an array"); 3803 } 3804 } 3805 3806 TEST(ConfigFileParserTests, ParseRoot) 3807 { 3808 // Test where works: Only required properties specified 3809 { 3810 const json element = R"( 3811 { 3812 "chassis": [ 3813 { "number": 1 } 3814 ] 3815 } 3816 )"_json; 3817 std::vector<std::unique_ptr<Rule>> rules{}; 3818 std::vector<std::unique_ptr<Chassis>> chassis{}; 3819 std::tie(rules, chassis) = parseRoot(element); 3820 EXPECT_EQ(rules.size(), 0); 3821 EXPECT_EQ(chassis.size(), 1); 3822 } 3823 3824 // Test where works: All properties specified 3825 { 3826 const json element = R"( 3827 { 3828 "comments": [ "Config file for a FooBar one-chassis system" ], 3829 "rules": [ 3830 { 3831 "id": "set_voltage_rule", 3832 "actions": [ 3833 { "pmbus_write_vout_command": { "format": "linear" } } 3834 ] 3835 } 3836 ], 3837 "chassis": [ 3838 { "number": 1 }, 3839 { "number": 3 } 3840 ] 3841 } 3842 )"_json; 3843 std::vector<std::unique_ptr<Rule>> rules{}; 3844 std::vector<std::unique_ptr<Chassis>> chassis{}; 3845 std::tie(rules, chassis) = parseRoot(element); 3846 EXPECT_EQ(rules.size(), 1); 3847 EXPECT_EQ(chassis.size(), 2); 3848 } 3849 3850 // Test where fails: Element is not an object 3851 try 3852 { 3853 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3854 parseRoot(element); 3855 ADD_FAILURE() << "Should not have reached this line."; 3856 } 3857 catch (const std::invalid_argument& e) 3858 { 3859 EXPECT_STREQ(e.what(), "Element is not an object"); 3860 } 3861 3862 // Test where fails: chassis property not specified 3863 try 3864 { 3865 const json element = R"( 3866 { 3867 "rules": [ 3868 { 3869 "id": "set_voltage_rule", 3870 "actions": [ 3871 { "pmbus_write_vout_command": { "format": "linear" } } 3872 ] 3873 } 3874 ] 3875 } 3876 )"_json; 3877 parseRoot(element); 3878 ADD_FAILURE() << "Should not have reached this line."; 3879 } 3880 catch (const std::invalid_argument& e) 3881 { 3882 EXPECT_STREQ(e.what(), "Required property missing: chassis"); 3883 } 3884 3885 // Test where fails: Invalid property specified 3886 try 3887 { 3888 const json element = R"( 3889 { 3890 "remarks": [ "Config file for a FooBar one-chassis system" ], 3891 "chassis": [ 3892 { "number": 1 } 3893 ] 3894 } 3895 )"_json; 3896 parseRoot(element); 3897 ADD_FAILURE() << "Should not have reached this line."; 3898 } 3899 catch (const std::invalid_argument& e) 3900 { 3901 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 3902 } 3903 } 3904 3905 TEST(ConfigFileParserTests, ParseRule) 3906 { 3907 // Test where works: comments property specified 3908 { 3909 const json element = R"( 3910 { 3911 "comments": [ "Set voltage rule" ], 3912 "id": "set_voltage_rule", 3913 "actions": [ 3914 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 3915 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 3916 ] 3917 } 3918 )"_json; 3919 std::unique_ptr<Rule> rule = parseRule(element); 3920 EXPECT_EQ(rule->getID(), "set_voltage_rule"); 3921 EXPECT_EQ(rule->getActions().size(), 2); 3922 } 3923 3924 // Test where works: comments property not specified 3925 { 3926 const json element = R"( 3927 { 3928 "id": "set_voltage_rule", 3929 "actions": [ 3930 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 3931 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }, 3932 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } } 3933 ] 3934 } 3935 )"_json; 3936 std::unique_ptr<Rule> rule = parseRule(element); 3937 EXPECT_EQ(rule->getID(), "set_voltage_rule"); 3938 EXPECT_EQ(rule->getActions().size(), 3); 3939 } 3940 3941 // Test where fails: Element is not an object 3942 try 3943 { 3944 const json element = R"( [ "0xFF", "0x01" ] )"_json; 3945 parseRule(element); 3946 ADD_FAILURE() << "Should not have reached this line."; 3947 } 3948 catch (const std::invalid_argument& e) 3949 { 3950 EXPECT_STREQ(e.what(), "Element is not an object"); 3951 } 3952 3953 // Test where fails: id property not specified 3954 try 3955 { 3956 const json element = R"( 3957 { 3958 "actions": [ 3959 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 3960 ] 3961 } 3962 )"_json; 3963 parseRule(element); 3964 ADD_FAILURE() << "Should not have reached this line."; 3965 } 3966 catch (const std::invalid_argument& e) 3967 { 3968 EXPECT_STREQ(e.what(), "Required property missing: id"); 3969 } 3970 3971 // Test where fails: id property is invalid 3972 try 3973 { 3974 const json element = R"( 3975 { 3976 "id": "", 3977 "actions": [ 3978 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 3979 ] 3980 } 3981 )"_json; 3982 parseRule(element); 3983 ADD_FAILURE() << "Should not have reached this line."; 3984 } 3985 catch (const std::invalid_argument& e) 3986 { 3987 EXPECT_STREQ(e.what(), "Element contains an empty string"); 3988 } 3989 3990 // Test where fails: actions property not specified 3991 try 3992 { 3993 const json element = R"( 3994 { 3995 "comments": [ "Set voltage rule" ], 3996 "id": "set_voltage_rule" 3997 } 3998 )"_json; 3999 parseRule(element); 4000 ADD_FAILURE() << "Should not have reached this line."; 4001 } 4002 catch (const std::invalid_argument& e) 4003 { 4004 EXPECT_STREQ(e.what(), "Required property missing: actions"); 4005 } 4006 4007 // Test where fails: actions property is invalid 4008 try 4009 { 4010 const json element = R"( 4011 { 4012 "id": "set_voltage_rule", 4013 "actions": true 4014 } 4015 )"_json; 4016 parseRule(element); 4017 ADD_FAILURE() << "Should not have reached this line."; 4018 } 4019 catch (const std::invalid_argument& e) 4020 { 4021 EXPECT_STREQ(e.what(), "Element is not an array"); 4022 } 4023 4024 // Test where fails: Invalid property specified 4025 try 4026 { 4027 const json element = R"( 4028 { 4029 "remarks": [ "Set voltage rule" ], 4030 "id": "set_voltage_rule", 4031 "actions": [ 4032 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4033 ] 4034 } 4035 )"_json; 4036 parseRule(element); 4037 ADD_FAILURE() << "Should not have reached this line."; 4038 } 4039 catch (const std::invalid_argument& e) 4040 { 4041 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4042 } 4043 } 4044 4045 TEST(ConfigFileParserTests, ParseRuleArray) 4046 { 4047 // Test where works 4048 { 4049 const json element = R"( 4050 [ 4051 { 4052 "id": "set_voltage_rule1", 4053 "actions": [ 4054 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 4055 ] 4056 }, 4057 { 4058 "id": "set_voltage_rule2", 4059 "actions": [ 4060 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 4061 { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } } 4062 ] 4063 } 4064 ] 4065 )"_json; 4066 std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element); 4067 EXPECT_EQ(rules.size(), 2); 4068 EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 4069 EXPECT_EQ(rules[0]->getActions().size(), 1); 4070 EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 4071 EXPECT_EQ(rules[1]->getActions().size(), 2); 4072 } 4073 4074 // Test where fails: Element is not an array 4075 try 4076 { 4077 const json element = R"( { "id": "set_voltage_rule" } )"_json; 4078 parseRuleArray(element); 4079 ADD_FAILURE() << "Should not have reached this line."; 4080 } 4081 catch (const std::invalid_argument& e) 4082 { 4083 EXPECT_STREQ(e.what(), "Element is not an array"); 4084 } 4085 } 4086 4087 TEST(ConfigFileParserTests, ParseRuleIDOrActionsProperty) 4088 { 4089 // Test where works: actions specified 4090 { 4091 const json element = R"( 4092 { 4093 "actions": [ 4094 { "pmbus_write_vout_command": { "format": "linear" } }, 4095 { "run_rule": "set_voltage_rule" } 4096 ] 4097 } 4098 )"_json; 4099 std::vector<std::unique_ptr<Action>> actions = 4100 parseRuleIDOrActionsProperty(element); 4101 EXPECT_EQ(actions.size(), 2); 4102 } 4103 4104 // Test where works: rule_id specified 4105 { 4106 const json element = R"( 4107 { 4108 "rule_id": "set_voltage_rule" 4109 } 4110 )"_json; 4111 std::vector<std::unique_ptr<Action>> actions = 4112 parseRuleIDOrActionsProperty(element); 4113 EXPECT_EQ(actions.size(), 1); 4114 } 4115 4116 // Test where fails: Element is not an object 4117 try 4118 { 4119 const json element = R"( [ "foo", "bar" ] )"_json; 4120 parseRuleIDOrActionsProperty(element); 4121 ADD_FAILURE() << "Should not have reached this line."; 4122 } 4123 catch (const std::invalid_argument& e) 4124 { 4125 EXPECT_STREQ(e.what(), "Element is not an object"); 4126 } 4127 4128 // Test where fails: rule_id is invalid 4129 try 4130 { 4131 const json element = R"( 4132 { "rule_id": 1 } 4133 )"_json; 4134 parseRuleIDOrActionsProperty(element); 4135 ADD_FAILURE() << "Should not have reached this line."; 4136 } 4137 catch (const std::invalid_argument& e) 4138 { 4139 EXPECT_STREQ(e.what(), "Element is not a string"); 4140 } 4141 4142 // Test where fails: actions is invalid 4143 try 4144 { 4145 const json element = R"( 4146 { "actions": 1 } 4147 )"_json; 4148 parseRuleIDOrActionsProperty(element); 4149 ADD_FAILURE() << "Should not have reached this line."; 4150 } 4151 catch (const std::invalid_argument& e) 4152 { 4153 EXPECT_STREQ(e.what(), "Element is not an array"); 4154 } 4155 4156 // Test where fails: Neither rule_id nor actions specified 4157 try 4158 { 4159 const json element = R"( 4160 { 4161 "volts": 1.03 4162 } 4163 )"_json; 4164 parseRuleIDOrActionsProperty(element); 4165 ADD_FAILURE() << "Should not have reached this line."; 4166 } 4167 catch (const std::invalid_argument& e) 4168 { 4169 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4170 "either rule_id or actions"); 4171 } 4172 4173 // Test where fails: Both rule_id and actions specified 4174 try 4175 { 4176 const json element = R"( 4177 { 4178 "volts": 1.03, 4179 "rule_id": "set_voltage_rule", 4180 "actions": [ 4181 { 4182 "pmbus_write_vout_command": { 4183 "format": "linear" 4184 } 4185 } 4186 ] 4187 } 4188 )"_json; 4189 parseRuleIDOrActionsProperty(element); 4190 ADD_FAILURE() << "Should not have reached this line."; 4191 } 4192 catch (const std::invalid_argument& e) 4193 { 4194 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4195 "either rule_id or actions"); 4196 } 4197 } 4198 4199 TEST(ConfigFileParserTests, ParseRunRule) 4200 { 4201 // Test where works 4202 { 4203 const json element = "vdd_regulator"; 4204 std::unique_ptr<RunRuleAction> action = parseRunRule(element); 4205 EXPECT_EQ(action->getRuleID(), "vdd_regulator"); 4206 } 4207 4208 // Test where fails: Element is not a string 4209 try 4210 { 4211 const json element = 1; 4212 parseRunRule(element); 4213 ADD_FAILURE() << "Should not have reached this line."; 4214 } 4215 catch (const std::invalid_argument& e) 4216 { 4217 EXPECT_STREQ(e.what(), "Element is not a string"); 4218 } 4219 4220 // Test where fails: Empty string 4221 try 4222 { 4223 const json element = ""; 4224 parseRunRule(element); 4225 ADD_FAILURE() << "Should not have reached this line."; 4226 } 4227 catch (const std::invalid_argument& e) 4228 { 4229 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4230 } 4231 } 4232 4233 TEST(ConfigFileParserTests, ParseSensorDataFormat) 4234 { 4235 // Test where works: linear_11 4236 { 4237 const json element = "linear_11"; 4238 pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element); 4239 pmbus_utils::SensorDataFormat format = 4240 pmbus_utils::SensorDataFormat::linear_11; 4241 EXPECT_EQ(value, format); 4242 } 4243 4244 // Test where works: linear_16 4245 { 4246 const json element = "linear_16"; 4247 pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element); 4248 pmbus_utils::SensorDataFormat format = 4249 pmbus_utils::SensorDataFormat::linear_16; 4250 EXPECT_EQ(value, format); 4251 } 4252 4253 // Test where fails: Element is not a sensor data format 4254 try 4255 { 4256 const json element = "foo"; 4257 parseSensorDataFormat(element); 4258 ADD_FAILURE() << "Should not have reached this line."; 4259 } 4260 catch (const std::invalid_argument& e) 4261 { 4262 EXPECT_STREQ(e.what(), "Element is not a sensor data format"); 4263 } 4264 4265 // Test where fails: Element is not a string 4266 try 4267 { 4268 const json element = R"( { "foo": "bar" } )"_json; 4269 parseSensorDataFormat(element); 4270 ADD_FAILURE() << "Should not have reached this line."; 4271 } 4272 catch (const std::invalid_argument& e) 4273 { 4274 EXPECT_STREQ(e.what(), "Element is not a string"); 4275 } 4276 } 4277 4278 TEST(ConfigFileParserTests, ParseSensorMonitoring) 4279 { 4280 // Test where works: actions property specified 4281 { 4282 const json element = R"( 4283 { 4284 "actions": [ 4285 { "run_rule": "read_sensors_rule" } 4286 ] 4287 } 4288 )"_json; 4289 std::unique_ptr<SensorMonitoring> sensorMonitoring = 4290 parseSensorMonitoring(element); 4291 EXPECT_EQ(sensorMonitoring->getActions().size(), 1); 4292 } 4293 4294 // Test where works: rule_id property specified 4295 { 4296 const json element = R"( 4297 { 4298 "comments": [ "comments property" ], 4299 "rule_id": "set_voltage_rule" 4300 } 4301 )"_json; 4302 std::unique_ptr<SensorMonitoring> sensorMonitoring = 4303 parseSensorMonitoring(element); 4304 EXPECT_EQ(sensorMonitoring->getActions().size(), 1); 4305 } 4306 4307 // Test where fails: actions object is invalid 4308 try 4309 { 4310 const json element = R"( 4311 { 4312 "actions": 1 4313 } 4314 )"_json; 4315 parseSensorMonitoring(element); 4316 ADD_FAILURE() << "Should not have reached this line."; 4317 } 4318 catch (const std::invalid_argument& e) 4319 { 4320 EXPECT_STREQ(e.what(), "Element is not an array"); 4321 } 4322 4323 // Test where fails: rule_id value is invalid 4324 try 4325 { 4326 const json element = R"( 4327 { 4328 "rule_id": 1 4329 } 4330 )"_json; 4331 parseSensorMonitoring(element); 4332 ADD_FAILURE() << "Should not have reached this line."; 4333 } 4334 catch (const std::invalid_argument& e) 4335 { 4336 EXPECT_STREQ(e.what(), "Element is not a string"); 4337 } 4338 4339 // Test where fails: Required actions or rule_id property not specified 4340 try 4341 { 4342 const json element = R"( 4343 { 4344 "comments": [ "comments property" ] 4345 } 4346 )"_json; 4347 parseSensorMonitoring(element); 4348 ADD_FAILURE() << "Should not have reached this line."; 4349 } 4350 catch (const std::invalid_argument& e) 4351 { 4352 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4353 "either rule_id or actions"); 4354 } 4355 4356 // Test where fails: Required actions or rule_id property both specified 4357 try 4358 { 4359 const json element = R"( 4360 { 4361 "rule_id": "set_voltage_rule", 4362 "actions": [ 4363 { "run_rule": "read_sensors_rule" } 4364 ] 4365 } 4366 )"_json; 4367 parseSensorMonitoring(element); 4368 ADD_FAILURE() << "Should not have reached this line."; 4369 } 4370 catch (const std::invalid_argument& e) 4371 { 4372 EXPECT_STREQ(e.what(), "Invalid property combination: Must contain " 4373 "either rule_id or actions"); 4374 } 4375 4376 // Test where fails: Element is not an object 4377 try 4378 { 4379 const json element = R"( [ "foo", "bar" ] )"_json; 4380 parseSensorMonitoring(element); 4381 ADD_FAILURE() << "Should not have reached this line."; 4382 } 4383 catch (const std::invalid_argument& e) 4384 { 4385 EXPECT_STREQ(e.what(), "Element is not an object"); 4386 } 4387 4388 // Test where fails: Invalid property specified 4389 try 4390 { 4391 const json element = R"( 4392 { 4393 "foo": "bar", 4394 "actions": [ 4395 { "run_rule": "read_sensors_rule" } 4396 ] 4397 } 4398 )"_json; 4399 parseSensorMonitoring(element); 4400 ADD_FAILURE() << "Should not have reached this line."; 4401 } 4402 catch (const std::invalid_argument& e) 4403 { 4404 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4405 } 4406 } 4407 4408 TEST(ConfigFileParserTests, ParseSensorValueType) 4409 { 4410 // Test where works: iout 4411 { 4412 const json element = "iout"; 4413 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4414 pmbus_utils::SensorValueType type = pmbus_utils::SensorValueType::iout; 4415 EXPECT_EQ(value, type); 4416 } 4417 4418 // Test where works: iout_peak 4419 { 4420 const json element = "iout_peak"; 4421 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4422 pmbus_utils::SensorValueType type = 4423 pmbus_utils::SensorValueType::iout_peak; 4424 EXPECT_EQ(value, type); 4425 } 4426 4427 // Test where works: iout_valley 4428 { 4429 const json element = "iout_valley"; 4430 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4431 pmbus_utils::SensorValueType type = 4432 pmbus_utils::SensorValueType::iout_valley; 4433 EXPECT_EQ(value, type); 4434 } 4435 4436 // Test where works: pout 4437 { 4438 const json element = "pout"; 4439 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4440 pmbus_utils::SensorValueType type = pmbus_utils::SensorValueType::pout; 4441 EXPECT_EQ(value, type); 4442 } 4443 4444 // Test where works: temperature 4445 { 4446 const json element = "temperature"; 4447 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4448 pmbus_utils::SensorValueType type = 4449 pmbus_utils::SensorValueType::temperature; 4450 EXPECT_EQ(value, type); 4451 } 4452 4453 // Test where works: temperature_peak 4454 { 4455 const json element = "temperature_peak"; 4456 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4457 pmbus_utils::SensorValueType type = 4458 pmbus_utils::SensorValueType::temperature_peak; 4459 EXPECT_EQ(value, type); 4460 } 4461 4462 // Test where works: vout 4463 { 4464 const json element = "vout"; 4465 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4466 pmbus_utils::SensorValueType type = pmbus_utils::SensorValueType::vout; 4467 EXPECT_EQ(value, type); 4468 } 4469 4470 // Test where works: vout_peak 4471 { 4472 const json element = "vout_peak"; 4473 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4474 pmbus_utils::SensorValueType type = 4475 pmbus_utils::SensorValueType::vout_peak; 4476 EXPECT_EQ(value, type); 4477 } 4478 4479 // Test where works: vout_valley 4480 { 4481 const json element = "vout_valley"; 4482 pmbus_utils::SensorValueType value = parseSensorValueType(element); 4483 pmbus_utils::SensorValueType type = 4484 pmbus_utils::SensorValueType::vout_valley; 4485 EXPECT_EQ(value, type); 4486 } 4487 4488 // Test where fails: Element is not a sensor value type 4489 try 4490 { 4491 const json element = "foo"; 4492 parseSensorValueType(element); 4493 ADD_FAILURE() << "Should not have reached this line."; 4494 } 4495 catch (const std::invalid_argument& e) 4496 { 4497 EXPECT_STREQ(e.what(), "Element is not a sensor value type"); 4498 } 4499 4500 // Test where fails: Element is not a string 4501 try 4502 { 4503 const json element = R"( { "foo": "bar" } )"_json; 4504 parseSensorValueType(element); 4505 ADD_FAILURE() << "Should not have reached this line."; 4506 } 4507 catch (const std::invalid_argument& e) 4508 { 4509 EXPECT_STREQ(e.what(), "Element is not a string"); 4510 } 4511 } 4512 4513 TEST(ConfigFileParserTests, ParseSetDevice) 4514 { 4515 // Test where works 4516 { 4517 const json element = "regulator1"; 4518 std::unique_ptr<SetDeviceAction> action = parseSetDevice(element); 4519 EXPECT_EQ(action->getDeviceID(), "regulator1"); 4520 } 4521 4522 // Test where fails: Element is not a string 4523 try 4524 { 4525 const json element = 1; 4526 parseSetDevice(element); 4527 ADD_FAILURE() << "Should not have reached this line."; 4528 } 4529 catch (const std::invalid_argument& e) 4530 { 4531 EXPECT_STREQ(e.what(), "Element is not a string"); 4532 } 4533 4534 // Test where fails: Empty string 4535 try 4536 { 4537 const json element = ""; 4538 parseSetDevice(element); 4539 ADD_FAILURE() << "Should not have reached this line."; 4540 } 4541 catch (const std::invalid_argument& e) 4542 { 4543 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4544 } 4545 } 4546 4547 TEST(ConfigFileParserTests, ParseString) 4548 { 4549 // Test where works: Empty string 4550 { 4551 const json element = ""; 4552 std::string value = parseString(element, true); 4553 EXPECT_EQ(value, ""); 4554 } 4555 4556 // Test where works: Non-empty string 4557 { 4558 const json element = "vdd_regulator"; 4559 std::string value = parseString(element, false); 4560 EXPECT_EQ(value, "vdd_regulator"); 4561 } 4562 4563 // Test where fails: Element is not a string 4564 try 4565 { 4566 const json element = R"( { "foo": "bar" } )"_json; 4567 parseString(element); 4568 ADD_FAILURE() << "Should not have reached this line."; 4569 } 4570 catch (const std::invalid_argument& e) 4571 { 4572 EXPECT_STREQ(e.what(), "Element is not a string"); 4573 } 4574 4575 // Test where fails: Empty string 4576 try 4577 { 4578 const json element = ""; 4579 parseString(element); 4580 ADD_FAILURE() << "Should not have reached this line."; 4581 } 4582 catch (const std::invalid_argument& e) 4583 { 4584 EXPECT_STREQ(e.what(), "Element contains an empty string"); 4585 } 4586 } 4587 4588 TEST(ConfigFileParserTests, ParseUint8) 4589 { 4590 // Test where works: 0 4591 { 4592 const json element = R"( 0 )"_json; 4593 uint8_t value = parseUint8(element); 4594 EXPECT_EQ(value, 0); 4595 } 4596 4597 // Test where works: UINT8_MAX 4598 { 4599 const json element = R"( 255 )"_json; 4600 uint8_t value = parseUint8(element); 4601 EXPECT_EQ(value, 255); 4602 } 4603 4604 // Test where fails: Element is not an integer 4605 try 4606 { 4607 const json element = R"( 1.03 )"_json; 4608 parseUint8(element); 4609 ADD_FAILURE() << "Should not have reached this line."; 4610 } 4611 catch (const std::invalid_argument& e) 4612 { 4613 EXPECT_STREQ(e.what(), "Element is not an integer"); 4614 } 4615 4616 // Test where fails: Value < 0 4617 try 4618 { 4619 const json element = R"( -1 )"_json; 4620 parseUint8(element); 4621 ADD_FAILURE() << "Should not have reached this line."; 4622 } 4623 catch (const std::invalid_argument& e) 4624 { 4625 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); 4626 } 4627 4628 // Test where fails: Value > UINT8_MAX 4629 try 4630 { 4631 const json element = R"( 256 )"_json; 4632 parseUint8(element); 4633 ADD_FAILURE() << "Should not have reached this line."; 4634 } 4635 catch (const std::invalid_argument& e) 4636 { 4637 EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer"); 4638 } 4639 } 4640 4641 TEST(ConfigFileParserTests, ParseUnsignedInteger) 4642 { 4643 // Test where works: 1 4644 { 4645 const json element = R"( 1 )"_json; 4646 unsigned int value = parseUnsignedInteger(element); 4647 EXPECT_EQ(value, 1); 4648 } 4649 4650 // Test where fails: Element is not an integer 4651 try 4652 { 4653 const json element = R"( 1.5 )"_json; 4654 parseUnsignedInteger(element); 4655 ADD_FAILURE() << "Should not have reached this line."; 4656 } 4657 catch (const std::invalid_argument& e) 4658 { 4659 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 4660 } 4661 4662 // Test where fails: Value < 0 4663 try 4664 { 4665 const json element = R"( -1 )"_json; 4666 parseUnsignedInteger(element); 4667 ADD_FAILURE() << "Should not have reached this line."; 4668 } 4669 catch (const std::invalid_argument& e) 4670 { 4671 EXPECT_STREQ(e.what(), "Element is not an unsigned integer"); 4672 } 4673 } 4674 4675 TEST(ConfigFileParserTests, ParseVoutDataFormat) 4676 { 4677 // Test where works: linear 4678 { 4679 const json element = "linear"; 4680 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 4681 pmbus_utils::VoutDataFormat format = 4682 pmbus_utils::VoutDataFormat::linear; 4683 EXPECT_EQ(value, format); 4684 } 4685 4686 // Test where works: vid 4687 { 4688 const json element = "vid"; 4689 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 4690 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::vid; 4691 EXPECT_EQ(value, format); 4692 } 4693 4694 // Test where works: direct 4695 { 4696 const json element = "direct"; 4697 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 4698 pmbus_utils::VoutDataFormat format = 4699 pmbus_utils::VoutDataFormat::direct; 4700 EXPECT_EQ(value, format); 4701 } 4702 4703 // Test where works: ieee 4704 { 4705 const json element = "ieee"; 4706 pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element); 4707 pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::ieee; 4708 EXPECT_EQ(value, format); 4709 } 4710 4711 // Test where fails: Element is not a vout data format 4712 try 4713 { 4714 const json element = "foo"; 4715 parseVoutDataFormat(element); 4716 ADD_FAILURE() << "Should not have reached this line."; 4717 } 4718 catch (const std::invalid_argument& e) 4719 { 4720 EXPECT_STREQ(e.what(), "Element is not a vout data format"); 4721 } 4722 4723 // Test where fails: Element is not a string 4724 try 4725 { 4726 const json element = R"( { "foo": "bar" } )"_json; 4727 parseVoutDataFormat(element); 4728 ADD_FAILURE() << "Should not have reached this line."; 4729 } 4730 catch (const std::invalid_argument& e) 4731 { 4732 EXPECT_STREQ(e.what(), "Element is not a string"); 4733 } 4734 } 4735 4736 TEST(ConfigFileParserTests, VerifyIsArray) 4737 { 4738 // Test where element is an array 4739 try 4740 { 4741 const json element = R"( [ "foo", "bar" ] )"_json; 4742 verifyIsArray(element); 4743 } 4744 catch (const std::exception& e) 4745 { 4746 ADD_FAILURE() << "Should not have caught exception."; 4747 } 4748 4749 // Test where element is not an array 4750 try 4751 { 4752 const json element = R"( { "foo": "bar" } )"_json; 4753 verifyIsArray(element); 4754 ADD_FAILURE() << "Should not have reached this line."; 4755 } 4756 catch (const std::invalid_argument& e) 4757 { 4758 EXPECT_STREQ(e.what(), "Element is not an array"); 4759 } 4760 } 4761 4762 TEST(ConfigFileParserTests, VerifyIsObject) 4763 { 4764 // Test where element is an object 4765 try 4766 { 4767 const json element = R"( { "foo": "bar" } )"_json; 4768 verifyIsObject(element); 4769 } 4770 catch (const std::exception& e) 4771 { 4772 ADD_FAILURE() << "Should not have caught exception."; 4773 } 4774 4775 // Test where element is not an object 4776 try 4777 { 4778 const json element = R"( [ "foo", "bar" ] )"_json; 4779 verifyIsObject(element); 4780 ADD_FAILURE() << "Should not have reached this line."; 4781 } 4782 catch (const std::invalid_argument& e) 4783 { 4784 EXPECT_STREQ(e.what(), "Element is not an object"); 4785 } 4786 } 4787 4788 TEST(ConfigFileParserTests, VerifyPropertyCount) 4789 { 4790 // Test where element has expected number of properties 4791 try 4792 { 4793 const json element = R"( 4794 { 4795 "comments": [ "Set voltage rule" ], 4796 "id": "set_voltage_rule" 4797 } 4798 )"_json; 4799 verifyPropertyCount(element, 2); 4800 } 4801 catch (const std::exception& e) 4802 { 4803 ADD_FAILURE() << "Should not have caught exception."; 4804 } 4805 4806 // Test where element has unexpected number of properties 4807 try 4808 { 4809 const json element = R"( 4810 { 4811 "comments": [ "Set voltage rule" ], 4812 "id": "set_voltage_rule", 4813 "foo": 1.3 4814 } 4815 )"_json; 4816 verifyPropertyCount(element, 2); 4817 ADD_FAILURE() << "Should not have reached this line."; 4818 } 4819 catch (const std::invalid_argument& e) 4820 { 4821 EXPECT_STREQ(e.what(), "Element contains an invalid property"); 4822 } 4823 } 4824