16a957f6fSShawn McCarney /**
26a957f6fSShawn McCarney * Copyright © 2024 IBM Corporation
36a957f6fSShawn McCarney *
46a957f6fSShawn McCarney * Licensed under the Apache License, Version 2.0 (the "License");
56a957f6fSShawn McCarney * you may not use this file except in compliance with the License.
66a957f6fSShawn McCarney * You may obtain a copy of the License at
76a957f6fSShawn McCarney *
86a957f6fSShawn McCarney * http://www.apache.org/licenses/LICENSE-2.0
96a957f6fSShawn McCarney *
106a957f6fSShawn McCarney * Unless required by applicable law or agreed to in writing, software
116a957f6fSShawn McCarney * distributed under the License is distributed on an "AS IS" BASIS,
126a957f6fSShawn McCarney * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136a957f6fSShawn McCarney * See the License for the specific language governing permissions and
146a957f6fSShawn McCarney * limitations under the License.
156a957f6fSShawn McCarney */
166a957f6fSShawn McCarney #include "config_file_parser.hpp"
176a957f6fSShawn McCarney #include "config_file_parser_error.hpp"
186a957f6fSShawn McCarney #include "rail.hpp"
196a957f6fSShawn McCarney #include "temporary_file.hpp"
20*e9144ab4SShawn McCarney #include "temporary_subdirectory.hpp"
216a957f6fSShawn McCarney
226a957f6fSShawn McCarney #include <sys/stat.h> // for chmod()
236a957f6fSShawn McCarney
246a957f6fSShawn McCarney #include <nlohmann/json.hpp>
256a957f6fSShawn McCarney
266a957f6fSShawn McCarney #include <cstdint>
276a957f6fSShawn McCarney #include <exception>
286a957f6fSShawn McCarney #include <filesystem>
296a957f6fSShawn McCarney #include <fstream>
306a957f6fSShawn McCarney #include <memory>
316a957f6fSShawn McCarney #include <optional>
326a957f6fSShawn McCarney #include <stdexcept>
336a957f6fSShawn McCarney #include <string>
346a957f6fSShawn McCarney #include <vector>
356a957f6fSShawn McCarney
366a957f6fSShawn McCarney #include <gtest/gtest.h>
376a957f6fSShawn McCarney
386a957f6fSShawn McCarney using namespace phosphor::power::sequencer;
396a957f6fSShawn McCarney using namespace phosphor::power::sequencer::config_file_parser;
406a957f6fSShawn McCarney using namespace phosphor::power::sequencer::config_file_parser::internal;
41*e9144ab4SShawn McCarney using namespace phosphor::power::util;
426a957f6fSShawn McCarney using json = nlohmann::json;
43*e9144ab4SShawn McCarney namespace fs = std::filesystem;
446a957f6fSShawn McCarney
writeConfigFile(const fs::path & pathName,const std::string & contents)45*e9144ab4SShawn McCarney void writeConfigFile(const fs::path& pathName, const std::string& contents)
466a957f6fSShawn McCarney {
476a957f6fSShawn McCarney std::ofstream file{pathName};
486a957f6fSShawn McCarney file << contents;
496a957f6fSShawn McCarney }
506a957f6fSShawn McCarney
writeConfigFile(const fs::path & pathName,const json & contents)51*e9144ab4SShawn McCarney void writeConfigFile(const fs::path& pathName, const json& contents)
526a957f6fSShawn McCarney {
536a957f6fSShawn McCarney std::ofstream file{pathName};
546a957f6fSShawn McCarney file << contents;
556a957f6fSShawn McCarney }
566a957f6fSShawn McCarney
TEST(ConfigFileParserTests,Find)57*e9144ab4SShawn McCarney TEST(ConfigFileParserTests, Find)
58*e9144ab4SShawn McCarney {
59*e9144ab4SShawn McCarney std::vector<std::string> compatibleSystemTypes{
60*e9144ab4SShawn McCarney "com.acme.Hardware.Chassis.Model.MegaServer4CPU",
61*e9144ab4SShawn McCarney "com.acme.Hardware.Chassis.Model.MegaServer",
62*e9144ab4SShawn McCarney "com.acme.Hardware.Chassis.Model.Server"};
63*e9144ab4SShawn McCarney
64*e9144ab4SShawn McCarney // Test where works: Fully qualified system type: First in list
65*e9144ab4SShawn McCarney {
66*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
67*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
68*e9144ab4SShawn McCarney
69*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
70*e9144ab4SShawn McCarney configFilePath /= "com.acme.Hardware.Chassis.Model.MegaServer4CPU.json";
71*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
72*e9144ab4SShawn McCarney
73*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
74*e9144ab4SShawn McCarney EXPECT_EQ(pathFound, configFilePath);
75*e9144ab4SShawn McCarney }
76*e9144ab4SShawn McCarney
77*e9144ab4SShawn McCarney // Test where works: Fully qualified system type: Second in list
78*e9144ab4SShawn McCarney {
79*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
80*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
81*e9144ab4SShawn McCarney
82*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
83*e9144ab4SShawn McCarney configFilePath /= "com.acme.Hardware.Chassis.Model.MegaServer.json";
84*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
85*e9144ab4SShawn McCarney
86*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
87*e9144ab4SShawn McCarney EXPECT_EQ(pathFound, configFilePath);
88*e9144ab4SShawn McCarney }
89*e9144ab4SShawn McCarney
90*e9144ab4SShawn McCarney // Test where works: Last node in system type: Second in list
91*e9144ab4SShawn McCarney {
92*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
93*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
94*e9144ab4SShawn McCarney
95*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
96*e9144ab4SShawn McCarney configFilePath /= "MegaServer.json";
97*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
98*e9144ab4SShawn McCarney
99*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
100*e9144ab4SShawn McCarney EXPECT_EQ(pathFound, configFilePath);
101*e9144ab4SShawn McCarney }
102*e9144ab4SShawn McCarney
103*e9144ab4SShawn McCarney // Test where works: Last node in system type: Last in list
104*e9144ab4SShawn McCarney {
105*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
106*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
107*e9144ab4SShawn McCarney
108*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
109*e9144ab4SShawn McCarney configFilePath /= "Server.json";
110*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
111*e9144ab4SShawn McCarney
112*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
113*e9144ab4SShawn McCarney EXPECT_EQ(pathFound, configFilePath);
114*e9144ab4SShawn McCarney }
115*e9144ab4SShawn McCarney
116*e9144ab4SShawn McCarney // Test where works: System type has no '.'
117*e9144ab4SShawn McCarney {
118*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
119*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
120*e9144ab4SShawn McCarney
121*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
122*e9144ab4SShawn McCarney configFilePath /= "Server.json";
123*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
124*e9144ab4SShawn McCarney
125*e9144ab4SShawn McCarney std::vector<std::string> noDotSystemTypes{"MegaServer4CPU",
126*e9144ab4SShawn McCarney "MegaServer", "Server"};
127*e9144ab4SShawn McCarney fs::path pathFound = find(noDotSystemTypes, configFileDirPath);
128*e9144ab4SShawn McCarney EXPECT_EQ(pathFound, configFilePath);
129*e9144ab4SShawn McCarney }
130*e9144ab4SShawn McCarney
131*e9144ab4SShawn McCarney // Test where fails: System type list is empty
132*e9144ab4SShawn McCarney {
133*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
134*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
135*e9144ab4SShawn McCarney
136*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
137*e9144ab4SShawn McCarney configFilePath /= "Server.json";
138*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
139*e9144ab4SShawn McCarney
140*e9144ab4SShawn McCarney std::vector<std::string> emptySystemTypes{};
141*e9144ab4SShawn McCarney fs::path pathFound = find(emptySystemTypes, configFileDirPath);
142*e9144ab4SShawn McCarney EXPECT_TRUE(pathFound.empty());
143*e9144ab4SShawn McCarney }
144*e9144ab4SShawn McCarney
145*e9144ab4SShawn McCarney // Test where fails: Configuration file directory is empty
146*e9144ab4SShawn McCarney {
147*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
148*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
149*e9144ab4SShawn McCarney
150*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
151*e9144ab4SShawn McCarney EXPECT_TRUE(pathFound.empty());
152*e9144ab4SShawn McCarney }
153*e9144ab4SShawn McCarney
154*e9144ab4SShawn McCarney // Test where fails: Configuration file directory does not exist
155*e9144ab4SShawn McCarney {
156*e9144ab4SShawn McCarney fs::path configFileDirPath{"/tmp/does_not_exist_XYZ"};
157*e9144ab4SShawn McCarney
158*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
159*e9144ab4SShawn McCarney EXPECT_TRUE(pathFound.empty());
160*e9144ab4SShawn McCarney }
161*e9144ab4SShawn McCarney
162*e9144ab4SShawn McCarney // Test where fails: Configuration file directory is not readable
163*e9144ab4SShawn McCarney {
164*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
165*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
166*e9144ab4SShawn McCarney fs::permissions(configFileDirPath, fs::perms::none);
167*e9144ab4SShawn McCarney
168*e9144ab4SShawn McCarney EXPECT_THROW(find(compatibleSystemTypes, configFileDirPath),
169*e9144ab4SShawn McCarney std::exception);
170*e9144ab4SShawn McCarney
171*e9144ab4SShawn McCarney fs::permissions(configFileDirPath, fs::perms::owner_all);
172*e9144ab4SShawn McCarney }
173*e9144ab4SShawn McCarney
174*e9144ab4SShawn McCarney // Test where fails: No matching file name found
175*e9144ab4SShawn McCarney {
176*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
177*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
178*e9144ab4SShawn McCarney
179*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
180*e9144ab4SShawn McCarney configFilePath /= "com.acme.Hardware.Chassis.Model.MegaServer";
181*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
182*e9144ab4SShawn McCarney
183*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
184*e9144ab4SShawn McCarney EXPECT_TRUE(pathFound.empty());
185*e9144ab4SShawn McCarney }
186*e9144ab4SShawn McCarney
187*e9144ab4SShawn McCarney // Test where fails: Matching file name is a directory: Fully qualified
188*e9144ab4SShawn McCarney {
189*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
190*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
191*e9144ab4SShawn McCarney
192*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
193*e9144ab4SShawn McCarney configFilePath /= "com.acme.Hardware.Chassis.Model.MegaServer4CPU.json";
194*e9144ab4SShawn McCarney fs::create_directory(configFilePath);
195*e9144ab4SShawn McCarney
196*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
197*e9144ab4SShawn McCarney EXPECT_TRUE(pathFound.empty());
198*e9144ab4SShawn McCarney }
199*e9144ab4SShawn McCarney
200*e9144ab4SShawn McCarney // Test where fails: Matching file name is a directory: Last node
201*e9144ab4SShawn McCarney {
202*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
203*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
204*e9144ab4SShawn McCarney
205*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
206*e9144ab4SShawn McCarney configFilePath /= "MegaServer.json";
207*e9144ab4SShawn McCarney fs::create_directory(configFilePath);
208*e9144ab4SShawn McCarney
209*e9144ab4SShawn McCarney fs::path pathFound = find(compatibleSystemTypes, configFileDirPath);
210*e9144ab4SShawn McCarney EXPECT_TRUE(pathFound.empty());
211*e9144ab4SShawn McCarney }
212*e9144ab4SShawn McCarney
213*e9144ab4SShawn McCarney // Test where fails: System type has no '.'
214*e9144ab4SShawn McCarney {
215*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
216*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
217*e9144ab4SShawn McCarney
218*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
219*e9144ab4SShawn McCarney configFilePath /= "MegaServer2CPU.json";
220*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
221*e9144ab4SShawn McCarney
222*e9144ab4SShawn McCarney std::vector<std::string> noDotSystemTypes{"MegaServer4CPU",
223*e9144ab4SShawn McCarney "MegaServer", "Server", ""};
224*e9144ab4SShawn McCarney fs::path pathFound = find(noDotSystemTypes, configFileDirPath);
225*e9144ab4SShawn McCarney EXPECT_TRUE(pathFound.empty());
226*e9144ab4SShawn McCarney }
227*e9144ab4SShawn McCarney
228*e9144ab4SShawn McCarney // Test where fails: System type ends with '.'
229*e9144ab4SShawn McCarney {
230*e9144ab4SShawn McCarney TemporarySubDirectory configFileDir;
231*e9144ab4SShawn McCarney fs::path configFileDirPath = configFileDir.getPath();
232*e9144ab4SShawn McCarney
233*e9144ab4SShawn McCarney fs::path configFilePath = configFileDirPath;
234*e9144ab4SShawn McCarney configFilePath /= "MegaServer4CPU.json";
235*e9144ab4SShawn McCarney writeConfigFile(configFilePath, std::string{""});
236*e9144ab4SShawn McCarney
237*e9144ab4SShawn McCarney std::vector<std::string> dotAtEndSystemTypes{
238*e9144ab4SShawn McCarney "com.acme.Hardware.Chassis.Model.MegaServer4CPU.", "a.", "."};
239*e9144ab4SShawn McCarney fs::path pathFound = find(dotAtEndSystemTypes, configFileDirPath);
240*e9144ab4SShawn McCarney EXPECT_TRUE(pathFound.empty());
241*e9144ab4SShawn McCarney }
242*e9144ab4SShawn McCarney }
243*e9144ab4SShawn McCarney
TEST(ConfigFileParserTests,Parse)2446a957f6fSShawn McCarney TEST(ConfigFileParserTests, Parse)
2456a957f6fSShawn McCarney {
2466a957f6fSShawn McCarney // Test where works
2476a957f6fSShawn McCarney {
2486a957f6fSShawn McCarney const json configFileContents = R"(
2496a957f6fSShawn McCarney {
2506a957f6fSShawn McCarney "rails": [
2516a957f6fSShawn McCarney {
2526a957f6fSShawn McCarney "name": "VDD_CPU0",
2536a957f6fSShawn McCarney "page": 11,
2546a957f6fSShawn McCarney "check_status_vout": true
2556a957f6fSShawn McCarney },
2566a957f6fSShawn McCarney {
2576a957f6fSShawn McCarney "name": "VCS_CPU1",
2586a957f6fSShawn McCarney "presence": "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1",
2596a957f6fSShawn McCarney "gpio": { "line": 60 }
2606a957f6fSShawn McCarney }
2616a957f6fSShawn McCarney ]
2626a957f6fSShawn McCarney }
2636a957f6fSShawn McCarney )"_json;
2646a957f6fSShawn McCarney
2656a957f6fSShawn McCarney TemporaryFile configFile;
266*e9144ab4SShawn McCarney fs::path pathName{configFile.getPath()};
2676a957f6fSShawn McCarney writeConfigFile(pathName, configFileContents);
2686a957f6fSShawn McCarney
2696a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> rails = parse(pathName);
2706a957f6fSShawn McCarney
2716a957f6fSShawn McCarney EXPECT_EQ(rails.size(), 2);
2726a957f6fSShawn McCarney EXPECT_EQ(rails[0]->getName(), "VDD_CPU0");
2736a957f6fSShawn McCarney EXPECT_EQ(rails[1]->getName(), "VCS_CPU1");
2746a957f6fSShawn McCarney }
2756a957f6fSShawn McCarney
2766a957f6fSShawn McCarney // Test where fails: File does not exist
2776a957f6fSShawn McCarney {
278*e9144ab4SShawn McCarney fs::path pathName{"/tmp/non_existent_file"};
2796a957f6fSShawn McCarney EXPECT_THROW(parse(pathName), ConfigFileParserError);
2806a957f6fSShawn McCarney }
2816a957f6fSShawn McCarney
2826a957f6fSShawn McCarney // Test where fails: File is not readable
2836a957f6fSShawn McCarney {
2846a957f6fSShawn McCarney const json configFileContents = R"(
2856a957f6fSShawn McCarney {
2866a957f6fSShawn McCarney "rails": [
2876a957f6fSShawn McCarney {
2886a957f6fSShawn McCarney "name": "VDD_CPU0"
2896a957f6fSShawn McCarney }
2906a957f6fSShawn McCarney ]
2916a957f6fSShawn McCarney }
2926a957f6fSShawn McCarney )"_json;
2936a957f6fSShawn McCarney
2946a957f6fSShawn McCarney TemporaryFile configFile;
295*e9144ab4SShawn McCarney fs::path pathName{configFile.getPath()};
2966a957f6fSShawn McCarney writeConfigFile(pathName, configFileContents);
2976a957f6fSShawn McCarney
2986a957f6fSShawn McCarney chmod(pathName.c_str(), 0222);
2996a957f6fSShawn McCarney EXPECT_THROW(parse(pathName), ConfigFileParserError);
3006a957f6fSShawn McCarney }
3016a957f6fSShawn McCarney
3026a957f6fSShawn McCarney // Test where fails: File is not valid JSON
3036a957f6fSShawn McCarney {
3046a957f6fSShawn McCarney const std::string configFileContents = "] foo [";
3056a957f6fSShawn McCarney
3066a957f6fSShawn McCarney TemporaryFile configFile;
307*e9144ab4SShawn McCarney fs::path pathName{configFile.getPath()};
3086a957f6fSShawn McCarney writeConfigFile(pathName, configFileContents);
3096a957f6fSShawn McCarney
3106a957f6fSShawn McCarney EXPECT_THROW(parse(pathName), ConfigFileParserError);
3116a957f6fSShawn McCarney }
3126a957f6fSShawn McCarney
3136a957f6fSShawn McCarney // Test where fails: JSON does not conform to config file format
3146a957f6fSShawn McCarney {
3156a957f6fSShawn McCarney const json configFileContents = R"( [ "foo", "bar" ] )"_json;
3166a957f6fSShawn McCarney
3176a957f6fSShawn McCarney TemporaryFile configFile;
318*e9144ab4SShawn McCarney fs::path pathName{configFile.getPath()};
3196a957f6fSShawn McCarney writeConfigFile(pathName, configFileContents);
3206a957f6fSShawn McCarney
3216a957f6fSShawn McCarney EXPECT_THROW(parse(pathName), ConfigFileParserError);
3226a957f6fSShawn McCarney }
3236a957f6fSShawn McCarney }
3246a957f6fSShawn McCarney
TEST(ConfigFileParserTests,GetRequiredProperty)3256a957f6fSShawn McCarney TEST(ConfigFileParserTests, GetRequiredProperty)
3266a957f6fSShawn McCarney {
3276a957f6fSShawn McCarney // Test where property exists
3286a957f6fSShawn McCarney {
3296a957f6fSShawn McCarney const json element = R"( { "name": "VDD_CPU0" } )"_json;
3306a957f6fSShawn McCarney const json& propertyElement = getRequiredProperty(element, "name");
3316a957f6fSShawn McCarney EXPECT_EQ(propertyElement.get<std::string>(), "VDD_CPU0");
3326a957f6fSShawn McCarney }
3336a957f6fSShawn McCarney
3346a957f6fSShawn McCarney // Test where property does not exist
3356a957f6fSShawn McCarney try
3366a957f6fSShawn McCarney {
3376a957f6fSShawn McCarney const json element = R"( { "foo": 23 } )"_json;
3386a957f6fSShawn McCarney getRequiredProperty(element, "name");
3396a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
3406a957f6fSShawn McCarney }
3416a957f6fSShawn McCarney catch (const std::invalid_argument& e)
3426a957f6fSShawn McCarney {
3436a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: name");
3446a957f6fSShawn McCarney }
3456a957f6fSShawn McCarney }
3466a957f6fSShawn McCarney
TEST(ConfigFileParserTests,ParseBoolean)3476a957f6fSShawn McCarney TEST(ConfigFileParserTests, ParseBoolean)
3486a957f6fSShawn McCarney {
3496a957f6fSShawn McCarney // Test where works: true
3506a957f6fSShawn McCarney {
3516a957f6fSShawn McCarney const json element = R"( true )"_json;
3526a957f6fSShawn McCarney bool value = parseBoolean(element);
3536a957f6fSShawn McCarney EXPECT_EQ(value, true);
3546a957f6fSShawn McCarney }
3556a957f6fSShawn McCarney
3566a957f6fSShawn McCarney // Test where works: false
3576a957f6fSShawn McCarney {
3586a957f6fSShawn McCarney const json element = R"( false )"_json;
3596a957f6fSShawn McCarney bool value = parseBoolean(element);
3606a957f6fSShawn McCarney EXPECT_EQ(value, false);
3616a957f6fSShawn McCarney }
3626a957f6fSShawn McCarney
3636a957f6fSShawn McCarney // Test where fails: Element is not a boolean
3646a957f6fSShawn McCarney try
3656a957f6fSShawn McCarney {
3666a957f6fSShawn McCarney const json element = R"( 1 )"_json;
3676a957f6fSShawn McCarney parseBoolean(element);
3686a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
3696a957f6fSShawn McCarney }
3706a957f6fSShawn McCarney catch (const std::invalid_argument& e)
3716a957f6fSShawn McCarney {
3726a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a boolean");
3736a957f6fSShawn McCarney }
3746a957f6fSShawn McCarney }
3756a957f6fSShawn McCarney
TEST(ConfigFileParserTests,ParseGPIO)3766a957f6fSShawn McCarney TEST(ConfigFileParserTests, ParseGPIO)
3776a957f6fSShawn McCarney {
3786a957f6fSShawn McCarney // Test where works: Only required properties specified
3796a957f6fSShawn McCarney {
3806a957f6fSShawn McCarney const json element = R"(
3816a957f6fSShawn McCarney {
3826a957f6fSShawn McCarney "line": 60
3836a957f6fSShawn McCarney }
3846a957f6fSShawn McCarney )"_json;
3856a957f6fSShawn McCarney GPIO gpio = parseGPIO(element);
3866a957f6fSShawn McCarney EXPECT_EQ(gpio.line, 60);
3876a957f6fSShawn McCarney EXPECT_FALSE(gpio.activeLow);
3886a957f6fSShawn McCarney }
3896a957f6fSShawn McCarney
3906a957f6fSShawn McCarney // Test where works: All properties specified
3916a957f6fSShawn McCarney {
3926a957f6fSShawn McCarney const json element = R"(
3936a957f6fSShawn McCarney {
3946a957f6fSShawn McCarney "line": 131,
3956a957f6fSShawn McCarney "active_low": true
3966a957f6fSShawn McCarney }
3976a957f6fSShawn McCarney )"_json;
3986a957f6fSShawn McCarney GPIO gpio = parseGPIO(element);
3996a957f6fSShawn McCarney EXPECT_EQ(gpio.line, 131);
4006a957f6fSShawn McCarney EXPECT_TRUE(gpio.activeLow);
4016a957f6fSShawn McCarney }
4026a957f6fSShawn McCarney
4036a957f6fSShawn McCarney // Test where fails: Element is not an object
4046a957f6fSShawn McCarney try
4056a957f6fSShawn McCarney {
4066a957f6fSShawn McCarney const json element = R"( [ "vdda", "vddb" ] )"_json;
4076a957f6fSShawn McCarney parseGPIO(element);
4086a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
4096a957f6fSShawn McCarney }
4106a957f6fSShawn McCarney catch (const std::invalid_argument& e)
4116a957f6fSShawn McCarney {
4126a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object");
4136a957f6fSShawn McCarney }
4146a957f6fSShawn McCarney
4156a957f6fSShawn McCarney // Test where fails: Required line property not specified
4166a957f6fSShawn McCarney try
4176a957f6fSShawn McCarney {
4186a957f6fSShawn McCarney const json element = R"(
4196a957f6fSShawn McCarney {
4206a957f6fSShawn McCarney "active_low": true
4216a957f6fSShawn McCarney }
4226a957f6fSShawn McCarney )"_json;
4236a957f6fSShawn McCarney parseGPIO(element);
4246a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
4256a957f6fSShawn McCarney }
4266a957f6fSShawn McCarney catch (const std::invalid_argument& e)
4276a957f6fSShawn McCarney {
4286a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: line");
4296a957f6fSShawn McCarney }
4306a957f6fSShawn McCarney
4316a957f6fSShawn McCarney // Test where fails: line value is invalid
4326a957f6fSShawn McCarney try
4336a957f6fSShawn McCarney {
4346a957f6fSShawn McCarney const json element = R"(
4356a957f6fSShawn McCarney {
4366a957f6fSShawn McCarney "line": -131,
4376a957f6fSShawn McCarney "active_low": true
4386a957f6fSShawn McCarney }
4396a957f6fSShawn McCarney )"_json;
4406a957f6fSShawn McCarney parseGPIO(element);
4416a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
4426a957f6fSShawn McCarney }
4436a957f6fSShawn McCarney catch (const std::invalid_argument& e)
4446a957f6fSShawn McCarney {
4456a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
4466a957f6fSShawn McCarney }
4476a957f6fSShawn McCarney
4486a957f6fSShawn McCarney // Test where fails: active_low value is invalid
4496a957f6fSShawn McCarney try
4506a957f6fSShawn McCarney {
4516a957f6fSShawn McCarney const json element = R"(
4526a957f6fSShawn McCarney {
4536a957f6fSShawn McCarney "line": 131,
4546a957f6fSShawn McCarney "active_low": "true"
4556a957f6fSShawn McCarney }
4566a957f6fSShawn McCarney )"_json;
4576a957f6fSShawn McCarney parseGPIO(element);
4586a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
4596a957f6fSShawn McCarney }
4606a957f6fSShawn McCarney catch (const std::invalid_argument& e)
4616a957f6fSShawn McCarney {
4626a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a boolean");
4636a957f6fSShawn McCarney }
4646a957f6fSShawn McCarney
4656a957f6fSShawn McCarney // Test where fails: Invalid property specified
4666a957f6fSShawn McCarney try
4676a957f6fSShawn McCarney {
4686a957f6fSShawn McCarney const json element = R"(
4696a957f6fSShawn McCarney {
4706a957f6fSShawn McCarney "line": 131,
4716a957f6fSShawn McCarney "foo": "bar"
4726a957f6fSShawn McCarney }
4736a957f6fSShawn McCarney )"_json;
4746a957f6fSShawn McCarney parseGPIO(element);
4756a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
4766a957f6fSShawn McCarney }
4776a957f6fSShawn McCarney catch (const std::invalid_argument& e)
4786a957f6fSShawn McCarney {
4796a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property");
4806a957f6fSShawn McCarney }
4816a957f6fSShawn McCarney }
4826a957f6fSShawn McCarney
TEST(ConfigFileParserTests,ParseRail)4836a957f6fSShawn McCarney TEST(ConfigFileParserTests, ParseRail)
4846a957f6fSShawn McCarney {
4856a957f6fSShawn McCarney // Test where works: Only required properties specified
4866a957f6fSShawn McCarney {
4876a957f6fSShawn McCarney const json element = R"(
4886a957f6fSShawn McCarney {
4896a957f6fSShawn McCarney "name": "VDD_CPU0"
4906a957f6fSShawn McCarney }
4916a957f6fSShawn McCarney )"_json;
4926a957f6fSShawn McCarney std::unique_ptr<Rail> rail = parseRail(element);
4936a957f6fSShawn McCarney EXPECT_EQ(rail->getName(), "VDD_CPU0");
4946a957f6fSShawn McCarney EXPECT_FALSE(rail->getPresence().has_value());
4956a957f6fSShawn McCarney EXPECT_FALSE(rail->getPage().has_value());
49616e493afSShawn McCarney EXPECT_FALSE(rail->isPowerSupplyRail());
4976a957f6fSShawn McCarney EXPECT_FALSE(rail->getCheckStatusVout());
4989ec0d43dSShawn McCarney EXPECT_FALSE(rail->getCompareVoltageToLimit());
4996a957f6fSShawn McCarney EXPECT_FALSE(rail->getGPIO().has_value());
5006a957f6fSShawn McCarney }
5016a957f6fSShawn McCarney
5026a957f6fSShawn McCarney // Test where works: All properties specified
5036a957f6fSShawn McCarney {
5046a957f6fSShawn McCarney const json element = R"(
5056a957f6fSShawn McCarney {
50616e493afSShawn McCarney "name": "12.0VB",
50716e493afSShawn McCarney "presence": "/xyz/openbmc_project/inventory/system/chassis/powersupply1",
5086a957f6fSShawn McCarney "page": 11,
50916e493afSShawn McCarney "is_power_supply_rail": true,
5106a957f6fSShawn McCarney "check_status_vout": true,
5119ec0d43dSShawn McCarney "compare_voltage_to_limit": true,
5126a957f6fSShawn McCarney "gpio": { "line": 60, "active_low": true }
5136a957f6fSShawn McCarney }
5146a957f6fSShawn McCarney )"_json;
5156a957f6fSShawn McCarney std::unique_ptr<Rail> rail = parseRail(element);
51616e493afSShawn McCarney EXPECT_EQ(rail->getName(), "12.0VB");
5176a957f6fSShawn McCarney EXPECT_TRUE(rail->getPresence().has_value());
51816e493afSShawn McCarney EXPECT_EQ(rail->getPresence().value(),
51916e493afSShawn McCarney "/xyz/openbmc_project/inventory/system/chassis/powersupply1");
5206a957f6fSShawn McCarney EXPECT_TRUE(rail->getPage().has_value());
5216a957f6fSShawn McCarney EXPECT_EQ(rail->getPage().value(), 11);
52216e493afSShawn McCarney EXPECT_TRUE(rail->isPowerSupplyRail());
5236a957f6fSShawn McCarney EXPECT_TRUE(rail->getCheckStatusVout());
5249ec0d43dSShawn McCarney EXPECT_TRUE(rail->getCompareVoltageToLimit());
5256a957f6fSShawn McCarney EXPECT_TRUE(rail->getGPIO().has_value());
5266a957f6fSShawn McCarney EXPECT_EQ(rail->getGPIO().value().line, 60);
5276a957f6fSShawn McCarney EXPECT_TRUE(rail->getGPIO().value().activeLow);
5286a957f6fSShawn McCarney }
5296a957f6fSShawn McCarney
5306a957f6fSShawn McCarney // Test where fails: Element is not an object
5316a957f6fSShawn McCarney try
5326a957f6fSShawn McCarney {
5336a957f6fSShawn McCarney const json element = R"( [ "vdda", "vddb" ] )"_json;
5346a957f6fSShawn McCarney parseRail(element);
5356a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
5366a957f6fSShawn McCarney }
5376a957f6fSShawn McCarney catch (const std::invalid_argument& e)
5386a957f6fSShawn McCarney {
5396a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object");
5406a957f6fSShawn McCarney }
5416a957f6fSShawn McCarney
5426a957f6fSShawn McCarney // Test where fails: Required name property not specified
5436a957f6fSShawn McCarney try
5446a957f6fSShawn McCarney {
5456a957f6fSShawn McCarney const json element = R"(
5466a957f6fSShawn McCarney {
5476a957f6fSShawn McCarney "page": 11
5486a957f6fSShawn McCarney }
5496a957f6fSShawn McCarney )"_json;
5506a957f6fSShawn McCarney parseRail(element);
5516a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
5526a957f6fSShawn McCarney }
5536a957f6fSShawn McCarney catch (const std::invalid_argument& e)
5546a957f6fSShawn McCarney {
5556a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: name");
5566a957f6fSShawn McCarney }
5576a957f6fSShawn McCarney
5586a957f6fSShawn McCarney // Test where fails: name value is invalid
5596a957f6fSShawn McCarney try
5606a957f6fSShawn McCarney {
5616a957f6fSShawn McCarney const json element = R"(
5626a957f6fSShawn McCarney {
5636a957f6fSShawn McCarney "name": 31,
5646a957f6fSShawn McCarney "page": 11
5656a957f6fSShawn McCarney }
5666a957f6fSShawn McCarney )"_json;
5676a957f6fSShawn McCarney parseRail(element);
5686a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
5696a957f6fSShawn McCarney }
5706a957f6fSShawn McCarney catch (const std::invalid_argument& e)
5716a957f6fSShawn McCarney {
5726a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a string");
5736a957f6fSShawn McCarney }
5746a957f6fSShawn McCarney
5756a957f6fSShawn McCarney // Test where fails: presence value is invalid
5766a957f6fSShawn McCarney try
5776a957f6fSShawn McCarney {
5786a957f6fSShawn McCarney const json element = R"(
5796a957f6fSShawn McCarney {
5806a957f6fSShawn McCarney "name": "VCS_CPU1",
5816a957f6fSShawn McCarney "presence": false
5826a957f6fSShawn McCarney }
5836a957f6fSShawn McCarney )"_json;
5846a957f6fSShawn McCarney parseRail(element);
5856a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
5866a957f6fSShawn McCarney }
5876a957f6fSShawn McCarney catch (const std::invalid_argument& e)
5886a957f6fSShawn McCarney {
5896a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a string");
5906a957f6fSShawn McCarney }
5916a957f6fSShawn McCarney
5926a957f6fSShawn McCarney // Test where fails: page value is invalid
5936a957f6fSShawn McCarney try
5946a957f6fSShawn McCarney {
5956a957f6fSShawn McCarney const json element = R"(
5966a957f6fSShawn McCarney {
5976a957f6fSShawn McCarney "name": "VCS_CPU1",
5986a957f6fSShawn McCarney "page": 256
5996a957f6fSShawn McCarney }
6006a957f6fSShawn McCarney )"_json;
6016a957f6fSShawn McCarney parseRail(element);
6026a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
6036a957f6fSShawn McCarney }
6046a957f6fSShawn McCarney catch (const std::invalid_argument& e)
6056a957f6fSShawn McCarney {
6066a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
6076a957f6fSShawn McCarney }
6086a957f6fSShawn McCarney
60916e493afSShawn McCarney // Test where fails: is_power_supply_rail value is invalid
61016e493afSShawn McCarney try
61116e493afSShawn McCarney {
61216e493afSShawn McCarney const json element = R"(
61316e493afSShawn McCarney {
61416e493afSShawn McCarney "name": "12.0VA",
61516e493afSShawn McCarney "is_power_supply_rail": "true"
61616e493afSShawn McCarney }
61716e493afSShawn McCarney )"_json;
61816e493afSShawn McCarney parseRail(element);
61916e493afSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
62016e493afSShawn McCarney }
62116e493afSShawn McCarney catch (const std::invalid_argument& e)
62216e493afSShawn McCarney {
62316e493afSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a boolean");
62416e493afSShawn McCarney }
62516e493afSShawn McCarney
6266a957f6fSShawn McCarney // Test where fails: check_status_vout value is invalid
6276a957f6fSShawn McCarney try
6286a957f6fSShawn McCarney {
6296a957f6fSShawn McCarney const json element = R"(
6306a957f6fSShawn McCarney {
6316a957f6fSShawn McCarney "name": "VCS_CPU1",
6326a957f6fSShawn McCarney "check_status_vout": "false"
6336a957f6fSShawn McCarney }
6346a957f6fSShawn McCarney )"_json;
6356a957f6fSShawn McCarney parseRail(element);
6366a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
6376a957f6fSShawn McCarney }
6386a957f6fSShawn McCarney catch (const std::invalid_argument& e)
6396a957f6fSShawn McCarney {
6406a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a boolean");
6416a957f6fSShawn McCarney }
6426a957f6fSShawn McCarney
6439ec0d43dSShawn McCarney // Test where fails: compare_voltage_to_limit value is invalid
6446a957f6fSShawn McCarney try
6456a957f6fSShawn McCarney {
6466a957f6fSShawn McCarney const json element = R"(
6476a957f6fSShawn McCarney {
6486a957f6fSShawn McCarney "name": "VCS_CPU1",
6499ec0d43dSShawn McCarney "compare_voltage_to_limit": 23
6506a957f6fSShawn McCarney }
6516a957f6fSShawn McCarney )"_json;
6526a957f6fSShawn McCarney parseRail(element);
6536a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
6546a957f6fSShawn McCarney }
6556a957f6fSShawn McCarney catch (const std::invalid_argument& e)
6566a957f6fSShawn McCarney {
6576a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a boolean");
6586a957f6fSShawn McCarney }
6596a957f6fSShawn McCarney
6606a957f6fSShawn McCarney // Test where fails: gpio value is invalid
6616a957f6fSShawn McCarney try
6626a957f6fSShawn McCarney {
6636a957f6fSShawn McCarney const json element = R"(
6646a957f6fSShawn McCarney {
6656a957f6fSShawn McCarney "name": "VCS_CPU1",
6666a957f6fSShawn McCarney "gpio": 131
6676a957f6fSShawn McCarney }
6686a957f6fSShawn McCarney )"_json;
6696a957f6fSShawn McCarney parseRail(element);
6706a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
6716a957f6fSShawn McCarney }
6726a957f6fSShawn McCarney catch (const std::invalid_argument& e)
6736a957f6fSShawn McCarney {
6746a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object");
6756a957f6fSShawn McCarney }
6766a957f6fSShawn McCarney
6776a957f6fSShawn McCarney // Test where fails: check_status_vout is true and page not specified
6786a957f6fSShawn McCarney try
6796a957f6fSShawn McCarney {
6806a957f6fSShawn McCarney const json element = R"(
6816a957f6fSShawn McCarney {
6826a957f6fSShawn McCarney "name": "VCS_CPU1",
6836a957f6fSShawn McCarney "check_status_vout": true
6846a957f6fSShawn McCarney }
6856a957f6fSShawn McCarney )"_json;
6866a957f6fSShawn McCarney parseRail(element);
6876a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
6886a957f6fSShawn McCarney }
6896a957f6fSShawn McCarney catch (const std::invalid_argument& e)
6906a957f6fSShawn McCarney {
6916a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: page");
6926a957f6fSShawn McCarney }
6936a957f6fSShawn McCarney
6949ec0d43dSShawn McCarney // Test where fails: compare_voltage_to_limit is true and page not
6956a957f6fSShawn McCarney // specified
6966a957f6fSShawn McCarney try
6976a957f6fSShawn McCarney {
6986a957f6fSShawn McCarney const json element = R"(
6996a957f6fSShawn McCarney {
7006a957f6fSShawn McCarney "name": "VCS_CPU1",
7019ec0d43dSShawn McCarney "compare_voltage_to_limit": true
7026a957f6fSShawn McCarney }
7036a957f6fSShawn McCarney )"_json;
7046a957f6fSShawn McCarney parseRail(element);
7056a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
7066a957f6fSShawn McCarney }
7076a957f6fSShawn McCarney catch (const std::invalid_argument& e)
7086a957f6fSShawn McCarney {
7096a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: page");
7106a957f6fSShawn McCarney }
7116a957f6fSShawn McCarney
7126a957f6fSShawn McCarney // Test where fails: Invalid property specified
7136a957f6fSShawn McCarney try
7146a957f6fSShawn McCarney {
7156a957f6fSShawn McCarney const json element = R"(
7166a957f6fSShawn McCarney {
7176a957f6fSShawn McCarney "name": "VCS_CPU1",
7186a957f6fSShawn McCarney "foo": "bar"
7196a957f6fSShawn McCarney }
7206a957f6fSShawn McCarney )"_json;
7216a957f6fSShawn McCarney parseRail(element);
7226a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
7236a957f6fSShawn McCarney }
7246a957f6fSShawn McCarney catch (const std::invalid_argument& e)
7256a957f6fSShawn McCarney {
7266a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property");
7276a957f6fSShawn McCarney }
7286a957f6fSShawn McCarney }
7296a957f6fSShawn McCarney
TEST(ConfigFileParserTests,ParseRailArray)7306a957f6fSShawn McCarney TEST(ConfigFileParserTests, ParseRailArray)
7316a957f6fSShawn McCarney {
7326a957f6fSShawn McCarney // Test where works: Array is empty
7336a957f6fSShawn McCarney {
7346a957f6fSShawn McCarney const json element = R"(
7356a957f6fSShawn McCarney [
7366a957f6fSShawn McCarney ]
7376a957f6fSShawn McCarney )"_json;
7386a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
7396a957f6fSShawn McCarney EXPECT_EQ(rails.size(), 0);
7406a957f6fSShawn McCarney }
7416a957f6fSShawn McCarney
7426a957f6fSShawn McCarney // Test where works: Array is not empty
7436a957f6fSShawn McCarney {
7446a957f6fSShawn McCarney const json element = R"(
7456a957f6fSShawn McCarney [
7466a957f6fSShawn McCarney { "name": "VDD_CPU0" },
7476a957f6fSShawn McCarney { "name": "VCS_CPU1" }
7486a957f6fSShawn McCarney ]
7496a957f6fSShawn McCarney )"_json;
7506a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> rails = parseRailArray(element);
7516a957f6fSShawn McCarney EXPECT_EQ(rails.size(), 2);
7526a957f6fSShawn McCarney EXPECT_EQ(rails[0]->getName(), "VDD_CPU0");
7536a957f6fSShawn McCarney EXPECT_EQ(rails[1]->getName(), "VCS_CPU1");
7546a957f6fSShawn McCarney }
7556a957f6fSShawn McCarney
7566a957f6fSShawn McCarney // Test where fails: Element is not an array
7576a957f6fSShawn McCarney try
7586a957f6fSShawn McCarney {
7596a957f6fSShawn McCarney const json element = R"(
7606a957f6fSShawn McCarney {
7616a957f6fSShawn McCarney "foo": "bar"
7626a957f6fSShawn McCarney }
7636a957f6fSShawn McCarney )"_json;
7646a957f6fSShawn McCarney parseRailArray(element);
7656a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
7666a957f6fSShawn McCarney }
7676a957f6fSShawn McCarney catch (const std::invalid_argument& e)
7686a957f6fSShawn McCarney {
7696a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an array");
7706a957f6fSShawn McCarney }
7716a957f6fSShawn McCarney
7726a957f6fSShawn McCarney // Test where fails: Element within array is invalid
7736a957f6fSShawn McCarney try
7746a957f6fSShawn McCarney {
7756a957f6fSShawn McCarney const json element = R"(
7766a957f6fSShawn McCarney [
7776a957f6fSShawn McCarney { "name": "VDD_CPU0" },
7786a957f6fSShawn McCarney 23
7796a957f6fSShawn McCarney ]
7806a957f6fSShawn McCarney )"_json;
7816a957f6fSShawn McCarney parseRailArray(element);
7826a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
7836a957f6fSShawn McCarney }
7846a957f6fSShawn McCarney catch (const std::invalid_argument& e)
7856a957f6fSShawn McCarney {
7866a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object");
7876a957f6fSShawn McCarney }
7886a957f6fSShawn McCarney }
7896a957f6fSShawn McCarney
TEST(ConfigFileParserTests,ParseRoot)7906a957f6fSShawn McCarney TEST(ConfigFileParserTests, ParseRoot)
7916a957f6fSShawn McCarney {
7926a957f6fSShawn McCarney // Test where works
7936a957f6fSShawn McCarney {
7946a957f6fSShawn McCarney const json element = R"(
7956a957f6fSShawn McCarney {
7966a957f6fSShawn McCarney "rails": [
7976a957f6fSShawn McCarney {
7986a957f6fSShawn McCarney "name": "VDD_CPU0",
7996a957f6fSShawn McCarney "page": 11,
8006a957f6fSShawn McCarney "check_status_vout": true
8016a957f6fSShawn McCarney },
8026a957f6fSShawn McCarney {
8036a957f6fSShawn McCarney "name": "VCS_CPU1",
8046a957f6fSShawn McCarney "presence": "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1",
8056a957f6fSShawn McCarney "gpio": { "line": 60 }
8066a957f6fSShawn McCarney }
8076a957f6fSShawn McCarney ]
8086a957f6fSShawn McCarney }
8096a957f6fSShawn McCarney )"_json;
8106a957f6fSShawn McCarney std::vector<std::unique_ptr<Rail>> rails = parseRoot(element);
8116a957f6fSShawn McCarney EXPECT_EQ(rails.size(), 2);
8126a957f6fSShawn McCarney EXPECT_EQ(rails[0]->getName(), "VDD_CPU0");
8136a957f6fSShawn McCarney EXPECT_EQ(rails[1]->getName(), "VCS_CPU1");
8146a957f6fSShawn McCarney }
8156a957f6fSShawn McCarney
8166a957f6fSShawn McCarney // Test where fails: Element is not an object
8176a957f6fSShawn McCarney try
8186a957f6fSShawn McCarney {
8196a957f6fSShawn McCarney const json element = R"( [ "VDD_CPU0", "VCS_CPU1" ] )"_json;
8206a957f6fSShawn McCarney parseRoot(element);
8216a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
8226a957f6fSShawn McCarney }
8236a957f6fSShawn McCarney catch (const std::invalid_argument& e)
8246a957f6fSShawn McCarney {
8256a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object");
8266a957f6fSShawn McCarney }
8276a957f6fSShawn McCarney
8286a957f6fSShawn McCarney // Test where fails: Required rails property not specified
8296a957f6fSShawn McCarney try
8306a957f6fSShawn McCarney {
8316a957f6fSShawn McCarney const json element = R"(
8326a957f6fSShawn McCarney {
8336a957f6fSShawn McCarney }
8346a957f6fSShawn McCarney )"_json;
8356a957f6fSShawn McCarney parseRoot(element);
8366a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
8376a957f6fSShawn McCarney }
8386a957f6fSShawn McCarney catch (const std::invalid_argument& e)
8396a957f6fSShawn McCarney {
8406a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Required property missing: rails");
8416a957f6fSShawn McCarney }
8426a957f6fSShawn McCarney
8436a957f6fSShawn McCarney // Test where fails: rails value is invalid
8446a957f6fSShawn McCarney try
8456a957f6fSShawn McCarney {
8466a957f6fSShawn McCarney const json element = R"(
8476a957f6fSShawn McCarney {
8486a957f6fSShawn McCarney "rails": 31
8496a957f6fSShawn McCarney }
8506a957f6fSShawn McCarney )"_json;
8516a957f6fSShawn McCarney parseRoot(element);
8526a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
8536a957f6fSShawn McCarney }
8546a957f6fSShawn McCarney catch (const std::invalid_argument& e)
8556a957f6fSShawn McCarney {
8566a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an array");
8576a957f6fSShawn McCarney }
8586a957f6fSShawn McCarney
8596a957f6fSShawn McCarney // Test where fails: Invalid property specified
8606a957f6fSShawn McCarney try
8616a957f6fSShawn McCarney {
8626a957f6fSShawn McCarney const json element = R"(
8636a957f6fSShawn McCarney {
8646a957f6fSShawn McCarney "rails": [
8656a957f6fSShawn McCarney {
8666a957f6fSShawn McCarney "name": "VDD_CPU0",
8676a957f6fSShawn McCarney "page": 11,
8686a957f6fSShawn McCarney "check_status_vout": true
8696a957f6fSShawn McCarney }
8706a957f6fSShawn McCarney ],
8716a957f6fSShawn McCarney "foo": true
8726a957f6fSShawn McCarney }
8736a957f6fSShawn McCarney )"_json;
8746a957f6fSShawn McCarney parseRoot(element);
8756a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
8766a957f6fSShawn McCarney }
8776a957f6fSShawn McCarney catch (const std::invalid_argument& e)
8786a957f6fSShawn McCarney {
8796a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property");
8806a957f6fSShawn McCarney }
8816a957f6fSShawn McCarney }
8826a957f6fSShawn McCarney
TEST(ConfigFileParserTests,ParseString)8836a957f6fSShawn McCarney TEST(ConfigFileParserTests, ParseString)
8846a957f6fSShawn McCarney {
8856a957f6fSShawn McCarney // Test where works: Empty string
8866a957f6fSShawn McCarney {
8876a957f6fSShawn McCarney const json element = "";
8886a957f6fSShawn McCarney std::string value = parseString(element, true);
8896a957f6fSShawn McCarney EXPECT_EQ(value, "");
8906a957f6fSShawn McCarney }
8916a957f6fSShawn McCarney
8926a957f6fSShawn McCarney // Test where works: Non-empty string
8936a957f6fSShawn McCarney {
8946a957f6fSShawn McCarney const json element = "vdd_cpu1";
8956a957f6fSShawn McCarney std::string value = parseString(element, false);
8966a957f6fSShawn McCarney EXPECT_EQ(value, "vdd_cpu1");
8976a957f6fSShawn McCarney }
8986a957f6fSShawn McCarney
8996a957f6fSShawn McCarney // Test where fails: Element is not a string
9006a957f6fSShawn McCarney try
9016a957f6fSShawn McCarney {
9026a957f6fSShawn McCarney const json element = R"( { "foo": "bar" } )"_json;
9036a957f6fSShawn McCarney parseString(element);
9046a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
9056a957f6fSShawn McCarney }
9066a957f6fSShawn McCarney catch (const std::invalid_argument& e)
9076a957f6fSShawn McCarney {
9086a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not a string");
9096a957f6fSShawn McCarney }
9106a957f6fSShawn McCarney
9116a957f6fSShawn McCarney // Test where fails: Empty string
9126a957f6fSShawn McCarney try
9136a957f6fSShawn McCarney {
9146a957f6fSShawn McCarney const json element = "";
9156a957f6fSShawn McCarney parseString(element);
9166a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
9176a957f6fSShawn McCarney }
9186a957f6fSShawn McCarney catch (const std::invalid_argument& e)
9196a957f6fSShawn McCarney {
9206a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an empty string");
9216a957f6fSShawn McCarney }
9226a957f6fSShawn McCarney }
9236a957f6fSShawn McCarney
TEST(ConfigFileParserTests,ParseUint8)9246a957f6fSShawn McCarney TEST(ConfigFileParserTests, ParseUint8)
9256a957f6fSShawn McCarney {
9266a957f6fSShawn McCarney // Test where works: 0
9276a957f6fSShawn McCarney {
9286a957f6fSShawn McCarney const json element = R"( 0 )"_json;
9296a957f6fSShawn McCarney uint8_t value = parseUint8(element);
9306a957f6fSShawn McCarney EXPECT_EQ(value, 0);
9316a957f6fSShawn McCarney }
9326a957f6fSShawn McCarney
9336a957f6fSShawn McCarney // Test where works: UINT8_MAX
9346a957f6fSShawn McCarney {
9356a957f6fSShawn McCarney const json element = R"( 255 )"_json;
9366a957f6fSShawn McCarney uint8_t value = parseUint8(element);
9376a957f6fSShawn McCarney EXPECT_EQ(value, 255);
9386a957f6fSShawn McCarney }
9396a957f6fSShawn McCarney
9406a957f6fSShawn McCarney // Test where fails: Element is not an integer
9416a957f6fSShawn McCarney try
9426a957f6fSShawn McCarney {
9436a957f6fSShawn McCarney const json element = R"( 1.03 )"_json;
9446a957f6fSShawn McCarney parseUint8(element);
9456a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
9466a957f6fSShawn McCarney }
9476a957f6fSShawn McCarney catch (const std::invalid_argument& e)
9486a957f6fSShawn McCarney {
9496a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an integer");
9506a957f6fSShawn McCarney }
9516a957f6fSShawn McCarney
9526a957f6fSShawn McCarney // Test where fails: Value < 0
9536a957f6fSShawn McCarney try
9546a957f6fSShawn McCarney {
9556a957f6fSShawn McCarney const json element = R"( -1 )"_json;
9566a957f6fSShawn McCarney parseUint8(element);
9576a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
9586a957f6fSShawn McCarney }
9596a957f6fSShawn McCarney catch (const std::invalid_argument& e)
9606a957f6fSShawn McCarney {
9616a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
9626a957f6fSShawn McCarney }
9636a957f6fSShawn McCarney
9646a957f6fSShawn McCarney // Test where fails: Value > UINT8_MAX
9656a957f6fSShawn McCarney try
9666a957f6fSShawn McCarney {
9676a957f6fSShawn McCarney const json element = R"( 256 )"_json;
9686a957f6fSShawn McCarney parseUint8(element);
9696a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
9706a957f6fSShawn McCarney }
9716a957f6fSShawn McCarney catch (const std::invalid_argument& e)
9726a957f6fSShawn McCarney {
9736a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an 8-bit unsigned integer");
9746a957f6fSShawn McCarney }
9756a957f6fSShawn McCarney }
9766a957f6fSShawn McCarney
TEST(ConfigFileParserTests,ParseUnsignedInteger)9776a957f6fSShawn McCarney TEST(ConfigFileParserTests, ParseUnsignedInteger)
9786a957f6fSShawn McCarney {
9796a957f6fSShawn McCarney // Test where works: 1
9806a957f6fSShawn McCarney {
9816a957f6fSShawn McCarney const json element = R"( 1 )"_json;
9826a957f6fSShawn McCarney unsigned int value = parseUnsignedInteger(element);
9836a957f6fSShawn McCarney EXPECT_EQ(value, 1);
9846a957f6fSShawn McCarney }
9856a957f6fSShawn McCarney
9866a957f6fSShawn McCarney // Test where fails: Element is not an integer
9876a957f6fSShawn McCarney try
9886a957f6fSShawn McCarney {
9896a957f6fSShawn McCarney const json element = R"( 1.5 )"_json;
9906a957f6fSShawn McCarney parseUnsignedInteger(element);
9916a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
9926a957f6fSShawn McCarney }
9936a957f6fSShawn McCarney catch (const std::invalid_argument& e)
9946a957f6fSShawn McCarney {
9956a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
9966a957f6fSShawn McCarney }
9976a957f6fSShawn McCarney
9986a957f6fSShawn McCarney // Test where fails: Value < 0
9996a957f6fSShawn McCarney try
10006a957f6fSShawn McCarney {
10016a957f6fSShawn McCarney const json element = R"( -1 )"_json;
10026a957f6fSShawn McCarney parseUnsignedInteger(element);
10036a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
10046a957f6fSShawn McCarney }
10056a957f6fSShawn McCarney catch (const std::invalid_argument& e)
10066a957f6fSShawn McCarney {
10076a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an unsigned integer");
10086a957f6fSShawn McCarney }
10096a957f6fSShawn McCarney }
10106a957f6fSShawn McCarney
TEST(ConfigFileParserTests,VerifyIsArray)10116a957f6fSShawn McCarney TEST(ConfigFileParserTests, VerifyIsArray)
10126a957f6fSShawn McCarney {
10136a957f6fSShawn McCarney // Test where element is an array
10146a957f6fSShawn McCarney {
10156a957f6fSShawn McCarney const json element = R"( [ "foo", "bar" ] )"_json;
10166a957f6fSShawn McCarney verifyIsArray(element);
10176a957f6fSShawn McCarney }
10186a957f6fSShawn McCarney
10196a957f6fSShawn McCarney // Test where element is not an array
10206a957f6fSShawn McCarney try
10216a957f6fSShawn McCarney {
10226a957f6fSShawn McCarney const json element = R"( { "foo": "bar" } )"_json;
10236a957f6fSShawn McCarney verifyIsArray(element);
10246a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
10256a957f6fSShawn McCarney }
10266a957f6fSShawn McCarney catch (const std::invalid_argument& e)
10276a957f6fSShawn McCarney {
10286a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an array");
10296a957f6fSShawn McCarney }
10306a957f6fSShawn McCarney }
10316a957f6fSShawn McCarney
TEST(ConfigFileParserTests,VerifyIsObject)10326a957f6fSShawn McCarney TEST(ConfigFileParserTests, VerifyIsObject)
10336a957f6fSShawn McCarney {
10346a957f6fSShawn McCarney // Test where element is an object
10356a957f6fSShawn McCarney {
10366a957f6fSShawn McCarney const json element = R"( { "foo": "bar" } )"_json;
10376a957f6fSShawn McCarney verifyIsObject(element);
10386a957f6fSShawn McCarney }
10396a957f6fSShawn McCarney
10406a957f6fSShawn McCarney // Test where element is not an object
10416a957f6fSShawn McCarney try
10426a957f6fSShawn McCarney {
10436a957f6fSShawn McCarney const json element = R"( [ "foo", "bar" ] )"_json;
10446a957f6fSShawn McCarney verifyIsObject(element);
10456a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
10466a957f6fSShawn McCarney }
10476a957f6fSShawn McCarney catch (const std::invalid_argument& e)
10486a957f6fSShawn McCarney {
10496a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element is not an object");
10506a957f6fSShawn McCarney }
10516a957f6fSShawn McCarney }
10526a957f6fSShawn McCarney
TEST(ConfigFileParserTests,VerifyPropertyCount)10536a957f6fSShawn McCarney TEST(ConfigFileParserTests, VerifyPropertyCount)
10546a957f6fSShawn McCarney {
10556a957f6fSShawn McCarney // Test where element has expected number of properties
10566a957f6fSShawn McCarney {
10576a957f6fSShawn McCarney const json element = R"(
10586a957f6fSShawn McCarney {
10596a957f6fSShawn McCarney "line": 131,
10606a957f6fSShawn McCarney "active_low": true
10616a957f6fSShawn McCarney }
10626a957f6fSShawn McCarney )"_json;
10636a957f6fSShawn McCarney verifyPropertyCount(element, 2);
10646a957f6fSShawn McCarney }
10656a957f6fSShawn McCarney
10666a957f6fSShawn McCarney // Test where element has unexpected number of properties
10676a957f6fSShawn McCarney try
10686a957f6fSShawn McCarney {
10696a957f6fSShawn McCarney const json element = R"(
10706a957f6fSShawn McCarney {
10716a957f6fSShawn McCarney "line": 131,
10726a957f6fSShawn McCarney "active_low": true,
10736a957f6fSShawn McCarney "foo": 1.3
10746a957f6fSShawn McCarney }
10756a957f6fSShawn McCarney )"_json;
10766a957f6fSShawn McCarney verifyPropertyCount(element, 2);
10776a957f6fSShawn McCarney ADD_FAILURE() << "Should not have reached this line.";
10786a957f6fSShawn McCarney }
10796a957f6fSShawn McCarney catch (const std::invalid_argument& e)
10806a957f6fSShawn McCarney {
10816a957f6fSShawn McCarney EXPECT_STREQ(e.what(), "Element contains an invalid property");
10826a957f6fSShawn McCarney }
10836a957f6fSShawn McCarney }
1084