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