1*0e8c68abSShawn McCarney /** 2*0e8c68abSShawn McCarney * Copyright © 2020 IBM Corporation 3*0e8c68abSShawn McCarney * 4*0e8c68abSShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License"); 5*0e8c68abSShawn McCarney * you may not use this file except in compliance with the License. 6*0e8c68abSShawn McCarney * You may obtain a copy of the License at 7*0e8c68abSShawn McCarney * 8*0e8c68abSShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0 9*0e8c68abSShawn McCarney * 10*0e8c68abSShawn McCarney * Unless required by applicable law or agreed to in writing, software 11*0e8c68abSShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS, 12*0e8c68abSShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*0e8c68abSShawn McCarney * See the License for the specific language governing permissions and 14*0e8c68abSShawn McCarney * limitations under the License. 15*0e8c68abSShawn McCarney */ 16*0e8c68abSShawn McCarney #include "action.hpp" 17*0e8c68abSShawn McCarney #include "chassis.hpp" 18*0e8c68abSShawn McCarney #include "config_file_parser.hpp" 19*0e8c68abSShawn McCarney #include "config_file_parser_error.hpp" 20*0e8c68abSShawn McCarney #include "pmbus_utils.hpp" 21*0e8c68abSShawn McCarney #include "pmbus_write_vout_command_action.hpp" 22*0e8c68abSShawn McCarney #include "rule.hpp" 23*0e8c68abSShawn McCarney 24*0e8c68abSShawn McCarney #include <stdlib.h> 25*0e8c68abSShawn McCarney #include <sys/stat.h> 26*0e8c68abSShawn McCarney #include <unistd.h> 27*0e8c68abSShawn McCarney 28*0e8c68abSShawn McCarney #include <nlohmann/json.hpp> 29*0e8c68abSShawn McCarney 30*0e8c68abSShawn McCarney #include <cstdint> 31*0e8c68abSShawn McCarney #include <cstring> 32*0e8c68abSShawn McCarney #include <exception> 33*0e8c68abSShawn McCarney #include <filesystem> 34*0e8c68abSShawn McCarney #include <fstream> 35*0e8c68abSShawn McCarney #include <memory> 36*0e8c68abSShawn McCarney #include <optional> 37*0e8c68abSShawn McCarney #include <stdexcept> 38*0e8c68abSShawn McCarney #include <string> 39*0e8c68abSShawn McCarney #include <tuple> 40*0e8c68abSShawn McCarney #include <vector> 41*0e8c68abSShawn McCarney 42*0e8c68abSShawn McCarney #include <gtest/gtest.h> 43*0e8c68abSShawn McCarney 44*0e8c68abSShawn McCarney using namespace phosphor::power::regulators; 45*0e8c68abSShawn McCarney using namespace phosphor::power::regulators::config_file_parser; 46*0e8c68abSShawn McCarney using namespace phosphor::power::regulators::config_file_parser::internal; 47*0e8c68abSShawn McCarney using json = nlohmann::json; 48*0e8c68abSShawn McCarney 49*0e8c68abSShawn McCarney /** 50*0e8c68abSShawn McCarney * @class TmpFile 51*0e8c68abSShawn McCarney * 52*0e8c68abSShawn McCarney * Temporary file. 53*0e8c68abSShawn McCarney * 54*0e8c68abSShawn McCarney * File is deleted automatically by the destructor when the object goes out of 55*0e8c68abSShawn McCarney * scope. 56*0e8c68abSShawn McCarney */ 57*0e8c68abSShawn McCarney class TmpFile 58*0e8c68abSShawn McCarney { 59*0e8c68abSShawn McCarney public: 60*0e8c68abSShawn McCarney TmpFile() 61*0e8c68abSShawn McCarney { 62*0e8c68abSShawn McCarney int fd = mkstemp(fileName); 63*0e8c68abSShawn McCarney if (fd == -1) 64*0e8c68abSShawn McCarney { 65*0e8c68abSShawn McCarney throw std::runtime_error{"Unable to create temporary file"}; 66*0e8c68abSShawn McCarney } 67*0e8c68abSShawn McCarney close(fd); 68*0e8c68abSShawn McCarney } 69*0e8c68abSShawn McCarney 70*0e8c68abSShawn McCarney std::string getName() 71*0e8c68abSShawn McCarney { 72*0e8c68abSShawn McCarney return fileName; 73*0e8c68abSShawn McCarney } 74*0e8c68abSShawn McCarney 75*0e8c68abSShawn McCarney ~TmpFile() 76*0e8c68abSShawn McCarney { 77*0e8c68abSShawn McCarney unlink(fileName); 78*0e8c68abSShawn McCarney } 79*0e8c68abSShawn McCarney 80*0e8c68abSShawn McCarney private: 81*0e8c68abSShawn McCarney char fileName[17] = "/tmp/temp-XXXXXX"; 82*0e8c68abSShawn McCarney }; 83*0e8c68abSShawn McCarney 84*0e8c68abSShawn McCarney void writeConfigFile(const std::filesystem::path& pathName, 85*0e8c68abSShawn McCarney const std::string& contents) 86*0e8c68abSShawn McCarney { 87*0e8c68abSShawn McCarney std::ofstream file{pathName}; 88*0e8c68abSShawn McCarney file << contents; 89*0e8c68abSShawn McCarney } 90*0e8c68abSShawn McCarney 91*0e8c68abSShawn McCarney void writeConfigFile(const std::filesystem::path& pathName, 92*0e8c68abSShawn McCarney const json& contents) 93*0e8c68abSShawn McCarney { 94*0e8c68abSShawn McCarney std::ofstream file{pathName}; 95*0e8c68abSShawn McCarney file << contents; 96*0e8c68abSShawn McCarney } 97*0e8c68abSShawn McCarney 98*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, Parse) 99*0e8c68abSShawn McCarney { 100*0e8c68abSShawn McCarney // Test where works 101*0e8c68abSShawn McCarney { 102*0e8c68abSShawn McCarney const json configFileContents = R"( 103*0e8c68abSShawn McCarney { 104*0e8c68abSShawn McCarney "rules": [ 105*0e8c68abSShawn McCarney { 106*0e8c68abSShawn McCarney "id": "set_voltage_rule1", 107*0e8c68abSShawn McCarney "actions": [ 108*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 109*0e8c68abSShawn McCarney ] 110*0e8c68abSShawn McCarney }, 111*0e8c68abSShawn McCarney { 112*0e8c68abSShawn McCarney "id": "set_voltage_rule2", 113*0e8c68abSShawn McCarney "actions": [ 114*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.33, "format": "linear" } } 115*0e8c68abSShawn McCarney ] 116*0e8c68abSShawn McCarney } 117*0e8c68abSShawn McCarney ], 118*0e8c68abSShawn McCarney "chassis": [ 119*0e8c68abSShawn McCarney { "number": 1 }, 120*0e8c68abSShawn McCarney { "number": 2 }, 121*0e8c68abSShawn McCarney { "number": 3 } 122*0e8c68abSShawn McCarney ] 123*0e8c68abSShawn McCarney } 124*0e8c68abSShawn McCarney )"_json; 125*0e8c68abSShawn McCarney 126*0e8c68abSShawn McCarney TmpFile configFile; 127*0e8c68abSShawn McCarney std::filesystem::path pathName{configFile.getName()}; 128*0e8c68abSShawn McCarney writeConfigFile(pathName, configFileContents); 129*0e8c68abSShawn McCarney 130*0e8c68abSShawn McCarney std::vector<std::unique_ptr<Rule>> rules{}; 131*0e8c68abSShawn McCarney std::vector<std::unique_ptr<Chassis>> chassis{}; 132*0e8c68abSShawn McCarney std::tie(rules, chassis) = parse(pathName); 133*0e8c68abSShawn McCarney 134*0e8c68abSShawn McCarney EXPECT_EQ(rules.size(), 2); 135*0e8c68abSShawn McCarney EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 136*0e8c68abSShawn McCarney EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 137*0e8c68abSShawn McCarney 138*0e8c68abSShawn McCarney // TODO: Not implemented yet 139*0e8c68abSShawn McCarney // EXPECT_EQ(chassis.size(), 3); 140*0e8c68abSShawn McCarney // EXPECT_EQ(chassis[0]->getNumber(), 1); 141*0e8c68abSShawn McCarney // EXPECT_EQ(chassis[1]->getNumber(), 2); 142*0e8c68abSShawn McCarney // EXPECT_EQ(chassis[2]->getNumber(), 3); 143*0e8c68abSShawn McCarney } 144*0e8c68abSShawn McCarney 145*0e8c68abSShawn McCarney // Test where fails: File does not exist 146*0e8c68abSShawn McCarney try 147*0e8c68abSShawn McCarney { 148*0e8c68abSShawn McCarney std::filesystem::path pathName{"/tmp/non_existent_file"}; 149*0e8c68abSShawn McCarney parse(pathName); 150*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 151*0e8c68abSShawn McCarney } 152*0e8c68abSShawn McCarney catch (const ConfigFileParserError& e) 153*0e8c68abSShawn McCarney { 154*0e8c68abSShawn McCarney // Expected exception; what() message will vary 155*0e8c68abSShawn McCarney } 156*0e8c68abSShawn McCarney 157*0e8c68abSShawn McCarney // Test where fails: File is not readable 158*0e8c68abSShawn McCarney try 159*0e8c68abSShawn McCarney { 160*0e8c68abSShawn McCarney const json configFileContents = R"( 161*0e8c68abSShawn McCarney { 162*0e8c68abSShawn McCarney "chassis": [ { "number": 1 } ] 163*0e8c68abSShawn McCarney } 164*0e8c68abSShawn McCarney )"_json; 165*0e8c68abSShawn McCarney 166*0e8c68abSShawn McCarney TmpFile configFile; 167*0e8c68abSShawn McCarney std::filesystem::path pathName{configFile.getName()}; 168*0e8c68abSShawn McCarney writeConfigFile(pathName, configFileContents); 169*0e8c68abSShawn McCarney 170*0e8c68abSShawn McCarney chmod(pathName.c_str(), 0222); 171*0e8c68abSShawn McCarney 172*0e8c68abSShawn McCarney parse(pathName); 173*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 174*0e8c68abSShawn McCarney } 175*0e8c68abSShawn McCarney catch (const ConfigFileParserError& e) 176*0e8c68abSShawn McCarney { 177*0e8c68abSShawn McCarney // Expected exception; what() message will vary 178*0e8c68abSShawn McCarney } 179*0e8c68abSShawn McCarney 180*0e8c68abSShawn McCarney // Test where fails: File is not valid JSON 181*0e8c68abSShawn McCarney try 182*0e8c68abSShawn McCarney { 183*0e8c68abSShawn McCarney const std::string configFileContents = "] foo ["; 184*0e8c68abSShawn McCarney 185*0e8c68abSShawn McCarney TmpFile configFile; 186*0e8c68abSShawn McCarney std::filesystem::path pathName{configFile.getName()}; 187*0e8c68abSShawn McCarney writeConfigFile(pathName, configFileContents); 188*0e8c68abSShawn McCarney 189*0e8c68abSShawn McCarney parse(pathName); 190*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 191*0e8c68abSShawn McCarney } 192*0e8c68abSShawn McCarney catch (const ConfigFileParserError& e) 193*0e8c68abSShawn McCarney { 194*0e8c68abSShawn McCarney // Expected exception; what() message will vary 195*0e8c68abSShawn McCarney } 196*0e8c68abSShawn McCarney 197*0e8c68abSShawn McCarney // Test where fails: Error when parsing JSON elements 198*0e8c68abSShawn McCarney try 199*0e8c68abSShawn McCarney { 200*0e8c68abSShawn McCarney const json configFileContents = R"( { "foo": "bar" } )"_json; 201*0e8c68abSShawn McCarney 202*0e8c68abSShawn McCarney TmpFile configFile; 203*0e8c68abSShawn McCarney std::filesystem::path pathName{configFile.getName()}; 204*0e8c68abSShawn McCarney writeConfigFile(pathName, configFileContents); 205*0e8c68abSShawn McCarney 206*0e8c68abSShawn McCarney parse(pathName); 207*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 208*0e8c68abSShawn McCarney } 209*0e8c68abSShawn McCarney catch (const ConfigFileParserError& e) 210*0e8c68abSShawn McCarney { 211*0e8c68abSShawn McCarney // Expected exception; what() message will vary 212*0e8c68abSShawn McCarney } 213*0e8c68abSShawn McCarney } 214*0e8c68abSShawn McCarney 215*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, GetRequiredProperty) 216*0e8c68abSShawn McCarney { 217*0e8c68abSShawn McCarney // Test where property exists 218*0e8c68abSShawn McCarney { 219*0e8c68abSShawn McCarney const json element = R"( { "format": "linear" } )"_json; 220*0e8c68abSShawn McCarney const json& propertyElement = getRequiredProperty(element, "format"); 221*0e8c68abSShawn McCarney EXPECT_EQ(propertyElement.get<std::string>(), "linear"); 222*0e8c68abSShawn McCarney } 223*0e8c68abSShawn McCarney 224*0e8c68abSShawn McCarney // Test where property does not exist 225*0e8c68abSShawn McCarney try 226*0e8c68abSShawn McCarney { 227*0e8c68abSShawn McCarney const json element = R"( { "volts": 1.03 } )"_json; 228*0e8c68abSShawn McCarney getRequiredProperty(element, "format"); 229*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 230*0e8c68abSShawn McCarney } 231*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 232*0e8c68abSShawn McCarney { 233*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: format"); 234*0e8c68abSShawn McCarney } 235*0e8c68abSShawn McCarney } 236*0e8c68abSShawn McCarney 237*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseAction) 238*0e8c68abSShawn McCarney { 239*0e8c68abSShawn McCarney // Test where works: comments property specified 240*0e8c68abSShawn McCarney { 241*0e8c68abSShawn McCarney const json element = R"( 242*0e8c68abSShawn McCarney { 243*0e8c68abSShawn McCarney "comments": [ "Set output voltage." ], 244*0e8c68abSShawn McCarney "pmbus_write_vout_command": { 245*0e8c68abSShawn McCarney "format": "linear" 246*0e8c68abSShawn McCarney } 247*0e8c68abSShawn McCarney } 248*0e8c68abSShawn McCarney )"_json; 249*0e8c68abSShawn McCarney std::unique_ptr<Action> action = parseAction(element); 250*0e8c68abSShawn McCarney EXPECT_NE(action.get(), nullptr); 251*0e8c68abSShawn McCarney } 252*0e8c68abSShawn McCarney 253*0e8c68abSShawn McCarney // Test where works: comments property not specified 254*0e8c68abSShawn McCarney { 255*0e8c68abSShawn McCarney const json element = R"( 256*0e8c68abSShawn McCarney { 257*0e8c68abSShawn McCarney "pmbus_write_vout_command": { 258*0e8c68abSShawn McCarney "format": "linear" 259*0e8c68abSShawn McCarney } 260*0e8c68abSShawn McCarney } 261*0e8c68abSShawn McCarney )"_json; 262*0e8c68abSShawn McCarney std::unique_ptr<Action> action = parseAction(element); 263*0e8c68abSShawn McCarney EXPECT_NE(action.get(), nullptr); 264*0e8c68abSShawn McCarney } 265*0e8c68abSShawn McCarney 266*0e8c68abSShawn McCarney // Test where works: and action type specified 267*0e8c68abSShawn McCarney // TODO: Not implemented yet 268*0e8c68abSShawn McCarney 269*0e8c68abSShawn McCarney // Test where works: compare_presence action type specified 270*0e8c68abSShawn McCarney // TODO: Not implemented yet 271*0e8c68abSShawn McCarney 272*0e8c68abSShawn McCarney // Test where works: compare_vpd action type specified 273*0e8c68abSShawn McCarney // TODO: Not implemented yet 274*0e8c68abSShawn McCarney 275*0e8c68abSShawn McCarney // Test where works: i2c_compare_bit action type specified 276*0e8c68abSShawn McCarney // TODO: Not implemented yet 277*0e8c68abSShawn McCarney 278*0e8c68abSShawn McCarney // Test where works: i2c_compare_byte action type specified 279*0e8c68abSShawn McCarney // TODO: Not implemented yet 280*0e8c68abSShawn McCarney 281*0e8c68abSShawn McCarney // Test where works: i2c_compare_bytes action type specified 282*0e8c68abSShawn McCarney // TODO: Not implemented yet 283*0e8c68abSShawn McCarney 284*0e8c68abSShawn McCarney // Test where works: i2c_write_bit action type specified 285*0e8c68abSShawn McCarney // TODO: Not implemented yet 286*0e8c68abSShawn McCarney 287*0e8c68abSShawn McCarney // Test where works: i2c_write_byte action type specified 288*0e8c68abSShawn McCarney // TODO: Not implemented yet 289*0e8c68abSShawn McCarney 290*0e8c68abSShawn McCarney // Test where works: i2c_write_bytes action type specified 291*0e8c68abSShawn McCarney // TODO: Not implemented yet 292*0e8c68abSShawn McCarney 293*0e8c68abSShawn McCarney // Test where works: if action type specified 294*0e8c68abSShawn McCarney // TODO: Not implemented yet 295*0e8c68abSShawn McCarney 296*0e8c68abSShawn McCarney // Test where works: not action type specified 297*0e8c68abSShawn McCarney // TODO: Not implemented yet 298*0e8c68abSShawn McCarney 299*0e8c68abSShawn McCarney // Test where works: or action type specified 300*0e8c68abSShawn McCarney // TODO: Not implemented yet 301*0e8c68abSShawn McCarney 302*0e8c68abSShawn McCarney // Test where works: pmbus_read_sensor action type specified 303*0e8c68abSShawn McCarney // TODO: Not implemented yet 304*0e8c68abSShawn McCarney 305*0e8c68abSShawn McCarney // Test where works: pmbus_write_vout_command action type specified 306*0e8c68abSShawn McCarney { 307*0e8c68abSShawn McCarney const json element = R"( 308*0e8c68abSShawn McCarney { 309*0e8c68abSShawn McCarney "pmbus_write_vout_command": { 310*0e8c68abSShawn McCarney "format": "linear" 311*0e8c68abSShawn McCarney } 312*0e8c68abSShawn McCarney } 313*0e8c68abSShawn McCarney )"_json; 314*0e8c68abSShawn McCarney std::unique_ptr<Action> action = parseAction(element); 315*0e8c68abSShawn McCarney EXPECT_NE(action.get(), nullptr); 316*0e8c68abSShawn McCarney } 317*0e8c68abSShawn McCarney 318*0e8c68abSShawn McCarney // Test where works: run_rule action type specified 319*0e8c68abSShawn McCarney // TODO: Not implemented yet 320*0e8c68abSShawn McCarney 321*0e8c68abSShawn McCarney // Test where works: set_device action type specified 322*0e8c68abSShawn McCarney // TODO: Not implemented yet 323*0e8c68abSShawn McCarney 324*0e8c68abSShawn McCarney // Test where fails: Element is not an object 325*0e8c68abSShawn McCarney try 326*0e8c68abSShawn McCarney { 327*0e8c68abSShawn McCarney const json element = R"( [ "0xFF", "0x01" ] )"_json; 328*0e8c68abSShawn McCarney parseAction(element); 329*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 330*0e8c68abSShawn McCarney } 331*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 332*0e8c68abSShawn McCarney { 333*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object"); 334*0e8c68abSShawn McCarney } 335*0e8c68abSShawn McCarney 336*0e8c68abSShawn McCarney // Test where fails: No action type specified 337*0e8c68abSShawn McCarney try 338*0e8c68abSShawn McCarney { 339*0e8c68abSShawn McCarney const json element = R"( 340*0e8c68abSShawn McCarney { 341*0e8c68abSShawn McCarney "comments": [ "Set output voltage." ] 342*0e8c68abSShawn McCarney } 343*0e8c68abSShawn McCarney )"_json; 344*0e8c68abSShawn McCarney parseAction(element); 345*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 346*0e8c68abSShawn McCarney } 347*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 348*0e8c68abSShawn McCarney { 349*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Required action type property missing"); 350*0e8c68abSShawn McCarney } 351*0e8c68abSShawn McCarney 352*0e8c68abSShawn McCarney // Test where fails: Multiple action types specified 353*0e8c68abSShawn McCarney // TODO: Implement after another action type is supported 354*0e8c68abSShawn McCarney 355*0e8c68abSShawn McCarney // Test where fails: Invalid property specified 356*0e8c68abSShawn McCarney try 357*0e8c68abSShawn McCarney { 358*0e8c68abSShawn McCarney const json element = R"( 359*0e8c68abSShawn McCarney { 360*0e8c68abSShawn McCarney "remarks": [ "Set output voltage." ], 361*0e8c68abSShawn McCarney "pmbus_write_vout_command": { 362*0e8c68abSShawn McCarney "format": "linear" 363*0e8c68abSShawn McCarney } 364*0e8c68abSShawn McCarney } 365*0e8c68abSShawn McCarney )"_json; 366*0e8c68abSShawn McCarney parseAction(element); 367*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 368*0e8c68abSShawn McCarney } 369*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 370*0e8c68abSShawn McCarney { 371*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property"); 372*0e8c68abSShawn McCarney } 373*0e8c68abSShawn McCarney } 374*0e8c68abSShawn McCarney 375*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseActionArray) 376*0e8c68abSShawn McCarney { 377*0e8c68abSShawn McCarney // Test where works 378*0e8c68abSShawn McCarney { 379*0e8c68abSShawn McCarney const json element = R"( 380*0e8c68abSShawn McCarney [ 381*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 382*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 383*0e8c68abSShawn McCarney ] 384*0e8c68abSShawn McCarney )"_json; 385*0e8c68abSShawn McCarney std::vector<std::unique_ptr<Action>> actions = 386*0e8c68abSShawn McCarney parseActionArray(element); 387*0e8c68abSShawn McCarney EXPECT_EQ(actions.size(), 2); 388*0e8c68abSShawn McCarney } 389*0e8c68abSShawn McCarney 390*0e8c68abSShawn McCarney // Test where fails: Element is not an array 391*0e8c68abSShawn McCarney try 392*0e8c68abSShawn McCarney { 393*0e8c68abSShawn McCarney const json element = R"( 394*0e8c68abSShawn McCarney { 395*0e8c68abSShawn McCarney "foo": "bar" 396*0e8c68abSShawn McCarney } 397*0e8c68abSShawn McCarney )"_json; 398*0e8c68abSShawn McCarney parseActionArray(element); 399*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 400*0e8c68abSShawn McCarney } 401*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 402*0e8c68abSShawn McCarney { 403*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an array"); 404*0e8c68abSShawn McCarney } 405*0e8c68abSShawn McCarney } 406*0e8c68abSShawn McCarney 407*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseBoolean) 408*0e8c68abSShawn McCarney { 409*0e8c68abSShawn McCarney // Test where works: true 410*0e8c68abSShawn McCarney { 411*0e8c68abSShawn McCarney const json element = R"( true )"_json; 412*0e8c68abSShawn McCarney bool value = parseBoolean(element); 413*0e8c68abSShawn McCarney EXPECT_EQ(value, true); 414*0e8c68abSShawn McCarney } 415*0e8c68abSShawn McCarney 416*0e8c68abSShawn McCarney // Test where works: false 417*0e8c68abSShawn McCarney { 418*0e8c68abSShawn McCarney const json element = R"( false )"_json; 419*0e8c68abSShawn McCarney bool value = parseBoolean(element); 420*0e8c68abSShawn McCarney EXPECT_EQ(value, false); 421*0e8c68abSShawn McCarney } 422*0e8c68abSShawn McCarney 423*0e8c68abSShawn McCarney // Test where fails: Element is not a boolean 424*0e8c68abSShawn McCarney try 425*0e8c68abSShawn McCarney { 426*0e8c68abSShawn McCarney const json element = R"( 1 )"_json; 427*0e8c68abSShawn McCarney parseBoolean(element); 428*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 429*0e8c68abSShawn McCarney } 430*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 431*0e8c68abSShawn McCarney { 432*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a boolean"); 433*0e8c68abSShawn McCarney } 434*0e8c68abSShawn McCarney } 435*0e8c68abSShawn McCarney 436*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseChassisArray) 437*0e8c68abSShawn McCarney { 438*0e8c68abSShawn McCarney // TODO: Not implemented yet 439*0e8c68abSShawn McCarney } 440*0e8c68abSShawn McCarney 441*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseDouble) 442*0e8c68abSShawn McCarney { 443*0e8c68abSShawn McCarney // Test where works: floating point value 444*0e8c68abSShawn McCarney { 445*0e8c68abSShawn McCarney const json element = R"( 1.03 )"_json; 446*0e8c68abSShawn McCarney double value = parseDouble(element); 447*0e8c68abSShawn McCarney EXPECT_EQ(value, 1.03); 448*0e8c68abSShawn McCarney } 449*0e8c68abSShawn McCarney 450*0e8c68abSShawn McCarney // Test where works: integer value 451*0e8c68abSShawn McCarney { 452*0e8c68abSShawn McCarney const json element = R"( 24 )"_json; 453*0e8c68abSShawn McCarney double value = parseDouble(element); 454*0e8c68abSShawn McCarney EXPECT_EQ(value, 24.0); 455*0e8c68abSShawn McCarney } 456*0e8c68abSShawn McCarney 457*0e8c68abSShawn McCarney // Test where fails: Element is not a number 458*0e8c68abSShawn McCarney try 459*0e8c68abSShawn McCarney { 460*0e8c68abSShawn McCarney const json element = R"( true )"_json; 461*0e8c68abSShawn McCarney parseDouble(element); 462*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 463*0e8c68abSShawn McCarney } 464*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 465*0e8c68abSShawn McCarney { 466*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a number"); 467*0e8c68abSShawn McCarney } 468*0e8c68abSShawn McCarney } 469*0e8c68abSShawn McCarney 470*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseInt8) 471*0e8c68abSShawn McCarney { 472*0e8c68abSShawn McCarney // Test where works: INT8_MIN 473*0e8c68abSShawn McCarney { 474*0e8c68abSShawn McCarney const json element = R"( -128 )"_json; 475*0e8c68abSShawn McCarney int8_t value = parseInt8(element); 476*0e8c68abSShawn McCarney EXPECT_EQ(value, -128); 477*0e8c68abSShawn McCarney } 478*0e8c68abSShawn McCarney 479*0e8c68abSShawn McCarney // Test where works: INT8_MAX 480*0e8c68abSShawn McCarney { 481*0e8c68abSShawn McCarney const json element = R"( 127 )"_json; 482*0e8c68abSShawn McCarney int8_t value = parseInt8(element); 483*0e8c68abSShawn McCarney EXPECT_EQ(value, 127); 484*0e8c68abSShawn McCarney } 485*0e8c68abSShawn McCarney 486*0e8c68abSShawn McCarney // Test where fails: Element is not an integer 487*0e8c68abSShawn McCarney try 488*0e8c68abSShawn McCarney { 489*0e8c68abSShawn McCarney const json element = R"( 1.03 )"_json; 490*0e8c68abSShawn McCarney parseInt8(element); 491*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 492*0e8c68abSShawn McCarney } 493*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 494*0e8c68abSShawn McCarney { 495*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an integer"); 496*0e8c68abSShawn McCarney } 497*0e8c68abSShawn McCarney 498*0e8c68abSShawn McCarney // Test where fails: Value < INT8_MIN 499*0e8c68abSShawn McCarney try 500*0e8c68abSShawn McCarney { 501*0e8c68abSShawn McCarney const json element = R"( -129 )"_json; 502*0e8c68abSShawn McCarney parseInt8(element); 503*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 504*0e8c68abSShawn McCarney } 505*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 506*0e8c68abSShawn McCarney { 507*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 508*0e8c68abSShawn McCarney } 509*0e8c68abSShawn McCarney 510*0e8c68abSShawn McCarney // Test where fails: Value > INT8_MAX 511*0e8c68abSShawn McCarney try 512*0e8c68abSShawn McCarney { 513*0e8c68abSShawn McCarney const json element = R"( 128 )"_json; 514*0e8c68abSShawn McCarney parseInt8(element); 515*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 516*0e8c68abSShawn McCarney } 517*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 518*0e8c68abSShawn McCarney { 519*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an 8-bit signed integer"); 520*0e8c68abSShawn McCarney } 521*0e8c68abSShawn McCarney } 522*0e8c68abSShawn McCarney 523*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParsePMBusWriteVoutCommand) 524*0e8c68abSShawn McCarney { 525*0e8c68abSShawn McCarney // Test where works: Only required properties specified 526*0e8c68abSShawn McCarney { 527*0e8c68abSShawn McCarney const json element = R"( 528*0e8c68abSShawn McCarney { 529*0e8c68abSShawn McCarney "format": "linear" 530*0e8c68abSShawn McCarney } 531*0e8c68abSShawn McCarney )"_json; 532*0e8c68abSShawn McCarney std::unique_ptr<PMBusWriteVoutCommandAction> action = 533*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 534*0e8c68abSShawn McCarney EXPECT_EQ(action->getVolts().has_value(), false); 535*0e8c68abSShawn McCarney EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 536*0e8c68abSShawn McCarney EXPECT_EQ(action->getExponent().has_value(), false); 537*0e8c68abSShawn McCarney EXPECT_EQ(action->isVerified(), false); 538*0e8c68abSShawn McCarney } 539*0e8c68abSShawn McCarney 540*0e8c68abSShawn McCarney // Test where works: All properties specified 541*0e8c68abSShawn McCarney { 542*0e8c68abSShawn McCarney const json element = R"( 543*0e8c68abSShawn McCarney { 544*0e8c68abSShawn McCarney "volts": 1.03, 545*0e8c68abSShawn McCarney "format": "linear", 546*0e8c68abSShawn McCarney "exponent": -8, 547*0e8c68abSShawn McCarney "is_verified": true 548*0e8c68abSShawn McCarney } 549*0e8c68abSShawn McCarney )"_json; 550*0e8c68abSShawn McCarney std::unique_ptr<PMBusWriteVoutCommandAction> action = 551*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 552*0e8c68abSShawn McCarney EXPECT_EQ(action->getVolts().has_value(), true); 553*0e8c68abSShawn McCarney EXPECT_EQ(action->getVolts().value(), 1.03); 554*0e8c68abSShawn McCarney EXPECT_EQ(action->getFormat(), pmbus_utils::VoutDataFormat::linear); 555*0e8c68abSShawn McCarney EXPECT_EQ(action->getExponent().has_value(), true); 556*0e8c68abSShawn McCarney EXPECT_EQ(action->getExponent().value(), -8); 557*0e8c68abSShawn McCarney EXPECT_EQ(action->isVerified(), true); 558*0e8c68abSShawn McCarney } 559*0e8c68abSShawn McCarney 560*0e8c68abSShawn McCarney // Test where fails: Element is not an object 561*0e8c68abSShawn McCarney try 562*0e8c68abSShawn McCarney { 563*0e8c68abSShawn McCarney const json element = R"( [ "0xFF", "0x01" ] )"_json; 564*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 565*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 566*0e8c68abSShawn McCarney } 567*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 568*0e8c68abSShawn McCarney { 569*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object"); 570*0e8c68abSShawn McCarney } 571*0e8c68abSShawn McCarney 572*0e8c68abSShawn McCarney // Test where fails: volts value is invalid 573*0e8c68abSShawn McCarney try 574*0e8c68abSShawn McCarney { 575*0e8c68abSShawn McCarney const json element = R"( 576*0e8c68abSShawn McCarney { 577*0e8c68abSShawn McCarney "volts": "foo", 578*0e8c68abSShawn McCarney "format": "linear" 579*0e8c68abSShawn McCarney } 580*0e8c68abSShawn McCarney )"_json; 581*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 582*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 583*0e8c68abSShawn McCarney } 584*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 585*0e8c68abSShawn McCarney { 586*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a number"); 587*0e8c68abSShawn McCarney } 588*0e8c68abSShawn McCarney 589*0e8c68abSShawn McCarney // Test where fails: Required format property not specified 590*0e8c68abSShawn McCarney try 591*0e8c68abSShawn McCarney { 592*0e8c68abSShawn McCarney const json element = R"( 593*0e8c68abSShawn McCarney { 594*0e8c68abSShawn McCarney "volts": 1.03, 595*0e8c68abSShawn McCarney "is_verified": true 596*0e8c68abSShawn McCarney } 597*0e8c68abSShawn McCarney )"_json; 598*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 599*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 600*0e8c68abSShawn McCarney } 601*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 602*0e8c68abSShawn McCarney { 603*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: format"); 604*0e8c68abSShawn McCarney } 605*0e8c68abSShawn McCarney 606*0e8c68abSShawn McCarney // Test where fails: format value is invalid 607*0e8c68abSShawn McCarney try 608*0e8c68abSShawn McCarney { 609*0e8c68abSShawn McCarney const json element = R"( 610*0e8c68abSShawn McCarney { 611*0e8c68abSShawn McCarney "format": "linear_11" 612*0e8c68abSShawn McCarney } 613*0e8c68abSShawn McCarney )"_json; 614*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 615*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 616*0e8c68abSShawn McCarney } 617*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 618*0e8c68abSShawn McCarney { 619*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Invalid format value: linear_11"); 620*0e8c68abSShawn McCarney } 621*0e8c68abSShawn McCarney 622*0e8c68abSShawn McCarney // Test where fails: exponent value is invalid 623*0e8c68abSShawn McCarney try 624*0e8c68abSShawn McCarney { 625*0e8c68abSShawn McCarney const json element = R"( 626*0e8c68abSShawn McCarney { 627*0e8c68abSShawn McCarney "format": "linear", 628*0e8c68abSShawn McCarney "exponent": 1.3 629*0e8c68abSShawn McCarney } 630*0e8c68abSShawn McCarney )"_json; 631*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 632*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 633*0e8c68abSShawn McCarney } 634*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 635*0e8c68abSShawn McCarney { 636*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an integer"); 637*0e8c68abSShawn McCarney } 638*0e8c68abSShawn McCarney 639*0e8c68abSShawn McCarney // Test where fails: is_verified value is invalid 640*0e8c68abSShawn McCarney try 641*0e8c68abSShawn McCarney { 642*0e8c68abSShawn McCarney const json element = R"( 643*0e8c68abSShawn McCarney { 644*0e8c68abSShawn McCarney "format": "linear", 645*0e8c68abSShawn McCarney "is_verified": "true" 646*0e8c68abSShawn McCarney } 647*0e8c68abSShawn McCarney )"_json; 648*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 649*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 650*0e8c68abSShawn McCarney } 651*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 652*0e8c68abSShawn McCarney { 653*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a boolean"); 654*0e8c68abSShawn McCarney } 655*0e8c68abSShawn McCarney 656*0e8c68abSShawn McCarney // Test where fails: Invalid property specified 657*0e8c68abSShawn McCarney try 658*0e8c68abSShawn McCarney { 659*0e8c68abSShawn McCarney const json element = R"( 660*0e8c68abSShawn McCarney { 661*0e8c68abSShawn McCarney "format": "linear", 662*0e8c68abSShawn McCarney "foo": "bar" 663*0e8c68abSShawn McCarney } 664*0e8c68abSShawn McCarney )"_json; 665*0e8c68abSShawn McCarney parsePMBusWriteVoutCommand(element); 666*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 667*0e8c68abSShawn McCarney } 668*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 669*0e8c68abSShawn McCarney { 670*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property"); 671*0e8c68abSShawn McCarney } 672*0e8c68abSShawn McCarney } 673*0e8c68abSShawn McCarney 674*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseRoot) 675*0e8c68abSShawn McCarney { 676*0e8c68abSShawn McCarney // Test where works: Only required properties specified 677*0e8c68abSShawn McCarney { 678*0e8c68abSShawn McCarney const json element = R"( 679*0e8c68abSShawn McCarney { 680*0e8c68abSShawn McCarney "chassis": [ 681*0e8c68abSShawn McCarney { "number": 1 } 682*0e8c68abSShawn McCarney ] 683*0e8c68abSShawn McCarney } 684*0e8c68abSShawn McCarney )"_json; 685*0e8c68abSShawn McCarney std::vector<std::unique_ptr<Rule>> rules{}; 686*0e8c68abSShawn McCarney std::vector<std::unique_ptr<Chassis>> chassis{}; 687*0e8c68abSShawn McCarney std::tie(rules, chassis) = parseRoot(element); 688*0e8c68abSShawn McCarney EXPECT_EQ(rules.size(), 0); 689*0e8c68abSShawn McCarney // TODO: Not implemented yet 690*0e8c68abSShawn McCarney // EXPECT_EQ(chassis.size(), 1); 691*0e8c68abSShawn McCarney } 692*0e8c68abSShawn McCarney 693*0e8c68abSShawn McCarney // Test where works: All properties specified 694*0e8c68abSShawn McCarney { 695*0e8c68abSShawn McCarney const json element = R"( 696*0e8c68abSShawn McCarney { 697*0e8c68abSShawn McCarney "comments": [ "Config file for a FooBar one-chassis system" ], 698*0e8c68abSShawn McCarney "rules": [ 699*0e8c68abSShawn McCarney { 700*0e8c68abSShawn McCarney "id": "set_voltage_rule", 701*0e8c68abSShawn McCarney "actions": [ 702*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "format": "linear" } } 703*0e8c68abSShawn McCarney ] 704*0e8c68abSShawn McCarney } 705*0e8c68abSShawn McCarney ], 706*0e8c68abSShawn McCarney "chassis": [ 707*0e8c68abSShawn McCarney { "number": 1 }, 708*0e8c68abSShawn McCarney { "number": 3 } 709*0e8c68abSShawn McCarney ] 710*0e8c68abSShawn McCarney } 711*0e8c68abSShawn McCarney )"_json; 712*0e8c68abSShawn McCarney std::vector<std::unique_ptr<Rule>> rules{}; 713*0e8c68abSShawn McCarney std::vector<std::unique_ptr<Chassis>> chassis{}; 714*0e8c68abSShawn McCarney std::tie(rules, chassis) = parseRoot(element); 715*0e8c68abSShawn McCarney EXPECT_EQ(rules.size(), 1); 716*0e8c68abSShawn McCarney // TODO: Not implemented yet 717*0e8c68abSShawn McCarney // EXPECT_EQ(chassis.size(), 2); 718*0e8c68abSShawn McCarney } 719*0e8c68abSShawn McCarney 720*0e8c68abSShawn McCarney // Test where fails: Element is not an object 721*0e8c68abSShawn McCarney try 722*0e8c68abSShawn McCarney { 723*0e8c68abSShawn McCarney const json element = R"( [ "0xFF", "0x01" ] )"_json; 724*0e8c68abSShawn McCarney parseRoot(element); 725*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 726*0e8c68abSShawn McCarney } 727*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 728*0e8c68abSShawn McCarney { 729*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object"); 730*0e8c68abSShawn McCarney } 731*0e8c68abSShawn McCarney 732*0e8c68abSShawn McCarney // Test where fails: chassis property not specified 733*0e8c68abSShawn McCarney try 734*0e8c68abSShawn McCarney { 735*0e8c68abSShawn McCarney const json element = R"( 736*0e8c68abSShawn McCarney { 737*0e8c68abSShawn McCarney "rules": [ 738*0e8c68abSShawn McCarney { 739*0e8c68abSShawn McCarney "id": "set_voltage_rule", 740*0e8c68abSShawn McCarney "actions": [ 741*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "format": "linear" } } 742*0e8c68abSShawn McCarney ] 743*0e8c68abSShawn McCarney } 744*0e8c68abSShawn McCarney ] 745*0e8c68abSShawn McCarney } 746*0e8c68abSShawn McCarney )"_json; 747*0e8c68abSShawn McCarney parseRoot(element); 748*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 749*0e8c68abSShawn McCarney } 750*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 751*0e8c68abSShawn McCarney { 752*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: chassis"); 753*0e8c68abSShawn McCarney } 754*0e8c68abSShawn McCarney 755*0e8c68abSShawn McCarney // Test where fails: Invalid property specified 756*0e8c68abSShawn McCarney try 757*0e8c68abSShawn McCarney { 758*0e8c68abSShawn McCarney const json element = R"( 759*0e8c68abSShawn McCarney { 760*0e8c68abSShawn McCarney "remarks": [ "Config file for a FooBar one-chassis system" ], 761*0e8c68abSShawn McCarney "chassis": [ 762*0e8c68abSShawn McCarney { "number": 1 } 763*0e8c68abSShawn McCarney ] 764*0e8c68abSShawn McCarney } 765*0e8c68abSShawn McCarney )"_json; 766*0e8c68abSShawn McCarney parseRoot(element); 767*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 768*0e8c68abSShawn McCarney } 769*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 770*0e8c68abSShawn McCarney { 771*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property"); 772*0e8c68abSShawn McCarney } 773*0e8c68abSShawn McCarney } 774*0e8c68abSShawn McCarney 775*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseRule) 776*0e8c68abSShawn McCarney { 777*0e8c68abSShawn McCarney // Test where works: comments property specified 778*0e8c68abSShawn McCarney { 779*0e8c68abSShawn McCarney const json element = R"( 780*0e8c68abSShawn McCarney { 781*0e8c68abSShawn McCarney "comments": [ "Set voltage rule" ], 782*0e8c68abSShawn McCarney "id": "set_voltage_rule", 783*0e8c68abSShawn McCarney "actions": [ 784*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 785*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } } 786*0e8c68abSShawn McCarney ] 787*0e8c68abSShawn McCarney } 788*0e8c68abSShawn McCarney )"_json; 789*0e8c68abSShawn McCarney std::unique_ptr<Rule> rule = parseRule(element); 790*0e8c68abSShawn McCarney EXPECT_EQ(rule->getID(), "set_voltage_rule"); 791*0e8c68abSShawn McCarney EXPECT_EQ(rule->getActions().size(), 2); 792*0e8c68abSShawn McCarney } 793*0e8c68abSShawn McCarney 794*0e8c68abSShawn McCarney // Test where works: comments property not specified 795*0e8c68abSShawn McCarney { 796*0e8c68abSShawn McCarney const json element = R"( 797*0e8c68abSShawn McCarney { 798*0e8c68abSShawn McCarney "id": "set_voltage_rule", 799*0e8c68abSShawn McCarney "actions": [ 800*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 801*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.03, "format": "linear" } }, 802*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.05, "format": "linear" } } 803*0e8c68abSShawn McCarney ] 804*0e8c68abSShawn McCarney } 805*0e8c68abSShawn McCarney )"_json; 806*0e8c68abSShawn McCarney std::unique_ptr<Rule> rule = parseRule(element); 807*0e8c68abSShawn McCarney EXPECT_EQ(rule->getID(), "set_voltage_rule"); 808*0e8c68abSShawn McCarney EXPECT_EQ(rule->getActions().size(), 3); 809*0e8c68abSShawn McCarney } 810*0e8c68abSShawn McCarney 811*0e8c68abSShawn McCarney // Test where fails: Element is not an object 812*0e8c68abSShawn McCarney try 813*0e8c68abSShawn McCarney { 814*0e8c68abSShawn McCarney const json element = R"( [ "0xFF", "0x01" ] )"_json; 815*0e8c68abSShawn McCarney parseRule(element); 816*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 817*0e8c68abSShawn McCarney } 818*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 819*0e8c68abSShawn McCarney { 820*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object"); 821*0e8c68abSShawn McCarney } 822*0e8c68abSShawn McCarney 823*0e8c68abSShawn McCarney // Test where fails: id property not specified 824*0e8c68abSShawn McCarney try 825*0e8c68abSShawn McCarney { 826*0e8c68abSShawn McCarney const json element = R"( 827*0e8c68abSShawn McCarney { 828*0e8c68abSShawn McCarney "actions": [ 829*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 830*0e8c68abSShawn McCarney ] 831*0e8c68abSShawn McCarney } 832*0e8c68abSShawn McCarney )"_json; 833*0e8c68abSShawn McCarney parseRule(element); 834*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 835*0e8c68abSShawn McCarney } 836*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 837*0e8c68abSShawn McCarney { 838*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: id"); 839*0e8c68abSShawn McCarney } 840*0e8c68abSShawn McCarney 841*0e8c68abSShawn McCarney // Test where fails: id property is invalid 842*0e8c68abSShawn McCarney try 843*0e8c68abSShawn McCarney { 844*0e8c68abSShawn McCarney const json element = R"( 845*0e8c68abSShawn McCarney { 846*0e8c68abSShawn McCarney "id": "", 847*0e8c68abSShawn McCarney "actions": [ 848*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 849*0e8c68abSShawn McCarney ] 850*0e8c68abSShawn McCarney } 851*0e8c68abSShawn McCarney )"_json; 852*0e8c68abSShawn McCarney parseRule(element); 853*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 854*0e8c68abSShawn McCarney } 855*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 856*0e8c68abSShawn McCarney { 857*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an empty string"); 858*0e8c68abSShawn McCarney } 859*0e8c68abSShawn McCarney 860*0e8c68abSShawn McCarney // Test where fails: actions property not specified 861*0e8c68abSShawn McCarney try 862*0e8c68abSShawn McCarney { 863*0e8c68abSShawn McCarney const json element = R"( 864*0e8c68abSShawn McCarney { 865*0e8c68abSShawn McCarney "comments": [ "Set voltage rule" ], 866*0e8c68abSShawn McCarney "id": "set_voltage_rule" 867*0e8c68abSShawn McCarney } 868*0e8c68abSShawn McCarney )"_json; 869*0e8c68abSShawn McCarney parseRule(element); 870*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 871*0e8c68abSShawn McCarney } 872*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 873*0e8c68abSShawn McCarney { 874*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: actions"); 875*0e8c68abSShawn McCarney } 876*0e8c68abSShawn McCarney 877*0e8c68abSShawn McCarney // Test where fails: actions property is invalid 878*0e8c68abSShawn McCarney try 879*0e8c68abSShawn McCarney { 880*0e8c68abSShawn McCarney const json element = R"( 881*0e8c68abSShawn McCarney { 882*0e8c68abSShawn McCarney "id": "set_voltage_rule", 883*0e8c68abSShawn McCarney "actions": true 884*0e8c68abSShawn McCarney } 885*0e8c68abSShawn McCarney )"_json; 886*0e8c68abSShawn McCarney parseRule(element); 887*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 888*0e8c68abSShawn McCarney } 889*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 890*0e8c68abSShawn McCarney { 891*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an array"); 892*0e8c68abSShawn McCarney } 893*0e8c68abSShawn McCarney 894*0e8c68abSShawn McCarney // Test where fails: Invalid property specified 895*0e8c68abSShawn McCarney try 896*0e8c68abSShawn McCarney { 897*0e8c68abSShawn McCarney const json element = R"( 898*0e8c68abSShawn McCarney { 899*0e8c68abSShawn McCarney "remarks": [ "Set voltage rule" ], 900*0e8c68abSShawn McCarney "id": "set_voltage_rule", 901*0e8c68abSShawn McCarney "actions": [ 902*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 903*0e8c68abSShawn McCarney ] 904*0e8c68abSShawn McCarney } 905*0e8c68abSShawn McCarney )"_json; 906*0e8c68abSShawn McCarney parseRule(element); 907*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 908*0e8c68abSShawn McCarney } 909*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 910*0e8c68abSShawn McCarney { 911*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property"); 912*0e8c68abSShawn McCarney } 913*0e8c68abSShawn McCarney } 914*0e8c68abSShawn McCarney 915*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseRuleArray) 916*0e8c68abSShawn McCarney { 917*0e8c68abSShawn McCarney // Test where works 918*0e8c68abSShawn McCarney { 919*0e8c68abSShawn McCarney const json element = R"( 920*0e8c68abSShawn McCarney [ 921*0e8c68abSShawn McCarney { 922*0e8c68abSShawn McCarney "id": "set_voltage_rule1", 923*0e8c68abSShawn McCarney "actions": [ 924*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } } 925*0e8c68abSShawn McCarney ] 926*0e8c68abSShawn McCarney }, 927*0e8c68abSShawn McCarney { 928*0e8c68abSShawn McCarney "id": "set_voltage_rule2", 929*0e8c68abSShawn McCarney "actions": [ 930*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.01, "format": "linear" } }, 931*0e8c68abSShawn McCarney { "pmbus_write_vout_command": { "volts": 1.11, "format": "linear" } } 932*0e8c68abSShawn McCarney ] 933*0e8c68abSShawn McCarney } 934*0e8c68abSShawn McCarney ] 935*0e8c68abSShawn McCarney )"_json; 936*0e8c68abSShawn McCarney std::vector<std::unique_ptr<Rule>> rules = parseRuleArray(element); 937*0e8c68abSShawn McCarney EXPECT_EQ(rules.size(), 2); 938*0e8c68abSShawn McCarney EXPECT_EQ(rules[0]->getID(), "set_voltage_rule1"); 939*0e8c68abSShawn McCarney EXPECT_EQ(rules[0]->getActions().size(), 1); 940*0e8c68abSShawn McCarney EXPECT_EQ(rules[1]->getID(), "set_voltage_rule2"); 941*0e8c68abSShawn McCarney EXPECT_EQ(rules[1]->getActions().size(), 2); 942*0e8c68abSShawn McCarney } 943*0e8c68abSShawn McCarney 944*0e8c68abSShawn McCarney // Test where fails: Element is not an array 945*0e8c68abSShawn McCarney try 946*0e8c68abSShawn McCarney { 947*0e8c68abSShawn McCarney const json element = R"( { "id": "set_voltage_rule" } )"_json; 948*0e8c68abSShawn McCarney parseRuleArray(element); 949*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 950*0e8c68abSShawn McCarney } 951*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 952*0e8c68abSShawn McCarney { 953*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an array"); 954*0e8c68abSShawn McCarney } 955*0e8c68abSShawn McCarney } 956*0e8c68abSShawn McCarney 957*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, ParseString) 958*0e8c68abSShawn McCarney { 959*0e8c68abSShawn McCarney // Test where works: Empty string 960*0e8c68abSShawn McCarney { 961*0e8c68abSShawn McCarney const json element = ""; 962*0e8c68abSShawn McCarney std::string value = parseString(element, true); 963*0e8c68abSShawn McCarney EXPECT_EQ(value, ""); 964*0e8c68abSShawn McCarney } 965*0e8c68abSShawn McCarney 966*0e8c68abSShawn McCarney // Test where works: Non-empty string 967*0e8c68abSShawn McCarney { 968*0e8c68abSShawn McCarney const json element = "vdd_regulator"; 969*0e8c68abSShawn McCarney std::string value = parseString(element, false); 970*0e8c68abSShawn McCarney EXPECT_EQ(value, "vdd_regulator"); 971*0e8c68abSShawn McCarney } 972*0e8c68abSShawn McCarney 973*0e8c68abSShawn McCarney // Test where fails: Element is not a string 974*0e8c68abSShawn McCarney try 975*0e8c68abSShawn McCarney { 976*0e8c68abSShawn McCarney const json element = R"( { "foo": "bar" } )"_json; 977*0e8c68abSShawn McCarney parseString(element); 978*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 979*0e8c68abSShawn McCarney } 980*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 981*0e8c68abSShawn McCarney { 982*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a string"); 983*0e8c68abSShawn McCarney } 984*0e8c68abSShawn McCarney 985*0e8c68abSShawn McCarney // Test where fails: Empty string 986*0e8c68abSShawn McCarney try 987*0e8c68abSShawn McCarney { 988*0e8c68abSShawn McCarney const json element = ""; 989*0e8c68abSShawn McCarney parseString(element); 990*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 991*0e8c68abSShawn McCarney } 992*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 993*0e8c68abSShawn McCarney { 994*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an empty string"); 995*0e8c68abSShawn McCarney } 996*0e8c68abSShawn McCarney } 997*0e8c68abSShawn McCarney 998*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, VerifyIsArray) 999*0e8c68abSShawn McCarney { 1000*0e8c68abSShawn McCarney // Test where element is an array 1001*0e8c68abSShawn McCarney try 1002*0e8c68abSShawn McCarney { 1003*0e8c68abSShawn McCarney const json element = R"( [ "foo", "bar" ] )"_json; 1004*0e8c68abSShawn McCarney verifyIsArray(element); 1005*0e8c68abSShawn McCarney } 1006*0e8c68abSShawn McCarney catch (const std::exception& e) 1007*0e8c68abSShawn McCarney { 1008*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have caught exception."; 1009*0e8c68abSShawn McCarney } 1010*0e8c68abSShawn McCarney 1011*0e8c68abSShawn McCarney // Test where element is not an array 1012*0e8c68abSShawn McCarney try 1013*0e8c68abSShawn McCarney { 1014*0e8c68abSShawn McCarney const json element = R"( { "foo": "bar" } )"_json; 1015*0e8c68abSShawn McCarney verifyIsArray(element); 1016*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 1017*0e8c68abSShawn McCarney } 1018*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 1019*0e8c68abSShawn McCarney { 1020*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an array"); 1021*0e8c68abSShawn McCarney } 1022*0e8c68abSShawn McCarney } 1023*0e8c68abSShawn McCarney 1024*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, VerifyIsObject) 1025*0e8c68abSShawn McCarney { 1026*0e8c68abSShawn McCarney // Test where element is an object 1027*0e8c68abSShawn McCarney try 1028*0e8c68abSShawn McCarney { 1029*0e8c68abSShawn McCarney const json element = R"( { "foo": "bar" } )"_json; 1030*0e8c68abSShawn McCarney verifyIsObject(element); 1031*0e8c68abSShawn McCarney } 1032*0e8c68abSShawn McCarney catch (const std::exception& e) 1033*0e8c68abSShawn McCarney { 1034*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have caught exception."; 1035*0e8c68abSShawn McCarney } 1036*0e8c68abSShawn McCarney 1037*0e8c68abSShawn McCarney // Test where element is not an object 1038*0e8c68abSShawn McCarney try 1039*0e8c68abSShawn McCarney { 1040*0e8c68abSShawn McCarney const json element = R"( [ "foo", "bar" ] )"_json; 1041*0e8c68abSShawn McCarney verifyIsObject(element); 1042*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 1043*0e8c68abSShawn McCarney } 1044*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 1045*0e8c68abSShawn McCarney { 1046*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object"); 1047*0e8c68abSShawn McCarney } 1048*0e8c68abSShawn McCarney } 1049*0e8c68abSShawn McCarney 1050*0e8c68abSShawn McCarney TEST(ConfigFileParserTests, VerifyPropertyCount) 1051*0e8c68abSShawn McCarney { 1052*0e8c68abSShawn McCarney // Test where element has expected number of properties 1053*0e8c68abSShawn McCarney try 1054*0e8c68abSShawn McCarney { 1055*0e8c68abSShawn McCarney const json element = R"( 1056*0e8c68abSShawn McCarney { 1057*0e8c68abSShawn McCarney "comments": [ "Set voltage rule" ], 1058*0e8c68abSShawn McCarney "id": "set_voltage_rule" 1059*0e8c68abSShawn McCarney } 1060*0e8c68abSShawn McCarney )"_json; 1061*0e8c68abSShawn McCarney verifyPropertyCount(element, 2); 1062*0e8c68abSShawn McCarney } 1063*0e8c68abSShawn McCarney catch (const std::exception& e) 1064*0e8c68abSShawn McCarney { 1065*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have caught exception."; 1066*0e8c68abSShawn McCarney } 1067*0e8c68abSShawn McCarney 1068*0e8c68abSShawn McCarney // Test where element has unexpected number of properties 1069*0e8c68abSShawn McCarney try 1070*0e8c68abSShawn McCarney { 1071*0e8c68abSShawn McCarney const json element = R"( 1072*0e8c68abSShawn McCarney { 1073*0e8c68abSShawn McCarney "comments": [ "Set voltage rule" ], 1074*0e8c68abSShawn McCarney "id": "set_voltage_rule", 1075*0e8c68abSShawn McCarney "foo": 1.3 1076*0e8c68abSShawn McCarney } 1077*0e8c68abSShawn McCarney )"_json; 1078*0e8c68abSShawn McCarney verifyPropertyCount(element, 2); 1079*0e8c68abSShawn McCarney ADD_FAILURE() << "Should not have reached this line."; 1080*0e8c68abSShawn McCarney } 1081*0e8c68abSShawn McCarney catch (const std::invalid_argument& e) 1082*0e8c68abSShawn McCarney { 1083*0e8c68abSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property"); 1084*0e8c68abSShawn McCarney } 1085*0e8c68abSShawn McCarney } 1086