10e8c68abSShawn McCarney /**
20e8c68abSShawn McCarney  * Copyright © 2020 IBM Corporation
30e8c68abSShawn McCarney  *
40e8c68abSShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
50e8c68abSShawn McCarney  * you may not use this file except in compliance with the License.
60e8c68abSShawn McCarney  * You may obtain a copy of the License at
70e8c68abSShawn McCarney  *
80e8c68abSShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
90e8c68abSShawn McCarney  *
100e8c68abSShawn McCarney  * Unless required by applicable law or agreed to in writing, software
110e8c68abSShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
120e8c68abSShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130e8c68abSShawn McCarney  * See the License for the specific language governing permissions and
140e8c68abSShawn McCarney  * limitations under the License.
150e8c68abSShawn McCarney  */
160e8c68abSShawn McCarney #include "action.hpp"
173a787540SBob King #include "and_action.hpp"
180e8c68abSShawn McCarney #include "chassis.hpp"
19b267b7ebSBob King #include "compare_presence_action.hpp"
20f2134320SBob King #include "compare_vpd_action.hpp"
210e8c68abSShawn McCarney #include "config_file_parser.hpp"
220e8c68abSShawn McCarney #include "config_file_parser_error.hpp"
239c36c5fbSBob King #include "configuration.hpp"
240e70113dSBob King #include "device.hpp"
2591f87a56SShawn McCarney #include "i2c_capture_bytes_action.hpp"
26f09bfe07SBob King #include "i2c_compare_bit_action.hpp"
27f09bfe07SBob King #include "i2c_compare_byte_action.hpp"
28f09bfe07SBob King #include "i2c_compare_bytes_action.hpp"
29f617f893SBob King #include "i2c_interface.hpp"
30f617f893SBob King #include "i2c_write_bit_action.hpp"
3187ff9d7dSBob King #include "i2c_write_byte_action.hpp"
32bafcb86cSBob King #include "i2c_write_bytes_action.hpp"
331115785fSShawn McCarney #include "log_phase_fault_action.hpp"
34f1b58dc4SBob King #include "not_action.hpp"
350b51a9b2SBob King #include "or_action.hpp"
36b70370b7SShawn McCarney #include "phase_fault.hpp"
3739eb08a9SShawn McCarney #include "phase_fault_detection.hpp"
3884614882SBob King #include "pmbus_read_sensor_action.hpp"
390e8c68abSShawn McCarney #include "pmbus_utils.hpp"
400e8c68abSShawn McCarney #include "pmbus_write_vout_command_action.hpp"
419c36c5fbSBob King #include "presence_detection.hpp"
429c36c5fbSBob King #include "rail.hpp"
430e8c68abSShawn McCarney #include "rule.hpp"
44315b0b62SBob King #include "run_rule_action.hpp"
45a2f2a0dcSBob King #include "sensor_monitoring.hpp"
462f9e14f6SShawn McCarney #include "sensors.hpp"
4718a68505SBob King #include "set_device_action.hpp"
480f6ebadeSShawn McCarney #include "temporary_file.hpp"
490e8c68abSShawn McCarney 
5080c0b049SShawn McCarney #include <sys/stat.h> // for chmod()
510e8c68abSShawn McCarney 
520e8c68abSShawn McCarney #include <nlohmann/json.hpp>
530e8c68abSShawn McCarney 
540e8c68abSShawn McCarney #include <cstdint>
550e8c68abSShawn McCarney #include <cstring>
560e8c68abSShawn McCarney #include <exception>
570e8c68abSShawn McCarney #include <filesystem>
580e8c68abSShawn McCarney #include <fstream>
590e8c68abSShawn McCarney #include <memory>
600e8c68abSShawn McCarney #include <optional>
610e8c68abSShawn McCarney #include <stdexcept>
620e8c68abSShawn McCarney #include <string>
630e8c68abSShawn McCarney #include <tuple>
640e8c68abSShawn McCarney #include <vector>
650e8c68abSShawn McCarney 
660e8c68abSShawn McCarney #include <gtest/gtest.h>
670e8c68abSShawn McCarney 
680e8c68abSShawn McCarney using namespace phosphor::power::regulators;
690e8c68abSShawn McCarney using namespace phosphor::power::regulators::config_file_parser;
700e8c68abSShawn McCarney using namespace phosphor::power::regulators::config_file_parser::internal;
710e8c68abSShawn McCarney using json = nlohmann::json;
72*5f51444dSShawn McCarney using TemporaryFile = phosphor::power::util::TemporaryFile;
730e8c68abSShawn McCarney 
writeConfigFile(const std::filesystem::path & pathName,const std::string & contents)740e8c68abSShawn McCarney void writeConfigFile(const std::filesystem::path& pathName,
750e8c68abSShawn McCarney                      const std::string& contents)
760e8c68abSShawn McCarney {
770e8c68abSShawn McCarney     std::ofstream file{pathName};
780e8c68abSShawn McCarney     file << contents;
790e8c68abSShawn McCarney }
800e8c68abSShawn McCarney 
writeConfigFile(const std::filesystem::path & pathName,const json & contents)810e8c68abSShawn McCarney void writeConfigFile(const std::filesystem::path& pathName,
820e8c68abSShawn McCarney                      const json& contents)
830e8c68abSShawn McCarney {
840e8c68abSShawn McCarney     std::ofstream file{pathName};
850e8c68abSShawn McCarney     file << contents;
860e8c68abSShawn McCarney }
870e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,Parse)880e8c68abSShawn McCarney TEST(ConfigFileParserTests, Parse)
890e8c68abSShawn McCarney {
900e8c68abSShawn McCarney     // Test where works
910e8c68abSShawn McCarney     {
920e8c68abSShawn McCarney         const json configFileContents = R"(
930e8c68abSShawn McCarney             {
940e8c68abSShawn McCarney               "rules": [
950e8c68abSShawn McCarney                 {
960e8c68abSShawn McCarney                   "id": "set_voltage_rule1",
970e8c68abSShawn McCarney                   "actions": [
980e8c68abSShawn McCarney                     { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
990e8c68abSShawn McCarney                   ]
1000e8c68abSShawn McCarney                 },
1010e8c68abSShawn McCarney                 {
1020e8c68abSShawn McCarney                   "id": "set_voltage_rule2",
1030e8c68abSShawn McCarney                   "actions": [
1040e8c68abSShawn McCarney                     { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } }
1050e8c68abSShawn McCarney                   ]
1060e8c68abSShawn McCarney                 }
1070e8c68abSShawn McCarney               ],
1080e8c68abSShawn McCarney               "chassis": [
1094c88a4c2SShawn McCarney                 { "number": 1, "inventory_path": "system/chassis1" },
1104c88a4c2SShawn McCarney                 { "number": 2, "inventory_path": "system/chassis2" },
1114c88a4c2SShawn McCarney                 { "number": 3, "inventory_path": "system/chassis3" }
1120e8c68abSShawn McCarney               ]
1130e8c68abSShawn McCarney             }
1140e8c68abSShawn McCarney         )"_json;
1150e8c68abSShawn McCarney 
1160f6ebadeSShawn McCarney         TemporaryFile configFile;
1170f6ebadeSShawn McCarney         std::filesystem::path pathName{configFile.getPath()};
1180e8c68abSShawn McCarney         writeConfigFile(pathName, configFileContents);
1190e8c68abSShawn McCarney 
1200e8c68abSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
1210e8c68abSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassis{};
1220e8c68abSShawn McCarney         std::tie(rules, chassis) = parse(pathName);
1230e8c68abSShawn McCarney 
1240e8c68abSShawn McCarney         EXPECT_EQ(rules.size(), 2);
1250e8c68abSShawn McCarney         EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
1260e8c68abSShawn McCarney         EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
1270e8c68abSShawn McCarney 
1280e70113dSBob King         EXPECT_EQ(chassis.size(), 3);
1290e70113dSBob King         EXPECT_EQ(chassis[0]->getNumber(), 1);
1304c88a4c2SShawn McCarney         EXPECT_EQ(chassis[0]->getInventoryPath(),
1314c88a4c2SShawn McCarney                   "/xyz/openbmc_project/inventory/system/chassis1");
1320e70113dSBob King         EXPECT_EQ(chassis[1]->getNumber(), 2);
1334c88a4c2SShawn McCarney         EXPECT_EQ(chassis[1]->getInventoryPath(),
1344c88a4c2SShawn McCarney                   "/xyz/openbmc_project/inventory/system/chassis2");
1350e70113dSBob King         EXPECT_EQ(chassis[2]->getNumber(), 3);
1364c88a4c2SShawn McCarney         EXPECT_EQ(chassis[2]->getInventoryPath(),
1374c88a4c2SShawn McCarney                   "/xyz/openbmc_project/inventory/system/chassis3");
1380e8c68abSShawn McCarney     }
1390e8c68abSShawn McCarney 
1400e8c68abSShawn McCarney     // Test where fails: File does not exist
1410e8c68abSShawn McCarney     try
1420e8c68abSShawn McCarney     {
1430e8c68abSShawn McCarney         std::filesystem::path pathName{"/tmp/non_existent_file"};
1440e8c68abSShawn McCarney         parse(pathName);
1450e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
1460e8c68abSShawn McCarney     }
1470e8c68abSShawn McCarney     catch (const ConfigFileParserError& e)
1480e8c68abSShawn McCarney     {
1490e8c68abSShawn McCarney         // Expected exception; what() message will vary
1500e8c68abSShawn McCarney     }
1510e8c68abSShawn McCarney 
1520e8c68abSShawn McCarney     // Test where fails: File is not readable
1530e8c68abSShawn McCarney     try
1540e8c68abSShawn McCarney     {
1550e8c68abSShawn McCarney         const json configFileContents = R"(
1560e8c68abSShawn McCarney             {
1574c88a4c2SShawn McCarney               "chassis": [
1584c88a4c2SShawn McCarney                 { "number": 1, "inventory_path": "system/chassis1" }
1594c88a4c2SShawn McCarney               ]
1600e8c68abSShawn McCarney             }
1610e8c68abSShawn McCarney         )"_json;
1620e8c68abSShawn McCarney 
1630f6ebadeSShawn McCarney         TemporaryFile configFile;
1640f6ebadeSShawn McCarney         std::filesystem::path pathName{configFile.getPath()};
1650e8c68abSShawn McCarney         writeConfigFile(pathName, configFileContents);
1660e8c68abSShawn McCarney 
1670e8c68abSShawn McCarney         chmod(pathName.c_str(), 0222);
1680e8c68abSShawn McCarney 
1690e8c68abSShawn McCarney         parse(pathName);
1700e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
1710e8c68abSShawn McCarney     }
1720e8c68abSShawn McCarney     catch (const ConfigFileParserError& e)
1730e8c68abSShawn McCarney     {
1740e8c68abSShawn McCarney         // Expected exception; what() message will vary
1750e8c68abSShawn McCarney     }
1760e8c68abSShawn McCarney 
1770e8c68abSShawn McCarney     // Test where fails: File is not valid JSON
1780e8c68abSShawn McCarney     try
1790e8c68abSShawn McCarney     {
1800e8c68abSShawn McCarney         const std::string configFileContents = "] foo [";
1810e8c68abSShawn McCarney 
1820f6ebadeSShawn McCarney         TemporaryFile configFile;
1830f6ebadeSShawn McCarney         std::filesystem::path pathName{configFile.getPath()};
1840e8c68abSShawn McCarney         writeConfigFile(pathName, configFileContents);
1850e8c68abSShawn McCarney 
1860e8c68abSShawn McCarney         parse(pathName);
1870e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
1880e8c68abSShawn McCarney     }
1890e8c68abSShawn McCarney     catch (const ConfigFileParserError& e)
1900e8c68abSShawn McCarney     {
1910e8c68abSShawn McCarney         // Expected exception; what() message will vary
1920e8c68abSShawn McCarney     }
1930e8c68abSShawn McCarney 
1940e8c68abSShawn McCarney     // Test where fails: Error when parsing JSON elements
1950e8c68abSShawn McCarney     try
1960e8c68abSShawn McCarney     {
1970e8c68abSShawn McCarney         const json configFileContents = R"( { "foo": "bar" } )"_json;
1980e8c68abSShawn McCarney 
1990f6ebadeSShawn McCarney         TemporaryFile configFile;
2000f6ebadeSShawn McCarney         std::filesystem::path pathName{configFile.getPath()};
2010e8c68abSShawn McCarney         writeConfigFile(pathName, configFileContents);
2020e8c68abSShawn McCarney 
2030e8c68abSShawn McCarney         parse(pathName);
2040e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
2050e8c68abSShawn McCarney     }
2060e8c68abSShawn McCarney     catch (const ConfigFileParserError& e)
2070e8c68abSShawn McCarney     {
2080e8c68abSShawn McCarney         // Expected exception; what() message will vary
2090e8c68abSShawn McCarney     }
2100e8c68abSShawn McCarney }
2110e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,GetRequiredProperty)2120e8c68abSShawn McCarney TEST(ConfigFileParserTests, GetRequiredProperty)
2130e8c68abSShawn McCarney {
2140e8c68abSShawn McCarney     // Test where property exists
2150e8c68abSShawn McCarney     {
2160e8c68abSShawn McCarney         const json element = R"( { "format": "linear" } )"_json;
2170e8c68abSShawn McCarney         const json& propertyElement = getRequiredProperty(element, "format");
2180e8c68abSShawn McCarney         EXPECT_EQ(propertyElement.get<std::string>(), "linear");
2190e8c68abSShawn McCarney     }
2200e8c68abSShawn McCarney 
2210e8c68abSShawn McCarney     // Test where property does not exist
2220e8c68abSShawn McCarney     try
2230e8c68abSShawn McCarney     {
2240e8c68abSShawn McCarney         const json element = R"( { "volts": 1.03 } )"_json;
2250e8c68abSShawn McCarney         getRequiredProperty(element, "format");
2260e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
2270e8c68abSShawn McCarney     }
2280e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
2290e8c68abSShawn McCarney     {
2300e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: format");
2310e8c68abSShawn McCarney     }
2320e8c68abSShawn McCarney }
2330e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseAction)2340e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseAction)
2350e8c68abSShawn McCarney {
2360e8c68abSShawn McCarney     // Test where works: comments property specified
2370e8c68abSShawn McCarney     {
2380e8c68abSShawn McCarney         const json element = R"(
2390e8c68abSShawn McCarney             {
2400e8c68abSShawn McCarney               "comments": [ "Set output voltage." ],
2410e8c68abSShawn McCarney               "pmbus_write_vout_command": {
2420e8c68abSShawn McCarney                 "format": "linear"
2430e8c68abSShawn McCarney               }
2440e8c68abSShawn McCarney             }
2450e8c68abSShawn McCarney         )"_json;
2460e8c68abSShawn McCarney         std::unique_ptr<Action> action = parseAction(element);
2470e8c68abSShawn McCarney         EXPECT_NE(action.get(), nullptr);
2480e8c68abSShawn McCarney     }
2490e8c68abSShawn McCarney 
2500e8c68abSShawn McCarney     // Test where works: comments property not specified
2510e8c68abSShawn McCarney     {
2520e8c68abSShawn McCarney         const json element = R"(
2530e8c68abSShawn McCarney             {
2540e8c68abSShawn McCarney               "pmbus_write_vout_command": {
2550e8c68abSShawn McCarney                 "format": "linear"
2560e8c68abSShawn McCarney               }
2570e8c68abSShawn McCarney             }
2580e8c68abSShawn McCarney         )"_json;
2590e8c68abSShawn McCarney         std::unique_ptr<Action> action = parseAction(element);
2600e8c68abSShawn McCarney         EXPECT_NE(action.get(), nullptr);
2610e8c68abSShawn McCarney     }
2620e8c68abSShawn McCarney 
2630e8c68abSShawn McCarney     // Test where works: and action type specified
2643a787540SBob King     {
2653a787540SBob King         const json element = R"(
2663a787540SBob King             {
2673a787540SBob King               "and": [
2683a787540SBob King                 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
2693a787540SBob King                 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
2703a787540SBob King               ]
2713a787540SBob King             }
2723a787540SBob King         )"_json;
2733a787540SBob King         std::unique_ptr<Action> action = parseAction(element);
2743a787540SBob King         EXPECT_NE(action.get(), nullptr);
2753a787540SBob King     }
2760e8c68abSShawn McCarney 
2770e8c68abSShawn McCarney     // Test where works: compare_presence action type specified
278b267b7ebSBob King     {
279b267b7ebSBob King         const json element = R"(
280b267b7ebSBob King             {
281b267b7ebSBob King               "compare_presence":
282b267b7ebSBob King               {
283a76898f1SBob King                 "fru": "system/chassis/motherboard/cpu3",
284b267b7ebSBob King                 "value": true
285b267b7ebSBob King               }
286b267b7ebSBob King             }
287b267b7ebSBob King         )"_json;
288b267b7ebSBob King         std::unique_ptr<Action> action = parseAction(element);
289b267b7ebSBob King         EXPECT_NE(action.get(), nullptr);
290b267b7ebSBob King     }
2910e8c68abSShawn McCarney 
2920e8c68abSShawn McCarney     // Test where works: compare_vpd action type specified
293f2134320SBob King     {
294f2134320SBob King         const json element = R"(
295f2134320SBob King             {
296f2134320SBob King               "compare_vpd":
297f2134320SBob King               {
298a76898f1SBob King                 "fru": "system/chassis/disk_backplane",
299f2134320SBob King                 "keyword": "CCIN",
300f2134320SBob King                 "value": "2D35"
301f2134320SBob King               }
302f2134320SBob King             }
303f2134320SBob King         )"_json;
304f2134320SBob King         std::unique_ptr<Action> action = parseAction(element);
305f2134320SBob King         EXPECT_NE(action.get(), nullptr);
306f2134320SBob King     }
3070e8c68abSShawn McCarney 
30891f87a56SShawn McCarney     // Test where works: i2c_capture_bytes action type specified
30991f87a56SShawn McCarney     {
31091f87a56SShawn McCarney         const json element = R"(
31191f87a56SShawn McCarney             {
31291f87a56SShawn McCarney               "i2c_capture_bytes": {
31391f87a56SShawn McCarney                 "register": "0xA0",
31491f87a56SShawn McCarney                 "count": 2
31591f87a56SShawn McCarney               }
31691f87a56SShawn McCarney             }
31791f87a56SShawn McCarney         )"_json;
31891f87a56SShawn McCarney         std::unique_ptr<Action> action = parseAction(element);
31991f87a56SShawn McCarney         EXPECT_NE(action.get(), nullptr);
32091f87a56SShawn McCarney     }
32191f87a56SShawn McCarney 
3220e8c68abSShawn McCarney     // Test where works: i2c_compare_bit action type specified
323f09bfe07SBob King     {
324f09bfe07SBob King         const json element = R"(
325f09bfe07SBob King             {
326f09bfe07SBob King               "i2c_compare_bit": {
327f09bfe07SBob King                 "register": "0xA0",
328f09bfe07SBob King                 "position": 3,
329f09bfe07SBob King                 "value": 0
330f09bfe07SBob King               }
331f09bfe07SBob King             }
332f09bfe07SBob King         )"_json;
333f09bfe07SBob King         std::unique_ptr<Action> action = parseAction(element);
334f09bfe07SBob King         EXPECT_NE(action.get(), nullptr);
335f09bfe07SBob King     }
3360e8c68abSShawn McCarney 
3370e8c68abSShawn McCarney     // Test where works: i2c_compare_byte action type specified
338f09bfe07SBob King     {
339f09bfe07SBob King         const json element = R"(
340f09bfe07SBob King             {
341f09bfe07SBob King               "i2c_compare_byte": {
342f09bfe07SBob King                 "register": "0x0A",
343f09bfe07SBob King                 "value": "0xCC"
344f09bfe07SBob King               }
345f09bfe07SBob King             }
346f09bfe07SBob King         )"_json;
347f09bfe07SBob King         std::unique_ptr<Action> action = parseAction(element);
348f09bfe07SBob King         EXPECT_NE(action.get(), nullptr);
349f09bfe07SBob King     }
3500e8c68abSShawn McCarney 
3510e8c68abSShawn McCarney     // Test where works: i2c_compare_bytes action type specified
352f09bfe07SBob King     {
353f09bfe07SBob King         const json element = R"(
354f09bfe07SBob King             {
355f09bfe07SBob King               "i2c_compare_bytes": {
356f09bfe07SBob King                 "register": "0x0A",
357f09bfe07SBob King                 "values": [ "0xCC", "0xFF" ]
358f09bfe07SBob King               }
359f09bfe07SBob King             }
360f09bfe07SBob King         )"_json;
361f09bfe07SBob King         std::unique_ptr<Action> action = parseAction(element);
362f09bfe07SBob King         EXPECT_NE(action.get(), nullptr);
363f09bfe07SBob King     }
3640e8c68abSShawn McCarney 
3650e8c68abSShawn McCarney     // Test where works: i2c_write_bit action type specified
366f617f893SBob King     {
367f617f893SBob King         const json element = R"(
368f617f893SBob King             {
369f617f893SBob King               "i2c_write_bit": {
370f617f893SBob King                 "register": "0xA0",
371f617f893SBob King                 "position": 3,
372f617f893SBob King                 "value": 0
373f617f893SBob King               }
374f617f893SBob King             }
375f617f893SBob King         )"_json;
376f617f893SBob King         std::unique_ptr<Action> action = parseAction(element);
377f617f893SBob King         EXPECT_NE(action.get(), nullptr);
378f617f893SBob King     }
3790e8c68abSShawn McCarney 
3800e8c68abSShawn McCarney     // Test where works: i2c_write_byte action type specified
38187ff9d7dSBob King     {
38287ff9d7dSBob King         const json element = R"(
38387ff9d7dSBob King             {
38487ff9d7dSBob King               "i2c_write_byte": {
38587ff9d7dSBob King                 "register": "0x0A",
38687ff9d7dSBob King                 "value": "0xCC"
38787ff9d7dSBob King               }
38887ff9d7dSBob King             }
38987ff9d7dSBob King         )"_json;
39087ff9d7dSBob King         std::unique_ptr<Action> action = parseAction(element);
39187ff9d7dSBob King         EXPECT_NE(action.get(), nullptr);
39287ff9d7dSBob King     }
3930e8c68abSShawn McCarney 
3940e8c68abSShawn McCarney     // Test where works: i2c_write_bytes action type specified
395bafcb86cSBob King     {
396bafcb86cSBob King         const json element = R"(
397bafcb86cSBob King             {
398bafcb86cSBob King               "i2c_write_bytes": {
399bafcb86cSBob King                 "register": "0x0A",
400bafcb86cSBob King                 "values": [ "0xCC", "0xFF" ]
401bafcb86cSBob King               }
402bafcb86cSBob King             }
403bafcb86cSBob King         )"_json;
404bafcb86cSBob King         std::unique_ptr<Action> action = parseAction(element);
405bafcb86cSBob King         EXPECT_NE(action.get(), nullptr);
406bafcb86cSBob King     }
4070e8c68abSShawn McCarney 
4080e8c68abSShawn McCarney     // Test where works: if action type specified
40993a89d72SBob King     {
41093a89d72SBob King         const json element = R"(
41193a89d72SBob King             {
41293a89d72SBob King               "if":
41393a89d72SBob King               {
41493a89d72SBob King                 "condition": { "run_rule": "is_downlevel_regulator" },
41593a89d72SBob King                 "then": [ { "run_rule": "configure_downlevel_regulator" } ],
41693a89d72SBob King                 "else": [ { "run_rule": "configure_standard_regulator" } ]
41793a89d72SBob King               }
41893a89d72SBob King             }
41993a89d72SBob King         )"_json;
42093a89d72SBob King         std::unique_ptr<Action> action = parseAction(element);
42193a89d72SBob King         EXPECT_NE(action.get(), nullptr);
42293a89d72SBob King     }
4230e8c68abSShawn McCarney 
4241115785fSShawn McCarney     // Test where works: log_phase_fault action type specified
4251115785fSShawn McCarney     {
4261115785fSShawn McCarney         const json element = R"(
4271115785fSShawn McCarney             {
4281115785fSShawn McCarney               "log_phase_fault": {
4291115785fSShawn McCarney                 "type": "n+1"
4301115785fSShawn McCarney               }
4311115785fSShawn McCarney             }
4321115785fSShawn McCarney         )"_json;
4331115785fSShawn McCarney         std::unique_ptr<Action> action = parseAction(element);
4341115785fSShawn McCarney         EXPECT_NE(action.get(), nullptr);
4351115785fSShawn McCarney     }
4361115785fSShawn McCarney 
4370e8c68abSShawn McCarney     // Test where works: not action type specified
438f1b58dc4SBob King     {
439f1b58dc4SBob King         const json element = R"(
440f1b58dc4SBob King             {
441f1b58dc4SBob King               "not":
442f1b58dc4SBob King               { "i2c_compare_byte": { "register": "0xA0", "value": "0xFF" } }
443f1b58dc4SBob King             }
444f1b58dc4SBob King         )"_json;
445f1b58dc4SBob King         std::unique_ptr<Action> action = parseAction(element);
446f1b58dc4SBob King         EXPECT_NE(action.get(), nullptr);
447f1b58dc4SBob King     }
4480e8c68abSShawn McCarney 
4490e8c68abSShawn McCarney     // Test where works: or action type specified
4500b51a9b2SBob King     {
4510b51a9b2SBob King         const json element = R"(
4520b51a9b2SBob King             {
4530b51a9b2SBob King               "or": [
4540b51a9b2SBob King                 { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
4550b51a9b2SBob King                 { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
4560b51a9b2SBob King               ]
4570b51a9b2SBob King             }
4580b51a9b2SBob King         )"_json;
4590b51a9b2SBob King         std::unique_ptr<Action> action = parseAction(element);
4600b51a9b2SBob King         EXPECT_NE(action.get(), nullptr);
4610b51a9b2SBob King     }
4620e8c68abSShawn McCarney 
4630e8c68abSShawn McCarney     // Test where works: pmbus_read_sensor action type specified
46484614882SBob King     {
46584614882SBob King         const json element = R"(
46684614882SBob King             {
46784614882SBob King               "pmbus_read_sensor": {
46884614882SBob King                 "type": "iout",
46984614882SBob King                 "command": "0x8C",
47084614882SBob King                 "format": "linear_11"
47184614882SBob King               }
47284614882SBob King             }
47384614882SBob King         )"_json;
47484614882SBob King         std::unique_ptr<Action> action = parseAction(element);
47584614882SBob King         EXPECT_NE(action.get(), nullptr);
47684614882SBob King     }
4770e8c68abSShawn McCarney 
4780e8c68abSShawn McCarney     // Test where works: pmbus_write_vout_command action type specified
4790e8c68abSShawn McCarney     {
4800e8c68abSShawn McCarney         const json element = R"(
4810e8c68abSShawn McCarney             {
4820e8c68abSShawn McCarney               "pmbus_write_vout_command": {
4830e8c68abSShawn McCarney                 "format": "linear"
4840e8c68abSShawn McCarney               }
4850e8c68abSShawn McCarney             }
4860e8c68abSShawn McCarney         )"_json;
4870e8c68abSShawn McCarney         std::unique_ptr<Action> action = parseAction(element);
4880e8c68abSShawn McCarney         EXPECT_NE(action.get(), nullptr);
4890e8c68abSShawn McCarney     }
4900e8c68abSShawn McCarney 
4910e8c68abSShawn McCarney     // Test where works: run_rule action type specified
492315b0b62SBob King     {
493315b0b62SBob King         const json element = R"(
494315b0b62SBob King             {
495315b0b62SBob King               "run_rule": "set_voltage_rule"
496315b0b62SBob King             }
497315b0b62SBob King         )"_json;
498315b0b62SBob King         std::unique_ptr<Action> action = parseAction(element);
499315b0b62SBob King         EXPECT_NE(action.get(), nullptr);
500315b0b62SBob King     }
5010e8c68abSShawn McCarney 
5020e8c68abSShawn McCarney     // Test where works: set_device action type specified
50318a68505SBob King     {
50418a68505SBob King         const json element = R"(
50518a68505SBob King             {
50618a68505SBob King               "set_device": "io_expander2"
50718a68505SBob King             }
50818a68505SBob King         )"_json;
50918a68505SBob King         std::unique_ptr<Action> action = parseAction(element);
51018a68505SBob King         EXPECT_NE(action.get(), nullptr);
51118a68505SBob King     }
5120e8c68abSShawn McCarney 
5130e8c68abSShawn McCarney     // Test where fails: Element is not an object
5140e8c68abSShawn McCarney     try
5150e8c68abSShawn McCarney     {
5160e8c68abSShawn McCarney         const json element = R"( [ "0xFF", "0x01" ] )"_json;
5170e8c68abSShawn McCarney         parseAction(element);
5180e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
5190e8c68abSShawn McCarney     }
5200e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
5210e8c68abSShawn McCarney     {
5220e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an object");
5230e8c68abSShawn McCarney     }
5240e8c68abSShawn McCarney 
5250e8c68abSShawn McCarney     // Test where fails: No action type specified
5260e8c68abSShawn McCarney     try
5270e8c68abSShawn McCarney     {
5280e8c68abSShawn McCarney         const json element = R"(
5290e8c68abSShawn McCarney             {
5300e8c68abSShawn McCarney               "comments": [ "Set output voltage." ]
5310e8c68abSShawn McCarney             }
5320e8c68abSShawn McCarney         )"_json;
5330e8c68abSShawn McCarney         parseAction(element);
5340e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
5350e8c68abSShawn McCarney     }
5360e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
5370e8c68abSShawn McCarney     {
5380e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Required action type property missing");
5390e8c68abSShawn McCarney     }
5400e8c68abSShawn McCarney 
5410e8c68abSShawn McCarney     // Test where fails: Multiple action types specified
5420e70113dSBob King     try
5430e70113dSBob King     {
5440e70113dSBob King         const json element = R"(
5450e70113dSBob King             {
5460e70113dSBob King               "pmbus_write_vout_command": { "format": "linear" },
5470e70113dSBob King               "run_rule": "set_voltage_rule"
5480e70113dSBob King             }
5490e70113dSBob King         )"_json;
5500e70113dSBob King         parseAction(element);
5510e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
5520e70113dSBob King     }
5530e70113dSBob King     catch (const std::invalid_argument& e)
5540e70113dSBob King     {
5550e70113dSBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
5560e70113dSBob King     }
5570e8c68abSShawn McCarney 
5580e8c68abSShawn McCarney     // Test where fails: Invalid property specified
5590e8c68abSShawn McCarney     try
5600e8c68abSShawn McCarney     {
5610e8c68abSShawn McCarney         const json element = R"(
5620e8c68abSShawn McCarney             {
5630e8c68abSShawn McCarney               "remarks": [ "Set output voltage." ],
5640e8c68abSShawn McCarney               "pmbus_write_vout_command": {
5650e8c68abSShawn McCarney                 "format": "linear"
5660e8c68abSShawn McCarney               }
5670e8c68abSShawn McCarney             }
5680e8c68abSShawn McCarney         )"_json;
5690e8c68abSShawn McCarney         parseAction(element);
5700e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
5710e8c68abSShawn McCarney     }
5720e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
5730e8c68abSShawn McCarney     {
5740e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an invalid property");
5750e8c68abSShawn McCarney     }
5760e8c68abSShawn McCarney }
5770e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseActionArray)5780e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseActionArray)
5790e8c68abSShawn McCarney {
5800e8c68abSShawn McCarney     // Test where works
5810e8c68abSShawn McCarney     {
5820e8c68abSShawn McCarney         const json element = R"(
5830e8c68abSShawn McCarney             [
5840e8c68abSShawn McCarney               { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
5850e8c68abSShawn McCarney               { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
5860e8c68abSShawn McCarney             ]
5870e8c68abSShawn McCarney         )"_json;
5880e8c68abSShawn McCarney         std::vector<std::unique_ptr<Action>> actions =
5890e8c68abSShawn McCarney             parseActionArray(element);
5900e8c68abSShawn McCarney         EXPECT_EQ(actions.size(), 2);
5910e8c68abSShawn McCarney     }
5920e8c68abSShawn McCarney 
5930e8c68abSShawn McCarney     // Test where fails: Element is not an array
5940e8c68abSShawn McCarney     try
5950e8c68abSShawn McCarney     {
5960e8c68abSShawn McCarney         const json element = R"(
5970e8c68abSShawn McCarney             {
5980e8c68abSShawn McCarney               "foo": "bar"
5990e8c68abSShawn McCarney             }
6000e8c68abSShawn McCarney         )"_json;
6010e8c68abSShawn McCarney         parseActionArray(element);
6020e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
6030e8c68abSShawn McCarney     }
6040e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
6050e8c68abSShawn McCarney     {
6060e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an array");
6070e8c68abSShawn McCarney     }
6080e8c68abSShawn McCarney }
6090e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseAnd)6103a787540SBob King TEST(ConfigFileParserTests, ParseAnd)
6113a787540SBob King {
6123a787540SBob King     // Test where works: Element is an array with 2 actions
6133a787540SBob King     {
6143a787540SBob King         const json element = R"(
6153a787540SBob King             [
6163a787540SBob King               { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
6173a787540SBob King               { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
6183a787540SBob King             ]
6193a787540SBob King         )"_json;
6203a787540SBob King         std::unique_ptr<AndAction> action = parseAnd(element);
6213a787540SBob King         EXPECT_EQ(action->getActions().size(), 2);
6223a787540SBob King     }
6233a787540SBob King 
6243a787540SBob King     // Test where fails: Element is an array with 1 action
6253a787540SBob King     try
6263a787540SBob King     {
6273a787540SBob King         const json element = R"(
6283a787540SBob King             [
6293a787540SBob King               { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }
6303a787540SBob King             ]
6313a787540SBob King         )"_json;
6323a787540SBob King         parseAnd(element);
6333a787540SBob King         ADD_FAILURE() << "Should not have reached this line.";
6343a787540SBob King     }
6353a787540SBob King     catch (const std::invalid_argument& e)
6363a787540SBob King     {
6373a787540SBob King         EXPECT_STREQ(e.what(), "Array must contain two or more actions");
6383a787540SBob King     }
6393a787540SBob King 
6403a787540SBob King     // Test where fails: Element is not an array
6413a787540SBob King     try
6423a787540SBob King     {
6433a787540SBob King         const json element = R"(
6443a787540SBob King             {
6453a787540SBob King               "foo": "bar"
6463a787540SBob King             }
6473a787540SBob King         )"_json;
6483a787540SBob King         parseAnd(element);
6493a787540SBob King         ADD_FAILURE() << "Should not have reached this line.";
6503a787540SBob King     }
6513a787540SBob King     catch (const std::invalid_argument& e)
6523a787540SBob King     {
6533a787540SBob King         EXPECT_STREQ(e.what(), "Element is not an array");
6543a787540SBob King     }
6553a787540SBob King }
6563a787540SBob King 
TEST(ConfigFileParserTests,ParseBitPosition)657f617f893SBob King TEST(ConfigFileParserTests, ParseBitPosition)
658f617f893SBob King {
659f617f893SBob King     // Test where works: 0
660f617f893SBob King     {
661f617f893SBob King         const json element = R"( 0 )"_json;
662f617f893SBob King         uint8_t value = parseBitPosition(element);
663f617f893SBob King         EXPECT_EQ(value, 0);
664f617f893SBob King     }
665f617f893SBob King 
666f617f893SBob King     // Test where works: 7
667f617f893SBob King     {
668f617f893SBob King         const json element = R"( 7 )"_json;
669f617f893SBob King         uint8_t value = parseBitPosition(element);
670f617f893SBob King         EXPECT_EQ(value, 7);
671f617f893SBob King     }
672f617f893SBob King 
673f617f893SBob King     // Test where fails: Element is not an integer
674f617f893SBob King     try
675f617f893SBob King     {
676f617f893SBob King         const json element = R"( 1.03 )"_json;
677f617f893SBob King         parseBitPosition(element);
678f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
679f617f893SBob King     }
680f617f893SBob King     catch (const std::invalid_argument& e)
681f617f893SBob King     {
682f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not an integer");
683f617f893SBob King     }
684f617f893SBob King 
685f617f893SBob King     // Test where fails: Value < 0
686f617f893SBob King     try
687f617f893SBob King     {
688f617f893SBob King         const json element = R"( -1 )"_json;
689f617f893SBob King         parseBitPosition(element);
690f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
691f617f893SBob King     }
692f617f893SBob King     catch (const std::invalid_argument& e)
693f617f893SBob King     {
694f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not a bit position");
695f617f893SBob King     }
696f617f893SBob King 
697f617f893SBob King     // Test where fails: Value > 7
698f617f893SBob King     try
699f617f893SBob King     {
700f617f893SBob King         const json element = R"( 8 )"_json;
701f617f893SBob King         parseBitPosition(element);
702f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
703f617f893SBob King     }
704f617f893SBob King     catch (const std::invalid_argument& e)
705f617f893SBob King     {
706f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not a bit position");
707f617f893SBob King     }
708f617f893SBob King }
709f617f893SBob King 
TEST(ConfigFileParserTests,ParseBitValue)710f617f893SBob King TEST(ConfigFileParserTests, ParseBitValue)
711f617f893SBob King {
712f617f893SBob King     // Test where works: 0
713f617f893SBob King     {
714f617f893SBob King         const json element = R"( 0 )"_json;
715f617f893SBob King         uint8_t value = parseBitValue(element);
716f617f893SBob King         EXPECT_EQ(value, 0);
717f617f893SBob King     }
718f617f893SBob King 
719f617f893SBob King     // Test where works: 1
720f617f893SBob King     {
721f617f893SBob King         const json element = R"( 1 )"_json;
722f617f893SBob King         uint8_t value = parseBitValue(element);
723f617f893SBob King         EXPECT_EQ(value, 1);
724f617f893SBob King     }
725f617f893SBob King 
726f617f893SBob King     // Test where fails: Element is not an integer
727f617f893SBob King     try
728f617f893SBob King     {
729f617f893SBob King         const json element = R"( 0.5 )"_json;
730f617f893SBob King         parseBitValue(element);
731f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
732f617f893SBob King     }
733f617f893SBob King     catch (const std::invalid_argument& e)
734f617f893SBob King     {
735f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not an integer");
736f617f893SBob King     }
737f617f893SBob King 
738f617f893SBob King     // Test where fails: Value < 0
739f617f893SBob King     try
740f617f893SBob King     {
741f617f893SBob King         const json element = R"( -1 )"_json;
742f617f893SBob King         parseBitValue(element);
743f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
744f617f893SBob King     }
745f617f893SBob King     catch (const std::invalid_argument& e)
746f617f893SBob King     {
747f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not a bit value");
748f617f893SBob King     }
749f617f893SBob King 
750f617f893SBob King     // Test where fails: Value > 1
751f617f893SBob King     try
752f617f893SBob King     {
753f617f893SBob King         const json element = R"( 2 )"_json;
754f617f893SBob King         parseBitValue(element);
755f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
756f617f893SBob King     }
757f617f893SBob King     catch (const std::invalid_argument& e)
758f617f893SBob King     {
759f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not a bit value");
760f617f893SBob King     }
761f617f893SBob King }
762f617f893SBob King 
TEST(ConfigFileParserTests,ParseBoolean)7630e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseBoolean)
7640e8c68abSShawn McCarney {
7650e8c68abSShawn McCarney     // Test where works: true
7660e8c68abSShawn McCarney     {
7670e8c68abSShawn McCarney         const json element = R"( true )"_json;
7680e8c68abSShawn McCarney         bool value = parseBoolean(element);
7690e8c68abSShawn McCarney         EXPECT_EQ(value, true);
7700e8c68abSShawn McCarney     }
7710e8c68abSShawn McCarney 
7720e8c68abSShawn McCarney     // Test where works: false
7730e8c68abSShawn McCarney     {
7740e8c68abSShawn McCarney         const json element = R"( false )"_json;
7750e8c68abSShawn McCarney         bool value = parseBoolean(element);
7760e8c68abSShawn McCarney         EXPECT_EQ(value, false);
7770e8c68abSShawn McCarney     }
7780e8c68abSShawn McCarney 
7790e8c68abSShawn McCarney     // Test where fails: Element is not a boolean
7800e8c68abSShawn McCarney     try
7810e8c68abSShawn McCarney     {
7820e8c68abSShawn McCarney         const json element = R"( 1 )"_json;
7830e8c68abSShawn McCarney         parseBoolean(element);
7840e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
7850e8c68abSShawn McCarney     }
7860e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
7870e8c68abSShawn McCarney     {
7880e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a boolean");
7890e8c68abSShawn McCarney     }
7900e8c68abSShawn McCarney }
7910e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseChassis)7920e70113dSBob King TEST(ConfigFileParserTests, ParseChassis)
7930e70113dSBob King {
7940e70113dSBob King     // Test where works: Only required properties specified
7950e70113dSBob King     {
7960e70113dSBob King         const json element = R"(
7970e70113dSBob King             {
7984c88a4c2SShawn McCarney               "number": 1,
7994c88a4c2SShawn McCarney               "inventory_path": "system/chassis1"
8000e70113dSBob King             }
8010e70113dSBob King         )"_json;
8020e70113dSBob King         std::unique_ptr<Chassis> chassis = parseChassis(element);
8030e70113dSBob King         EXPECT_EQ(chassis->getNumber(), 1);
804cb3f6a63SShawn McCarney         EXPECT_EQ(chassis->getInventoryPath(),
8054c88a4c2SShawn McCarney                   "/xyz/openbmc_project/inventory/system/chassis1");
8069c36c5fbSBob King         EXPECT_EQ(chassis->getDevices().size(), 0);
8070e70113dSBob King     }
8080e70113dSBob King 
8090e70113dSBob King     // Test where works: All properties specified
8100e70113dSBob King     {
8110e70113dSBob King         const json element = R"(
8120e70113dSBob King             {
8130e70113dSBob King               "comments": [ "comments property" ],
8140e70113dSBob King               "number": 2,
815cb3f6a63SShawn McCarney               "inventory_path": "system/chassis2",
8160e70113dSBob King               "devices": [
8170e70113dSBob King                 {
8180e70113dSBob King                   "id": "vdd_regulator",
8190e70113dSBob King                   "is_regulator": true,
820a76898f1SBob King                   "fru": "system/chassis/motherboard/regulator2",
8210e70113dSBob King                   "i2c_interface":
8220e70113dSBob King                   {
8230e70113dSBob King                       "bus": 1,
8240e70113dSBob King                       "address": "0x70"
8250e70113dSBob King                   }
8260e70113dSBob King                 }
8270e70113dSBob King               ]
8280e70113dSBob King             }
8290e70113dSBob King         )"_json;
8300e70113dSBob King         std::unique_ptr<Chassis> chassis = parseChassis(element);
8310e70113dSBob King         EXPECT_EQ(chassis->getNumber(), 2);
832cb3f6a63SShawn McCarney         EXPECT_EQ(chassis->getInventoryPath(),
833cb3f6a63SShawn McCarney                   "/xyz/openbmc_project/inventory/system/chassis2");
8349c36c5fbSBob King         EXPECT_EQ(chassis->getDevices().size(), 1);
8359c36c5fbSBob King         EXPECT_EQ(chassis->getDevices()[0]->getID(), "vdd_regulator");
8360e70113dSBob King     }
8370e70113dSBob King 
8380e70113dSBob King     // Test where fails: number value is invalid
8390e70113dSBob King     try
8400e70113dSBob King     {
8410e70113dSBob King         const json element = R"(
8420e70113dSBob King             {
8434c88a4c2SShawn McCarney               "number": 0.5,
8444c88a4c2SShawn McCarney               "inventory_path": "system/chassis"
8450e70113dSBob King             }
8460e70113dSBob King         )"_json;
8470e70113dSBob King         parseChassis(element);
8480e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
8490e70113dSBob King     }
8500e70113dSBob King     catch (const std::invalid_argument& e)
8510e70113dSBob King     {
8520e70113dSBob King         EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
8530e70113dSBob King     }
8540e70113dSBob King 
855cb3f6a63SShawn McCarney     // Test where fails: inventory_path is invalid: Not a string
856cb3f6a63SShawn McCarney     try
857cb3f6a63SShawn McCarney     {
858cb3f6a63SShawn McCarney         const json element = R"(
859cb3f6a63SShawn McCarney             {
860cb3f6a63SShawn McCarney               "number": 2,
861cb3f6a63SShawn McCarney               "inventory_path": true
862cb3f6a63SShawn McCarney             }
863cb3f6a63SShawn McCarney         )"_json;
864cb3f6a63SShawn McCarney         parseChassis(element);
865cb3f6a63SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
866cb3f6a63SShawn McCarney     }
867cb3f6a63SShawn McCarney     catch (const std::invalid_argument& e)
868cb3f6a63SShawn McCarney     {
869cb3f6a63SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a string");
870cb3f6a63SShawn McCarney     }
871cb3f6a63SShawn McCarney 
872cb3f6a63SShawn McCarney     // Test where fails: inventory_path is invalid: Empty string
873cb3f6a63SShawn McCarney     try
874cb3f6a63SShawn McCarney     {
875cb3f6a63SShawn McCarney         const json element = R"(
876cb3f6a63SShawn McCarney             {
877cb3f6a63SShawn McCarney               "number": 2,
878cb3f6a63SShawn McCarney               "inventory_path": ""
879cb3f6a63SShawn McCarney             }
880cb3f6a63SShawn McCarney         )"_json;
881cb3f6a63SShawn McCarney         parseChassis(element);
882cb3f6a63SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
883cb3f6a63SShawn McCarney     }
884cb3f6a63SShawn McCarney     catch (const std::invalid_argument& e)
885cb3f6a63SShawn McCarney     {
886cb3f6a63SShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an empty string");
887cb3f6a63SShawn McCarney     }
888cb3f6a63SShawn McCarney 
8890e70113dSBob King     // Test where fails: Invalid property specified
8900e70113dSBob King     try
8910e70113dSBob King     {
8920e70113dSBob King         const json element = R"(
8930e70113dSBob King             {
8940e70113dSBob King               "number": 1,
8954c88a4c2SShawn McCarney               "inventory_path": "system/chassis",
8960e70113dSBob King               "foo": 2
8970e70113dSBob King             }
8980e70113dSBob King         )"_json;
8990e70113dSBob King         parseChassis(element);
9000e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
9010e70113dSBob King     }
9020e70113dSBob King     catch (const std::invalid_argument& e)
9030e70113dSBob King     {
9040e70113dSBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
9050e70113dSBob King     }
9060e70113dSBob King 
9070e70113dSBob King     // Test where fails: Required number property not specified
9080e70113dSBob King     try
9090e70113dSBob King     {
9100e70113dSBob King         const json element = R"(
9110e70113dSBob King             {
9124c88a4c2SShawn McCarney               "inventory_path": "system/chassis"
9130e70113dSBob King             }
9140e70113dSBob King         )"_json;
9150e70113dSBob King         parseChassis(element);
9160e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
9170e70113dSBob King     }
9180e70113dSBob King     catch (const std::invalid_argument& e)
9190e70113dSBob King     {
9200e70113dSBob King         EXPECT_STREQ(e.what(), "Required property missing: number");
9210e70113dSBob King     }
9220e70113dSBob King 
9234c88a4c2SShawn McCarney     // Test where fails: Required inventory_path property not specified
9244c88a4c2SShawn McCarney     try
9254c88a4c2SShawn McCarney     {
9264c88a4c2SShawn McCarney         const json element = R"(
9274c88a4c2SShawn McCarney             {
9284c88a4c2SShawn McCarney               "number": 1
9294c88a4c2SShawn McCarney             }
9304c88a4c2SShawn McCarney         )"_json;
9314c88a4c2SShawn McCarney         parseChassis(element);
9324c88a4c2SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
9334c88a4c2SShawn McCarney     }
9344c88a4c2SShawn McCarney     catch (const std::invalid_argument& e)
9354c88a4c2SShawn McCarney     {
9364c88a4c2SShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: inventory_path");
9374c88a4c2SShawn McCarney     }
9384c88a4c2SShawn McCarney 
9390e70113dSBob King     // Test where fails: Element is not an object
9400e70113dSBob King     try
9410e70113dSBob King     {
9420e70113dSBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
9430e70113dSBob King         parseChassis(element);
9440e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
9450e70113dSBob King     }
9460e70113dSBob King     catch (const std::invalid_argument& e)
9470e70113dSBob King     {
9480e70113dSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
9490e70113dSBob King     }
9500e70113dSBob King 
9510e70113dSBob King     // Test where fails: number value is < 1
9520e70113dSBob King     try
9530e70113dSBob King     {
9540e70113dSBob King         const json element = R"(
9550e70113dSBob King             {
9564c88a4c2SShawn McCarney               "number": 0,
9574c88a4c2SShawn McCarney               "inventory_path": "system/chassis"
9580e70113dSBob King             }
9590e70113dSBob King         )"_json;
9600e70113dSBob King         parseChassis(element);
9610e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
9620e70113dSBob King     }
9630e70113dSBob King     catch (const std::invalid_argument& e)
9640e70113dSBob King     {
9650e70113dSBob King         EXPECT_STREQ(e.what(), "Invalid chassis number: Must be > 0");
9660e70113dSBob King     }
9670e70113dSBob King 
9680e70113dSBob King     // Test where fails: devices value is invalid
9690e70113dSBob King     try
9700e70113dSBob King     {
9710e70113dSBob King         const json element = R"(
9720e70113dSBob King             {
9730e70113dSBob King               "number": 1,
9744c88a4c2SShawn McCarney               "inventory_path": "system/chassis",
9750e70113dSBob King               "devices": 2
9760e70113dSBob King             }
9770e70113dSBob King         )"_json;
9780e70113dSBob King         parseChassis(element);
9790e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
9800e70113dSBob King     }
9810e70113dSBob King     catch (const std::invalid_argument& e)
9820e70113dSBob King     {
9830e70113dSBob King         EXPECT_STREQ(e.what(), "Element is not an array");
9840e70113dSBob King     }
9850e70113dSBob King }
9860e70113dSBob King 
TEST(ConfigFileParserTests,ParseChassisArray)9870e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseChassisArray)
9880e8c68abSShawn McCarney {
9890e70113dSBob King     // Test where works
9900e70113dSBob King     {
9910e70113dSBob King         const json element = R"(
9920e70113dSBob King             [
9934c88a4c2SShawn McCarney               { "number": 1, "inventory_path": "system/chassis1" },
9944c88a4c2SShawn McCarney               { "number": 2, "inventory_path": "system/chassis2" }
9950e70113dSBob King             ]
9960e70113dSBob King         )"_json;
9970e70113dSBob King         std::vector<std::unique_ptr<Chassis>> chassis =
9980e70113dSBob King             parseChassisArray(element);
9990e70113dSBob King         EXPECT_EQ(chassis.size(), 2);
10000e70113dSBob King         EXPECT_EQ(chassis[0]->getNumber(), 1);
10014c88a4c2SShawn McCarney         EXPECT_EQ(chassis[0]->getInventoryPath(),
10024c88a4c2SShawn McCarney                   "/xyz/openbmc_project/inventory/system/chassis1");
10030e70113dSBob King         EXPECT_EQ(chassis[1]->getNumber(), 2);
10044c88a4c2SShawn McCarney         EXPECT_EQ(chassis[1]->getInventoryPath(),
10054c88a4c2SShawn McCarney                   "/xyz/openbmc_project/inventory/system/chassis2");
10060e70113dSBob King     }
10070e70113dSBob King 
10080e70113dSBob King     // Test where fails: Element is not an array
10090e70113dSBob King     try
10100e70113dSBob King     {
10110e70113dSBob King         const json element = R"(
10120e70113dSBob King             {
10130e70113dSBob King               "foo": "bar"
10140e70113dSBob King             }
10150e70113dSBob King         )"_json;
10160e70113dSBob King         parseChassisArray(element);
10170e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
10180e70113dSBob King     }
10190e70113dSBob King     catch (const std::invalid_argument& e)
10200e70113dSBob King     {
10210e70113dSBob King         EXPECT_STREQ(e.what(), "Element is not an array");
10220e70113dSBob King     }
10230e8c68abSShawn McCarney }
10240e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseComparePresence)1025b267b7ebSBob King TEST(ConfigFileParserTests, ParseComparePresence)
1026b267b7ebSBob King {
1027b267b7ebSBob King     // Test where works
1028b267b7ebSBob King     {
1029b267b7ebSBob King         const json element = R"(
1030b267b7ebSBob King             {
1031a76898f1SBob King               "fru": "system/chassis/motherboard/cpu3",
1032b267b7ebSBob King               "value": true
1033b267b7ebSBob King             }
1034b267b7ebSBob King         )"_json;
1035b267b7ebSBob King         std::unique_ptr<ComparePresenceAction> action =
1036b267b7ebSBob King             parseComparePresence(element);
1037a76898f1SBob King         EXPECT_EQ(
1038a76898f1SBob King             action->getFRU(),
1039a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu3");
1040b267b7ebSBob King         EXPECT_EQ(action->getValue(), true);
1041b267b7ebSBob King     }
1042b267b7ebSBob King 
1043b267b7ebSBob King     // Test where fails: Element is not an object
1044b267b7ebSBob King     try
1045b267b7ebSBob King     {
1046b267b7ebSBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
1047b267b7ebSBob King         parseComparePresence(element);
1048b267b7ebSBob King         ADD_FAILURE() << "Should not have reached this line.";
1049b267b7ebSBob King     }
1050b267b7ebSBob King     catch (const std::invalid_argument& e)
1051b267b7ebSBob King     {
1052b267b7ebSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
1053b267b7ebSBob King     }
1054b267b7ebSBob King 
1055b267b7ebSBob King     // Test where fails: Invalid property specified
1056b267b7ebSBob King     try
1057b267b7ebSBob King     {
1058b267b7ebSBob King         const json element = R"(
1059b267b7ebSBob King             {
1060a76898f1SBob King               "fru": "system/chassis/motherboard/cpu3",
1061b267b7ebSBob King               "value": true,
1062b267b7ebSBob King               "foo" : true
1063b267b7ebSBob King             }
1064b267b7ebSBob King         )"_json;
1065b267b7ebSBob King         parseComparePresence(element);
1066b267b7ebSBob King         ADD_FAILURE() << "Should not have reached this line.";
1067b267b7ebSBob King     }
1068b267b7ebSBob King     catch (const std::invalid_argument& e)
1069b267b7ebSBob King     {
1070b267b7ebSBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
1071b267b7ebSBob King     }
1072b267b7ebSBob King 
1073b267b7ebSBob King     // Test where fails: Required fru property not specified
1074b267b7ebSBob King     try
1075b267b7ebSBob King     {
1076b267b7ebSBob King         const json element = R"(
1077b267b7ebSBob King             {
1078b267b7ebSBob King               "value": true
1079b267b7ebSBob King             }
1080b267b7ebSBob King         )"_json;
1081b267b7ebSBob King         parseComparePresence(element);
1082b267b7ebSBob King         ADD_FAILURE() << "Should not have reached this line.";
1083b267b7ebSBob King     }
1084b267b7ebSBob King     catch (const std::invalid_argument& e)
1085b267b7ebSBob King     {
1086b267b7ebSBob King         EXPECT_STREQ(e.what(), "Required property missing: fru");
1087b267b7ebSBob King     }
1088b267b7ebSBob King 
1089b267b7ebSBob King     // Test where fails: Required value property not specified
1090b267b7ebSBob King     try
1091b267b7ebSBob King     {
1092b267b7ebSBob King         const json element = R"(
1093b267b7ebSBob King             {
1094a76898f1SBob King               "fru": "system/chassis/motherboard/cpu3"
1095b267b7ebSBob King             }
1096b267b7ebSBob King         )"_json;
1097b267b7ebSBob King         parseComparePresence(element);
1098b267b7ebSBob King         ADD_FAILURE() << "Should not have reached this line.";
1099b267b7ebSBob King     }
1100b267b7ebSBob King     catch (const std::invalid_argument& e)
1101b267b7ebSBob King     {
1102b267b7ebSBob King         EXPECT_STREQ(e.what(), "Required property missing: value");
1103b267b7ebSBob King     }
1104b267b7ebSBob King 
1105b267b7ebSBob King     // Test where fails: fru value is invalid
1106b267b7ebSBob King     try
1107b267b7ebSBob King     {
1108b267b7ebSBob King         const json element = R"(
1109b267b7ebSBob King             {
1110b267b7ebSBob King               "fru": 1,
1111b267b7ebSBob King               "value": true
1112b267b7ebSBob King             }
1113b267b7ebSBob King         )"_json;
1114b267b7ebSBob King         parseComparePresence(element);
1115b267b7ebSBob King         ADD_FAILURE() << "Should not have reached this line.";
1116b267b7ebSBob King     }
1117b267b7ebSBob King     catch (const std::invalid_argument& e)
1118b267b7ebSBob King     {
1119b267b7ebSBob King         EXPECT_STREQ(e.what(), "Element is not a string");
1120b267b7ebSBob King     }
1121b267b7ebSBob King 
1122b267b7ebSBob King     // Test where fails: value value is invalid
1123b267b7ebSBob King     try
1124b267b7ebSBob King     {
1125b267b7ebSBob King         const json element = R"(
1126b267b7ebSBob King             {
1127a76898f1SBob King               "fru": "system/chassis/motherboard/cpu3",
1128b267b7ebSBob King               "value": 1
1129b267b7ebSBob King             }
1130b267b7ebSBob King         )"_json;
1131b267b7ebSBob King         parseComparePresence(element);
1132b267b7ebSBob King         ADD_FAILURE() << "Should not have reached this line.";
1133b267b7ebSBob King     }
1134b267b7ebSBob King     catch (const std::invalid_argument& e)
1135b267b7ebSBob King     {
1136b267b7ebSBob King         EXPECT_STREQ(e.what(), "Element is not a boolean");
1137b267b7ebSBob King     }
1138b267b7ebSBob King }
1139b267b7ebSBob King 
TEST(ConfigFileParserTests,ParseCompareVPD)1140f2134320SBob King TEST(ConfigFileParserTests, ParseCompareVPD)
1141f2134320SBob King {
1142a2a830b1SShawn McCarney     // Test where works: value property: Not empty
1143f2134320SBob King     {
1144f2134320SBob King         const json element = R"(
1145f2134320SBob King             {
1146a76898f1SBob King               "fru": "system/chassis/disk_backplane",
1147f2134320SBob King               "keyword": "CCIN",
1148f2134320SBob King               "value": "2D35"
1149f2134320SBob King             }
1150f2134320SBob King         )"_json;
1151f2134320SBob King         std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element);
1152a76898f1SBob King         EXPECT_EQ(
1153a76898f1SBob King             action->getFRU(),
1154a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
1155f2134320SBob King         EXPECT_EQ(action->getKeyword(), "CCIN");
1156aacc2aafSMatt Spinler         EXPECT_EQ(action->getValue(),
1157aacc2aafSMatt Spinler                   (std::vector<uint8_t>{0x32, 0x44, 0x33, 0x35}));
1158aacc2aafSMatt Spinler     }
1159aacc2aafSMatt Spinler 
1160a2a830b1SShawn McCarney     // Test where works: value property: Empty
1161a2a830b1SShawn McCarney     {
1162a2a830b1SShawn McCarney         const json element = R"(
1163a2a830b1SShawn McCarney             {
1164a2a830b1SShawn McCarney               "fru": "system/chassis/disk_backplane",
1165a2a830b1SShawn McCarney               "keyword": "CCIN",
1166a2a830b1SShawn McCarney               "value": ""
1167a2a830b1SShawn McCarney             }
1168a2a830b1SShawn McCarney         )"_json;
1169a2a830b1SShawn McCarney         std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element);
1170a2a830b1SShawn McCarney         EXPECT_EQ(
1171a2a830b1SShawn McCarney             action->getFRU(),
1172a2a830b1SShawn McCarney             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
1173a2a830b1SShawn McCarney         EXPECT_EQ(action->getKeyword(), "CCIN");
1174a2a830b1SShawn McCarney         EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{}));
1175a2a830b1SShawn McCarney     }
1176a2a830b1SShawn McCarney 
1177a2a830b1SShawn McCarney     // Test where works: byte_values property: Not empty
1178aacc2aafSMatt Spinler     {
1179aacc2aafSMatt Spinler         const json element = R"(
1180aacc2aafSMatt Spinler             {
1181aacc2aafSMatt Spinler               "fru": "system/chassis/disk_backplane",
1182aacc2aafSMatt Spinler               "keyword": "CCIN",
1183aacc2aafSMatt Spinler               "byte_values": ["0x11", "0x22", "0x33"]
1184aacc2aafSMatt Spinler             }
1185aacc2aafSMatt Spinler         )"_json;
1186aacc2aafSMatt Spinler         std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element);
1187aacc2aafSMatt Spinler         EXPECT_EQ(
1188aacc2aafSMatt Spinler             action->getFRU(),
1189aacc2aafSMatt Spinler             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
1190aacc2aafSMatt Spinler         EXPECT_EQ(action->getKeyword(), "CCIN");
1191aacc2aafSMatt Spinler         EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{0x11, 0x22, 0x33}));
1192f2134320SBob King     }
1193f2134320SBob King 
1194a2a830b1SShawn McCarney     // Test where works: byte_values property: Empty
1195a2a830b1SShawn McCarney     {
1196a2a830b1SShawn McCarney         const json element = R"(
1197a2a830b1SShawn McCarney             {
1198a2a830b1SShawn McCarney               "fru": "system/chassis/disk_backplane",
1199a2a830b1SShawn McCarney               "keyword": "CCIN",
1200a2a830b1SShawn McCarney               "byte_values": []
1201a2a830b1SShawn McCarney             }
1202a2a830b1SShawn McCarney         )"_json;
1203a2a830b1SShawn McCarney         std::unique_ptr<CompareVPDAction> action = parseCompareVPD(element);
1204a2a830b1SShawn McCarney         EXPECT_EQ(
1205a2a830b1SShawn McCarney             action->getFRU(),
1206a2a830b1SShawn McCarney             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
1207a2a830b1SShawn McCarney         EXPECT_EQ(action->getKeyword(), "CCIN");
1208a2a830b1SShawn McCarney         EXPECT_EQ(action->getValue(), (std::vector<uint8_t>{}));
1209a2a830b1SShawn McCarney     }
1210a2a830b1SShawn McCarney 
1211f2134320SBob King     // Test where fails: Element is not an object
1212f2134320SBob King     try
1213f2134320SBob King     {
1214f2134320SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
1215f2134320SBob King         parseCompareVPD(element);
1216f2134320SBob King         ADD_FAILURE() << "Should not have reached this line.";
1217f2134320SBob King     }
1218f2134320SBob King     catch (const std::invalid_argument& e)
1219f2134320SBob King     {
1220f2134320SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
1221f2134320SBob King     }
1222f2134320SBob King 
1223f2134320SBob King     // Test where fails: Invalid property specified
1224f2134320SBob King     try
1225f2134320SBob King     {
1226f2134320SBob King         const json element = R"(
1227f2134320SBob King             {
1228a76898f1SBob King               "fru": "system/chassis/disk_backplane",
1229f2134320SBob King               "keyword": "CCIN",
1230f2134320SBob King               "value": "2D35",
1231f2134320SBob King               "foo" : true
1232f2134320SBob King             }
1233f2134320SBob King         )"_json;
1234f2134320SBob King         parseCompareVPD(element);
1235f2134320SBob King         ADD_FAILURE() << "Should not have reached this line.";
1236f2134320SBob King     }
1237f2134320SBob King     catch (const std::invalid_argument& e)
1238f2134320SBob King     {
1239f2134320SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
1240f2134320SBob King     }
1241f2134320SBob King 
1242f2134320SBob King     // Test where fails: Required fru property not specified
1243f2134320SBob King     try
1244f2134320SBob King     {
1245f2134320SBob King         const json element = R"(
1246f2134320SBob King             {
1247f2134320SBob King               "keyword": "CCIN",
1248f2134320SBob King               "value": "2D35"
1249f2134320SBob King             }
1250f2134320SBob King         )"_json;
1251f2134320SBob King         parseCompareVPD(element);
1252f2134320SBob King         ADD_FAILURE() << "Should not have reached this line.";
1253f2134320SBob King     }
1254f2134320SBob King     catch (const std::invalid_argument& e)
1255f2134320SBob King     {
1256f2134320SBob King         EXPECT_STREQ(e.what(), "Required property missing: fru");
1257f2134320SBob King     }
1258f2134320SBob King 
1259f2134320SBob King     // Test where fails: Required keyword property not specified
1260f2134320SBob King     try
1261f2134320SBob King     {
1262f2134320SBob King         const json element = R"(
1263f2134320SBob King             {
1264a76898f1SBob King               "fru": "system/chassis/disk_backplane",
1265f2134320SBob King               "value": "2D35"
1266f2134320SBob King             }
1267f2134320SBob King         )"_json;
1268f2134320SBob King         parseCompareVPD(element);
1269f2134320SBob King         ADD_FAILURE() << "Should not have reached this line.";
1270f2134320SBob King     }
1271f2134320SBob King     catch (const std::invalid_argument& e)
1272f2134320SBob King     {
1273f2134320SBob King         EXPECT_STREQ(e.what(), "Required property missing: keyword");
1274f2134320SBob King     }
1275f2134320SBob King 
1276f2134320SBob King     // Test where fails: Required value property not specified
1277f2134320SBob King     try
1278f2134320SBob King     {
1279f2134320SBob King         const json element = R"(
1280f2134320SBob King             {
1281a76898f1SBob King               "fru": "system/chassis/disk_backplane",
1282f2134320SBob King               "keyword": "CCIN"
1283f2134320SBob King             }
1284f2134320SBob King         )"_json;
1285f2134320SBob King         parseCompareVPD(element);
1286f2134320SBob King         ADD_FAILURE() << "Should not have reached this line.";
1287f2134320SBob King     }
1288f2134320SBob King     catch (const std::invalid_argument& e)
1289f2134320SBob King     {
1290aacc2aafSMatt Spinler         EXPECT_STREQ(e.what(), "Invalid property: Must contain "
1291aacc2aafSMatt Spinler                                "either value or byte_values");
1292aacc2aafSMatt Spinler     }
1293aacc2aafSMatt Spinler 
1294a2a830b1SShawn McCarney     // Test where fails: both value and byte_values specified
1295aacc2aafSMatt Spinler     try
1296aacc2aafSMatt Spinler     {
1297aacc2aafSMatt Spinler         const json element = R"(
1298aacc2aafSMatt Spinler             {
1299aacc2aafSMatt Spinler               "fru": "system/chassis/disk_backplane",
1300aacc2aafSMatt Spinler               "keyword": "CCIN",
1301aacc2aafSMatt Spinler               "value": "2D35",
1302aacc2aafSMatt Spinler               "byte_values": [ "0x01", "0x02" ]
1303aacc2aafSMatt Spinler             }
1304aacc2aafSMatt Spinler         )"_json;
1305aacc2aafSMatt Spinler         parseCompareVPD(element);
1306aacc2aafSMatt Spinler         ADD_FAILURE() << "Should not have reached this line.";
1307aacc2aafSMatt Spinler     }
1308aacc2aafSMatt Spinler     catch (const std::invalid_argument& e)
1309aacc2aafSMatt Spinler     {
1310aacc2aafSMatt Spinler         EXPECT_STREQ(e.what(), "Invalid property: Must contain "
1311aacc2aafSMatt Spinler                                "either value or byte_values");
1312f2134320SBob King     }
1313f2134320SBob King 
1314f2134320SBob King     // Test where fails: fru value is invalid
1315f2134320SBob King     try
1316f2134320SBob King     {
1317f2134320SBob King         const json element = R"(
1318f2134320SBob King             {
1319f2134320SBob King               "fru": 1,
1320f2134320SBob King               "keyword": "CCIN",
1321f2134320SBob King               "value": "2D35"
1322f2134320SBob King             }
1323f2134320SBob King         )"_json;
1324f2134320SBob King         parseCompareVPD(element);
1325f2134320SBob King         ADD_FAILURE() << "Should not have reached this line.";
1326f2134320SBob King     }
1327f2134320SBob King     catch (const std::invalid_argument& e)
1328f2134320SBob King     {
1329f2134320SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
1330f2134320SBob King     }
1331f2134320SBob King 
1332f2134320SBob King     // Test where fails: keyword value is invalid
1333f2134320SBob King     try
1334f2134320SBob King     {
1335f2134320SBob King         const json element = R"(
1336f2134320SBob King             {
1337a76898f1SBob King               "fru": "system/chassis/disk_backplane",
1338f2134320SBob King               "keyword": 1,
1339f2134320SBob King               "value": "2D35"
1340f2134320SBob King             }
1341f2134320SBob King         )"_json;
1342f2134320SBob King         parseCompareVPD(element);
1343f2134320SBob King         ADD_FAILURE() << "Should not have reached this line.";
1344f2134320SBob King     }
1345f2134320SBob King     catch (const std::invalid_argument& e)
1346f2134320SBob King     {
1347f2134320SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
1348f2134320SBob King     }
1349f2134320SBob King 
1350f2134320SBob King     // Test where fails: value value is invalid
1351f2134320SBob King     try
1352f2134320SBob King     {
1353f2134320SBob King         const json element = R"(
1354f2134320SBob King             {
1355a76898f1SBob King               "fru": "system/chassis/disk_backplane",
1356f2134320SBob King               "keyword": "CCIN",
1357f2134320SBob King               "value": 1
1358f2134320SBob King             }
1359f2134320SBob King         )"_json;
1360f2134320SBob King         parseCompareVPD(element);
1361f2134320SBob King         ADD_FAILURE() << "Should not have reached this line.";
1362f2134320SBob King     }
1363f2134320SBob King     catch (const std::invalid_argument& e)
1364f2134320SBob King     {
1365f2134320SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
1366f2134320SBob King     }
1367aacc2aafSMatt Spinler 
1368aacc2aafSMatt Spinler     // Test where fails: byte_values is wrong format
1369aacc2aafSMatt Spinler     try
1370aacc2aafSMatt Spinler     {
1371aacc2aafSMatt Spinler         const json element = R"(
1372aacc2aafSMatt Spinler             {
1373aacc2aafSMatt Spinler               "fru": "system/chassis/disk_backplane",
1374aacc2aafSMatt Spinler               "keyword": "CCIN",
1375aacc2aafSMatt Spinler               "byte_values": [1, 2, 3]
1376aacc2aafSMatt Spinler             }
1377aacc2aafSMatt Spinler         )"_json;
1378aacc2aafSMatt Spinler         parseCompareVPD(element);
1379aacc2aafSMatt Spinler         ADD_FAILURE() << "Should not have reached this line.";
1380aacc2aafSMatt Spinler     }
1381aacc2aafSMatt Spinler     catch (const std::invalid_argument& e)
1382aacc2aafSMatt Spinler     {
1383aacc2aafSMatt Spinler         EXPECT_STREQ(e.what(), "Element is not a string");
1384aacc2aafSMatt Spinler     }
1385f2134320SBob King }
1386f2134320SBob King 
TEST(ConfigFileParserTests,ParseConfiguration)138733e7eaa5SBob King TEST(ConfigFileParserTests, ParseConfiguration)
138833e7eaa5SBob King {
138933e7eaa5SBob King     // Test where works: actions required property specified
139033e7eaa5SBob King     {
139133e7eaa5SBob King         const json element = R"(
139233e7eaa5SBob King             {
139333e7eaa5SBob King               "actions": [
139433e7eaa5SBob King                 {
139533e7eaa5SBob King                   "pmbus_write_vout_command": {
139633e7eaa5SBob King                     "format": "linear"
139733e7eaa5SBob King                   }
139833e7eaa5SBob King                 }
139933e7eaa5SBob King               ]
140033e7eaa5SBob King             }
140133e7eaa5SBob King         )"_json;
140233e7eaa5SBob King         std::unique_ptr<Configuration> configuration =
140333e7eaa5SBob King             parseConfiguration(element);
140433e7eaa5SBob King         EXPECT_EQ(configuration->getActions().size(), 1);
140533e7eaa5SBob King         EXPECT_EQ(configuration->getVolts().has_value(), false);
140633e7eaa5SBob King     }
140733e7eaa5SBob King 
140833e7eaa5SBob King     // Test where works: volts and actions properties specified
140933e7eaa5SBob King     {
141033e7eaa5SBob King         const json element = R"(
141133e7eaa5SBob King             {
141233e7eaa5SBob King               "comments": [ "comments property" ],
141333e7eaa5SBob King               "volts": 1.03,
141433e7eaa5SBob King               "actions": [
141533e7eaa5SBob King                 { "pmbus_write_vout_command": { "format": "linear" } },
141633e7eaa5SBob King                 { "run_rule": "set_voltage_rule" }
141733e7eaa5SBob King               ]
141833e7eaa5SBob King             }
141933e7eaa5SBob King         )"_json;
142033e7eaa5SBob King         std::unique_ptr<Configuration> configuration =
142133e7eaa5SBob King             parseConfiguration(element);
142233e7eaa5SBob King         EXPECT_EQ(configuration->getVolts().has_value(), true);
142333e7eaa5SBob King         EXPECT_EQ(configuration->getVolts().value(), 1.03);
142433e7eaa5SBob King         EXPECT_EQ(configuration->getActions().size(), 2);
142533e7eaa5SBob King     }
142633e7eaa5SBob King 
142733e7eaa5SBob King     // Test where works: volts and rule_id properties specified
142833e7eaa5SBob King     {
142933e7eaa5SBob King         const json element = R"(
143033e7eaa5SBob King             {
143133e7eaa5SBob King               "volts": 1.05,
143233e7eaa5SBob King               "rule_id": "set_voltage_rule"
143333e7eaa5SBob King             }
143433e7eaa5SBob King         )"_json;
143533e7eaa5SBob King         std::unique_ptr<Configuration> configuration =
143633e7eaa5SBob King             parseConfiguration(element);
143733e7eaa5SBob King         EXPECT_EQ(configuration->getVolts().has_value(), true);
143833e7eaa5SBob King         EXPECT_EQ(configuration->getVolts().value(), 1.05);
143933e7eaa5SBob King         EXPECT_EQ(configuration->getActions().size(), 1);
144033e7eaa5SBob King     }
144133e7eaa5SBob King 
144233e7eaa5SBob King     // Test where fails: volts value is invalid
144333e7eaa5SBob King     try
144433e7eaa5SBob King     {
144533e7eaa5SBob King         const json element = R"(
144633e7eaa5SBob King             {
144733e7eaa5SBob King               "volts": "foo",
144833e7eaa5SBob King               "actions": [
144933e7eaa5SBob King                 {
145033e7eaa5SBob King                   "pmbus_write_vout_command": {
145133e7eaa5SBob King                     "format": "linear"
145233e7eaa5SBob King                   }
145333e7eaa5SBob King                 }
145433e7eaa5SBob King               ]
145533e7eaa5SBob King             }
145633e7eaa5SBob King         )"_json;
145733e7eaa5SBob King         parseConfiguration(element);
145833e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
145933e7eaa5SBob King     }
146033e7eaa5SBob King     catch (const std::invalid_argument& e)
146133e7eaa5SBob King     {
146233e7eaa5SBob King         EXPECT_STREQ(e.what(), "Element is not a number");
146333e7eaa5SBob King     }
146433e7eaa5SBob King 
146533e7eaa5SBob King     // Test where fails: actions object is invalid
146633e7eaa5SBob King     try
146733e7eaa5SBob King     {
146833e7eaa5SBob King         const json element = R"(
146933e7eaa5SBob King             {
147033e7eaa5SBob King               "volts": 1.03,
147133e7eaa5SBob King               "actions": 1
147233e7eaa5SBob King             }
147333e7eaa5SBob King         )"_json;
147433e7eaa5SBob King         parseConfiguration(element);
147533e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
147633e7eaa5SBob King     }
147733e7eaa5SBob King     catch (const std::invalid_argument& e)
147833e7eaa5SBob King     {
147933e7eaa5SBob King         EXPECT_STREQ(e.what(), "Element is not an array");
148033e7eaa5SBob King     }
148133e7eaa5SBob King 
148233e7eaa5SBob King     // Test where fails: rule_id value is invalid
148333e7eaa5SBob King     try
148433e7eaa5SBob King     {
148533e7eaa5SBob King         const json element = R"(
148633e7eaa5SBob King             {
148733e7eaa5SBob King               "volts": 1.05,
148833e7eaa5SBob King               "rule_id": 1
148933e7eaa5SBob King             }
149033e7eaa5SBob King         )"_json;
149133e7eaa5SBob King         parseConfiguration(element);
149233e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
149333e7eaa5SBob King     }
149433e7eaa5SBob King     catch (const std::invalid_argument& e)
149533e7eaa5SBob King     {
149633e7eaa5SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
149733e7eaa5SBob King     }
149833e7eaa5SBob King 
149933e7eaa5SBob King     // Test where fails: Required actions or rule_id property not specified
150033e7eaa5SBob King     try
150133e7eaa5SBob King     {
150233e7eaa5SBob King         const json element = R"(
150333e7eaa5SBob King             {
150433e7eaa5SBob King               "volts": 1.03
150533e7eaa5SBob King             }
150633e7eaa5SBob King         )"_json;
150733e7eaa5SBob King         parseConfiguration(element);
150833e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
150933e7eaa5SBob King     }
151033e7eaa5SBob King     catch (const std::invalid_argument& e)
151133e7eaa5SBob King     {
151233e7eaa5SBob King         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
151333e7eaa5SBob King                                "either rule_id or actions");
151433e7eaa5SBob King     }
151533e7eaa5SBob King 
151633e7eaa5SBob King     // Test where fails: Required actions or rule_id property both specified
151733e7eaa5SBob King     try
151833e7eaa5SBob King     {
151933e7eaa5SBob King         const json element = R"(
152033e7eaa5SBob King             {
152133e7eaa5SBob King               "volts": 1.03,
152233e7eaa5SBob King               "rule_id": "set_voltage_rule",
152333e7eaa5SBob King               "actions": [
152433e7eaa5SBob King                 {
152533e7eaa5SBob King                   "pmbus_write_vout_command": {
152633e7eaa5SBob King                     "format": "linear"
152733e7eaa5SBob King                   }
152833e7eaa5SBob King                 }
152933e7eaa5SBob King               ]
153033e7eaa5SBob King             }
153133e7eaa5SBob King         )"_json;
153233e7eaa5SBob King         parseConfiguration(element);
153333e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
153433e7eaa5SBob King     }
153533e7eaa5SBob King     catch (const std::invalid_argument& e)
153633e7eaa5SBob King     {
153733e7eaa5SBob King         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
153833e7eaa5SBob King                                "either rule_id or actions");
153933e7eaa5SBob King     }
154033e7eaa5SBob King 
154133e7eaa5SBob King     // Test where fails: Element is not an object
154233e7eaa5SBob King     try
154333e7eaa5SBob King     {
154433e7eaa5SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
154533e7eaa5SBob King         parseConfiguration(element);
154633e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
154733e7eaa5SBob King     }
154833e7eaa5SBob King     catch (const std::invalid_argument& e)
154933e7eaa5SBob King     {
155033e7eaa5SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
155133e7eaa5SBob King     }
155233e7eaa5SBob King 
155333e7eaa5SBob King     // Test where fails: Invalid property specified
155433e7eaa5SBob King     try
155533e7eaa5SBob King     {
155633e7eaa5SBob King         const json element = R"(
155733e7eaa5SBob King             {
155833e7eaa5SBob King               "volts": 1.03,
155933e7eaa5SBob King               "rule_id": "set_voltage_rule",
156033e7eaa5SBob King               "foo": 1
156133e7eaa5SBob King             }
156233e7eaa5SBob King         )"_json;
156333e7eaa5SBob King         parseConfiguration(element);
156433e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
156533e7eaa5SBob King     }
156633e7eaa5SBob King     catch (const std::invalid_argument& e)
156733e7eaa5SBob King     {
156833e7eaa5SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
156933e7eaa5SBob King     }
157033e7eaa5SBob King }
157133e7eaa5SBob King 
TEST(ConfigFileParserTests,ParseDevice)15729c36c5fbSBob King TEST(ConfigFileParserTests, ParseDevice)
15739c36c5fbSBob King {
15749c36c5fbSBob King     // Test where works: Only required properties specified
15759c36c5fbSBob King     {
15769c36c5fbSBob King         const json element = R"(
15779c36c5fbSBob King             {
15789c36c5fbSBob King               "id": "vdd_regulator",
15799c36c5fbSBob King               "is_regulator": true,
1580a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
15819c36c5fbSBob King               "i2c_interface": { "bus": 1, "address": "0x70" }
15829c36c5fbSBob King             }
15839c36c5fbSBob King         )"_json;
15849c36c5fbSBob King         std::unique_ptr<Device> device = parseDevice(element);
15859c36c5fbSBob King         EXPECT_EQ(device->getID(), "vdd_regulator");
15869c36c5fbSBob King         EXPECT_EQ(device->isRegulator(), true);
1587a76898f1SBob King         EXPECT_EQ(device->getFRU(), "/xyz/openbmc_project/inventory/system/"
1588a76898f1SBob King                                     "chassis/motherboard/regulator2");
15899c36c5fbSBob King         EXPECT_NE(&(device->getI2CInterface()), nullptr);
15909c36c5fbSBob King         EXPECT_EQ(device->getPresenceDetection(), nullptr);
15919c36c5fbSBob King         EXPECT_EQ(device->getConfiguration(), nullptr);
159232252599SShawn McCarney         EXPECT_EQ(device->getPhaseFaultDetection(), nullptr);
15939c36c5fbSBob King         EXPECT_EQ(device->getRails().size(), 0);
15949c36c5fbSBob King     }
15959c36c5fbSBob King 
15969c36c5fbSBob King     // Test where works: All properties specified
159733e7eaa5SBob King     {
159833e7eaa5SBob King         const json element = R"(
159933e7eaa5SBob King             {
160032252599SShawn McCarney               "comments": [ "VDD Regulator" ],
160133e7eaa5SBob King               "id": "vdd_regulator",
160233e7eaa5SBob King               "is_regulator": true,
1603a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
160433e7eaa5SBob King               "i2c_interface":
160533e7eaa5SBob King               {
160633e7eaa5SBob King                   "bus": 1,
160733e7eaa5SBob King                   "address": "0x70"
160833e7eaa5SBob King               },
160932252599SShawn McCarney               "presence_detection":
161032252599SShawn McCarney               {
161132252599SShawn McCarney                   "rule_id": "is_foobar_backplane_installed_rule"
161232252599SShawn McCarney               },
161333e7eaa5SBob King               "configuration":
161433e7eaa5SBob King               {
161533e7eaa5SBob King                   "rule_id": "configure_ir35221_rule"
1616a2f2a0dcSBob King               },
161732252599SShawn McCarney               "phase_fault_detection":
16182aafb1c7SBob King               {
161932252599SShawn McCarney                   "rule_id": "detect_phase_fault_rule"
16202aafb1c7SBob King               },
1621a2f2a0dcSBob King               "rails":
1622a2f2a0dcSBob King               [
1623a2f2a0dcSBob King                 {
1624a2f2a0dcSBob King                   "id": "vdd"
162533e7eaa5SBob King                 }
1626a2f2a0dcSBob King               ]
162733e7eaa5SBob King             }
162833e7eaa5SBob King         )"_json;
162933e7eaa5SBob King         std::unique_ptr<Device> device = parseDevice(element);
163033e7eaa5SBob King         EXPECT_EQ(device->getID(), "vdd_regulator");
163133e7eaa5SBob King         EXPECT_EQ(device->isRegulator(), true);
1632a76898f1SBob King         EXPECT_EQ(device->getFRU(), "/xyz/openbmc_project/inventory/system/"
1633a76898f1SBob King                                     "chassis/motherboard/regulator2");
163433e7eaa5SBob King         EXPECT_NE(&(device->getI2CInterface()), nullptr);
16352aafb1c7SBob King         EXPECT_NE(device->getPresenceDetection(), nullptr);
163633e7eaa5SBob King         EXPECT_NE(device->getConfiguration(), nullptr);
163732252599SShawn McCarney         EXPECT_NE(device->getPhaseFaultDetection(), nullptr);
1638a2f2a0dcSBob King         EXPECT_EQ(device->getRails().size(), 1);
1639a2f2a0dcSBob King     }
1640a2f2a0dcSBob King 
164132252599SShawn McCarney     // Test where fails: phase_fault_detection property exists and is_regulator
164232252599SShawn McCarney     // is false
164332252599SShawn McCarney     try
164432252599SShawn McCarney     {
164532252599SShawn McCarney         const json element = R"(
164632252599SShawn McCarney             {
164732252599SShawn McCarney               "id": "vdd_regulator",
164832252599SShawn McCarney               "is_regulator": false,
164932252599SShawn McCarney               "fru": "system/chassis/motherboard/regulator2",
165032252599SShawn McCarney               "i2c_interface":
165132252599SShawn McCarney               {
165232252599SShawn McCarney                   "bus": 1,
165332252599SShawn McCarney                   "address": "0x70"
165432252599SShawn McCarney               },
165532252599SShawn McCarney               "phase_fault_detection":
165632252599SShawn McCarney               {
165732252599SShawn McCarney                   "rule_id": "detect_phase_fault_rule"
165832252599SShawn McCarney               }
165932252599SShawn McCarney             }
166032252599SShawn McCarney         )"_json;
166132252599SShawn McCarney         parseDevice(element);
166232252599SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
166332252599SShawn McCarney     }
166432252599SShawn McCarney     catch (const std::invalid_argument& e)
166532252599SShawn McCarney     {
166632252599SShawn McCarney         EXPECT_STREQ(e.what(), "Invalid phase_fault_detection property when "
166732252599SShawn McCarney                                "is_regulator is false");
166832252599SShawn McCarney     }
166932252599SShawn McCarney 
1670a2f2a0dcSBob King     // Test where fails: rails property exists and is_regulator is false
1671a2f2a0dcSBob King     try
1672a2f2a0dcSBob King     {
1673a2f2a0dcSBob King         const json element = R"(
1674a2f2a0dcSBob King             {
1675a2f2a0dcSBob King               "id": "vdd_regulator",
1676a2f2a0dcSBob King               "is_regulator": false,
1677a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
1678a2f2a0dcSBob King               "i2c_interface":
1679a2f2a0dcSBob King               {
1680a2f2a0dcSBob King                   "bus": 1,
1681a2f2a0dcSBob King                   "address": "0x70"
1682a2f2a0dcSBob King               },
1683a2f2a0dcSBob King               "configuration":
1684a2f2a0dcSBob King               {
1685a2f2a0dcSBob King                   "rule_id": "configure_ir35221_rule"
1686a2f2a0dcSBob King               },
1687a2f2a0dcSBob King               "rails":
1688a2f2a0dcSBob King               [
1689a2f2a0dcSBob King                 {
1690a2f2a0dcSBob King                   "id": "vdd"
1691a2f2a0dcSBob King                 }
1692a2f2a0dcSBob King               ]
1693a2f2a0dcSBob King             }
1694a2f2a0dcSBob King         )"_json;
1695a2f2a0dcSBob King         parseDevice(element);
1696a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
1697a2f2a0dcSBob King     }
1698a2f2a0dcSBob King     catch (const std::invalid_argument& e)
1699a2f2a0dcSBob King     {
1700a2f2a0dcSBob King         EXPECT_STREQ(e.what(),
1701a2f2a0dcSBob King                      "Invalid rails property when is_regulator is false");
170233e7eaa5SBob King     }
17039c36c5fbSBob King 
17049c36c5fbSBob King     // Test where fails: id value is invalid
17059c36c5fbSBob King     try
17069c36c5fbSBob King     {
17079c36c5fbSBob King         const json element = R"(
17089c36c5fbSBob King             {
17099c36c5fbSBob King               "id": 3,
17109c36c5fbSBob King               "is_regulator": true,
1711a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
17129c36c5fbSBob King               "i2c_interface":
17139c36c5fbSBob King               {
17149c36c5fbSBob King                   "bus": 1,
17159c36c5fbSBob King                   "address": "0x70"
17169c36c5fbSBob King               }
17179c36c5fbSBob King             }
17189c36c5fbSBob King         )"_json;
17199c36c5fbSBob King         parseDevice(element);
17209c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
17219c36c5fbSBob King     }
17229c36c5fbSBob King     catch (const std::invalid_argument& e)
17239c36c5fbSBob King     {
17249c36c5fbSBob King         EXPECT_STREQ(e.what(), "Element is not a string");
17259c36c5fbSBob King     }
17269c36c5fbSBob King 
17279c36c5fbSBob King     // Test where fails: is_regulator value is invalid
17289c36c5fbSBob King     try
17299c36c5fbSBob King     {
17309c36c5fbSBob King         const json element = R"(
17319c36c5fbSBob King             {
17329c36c5fbSBob King               "id": "vdd_regulator",
17339c36c5fbSBob King               "is_regulator": 3,
1734a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
17359c36c5fbSBob King               "i2c_interface":
17369c36c5fbSBob King               {
17379c36c5fbSBob King                   "bus": 1,
17389c36c5fbSBob King                   "address": "0x70"
17399c36c5fbSBob King               }
17409c36c5fbSBob King             }
17419c36c5fbSBob King         )"_json;
17429c36c5fbSBob King         parseDevice(element);
17439c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
17449c36c5fbSBob King     }
17459c36c5fbSBob King     catch (const std::invalid_argument& e)
17469c36c5fbSBob King     {
17479c36c5fbSBob King         EXPECT_STREQ(e.what(), "Element is not a boolean");
17489c36c5fbSBob King     }
17499c36c5fbSBob King 
17509c36c5fbSBob King     // Test where fails: fru value is invalid
17519c36c5fbSBob King     try
17529c36c5fbSBob King     {
17539c36c5fbSBob King         const json element = R"(
17549c36c5fbSBob King             {
17559c36c5fbSBob King               "id": "vdd_regulator",
17569c36c5fbSBob King               "is_regulator": true,
17579c36c5fbSBob King               "fru": 2,
17589c36c5fbSBob King               "i2c_interface":
17599c36c5fbSBob King               {
17609c36c5fbSBob King                   "bus": 1,
17619c36c5fbSBob King                   "address": "0x70"
17629c36c5fbSBob King               }
17639c36c5fbSBob King             }
17649c36c5fbSBob King         )"_json;
17659c36c5fbSBob King         parseDevice(element);
17669c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
17679c36c5fbSBob King     }
17689c36c5fbSBob King     catch (const std::invalid_argument& e)
17699c36c5fbSBob King     {
17709c36c5fbSBob King         EXPECT_STREQ(e.what(), "Element is not a string");
17719c36c5fbSBob King     }
17729c36c5fbSBob King 
17739c36c5fbSBob King     // Test where fails: i2c_interface value is invalid
17749c36c5fbSBob King     try
17759c36c5fbSBob King     {
17769c36c5fbSBob King         const json element = R"(
17779c36c5fbSBob King             {
17789c36c5fbSBob King               "id": "vdd_regulator",
17799c36c5fbSBob King               "is_regulator": true,
1780a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
17819c36c5fbSBob King               "i2c_interface": 3
17829c36c5fbSBob King             }
17839c36c5fbSBob King         )"_json;
17849c36c5fbSBob King         parseDevice(element);
17859c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
17869c36c5fbSBob King     }
17879c36c5fbSBob King     catch (const std::invalid_argument& e)
17889c36c5fbSBob King     {
17899c36c5fbSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
17909c36c5fbSBob King     }
17919c36c5fbSBob King 
17929c36c5fbSBob King     // Test where fails: Required id property not specified
17939c36c5fbSBob King     try
17949c36c5fbSBob King     {
17959c36c5fbSBob King         const json element = R"(
17969c36c5fbSBob King             {
17979c36c5fbSBob King               "is_regulator": true,
1798a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
17999c36c5fbSBob King               "i2c_interface":
18009c36c5fbSBob King               {
18019c36c5fbSBob King                   "bus": 1,
18029c36c5fbSBob King                   "address": "0x70"
18039c36c5fbSBob King               }
18049c36c5fbSBob King             }
18059c36c5fbSBob King         )"_json;
18069c36c5fbSBob King         parseDevice(element);
18079c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
18089c36c5fbSBob King     }
18099c36c5fbSBob King     catch (const std::invalid_argument& e)
18109c36c5fbSBob King     {
18119c36c5fbSBob King         EXPECT_STREQ(e.what(), "Required property missing: id");
18129c36c5fbSBob King     }
18139c36c5fbSBob King 
18149c36c5fbSBob King     // Test where fails: Required is_regulator property not specified
18159c36c5fbSBob King     try
18169c36c5fbSBob King     {
18179c36c5fbSBob King         const json element = R"(
18189c36c5fbSBob King             {
18199c36c5fbSBob King               "id": "vdd_regulator",
1820a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
18219c36c5fbSBob King               "i2c_interface":
18229c36c5fbSBob King               {
18239c36c5fbSBob King                   "bus": 1,
18249c36c5fbSBob King                   "address": "0x70"
18259c36c5fbSBob King               }
18269c36c5fbSBob King             }
18279c36c5fbSBob King         )"_json;
18289c36c5fbSBob King         parseDevice(element);
18299c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
18309c36c5fbSBob King     }
18319c36c5fbSBob King     catch (const std::invalid_argument& e)
18329c36c5fbSBob King     {
18339c36c5fbSBob King         EXPECT_STREQ(e.what(), "Required property missing: is_regulator");
18349c36c5fbSBob King     }
18359c36c5fbSBob King 
18369c36c5fbSBob King     // Test where fails: Required fru property not specified
18379c36c5fbSBob King     try
18389c36c5fbSBob King     {
18399c36c5fbSBob King         const json element = R"(
18409c36c5fbSBob King             {
18419c36c5fbSBob King               "id": "vdd_regulator",
18429c36c5fbSBob King               "is_regulator": true,
18439c36c5fbSBob King               "i2c_interface":
18449c36c5fbSBob King               {
18459c36c5fbSBob King                   "bus": 1,
18469c36c5fbSBob King                   "address": "0x70"
18479c36c5fbSBob King               }
18489c36c5fbSBob King             }
18499c36c5fbSBob King         )"_json;
18509c36c5fbSBob King         parseDevice(element);
18519c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
18529c36c5fbSBob King     }
18539c36c5fbSBob King     catch (const std::invalid_argument& e)
18549c36c5fbSBob King     {
18559c36c5fbSBob King         EXPECT_STREQ(e.what(), "Required property missing: fru");
18569c36c5fbSBob King     }
18579c36c5fbSBob King 
18589c36c5fbSBob King     // Test where fails: Required i2c_interface property not specified
18599c36c5fbSBob King     try
18609c36c5fbSBob King     {
18619c36c5fbSBob King         const json element = R"(
18629c36c5fbSBob King             {
18639c36c5fbSBob King               "id": "vdd_regulator",
18649c36c5fbSBob King               "is_regulator": true,
1865a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2"
18669c36c5fbSBob King             }
18679c36c5fbSBob King         )"_json;
18689c36c5fbSBob King         parseDevice(element);
18699c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
18709c36c5fbSBob King     }
18719c36c5fbSBob King     catch (const std::invalid_argument& e)
18729c36c5fbSBob King     {
18739c36c5fbSBob King         EXPECT_STREQ(e.what(), "Required property missing: i2c_interface");
18749c36c5fbSBob King     }
18759c36c5fbSBob King 
18769c36c5fbSBob King     // Test where fails: Element is not an object
18779c36c5fbSBob King     try
18789c36c5fbSBob King     {
18799c36c5fbSBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
18809c36c5fbSBob King         parseDevice(element);
18819c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
18829c36c5fbSBob King     }
18839c36c5fbSBob King     catch (const std::invalid_argument& e)
18849c36c5fbSBob King     {
18859c36c5fbSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
18869c36c5fbSBob King     }
18879c36c5fbSBob King 
18889c36c5fbSBob King     // Test where fails: Invalid property specified
18899c36c5fbSBob King     try
18909c36c5fbSBob King     {
18919c36c5fbSBob King         const json element = R"(
18929c36c5fbSBob King             {
18939c36c5fbSBob King               "id": "vdd_regulator",
18949c36c5fbSBob King               "is_regulator": true,
1895a76898f1SBob King               "fru": "system/chassis/motherboard/regulator2",
18969c36c5fbSBob King               "i2c_interface": { "bus": 1, "address": "0x70" },
18979c36c5fbSBob King               "foo" : true
18989c36c5fbSBob King             }
18999c36c5fbSBob King         )"_json;
19009c36c5fbSBob King         parseDevice(element);
19019c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
19029c36c5fbSBob King     }
19039c36c5fbSBob King     catch (const std::invalid_argument& e)
19049c36c5fbSBob King     {
19059c36c5fbSBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
19069c36c5fbSBob King     }
19079c36c5fbSBob King }
19089c36c5fbSBob King 
TEST(ConfigFileParserTests,ParseDeviceArray)19099c36c5fbSBob King TEST(ConfigFileParserTests, ParseDeviceArray)
19109c36c5fbSBob King {
19119c36c5fbSBob King     // Test where works
19129c36c5fbSBob King     {
19139c36c5fbSBob King         const json element = R"(
19149c36c5fbSBob King             [
19159c36c5fbSBob King               {
19169c36c5fbSBob King                 "id": "vdd_regulator",
19179c36c5fbSBob King                 "is_regulator": true,
1918a76898f1SBob King                 "fru": "system/chassis/motherboard/regulator2",
19199c36c5fbSBob King                 "i2c_interface": { "bus": 1, "address": "0x70" }
19209c36c5fbSBob King               },
19219c36c5fbSBob King               {
19229c36c5fbSBob King                 "id": "vio_regulator",
19239c36c5fbSBob King                 "is_regulator": true,
1924a76898f1SBob King                 "fru": "system/chassis/motherboard/regulator2",
19259c36c5fbSBob King                 "i2c_interface": { "bus": 1, "address": "0x71" }
19269c36c5fbSBob King               }
19279c36c5fbSBob King             ]
19289c36c5fbSBob King         )"_json;
19299c36c5fbSBob King         std::vector<std::unique_ptr<Device>> devices =
19309c36c5fbSBob King             parseDeviceArray(element);
19319c36c5fbSBob King         EXPECT_EQ(devices.size(), 2);
19329c36c5fbSBob King         EXPECT_EQ(devices[0]->getID(), "vdd_regulator");
19339c36c5fbSBob King         EXPECT_EQ(devices[1]->getID(), "vio_regulator");
19349c36c5fbSBob King     }
19359c36c5fbSBob King 
19369c36c5fbSBob King     // Test where fails: Element is not an array
19379c36c5fbSBob King     try
19389c36c5fbSBob King     {
19399c36c5fbSBob King         const json element = R"(
19409c36c5fbSBob King             {
19419c36c5fbSBob King               "foo": "bar"
19429c36c5fbSBob King             }
19439c36c5fbSBob King         )"_json;
19449c36c5fbSBob King         parseDeviceArray(element);
19459c36c5fbSBob King         ADD_FAILURE() << "Should not have reached this line.";
19469c36c5fbSBob King     }
19479c36c5fbSBob King     catch (const std::invalid_argument& e)
19489c36c5fbSBob King     {
19499c36c5fbSBob King         EXPECT_STREQ(e.what(), "Element is not an array");
19509c36c5fbSBob King     }
19519c36c5fbSBob King }
19529c36c5fbSBob King 
TEST(ConfigFileParserTests,ParseDouble)19530e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseDouble)
19540e8c68abSShawn McCarney {
19550e8c68abSShawn McCarney     // Test where works: floating point value
19560e8c68abSShawn McCarney     {
19570e8c68abSShawn McCarney         const json element = R"( 1.03 )"_json;
19580e8c68abSShawn McCarney         double value = parseDouble(element);
19590e8c68abSShawn McCarney         EXPECT_EQ(value, 1.03);
19600e8c68abSShawn McCarney     }
19610e8c68abSShawn McCarney 
19620e8c68abSShawn McCarney     // Test where works: integer value
19630e8c68abSShawn McCarney     {
19640e8c68abSShawn McCarney         const json element = R"( 24 )"_json;
19650e8c68abSShawn McCarney         double value = parseDouble(element);
19660e8c68abSShawn McCarney         EXPECT_EQ(value, 24.0);
19670e8c68abSShawn McCarney     }
19680e8c68abSShawn McCarney 
19690e8c68abSShawn McCarney     // Test where fails: Element is not a number
19700e8c68abSShawn McCarney     try
19710e8c68abSShawn McCarney     {
19720e8c68abSShawn McCarney         const json element = R"( true )"_json;
19730e8c68abSShawn McCarney         parseDouble(element);
19740e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
19750e8c68abSShawn McCarney     }
19760e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
19770e8c68abSShawn McCarney     {
19780e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a number");
19790e8c68abSShawn McCarney     }
19800e8c68abSShawn McCarney }
19810e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseHexByte)1982bafcb86cSBob King TEST(ConfigFileParserTests, ParseHexByte)
1983bafcb86cSBob King {
1984bafcb86cSBob King     // Test where works: "0xFF"
1985bafcb86cSBob King     {
1986bafcb86cSBob King         const json element = R"( "0xFF" )"_json;
1987bafcb86cSBob King         uint8_t value = parseHexByte(element);
1988bafcb86cSBob King         EXPECT_EQ(value, 0xFF);
1989bafcb86cSBob King     }
1990bafcb86cSBob King 
1991bafcb86cSBob King     // Test where works: "0xff"
1992bafcb86cSBob King     {
1993bafcb86cSBob King         const json element = R"( "0xff" )"_json;
1994bafcb86cSBob King         uint8_t value = parseHexByte(element);
1995bafcb86cSBob King         EXPECT_EQ(value, 0xff);
1996bafcb86cSBob King     }
1997bafcb86cSBob King 
1998bafcb86cSBob King     // Test where works: "0xf"
1999bafcb86cSBob King     {
2000bafcb86cSBob King         const json element = R"( "0xf" )"_json;
2001bafcb86cSBob King         uint8_t value = parseHexByte(element);
2002bafcb86cSBob King         EXPECT_EQ(value, 0xf);
2003bafcb86cSBob King     }
2004bafcb86cSBob King 
2005bafcb86cSBob King     // Test where fails: "0xfff"
2006bafcb86cSBob King     try
2007bafcb86cSBob King     {
2008bafcb86cSBob King         const json element = R"( "0xfff" )"_json;
2009bafcb86cSBob King         parseHexByte(element);
2010bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
2011bafcb86cSBob King     }
2012bafcb86cSBob King     catch (const std::invalid_argument& e)
2013bafcb86cSBob King     {
2014bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2015bafcb86cSBob King     }
2016bafcb86cSBob King 
2017bafcb86cSBob King     // Test where fails: "0xAG"
2018bafcb86cSBob King     try
2019bafcb86cSBob King     {
2020bafcb86cSBob King         const json element = R"( "0xAG" )"_json;
2021bafcb86cSBob King         parseHexByte(element);
2022bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
2023bafcb86cSBob King     }
2024bafcb86cSBob King     catch (const std::invalid_argument& e)
2025bafcb86cSBob King     {
2026bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2027bafcb86cSBob King     }
2028bafcb86cSBob King 
2029bafcb86cSBob King     // Test where fails: "ff"
2030bafcb86cSBob King     try
2031bafcb86cSBob King     {
2032bafcb86cSBob King         const json element = R"( "ff" )"_json;
2033bafcb86cSBob King         parseHexByte(element);
2034bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
2035bafcb86cSBob King     }
2036bafcb86cSBob King     catch (const std::invalid_argument& e)
2037bafcb86cSBob King     {
2038bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2039bafcb86cSBob King     }
2040bafcb86cSBob King 
2041bafcb86cSBob King     // Test where fails: ""
2042bafcb86cSBob King     try
2043bafcb86cSBob King     {
2044bafcb86cSBob King         const json element = "";
2045bafcb86cSBob King         parseHexByte(element);
2046bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
2047bafcb86cSBob King     }
2048bafcb86cSBob King     catch (const std::invalid_argument& e)
2049bafcb86cSBob King     {
2050bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2051bafcb86cSBob King     }
2052bafcb86cSBob King 
2053bafcb86cSBob King     // Test where fails: "f"
2054bafcb86cSBob King     try
2055bafcb86cSBob King     {
2056bafcb86cSBob King         const json element = R"( "f" )"_json;
2057bafcb86cSBob King         parseHexByte(element);
2058bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
2059bafcb86cSBob King     }
2060bafcb86cSBob King     catch (const std::invalid_argument& e)
2061bafcb86cSBob King     {
2062bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2063bafcb86cSBob King     }
2064bafcb86cSBob King 
2065bafcb86cSBob King     // Test where fails: "0x"
2066bafcb86cSBob King     try
2067bafcb86cSBob King     {
2068bafcb86cSBob King         const json element = R"( "0x" )"_json;
2069bafcb86cSBob King         parseHexByte(element);
2070bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
2071bafcb86cSBob King     }
2072bafcb86cSBob King     catch (const std::invalid_argument& e)
2073bafcb86cSBob King     {
2074bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2075bafcb86cSBob King     }
2076bafcb86cSBob King 
2077bafcb86cSBob King     // Test where fails: "0Xff"
2078bafcb86cSBob King     try
2079bafcb86cSBob King     {
2080bafcb86cSBob King         const json element = R"( "0XFF" )"_json;
2081bafcb86cSBob King         parseHexByte(element);
2082bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
2083bafcb86cSBob King     }
2084bafcb86cSBob King     catch (const std::invalid_argument& e)
2085bafcb86cSBob King     {
2086bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2087bafcb86cSBob King     }
2088bafcb86cSBob King }
2089bafcb86cSBob King 
TEST(ConfigFileParserTests,ParseHexByteArray)2090bafcb86cSBob King TEST(ConfigFileParserTests, ParseHexByteArray)
2091bafcb86cSBob King {
2092bafcb86cSBob King     // Test where works
2093bafcb86cSBob King     {
2094bafcb86cSBob King         const json element = R"( [ "0xCC", "0xFF" ] )"_json;
2095bafcb86cSBob King         std::vector<uint8_t> hexBytes = parseHexByteArray(element);
2096bafcb86cSBob King         std::vector<uint8_t> expected = {0xcc, 0xff};
2097bafcb86cSBob King         EXPECT_EQ(hexBytes, expected);
2098bafcb86cSBob King     }
2099bafcb86cSBob King 
2100bafcb86cSBob King     // Test where fails: Element is not an array
2101bafcb86cSBob King     try
2102bafcb86cSBob King     {
2103bafcb86cSBob King         const json element = 0;
2104bafcb86cSBob King         parseHexByteArray(element);
2105bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
2106bafcb86cSBob King     }
2107bafcb86cSBob King     catch (const std::invalid_argument& e)
2108bafcb86cSBob King     {
2109bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not an array");
2110bafcb86cSBob King     }
2111bafcb86cSBob King }
2112bafcb86cSBob King 
TEST(ConfigFileParserTests,ParseI2CCaptureBytes)211391f87a56SShawn McCarney TEST(ConfigFileParserTests, ParseI2CCaptureBytes)
211491f87a56SShawn McCarney {
211591f87a56SShawn McCarney     // Test where works
211691f87a56SShawn McCarney     {
211791f87a56SShawn McCarney         const json element = R"(
211891f87a56SShawn McCarney             {
211991f87a56SShawn McCarney               "register": "0xA0",
212091f87a56SShawn McCarney               "count": 2
212191f87a56SShawn McCarney             }
212291f87a56SShawn McCarney         )"_json;
212391f87a56SShawn McCarney         std::unique_ptr<I2CCaptureBytesAction> action =
212491f87a56SShawn McCarney             parseI2CCaptureBytes(element);
212591f87a56SShawn McCarney         EXPECT_EQ(action->getRegister(), 0xA0);
212691f87a56SShawn McCarney         EXPECT_EQ(action->getCount(), 2);
212791f87a56SShawn McCarney     }
212891f87a56SShawn McCarney 
212991f87a56SShawn McCarney     // Test where fails: Element is not an object
213091f87a56SShawn McCarney     try
213191f87a56SShawn McCarney     {
213291f87a56SShawn McCarney         const json element = R"( [ "0xFF", "0x01" ] )"_json;
213391f87a56SShawn McCarney         parseI2CCaptureBytes(element);
213491f87a56SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
213591f87a56SShawn McCarney     }
213691f87a56SShawn McCarney     catch (const std::invalid_argument& e)
213791f87a56SShawn McCarney     {
213891f87a56SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an object");
213991f87a56SShawn McCarney     }
214091f87a56SShawn McCarney 
214191f87a56SShawn McCarney     // Test where fails: register value is invalid
214291f87a56SShawn McCarney     try
214391f87a56SShawn McCarney     {
214491f87a56SShawn McCarney         const json element = R"(
214591f87a56SShawn McCarney             {
214691f87a56SShawn McCarney               "register": "0x0Z",
214791f87a56SShawn McCarney               "count": 2
214891f87a56SShawn McCarney             }
214991f87a56SShawn McCarney         )"_json;
215091f87a56SShawn McCarney         parseI2CCaptureBytes(element);
215191f87a56SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
215291f87a56SShawn McCarney     }
215391f87a56SShawn McCarney     catch (const std::invalid_argument& e)
215491f87a56SShawn McCarney     {
215591f87a56SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
215691f87a56SShawn McCarney     }
215791f87a56SShawn McCarney 
215891f87a56SShawn McCarney     // Test where fails: count value is invalid
215991f87a56SShawn McCarney     try
216091f87a56SShawn McCarney     {
216191f87a56SShawn McCarney         const json element = R"(
216291f87a56SShawn McCarney             {
216391f87a56SShawn McCarney               "register": "0xA0",
216491f87a56SShawn McCarney               "count": 0
216591f87a56SShawn McCarney             }
216691f87a56SShawn McCarney         )"_json;
216791f87a56SShawn McCarney         parseI2CCaptureBytes(element);
216891f87a56SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
216991f87a56SShawn McCarney     }
217091f87a56SShawn McCarney     catch (const std::invalid_argument& e)
217191f87a56SShawn McCarney     {
217291f87a56SShawn McCarney         EXPECT_STREQ(e.what(), "Invalid byte count: Must be > 0");
217391f87a56SShawn McCarney     }
217491f87a56SShawn McCarney 
217591f87a56SShawn McCarney     // Test where fails: Required register property not specified
217691f87a56SShawn McCarney     try
217791f87a56SShawn McCarney     {
217891f87a56SShawn McCarney         const json element = R"(
217991f87a56SShawn McCarney             {
218091f87a56SShawn McCarney               "count": 2
218191f87a56SShawn McCarney             }
218291f87a56SShawn McCarney         )"_json;
218391f87a56SShawn McCarney         parseI2CCaptureBytes(element);
218491f87a56SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
218591f87a56SShawn McCarney     }
218691f87a56SShawn McCarney     catch (const std::invalid_argument& e)
218791f87a56SShawn McCarney     {
218891f87a56SShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: register");
218991f87a56SShawn McCarney     }
219091f87a56SShawn McCarney 
219191f87a56SShawn McCarney     // Test where fails: Required count property not specified
219291f87a56SShawn McCarney     try
219391f87a56SShawn McCarney     {
219491f87a56SShawn McCarney         const json element = R"(
219591f87a56SShawn McCarney             {
219691f87a56SShawn McCarney               "register": "0xA0"
219791f87a56SShawn McCarney             }
219891f87a56SShawn McCarney         )"_json;
219991f87a56SShawn McCarney         parseI2CCaptureBytes(element);
220091f87a56SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
220191f87a56SShawn McCarney     }
220291f87a56SShawn McCarney     catch (const std::invalid_argument& e)
220391f87a56SShawn McCarney     {
220491f87a56SShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: count");
220591f87a56SShawn McCarney     }
220691f87a56SShawn McCarney 
220791f87a56SShawn McCarney     // Test where fails: Invalid property specified
220891f87a56SShawn McCarney     try
220991f87a56SShawn McCarney     {
221091f87a56SShawn McCarney         const json element = R"(
221191f87a56SShawn McCarney             {
221291f87a56SShawn McCarney               "register": "0xA0",
221391f87a56SShawn McCarney               "count": 2,
221491f87a56SShawn McCarney               "foo": 3
221591f87a56SShawn McCarney             }
221691f87a56SShawn McCarney         )"_json;
221791f87a56SShawn McCarney         parseI2CCaptureBytes(element);
221891f87a56SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
221991f87a56SShawn McCarney     }
222091f87a56SShawn McCarney     catch (const std::invalid_argument& e)
222191f87a56SShawn McCarney     {
222291f87a56SShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an invalid property");
222391f87a56SShawn McCarney     }
222491f87a56SShawn McCarney }
222591f87a56SShawn McCarney 
TEST(ConfigFileParserTests,ParseI2CCompareBit)2226f09bfe07SBob King TEST(ConfigFileParserTests, ParseI2CCompareBit)
2227f09bfe07SBob King {
2228f09bfe07SBob King     // Test where works
2229f09bfe07SBob King     {
2230f09bfe07SBob King         const json element = R"(
2231f09bfe07SBob King             {
2232f09bfe07SBob King               "register": "0xA0",
2233f09bfe07SBob King               "position": 3,
2234f09bfe07SBob King               "value": 0
2235f09bfe07SBob King             }
2236f09bfe07SBob King         )"_json;
2237f09bfe07SBob King         std::unique_ptr<I2CCompareBitAction> action =
2238f09bfe07SBob King             parseI2CCompareBit(element);
2239f09bfe07SBob King         EXPECT_EQ(action->getRegister(), 0xA0);
2240f09bfe07SBob King         EXPECT_EQ(action->getPosition(), 3);
2241f09bfe07SBob King         EXPECT_EQ(action->getValue(), 0);
2242f09bfe07SBob King     }
2243f09bfe07SBob King 
2244f09bfe07SBob King     // Test where fails: Invalid property specified
2245f09bfe07SBob King     try
2246f09bfe07SBob King     {
2247f09bfe07SBob King         const json element = R"(
2248f09bfe07SBob King             {
2249f09bfe07SBob King               "register": "0xA0",
2250f09bfe07SBob King               "position": 3,
2251f09bfe07SBob King               "value": 0,
2252f09bfe07SBob King               "foo": 3
2253f09bfe07SBob King             }
2254f09bfe07SBob King         )"_json;
2255f09bfe07SBob King         parseI2CCompareBit(element);
2256f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2257f09bfe07SBob King     }
2258f09bfe07SBob King     catch (const std::invalid_argument& e)
2259f09bfe07SBob King     {
2260f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
2261f09bfe07SBob King     }
2262f09bfe07SBob King 
2263f09bfe07SBob King     // Test where fails: Element is not an object
2264f09bfe07SBob King     try
2265f09bfe07SBob King     {
2266f09bfe07SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
2267f09bfe07SBob King         parseI2CCompareBit(element);
2268f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2269f09bfe07SBob King     }
2270f09bfe07SBob King     catch (const std::invalid_argument& e)
2271f09bfe07SBob King     {
2272f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
2273f09bfe07SBob King     }
2274f09bfe07SBob King 
2275f09bfe07SBob King     // Test where fails: register value is invalid
2276f09bfe07SBob King     try
2277f09bfe07SBob King     {
2278f09bfe07SBob King         const json element = R"(
2279f09bfe07SBob King             {
2280f09bfe07SBob King               "register": "0xAG",
2281f09bfe07SBob King               "position": 3,
2282f09bfe07SBob King               "value": 0
2283f09bfe07SBob King             }
2284f09bfe07SBob King         )"_json;
2285f09bfe07SBob King         parseI2CCompareBit(element);
2286f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2287f09bfe07SBob King     }
2288f09bfe07SBob King     catch (const std::invalid_argument& e)
2289f09bfe07SBob King     {
2290f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2291f09bfe07SBob King     }
2292f09bfe07SBob King 
2293f09bfe07SBob King     // Test where fails: position value is invalid
2294f09bfe07SBob King     try
2295f09bfe07SBob King     {
2296f09bfe07SBob King         const json element = R"(
2297f09bfe07SBob King                 {
2298f09bfe07SBob King                   "register": "0xA0",
2299f09bfe07SBob King                   "position": 8,
2300f09bfe07SBob King                   "value": 0
2301f09bfe07SBob King                 }
2302f09bfe07SBob King             )"_json;
2303f09bfe07SBob King         parseI2CCompareBit(element);
2304f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2305f09bfe07SBob King     }
2306f09bfe07SBob King     catch (const std::invalid_argument& e)
2307f09bfe07SBob King     {
2308f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not a bit position");
2309f09bfe07SBob King     }
2310f09bfe07SBob King 
2311f09bfe07SBob King     // Test where fails: value value is invalid
2312f09bfe07SBob King     try
2313f09bfe07SBob King     {
2314f09bfe07SBob King         const json element = R"(
2315f09bfe07SBob King                 {
2316f09bfe07SBob King                   "register": "0xA0",
2317f09bfe07SBob King                   "position": 3,
2318f09bfe07SBob King                   "value": 2
2319f09bfe07SBob King                 }
2320f09bfe07SBob King             )"_json;
2321f09bfe07SBob King         parseI2CCompareBit(element);
2322f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2323f09bfe07SBob King     }
2324f09bfe07SBob King     catch (const std::invalid_argument& e)
2325f09bfe07SBob King     {
2326f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not a bit value");
2327f09bfe07SBob King     }
2328f09bfe07SBob King 
2329f09bfe07SBob King     // Test where fails: Required register property not specified
2330f09bfe07SBob King     try
2331f09bfe07SBob King     {
2332f09bfe07SBob King         const json element = R"(
2333f09bfe07SBob King             {
2334f09bfe07SBob King               "position": 3,
2335f09bfe07SBob King               "value": 0
2336f09bfe07SBob King             }
2337f09bfe07SBob King         )"_json;
2338f09bfe07SBob King         parseI2CCompareBit(element);
2339f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2340f09bfe07SBob King     }
2341f09bfe07SBob King     catch (const std::invalid_argument& e)
2342f09bfe07SBob King     {
2343f09bfe07SBob King         EXPECT_STREQ(e.what(), "Required property missing: register");
2344f09bfe07SBob King     }
2345f09bfe07SBob King 
2346f09bfe07SBob King     // Test where fails: Required position property not specified
2347f09bfe07SBob King     try
2348f09bfe07SBob King     {
2349f09bfe07SBob King         const json element = R"(
2350f09bfe07SBob King             {
2351f09bfe07SBob King               "register": "0xA0",
2352f09bfe07SBob King               "value": 0
2353f09bfe07SBob King             }
2354f09bfe07SBob King         )"_json;
2355f09bfe07SBob King         parseI2CCompareBit(element);
2356f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2357f09bfe07SBob King     }
2358f09bfe07SBob King     catch (const std::invalid_argument& e)
2359f09bfe07SBob King     {
2360f09bfe07SBob King         EXPECT_STREQ(e.what(), "Required property missing: position");
2361f09bfe07SBob King     }
2362f09bfe07SBob King 
2363f09bfe07SBob King     // Test where fails: Required value property not specified
2364f09bfe07SBob King     try
2365f09bfe07SBob King     {
2366f09bfe07SBob King         const json element = R"(
2367f09bfe07SBob King             {
2368f09bfe07SBob King               "register": "0xA0",
2369f09bfe07SBob King               "position": 3
2370f09bfe07SBob King             }
2371f09bfe07SBob King         )"_json;
2372f09bfe07SBob King         parseI2CCompareBit(element);
2373f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2374f09bfe07SBob King     }
2375f09bfe07SBob King     catch (const std::invalid_argument& e)
2376f09bfe07SBob King     {
2377f09bfe07SBob King         EXPECT_STREQ(e.what(), "Required property missing: value");
2378f09bfe07SBob King     }
2379f09bfe07SBob King }
2380f09bfe07SBob King 
TEST(ConfigFileParserTests,ParseI2CCompareByte)2381f09bfe07SBob King TEST(ConfigFileParserTests, ParseI2CCompareByte)
2382f09bfe07SBob King {
2383f09bfe07SBob King     // Test where works: Only required properties specified
2384f09bfe07SBob King     {
2385f09bfe07SBob King         const json element = R"(
2386f09bfe07SBob King             {
2387f09bfe07SBob King               "register": "0x0A",
2388f09bfe07SBob King               "value": "0xCC"
2389f09bfe07SBob King             }
2390f09bfe07SBob King         )"_json;
2391f09bfe07SBob King         std::unique_ptr<I2CCompareByteAction> action =
2392f09bfe07SBob King             parseI2CCompareByte(element);
2393f09bfe07SBob King         EXPECT_EQ(action->getRegister(), 0x0A);
2394f09bfe07SBob King         EXPECT_EQ(action->getValue(), 0xCC);
2395f09bfe07SBob King         EXPECT_EQ(action->getMask(), 0xFF);
2396f09bfe07SBob King     }
2397f09bfe07SBob King 
2398f09bfe07SBob King     // Test where works: All properties specified
2399f09bfe07SBob King     {
2400f09bfe07SBob King         const json element = R"(
2401f09bfe07SBob King             {
2402f09bfe07SBob King               "register": "0x0A",
2403f09bfe07SBob King               "value": "0xCC",
2404f09bfe07SBob King               "mask": "0xF7"
2405f09bfe07SBob King             }
2406f09bfe07SBob King         )"_json;
2407f09bfe07SBob King         std::unique_ptr<I2CCompareByteAction> action =
2408f09bfe07SBob King             parseI2CCompareByte(element);
2409f09bfe07SBob King         EXPECT_EQ(action->getRegister(), 0x0A);
2410f09bfe07SBob King         EXPECT_EQ(action->getValue(), 0xCC);
2411f09bfe07SBob King         EXPECT_EQ(action->getMask(), 0xF7);
2412f09bfe07SBob King     }
2413f09bfe07SBob King 
2414f09bfe07SBob King     // Test where fails: Element is not an object
2415f09bfe07SBob King     try
2416f09bfe07SBob King     {
2417f09bfe07SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
2418f09bfe07SBob King         parseI2CCompareByte(element);
2419f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2420f09bfe07SBob King     }
2421f09bfe07SBob King     catch (const std::invalid_argument& e)
2422f09bfe07SBob King     {
2423f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
2424f09bfe07SBob King     }
2425f09bfe07SBob King 
2426f09bfe07SBob King     // Test where fails: Invalid property specified
2427f09bfe07SBob King     try
2428f09bfe07SBob King     {
2429f09bfe07SBob King         const json element = R"(
2430f09bfe07SBob King             {
2431f09bfe07SBob King               "register": "0x0A",
2432f09bfe07SBob King               "value": "0xCC",
2433f09bfe07SBob King               "mask": "0xF7",
2434f09bfe07SBob King               "foo": 1
2435f09bfe07SBob King             }
2436f09bfe07SBob King         )"_json;
2437f09bfe07SBob King         parseI2CCompareByte(element);
2438f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2439f09bfe07SBob King     }
2440f09bfe07SBob King     catch (const std::invalid_argument& e)
2441f09bfe07SBob King     {
2442f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
2443f09bfe07SBob King     }
2444f09bfe07SBob King 
2445f09bfe07SBob King     // Test where fails: register value is invalid
2446f09bfe07SBob King     try
2447f09bfe07SBob King     {
2448f09bfe07SBob King         const json element = R"(
2449f09bfe07SBob King             {
2450f09bfe07SBob King               "register": "0x0Z",
2451f09bfe07SBob King               "value": "0xCC",
2452f09bfe07SBob King               "mask": "0xF7"
2453f09bfe07SBob King             }
2454f09bfe07SBob King         )"_json;
2455f09bfe07SBob King         parseI2CCompareByte(element);
2456f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2457f09bfe07SBob King     }
2458f09bfe07SBob King     catch (const std::invalid_argument& e)
2459f09bfe07SBob King     {
2460f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2461f09bfe07SBob King     }
2462f09bfe07SBob King 
2463f09bfe07SBob King     // Test where fails: value value is invalid
2464f09bfe07SBob King     try
2465f09bfe07SBob King     {
2466f09bfe07SBob King         const json element = R"(
2467f09bfe07SBob King             {
2468f09bfe07SBob King               "register": "0x0A",
2469f09bfe07SBob King               "value": "0xCCC",
2470f09bfe07SBob King               "mask": "0xF7"
2471f09bfe07SBob King             }
2472f09bfe07SBob King         )"_json;
2473f09bfe07SBob King         parseI2CCompareByte(element);
2474f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2475f09bfe07SBob King     }
2476f09bfe07SBob King     catch (const std::invalid_argument& e)
2477f09bfe07SBob King     {
2478f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2479f09bfe07SBob King     }
2480f09bfe07SBob King 
2481f09bfe07SBob King     // Test where fails: mask value is invalid
2482f09bfe07SBob King     try
2483f09bfe07SBob King     {
2484f09bfe07SBob King         const json element = R"(
2485f09bfe07SBob King             {
2486f09bfe07SBob King               "register": "0x0A",
2487f09bfe07SBob King               "value": "0xCC",
2488f09bfe07SBob King               "mask": "F7"
2489f09bfe07SBob King             }
2490f09bfe07SBob King         )"_json;
2491f09bfe07SBob King         parseI2CCompareByte(element);
2492f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2493f09bfe07SBob King     }
2494f09bfe07SBob King     catch (const std::invalid_argument& e)
2495f09bfe07SBob King     {
2496f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2497f09bfe07SBob King     }
2498f09bfe07SBob King 
2499f09bfe07SBob King     // Test where fails: Required register property not specified
2500f09bfe07SBob King     try
2501f09bfe07SBob King     {
2502f09bfe07SBob King         const json element = R"(
2503f09bfe07SBob King             {
2504f09bfe07SBob King               "value": "0xCC",
2505f09bfe07SBob King               "mask": "0xF7"
2506f09bfe07SBob King             }
2507f09bfe07SBob King         )"_json;
2508f09bfe07SBob King         parseI2CCompareByte(element);
2509f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2510f09bfe07SBob King     }
2511f09bfe07SBob King     catch (const std::invalid_argument& e)
2512f09bfe07SBob King     {
2513f09bfe07SBob King         EXPECT_STREQ(e.what(), "Required property missing: register");
2514f09bfe07SBob King     }
2515f09bfe07SBob King 
2516f09bfe07SBob King     // Test where fails: Required value property not specified
2517f09bfe07SBob King     try
2518f09bfe07SBob King     {
2519f09bfe07SBob King         const json element = R"(
2520f09bfe07SBob King             {
2521f09bfe07SBob King               "register": "0x0A",
2522f09bfe07SBob King               "mask": "0xF7"
2523f09bfe07SBob King             }
2524f09bfe07SBob King         )"_json;
2525f09bfe07SBob King         parseI2CCompareByte(element);
2526f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2527f09bfe07SBob King     }
2528f09bfe07SBob King     catch (const std::invalid_argument& e)
2529f09bfe07SBob King     {
2530f09bfe07SBob King         EXPECT_STREQ(e.what(), "Required property missing: value");
2531f09bfe07SBob King     }
2532f09bfe07SBob King }
2533f09bfe07SBob King 
TEST(ConfigFileParserTests,ParseI2CCompareBytes)2534f09bfe07SBob King TEST(ConfigFileParserTests, ParseI2CCompareBytes)
2535f09bfe07SBob King {
2536f09bfe07SBob King     // Test where works: Only required properties specified
2537f09bfe07SBob King     {
2538f09bfe07SBob King         const json element = R"(
2539f09bfe07SBob King             {
2540f09bfe07SBob King               "register": "0x0A",
2541f09bfe07SBob King               "values": [ "0xCC", "0xFF" ]
2542f09bfe07SBob King             }
2543f09bfe07SBob King         )"_json;
2544f09bfe07SBob King         std::unique_ptr<I2CCompareBytesAction> action =
2545f09bfe07SBob King             parseI2CCompareBytes(element);
2546f09bfe07SBob King         EXPECT_EQ(action->getRegister(), 0x0A);
2547f09bfe07SBob King         EXPECT_EQ(action->getValues().size(), 2);
2548f09bfe07SBob King         EXPECT_EQ(action->getValues()[0], 0xCC);
2549f09bfe07SBob King         EXPECT_EQ(action->getValues()[1], 0xFF);
2550f09bfe07SBob King         EXPECT_EQ(action->getMasks().size(), 2);
2551f09bfe07SBob King         EXPECT_EQ(action->getMasks()[0], 0xFF);
2552f09bfe07SBob King         EXPECT_EQ(action->getMasks()[1], 0xFF);
2553f09bfe07SBob King     }
2554f09bfe07SBob King 
2555f09bfe07SBob King     // Test where works: All properties specified
2556f09bfe07SBob King     {
2557f09bfe07SBob King         const json element = R"(
2558f09bfe07SBob King             {
2559f09bfe07SBob King               "register": "0x0A",
2560f09bfe07SBob King               "values": [ "0xCC", "0xFF" ],
2561f09bfe07SBob King               "masks":  [ "0x7F", "0x77" ]
2562f09bfe07SBob King             }
2563f09bfe07SBob King         )"_json;
2564f09bfe07SBob King         std::unique_ptr<I2CCompareBytesAction> action =
2565f09bfe07SBob King             parseI2CCompareBytes(element);
2566f09bfe07SBob King         EXPECT_EQ(action->getRegister(), 0x0A);
2567f09bfe07SBob King         EXPECT_EQ(action->getValues().size(), 2);
2568f09bfe07SBob King         EXPECT_EQ(action->getValues()[0], 0xCC);
2569f09bfe07SBob King         EXPECT_EQ(action->getValues()[1], 0xFF);
2570f09bfe07SBob King         EXPECT_EQ(action->getMasks().size(), 2);
2571f09bfe07SBob King         EXPECT_EQ(action->getMasks()[0], 0x7F);
2572f09bfe07SBob King         EXPECT_EQ(action->getMasks()[1], 0x77);
2573f09bfe07SBob King     }
2574f09bfe07SBob King 
2575f09bfe07SBob King     // Test where fails: Element is not an object
2576f09bfe07SBob King     try
2577f09bfe07SBob King     {
2578f09bfe07SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
2579f09bfe07SBob King         parseI2CCompareBytes(element);
2580f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2581f09bfe07SBob King     }
2582f09bfe07SBob King     catch (const std::invalid_argument& e)
2583f09bfe07SBob King     {
2584f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
2585f09bfe07SBob King     }
2586f09bfe07SBob King 
2587f09bfe07SBob King     // Test where fails: Invalid property specified
2588f09bfe07SBob King     try
2589f09bfe07SBob King     {
2590f09bfe07SBob King         const json element = R"(
2591f09bfe07SBob King             {
2592f09bfe07SBob King               "register": "0x0A",
2593f09bfe07SBob King               "values": [ "0xCC", "0xFF" ],
2594f09bfe07SBob King               "masks":  [ "0x7F", "0x7F" ],
2595f09bfe07SBob King               "foo": 1
2596f09bfe07SBob King             }
2597f09bfe07SBob King         )"_json;
2598f09bfe07SBob King         parseI2CCompareBytes(element);
2599f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2600f09bfe07SBob King     }
2601f09bfe07SBob King     catch (const std::invalid_argument& e)
2602f09bfe07SBob King     {
2603f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
2604f09bfe07SBob King     }
2605f09bfe07SBob King 
2606f09bfe07SBob King     // Test where fails: register value is invalid
2607f09bfe07SBob King     try
2608f09bfe07SBob King     {
2609f09bfe07SBob King         const json element = R"(
2610f09bfe07SBob King             {
2611f09bfe07SBob King               "register": "0x0Z",
2612f09bfe07SBob King               "values": [ "0xCC", "0xFF" ],
2613f09bfe07SBob King               "masks":  [ "0x7F", "0x7F" ]
2614f09bfe07SBob King             }
2615f09bfe07SBob King         )"_json;
2616f09bfe07SBob King         parseI2CCompareBytes(element);
2617f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2618f09bfe07SBob King     }
2619f09bfe07SBob King     catch (const std::invalid_argument& e)
2620f09bfe07SBob King     {
2621f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2622f09bfe07SBob King     }
2623f09bfe07SBob King 
2624f09bfe07SBob King     // Test where fails: values value is invalid
2625f09bfe07SBob King     try
2626f09bfe07SBob King     {
2627f09bfe07SBob King         const json element = R"(
2628f09bfe07SBob King             {
2629f09bfe07SBob King               "register": "0x0A",
2630f09bfe07SBob King               "values": [ "0xCCC", "0xFF" ],
2631f09bfe07SBob King               "masks":  [ "0x7F", "0x7F" ]
2632f09bfe07SBob King             }
2633f09bfe07SBob King         )"_json;
2634f09bfe07SBob King         parseI2CCompareBytes(element);
2635f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2636f09bfe07SBob King     }
2637f09bfe07SBob King     catch (const std::invalid_argument& e)
2638f09bfe07SBob King     {
2639f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2640f09bfe07SBob King     }
2641f09bfe07SBob King 
2642f09bfe07SBob King     // Test where fails: masks value is invalid
2643f09bfe07SBob King     try
2644f09bfe07SBob King     {
2645f09bfe07SBob King         const json element = R"(
2646f09bfe07SBob King             {
2647f09bfe07SBob King               "register": "0x0A",
2648f09bfe07SBob King               "values": [ "0xCC", "0xFF" ],
2649f09bfe07SBob King               "masks":  [ "F", "0x7F" ]
2650f09bfe07SBob King             }
2651f09bfe07SBob King         )"_json;
2652f09bfe07SBob King         parseI2CCompareBytes(element);
2653f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2654f09bfe07SBob King     }
2655f09bfe07SBob King     catch (const std::invalid_argument& e)
2656f09bfe07SBob King     {
2657f09bfe07SBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2658f09bfe07SBob King     }
2659f09bfe07SBob King 
2660f09bfe07SBob King     // Test where fails: number of elements in masks is invalid
2661f09bfe07SBob King     try
2662f09bfe07SBob King     {
2663f09bfe07SBob King         const json element = R"(
2664f09bfe07SBob King             {
2665f09bfe07SBob King               "register": "0x0A",
2666f09bfe07SBob King               "values": [ "0xCC", "0xFF" ],
2667f09bfe07SBob King               "masks":  [ "0x7F" ]
2668f09bfe07SBob King             }
2669f09bfe07SBob King         )"_json;
2670f09bfe07SBob King         parseI2CCompareBytes(element);
2671f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2672f09bfe07SBob King     }
2673f09bfe07SBob King     catch (const std::invalid_argument& e)
2674f09bfe07SBob King     {
2675f09bfe07SBob King         EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
2676f09bfe07SBob King     }
2677f09bfe07SBob King 
2678f09bfe07SBob King     // Test where fails: Required register property not specified
2679f09bfe07SBob King     try
2680f09bfe07SBob King     {
2681f09bfe07SBob King         const json element = R"(
2682f09bfe07SBob King             {
2683f09bfe07SBob King               "values": [ "0xCC", "0xFF" ]
2684f09bfe07SBob King             }
2685f09bfe07SBob King         )"_json;
2686f09bfe07SBob King         parseI2CCompareBytes(element);
2687f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2688f09bfe07SBob King     }
2689f09bfe07SBob King     catch (const std::invalid_argument& e)
2690f09bfe07SBob King     {
2691f09bfe07SBob King         EXPECT_STREQ(e.what(), "Required property missing: register");
2692f09bfe07SBob King     }
2693f09bfe07SBob King 
2694f09bfe07SBob King     // Test where fails: Required values property not specified
2695f09bfe07SBob King     try
2696f09bfe07SBob King     {
2697f09bfe07SBob King         const json element = R"(
2698f09bfe07SBob King             {
2699f09bfe07SBob King               "register": "0x0A"
2700f09bfe07SBob King             }
2701f09bfe07SBob King         )"_json;
2702f09bfe07SBob King         parseI2CCompareBytes(element);
2703f09bfe07SBob King         ADD_FAILURE() << "Should not have reached this line.";
2704f09bfe07SBob King     }
2705f09bfe07SBob King     catch (const std::invalid_argument& e)
2706f09bfe07SBob King     {
2707f09bfe07SBob King         EXPECT_STREQ(e.what(), "Required property missing: values");
2708f09bfe07SBob King     }
2709f09bfe07SBob King }
2710f09bfe07SBob King 
TEST(ConfigFileParserTests,ParseI2CWriteBit)2711f617f893SBob King TEST(ConfigFileParserTests, ParseI2CWriteBit)
2712f617f893SBob King {
2713f617f893SBob King     // Test where works
2714f617f893SBob King     {
2715f617f893SBob King         const json element = R"(
2716f617f893SBob King             {
2717f617f893SBob King               "register": "0xA0",
2718f617f893SBob King               "position": 3,
2719f617f893SBob King               "value": 0
2720f617f893SBob King             }
2721f617f893SBob King         )"_json;
2722f617f893SBob King         std::unique_ptr<I2CWriteBitAction> action = parseI2CWriteBit(element);
2723f617f893SBob King         EXPECT_EQ(action->getRegister(), 0xA0);
2724f617f893SBob King         EXPECT_EQ(action->getPosition(), 3);
2725f617f893SBob King         EXPECT_EQ(action->getValue(), 0);
2726f617f893SBob King     }
2727f617f893SBob King 
2728f617f893SBob King     // Test where fails: Invalid property specified
2729f617f893SBob King     try
2730f617f893SBob King     {
2731f617f893SBob King         const json element = R"(
2732f617f893SBob King             {
2733f617f893SBob King               "register": "0xA0",
2734f617f893SBob King               "position": 3,
2735f617f893SBob King               "value": 0,
2736f617f893SBob King               "foo": 3
2737f617f893SBob King             }
2738f617f893SBob King         )"_json;
2739f617f893SBob King         parseI2CWriteBit(element);
2740f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
2741f617f893SBob King     }
2742f617f893SBob King     catch (const std::invalid_argument& e)
2743f617f893SBob King     {
2744f617f893SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
2745f617f893SBob King     }
2746f617f893SBob King 
2747f617f893SBob King     // Test where fails: Element is not an object
2748f617f893SBob King     try
2749f617f893SBob King     {
2750f617f893SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
2751f617f893SBob King         parseI2CWriteBit(element);
2752f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
2753f617f893SBob King     }
2754f617f893SBob King     catch (const std::invalid_argument& e)
2755f617f893SBob King     {
2756f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
2757f617f893SBob King     }
2758f617f893SBob King 
2759f617f893SBob King     // Test where fails: register value is invalid
2760f617f893SBob King     try
2761f617f893SBob King     {
2762f617f893SBob King         const json element = R"(
2763f617f893SBob King             {
2764f617f893SBob King               "register": "0xAG",
2765f617f893SBob King               "position": 3,
2766f617f893SBob King               "value": 0
2767f617f893SBob King             }
2768f617f893SBob King         )"_json;
2769f617f893SBob King         parseI2CWriteBit(element);
2770f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
2771f617f893SBob King     }
2772f617f893SBob King     catch (const std::invalid_argument& e)
2773f617f893SBob King     {
2774f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
2775f617f893SBob King     }
2776f617f893SBob King 
2777f617f893SBob King     // Test where fails: position value is invalid
2778f617f893SBob King     try
2779f617f893SBob King     {
2780f617f893SBob King         const json element = R"(
2781f617f893SBob King                 {
2782f617f893SBob King                   "register": "0xA0",
2783f617f893SBob King                   "position": 8,
2784f617f893SBob King                   "value": 0
2785f617f893SBob King                 }
2786f617f893SBob King             )"_json;
2787f617f893SBob King         parseI2CWriteBit(element);
2788f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
2789f617f893SBob King     }
2790f617f893SBob King     catch (const std::invalid_argument& e)
2791f617f893SBob King     {
2792f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not a bit position");
2793f617f893SBob King     }
2794f617f893SBob King 
2795f617f893SBob King     // Test where fails: value value is invalid
2796f617f893SBob King     try
2797f617f893SBob King     {
2798f617f893SBob King         const json element = R"(
2799f617f893SBob King                 {
2800f617f893SBob King                   "register": "0xA0",
2801f617f893SBob King                   "position": 3,
2802f617f893SBob King                   "value": 2
2803f617f893SBob King                 }
2804f617f893SBob King             )"_json;
2805f617f893SBob King         parseI2CWriteBit(element);
2806f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
2807f617f893SBob King     }
2808f617f893SBob King     catch (const std::invalid_argument& e)
2809f617f893SBob King     {
2810f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not a bit value");
2811f617f893SBob King     }
2812f617f893SBob King 
2813f617f893SBob King     // Test where fails: Required register property not specified
2814f617f893SBob King     try
2815f617f893SBob King     {
2816f617f893SBob King         const json element = R"(
2817f617f893SBob King             {
2818f617f893SBob King               "position": 3,
2819f617f893SBob King               "value": 0
2820f617f893SBob King             }
2821f617f893SBob King         )"_json;
2822f617f893SBob King         parseI2CWriteBit(element);
2823f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
2824f617f893SBob King     }
2825f617f893SBob King     catch (const std::invalid_argument& e)
2826f617f893SBob King     {
2827f617f893SBob King         EXPECT_STREQ(e.what(), "Required property missing: register");
2828f617f893SBob King     }
2829f617f893SBob King 
2830f617f893SBob King     // Test where fails: Required position property not specified
2831f617f893SBob King     try
2832f617f893SBob King     {
2833f617f893SBob King         const json element = R"(
2834f617f893SBob King             {
2835f617f893SBob King               "register": "0xA0",
2836f617f893SBob King               "value": 0
2837f617f893SBob King             }
2838f617f893SBob King         )"_json;
2839f617f893SBob King         parseI2CWriteBit(element);
2840f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
2841f617f893SBob King     }
2842f617f893SBob King     catch (const std::invalid_argument& e)
2843f617f893SBob King     {
2844f617f893SBob King         EXPECT_STREQ(e.what(), "Required property missing: position");
2845f617f893SBob King     }
2846f617f893SBob King 
2847f617f893SBob King     // Test where fails: Required value property not specified
2848f617f893SBob King     try
2849f617f893SBob King     {
2850f617f893SBob King         const json element = R"(
2851f617f893SBob King             {
2852f617f893SBob King               "register": "0xA0",
2853f617f893SBob King               "position": 3
2854f617f893SBob King             }
2855f617f893SBob King         )"_json;
2856f617f893SBob King         parseI2CWriteBit(element);
2857f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
2858f617f893SBob King     }
2859f617f893SBob King     catch (const std::invalid_argument& e)
2860f617f893SBob King     {
2861f617f893SBob King         EXPECT_STREQ(e.what(), "Required property missing: value");
2862f617f893SBob King     }
2863f617f893SBob King }
2864f617f893SBob King 
TEST(ConfigFileParserTests,ParseI2CWriteByte)286587ff9d7dSBob King TEST(ConfigFileParserTests, ParseI2CWriteByte)
286687ff9d7dSBob King {
286787ff9d7dSBob King     // Test where works: Only required properties specified
286887ff9d7dSBob King     {
286987ff9d7dSBob King         const json element = R"(
287087ff9d7dSBob King             {
287187ff9d7dSBob King               "register": "0x0A",
287287ff9d7dSBob King               "value": "0xCC"
287387ff9d7dSBob King             }
287487ff9d7dSBob King         )"_json;
287587ff9d7dSBob King         std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
287687ff9d7dSBob King         EXPECT_EQ(action->getRegister(), 0x0A);
287787ff9d7dSBob King         EXPECT_EQ(action->getValue(), 0xCC);
287887ff9d7dSBob King         EXPECT_EQ(action->getMask(), 0xFF);
287987ff9d7dSBob King     }
288087ff9d7dSBob King 
288187ff9d7dSBob King     // Test where works: All properties specified
288287ff9d7dSBob King     {
288387ff9d7dSBob King         const json element = R"(
288487ff9d7dSBob King             {
288587ff9d7dSBob King               "register": "0x0A",
288687ff9d7dSBob King               "value": "0xCC",
288787ff9d7dSBob King               "mask": "0xF7"
288887ff9d7dSBob King             }
288987ff9d7dSBob King         )"_json;
289087ff9d7dSBob King         std::unique_ptr<I2CWriteByteAction> action = parseI2CWriteByte(element);
289187ff9d7dSBob King         EXPECT_EQ(action->getRegister(), 0x0A);
289287ff9d7dSBob King         EXPECT_EQ(action->getValue(), 0xCC);
289387ff9d7dSBob King         EXPECT_EQ(action->getMask(), 0xF7);
289487ff9d7dSBob King     }
289587ff9d7dSBob King 
289687ff9d7dSBob King     // Test where fails: Element is not an object
289787ff9d7dSBob King     try
289887ff9d7dSBob King     {
289987ff9d7dSBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
290087ff9d7dSBob King         parseI2CWriteByte(element);
290187ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
290287ff9d7dSBob King     }
290387ff9d7dSBob King     catch (const std::invalid_argument& e)
290487ff9d7dSBob King     {
290587ff9d7dSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
290687ff9d7dSBob King     }
290787ff9d7dSBob King 
290887ff9d7dSBob King     // Test where fails: Invalid property specified
290987ff9d7dSBob King     try
291087ff9d7dSBob King     {
291187ff9d7dSBob King         const json element = R"(
291287ff9d7dSBob King             {
291387ff9d7dSBob King               "register": "0x0A",
291487ff9d7dSBob King               "value": "0xCC",
291587ff9d7dSBob King               "mask": "0xF7",
291687ff9d7dSBob King               "foo": 1
291787ff9d7dSBob King             }
291887ff9d7dSBob King         )"_json;
291987ff9d7dSBob King         parseI2CWriteByte(element);
292087ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
292187ff9d7dSBob King     }
292287ff9d7dSBob King     catch (const std::invalid_argument& e)
292387ff9d7dSBob King     {
292487ff9d7dSBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
292587ff9d7dSBob King     }
292687ff9d7dSBob King 
292787ff9d7dSBob King     // Test where fails: register value is invalid
292887ff9d7dSBob King     try
292987ff9d7dSBob King     {
293087ff9d7dSBob King         const json element = R"(
293187ff9d7dSBob King             {
293287ff9d7dSBob King               "register": "0x0Z",
293387ff9d7dSBob King               "value": "0xCC",
293487ff9d7dSBob King               "mask": "0xF7"
293587ff9d7dSBob King             }
293687ff9d7dSBob King         )"_json;
293787ff9d7dSBob King         parseI2CWriteByte(element);
293887ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
293987ff9d7dSBob King     }
294087ff9d7dSBob King     catch (const std::invalid_argument& e)
294187ff9d7dSBob King     {
294287ff9d7dSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
294387ff9d7dSBob King     }
294487ff9d7dSBob King 
294587ff9d7dSBob King     // Test where fails: value value is invalid
294687ff9d7dSBob King     try
294787ff9d7dSBob King     {
294887ff9d7dSBob King         const json element = R"(
294987ff9d7dSBob King             {
295087ff9d7dSBob King               "register": "0x0A",
295187ff9d7dSBob King               "value": "0xCCC",
295287ff9d7dSBob King               "mask": "0xF7"
295387ff9d7dSBob King             }
295487ff9d7dSBob King         )"_json;
295587ff9d7dSBob King         parseI2CWriteByte(element);
295687ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
295787ff9d7dSBob King     }
295887ff9d7dSBob King     catch (const std::invalid_argument& e)
295987ff9d7dSBob King     {
296087ff9d7dSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
296187ff9d7dSBob King     }
296287ff9d7dSBob King 
296387ff9d7dSBob King     // Test where fails: mask value is invalid
296487ff9d7dSBob King     try
296587ff9d7dSBob King     {
296687ff9d7dSBob King         const json element = R"(
296787ff9d7dSBob King             {
296887ff9d7dSBob King               "register": "0x0A",
296987ff9d7dSBob King               "value": "0xCC",
297087ff9d7dSBob King               "mask": "F7"
297187ff9d7dSBob King             }
297287ff9d7dSBob King         )"_json;
297387ff9d7dSBob King         parseI2CWriteByte(element);
297487ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
297587ff9d7dSBob King     }
297687ff9d7dSBob King     catch (const std::invalid_argument& e)
297787ff9d7dSBob King     {
297887ff9d7dSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
297987ff9d7dSBob King     }
298087ff9d7dSBob King 
298187ff9d7dSBob King     // Test where fails: Required register property not specified
298287ff9d7dSBob King     try
298387ff9d7dSBob King     {
298487ff9d7dSBob King         const json element = R"(
298587ff9d7dSBob King             {
298687ff9d7dSBob King               "value": "0xCC",
298787ff9d7dSBob King               "mask": "0xF7"
298887ff9d7dSBob King             }
298987ff9d7dSBob King         )"_json;
299087ff9d7dSBob King         parseI2CWriteByte(element);
299187ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
299287ff9d7dSBob King     }
299387ff9d7dSBob King     catch (const std::invalid_argument& e)
299487ff9d7dSBob King     {
299587ff9d7dSBob King         EXPECT_STREQ(e.what(), "Required property missing: register");
299687ff9d7dSBob King     }
299787ff9d7dSBob King 
299887ff9d7dSBob King     // Test where fails: Required value property not specified
299987ff9d7dSBob King     try
300087ff9d7dSBob King     {
300187ff9d7dSBob King         const json element = R"(
300287ff9d7dSBob King             {
300387ff9d7dSBob King               "register": "0x0A",
300487ff9d7dSBob King               "mask": "0xF7"
300587ff9d7dSBob King             }
300687ff9d7dSBob King         )"_json;
300787ff9d7dSBob King         parseI2CWriteByte(element);
300887ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
300987ff9d7dSBob King     }
301087ff9d7dSBob King     catch (const std::invalid_argument& e)
301187ff9d7dSBob King     {
301287ff9d7dSBob King         EXPECT_STREQ(e.what(), "Required property missing: value");
301387ff9d7dSBob King     }
301487ff9d7dSBob King }
301587ff9d7dSBob King 
TEST(ConfigFileParserTests,ParseI2CWriteBytes)3016bafcb86cSBob King TEST(ConfigFileParserTests, ParseI2CWriteBytes)
3017bafcb86cSBob King {
3018bafcb86cSBob King     // Test where works: Only required properties specified
3019bafcb86cSBob King     {
3020bafcb86cSBob King         const json element = R"(
3021bafcb86cSBob King             {
3022bafcb86cSBob King               "register": "0x0A",
3023bafcb86cSBob King               "values": [ "0xCC", "0xFF" ]
3024bafcb86cSBob King             }
3025bafcb86cSBob King         )"_json;
3026bafcb86cSBob King         std::unique_ptr<I2CWriteBytesAction> action =
3027bafcb86cSBob King             parseI2CWriteBytes(element);
3028bafcb86cSBob King         EXPECT_EQ(action->getRegister(), 0x0A);
3029bafcb86cSBob King         EXPECT_EQ(action->getValues().size(), 2);
3030bafcb86cSBob King         EXPECT_EQ(action->getValues()[0], 0xCC);
3031bafcb86cSBob King         EXPECT_EQ(action->getValues()[1], 0xFF);
3032bafcb86cSBob King         EXPECT_EQ(action->getMasks().size(), 0);
3033bafcb86cSBob King     }
3034bafcb86cSBob King 
3035bafcb86cSBob King     // Test where works: All properties specified
3036bafcb86cSBob King     {
3037bafcb86cSBob King         const json element = R"(
3038bafcb86cSBob King             {
3039bafcb86cSBob King               "register": "0x0A",
3040bafcb86cSBob King               "values": [ "0xCC", "0xFF" ],
3041bafcb86cSBob King               "masks":  [ "0x7F", "0x77" ]
3042bafcb86cSBob King             }
3043bafcb86cSBob King         )"_json;
3044bafcb86cSBob King         std::unique_ptr<I2CWriteBytesAction> action =
3045bafcb86cSBob King             parseI2CWriteBytes(element);
3046bafcb86cSBob King         EXPECT_EQ(action->getRegister(), 0x0A);
3047bafcb86cSBob King         EXPECT_EQ(action->getValues().size(), 2);
3048bafcb86cSBob King         EXPECT_EQ(action->getValues()[0], 0xCC);
3049bafcb86cSBob King         EXPECT_EQ(action->getValues()[1], 0xFF);
3050bafcb86cSBob King         EXPECT_EQ(action->getMasks().size(), 2);
3051bafcb86cSBob King         EXPECT_EQ(action->getMasks()[0], 0x7F);
3052bafcb86cSBob King         EXPECT_EQ(action->getMasks()[1], 0x77);
3053bafcb86cSBob King     }
3054bafcb86cSBob King 
3055bafcb86cSBob King     // Test where fails: Element is not an object
3056bafcb86cSBob King     try
3057bafcb86cSBob King     {
3058bafcb86cSBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
3059bafcb86cSBob King         parseI2CWriteBytes(element);
3060bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
3061bafcb86cSBob King     }
3062bafcb86cSBob King     catch (const std::invalid_argument& e)
3063bafcb86cSBob King     {
3064bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
3065bafcb86cSBob King     }
3066bafcb86cSBob King 
3067bafcb86cSBob King     // Test where fails: Invalid property specified
3068bafcb86cSBob King     try
3069bafcb86cSBob King     {
3070bafcb86cSBob King         const json element = R"(
3071bafcb86cSBob King             {
3072bafcb86cSBob King               "register": "0x0A",
3073bafcb86cSBob King               "values": [ "0xCC", "0xFF" ],
3074bafcb86cSBob King               "masks":  [ "0x7F", "0x7F" ],
3075bafcb86cSBob King               "foo": 1
3076bafcb86cSBob King             }
3077bafcb86cSBob King         )"_json;
3078bafcb86cSBob King         parseI2CWriteBytes(element);
3079bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
3080bafcb86cSBob King     }
3081bafcb86cSBob King     catch (const std::invalid_argument& e)
3082bafcb86cSBob King     {
3083bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
3084bafcb86cSBob King     }
3085bafcb86cSBob King 
3086bafcb86cSBob King     // Test where fails: register value is invalid
3087bafcb86cSBob King     try
3088bafcb86cSBob King     {
3089bafcb86cSBob King         const json element = R"(
3090bafcb86cSBob King             {
3091bafcb86cSBob King               "register": "0x0Z",
3092bafcb86cSBob King               "values": [ "0xCC", "0xFF" ],
3093bafcb86cSBob King               "masks":  [ "0x7F", "0x7F" ]
3094bafcb86cSBob King             }
3095bafcb86cSBob King         )"_json;
3096bafcb86cSBob King         parseI2CWriteBytes(element);
3097bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
3098bafcb86cSBob King     }
3099bafcb86cSBob King     catch (const std::invalid_argument& e)
3100bafcb86cSBob King     {
3101bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
3102bafcb86cSBob King     }
3103bafcb86cSBob King 
3104bafcb86cSBob King     // Test where fails: values value is invalid
3105bafcb86cSBob King     try
3106bafcb86cSBob King     {
3107bafcb86cSBob King         const json element = R"(
3108bafcb86cSBob King             {
3109bafcb86cSBob King               "register": "0x0A",
3110bafcb86cSBob King               "values": [ "0xCCC", "0xFF" ],
3111bafcb86cSBob King               "masks":  [ "0x7F", "0x7F" ]
3112bafcb86cSBob King             }
3113bafcb86cSBob King         )"_json;
3114bafcb86cSBob King         parseI2CWriteBytes(element);
3115bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
3116bafcb86cSBob King     }
3117bafcb86cSBob King     catch (const std::invalid_argument& e)
3118bafcb86cSBob King     {
3119bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
3120bafcb86cSBob King     }
3121bafcb86cSBob King 
3122bafcb86cSBob King     // Test where fails: masks value is invalid
3123bafcb86cSBob King     try
3124bafcb86cSBob King     {
3125bafcb86cSBob King         const json element = R"(
3126bafcb86cSBob King             {
3127bafcb86cSBob King               "register": "0x0A",
3128bafcb86cSBob King               "values": [ "0xCC", "0xFF" ],
3129bafcb86cSBob King               "masks":  [ "F", "0x7F" ]
3130bafcb86cSBob King             }
3131bafcb86cSBob King         )"_json;
3132bafcb86cSBob King         parseI2CWriteBytes(element);
3133bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
3134bafcb86cSBob King     }
3135bafcb86cSBob King     catch (const std::invalid_argument& e)
3136bafcb86cSBob King     {
3137bafcb86cSBob King         EXPECT_STREQ(e.what(), "Element is not hexadecimal string");
3138bafcb86cSBob King     }
3139bafcb86cSBob King 
3140bafcb86cSBob King     // Test where fails: number of elements in masks is invalid
3141bafcb86cSBob King     try
3142bafcb86cSBob King     {
3143bafcb86cSBob King         const json element = R"(
3144bafcb86cSBob King             {
3145bafcb86cSBob King               "register": "0x0A",
3146bafcb86cSBob King               "values": [ "0xCC", "0xFF" ],
3147bafcb86cSBob King               "masks":  [ "0x7F" ]
3148bafcb86cSBob King             }
3149bafcb86cSBob King         )"_json;
3150bafcb86cSBob King         parseI2CWriteBytes(element);
3151bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
3152bafcb86cSBob King     }
3153bafcb86cSBob King     catch (const std::invalid_argument& e)
3154bafcb86cSBob King     {
3155bafcb86cSBob King         EXPECT_STREQ(e.what(), "Invalid number of elements in masks");
3156bafcb86cSBob King     }
3157bafcb86cSBob King 
3158bafcb86cSBob King     // Test where fails: Required register property not specified
3159bafcb86cSBob King     try
3160bafcb86cSBob King     {
3161bafcb86cSBob King         const json element = R"(
3162bafcb86cSBob King             {
3163bafcb86cSBob King               "values": [ "0xCC", "0xFF" ]
3164bafcb86cSBob King             }
3165bafcb86cSBob King         )"_json;
3166bafcb86cSBob King         parseI2CWriteBytes(element);
3167bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
3168bafcb86cSBob King     }
3169bafcb86cSBob King     catch (const std::invalid_argument& e)
3170bafcb86cSBob King     {
3171bafcb86cSBob King         EXPECT_STREQ(e.what(), "Required property missing: register");
3172bafcb86cSBob King     }
3173bafcb86cSBob King 
3174bafcb86cSBob King     // Test where fails: Required values property not specified
3175bafcb86cSBob King     try
3176bafcb86cSBob King     {
3177bafcb86cSBob King         const json element = R"(
3178bafcb86cSBob King             {
3179bafcb86cSBob King               "register": "0x0A"
3180bafcb86cSBob King             }
3181bafcb86cSBob King         )"_json;
3182bafcb86cSBob King         parseI2CWriteBytes(element);
3183bafcb86cSBob King         ADD_FAILURE() << "Should not have reached this line.";
3184bafcb86cSBob King     }
3185bafcb86cSBob King     catch (const std::invalid_argument& e)
3186bafcb86cSBob King     {
3187bafcb86cSBob King         EXPECT_STREQ(e.what(), "Required property missing: values");
3188bafcb86cSBob King     }
3189bafcb86cSBob King }
3190bafcb86cSBob King 
TEST(ConfigFileParserTests,ParseIf)319193a89d72SBob King TEST(ConfigFileParserTests, ParseIf)
319293a89d72SBob King {
319393a89d72SBob King     // Test where works: Only required properties specified
319493a89d72SBob King     {
319593a89d72SBob King         const json element = R"(
319693a89d72SBob King             {
319793a89d72SBob King               "condition": { "run_rule": "is_downlevel_regulator" },
319893a89d72SBob King               "then": [ { "run_rule": "configure_downlevel_regulator" },
319993a89d72SBob King                         { "run_rule": "configure_standard_regulator" } ]
320093a89d72SBob King             }
320193a89d72SBob King         )"_json;
320293a89d72SBob King         std::unique_ptr<IfAction> action = parseIf(element);
320393a89d72SBob King         EXPECT_NE(action->getConditionAction().get(), nullptr);
320493a89d72SBob King         EXPECT_EQ(action->getThenActions().size(), 2);
320593a89d72SBob King         EXPECT_EQ(action->getElseActions().size(), 0);
320693a89d72SBob King     }
320793a89d72SBob King 
320893a89d72SBob King     // Test where works: All properties specified
320993a89d72SBob King     {
321093a89d72SBob King         const json element = R"(
321193a89d72SBob King             {
321293a89d72SBob King               "condition": { "run_rule": "is_downlevel_regulator" },
321393a89d72SBob King               "then": [ { "run_rule": "configure_downlevel_regulator" } ],
321493a89d72SBob King               "else": [ { "run_rule": "configure_standard_regulator" } ]
321593a89d72SBob King             }
321693a89d72SBob King         )"_json;
321793a89d72SBob King         std::unique_ptr<IfAction> action = parseIf(element);
321893a89d72SBob King         EXPECT_NE(action->getConditionAction().get(), nullptr);
321993a89d72SBob King         EXPECT_EQ(action->getThenActions().size(), 1);
322093a89d72SBob King         EXPECT_EQ(action->getElseActions().size(), 1);
322193a89d72SBob King     }
322293a89d72SBob King 
322393a89d72SBob King     // Test where fails: Required condition property not specified
322493a89d72SBob King     try
322593a89d72SBob King     {
322693a89d72SBob King         const json element = R"(
322793a89d72SBob King             {
322893a89d72SBob King               "then": [ { "run_rule": "configure_downlevel_regulator" } ],
322993a89d72SBob King               "else": [ { "run_rule": "configure_standard_regulator" } ]
323093a89d72SBob King             }
323193a89d72SBob King         )"_json;
323293a89d72SBob King         parseIf(element);
323393a89d72SBob King         ADD_FAILURE() << "Should not have reached this line.";
323493a89d72SBob King     }
323593a89d72SBob King     catch (const std::invalid_argument& e)
323693a89d72SBob King     {
323793a89d72SBob King         EXPECT_STREQ(e.what(), "Required property missing: condition");
323893a89d72SBob King     }
323993a89d72SBob King 
324093a89d72SBob King     // Test where fails: Required then property not specified
324193a89d72SBob King     try
324293a89d72SBob King     {
324393a89d72SBob King         const json element = R"(
324493a89d72SBob King             {
324593a89d72SBob King               "condition": { "run_rule": "is_downlevel_regulator" },
324693a89d72SBob King               "else": [ { "run_rule": "configure_standard_regulator" } ]
324793a89d72SBob King             }
324893a89d72SBob King         )"_json;
324993a89d72SBob King         parseIf(element);
325093a89d72SBob King         ADD_FAILURE() << "Should not have reached this line.";
325193a89d72SBob King     }
325293a89d72SBob King     catch (const std::invalid_argument& e)
325393a89d72SBob King     {
325493a89d72SBob King         EXPECT_STREQ(e.what(), "Required property missing: then");
325593a89d72SBob King     }
325693a89d72SBob King 
325793a89d72SBob King     // Test where fails: condition value is invalid
325893a89d72SBob King     try
325993a89d72SBob King     {
326093a89d72SBob King         const json element = R"(
326193a89d72SBob King             {
326293a89d72SBob King               "condition": 1,
326393a89d72SBob King               "then": [ { "run_rule": "configure_downlevel_regulator" } ],
326493a89d72SBob King               "else": [ { "run_rule": "configure_standard_regulator" } ]
326593a89d72SBob King             }
326693a89d72SBob King         )"_json;
326793a89d72SBob King         parseIf(element);
326893a89d72SBob King         ADD_FAILURE() << "Should not have reached this line.";
326993a89d72SBob King     }
327093a89d72SBob King     catch (const std::invalid_argument& e)
327193a89d72SBob King     {
327293a89d72SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
327393a89d72SBob King     }
327493a89d72SBob King 
327593a89d72SBob King     // Test where fails: then value is invalid
327693a89d72SBob King     try
327793a89d72SBob King     {
327893a89d72SBob King         const json element = R"(
327993a89d72SBob King             {
328093a89d72SBob King               "condition": { "run_rule": "is_downlevel_regulator" },
328193a89d72SBob King               "then": "foo",
328293a89d72SBob King               "else": [ { "run_rule": "configure_standard_regulator" } ]
328393a89d72SBob King             }
328493a89d72SBob King         )"_json;
328593a89d72SBob King         parseIf(element);
328693a89d72SBob King         ADD_FAILURE() << "Should not have reached this line.";
328793a89d72SBob King     }
328893a89d72SBob King     catch (const std::invalid_argument& e)
328993a89d72SBob King     {
329093a89d72SBob King         EXPECT_STREQ(e.what(), "Element is not an array");
329193a89d72SBob King     }
329293a89d72SBob King 
329393a89d72SBob King     // Test where fails: else value is invalid
329493a89d72SBob King     try
329593a89d72SBob King     {
329693a89d72SBob King         const json element = R"(
329793a89d72SBob King             {
329893a89d72SBob King               "condition": { "run_rule": "is_downlevel_regulator" },
329993a89d72SBob King               "then": [ { "run_rule": "configure_downlevel_regulator" } ],
330093a89d72SBob King               "else": 1
330193a89d72SBob King             }
330293a89d72SBob King         )"_json;
330393a89d72SBob King         parseIf(element);
330493a89d72SBob King         ADD_FAILURE() << "Should not have reached this line.";
330593a89d72SBob King     }
330693a89d72SBob King     catch (const std::invalid_argument& e)
330793a89d72SBob King     {
330893a89d72SBob King         EXPECT_STREQ(e.what(), "Element is not an array");
330993a89d72SBob King     }
331093a89d72SBob King 
331193a89d72SBob King     // Test where fails: Invalid property specified
331293a89d72SBob King     try
331393a89d72SBob King     {
331493a89d72SBob King         const json element = R"(
331593a89d72SBob King             {
331693a89d72SBob King               "condition": { "run_rule": "is_downlevel_regulator" },
331793a89d72SBob King               "then": [ { "run_rule": "configure_downlevel_regulator" } ],
331893a89d72SBob King               "foo": "bar"
331993a89d72SBob King             }
332093a89d72SBob King         )"_json;
332193a89d72SBob King         parseIf(element);
332293a89d72SBob King         ADD_FAILURE() << "Should not have reached this line.";
332393a89d72SBob King     }
332493a89d72SBob King     catch (const std::invalid_argument& e)
332593a89d72SBob King     {
332693a89d72SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
332793a89d72SBob King     }
332893a89d72SBob King 
332993a89d72SBob King     // Test where fails: Element is not an object
333093a89d72SBob King     try
333193a89d72SBob King     {
333293a89d72SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
333393a89d72SBob King         parseIf(element);
333493a89d72SBob King         ADD_FAILURE() << "Should not have reached this line.";
333593a89d72SBob King     }
333693a89d72SBob King     catch (const std::invalid_argument& e)
333793a89d72SBob King     {
333893a89d72SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
333993a89d72SBob King     }
334093a89d72SBob King }
334193a89d72SBob King 
TEST(ConfigFileParserTests,ParseInt8)334287ff9d7dSBob King TEST(ConfigFileParserTests, ParseInt8)
334387ff9d7dSBob King {
334487ff9d7dSBob King     // Test where works: INT8_MIN
334587ff9d7dSBob King     {
334687ff9d7dSBob King         const json element = R"( -128 )"_json;
334787ff9d7dSBob King         int8_t value = parseInt8(element);
334887ff9d7dSBob King         EXPECT_EQ(value, -128);
334987ff9d7dSBob King     }
335087ff9d7dSBob King 
335187ff9d7dSBob King     // Test where works: INT8_MAX
335287ff9d7dSBob King     {
335387ff9d7dSBob King         const json element = R"( 127 )"_json;
335487ff9d7dSBob King         int8_t value = parseInt8(element);
335587ff9d7dSBob King         EXPECT_EQ(value, 127);
335687ff9d7dSBob King     }
335787ff9d7dSBob King 
335887ff9d7dSBob King     // Test where fails: Element is not an integer
335987ff9d7dSBob King     try
336087ff9d7dSBob King     {
336187ff9d7dSBob King         const json element = R"( 1.03 )"_json;
336287ff9d7dSBob King         parseInt8(element);
336387ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
336487ff9d7dSBob King     }
336587ff9d7dSBob King     catch (const std::invalid_argument& e)
336687ff9d7dSBob King     {
336787ff9d7dSBob King         EXPECT_STREQ(e.what(), "Element is not an integer");
336887ff9d7dSBob King     }
336987ff9d7dSBob King 
337087ff9d7dSBob King     // Test where fails: Value < INT8_MIN
337187ff9d7dSBob King     try
337287ff9d7dSBob King     {
337387ff9d7dSBob King         const json element = R"( -129 )"_json;
337487ff9d7dSBob King         parseInt8(element);
337587ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
337687ff9d7dSBob King     }
337787ff9d7dSBob King     catch (const std::invalid_argument& e)
337887ff9d7dSBob King     {
337987ff9d7dSBob King         EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
338087ff9d7dSBob King     }
338187ff9d7dSBob King 
338287ff9d7dSBob King     // Test where fails: Value > INT8_MAX
338387ff9d7dSBob King     try
338487ff9d7dSBob King     {
338587ff9d7dSBob King         const json element = R"( 128 )"_json;
338687ff9d7dSBob King         parseInt8(element);
338787ff9d7dSBob King         ADD_FAILURE() << "Should not have reached this line.";
338887ff9d7dSBob King     }
338987ff9d7dSBob King     catch (const std::invalid_argument& e)
339087ff9d7dSBob King     {
339187ff9d7dSBob King         EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer");
339287ff9d7dSBob King     }
339387ff9d7dSBob King }
339487ff9d7dSBob King 
TEST(ConfigFileParserTests,ParseInventoryPath)3395a76898f1SBob King TEST(ConfigFileParserTests, ParseInventoryPath)
3396a76898f1SBob King {
3397a76898f1SBob King     // Test where works: Inventory path has a leading '/'
3398a76898f1SBob King     {
3399a76898f1SBob King         const json element = "/system/chassis/motherboard/cpu3";
3400a76898f1SBob King         std::string value = parseInventoryPath(element);
3401a76898f1SBob King         EXPECT_EQ(
3402a76898f1SBob King             value,
3403a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu3");
3404a76898f1SBob King     }
3405a76898f1SBob King 
3406a76898f1SBob King     // Test where works: Inventory path does not have a leading '/'
3407a76898f1SBob King     {
3408a76898f1SBob King         const json element = "system/chassis/motherboard/cpu1";
3409a76898f1SBob King         std::string value = parseInventoryPath(element);
3410a76898f1SBob King         EXPECT_EQ(
3411a76898f1SBob King             value,
3412a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1");
3413a76898f1SBob King     }
3414a76898f1SBob King 
3415a76898f1SBob King     // Test where fails: JSON element is not a string
3416a76898f1SBob King     try
3417a76898f1SBob King     {
3418a76898f1SBob King         const json element = R"( { "foo": "bar" } )"_json;
3419a76898f1SBob King         parseInventoryPath(element);
3420a76898f1SBob King         ADD_FAILURE() << "Should not have reached this line.";
3421a76898f1SBob King     }
3422a76898f1SBob King     catch (const std::invalid_argument& e)
3423a76898f1SBob King     {
3424a76898f1SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
3425a76898f1SBob King     }
3426a76898f1SBob King 
3427a76898f1SBob King     // Test where fails: JSON element contains an empty string
3428a76898f1SBob King     try
3429a76898f1SBob King     {
3430a76898f1SBob King         const json element = "";
3431a76898f1SBob King         parseInventoryPath(element);
3432a76898f1SBob King         ADD_FAILURE() << "Should not have reached this line.";
3433a76898f1SBob King     }
3434a76898f1SBob King     catch (const std::invalid_argument& e)
3435a76898f1SBob King     {
3436a76898f1SBob King         EXPECT_STREQ(e.what(), "Element contains an empty string");
3437a76898f1SBob King     }
3438a76898f1SBob King }
3439a76898f1SBob King 
TEST(ConfigFileParserTests,ParseLogPhaseFault)34401115785fSShawn McCarney TEST(ConfigFileParserTests, ParseLogPhaseFault)
34411115785fSShawn McCarney {
34421115785fSShawn McCarney     // Test where works
34431115785fSShawn McCarney     {
34441115785fSShawn McCarney         const json element = R"(
34451115785fSShawn McCarney             {
34461115785fSShawn McCarney               "type": "n+1"
34471115785fSShawn McCarney             }
34481115785fSShawn McCarney         )"_json;
34491115785fSShawn McCarney         std::unique_ptr<LogPhaseFaultAction> action =
34501115785fSShawn McCarney             parseLogPhaseFault(element);
34511115785fSShawn McCarney         EXPECT_EQ(action->getType(), PhaseFaultType::n_plus_1);
34521115785fSShawn McCarney     }
34531115785fSShawn McCarney 
34541115785fSShawn McCarney     // Test where fails: Element is not an object
34551115785fSShawn McCarney     try
34561115785fSShawn McCarney     {
34571115785fSShawn McCarney         const json element = R"( [ "0xFF", "0x01" ] )"_json;
34581115785fSShawn McCarney         parseLogPhaseFault(element);
34591115785fSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
34601115785fSShawn McCarney     }
34611115785fSShawn McCarney     catch (const std::invalid_argument& e)
34621115785fSShawn McCarney     {
34631115785fSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an object");
34641115785fSShawn McCarney     }
34651115785fSShawn McCarney 
34661115785fSShawn McCarney     // Test where fails: Required type property not specified
34671115785fSShawn McCarney     try
34681115785fSShawn McCarney     {
34691115785fSShawn McCarney         const json element = R"(
34701115785fSShawn McCarney             {
34711115785fSShawn McCarney             }
34721115785fSShawn McCarney         )"_json;
34731115785fSShawn McCarney         parseLogPhaseFault(element);
34741115785fSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
34751115785fSShawn McCarney     }
34761115785fSShawn McCarney     catch (const std::invalid_argument& e)
34771115785fSShawn McCarney     {
34781115785fSShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: type");
34791115785fSShawn McCarney     }
34801115785fSShawn McCarney 
34811115785fSShawn McCarney     // Test where fails: type value is invalid
34821115785fSShawn McCarney     try
34831115785fSShawn McCarney     {
34841115785fSShawn McCarney         const json element = R"(
34851115785fSShawn McCarney             {
34861115785fSShawn McCarney               "type": "n+2"
34871115785fSShawn McCarney             }
34881115785fSShawn McCarney         )"_json;
34891115785fSShawn McCarney         parseLogPhaseFault(element);
34901115785fSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
34911115785fSShawn McCarney     }
34921115785fSShawn McCarney     catch (const std::invalid_argument& e)
34931115785fSShawn McCarney     {
34941115785fSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a phase fault type");
34951115785fSShawn McCarney     }
34961115785fSShawn McCarney 
34971115785fSShawn McCarney     // Test where fails: Invalid property specified
34981115785fSShawn McCarney     try
34991115785fSShawn McCarney     {
35001115785fSShawn McCarney         const json element = R"(
35011115785fSShawn McCarney             {
35021115785fSShawn McCarney               "type": "n+1",
35031115785fSShawn McCarney               "foo": 1
35041115785fSShawn McCarney             }
35051115785fSShawn McCarney         )"_json;
35061115785fSShawn McCarney         parseLogPhaseFault(element);
35071115785fSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
35081115785fSShawn McCarney     }
35091115785fSShawn McCarney     catch (const std::invalid_argument& e)
35101115785fSShawn McCarney     {
35111115785fSShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an invalid property");
35121115785fSShawn McCarney     }
35131115785fSShawn McCarney }
35141115785fSShawn McCarney 
TEST(ConfigFileParserTests,ParseNot)3515f1b58dc4SBob King TEST(ConfigFileParserTests, ParseNot)
3516f1b58dc4SBob King {
3517f1b58dc4SBob King     // Test where works
3518f1b58dc4SBob King     {
3519f1b58dc4SBob King         const json element = R"(
3520f1b58dc4SBob King             { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }
3521f1b58dc4SBob King         )"_json;
3522f1b58dc4SBob King         std::unique_ptr<NotAction> action = parseNot(element);
3523f1b58dc4SBob King         EXPECT_NE(action->getAction().get(), nullptr);
3524f1b58dc4SBob King     }
3525f1b58dc4SBob King 
3526f1b58dc4SBob King     // Test where fails: Element is not an object
3527f1b58dc4SBob King     try
3528f1b58dc4SBob King     {
3529f1b58dc4SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
3530f1b58dc4SBob King         parseNot(element);
3531f1b58dc4SBob King         ADD_FAILURE() << "Should not have reached this line.";
3532f1b58dc4SBob King     }
3533f1b58dc4SBob King     catch (const std::invalid_argument& e)
3534f1b58dc4SBob King     {
3535f1b58dc4SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
3536f1b58dc4SBob King     }
3537f1b58dc4SBob King }
3538f1b58dc4SBob King 
TEST(ConfigFileParserTests,ParseOr)35390b51a9b2SBob King TEST(ConfigFileParserTests, ParseOr)
35400b51a9b2SBob King {
35410b51a9b2SBob King     // Test where works: Element is an array with 2 actions
35420b51a9b2SBob King     {
35430b51a9b2SBob King         const json element = R"(
35440b51a9b2SBob King             [
35450b51a9b2SBob King               { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
35460b51a9b2SBob King               { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
35470b51a9b2SBob King             ]
35480b51a9b2SBob King         )"_json;
35490b51a9b2SBob King         std::unique_ptr<OrAction> action = parseOr(element);
35500b51a9b2SBob King         EXPECT_EQ(action->getActions().size(), 2);
35510b51a9b2SBob King     }
35520b51a9b2SBob King 
35530b51a9b2SBob King     // Test where fails: Element is an array with 1 action
35540b51a9b2SBob King     try
35550b51a9b2SBob King     {
35560b51a9b2SBob King         const json element = R"(
35570b51a9b2SBob King             [
35580b51a9b2SBob King               { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } }
35590b51a9b2SBob King             ]
35600b51a9b2SBob King         )"_json;
35610b51a9b2SBob King         parseOr(element);
35620b51a9b2SBob King         ADD_FAILURE() << "Should not have reached this line.";
35630b51a9b2SBob King     }
35640b51a9b2SBob King     catch (const std::invalid_argument& e)
35650b51a9b2SBob King     {
35660b51a9b2SBob King         EXPECT_STREQ(e.what(), "Array must contain two or more actions");
35670b51a9b2SBob King     }
35680b51a9b2SBob King 
35690b51a9b2SBob King     // Test where fails: Element is not an array
35700b51a9b2SBob King     try
35710b51a9b2SBob King     {
35720b51a9b2SBob King         const json element = R"(
35730b51a9b2SBob King             {
35740b51a9b2SBob King               "foo": "bar"
35750b51a9b2SBob King             }
35760b51a9b2SBob King         )"_json;
35770b51a9b2SBob King         parseOr(element);
35780b51a9b2SBob King         ADD_FAILURE() << "Should not have reached this line.";
35790b51a9b2SBob King     }
35800b51a9b2SBob King     catch (const std::invalid_argument& e)
35810b51a9b2SBob King     {
35820b51a9b2SBob King         EXPECT_STREQ(e.what(), "Element is not an array");
35830b51a9b2SBob King     }
35840b51a9b2SBob King }
35850b51a9b2SBob King 
TEST(ConfigFileParserTests,ParsePhaseFaultDetection)358639eb08a9SShawn McCarney TEST(ConfigFileParserTests, ParsePhaseFaultDetection)
358739eb08a9SShawn McCarney {
358839eb08a9SShawn McCarney     // Test where works: actions specified: optional properties not specified
358939eb08a9SShawn McCarney     {
359039eb08a9SShawn McCarney         const json element = R"(
359139eb08a9SShawn McCarney             {
359239eb08a9SShawn McCarney               "actions": [
359339eb08a9SShawn McCarney                 { "run_rule": "detect_phase_fault_rule" }
359439eb08a9SShawn McCarney               ]
359539eb08a9SShawn McCarney             }
359639eb08a9SShawn McCarney         )"_json;
359739eb08a9SShawn McCarney         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection =
359839eb08a9SShawn McCarney             parsePhaseFaultDetection(element);
359939eb08a9SShawn McCarney         EXPECT_EQ(phaseFaultDetection->getActions().size(), 1);
360039eb08a9SShawn McCarney         EXPECT_EQ(phaseFaultDetection->getDeviceID(), "");
360139eb08a9SShawn McCarney     }
360239eb08a9SShawn McCarney 
360339eb08a9SShawn McCarney     // Test where works: rule_id specified: optional properties specified
360439eb08a9SShawn McCarney     {
360539eb08a9SShawn McCarney         const json element = R"(
360639eb08a9SShawn McCarney             {
360739eb08a9SShawn McCarney               "comments": [ "Detect phase fault using I/O expander" ],
360839eb08a9SShawn McCarney               "device_id": "io_expander",
360939eb08a9SShawn McCarney               "rule_id": "detect_phase_fault_rule"
361039eb08a9SShawn McCarney             }
361139eb08a9SShawn McCarney         )"_json;
361239eb08a9SShawn McCarney         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection =
361339eb08a9SShawn McCarney             parsePhaseFaultDetection(element);
361439eb08a9SShawn McCarney         EXPECT_EQ(phaseFaultDetection->getActions().size(), 1);
361539eb08a9SShawn McCarney         EXPECT_EQ(phaseFaultDetection->getDeviceID(), "io_expander");
361639eb08a9SShawn McCarney     }
361739eb08a9SShawn McCarney 
361839eb08a9SShawn McCarney     // Test where fails: Element is not an object
361939eb08a9SShawn McCarney     try
362039eb08a9SShawn McCarney     {
362139eb08a9SShawn McCarney         const json element = R"( [ "foo", "bar" ] )"_json;
362239eb08a9SShawn McCarney         parsePhaseFaultDetection(element);
362339eb08a9SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
362439eb08a9SShawn McCarney     }
362539eb08a9SShawn McCarney     catch (const std::invalid_argument& e)
362639eb08a9SShawn McCarney     {
362739eb08a9SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an object");
362839eb08a9SShawn McCarney     }
362939eb08a9SShawn McCarney 
363039eb08a9SShawn McCarney     // Test where fails: device_id value is invalid
363139eb08a9SShawn McCarney     try
363239eb08a9SShawn McCarney     {
363339eb08a9SShawn McCarney         const json element = R"(
363439eb08a9SShawn McCarney             {
363539eb08a9SShawn McCarney               "device_id": 1,
363639eb08a9SShawn McCarney               "rule_id": "detect_phase_fault_rule"
363739eb08a9SShawn McCarney             }
363839eb08a9SShawn McCarney         )"_json;
363939eb08a9SShawn McCarney         parsePhaseFaultDetection(element);
364039eb08a9SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
364139eb08a9SShawn McCarney     }
364239eb08a9SShawn McCarney     catch (const std::invalid_argument& e)
364339eb08a9SShawn McCarney     {
364439eb08a9SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a string");
364539eb08a9SShawn McCarney     }
364639eb08a9SShawn McCarney 
364739eb08a9SShawn McCarney     // Test where fails: rule_id value is invalid
364839eb08a9SShawn McCarney     try
364939eb08a9SShawn McCarney     {
365039eb08a9SShawn McCarney         const json element = R"(
365139eb08a9SShawn McCarney             {
365239eb08a9SShawn McCarney               "rule_id": 1
365339eb08a9SShawn McCarney             }
365439eb08a9SShawn McCarney         )"_json;
365539eb08a9SShawn McCarney         parsePhaseFaultDetection(element);
365639eb08a9SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
365739eb08a9SShawn McCarney     }
365839eb08a9SShawn McCarney     catch (const std::invalid_argument& e)
365939eb08a9SShawn McCarney     {
366039eb08a9SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a string");
366139eb08a9SShawn McCarney     }
366239eb08a9SShawn McCarney 
366339eb08a9SShawn McCarney     // Test where fails: actions object is invalid
366439eb08a9SShawn McCarney     try
366539eb08a9SShawn McCarney     {
366639eb08a9SShawn McCarney         const json element = R"(
366739eb08a9SShawn McCarney             {
366839eb08a9SShawn McCarney               "actions": 1
366939eb08a9SShawn McCarney             }
367039eb08a9SShawn McCarney         )"_json;
367139eb08a9SShawn McCarney         parsePhaseFaultDetection(element);
367239eb08a9SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
367339eb08a9SShawn McCarney     }
367439eb08a9SShawn McCarney     catch (const std::invalid_argument& e)
367539eb08a9SShawn McCarney     {
367639eb08a9SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an array");
367739eb08a9SShawn McCarney     }
367839eb08a9SShawn McCarney 
367939eb08a9SShawn McCarney     // Test where fails: Required actions or rule_id property not specified
368039eb08a9SShawn McCarney     try
368139eb08a9SShawn McCarney     {
368239eb08a9SShawn McCarney         const json element = R"(
368339eb08a9SShawn McCarney             {
368439eb08a9SShawn McCarney               "device_id": "io_expander"
368539eb08a9SShawn McCarney             }
368639eb08a9SShawn McCarney         )"_json;
368739eb08a9SShawn McCarney         parsePhaseFaultDetection(element);
368839eb08a9SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
368939eb08a9SShawn McCarney     }
369039eb08a9SShawn McCarney     catch (const std::invalid_argument& e)
369139eb08a9SShawn McCarney     {
369239eb08a9SShawn McCarney         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
369339eb08a9SShawn McCarney                                "either rule_id or actions");
369439eb08a9SShawn McCarney     }
369539eb08a9SShawn McCarney 
369639eb08a9SShawn McCarney     // Test where fails: Required actions or rule_id property both specified
369739eb08a9SShawn McCarney     try
369839eb08a9SShawn McCarney     {
369939eb08a9SShawn McCarney         const json element = R"(
370039eb08a9SShawn McCarney             {
370139eb08a9SShawn McCarney               "rule_id": "detect_phase_fault_rule",
370239eb08a9SShawn McCarney               "actions": [
370339eb08a9SShawn McCarney                 { "run_rule": "detect_phase_fault_rule" }
370439eb08a9SShawn McCarney               ]
370539eb08a9SShawn McCarney             }
370639eb08a9SShawn McCarney         )"_json;
370739eb08a9SShawn McCarney         parsePhaseFaultDetection(element);
370839eb08a9SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
370939eb08a9SShawn McCarney     }
371039eb08a9SShawn McCarney     catch (const std::invalid_argument& e)
371139eb08a9SShawn McCarney     {
371239eb08a9SShawn McCarney         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
371339eb08a9SShawn McCarney                                "either rule_id or actions");
371439eb08a9SShawn McCarney     }
371539eb08a9SShawn McCarney 
371639eb08a9SShawn McCarney     // Test where fails: Invalid property specified
371739eb08a9SShawn McCarney     try
371839eb08a9SShawn McCarney     {
371939eb08a9SShawn McCarney         const json element = R"(
372039eb08a9SShawn McCarney             {
372139eb08a9SShawn McCarney               "foo": "bar",
372239eb08a9SShawn McCarney               "actions": [
372339eb08a9SShawn McCarney                 { "run_rule": "detect_phase_fault_rule" }
372439eb08a9SShawn McCarney               ]
372539eb08a9SShawn McCarney             }
372639eb08a9SShawn McCarney         )"_json;
372739eb08a9SShawn McCarney         parsePhaseFaultDetection(element);
372839eb08a9SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
372939eb08a9SShawn McCarney     }
373039eb08a9SShawn McCarney     catch (const std::invalid_argument& e)
373139eb08a9SShawn McCarney     {
373239eb08a9SShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an invalid property");
373339eb08a9SShawn McCarney     }
373439eb08a9SShawn McCarney }
373539eb08a9SShawn McCarney 
TEST(ConfigFileParserTests,ParsePhaseFaultType)3736b70370b7SShawn McCarney TEST(ConfigFileParserTests, ParsePhaseFaultType)
3737b70370b7SShawn McCarney {
3738b70370b7SShawn McCarney     // Test where works: n
3739b70370b7SShawn McCarney     {
3740b70370b7SShawn McCarney         const json element = "n";
3741b70370b7SShawn McCarney         PhaseFaultType type = parsePhaseFaultType(element);
3742b70370b7SShawn McCarney         EXPECT_EQ(type, PhaseFaultType::n);
3743b70370b7SShawn McCarney     }
3744b70370b7SShawn McCarney 
3745b70370b7SShawn McCarney     // Test where works: n+1
3746b70370b7SShawn McCarney     {
3747b70370b7SShawn McCarney         const json element = "n+1";
3748b70370b7SShawn McCarney         PhaseFaultType type = parsePhaseFaultType(element);
3749b70370b7SShawn McCarney         EXPECT_EQ(type, PhaseFaultType::n_plus_1);
3750b70370b7SShawn McCarney     }
3751b70370b7SShawn McCarney 
3752b70370b7SShawn McCarney     // Test where fails: Element is not a phase fault type
3753b70370b7SShawn McCarney     try
3754b70370b7SShawn McCarney     {
3755b70370b7SShawn McCarney         const json element = "n+2";
3756b70370b7SShawn McCarney         parsePhaseFaultType(element);
3757b70370b7SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
3758b70370b7SShawn McCarney     }
3759b70370b7SShawn McCarney     catch (const std::invalid_argument& e)
3760b70370b7SShawn McCarney     {
3761b70370b7SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a phase fault type");
3762b70370b7SShawn McCarney     }
3763b70370b7SShawn McCarney 
3764b70370b7SShawn McCarney     // Test where fails: Element is not a string
3765b70370b7SShawn McCarney     try
3766b70370b7SShawn McCarney     {
3767b70370b7SShawn McCarney         const json element = R"( { "foo": "bar" } )"_json;
3768b70370b7SShawn McCarney         parsePhaseFaultType(element);
3769b70370b7SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
3770b70370b7SShawn McCarney     }
3771b70370b7SShawn McCarney     catch (const std::invalid_argument& e)
3772b70370b7SShawn McCarney     {
3773b70370b7SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a string");
3774b70370b7SShawn McCarney     }
3775b70370b7SShawn McCarney }
3776b70370b7SShawn McCarney 
TEST(ConfigFileParserTests,ParsePMBusReadSensor)377784614882SBob King TEST(ConfigFileParserTests, ParsePMBusReadSensor)
377884614882SBob King {
377984614882SBob King     // Test where works: Only required properties specified
378084614882SBob King     {
378184614882SBob King         const json element = R"(
378284614882SBob King             {
378384614882SBob King               "type": "iout",
378484614882SBob King               "command": "0x8C",
378584614882SBob King               "format": "linear_11"
378684614882SBob King             }
378784614882SBob King         )"_json;
378884614882SBob King         std::unique_ptr<PMBusReadSensorAction> action =
378984614882SBob King             parsePMBusReadSensor(element);
37902f9e14f6SShawn McCarney         EXPECT_EQ(action->getType(), SensorType::iout);
379184614882SBob King         EXPECT_EQ(action->getCommand(), 0x8C);
379284614882SBob King         EXPECT_EQ(action->getFormat(),
379384614882SBob King                   pmbus_utils::SensorDataFormat::linear_11);
379484614882SBob King         EXPECT_EQ(action->getExponent().has_value(), false);
379584614882SBob King     }
379684614882SBob King 
379784614882SBob King     // Test where works: All properties specified
379884614882SBob King     {
379984614882SBob King         const json element = R"(
380084614882SBob King             {
380184614882SBob King               "type": "temperature",
380284614882SBob King               "command": "0x7A",
380384614882SBob King               "format": "linear_16",
380484614882SBob King               "exponent": -8
380584614882SBob King             }
380684614882SBob King         )"_json;
380784614882SBob King         std::unique_ptr<PMBusReadSensorAction> action =
380884614882SBob King             parsePMBusReadSensor(element);
38092f9e14f6SShawn McCarney         EXPECT_EQ(action->getType(), SensorType::temperature);
381084614882SBob King         EXPECT_EQ(action->getCommand(), 0x7A);
381184614882SBob King         EXPECT_EQ(action->getFormat(),
381284614882SBob King                   pmbus_utils::SensorDataFormat::linear_16);
381384614882SBob King         EXPECT_EQ(action->getExponent().has_value(), true);
381484614882SBob King         EXPECT_EQ(action->getExponent().value(), -8);
381584614882SBob King     }
381684614882SBob King 
381784614882SBob King     // Test where fails: Element is not an object
381884614882SBob King     try
381984614882SBob King     {
382084614882SBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
382184614882SBob King         parsePMBusReadSensor(element);
382284614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
382384614882SBob King     }
382484614882SBob King     catch (const std::invalid_argument& e)
382584614882SBob King     {
382684614882SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
382784614882SBob King     }
382884614882SBob King 
382984614882SBob King     // Test where fails: Invalid property specified
383084614882SBob King     try
383184614882SBob King     {
383284614882SBob King         const json element = R"(
383384614882SBob King             {
383484614882SBob King               "type": "iout",
383584614882SBob King               "command": "0x8C",
383684614882SBob King               "format": "linear_11",
383784614882SBob King               "foo": 1
383884614882SBob King             }
383984614882SBob King         )"_json;
384084614882SBob King         parsePMBusReadSensor(element);
384184614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
384284614882SBob King     }
384384614882SBob King     catch (const std::invalid_argument& e)
384484614882SBob King     {
384584614882SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
384684614882SBob King     }
384784614882SBob King 
384884614882SBob King     // Test where fails: Required type property not specified
384984614882SBob King     try
385084614882SBob King     {
385184614882SBob King         const json element = R"(
385284614882SBob King             {
385384614882SBob King               "command": "0x8C",
385484614882SBob King               "format": "linear_11"
385584614882SBob King             }
385684614882SBob King         )"_json;
385784614882SBob King         parsePMBusReadSensor(element);
385884614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
385984614882SBob King     }
386084614882SBob King     catch (const std::invalid_argument& e)
386184614882SBob King     {
386284614882SBob King         EXPECT_STREQ(e.what(), "Required property missing: type");
386384614882SBob King     }
386484614882SBob King 
386584614882SBob King     // Test where fails: Required command property not specified
386684614882SBob King     try
386784614882SBob King     {
386884614882SBob King         const json element = R"(
386984614882SBob King             {
387084614882SBob King               "type": "iout",
387184614882SBob King               "format": "linear_11"
387284614882SBob King             }
387384614882SBob King         )"_json;
387484614882SBob King         parsePMBusReadSensor(element);
387584614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
387684614882SBob King     }
387784614882SBob King     catch (const std::invalid_argument& e)
387884614882SBob King     {
387984614882SBob King         EXPECT_STREQ(e.what(), "Required property missing: command");
388084614882SBob King     }
388184614882SBob King 
388284614882SBob King     // Test where fails: Required format property not specified
388384614882SBob King     try
388484614882SBob King     {
388584614882SBob King         const json element = R"(
388684614882SBob King             {
388784614882SBob King               "type": "iout",
388884614882SBob King               "command": "0x8C"
388984614882SBob King             }
389084614882SBob King         )"_json;
389184614882SBob King         parsePMBusReadSensor(element);
389284614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
389384614882SBob King     }
389484614882SBob King     catch (const std::invalid_argument& e)
389584614882SBob King     {
389684614882SBob King         EXPECT_STREQ(e.what(), "Required property missing: format");
389784614882SBob King     }
389884614882SBob King 
389984614882SBob King     // Test where fails: type value is invalid
390084614882SBob King     try
390184614882SBob King     {
390284614882SBob King         const json element = R"(
390384614882SBob King             {
390484614882SBob King               "type": 1,
390584614882SBob King               "command": "0x7A",
390684614882SBob King               "format": "linear_16"
390784614882SBob King             }
390884614882SBob King         )"_json;
390984614882SBob King         parsePMBusReadSensor(element);
391084614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
391184614882SBob King     }
391284614882SBob King     catch (const std::invalid_argument& e)
391384614882SBob King     {
391484614882SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
391584614882SBob King     }
391684614882SBob King 
391784614882SBob King     // Test where fails: command value is invalid
391884614882SBob King     try
391984614882SBob King     {
392084614882SBob King         const json element = R"(
392184614882SBob King             {
392284614882SBob King               "type": "temperature",
392384614882SBob King               "command": 0,
392484614882SBob King               "format": "linear_16"
392584614882SBob King             }
392684614882SBob King         )"_json;
392784614882SBob King         parsePMBusReadSensor(element);
392884614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
392984614882SBob King     }
393084614882SBob King     catch (const std::invalid_argument& e)
393184614882SBob King     {
393284614882SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
393384614882SBob King     }
393484614882SBob King 
393584614882SBob King     // Test where fails: format value is invalid
393684614882SBob King     try
393784614882SBob King     {
393884614882SBob King         const json element = R"(
393984614882SBob King             {
394084614882SBob King               "type": "temperature",
394184614882SBob King               "command": "0x7A",
394284614882SBob King               "format": 1
394384614882SBob King             }
394484614882SBob King         )"_json;
394584614882SBob King         parsePMBusReadSensor(element);
394684614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
394784614882SBob King     }
394884614882SBob King     catch (const std::invalid_argument& e)
394984614882SBob King     {
395084614882SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
395184614882SBob King     }
395284614882SBob King 
395384614882SBob King     // Test where fails: exponent value is invalid
395484614882SBob King     try
395584614882SBob King     {
395684614882SBob King         const json element = R"(
395784614882SBob King             {
395884614882SBob King               "type": "temperature",
395984614882SBob King               "command": "0x7A",
396084614882SBob King               "format": "linear_16",
396184614882SBob King               "exponent": 1.3
396284614882SBob King             }
396384614882SBob King         )"_json;
396484614882SBob King         parsePMBusReadSensor(element);
396584614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
396684614882SBob King     }
396784614882SBob King     catch (const std::invalid_argument& e)
396884614882SBob King     {
396984614882SBob King         EXPECT_STREQ(e.what(), "Element is not an integer");
397084614882SBob King     }
397184614882SBob King }
397284614882SBob King 
TEST(ConfigFileParserTests,ParsePMBusWriteVoutCommand)39730e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand)
39740e8c68abSShawn McCarney {
39750e8c68abSShawn McCarney     // Test where works: Only required properties specified
39760e8c68abSShawn McCarney     {
39770e8c68abSShawn McCarney         const json element = R"(
39780e8c68abSShawn McCarney             {
39790e8c68abSShawn McCarney               "format": "linear"
39800e8c68abSShawn McCarney             }
39810e8c68abSShawn McCarney         )"_json;
39820e8c68abSShawn McCarney         std::unique_ptr<PMBusWriteVoutCommandAction> action =
39830e8c68abSShawn McCarney             parsePMBusWriteVoutCommand(element);
39840e8c68abSShawn McCarney         EXPECT_EQ(action->getVolts().has_value(), false);
39850e8c68abSShawn McCarney         EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
39860e8c68abSShawn McCarney         EXPECT_EQ(action->getExponent().has_value(), false);
39870e8c68abSShawn McCarney         EXPECT_EQ(action->isVerified(), false);
39880e8c68abSShawn McCarney     }
39890e8c68abSShawn McCarney 
39900e8c68abSShawn McCarney     // Test where works: All properties specified
39910e8c68abSShawn McCarney     {
39920e8c68abSShawn McCarney         const json element = R"(
39930e8c68abSShawn McCarney             {
39940e8c68abSShawn McCarney               "volts": 1.03,
39950e8c68abSShawn McCarney               "format": "linear",
39960e8c68abSShawn McCarney               "exponent": -8,
39970e8c68abSShawn McCarney               "is_verified": true
39980e8c68abSShawn McCarney             }
39990e8c68abSShawn McCarney         )"_json;
40000e8c68abSShawn McCarney         std::unique_ptr<PMBusWriteVoutCommandAction> action =
40010e8c68abSShawn McCarney             parsePMBusWriteVoutCommand(element);
40020e8c68abSShawn McCarney         EXPECT_EQ(action->getVolts().has_value(), true);
40030e8c68abSShawn McCarney         EXPECT_EQ(action->getVolts().value(), 1.03);
40040e8c68abSShawn McCarney         EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear);
40050e8c68abSShawn McCarney         EXPECT_EQ(action->getExponent().has_value(), true);
40060e8c68abSShawn McCarney         EXPECT_EQ(action->getExponent().value(), -8);
40070e8c68abSShawn McCarney         EXPECT_EQ(action->isVerified(), true);
40080e8c68abSShawn McCarney     }
40090e8c68abSShawn McCarney 
40100e8c68abSShawn McCarney     // Test where fails: Element is not an object
40110e8c68abSShawn McCarney     try
40120e8c68abSShawn McCarney     {
40130e8c68abSShawn McCarney         const json element = R"( [ "0xFF", "0x01" ] )"_json;
40140e8c68abSShawn McCarney         parsePMBusWriteVoutCommand(element);
40150e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
40160e8c68abSShawn McCarney     }
40170e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
40180e8c68abSShawn McCarney     {
40190e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an object");
40200e8c68abSShawn McCarney     }
40210e8c68abSShawn McCarney 
40220e8c68abSShawn McCarney     // Test where fails: volts value is invalid
40230e8c68abSShawn McCarney     try
40240e8c68abSShawn McCarney     {
40250e8c68abSShawn McCarney         const json element = R"(
40260e8c68abSShawn McCarney             {
40270e8c68abSShawn McCarney               "volts": "foo",
40280e8c68abSShawn McCarney               "format": "linear"
40290e8c68abSShawn McCarney             }
40300e8c68abSShawn McCarney         )"_json;
40310e8c68abSShawn McCarney         parsePMBusWriteVoutCommand(element);
40320e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
40330e8c68abSShawn McCarney     }
40340e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
40350e8c68abSShawn McCarney     {
40360e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a number");
40370e8c68abSShawn McCarney     }
40380e8c68abSShawn McCarney 
40390e8c68abSShawn McCarney     // Test where fails: Required format property not specified
40400e8c68abSShawn McCarney     try
40410e8c68abSShawn McCarney     {
40420e8c68abSShawn McCarney         const json element = R"(
40430e8c68abSShawn McCarney             {
40440e8c68abSShawn McCarney               "volts": 1.03,
40450e8c68abSShawn McCarney               "is_verified": true
40460e8c68abSShawn McCarney             }
40470e8c68abSShawn McCarney         )"_json;
40480e8c68abSShawn McCarney         parsePMBusWriteVoutCommand(element);
40490e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
40500e8c68abSShawn McCarney     }
40510e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
40520e8c68abSShawn McCarney     {
40530e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: format");
40540e8c68abSShawn McCarney     }
40550e8c68abSShawn McCarney 
40560e8c68abSShawn McCarney     // Test where fails: format value is invalid
40570e8c68abSShawn McCarney     try
40580e8c68abSShawn McCarney     {
40590e8c68abSShawn McCarney         const json element = R"(
40600e8c68abSShawn McCarney             {
40610e8c68abSShawn McCarney               "format": "linear_11"
40620e8c68abSShawn McCarney             }
40630e8c68abSShawn McCarney         )"_json;
40640e8c68abSShawn McCarney         parsePMBusWriteVoutCommand(element);
40650e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
40660e8c68abSShawn McCarney     }
40670e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
40680e8c68abSShawn McCarney     {
40690e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Invalid format value: linear_11");
40700e8c68abSShawn McCarney     }
40710e8c68abSShawn McCarney 
40720e8c68abSShawn McCarney     // Test where fails: exponent value is invalid
40730e8c68abSShawn McCarney     try
40740e8c68abSShawn McCarney     {
40750e8c68abSShawn McCarney         const json element = R"(
40760e8c68abSShawn McCarney             {
40770e8c68abSShawn McCarney               "format": "linear",
40780e8c68abSShawn McCarney               "exponent": 1.3
40790e8c68abSShawn McCarney             }
40800e8c68abSShawn McCarney         )"_json;
40810e8c68abSShawn McCarney         parsePMBusWriteVoutCommand(element);
40820e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
40830e8c68abSShawn McCarney     }
40840e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
40850e8c68abSShawn McCarney     {
40860e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an integer");
40870e8c68abSShawn McCarney     }
40880e8c68abSShawn McCarney 
40890e8c68abSShawn McCarney     // Test where fails: is_verified value is invalid
40900e8c68abSShawn McCarney     try
40910e8c68abSShawn McCarney     {
40920e8c68abSShawn McCarney         const json element = R"(
40930e8c68abSShawn McCarney             {
40940e8c68abSShawn McCarney               "format": "linear",
40950e8c68abSShawn McCarney               "is_verified": "true"
40960e8c68abSShawn McCarney             }
40970e8c68abSShawn McCarney         )"_json;
40980e8c68abSShawn McCarney         parsePMBusWriteVoutCommand(element);
40990e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
41000e8c68abSShawn McCarney     }
41010e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
41020e8c68abSShawn McCarney     {
41030e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a boolean");
41040e8c68abSShawn McCarney     }
41050e8c68abSShawn McCarney 
41060e8c68abSShawn McCarney     // Test where fails: Invalid property specified
41070e8c68abSShawn McCarney     try
41080e8c68abSShawn McCarney     {
41090e8c68abSShawn McCarney         const json element = R"(
41100e8c68abSShawn McCarney             {
41110e8c68abSShawn McCarney               "format": "linear",
41120e8c68abSShawn McCarney               "foo": "bar"
41130e8c68abSShawn McCarney             }
41140e8c68abSShawn McCarney         )"_json;
41150e8c68abSShawn McCarney         parsePMBusWriteVoutCommand(element);
41160e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
41170e8c68abSShawn McCarney     }
41180e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
41190e8c68abSShawn McCarney     {
41200e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an invalid property");
41210e8c68abSShawn McCarney     }
41220e8c68abSShawn McCarney }
41230e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParsePresenceDetection)41242aafb1c7SBob King TEST(ConfigFileParserTests, ParsePresenceDetection)
41252aafb1c7SBob King {
41262aafb1c7SBob King     // Test where works: actions property specified
41272aafb1c7SBob King     {
41282aafb1c7SBob King         const json element = R"(
41292aafb1c7SBob King             {
41302aafb1c7SBob King               "actions": [
41312aafb1c7SBob King                 { "run_rule": "read_sensors_rule" }
41322aafb1c7SBob King               ]
41332aafb1c7SBob King             }
41342aafb1c7SBob King         )"_json;
41352aafb1c7SBob King         std::unique_ptr<PresenceDetection> presenceDetection =
41362aafb1c7SBob King             parsePresenceDetection(element);
41372aafb1c7SBob King         EXPECT_EQ(presenceDetection->getActions().size(), 1);
41382aafb1c7SBob King     }
41392aafb1c7SBob King 
41402aafb1c7SBob King     // Test where works: rule_id property specified
41412aafb1c7SBob King     {
41422aafb1c7SBob King         const json element = R"(
41432aafb1c7SBob King             {
41442aafb1c7SBob King               "comments": [ "comments property" ],
41452aafb1c7SBob King               "rule_id": "set_voltage_rule"
41462aafb1c7SBob King             }
41472aafb1c7SBob King         )"_json;
41482aafb1c7SBob King         std::unique_ptr<PresenceDetection> presenceDetection =
41492aafb1c7SBob King             parsePresenceDetection(element);
41502aafb1c7SBob King         EXPECT_EQ(presenceDetection->getActions().size(), 1);
41512aafb1c7SBob King     }
41522aafb1c7SBob King 
41532aafb1c7SBob King     // Test where fails: actions object is invalid
41542aafb1c7SBob King     try
41552aafb1c7SBob King     {
41562aafb1c7SBob King         const json element = R"(
41572aafb1c7SBob King             {
41582aafb1c7SBob King               "actions": 1
41592aafb1c7SBob King             }
41602aafb1c7SBob King         )"_json;
41612aafb1c7SBob King         parsePresenceDetection(element);
41622aafb1c7SBob King         ADD_FAILURE() << "Should not have reached this line.";
41632aafb1c7SBob King     }
41642aafb1c7SBob King     catch (const std::invalid_argument& e)
41652aafb1c7SBob King     {
41662aafb1c7SBob King         EXPECT_STREQ(e.what(), "Element is not an array");
41672aafb1c7SBob King     }
41682aafb1c7SBob King 
41692aafb1c7SBob King     // Test where fails: rule_id value is invalid
41702aafb1c7SBob King     try
41712aafb1c7SBob King     {
41722aafb1c7SBob King         const json element = R"(
41732aafb1c7SBob King             {
41742aafb1c7SBob King               "rule_id": 1
41752aafb1c7SBob King             }
41762aafb1c7SBob King         )"_json;
41772aafb1c7SBob King         parsePresenceDetection(element);
41782aafb1c7SBob King         ADD_FAILURE() << "Should not have reached this line.";
41792aafb1c7SBob King     }
41802aafb1c7SBob King     catch (const std::invalid_argument& e)
41812aafb1c7SBob King     {
41822aafb1c7SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
41832aafb1c7SBob King     }
41842aafb1c7SBob King 
41852aafb1c7SBob King     // Test where fails: Required actions or rule_id property not specified
41862aafb1c7SBob King     try
41872aafb1c7SBob King     {
41882aafb1c7SBob King         const json element = R"(
41892aafb1c7SBob King             {
41902aafb1c7SBob King               "comments": [ "comments property" ]
41912aafb1c7SBob King             }
41922aafb1c7SBob King         )"_json;
41932aafb1c7SBob King         parsePresenceDetection(element);
41942aafb1c7SBob King         ADD_FAILURE() << "Should not have reached this line.";
41952aafb1c7SBob King     }
41962aafb1c7SBob King     catch (const std::invalid_argument& e)
41972aafb1c7SBob King     {
41982aafb1c7SBob King         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
41992aafb1c7SBob King                                "either rule_id or actions");
42002aafb1c7SBob King     }
42012aafb1c7SBob King 
42022aafb1c7SBob King     // Test where fails: Required actions or rule_id property both specified
42032aafb1c7SBob King     try
42042aafb1c7SBob King     {
42052aafb1c7SBob King         const json element = R"(
42062aafb1c7SBob King             {
42072aafb1c7SBob King               "rule_id": "set_voltage_rule",
42082aafb1c7SBob King               "actions": [
42092aafb1c7SBob King                 { "run_rule": "read_sensors_rule" }
42102aafb1c7SBob King               ]
42112aafb1c7SBob King             }
42122aafb1c7SBob King         )"_json;
42132aafb1c7SBob King         parsePresenceDetection(element);
42142aafb1c7SBob King         ADD_FAILURE() << "Should not have reached this line.";
42152aafb1c7SBob King     }
42162aafb1c7SBob King     catch (const std::invalid_argument& e)
42172aafb1c7SBob King     {
42182aafb1c7SBob King         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
42192aafb1c7SBob King                                "either rule_id or actions");
42202aafb1c7SBob King     }
42212aafb1c7SBob King 
42222aafb1c7SBob King     // Test where fails: Element is not an object
42232aafb1c7SBob King     try
42242aafb1c7SBob King     {
42252aafb1c7SBob King         const json element = R"( [ "foo", "bar" ] )"_json;
42262aafb1c7SBob King         parsePresenceDetection(element);
42272aafb1c7SBob King         ADD_FAILURE() << "Should not have reached this line.";
42282aafb1c7SBob King     }
42292aafb1c7SBob King     catch (const std::invalid_argument& e)
42302aafb1c7SBob King     {
42312aafb1c7SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
42322aafb1c7SBob King     }
42332aafb1c7SBob King 
42342aafb1c7SBob King     // Test where fails: Invalid property specified
42352aafb1c7SBob King     try
42362aafb1c7SBob King     {
42372aafb1c7SBob King         const json element = R"(
42382aafb1c7SBob King             {
42392aafb1c7SBob King               "foo": "bar",
42402aafb1c7SBob King               "actions": [
42412aafb1c7SBob King                 { "run_rule": "read_sensors_rule" }
42422aafb1c7SBob King               ]
42432aafb1c7SBob King             }
42442aafb1c7SBob King         )"_json;
42452aafb1c7SBob King         parsePresenceDetection(element);
42462aafb1c7SBob King         ADD_FAILURE() << "Should not have reached this line.";
42472aafb1c7SBob King     }
42482aafb1c7SBob King     catch (const std::invalid_argument& e)
42492aafb1c7SBob King     {
42502aafb1c7SBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
42512aafb1c7SBob King     }
42522aafb1c7SBob King }
42532aafb1c7SBob King 
TEST(ConfigFileParserTests,ParseRail)4254a2f2a0dcSBob King TEST(ConfigFileParserTests, ParseRail)
4255a2f2a0dcSBob King {
4256a2f2a0dcSBob King     // Test where works: Only required properties specified
4257a2f2a0dcSBob King     {
4258a2f2a0dcSBob King         const json element = R"(
4259a2f2a0dcSBob King             {
4260a2f2a0dcSBob King               "id": "vdd"
4261a2f2a0dcSBob King             }
4262a2f2a0dcSBob King         )"_json;
4263a2f2a0dcSBob King         std::unique_ptr<Rail> rail = parseRail(element);
4264a2f2a0dcSBob King         EXPECT_EQ(rail->getID(), "vdd");
4265a2f2a0dcSBob King         EXPECT_EQ(rail->getConfiguration(), nullptr);
4266a2f2a0dcSBob King         EXPECT_EQ(rail->getSensorMonitoring(), nullptr);
4267a2f2a0dcSBob King     }
4268a2f2a0dcSBob King 
4269a2f2a0dcSBob King     // Test where works: All properties specified
4270a2f2a0dcSBob King     {
4271a2f2a0dcSBob King         const json element = R"(
4272a2f2a0dcSBob King             {
4273a2f2a0dcSBob King               "comments": [ "comments property" ],
4274a2f2a0dcSBob King               "id": "vdd",
4275a2f2a0dcSBob King               "configuration": {
4276a2f2a0dcSBob King                 "volts": 1.1,
4277a2f2a0dcSBob King                 "actions": [
4278a2f2a0dcSBob King                   {
4279a2f2a0dcSBob King                     "pmbus_write_vout_command": {
4280a2f2a0dcSBob King                       "format": "linear"
4281a2f2a0dcSBob King                     }
4282a2f2a0dcSBob King                   }
4283a2f2a0dcSBob King                 ]
4284a2f2a0dcSBob King               },
4285a2f2a0dcSBob King               "sensor_monitoring": {
4286a2f2a0dcSBob King                 "actions": [
4287a2f2a0dcSBob King                   { "run_rule": "read_sensors_rule" }
4288a2f2a0dcSBob King                 ]
4289a2f2a0dcSBob King               }
4290a2f2a0dcSBob King             }
4291a2f2a0dcSBob King         )"_json;
4292a2f2a0dcSBob King         std::unique_ptr<Rail> rail = parseRail(element);
4293a2f2a0dcSBob King         EXPECT_EQ(rail->getID(), "vdd");
4294a2f2a0dcSBob King         EXPECT_NE(rail->getConfiguration(), nullptr);
4295a2f2a0dcSBob King         EXPECT_NE(rail->getSensorMonitoring(), nullptr);
4296a2f2a0dcSBob King     }
4297a2f2a0dcSBob King 
4298a2f2a0dcSBob King     // Test where fails: id property not specified
4299a2f2a0dcSBob King     try
4300a2f2a0dcSBob King     {
4301a2f2a0dcSBob King         const json element = R"(
4302a2f2a0dcSBob King             {
4303a2f2a0dcSBob King               "configuration": {
4304a2f2a0dcSBob King                 "volts": 1.1,
4305a2f2a0dcSBob King                 "actions": [
4306a2f2a0dcSBob King                   {
4307a2f2a0dcSBob King                     "pmbus_write_vout_command": {
4308a2f2a0dcSBob King                       "format": "linear"
4309a2f2a0dcSBob King                     }
4310a2f2a0dcSBob King                   }
4311a2f2a0dcSBob King                 ]
4312a2f2a0dcSBob King               }
4313a2f2a0dcSBob King             }
4314a2f2a0dcSBob King         )"_json;
4315a2f2a0dcSBob King         parseRail(element);
4316a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4317a2f2a0dcSBob King     }
4318a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4319a2f2a0dcSBob King     {
4320a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Required property missing: id");
4321a2f2a0dcSBob King     }
4322a2f2a0dcSBob King 
4323a2f2a0dcSBob King     // Test where fails: id property is invalid
4324a2f2a0dcSBob King     try
4325a2f2a0dcSBob King     {
4326a2f2a0dcSBob King         const json element = R"(
4327a2f2a0dcSBob King             {
4328a2f2a0dcSBob King               "id": "",
4329a2f2a0dcSBob King               "configuration": {
4330a2f2a0dcSBob King                 "volts": 1.1,
4331a2f2a0dcSBob King                 "actions": [
4332a2f2a0dcSBob King                   {
4333a2f2a0dcSBob King                     "pmbus_write_vout_command": {
4334a2f2a0dcSBob King                       "format": "linear"
4335a2f2a0dcSBob King                     }
4336a2f2a0dcSBob King                   }
4337a2f2a0dcSBob King                 ]
4338a2f2a0dcSBob King               }
4339a2f2a0dcSBob King             }
4340a2f2a0dcSBob King         )"_json;
4341a2f2a0dcSBob King         parseRail(element);
4342a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4343a2f2a0dcSBob King     }
4344a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4345a2f2a0dcSBob King     {
4346a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element contains an empty string");
4347a2f2a0dcSBob King     }
4348a2f2a0dcSBob King 
4349a2f2a0dcSBob King     // Test where fails: Element is not an object
4350a2f2a0dcSBob King     try
4351a2f2a0dcSBob King     {
4352a2f2a0dcSBob King         const json element = R"( [ "0xFF", "0x01" ] )"_json;
4353a2f2a0dcSBob King         parseRail(element);
4354a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4355a2f2a0dcSBob King     }
4356a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4357a2f2a0dcSBob King     {
4358a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
4359a2f2a0dcSBob King     }
4360a2f2a0dcSBob King 
4361a2f2a0dcSBob King     // Test where fails: configuration value is invalid
4362a2f2a0dcSBob King     try
4363a2f2a0dcSBob King     {
4364a2f2a0dcSBob King         const json element = R"(
4365a2f2a0dcSBob King             {
4366a2f2a0dcSBob King               "id": "vdd",
4367a2f2a0dcSBob King               "configuration": "config"
4368a2f2a0dcSBob King             }
4369a2f2a0dcSBob King         )"_json;
4370a2f2a0dcSBob King         parseRail(element);
4371a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4372a2f2a0dcSBob King     }
4373a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4374a2f2a0dcSBob King     {
4375a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
4376a2f2a0dcSBob King     }
4377a2f2a0dcSBob King 
4378a2f2a0dcSBob King     // Test where fails: sensor_monitoring value is invalid
4379a2f2a0dcSBob King     try
4380a2f2a0dcSBob King     {
4381a2f2a0dcSBob King         const json element = R"(
4382a2f2a0dcSBob King             {
4383a2f2a0dcSBob King               "comments": [ "comments property" ],
4384a2f2a0dcSBob King               "id": "vdd",
4385a2f2a0dcSBob King               "configuration": {
4386a2f2a0dcSBob King                 "volts": 1.1,
4387a2f2a0dcSBob King                 "actions": [
4388a2f2a0dcSBob King                   {
4389a2f2a0dcSBob King                     "pmbus_write_vout_command": {
4390a2f2a0dcSBob King                       "format": "linear"
4391a2f2a0dcSBob King                     }
4392a2f2a0dcSBob King                   }
4393a2f2a0dcSBob King                 ]
4394a2f2a0dcSBob King               },
4395a2f2a0dcSBob King               "sensor_monitoring": 1
4396a2f2a0dcSBob King             }
4397a2f2a0dcSBob King         )"_json;
4398a2f2a0dcSBob King         parseRail(element);
4399a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4400a2f2a0dcSBob King     }
4401a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4402a2f2a0dcSBob King     {
4403a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
4404a2f2a0dcSBob King     }
4405a2f2a0dcSBob King 
4406a2f2a0dcSBob King     // Test where fails: Invalid property specified
4407a2f2a0dcSBob King     try
4408a2f2a0dcSBob King     {
4409a2f2a0dcSBob King         const json element = R"(
4410a2f2a0dcSBob King             {
4411a2f2a0dcSBob King               "id": "vdd",
4412a2f2a0dcSBob King               "foo" : true
4413a2f2a0dcSBob King             }
4414a2f2a0dcSBob King         )"_json;
4415a2f2a0dcSBob King         parseRail(element);
4416a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4417a2f2a0dcSBob King     }
4418a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4419a2f2a0dcSBob King     {
4420a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
4421a2f2a0dcSBob King     }
4422a2f2a0dcSBob King }
4423a2f2a0dcSBob King 
TEST(ConfigFileParserTests,ParseRailArray)4424a2f2a0dcSBob King TEST(ConfigFileParserTests, ParseRailArray)
4425a2f2a0dcSBob King {
4426a2f2a0dcSBob King     // Test where works
4427a2f2a0dcSBob King     {
4428a2f2a0dcSBob King         const json element = R"(
4429a2f2a0dcSBob King             [
4430a2f2a0dcSBob King               { "id": "vdd" },
4431a2f2a0dcSBob King               { "id": "vio" }
4432a2f2a0dcSBob King             ]
4433a2f2a0dcSBob King         )"_json;
4434a2f2a0dcSBob King         std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
4435a2f2a0dcSBob King         EXPECT_EQ(rails.size(), 2);
4436a2f2a0dcSBob King         EXPECT_EQ(rails[0]->getID(), "vdd");
4437a2f2a0dcSBob King         EXPECT_EQ(rails[1]->getID(), "vio");
4438a2f2a0dcSBob King     }
4439a2f2a0dcSBob King 
4440a2f2a0dcSBob King     // Test where fails: Element is not an array
4441a2f2a0dcSBob King     try
4442a2f2a0dcSBob King     {
4443a2f2a0dcSBob King         const json element = R"(
4444a2f2a0dcSBob King             {
4445a2f2a0dcSBob King               "foo": "bar"
4446a2f2a0dcSBob King             }
4447a2f2a0dcSBob King         )"_json;
4448a2f2a0dcSBob King         parseRailArray(element);
4449a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4450a2f2a0dcSBob King     }
4451a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4452a2f2a0dcSBob King     {
4453a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element is not an array");
4454a2f2a0dcSBob King     }
4455a2f2a0dcSBob King }
4456a2f2a0dcSBob King 
TEST(ConfigFileParserTests,ParseRoot)44570e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseRoot)
44580e8c68abSShawn McCarney {
44590e8c68abSShawn McCarney     // Test where works: Only required properties specified
44600e8c68abSShawn McCarney     {
44610e8c68abSShawn McCarney         const json element = R"(
44620e8c68abSShawn McCarney             {
44630e8c68abSShawn McCarney               "chassis": [
44644c88a4c2SShawn McCarney                 { "number": 1, "inventory_path": "system/chassis" }
44650e8c68abSShawn McCarney               ]
44660e8c68abSShawn McCarney             }
44670e8c68abSShawn McCarney         )"_json;
44680e8c68abSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
44690e8c68abSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassis{};
44700e8c68abSShawn McCarney         std::tie(rules, chassis) = parseRoot(element);
44710e8c68abSShawn McCarney         EXPECT_EQ(rules.size(), 0);
44720e70113dSBob King         EXPECT_EQ(chassis.size(), 1);
44730e8c68abSShawn McCarney     }
44740e8c68abSShawn McCarney 
44750e8c68abSShawn McCarney     // Test where works: All properties specified
44760e8c68abSShawn McCarney     {
44770e8c68abSShawn McCarney         const json element = R"(
44780e8c68abSShawn McCarney             {
44790e8c68abSShawn McCarney               "comments": [ "Config file for a FooBar one-chassis system" ],
44800e8c68abSShawn McCarney               "rules": [
44810e8c68abSShawn McCarney                 {
44820e8c68abSShawn McCarney                   "id": "set_voltage_rule",
44830e8c68abSShawn McCarney                   "actions": [
44840e8c68abSShawn McCarney                     { "pmbus_write_vout_command": { "format": "linear" } }
44850e8c68abSShawn McCarney                   ]
44860e8c68abSShawn McCarney                 }
44870e8c68abSShawn McCarney               ],
44880e8c68abSShawn McCarney               "chassis": [
44894c88a4c2SShawn McCarney                 { "number": 1, "inventory_path": "system/chassis1" },
44904c88a4c2SShawn McCarney                 { "number": 3, "inventory_path": "system/chassis3" }
44910e8c68abSShawn McCarney               ]
44920e8c68abSShawn McCarney             }
44930e8c68abSShawn McCarney         )"_json;
44940e8c68abSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
44950e8c68abSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassis{};
44960e8c68abSShawn McCarney         std::tie(rules, chassis) = parseRoot(element);
44970e8c68abSShawn McCarney         EXPECT_EQ(rules.size(), 1);
44980e70113dSBob King         EXPECT_EQ(chassis.size(), 2);
44990e8c68abSShawn McCarney     }
45000e8c68abSShawn McCarney 
45010e8c68abSShawn McCarney     // Test where fails: Element is not an object
45020e8c68abSShawn McCarney     try
45030e8c68abSShawn McCarney     {
45040e8c68abSShawn McCarney         const json element = R"( [ "0xFF", "0x01" ] )"_json;
45050e8c68abSShawn McCarney         parseRoot(element);
45060e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
45070e8c68abSShawn McCarney     }
45080e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
45090e8c68abSShawn McCarney     {
45100e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an object");
45110e8c68abSShawn McCarney     }
45120e8c68abSShawn McCarney 
45130e8c68abSShawn McCarney     // Test where fails: chassis property not specified
45140e8c68abSShawn McCarney     try
45150e8c68abSShawn McCarney     {
45160e8c68abSShawn McCarney         const json element = R"(
45170e8c68abSShawn McCarney             {
45180e8c68abSShawn McCarney               "rules": [
45190e8c68abSShawn McCarney                 {
45200e8c68abSShawn McCarney                   "id": "set_voltage_rule",
45210e8c68abSShawn McCarney                   "actions": [
45220e8c68abSShawn McCarney                     { "pmbus_write_vout_command": { "format": "linear" } }
45230e8c68abSShawn McCarney                   ]
45240e8c68abSShawn McCarney                 }
45250e8c68abSShawn McCarney               ]
45260e8c68abSShawn McCarney             }
45270e8c68abSShawn McCarney         )"_json;
45280e8c68abSShawn McCarney         parseRoot(element);
45290e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
45300e8c68abSShawn McCarney     }
45310e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
45320e8c68abSShawn McCarney     {
45330e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: chassis");
45340e8c68abSShawn McCarney     }
45350e8c68abSShawn McCarney 
45360e8c68abSShawn McCarney     // Test where fails: Invalid property specified
45370e8c68abSShawn McCarney     try
45380e8c68abSShawn McCarney     {
45390e8c68abSShawn McCarney         const json element = R"(
45400e8c68abSShawn McCarney             {
45410e8c68abSShawn McCarney               "remarks": [ "Config file for a FooBar one-chassis system" ],
45420e8c68abSShawn McCarney               "chassis": [
45434c88a4c2SShawn McCarney                 { "number": 1, "inventory_path": "system/chassis" }
45440e8c68abSShawn McCarney               ]
45450e8c68abSShawn McCarney             }
45460e8c68abSShawn McCarney         )"_json;
45470e8c68abSShawn McCarney         parseRoot(element);
45480e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
45490e8c68abSShawn McCarney     }
45500e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
45510e8c68abSShawn McCarney     {
45520e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an invalid property");
45530e8c68abSShawn McCarney     }
45540e8c68abSShawn McCarney }
45550e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseRule)45560e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseRule)
45570e8c68abSShawn McCarney {
45580e8c68abSShawn McCarney     // Test where works: comments property specified
45590e8c68abSShawn McCarney     {
45600e8c68abSShawn McCarney         const json element = R"(
45610e8c68abSShawn McCarney             {
45620e8c68abSShawn McCarney               "comments": [ "Set voltage rule" ],
45630e8c68abSShawn McCarney               "id": "set_voltage_rule",
45640e8c68abSShawn McCarney               "actions": [
45650e8c68abSShawn McCarney                 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
45660e8c68abSShawn McCarney                 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }
45670e8c68abSShawn McCarney               ]
45680e8c68abSShawn McCarney             }
45690e8c68abSShawn McCarney         )"_json;
45700e8c68abSShawn McCarney         std::unique_ptr<Rule> rule = parseRule(element);
45710e8c68abSShawn McCarney         EXPECT_EQ(rule->getID(), "set_voltage_rule");
45720e8c68abSShawn McCarney         EXPECT_EQ(rule->getActions().size(), 2);
45730e8c68abSShawn McCarney     }
45740e8c68abSShawn McCarney 
45750e8c68abSShawn McCarney     // Test where works: comments property not specified
45760e8c68abSShawn McCarney     {
45770e8c68abSShawn McCarney         const json element = R"(
45780e8c68abSShawn McCarney             {
45790e8c68abSShawn McCarney               "id": "set_voltage_rule",
45800e8c68abSShawn McCarney               "actions": [
45810e8c68abSShawn McCarney                 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
45820e8c68abSShawn McCarney                 { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } },
45830e8c68abSShawn McCarney                 { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } }
45840e8c68abSShawn McCarney               ]
45850e8c68abSShawn McCarney             }
45860e8c68abSShawn McCarney         )"_json;
45870e8c68abSShawn McCarney         std::unique_ptr<Rule> rule = parseRule(element);
45880e8c68abSShawn McCarney         EXPECT_EQ(rule->getID(), "set_voltage_rule");
45890e8c68abSShawn McCarney         EXPECT_EQ(rule->getActions().size(), 3);
45900e8c68abSShawn McCarney     }
45910e8c68abSShawn McCarney 
45920e8c68abSShawn McCarney     // Test where fails: Element is not an object
45930e8c68abSShawn McCarney     try
45940e8c68abSShawn McCarney     {
45950e8c68abSShawn McCarney         const json element = R"( [ "0xFF", "0x01" ] )"_json;
45960e8c68abSShawn McCarney         parseRule(element);
45970e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
45980e8c68abSShawn McCarney     }
45990e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
46000e8c68abSShawn McCarney     {
46010e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an object");
46020e8c68abSShawn McCarney     }
46030e8c68abSShawn McCarney 
46040e8c68abSShawn McCarney     // Test where fails: id property not specified
46050e8c68abSShawn McCarney     try
46060e8c68abSShawn McCarney     {
46070e8c68abSShawn McCarney         const json element = R"(
46080e8c68abSShawn McCarney             {
46090e8c68abSShawn McCarney               "actions": [
46100e8c68abSShawn McCarney                 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
46110e8c68abSShawn McCarney               ]
46120e8c68abSShawn McCarney             }
46130e8c68abSShawn McCarney         )"_json;
46140e8c68abSShawn McCarney         parseRule(element);
46150e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
46160e8c68abSShawn McCarney     }
46170e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
46180e8c68abSShawn McCarney     {
46190e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: id");
46200e8c68abSShawn McCarney     }
46210e8c68abSShawn McCarney 
46220e8c68abSShawn McCarney     // Test where fails: id property is invalid
46230e8c68abSShawn McCarney     try
46240e8c68abSShawn McCarney     {
46250e8c68abSShawn McCarney         const json element = R"(
46260e8c68abSShawn McCarney             {
46270e8c68abSShawn McCarney               "id": "",
46280e8c68abSShawn McCarney               "actions": [
46290e8c68abSShawn McCarney                 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
46300e8c68abSShawn McCarney               ]
46310e8c68abSShawn McCarney             }
46320e8c68abSShawn McCarney         )"_json;
46330e8c68abSShawn McCarney         parseRule(element);
46340e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
46350e8c68abSShawn McCarney     }
46360e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
46370e8c68abSShawn McCarney     {
46380e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an empty string");
46390e8c68abSShawn McCarney     }
46400e8c68abSShawn McCarney 
46410e8c68abSShawn McCarney     // Test where fails: actions property not specified
46420e8c68abSShawn McCarney     try
46430e8c68abSShawn McCarney     {
46440e8c68abSShawn McCarney         const json element = R"(
46450e8c68abSShawn McCarney             {
46460e8c68abSShawn McCarney               "comments": [ "Set voltage rule" ],
46470e8c68abSShawn McCarney               "id": "set_voltage_rule"
46480e8c68abSShawn McCarney             }
46490e8c68abSShawn McCarney         )"_json;
46500e8c68abSShawn McCarney         parseRule(element);
46510e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
46520e8c68abSShawn McCarney     }
46530e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
46540e8c68abSShawn McCarney     {
46550e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Required property missing: actions");
46560e8c68abSShawn McCarney     }
46570e8c68abSShawn McCarney 
46580e8c68abSShawn McCarney     // Test where fails: actions property is invalid
46590e8c68abSShawn McCarney     try
46600e8c68abSShawn McCarney     {
46610e8c68abSShawn McCarney         const json element = R"(
46620e8c68abSShawn McCarney             {
46630e8c68abSShawn McCarney               "id": "set_voltage_rule",
46640e8c68abSShawn McCarney               "actions": true
46650e8c68abSShawn McCarney             }
46660e8c68abSShawn McCarney         )"_json;
46670e8c68abSShawn McCarney         parseRule(element);
46680e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
46690e8c68abSShawn McCarney     }
46700e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
46710e8c68abSShawn McCarney     {
46720e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an array");
46730e8c68abSShawn McCarney     }
46740e8c68abSShawn McCarney 
46750e8c68abSShawn McCarney     // Test where fails: Invalid property specified
46760e8c68abSShawn McCarney     try
46770e8c68abSShawn McCarney     {
46780e8c68abSShawn McCarney         const json element = R"(
46790e8c68abSShawn McCarney             {
46800e8c68abSShawn McCarney               "remarks": [ "Set voltage rule" ],
46810e8c68abSShawn McCarney               "id": "set_voltage_rule",
46820e8c68abSShawn McCarney               "actions": [
46830e8c68abSShawn McCarney                 { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
46840e8c68abSShawn McCarney               ]
46850e8c68abSShawn McCarney             }
46860e8c68abSShawn McCarney         )"_json;
46870e8c68abSShawn McCarney         parseRule(element);
46880e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
46890e8c68abSShawn McCarney     }
46900e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
46910e8c68abSShawn McCarney     {
46920e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an invalid property");
46930e8c68abSShawn McCarney     }
46940e8c68abSShawn McCarney }
46950e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseRuleArray)46960e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseRuleArray)
46970e8c68abSShawn McCarney {
46980e8c68abSShawn McCarney     // Test where works
46990e8c68abSShawn McCarney     {
47000e8c68abSShawn McCarney         const json element = R"(
47010e8c68abSShawn McCarney             [
47020e8c68abSShawn McCarney               {
47030e8c68abSShawn McCarney                 "id": "set_voltage_rule1",
47040e8c68abSShawn McCarney                 "actions": [
47050e8c68abSShawn McCarney                   { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }
47060e8c68abSShawn McCarney                 ]
47070e8c68abSShawn McCarney               },
47080e8c68abSShawn McCarney               {
47090e8c68abSShawn McCarney                 "id": "set_voltage_rule2",
47100e8c68abSShawn McCarney                 "actions": [
47110e8c68abSShawn McCarney                   { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } },
47120e8c68abSShawn McCarney                   { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } }
47130e8c68abSShawn McCarney                 ]
47140e8c68abSShawn McCarney               }
47150e8c68abSShawn McCarney             ]
47160e8c68abSShawn McCarney         )"_json;
47170e8c68abSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element);
47180e8c68abSShawn McCarney         EXPECT_EQ(rules.size(), 2);
47190e8c68abSShawn McCarney         EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1");
47200e8c68abSShawn McCarney         EXPECT_EQ(rules[0]->getActions().size(), 1);
47210e8c68abSShawn McCarney         EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2");
47220e8c68abSShawn McCarney         EXPECT_EQ(rules[1]->getActions().size(), 2);
47230e8c68abSShawn McCarney     }
47240e8c68abSShawn McCarney 
47250e8c68abSShawn McCarney     // Test where fails: Element is not an array
47260e8c68abSShawn McCarney     try
47270e8c68abSShawn McCarney     {
47280e8c68abSShawn McCarney         const json element = R"( { "id": "set_voltage_rule" } )"_json;
47290e8c68abSShawn McCarney         parseRuleArray(element);
47300e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
47310e8c68abSShawn McCarney     }
47320e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
47330e8c68abSShawn McCarney     {
47340e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an array");
47350e8c68abSShawn McCarney     }
47360e8c68abSShawn McCarney }
47370e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseRuleIDOrActionsProperty)473833e7eaa5SBob King TEST(ConfigFileParserTests, ParseRuleIDOrActionsProperty)
473933e7eaa5SBob King {
474033e7eaa5SBob King     // Test where works: actions specified
474133e7eaa5SBob King     {
474233e7eaa5SBob King         const json element = R"(
474333e7eaa5SBob King             {
474433e7eaa5SBob King               "actions": [
474533e7eaa5SBob King                 { "pmbus_write_vout_command": { "format": "linear" } },
474633e7eaa5SBob King                 { "run_rule": "set_voltage_rule" }
474733e7eaa5SBob King               ]
474833e7eaa5SBob King             }
474933e7eaa5SBob King         )"_json;
475033e7eaa5SBob King         std::vector<std::unique_ptr<Action>> actions =
475133e7eaa5SBob King             parseRuleIDOrActionsProperty(element);
475233e7eaa5SBob King         EXPECT_EQ(actions.size(), 2);
475333e7eaa5SBob King     }
475433e7eaa5SBob King 
475533e7eaa5SBob King     // Test where works: rule_id specified
475633e7eaa5SBob King     {
475733e7eaa5SBob King         const json element = R"(
475833e7eaa5SBob King             {
475933e7eaa5SBob King               "rule_id": "set_voltage_rule"
476033e7eaa5SBob King             }
476133e7eaa5SBob King         )"_json;
476233e7eaa5SBob King         std::vector<std::unique_ptr<Action>> actions =
476333e7eaa5SBob King             parseRuleIDOrActionsProperty(element);
476433e7eaa5SBob King         EXPECT_EQ(actions.size(), 1);
476533e7eaa5SBob King     }
476633e7eaa5SBob King 
476733e7eaa5SBob King     // Test where fails: Element is not an object
476833e7eaa5SBob King     try
476933e7eaa5SBob King     {
477033e7eaa5SBob King         const json element = R"( [ "foo", "bar" ] )"_json;
477133e7eaa5SBob King         parseRuleIDOrActionsProperty(element);
477233e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
477333e7eaa5SBob King     }
477433e7eaa5SBob King     catch (const std::invalid_argument& e)
477533e7eaa5SBob King     {
477633e7eaa5SBob King         EXPECT_STREQ(e.what(), "Element is not an object");
477733e7eaa5SBob King     }
477833e7eaa5SBob King 
477933e7eaa5SBob King     // Test where fails: rule_id is invalid
478033e7eaa5SBob King     try
478133e7eaa5SBob King     {
478233e7eaa5SBob King         const json element = R"(
478333e7eaa5SBob King             { "rule_id": 1 }
478433e7eaa5SBob King         )"_json;
478533e7eaa5SBob King         parseRuleIDOrActionsProperty(element);
478633e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
478733e7eaa5SBob King     }
478833e7eaa5SBob King     catch (const std::invalid_argument& e)
478933e7eaa5SBob King     {
479033e7eaa5SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
479133e7eaa5SBob King     }
479233e7eaa5SBob King 
479333e7eaa5SBob King     // Test where fails: actions is invalid
479433e7eaa5SBob King     try
479533e7eaa5SBob King     {
479633e7eaa5SBob King         const json element = R"(
479733e7eaa5SBob King             { "actions": 1 }
479833e7eaa5SBob King         )"_json;
479933e7eaa5SBob King         parseRuleIDOrActionsProperty(element);
480033e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
480133e7eaa5SBob King     }
480233e7eaa5SBob King     catch (const std::invalid_argument& e)
480333e7eaa5SBob King     {
480433e7eaa5SBob King         EXPECT_STREQ(e.what(), "Element is not an array");
480533e7eaa5SBob King     }
480633e7eaa5SBob King 
480733e7eaa5SBob King     // Test where fails: Neither rule_id nor actions specified
480833e7eaa5SBob King     try
480933e7eaa5SBob King     {
481033e7eaa5SBob King         const json element = R"(
481133e7eaa5SBob King             {
481233e7eaa5SBob King               "volts": 1.03
481333e7eaa5SBob King             }
481433e7eaa5SBob King         )"_json;
481533e7eaa5SBob King         parseRuleIDOrActionsProperty(element);
481633e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
481733e7eaa5SBob King     }
481833e7eaa5SBob King     catch (const std::invalid_argument& e)
481933e7eaa5SBob King     {
482033e7eaa5SBob King         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
482133e7eaa5SBob King                                "either rule_id or actions");
482233e7eaa5SBob King     }
482333e7eaa5SBob King 
482433e7eaa5SBob King     // Test where fails: Both rule_id and actions specified
482533e7eaa5SBob King     try
482633e7eaa5SBob King     {
482733e7eaa5SBob King         const json element = R"(
482833e7eaa5SBob King             {
482933e7eaa5SBob King               "volts": 1.03,
483033e7eaa5SBob King               "rule_id": "set_voltage_rule",
483133e7eaa5SBob King               "actions": [
483233e7eaa5SBob King                 {
483333e7eaa5SBob King                   "pmbus_write_vout_command": {
483433e7eaa5SBob King                     "format": "linear"
483533e7eaa5SBob King                   }
483633e7eaa5SBob King                 }
483733e7eaa5SBob King               ]
483833e7eaa5SBob King             }
483933e7eaa5SBob King         )"_json;
484033e7eaa5SBob King         parseRuleIDOrActionsProperty(element);
484133e7eaa5SBob King         ADD_FAILURE() << "Should not have reached this line.";
484233e7eaa5SBob King     }
484333e7eaa5SBob King     catch (const std::invalid_argument& e)
484433e7eaa5SBob King     {
484533e7eaa5SBob King         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
484633e7eaa5SBob King                                "either rule_id or actions");
484733e7eaa5SBob King     }
484833e7eaa5SBob King }
484933e7eaa5SBob King 
TEST(ConfigFileParserTests,ParseRunRule)4850315b0b62SBob King TEST(ConfigFileParserTests, ParseRunRule)
4851315b0b62SBob King {
4852315b0b62SBob King     // Test where works
4853315b0b62SBob King     {
4854315b0b62SBob King         const json element = "vdd_regulator";
4855315b0b62SBob King         std::unique_ptr<RunRuleAction> action = parseRunRule(element);
4856315b0b62SBob King         EXPECT_EQ(action->getRuleID(), "vdd_regulator");
4857315b0b62SBob King     }
4858315b0b62SBob King 
4859315b0b62SBob King     // Test where fails: Element is not a string
4860315b0b62SBob King     try
4861315b0b62SBob King     {
4862315b0b62SBob King         const json element = 1;
4863315b0b62SBob King         parseRunRule(element);
4864315b0b62SBob King         ADD_FAILURE() << "Should not have reached this line.";
4865315b0b62SBob King     }
4866315b0b62SBob King     catch (const std::invalid_argument& e)
4867315b0b62SBob King     {
4868315b0b62SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
4869315b0b62SBob King     }
4870315b0b62SBob King 
4871315b0b62SBob King     // Test where fails: Empty string
4872315b0b62SBob King     try
4873315b0b62SBob King     {
4874315b0b62SBob King         const json element = "";
4875315b0b62SBob King         parseRunRule(element);
4876315b0b62SBob King         ADD_FAILURE() << "Should not have reached this line.";
4877315b0b62SBob King     }
4878315b0b62SBob King     catch (const std::invalid_argument& e)
4879315b0b62SBob King     {
4880315b0b62SBob King         EXPECT_STREQ(e.what(), "Element contains an empty string");
4881315b0b62SBob King     }
4882315b0b62SBob King }
4883315b0b62SBob King 
TEST(ConfigFileParserTests,ParseSensorDataFormat)488484614882SBob King TEST(ConfigFileParserTests, ParseSensorDataFormat)
488584614882SBob King {
488684614882SBob King     // Test where works: linear_11
488784614882SBob King     {
488884614882SBob King         const json element = "linear_11";
488984614882SBob King         pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element);
489084614882SBob King         pmbus_utils::SensorDataFormat format =
489184614882SBob King             pmbus_utils::SensorDataFormat::linear_11;
489284614882SBob King         EXPECT_EQ(value, format);
489384614882SBob King     }
489484614882SBob King 
489584614882SBob King     // Test where works: linear_16
489684614882SBob King     {
489784614882SBob King         const json element = "linear_16";
489884614882SBob King         pmbus_utils::SensorDataFormat value = parseSensorDataFormat(element);
489984614882SBob King         pmbus_utils::SensorDataFormat format =
490084614882SBob King             pmbus_utils::SensorDataFormat::linear_16;
490184614882SBob King         EXPECT_EQ(value, format);
490284614882SBob King     }
490384614882SBob King 
490484614882SBob King     // Test where fails: Element is not a sensor data format
490584614882SBob King     try
490684614882SBob King     {
490784614882SBob King         const json element = "foo";
490884614882SBob King         parseSensorDataFormat(element);
490984614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
491084614882SBob King     }
491184614882SBob King     catch (const std::invalid_argument& e)
491284614882SBob King     {
491384614882SBob King         EXPECT_STREQ(e.what(), "Element is not a sensor data format");
491484614882SBob King     }
491584614882SBob King 
491684614882SBob King     // Test where fails: Element is not a string
491784614882SBob King     try
491884614882SBob King     {
491984614882SBob King         const json element = R"( { "foo": "bar" } )"_json;
492084614882SBob King         parseSensorDataFormat(element);
492184614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
492284614882SBob King     }
492384614882SBob King     catch (const std::invalid_argument& e)
492484614882SBob King     {
492584614882SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
492684614882SBob King     }
492784614882SBob King }
492884614882SBob King 
TEST(ConfigFileParserTests,ParseSensorMonitoring)4929a2f2a0dcSBob King TEST(ConfigFileParserTests, ParseSensorMonitoring)
4930a2f2a0dcSBob King {
4931a2f2a0dcSBob King     // Test where works: actions property specified
4932a2f2a0dcSBob King     {
4933a2f2a0dcSBob King         const json element = R"(
4934a2f2a0dcSBob King             {
4935a2f2a0dcSBob King               "actions": [
4936a2f2a0dcSBob King                 { "run_rule": "read_sensors_rule" }
4937a2f2a0dcSBob King               ]
4938a2f2a0dcSBob King             }
4939a2f2a0dcSBob King         )"_json;
4940a2f2a0dcSBob King         std::unique_ptr<SensorMonitoring> sensorMonitoring =
4941a2f2a0dcSBob King             parseSensorMonitoring(element);
4942a2f2a0dcSBob King         EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
4943a2f2a0dcSBob King     }
4944a2f2a0dcSBob King 
4945a2f2a0dcSBob King     // Test where works: rule_id property specified
4946a2f2a0dcSBob King     {
4947a2f2a0dcSBob King         const json element = R"(
4948a2f2a0dcSBob King             {
4949a2f2a0dcSBob King               "comments": [ "comments property" ],
4950a2f2a0dcSBob King               "rule_id": "set_voltage_rule"
4951a2f2a0dcSBob King             }
4952a2f2a0dcSBob King         )"_json;
4953a2f2a0dcSBob King         std::unique_ptr<SensorMonitoring> sensorMonitoring =
4954a2f2a0dcSBob King             parseSensorMonitoring(element);
4955a2f2a0dcSBob King         EXPECT_EQ(sensorMonitoring->getActions().size(), 1);
4956a2f2a0dcSBob King     }
4957a2f2a0dcSBob King 
4958a2f2a0dcSBob King     // Test where fails: actions object is invalid
4959a2f2a0dcSBob King     try
4960a2f2a0dcSBob King     {
4961a2f2a0dcSBob King         const json element = R"(
4962a2f2a0dcSBob King             {
4963a2f2a0dcSBob King               "actions": 1
4964a2f2a0dcSBob King             }
4965a2f2a0dcSBob King         )"_json;
4966a2f2a0dcSBob King         parseSensorMonitoring(element);
4967a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4968a2f2a0dcSBob King     }
4969a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4970a2f2a0dcSBob King     {
4971a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element is not an array");
4972a2f2a0dcSBob King     }
4973a2f2a0dcSBob King 
4974a2f2a0dcSBob King     // Test where fails: rule_id value is invalid
4975a2f2a0dcSBob King     try
4976a2f2a0dcSBob King     {
4977a2f2a0dcSBob King         const json element = R"(
4978a2f2a0dcSBob King             {
4979a2f2a0dcSBob King               "rule_id": 1
4980a2f2a0dcSBob King             }
4981a2f2a0dcSBob King         )"_json;
4982a2f2a0dcSBob King         parseSensorMonitoring(element);
4983a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
4984a2f2a0dcSBob King     }
4985a2f2a0dcSBob King     catch (const std::invalid_argument& e)
4986a2f2a0dcSBob King     {
4987a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element is not a string");
4988a2f2a0dcSBob King     }
4989a2f2a0dcSBob King 
4990a2f2a0dcSBob King     // Test where fails: Required actions or rule_id property not specified
4991a2f2a0dcSBob King     try
4992a2f2a0dcSBob King     {
4993a2f2a0dcSBob King         const json element = R"(
4994a2f2a0dcSBob King             {
4995a2f2a0dcSBob King               "comments": [ "comments property" ]
4996a2f2a0dcSBob King             }
4997a2f2a0dcSBob King         )"_json;
4998a2f2a0dcSBob King         parseSensorMonitoring(element);
4999a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
5000a2f2a0dcSBob King     }
5001a2f2a0dcSBob King     catch (const std::invalid_argument& e)
5002a2f2a0dcSBob King     {
5003a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
5004a2f2a0dcSBob King                                "either rule_id or actions");
5005a2f2a0dcSBob King     }
5006a2f2a0dcSBob King 
5007a2f2a0dcSBob King     // Test where fails: Required actions or rule_id property both specified
5008a2f2a0dcSBob King     try
5009a2f2a0dcSBob King     {
5010a2f2a0dcSBob King         const json element = R"(
5011a2f2a0dcSBob King             {
5012a2f2a0dcSBob King               "rule_id": "set_voltage_rule",
5013a2f2a0dcSBob King               "actions": [
5014a2f2a0dcSBob King                 { "run_rule": "read_sensors_rule" }
5015a2f2a0dcSBob King               ]
5016a2f2a0dcSBob King             }
5017a2f2a0dcSBob King         )"_json;
5018a2f2a0dcSBob King         parseSensorMonitoring(element);
5019a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
5020a2f2a0dcSBob King     }
5021a2f2a0dcSBob King     catch (const std::invalid_argument& e)
5022a2f2a0dcSBob King     {
5023a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Invalid property combination: Must contain "
5024a2f2a0dcSBob King                                "either rule_id or actions");
5025a2f2a0dcSBob King     }
5026a2f2a0dcSBob King 
5027a2f2a0dcSBob King     // Test where fails: Element is not an object
5028a2f2a0dcSBob King     try
5029a2f2a0dcSBob King     {
5030a2f2a0dcSBob King         const json element = R"( [ "foo", "bar" ] )"_json;
5031a2f2a0dcSBob King         parseSensorMonitoring(element);
5032a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
5033a2f2a0dcSBob King     }
5034a2f2a0dcSBob King     catch (const std::invalid_argument& e)
5035a2f2a0dcSBob King     {
5036a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element is not an object");
5037a2f2a0dcSBob King     }
5038a2f2a0dcSBob King 
5039a2f2a0dcSBob King     // Test where fails: Invalid property specified
5040a2f2a0dcSBob King     try
5041a2f2a0dcSBob King     {
5042a2f2a0dcSBob King         const json element = R"(
5043a2f2a0dcSBob King             {
5044a2f2a0dcSBob King               "foo": "bar",
5045a2f2a0dcSBob King               "actions": [
5046a2f2a0dcSBob King                 { "run_rule": "read_sensors_rule" }
5047a2f2a0dcSBob King               ]
5048a2f2a0dcSBob King             }
5049a2f2a0dcSBob King         )"_json;
5050a2f2a0dcSBob King         parseSensorMonitoring(element);
5051a2f2a0dcSBob King         ADD_FAILURE() << "Should not have reached this line.";
5052a2f2a0dcSBob King     }
5053a2f2a0dcSBob King     catch (const std::invalid_argument& e)
5054a2f2a0dcSBob King     {
5055a2f2a0dcSBob King         EXPECT_STREQ(e.what(), "Element contains an invalid property");
5056a2f2a0dcSBob King     }
5057a2f2a0dcSBob King }
5058a2f2a0dcSBob King 
TEST(ConfigFileParserTests,ParseSensorType)50592f9e14f6SShawn McCarney TEST(ConfigFileParserTests, ParseSensorType)
506084614882SBob King {
506184614882SBob King     // Test where works: iout
506284614882SBob King     {
506384614882SBob King         const json element = "iout";
50642f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
50652f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::iout);
506684614882SBob King     }
506784614882SBob King 
506884614882SBob King     // Test where works: iout_peak
506984614882SBob King     {
507084614882SBob King         const json element = "iout_peak";
50712f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
50722f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::iout_peak);
507384614882SBob King     }
507484614882SBob King 
507584614882SBob King     // Test where works: iout_valley
507684614882SBob King     {
507784614882SBob King         const json element = "iout_valley";
50782f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
50792f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::iout_valley);
508084614882SBob King     }
508184614882SBob King 
508284614882SBob King     // Test where works: pout
508384614882SBob King     {
508484614882SBob King         const json element = "pout";
50852f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
50862f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::pout);
508784614882SBob King     }
508884614882SBob King 
508984614882SBob King     // Test where works: temperature
509084614882SBob King     {
509184614882SBob King         const json element = "temperature";
50922f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
50932f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::temperature);
509484614882SBob King     }
509584614882SBob King 
509684614882SBob King     // Test where works: temperature_peak
509784614882SBob King     {
509884614882SBob King         const json element = "temperature_peak";
50992f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
51002f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::temperature_peak);
510184614882SBob King     }
510284614882SBob King 
510384614882SBob King     // Test where works: vout
510484614882SBob King     {
510584614882SBob King         const json element = "vout";
51062f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
51072f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::vout);
510884614882SBob King     }
510984614882SBob King 
511084614882SBob King     // Test where works: vout_peak
511184614882SBob King     {
511284614882SBob King         const json element = "vout_peak";
51132f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
51142f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::vout_peak);
511584614882SBob King     }
511684614882SBob King 
511784614882SBob King     // Test where works: vout_valley
511884614882SBob King     {
511984614882SBob King         const json element = "vout_valley";
51202f9e14f6SShawn McCarney         SensorType type = parseSensorType(element);
51212f9e14f6SShawn McCarney         EXPECT_EQ(type, SensorType::vout_valley);
512284614882SBob King     }
512384614882SBob King 
51242f9e14f6SShawn McCarney     // Test where fails: Element is not a sensor type
512584614882SBob King     try
512684614882SBob King     {
512784614882SBob King         const json element = "foo";
51282f9e14f6SShawn McCarney         parseSensorType(element);
512984614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
513084614882SBob King     }
513184614882SBob King     catch (const std::invalid_argument& e)
513284614882SBob King     {
51332f9e14f6SShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a sensor type");
513484614882SBob King     }
513584614882SBob King 
513684614882SBob King     // Test where fails: Element is not a string
513784614882SBob King     try
513884614882SBob King     {
513984614882SBob King         const json element = R"( { "foo": "bar" } )"_json;
51402f9e14f6SShawn McCarney         parseSensorType(element);
514184614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
514284614882SBob King     }
514384614882SBob King     catch (const std::invalid_argument& e)
514484614882SBob King     {
514584614882SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
514684614882SBob King     }
514784614882SBob King }
514884614882SBob King 
TEST(ConfigFileParserTests,ParseSetDevice)514918a68505SBob King TEST(ConfigFileParserTests, ParseSetDevice)
515018a68505SBob King {
515118a68505SBob King     // Test where works
515218a68505SBob King     {
515318a68505SBob King         const json element = "regulator1";
515418a68505SBob King         std::unique_ptr<SetDeviceAction> action = parseSetDevice(element);
515518a68505SBob King         EXPECT_EQ(action->getDeviceID(), "regulator1");
515618a68505SBob King     }
515718a68505SBob King 
515818a68505SBob King     // Test where fails: Element is not a string
515918a68505SBob King     try
516018a68505SBob King     {
516118a68505SBob King         const json element = 1;
516218a68505SBob King         parseSetDevice(element);
516318a68505SBob King         ADD_FAILURE() << "Should not have reached this line.";
516418a68505SBob King     }
516518a68505SBob King     catch (const std::invalid_argument& e)
516618a68505SBob King     {
516718a68505SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
516818a68505SBob King     }
516918a68505SBob King 
517018a68505SBob King     // Test where fails: Empty string
517118a68505SBob King     try
517218a68505SBob King     {
517318a68505SBob King         const json element = "";
517418a68505SBob King         parseSetDevice(element);
517518a68505SBob King         ADD_FAILURE() << "Should not have reached this line.";
517618a68505SBob King     }
517718a68505SBob King     catch (const std::invalid_argument& e)
517818a68505SBob King     {
517918a68505SBob King         EXPECT_STREQ(e.what(), "Element contains an empty string");
518018a68505SBob King     }
518118a68505SBob King }
518218a68505SBob King 
TEST(ConfigFileParserTests,ParseString)51830e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseString)
51840e8c68abSShawn McCarney {
51850e8c68abSShawn McCarney     // Test where works: Empty string
51860e8c68abSShawn McCarney     {
51870e8c68abSShawn McCarney         const json element = "";
51880e8c68abSShawn McCarney         std::string value = parseString(element, true);
51890e8c68abSShawn McCarney         EXPECT_EQ(value, "");
51900e8c68abSShawn McCarney     }
51910e8c68abSShawn McCarney 
51920e8c68abSShawn McCarney     // Test where works: Non-empty string
51930e8c68abSShawn McCarney     {
51940e8c68abSShawn McCarney         const json element = "vdd_regulator";
51950e8c68abSShawn McCarney         std::string value = parseString(element, false);
51960e8c68abSShawn McCarney         EXPECT_EQ(value, "vdd_regulator");
51970e8c68abSShawn McCarney     }
51980e8c68abSShawn McCarney 
51990e8c68abSShawn McCarney     // Test where fails: Element is not a string
52000e8c68abSShawn McCarney     try
52010e8c68abSShawn McCarney     {
52020e8c68abSShawn McCarney         const json element = R"( { "foo": "bar" } )"_json;
52030e8c68abSShawn McCarney         parseString(element);
52040e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
52050e8c68abSShawn McCarney     }
52060e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
52070e8c68abSShawn McCarney     {
52080e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not a string");
52090e8c68abSShawn McCarney     }
52100e8c68abSShawn McCarney 
52110e8c68abSShawn McCarney     // Test where fails: Empty string
52120e8c68abSShawn McCarney     try
52130e8c68abSShawn McCarney     {
52140e8c68abSShawn McCarney         const json element = "";
52150e8c68abSShawn McCarney         parseString(element);
52160e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
52170e8c68abSShawn McCarney     }
52180e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
52190e8c68abSShawn McCarney     {
52200e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an empty string");
52210e8c68abSShawn McCarney     }
52220e8c68abSShawn McCarney }
52230e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,ParseUint8)5224f617f893SBob King TEST(ConfigFileParserTests, ParseUint8)
5225f617f893SBob King {
5226f617f893SBob King     // Test where works: 0
5227f617f893SBob King     {
5228f617f893SBob King         const json element = R"( 0 )"_json;
5229f617f893SBob King         uint8_t value = parseUint8(element);
5230f617f893SBob King         EXPECT_EQ(value, 0);
5231f617f893SBob King     }
5232f617f893SBob King 
5233f617f893SBob King     // Test where works: UINT8_MAX
5234f617f893SBob King     {
5235f617f893SBob King         const json element = R"( 255 )"_json;
5236f617f893SBob King         uint8_t value = parseUint8(element);
5237f617f893SBob King         EXPECT_EQ(value, 255);
5238f617f893SBob King     }
5239f617f893SBob King 
5240f617f893SBob King     // Test where fails: Element is not an integer
5241f617f893SBob King     try
5242f617f893SBob King     {
5243f617f893SBob King         const json element = R"( 1.03 )"_json;
5244f617f893SBob King         parseUint8(element);
5245f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
5246f617f893SBob King     }
5247f617f893SBob King     catch (const std::invalid_argument& e)
5248f617f893SBob King     {
5249f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not an integer");
5250f617f893SBob King     }
5251f617f893SBob King 
5252f617f893SBob King     // Test where fails: Value < 0
5253f617f893SBob King     try
5254f617f893SBob King     {
5255f617f893SBob King         const json element = R"( -1 )"_json;
5256f617f893SBob King         parseUint8(element);
5257f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
5258f617f893SBob King     }
5259f617f893SBob King     catch (const std::invalid_argument& e)
5260f617f893SBob King     {
5261f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
5262f617f893SBob King     }
5263f617f893SBob King 
5264f617f893SBob King     // Test where fails: Value > UINT8_MAX
5265f617f893SBob King     try
5266f617f893SBob King     {
5267f617f893SBob King         const json element = R"( 256 )"_json;
5268f617f893SBob King         parseUint8(element);
5269f617f893SBob King         ADD_FAILURE() << "Should not have reached this line.";
5270f617f893SBob King     }
5271f617f893SBob King     catch (const std::invalid_argument& e)
5272f617f893SBob King     {
5273f617f893SBob King         EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
5274f617f893SBob King     }
5275f617f893SBob King }
5276f617f893SBob King 
TEST(ConfigFileParserTests,ParseUnsignedInteger)52770e70113dSBob King TEST(ConfigFileParserTests, ParseUnsignedInteger)
52780e70113dSBob King {
52790e70113dSBob King     // Test where works: 1
52800e70113dSBob King     {
52810e70113dSBob King         const json element = R"( 1 )"_json;
52820e70113dSBob King         unsigned int value = parseUnsignedInteger(element);
52830e70113dSBob King         EXPECT_EQ(value, 1);
52840e70113dSBob King     }
52850e70113dSBob King 
52860e70113dSBob King     // Test where fails: Element is not an integer
52870e70113dSBob King     try
52880e70113dSBob King     {
52890e70113dSBob King         const json element = R"( 1.5 )"_json;
52900e70113dSBob King         parseUnsignedInteger(element);
52910e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
52920e70113dSBob King     }
52930e70113dSBob King     catch (const std::invalid_argument& e)
52940e70113dSBob King     {
52950e70113dSBob King         EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
52960e70113dSBob King     }
52970e70113dSBob King 
52980e70113dSBob King     // Test where fails: Value < 0
52990e70113dSBob King     try
53000e70113dSBob King     {
53010e70113dSBob King         const json element = R"( -1 )"_json;
53020e70113dSBob King         parseUnsignedInteger(element);
53030e70113dSBob King         ADD_FAILURE() << "Should not have reached this line.";
53040e70113dSBob King     }
53050e70113dSBob King     catch (const std::invalid_argument& e)
53060e70113dSBob King     {
53070e70113dSBob King         EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
53080e70113dSBob King     }
53090e70113dSBob King }
53100e70113dSBob King 
TEST(ConfigFileParserTests,ParseVoutDataFormat)531184614882SBob King TEST(ConfigFileParserTests, ParseVoutDataFormat)
531284614882SBob King {
531384614882SBob King     // Test where works: linear
531484614882SBob King     {
531584614882SBob King         const json element = "linear";
531684614882SBob King         pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
531784614882SBob King         pmbus_utils::VoutDataFormat format =
531884614882SBob King             pmbus_utils::VoutDataFormat::linear;
531984614882SBob King         EXPECT_EQ(value, format);
532084614882SBob King     }
532184614882SBob King 
532284614882SBob King     // Test where works: vid
532384614882SBob King     {
532484614882SBob King         const json element = "vid";
532584614882SBob King         pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
532684614882SBob King         pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::vid;
532784614882SBob King         EXPECT_EQ(value, format);
532884614882SBob King     }
532984614882SBob King 
533084614882SBob King     // Test where works: direct
533184614882SBob King     {
533284614882SBob King         const json element = "direct";
533384614882SBob King         pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
533484614882SBob King         pmbus_utils::VoutDataFormat format =
533584614882SBob King             pmbus_utils::VoutDataFormat::direct;
533684614882SBob King         EXPECT_EQ(value, format);
533784614882SBob King     }
533884614882SBob King 
533984614882SBob King     // Test where works: ieee
534084614882SBob King     {
534184614882SBob King         const json element = "ieee";
534284614882SBob King         pmbus_utils::VoutDataFormat value = parseVoutDataFormat(element);
534384614882SBob King         pmbus_utils::VoutDataFormat format = pmbus_utils::VoutDataFormat::ieee;
534484614882SBob King         EXPECT_EQ(value, format);
534584614882SBob King     }
534684614882SBob King 
534784614882SBob King     // Test where fails: Element is not a vout data format
534884614882SBob King     try
534984614882SBob King     {
535084614882SBob King         const json element = "foo";
535184614882SBob King         parseVoutDataFormat(element);
535284614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
535384614882SBob King     }
535484614882SBob King     catch (const std::invalid_argument& e)
535584614882SBob King     {
535684614882SBob King         EXPECT_STREQ(e.what(), "Element is not a vout data format");
535784614882SBob King     }
535884614882SBob King 
535984614882SBob King     // Test where fails: Element is not a string
536084614882SBob King     try
536184614882SBob King     {
536284614882SBob King         const json element = R"( { "foo": "bar" } )"_json;
536384614882SBob King         parseVoutDataFormat(element);
536484614882SBob King         ADD_FAILURE() << "Should not have reached this line.";
536584614882SBob King     }
536684614882SBob King     catch (const std::invalid_argument& e)
536784614882SBob King     {
536884614882SBob King         EXPECT_STREQ(e.what(), "Element is not a string");
536984614882SBob King     }
537084614882SBob King }
537184614882SBob King 
TEST(ConfigFileParserTests,VerifyIsArray)53720e8c68abSShawn McCarney TEST(ConfigFileParserTests, VerifyIsArray)
53730e8c68abSShawn McCarney {
53740e8c68abSShawn McCarney     // Test where element is an array
53750e8c68abSShawn McCarney     try
53760e8c68abSShawn McCarney     {
53770e8c68abSShawn McCarney         const json element = R"( [ "foo", "bar" ] )"_json;
53780e8c68abSShawn McCarney         verifyIsArray(element);
53790e8c68abSShawn McCarney     }
53800e8c68abSShawn McCarney     catch (const std::exception& e)
53810e8c68abSShawn McCarney     {
53820e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
53830e8c68abSShawn McCarney     }
53840e8c68abSShawn McCarney 
53850e8c68abSShawn McCarney     // Test where element is not an array
53860e8c68abSShawn McCarney     try
53870e8c68abSShawn McCarney     {
53880e8c68abSShawn McCarney         const json element = R"( { "foo": "bar" } )"_json;
53890e8c68abSShawn McCarney         verifyIsArray(element);
53900e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
53910e8c68abSShawn McCarney     }
53920e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
53930e8c68abSShawn McCarney     {
53940e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an array");
53950e8c68abSShawn McCarney     }
53960e8c68abSShawn McCarney }
53970e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,VerifyIsObject)53980e8c68abSShawn McCarney TEST(ConfigFileParserTests, VerifyIsObject)
53990e8c68abSShawn McCarney {
54000e8c68abSShawn McCarney     // Test where element is an object
54010e8c68abSShawn McCarney     try
54020e8c68abSShawn McCarney     {
54030e8c68abSShawn McCarney         const json element = R"( { "foo": "bar" } )"_json;
54040e8c68abSShawn McCarney         verifyIsObject(element);
54050e8c68abSShawn McCarney     }
54060e8c68abSShawn McCarney     catch (const std::exception& e)
54070e8c68abSShawn McCarney     {
54080e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
54090e8c68abSShawn McCarney     }
54100e8c68abSShawn McCarney 
54110e8c68abSShawn McCarney     // Test where element is not an object
54120e8c68abSShawn McCarney     try
54130e8c68abSShawn McCarney     {
54140e8c68abSShawn McCarney         const json element = R"( [ "foo", "bar" ] )"_json;
54150e8c68abSShawn McCarney         verifyIsObject(element);
54160e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
54170e8c68abSShawn McCarney     }
54180e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
54190e8c68abSShawn McCarney     {
54200e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element is not an object");
54210e8c68abSShawn McCarney     }
54220e8c68abSShawn McCarney }
54230e8c68abSShawn McCarney 
TEST(ConfigFileParserTests,VerifyPropertyCount)54240e8c68abSShawn McCarney TEST(ConfigFileParserTests, VerifyPropertyCount)
54250e8c68abSShawn McCarney {
54260e8c68abSShawn McCarney     // Test where element has expected number of properties
54270e8c68abSShawn McCarney     try
54280e8c68abSShawn McCarney     {
54290e8c68abSShawn McCarney         const json element = R"(
54300e8c68abSShawn McCarney             {
54310e8c68abSShawn McCarney               "comments": [ "Set voltage rule" ],
54320e8c68abSShawn McCarney               "id": "set_voltage_rule"
54330e8c68abSShawn McCarney             }
54340e8c68abSShawn McCarney         )"_json;
54350e8c68abSShawn McCarney         verifyPropertyCount(element, 2);
54360e8c68abSShawn McCarney     }
54370e8c68abSShawn McCarney     catch (const std::exception& e)
54380e8c68abSShawn McCarney     {
54390e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
54400e8c68abSShawn McCarney     }
54410e8c68abSShawn McCarney 
54420e8c68abSShawn McCarney     // Test where element has unexpected number of properties
54430e8c68abSShawn McCarney     try
54440e8c68abSShawn McCarney     {
54450e8c68abSShawn McCarney         const json element = R"(
54460e8c68abSShawn McCarney             {
54470e8c68abSShawn McCarney               "comments": [ "Set voltage rule" ],
54480e8c68abSShawn McCarney               "id": "set_voltage_rule",
54490e8c68abSShawn McCarney               "foo": 1.3
54500e8c68abSShawn McCarney             }
54510e8c68abSShawn McCarney         )"_json;
54520e8c68abSShawn McCarney         verifyPropertyCount(element, 2);
54530e8c68abSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
54540e8c68abSShawn McCarney     }
54550e8c68abSShawn McCarney     catch (const std::invalid_argument& e)
54560e8c68abSShawn McCarney     {
54570e8c68abSShawn McCarney         EXPECT_STREQ(e.what(), "Element contains an invalid property");
54580e8c68abSShawn McCarney     }
54590e8c68abSShawn McCarney }
5460