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