1 /**
2  * Copyright c 2020 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "temporary_file.hpp"
17 
18 #include <stdio.h>    // for popen(), pclose(), fgets()
19 #include <sys/stat.h> // for chmod()
20 #include <sys/wait.h> // for WEXITSTATUS
21 
22 #include <nlohmann/json.hpp>
23 
24 #include <cstdio>
25 #include <fstream>
26 
27 #include <gtest/gtest.h>
28 
29 #define EXPECT_FILE_VALID(configFile) expectFileValid(configFile)
30 #define EXPECT_FILE_INVALID(configFile, expectedErrorMessage,                  \
31                             expectedOutputMessage)                             \
32     expectFileInvalid(configFile, expectedErrorMessage, expectedOutputMessage)
33 #define EXPECT_JSON_VALID(configFileJson) expectJsonValid(configFileJson)
34 #define EXPECT_JSON_INVALID(configFileJson, expectedErrorMessage,              \
35                             expectedOutputMessage)                             \
36     expectJsonInvalid(configFileJson, expectedErrorMessage,                    \
37                       expectedOutputMessage)
38 
39 using namespace phosphor::power::regulators;
40 using json = nlohmann::json;
41 
42 const json validConfigFile = R"(
43     {
44       "comments": [ "Config file for a FooBar one-chassis system" ],
45 
46       "rules": [
47         {
48           "comments": [ "Sets output voltage for a PMBus regulator rail" ],
49           "id": "set_voltage_rule",
50           "actions": [
51             {
52               "pmbus_write_vout_command": {
53                 "format": "linear"
54               }
55             }
56           ]
57         },
58         {
59           "comments": [ "Reads sensors from a PMBus regulator rail" ],
60           "id": "read_sensors_rule",
61           "actions": [
62             {
63               "comments": [ "Read output voltage from READ_VOUT." ],
64               "pmbus_read_sensor": {
65                 "type": "vout",
66                 "command": "0x8B",
67                 "format": "linear_16"
68               }
69             }
70           ]
71         }
72       ],
73 
74       "chassis": [
75         {
76           "comments": [ "Chassis number 1 containing CPUs and memory" ],
77           "number": 1,
78           "devices": [
79             {
80               "comments": [ "IR35221 regulator producing the Vdd rail" ],
81               "id": "vdd_regulator",
82               "is_regulator": true,
83               "fru": "system/chassis/motherboard/regulator1",
84               "i2c_interface": {
85                 "bus": 1,
86                 "address": "0x70"
87               },
88               "rails": [
89                 {
90                   "comments": [ "Vdd rail" ],
91                   "id": "vdd",
92                   "configuration": {
93                     "volts": 1.03,
94                     "rule_id": "set_voltage_rule"
95                   },
96                   "sensor_monitoring": {
97                     "rule_id": "read_sensors_rule"
98                   }
99                 }
100               ]
101             }
102           ]
103         }
104       ]
105     }
106 )"_json;
107 
108 std::string getValidationToolCommand(const std::string& configFileName)
109 {
110     std::string command =
111         "../phosphor-regulators/tools/validate-regulators-config.py -s \
112          ../phosphor-regulators/schema/config_schema.json -c ";
113     command += configFileName;
114     return command;
115 }
116 
117 int runToolForOutputWithCommand(std::string command,
118                                 std::string& standardOutput,
119                                 std::string& standardError)
120 {
121     // run the validation tool with the temporary file and return the output
122     // of the validation tool.
123     TemporaryFile tmpFile;
124     command += " 2> " + tmpFile.getPath().string();
125     // get the jsonschema print from validation tool.
126     char buffer[256];
127     std::string result;
128     // to get the stdout from the validation tool.
129     FILE* pipe = popen(command.c_str(), "r");
130     if (!pipe)
131     {
132         throw std::runtime_error("popen() failed!");
133     }
134     while (!std::feof(pipe))
135     {
136         if (fgets(buffer, sizeof buffer, pipe) != NULL)
137         {
138             result += buffer;
139         }
140     }
141     int returnValue = pclose(pipe);
142     // Check if pclose() failed
143     if (returnValue == -1)
144     {
145         // unable to close pipe.  Print error and exit function.
146         throw std::runtime_error("pclose() failed!");
147     }
148     std::string firstLine = result.substr(0, result.find('\n'));
149     standardOutput = firstLine;
150     // Get command exit status from return value
151     int exitStatus = WEXITSTATUS(returnValue);
152 
153     // Read the standardError from tmpFile.
154     std::ifstream input(tmpFile.getPath());
155     std::string line;
156 
157     if (std::getline(input, line))
158     {
159         standardError = line;
160     }
161 
162     return exitStatus;
163 }
164 
165 int runToolForOutput(const std::string& configFileName, std::string& output,
166                      std::string& error)
167 {
168     std::string command = getValidationToolCommand(configFileName);
169     return runToolForOutputWithCommand(command, output, error);
170 }
171 
172 void expectFileValid(const std::string& configFileName)
173 {
174     std::string errorMessage;
175     std::string outputMessage;
176     EXPECT_EQ(runToolForOutput(configFileName, outputMessage, errorMessage), 0);
177     EXPECT_EQ(errorMessage, "");
178     EXPECT_EQ(outputMessage, "");
179 }
180 
181 void expectFileInvalid(const std::string& configFileName,
182                        const std::string& expectedErrorMessage,
183                        const std::string& expectedOutputMessage)
184 {
185     std::string errorMessage;
186     std::string outputMessage;
187     EXPECT_EQ(runToolForOutput(configFileName, outputMessage, errorMessage), 1);
188     EXPECT_EQ(errorMessage, expectedErrorMessage);
189     EXPECT_EQ(outputMessage, expectedOutputMessage);
190 }
191 
192 void writeDataToFile(const json configFileJson, std::string fileName)
193 {
194     std::string jsonData = configFileJson.dump();
195     std::ofstream out(fileName);
196     out << jsonData;
197     out.close();
198 }
199 
200 void expectJsonValid(const json configFileJson)
201 {
202     TemporaryFile tmpFile;
203     std::string fileName = tmpFile.getPath().string();
204     writeDataToFile(configFileJson, fileName);
205 
206     EXPECT_FILE_VALID(fileName);
207 }
208 
209 void expectJsonInvalid(const json configFileJson,
210                        const std::string& expectedErrorMessage,
211                        const std::string& expectedOutputMessage)
212 {
213     TemporaryFile tmpFile;
214     std::string fileName = tmpFile.getPath().string();
215     writeDataToFile(configFileJson, fileName);
216 
217     EXPECT_FILE_INVALID(fileName, expectedErrorMessage, expectedOutputMessage);
218 }
219 
220 void expectCommandLineSyntax(const std::string& expectedErrorMessage,
221                              const std::string& expectedOutputMessage,
222                              const std::string& command, int status)
223 {
224     std::string errorMessage;
225     std::string outputMessage;
226     EXPECT_EQ(runToolForOutputWithCommand(command, outputMessage, errorMessage),
227               status);
228     EXPECT_EQ(errorMessage, expectedErrorMessage);
229     EXPECT_EQ(outputMessage, expectedOutputMessage);
230 }
231 
232 TEST(ValidateRegulatorsConfigTest, Action)
233 {
234     // Valid: Comments property not specified
235     {
236         json configFile = validConfigFile;
237         EXPECT_JSON_VALID(configFile);
238     }
239     // Valid: Comments property specified
240     {
241         json configFile = validConfigFile;
242         configFile["rules"][0]["actions"][0]["comments"][0] =
243             "Set VOUT_COMMAND";
244         EXPECT_JSON_VALID(configFile);
245     }
246     // Valid: and action type specified
247     {
248         json configFile = validConfigFile;
249         json andAction =
250             R"(
251                 {
252                  "and": [
253                     { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
254                     { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
255                   ]
256                 }
257             )"_json;
258         configFile["rules"][0]["actions"].push_back(andAction);
259         EXPECT_JSON_VALID(configFile);
260     }
261     // Valid: compare_presence action type specified
262     {
263         json configFile = validConfigFile;
264         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] =
265             "system/chassis/motherboard/regulator2";
266         configFile["rules"][0]["actions"][1]["compare_presence"]["value"] =
267             true;
268         EXPECT_JSON_VALID(configFile);
269     }
270     // Valid: compare_vpd action type specified
271     {
272         json configFile = validConfigFile;
273         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] =
274             "system/chassis/motherboard/regulator2";
275         configFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] = "CCIN";
276         configFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = "2D35";
277         EXPECT_JSON_VALID(configFile);
278     }
279     // Valid: i2c_compare_bit action type specified
280     {
281         json configFile = validConfigFile;
282         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
283             "0xA0";
284         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] = 3;
285         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 1;
286         EXPECT_JSON_VALID(configFile);
287     }
288     // Valid: i2c_compare_byte action type specified
289     {
290         json configFile = validConfigFile;
291         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
292             "0x82";
293         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
294             "0x40";
295         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
296             "0x7F";
297         EXPECT_JSON_VALID(configFile);
298     }
299     // Valid: i2c_compare_bytes action type specified
300     {
301         json configFile = validConfigFile;
302         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
303             "0x82";
304         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = {
305             "0x02", "0x73"};
306         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = {
307             "0x7F", "0x7F"};
308         EXPECT_JSON_VALID(configFile);
309     }
310     // Valid: i2c_write_bit action type specified
311     {
312         json configFile = validConfigFile;
313         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] =
314             "0xA0";
315         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 3;
316         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = 1;
317         EXPECT_JSON_VALID(configFile);
318     }
319     // Valid: i2c_write_byte action type specified
320     {
321         json configFile = validConfigFile;
322         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
323             "0x82";
324         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
325             "0x40";
326         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "0x7F";
327         EXPECT_JSON_VALID(configFile);
328     }
329     // Valid: i2c_write_bytes action type specified
330     {
331         json configFile = validConfigFile;
332         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
333             "0x82";
334         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
335             "0x02", "0x73"};
336         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
337             "0x7F", "0x7F"};
338         EXPECT_JSON_VALID(configFile);
339     }
340     // Valid: if action type specified
341     {
342         json configFile = validConfigFile;
343         configFile["rules"][2]["actions"][0]["if"]["condition"]["run_rule"] =
344             "set_voltage_rule";
345         configFile["rules"][2]["actions"][0]["if"]["then"][0]["run_rule"] =
346             "read_sensors_rule";
347         configFile["rules"][2]["actions"][0]["if"]["else"][0]["run_rule"] =
348             "read_sensors_rule";
349         configFile["rules"][2]["id"] = "rule_if";
350         EXPECT_JSON_VALID(configFile);
351     }
352     // Valid: not action type specified
353     {
354         json configFile = validConfigFile;
355         configFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]
356                   ["register"] = "0xA0";
357         configFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]
358                   ["value"] = "0xFF";
359         EXPECT_JSON_VALID(configFile);
360     }
361     // Valid: or action type specified
362     {
363         json configFile = validConfigFile;
364         configFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]
365                   ["register"] = "0xA0";
366         configFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]
367                   ["value"] = "0x00";
368         configFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]
369                   ["register"] = "0xA1";
370         configFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]
371                   ["value"] = "0x00";
372         EXPECT_JSON_VALID(configFile);
373     }
374     // Valid: pmbus_read_sensor and pmbus_write_vout_command action type
375     // specified
376     {
377         EXPECT_JSON_VALID(validConfigFile);
378     }
379     // Valid: run_rule action type specified
380     {
381         json configFile = validConfigFile;
382         configFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
383         EXPECT_JSON_VALID(configFile);
384     }
385     // Valid: set_device action type specified
386     {
387         json configFile = validConfigFile;
388         configFile["rules"][0]["actions"][1]["set_device"] = "vdd_regulator";
389         EXPECT_JSON_VALID(configFile);
390     }
391     // Invalid: Wrong data type for comments (should be array of string)
392     {
393         json configFile = validConfigFile;
394         configFile["rules"][0]["actions"][0]["comments"] = true;
395         EXPECT_JSON_INVALID(configFile, "Validation failed.",
396                             "True is not of type 'array'");
397     }
398     // Invalid: Wrong data type for action type (such as "i2c_write_byte": true)
399     {
400         json configFile = validConfigFile;
401         configFile["rules"][0]["actions"][1]["i2c_write_byte"] = true;
402         EXPECT_JSON_INVALID(configFile, "Validation failed.",
403                             "True is not of type 'object'");
404     }
405     // Invalid: Empty comments array
406     {
407         json configFile = validConfigFile;
408         configFile["rules"][0]["actions"][0]["comments"] = json::array();
409         EXPECT_JSON_INVALID(configFile, "Validation failed.",
410                             "[] is too short");
411     }
412     // Invalid: Comments array has wrong element type (should be string)
413     {
414         json configFile = validConfigFile;
415         configFile["rules"][0]["actions"][0]["comments"][0] = true;
416         EXPECT_JSON_INVALID(configFile, "Validation failed.",
417                             "True is not of type 'string'");
418     }
419     // Invalid: No action type specified
420     {
421         json configFile = validConfigFile;
422         configFile["rules"][0]["actions"][1]["comments"][0] =
423             "Check if bit 3 is on";
424         EXPECT_JSON_INVALID(configFile, "Validation failed.",
425                             "'and' is a required property");
426     }
427     // Invalid: Multiple action types specified (such as both 'compare_presence'
428     // and 'pmbus_write_vout_command')
429     {
430         json configFile = validConfigFile;
431         configFile["rules"][0]["actions"][0]["compare_presence"]["value"] =
432             true;
433         EXPECT_JSON_INVALID(
434             configFile, "Validation failed.",
435             "{'compare_presence': {'value': True}, 'pmbus_write_vout_command': "
436             "{'format': 'linear'}} is valid under each of {'required': "
437             "['pmbus_write_vout_command']}, {'required': "
438             "['compare_presence']}");
439     }
440     // Invalid: Unexpected property specified (like 'foo')
441     {
442         json configFile = validConfigFile;
443         configFile["rules"][0]["actions"][1]["foo"] = "foo";
444         EXPECT_JSON_INVALID(
445             configFile, "Validation failed.",
446             "Additional properties are not allowed ('foo' was unexpected)");
447     }
448 }
449 TEST(ValidateRegulatorsConfigTest, And)
450 {
451     // Valid.
452     {
453         json configFile = validConfigFile;
454         json andAction =
455             R"(
456                 {
457                  "and": [
458                     { "i2c_compare_byte": { "register": "0xA0", "value": "0x00" } },
459                     { "i2c_compare_byte": { "register": "0xA1", "value": "0x00" } }
460                   ]
461                 }
462             )"_json;
463         configFile["rules"][0]["actions"].push_back(andAction);
464         EXPECT_JSON_VALID(configFile);
465     }
466 
467     // Invalid: actions property value is an empty array.
468     {
469         json configFile = validConfigFile;
470         json andAction =
471             R"(
472                 {
473                  "and": []
474                 }
475             )"_json;
476         configFile["rules"][0]["actions"].push_back(andAction);
477         EXPECT_JSON_INVALID(configFile, "Validation failed.",
478                             "[] is too short");
479     }
480 
481     // Invalid: actions property has incorrect value data type.
482     {
483         json configFile = validConfigFile;
484         json andAction =
485             R"(
486                 {
487                  "and": true
488                 }
489             )"_json;
490         configFile["rules"][0]["actions"].push_back(andAction);
491         EXPECT_JSON_INVALID(configFile, "Validation failed.",
492                             "True is not of type 'array'");
493     }
494 
495     // Invalid: actions property value contains wrong element type
496     {
497         json configFile = validConfigFile;
498         json andAction =
499             R"(
500                 {
501                  "and": ["foo"]
502                 }
503             )"_json;
504         configFile["rules"][0]["actions"].push_back(andAction);
505         EXPECT_JSON_INVALID(configFile, "Validation failed.",
506                             "'foo' is not of type 'object'");
507     }
508 }
509 TEST(ValidateRegulatorsConfigTest, Chassis)
510 {
511     // Valid: test chassis.
512     {
513         json configFile = validConfigFile;
514         EXPECT_JSON_VALID(configFile);
515     }
516     // Valid: test chassis with required properties.
517     {
518         json configFile = validConfigFile;
519         configFile["chassis"][0].erase("comments");
520         configFile["chassis"][0].erase("devices");
521         EXPECT_JSON_VALID(configFile);
522     }
523     // Invalid: test chassis with no number.
524     {
525         json configFile = validConfigFile;
526         configFile["chassis"][0].erase("number");
527         EXPECT_JSON_INVALID(configFile, "Validation failed.",
528                             "'number' is a required property");
529     }
530     // Invalid: test chassis with property comments wrong type.
531     {
532         json configFile = validConfigFile;
533         configFile["chassis"][0]["comments"] = true;
534         EXPECT_JSON_INVALID(configFile, "Validation failed.",
535                             "True is not of type 'array'");
536     }
537     // Invalid: test chassis with property number wrong type.
538     {
539         json configFile = validConfigFile;
540         configFile["chassis"][0]["number"] = 1.3;
541         EXPECT_JSON_INVALID(configFile, "Validation failed.",
542                             "1.3 is not of type 'integer'");
543     }
544     // Invalid: test chassis with property devices wrong type.
545     {
546         json configFile = validConfigFile;
547         configFile["chassis"][0]["devices"] = true;
548         EXPECT_JSON_INVALID(configFile, "Validation failed.",
549                             "True is not of type 'array'");
550     }
551     // Invalid: test chassis with property comments empty array.
552     {
553         json configFile = validConfigFile;
554         configFile["chassis"][0]["comments"] = json::array();
555         EXPECT_JSON_INVALID(configFile, "Validation failed.",
556                             "[] is too short");
557     }
558     // Invalid: test chassis with property devices empty array.
559     {
560         json configFile = validConfigFile;
561         configFile["chassis"][0]["devices"] = json::array();
562         EXPECT_JSON_INVALID(configFile, "Validation failed.",
563                             "[] is too short");
564     }
565     // Invalid: test chassis with property number less than 1.
566     {
567         json configFile = validConfigFile;
568         configFile["chassis"][0]["number"] = 0;
569         EXPECT_JSON_INVALID(configFile, "Validation failed.",
570                             "0 is less than the minimum of 1");
571     }
572 }
573 TEST(ValidateRegulatorsConfigTest, ComparePresence)
574 {
575     json comparePresenceFile = validConfigFile;
576     comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["fru"] =
577         "system/chassis/motherboard/regulator2";
578     comparePresenceFile["rules"][0]["actions"][1]["compare_presence"]["value"] =
579         true;
580     // Valid.
581     {
582         json configFile = comparePresenceFile;
583         EXPECT_JSON_VALID(configFile);
584     }
585 
586     // Invalid: no FRU property.
587     {
588         json configFile = comparePresenceFile;
589         configFile["rules"][0]["actions"][1]["compare_presence"].erase("fru");
590         EXPECT_JSON_INVALID(configFile, "Validation failed.",
591                             "'fru' is a required property");
592     }
593 
594     // Invalid: FRU property length is string less than 1.
595     {
596         json configFile = comparePresenceFile;
597         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = "";
598         EXPECT_JSON_INVALID(configFile, "Validation failed.",
599                             "'' is too short");
600     }
601 
602     // Invalid: no value property.
603     {
604         json configFile = comparePresenceFile;
605         configFile["rules"][0]["actions"][1]["compare_presence"].erase("value");
606         EXPECT_JSON_INVALID(configFile, "Validation failed.",
607                             "'value' is a required property");
608     }
609 
610     // Invalid: value property type is not boolean.
611     {
612         json configFile = comparePresenceFile;
613         configFile["rules"][0]["actions"][1]["compare_presence"]["value"] = "1";
614         EXPECT_JSON_INVALID(configFile, "Validation failed.",
615                             "'1' is not of type 'boolean'");
616     }
617 
618     // Invalid: FRU property type is not string.
619     {
620         json configFile = comparePresenceFile;
621         configFile["rules"][0]["actions"][1]["compare_presence"]["fru"] = 1;
622         EXPECT_JSON_INVALID(configFile, "Validation failed.",
623                             "1 is not of type 'string'");
624     }
625 }
626 TEST(ValidateRegulatorsConfigTest, CompareVpd)
627 {
628     json compareVpdFile = validConfigFile;
629     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] =
630         "system/chassis/motherboard/regulator2";
631     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] = "CCIN";
632     compareVpdFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = "2D35";
633 
634     // Valid.
635     {
636         json configFile = compareVpdFile;
637         EXPECT_JSON_VALID(configFile);
638     }
639 
640     // Invalid: no FRU property.
641     {
642         json configFile = compareVpdFile;
643         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("fru");
644         EXPECT_JSON_INVALID(configFile, "Validation failed.",
645                             "'fru' is a required property");
646     }
647 
648     // Invalid: no keyword property.
649     {
650         json configFile = compareVpdFile;
651         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("keyword");
652         EXPECT_JSON_INVALID(configFile, "Validation failed.",
653                             "'keyword' is a required property");
654     }
655 
656     // Invalid: no value property.
657     {
658         json configFile = compareVpdFile;
659         configFile["rules"][0]["actions"][1]["compare_vpd"].erase("value");
660         EXPECT_JSON_INVALID(configFile, "Validation failed.",
661                             "'value' is a required property");
662     }
663 
664     // Invalid: property FRU wrong type.
665     {
666         json configFile = compareVpdFile;
667         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = 1;
668         EXPECT_JSON_INVALID(configFile, "Validation failed.",
669                             "1 is not of type 'string'");
670     }
671 
672     // Invalid: property FRU is string less than 1.
673     {
674         json configFile = compareVpdFile;
675         configFile["rules"][0]["actions"][1]["compare_vpd"]["fru"] = "";
676         EXPECT_JSON_INVALID(configFile, "Validation failed.",
677                             "'' is too short");
678     }
679 
680     // Invalid: property keyword is not "CCIN", "Manufacturer", "Model",
681     // "PartNumber"
682     {
683         json configFile = compareVpdFile;
684         configFile["rules"][0]["actions"][1]["compare_vpd"]["keyword"] =
685             "Number";
686         EXPECT_JSON_INVALID(configFile, "Validation failed.",
687                             "'Number' is not one of ['CCIN', "
688                             "'Manufacturer', 'Model', 'PartNumber']");
689     }
690 
691     // Invalid: property value wrong type.
692     {
693         json configFile = compareVpdFile;
694         configFile["rules"][0]["actions"][1]["compare_vpd"]["value"] = 1;
695         EXPECT_JSON_INVALID(configFile, "Validation failed.",
696                             "1 is not of type 'string'");
697     }
698 }
699 TEST(ValidateRegulatorsConfigTest, ConfigFile)
700 {
701     // Valid: Only required properties specified
702     {
703         json configFile;
704         configFile["chassis"][0]["number"] = 1;
705         EXPECT_JSON_VALID(configFile);
706     }
707     // Valid: All properties specified
708     {
709         json configFile = validConfigFile;
710         EXPECT_JSON_VALID(configFile);
711     }
712     // Invalid: Required chassis property not specified
713     {
714         json configFile = validConfigFile;
715         configFile.erase("chassis");
716         EXPECT_JSON_INVALID(configFile, "Validation failed.",
717                             "'chassis' is a required property");
718     }
719     // Invalid: Wrong data type for comments
720     {
721         json configFile = validConfigFile;
722         configFile["comments"] = true;
723         EXPECT_JSON_INVALID(configFile, "Validation failed.",
724                             "True is not of type 'array'");
725     }
726     // Invalid: Wrong data type for rules
727     {
728         json configFile = validConfigFile;
729         configFile["rules"] = true;
730         EXPECT_JSON_INVALID(configFile, "Validation failed.",
731                             "True is not of type 'array'");
732     }
733     // Invalid: Wrong data type for chassis
734     {
735         json configFile = validConfigFile;
736         configFile["chassis"] = true;
737         EXPECT_JSON_INVALID(configFile, "Validation failed.",
738                             "True is not of type 'array'");
739     }
740     // Invalid: Empty comments array;
741     {
742         json configFile = validConfigFile;
743         configFile["comments"] = json::array();
744         EXPECT_JSON_INVALID(configFile, "Validation failed.",
745                             "[] is too short");
746     }
747     // Invalid: Empty rules array
748     {
749         json configFile = validConfigFile;
750         configFile["rules"] = json::array();
751         EXPECT_JSON_INVALID(configFile, "Validation failed.",
752                             "[] is too short");
753     }
754     // Invalid: Empty chassis array
755     {
756         json configFile = validConfigFile;
757         configFile["chassis"] = json::array();
758         EXPECT_JSON_INVALID(configFile, "Validation failed.",
759                             "[] is too short");
760     }
761     // Invalid: Comments array has wrong element type (should be string)
762     {
763         json configFile = validConfigFile;
764         configFile["comments"][0] = true;
765         EXPECT_JSON_INVALID(configFile, "Validation failed.",
766                             "True is not of type 'string'");
767     }
768     // Invalid: Rules array has wrong element type (should be rule)
769     {
770         json configFile = validConfigFile;
771         configFile["rules"][0] = true;
772         EXPECT_JSON_INVALID(configFile, "Validation failed.",
773                             "True is not of type 'object'");
774     }
775     // Invalid: Chassis array has wrong element type (should be chassis)
776     {
777         json configFile = validConfigFile;
778         configFile["chassis"][0] = true;
779         EXPECT_JSON_INVALID(configFile, "Validation failed.",
780                             "True is not of type 'object'");
781     }
782     // Invalid: Unexpected property specified
783     {
784         json configFile = validConfigFile;
785         configFile["foo"] = json::array();
786         EXPECT_JSON_INVALID(
787             configFile, "Validation failed.",
788             "Additional properties are not allowed ('foo' was unexpected)");
789     }
790 }
791 TEST(ValidateRegulatorsConfigTest, Configuration)
792 {
793     json configurationFile = validConfigFile;
794     configurationFile["chassis"][0]["devices"][0]["configuration"]["comments"]
795                      [0] = "Set rail to 1.25V using standard rule";
796     configurationFile["chassis"][0]["devices"][0]["configuration"]["volts"] =
797         1.25;
798     configurationFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
799         "set_voltage_rule";
800     // Valid: test configuration with property rule_id and with no actions.
801     {
802         json configFile = configurationFile;
803         configFile["chassis"][0]["devices"][0]["configuration"]["comments"][1] =
804             "test multiple array elements in comments.";
805         EXPECT_JSON_VALID(configFile);
806     }
807     // Valid: test configuration with property actions and with no rule_id.
808     {
809         json configFile = configurationFile;
810         configFile["chassis"][0]["devices"][0]["configuration"].erase(
811             "rule_id");
812         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
813                   ["compare_presence"]["fru"] =
814                       "system/chassis/motherboard/cpu3";
815         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
816                   ["compare_presence"]["value"] = true;
817         EXPECT_JSON_VALID(configFile);
818     }
819     // Valid: comments not specified (optional property).
820     {
821         json configFile = configurationFile;
822         configFile["chassis"][0]["devices"][0]["configuration"].erase(
823             "comments");
824         EXPECT_JSON_VALID(configFile);
825     }
826     // Valid: volts not specified (optional property).
827     {
828         json configFile = configurationFile;
829         configFile["chassis"][0]["devices"][0]["configuration"].erase("volts");
830         EXPECT_JSON_VALID(configFile);
831     }
832     // Valid: configuration is property of a rail (vs. a device).
833     {
834         json configFile = validConfigFile;
835         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
836                   ["comments"][0] = "Set rail to 1.25V using standard rule";
837         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
838                   ["volts"] = 1.25;
839         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"]
840                   ["rule_id"] = "set_voltage_rule";
841         EXPECT_JSON_VALID(configFile);
842     }
843     // Invalid: comments property has wrong data type (not an array).
844     {
845         json configFile = configurationFile;
846         configFile["chassis"][0]["devices"][0]["configuration"]["comments"] = 1;
847         EXPECT_JSON_INVALID(configFile, "Validation failed.",
848                             "1 is not of type 'array'");
849     }
850     // Invalid: test configuration with both actions and rule_id properties.
851     {
852         json configFile = configurationFile;
853         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
854                   ["compare_presence"]["fru"] =
855                       "system/chassis/motherboard/cpu3";
856         configFile["chassis"][0]["devices"][0]["configuration"]["actions"][0]
857                   ["compare_presence"]["value"] = true;
858         EXPECT_JSON_INVALID(
859             configFile, "Validation failed.",
860             "{'actions': [{'compare_presence': {'fru': "
861             "'system/chassis/motherboard/cpu3', 'value': True}}], 'comments': "
862             "['Set rail to 1.25V using standard rule'], 'rule_id': "
863             "'set_voltage_rule', 'volts': 1.25} is valid under each of "
864             "{'required': ['actions']}, {'required': ['rule_id']}");
865     }
866     // Invalid: test configuration with no rule_id and actions.
867     {
868         json configFile = configurationFile;
869         configFile["chassis"][0]["devices"][0]["configuration"].erase(
870             "rule_id");
871         EXPECT_JSON_INVALID(configFile, "Validation failed.",
872                             "'rule_id' is a required property");
873     }
874     // Invalid: test configuration with property volts wrong type.
875     {
876         json configFile = configurationFile;
877         configFile["chassis"][0]["devices"][0]["configuration"]["volts"] = true;
878         EXPECT_JSON_INVALID(configFile, "Validation failed.",
879                             "True is not of type 'number'");
880     }
881     // Invalid: test configuration with property rule_id wrong type.
882     {
883         json configFile = configurationFile;
884         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
885             true;
886         EXPECT_JSON_INVALID(configFile, "Validation failed.",
887                             "True is not of type 'string'");
888     }
889     // Invalid: test configuration with property actions wrong type.
890     {
891         json configFile = configurationFile;
892         configFile["chassis"][0]["devices"][0]["configuration"].erase(
893             "rule_id");
894         configFile["chassis"][0]["devices"][0]["configuration"]["actions"] =
895             true;
896         EXPECT_JSON_INVALID(configFile, "Validation failed.",
897                             "True is not of type 'array'");
898     }
899     // Invalid: test configuration with property comments empty array.
900     {
901         json configFile = configurationFile;
902         configFile["chassis"][0]["devices"][0]["configuration"]["comments"] =
903             json::array();
904         EXPECT_JSON_INVALID(configFile, "Validation failed.",
905                             "[] is too short");
906     }
907     // Invalid: test configuration with property rule_id wrong format.
908     {
909         json configFile = configurationFile;
910         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
911             "id!";
912         EXPECT_JSON_INVALID(configFile, "Validation failed.",
913                             "'id!' does not match '^[A-Za-z0-9_]+$'");
914     }
915     // Invalid: test configuration with property actions empty array.
916     {
917         json configFile = configurationFile;
918         configFile["chassis"][0]["devices"][0]["configuration"].erase(
919             "rule_id");
920         configFile["chassis"][0]["devices"][0]["configuration"]["actions"] =
921             json::array();
922         EXPECT_JSON_INVALID(configFile, "Validation failed.",
923                             "[] is too short");
924     }
925 }
926 TEST(ValidateRegulatorsConfigTest, Device)
927 {
928 
929     // Valid: test devices.
930     {
931         json configFile = validConfigFile;
932         EXPECT_JSON_VALID(configFile);
933     }
934     // Valid: test devices with required properties.
935     {
936         json configFile = validConfigFile;
937         configFile["chassis"][0]["devices"][0].erase("comments");
938         configFile["chassis"][0]["devices"][0].erase("presence_detection");
939         configFile["chassis"][0]["devices"][0].erase("configuration");
940         configFile["chassis"][0]["devices"][0].erase("rails");
941         EXPECT_JSON_VALID(configFile);
942     }
943     // Invalid: test devices with no id.
944     {
945         json configFile = validConfigFile;
946         configFile["chassis"][0]["devices"][0].erase("id");
947         EXPECT_JSON_INVALID(configFile, "Validation failed.",
948                             "'id' is a required property");
949     }
950     // Invalid: test devices with no is_regulator.
951     {
952         json configFile = validConfigFile;
953         configFile["chassis"][0]["devices"][0].erase("is_regulator");
954         EXPECT_JSON_INVALID(configFile, "Validation failed.",
955                             "'is_regulator' is a required property");
956     }
957     // Invalid: test devices with no fru.
958     {
959         json configFile = validConfigFile;
960         configFile["chassis"][0]["devices"][0].erase("fru");
961         EXPECT_JSON_INVALID(configFile, "Validation failed.",
962                             "'fru' is a required property");
963     }
964     // Invalid: test devices with no i2c_interface.
965     {
966         json configFile = validConfigFile;
967         configFile["chassis"][0]["devices"][0].erase("i2c_interface");
968         EXPECT_JSON_INVALID(configFile, "Validation failed.",
969                             "'i2c_interface' is a required property");
970     }
971     // Invalid: test devices with property comments wrong type.
972     {
973         json configFile = validConfigFile;
974         configFile["chassis"][0]["devices"][0]["comments"] = true;
975         EXPECT_JSON_INVALID(configFile, "Validation failed.",
976                             "True is not of type 'array'");
977     }
978     // Invalid: test devices with property id wrong type.
979     {
980         json configFile = validConfigFile;
981         configFile["chassis"][0]["devices"][0]["id"] = true;
982         EXPECT_JSON_INVALID(configFile, "Validation failed.",
983                             "True is not of type 'string'");
984     }
985     // Invalid: test devices with property is_regulator wrong type.
986     {
987         json configFile = validConfigFile;
988         configFile["chassis"][0]["devices"][0]["is_regulator"] = 1;
989         EXPECT_JSON_INVALID(configFile, "Validation failed.",
990                             "1 is not of type 'boolean'");
991     }
992     // Invalid: test devices with property fru wrong type.
993     {
994         json configFile = validConfigFile;
995         configFile["chassis"][0]["devices"][0]["fru"] = true;
996         EXPECT_JSON_INVALID(configFile, "Validation failed.",
997                             "True is not of type 'string'");
998     }
999     // Invalid: test devices with property i2c_interface wrong type.
1000     {
1001         json configFile = validConfigFile;
1002         configFile["chassis"][0]["devices"][0]["i2c_interface"] = true;
1003         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1004                             "True is not of type 'object'");
1005     }
1006     // Invalid: test devices with property presence_detection wrong
1007     // type.
1008     {
1009         json configFile = validConfigFile;
1010         configFile["chassis"][0]["devices"][0]["presence_detection"] = true;
1011         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1012                             "True is not of type 'object'");
1013     }
1014     // Invalid: test devices with property configuration wrong type.
1015     {
1016         json configFile = validConfigFile;
1017         configFile["chassis"][0]["devices"][0]["configuration"] = true;
1018         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1019                             "True is not of type 'object'");
1020     }
1021     // Invalid: test devices with property rails wrong type.
1022     {
1023         json configFile = validConfigFile;
1024         configFile["chassis"][0]["devices"][0]["rails"] = true;
1025         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1026                             "True is not of type 'array'");
1027     }
1028     // Invalid: test devices with property comments empty array.
1029     {
1030         json configFile = validConfigFile;
1031         configFile["chassis"][0]["devices"][0]["comments"] = json::array();
1032         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1033                             "[] is too short");
1034     }
1035     // Invalid: test devices with property fru length less than 1.
1036     {
1037         json configFile = validConfigFile;
1038         configFile["chassis"][0]["devices"][0]["fru"] = "";
1039         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1040                             "'' is too short");
1041     }
1042     // Invalid: test devices with property id wrong format.
1043     {
1044         json configFile = validConfigFile;
1045         configFile["chassis"][0]["devices"][0]["id"] = "id#";
1046         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1047                             "'id#' does not match '^[A-Za-z0-9_]+$'");
1048     }
1049     // Invalid: test devices with property rails empty array.
1050     {
1051         json configFile = validConfigFile;
1052         configFile["chassis"][0]["devices"][0]["rails"] = json::array();
1053         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1054                             "[] is too short");
1055     }
1056 }
1057 TEST(ValidateRegulatorsConfigTest, I2CCompareBit)
1058 {
1059     json i2cCompareBitFile = validConfigFile;
1060     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
1061         "0xA0";
1062     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
1063         3;
1064     i2cCompareBitFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 1;
1065     // Valid: test rule actions i2c_compare_bit.
1066     {
1067         json configFile = i2cCompareBitFile;
1068         EXPECT_JSON_VALID(configFile);
1069     }
1070     // Invalid: test i2c_compare_bit with no register.
1071     {
1072         json configFile = i2cCompareBitFile;
1073         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
1074             "register");
1075         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1076                             "'register' is a required property");
1077     }
1078     // Invalid: test i2c_compare_bit with no position.
1079     {
1080         json configFile = i2cCompareBitFile;
1081         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase(
1082             "position");
1083         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1084                             "'position' is a required property");
1085     }
1086     // Invalid: test i2c_compare_bit with no value.
1087     {
1088         json configFile = i2cCompareBitFile;
1089         configFile["rules"][0]["actions"][1]["i2c_compare_bit"].erase("value");
1090         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1091                             "'value' is a required property");
1092     }
1093     // Invalid: test i2c_compare_bit with register wrong type.
1094     {
1095         json configFile = i2cCompareBitFile;
1096         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] = 1;
1097         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1098                             "1 is not of type 'string'");
1099     }
1100     // Invalid: test i2c_compare_bit with register wrong format.
1101     {
1102         json configFile = i2cCompareBitFile;
1103         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["register"] =
1104             "0xA00";
1105         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1106                             "'0xA00' does not match '^0x[0-9A-Fa-f]{2}$'");
1107     }
1108     // Invalid: test i2c_compare_bit with position wrong type.
1109     {
1110         json configFile = i2cCompareBitFile;
1111         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
1112             3.1;
1113         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1114                             "3.1 is not of type 'integer'");
1115     }
1116     // Invalid: test i2c_compare_bit with position greater than 7.
1117     {
1118         json configFile = i2cCompareBitFile;
1119         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] = 8;
1120         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1121                             "8 is greater than the maximum of 7");
1122     }
1123     // Invalid: test i2c_compare_bit with position less than 0.
1124     {
1125         json configFile = i2cCompareBitFile;
1126         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["position"] =
1127             -1;
1128         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1129                             "-1 is less than the minimum of 0");
1130     }
1131     // Invalid: test i2c_compare_bit with value wrong type.
1132     {
1133         json configFile = i2cCompareBitFile;
1134         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = "1";
1135         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1136                             "'1' is not of type 'integer'");
1137     }
1138     // Invalid: test i2c_compare_bit with value greater than 1.
1139     {
1140         json configFile = i2cCompareBitFile;
1141         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = 2;
1142         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1143                             "2 is greater than the maximum of 1");
1144     }
1145     // Invalid: test i2c_compare_bit with value less than 0.
1146     {
1147         json configFile = i2cCompareBitFile;
1148         configFile["rules"][0]["actions"][1]["i2c_compare_bit"]["value"] = -1;
1149         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1150                             "-1 is less than the minimum of 0");
1151     }
1152 }
1153 TEST(ValidateRegulatorsConfigTest, I2CCompareByte)
1154 {
1155     json i2cCompareByteFile = validConfigFile;
1156     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]
1157                       ["register"] = "0x82";
1158     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1159         "0x40";
1160     i2cCompareByteFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1161         "0x7F";
1162     // Valid: test i2c_compare_byte with all properties.
1163     {
1164         json configFile = i2cCompareByteFile;
1165         EXPECT_JSON_VALID(configFile);
1166     }
1167     // Valid: test i2c_compare_byte with all required properties.
1168     {
1169         json configFile = i2cCompareByteFile;
1170         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("mask");
1171         EXPECT_JSON_VALID(configFile);
1172     }
1173     // Invalid: test i2c_compare_byte with no register.
1174     {
1175         json configFile = i2cCompareByteFile;
1176         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase(
1177             "register");
1178         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1179                             "'register' is a required property");
1180     }
1181     // Invalid: test i2c_compare_byte with no value.
1182     {
1183         json configFile = i2cCompareByteFile;
1184         configFile["rules"][0]["actions"][1]["i2c_compare_byte"].erase("value");
1185         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1186                             "'value' is a required property");
1187     }
1188     // Invalid: test i2c_compare_byte with property register wrong type.
1189     {
1190         json configFile = i2cCompareByteFile;
1191         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1192             1;
1193         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1194                             "1 is not of type 'string'");
1195     }
1196     // Invalid: test i2c_compare_byte with property value wrong type.
1197     {
1198         json configFile = i2cCompareByteFile;
1199         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] = 1;
1200         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1201                             "1 is not of type 'string'");
1202     }
1203     // Invalid: test i2c_compare_byte with property mask wrong type.
1204     {
1205         json configFile = i2cCompareByteFile;
1206         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = 1;
1207         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1208                             "1 is not of type 'string'");
1209     }
1210     // Invalid: test i2c_compare_byte with property register more than 2 hex
1211     // digits.
1212     {
1213         json configFile = i2cCompareByteFile;
1214         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1215             "0x820";
1216         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1217                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1218     }
1219     // Invalid: test i2c_compare_byte with property value more than 2 hex
1220     // digits.
1221     {
1222         json configFile = i2cCompareByteFile;
1223         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1224             "0x820";
1225         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1226                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1227     }
1228     // Invalid: test i2c_compare_byte with property mask more than 2 hex digits.
1229     {
1230         json configFile = i2cCompareByteFile;
1231         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1232             "0x820";
1233         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1234                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1235     }
1236     // Invalid: test i2c_compare_byte with property register less than 2 hex
1237     // digits.
1238     {
1239         json configFile = i2cCompareByteFile;
1240         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1241             "0x8";
1242         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1243                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1244     }
1245     // Invalid: test i2c_compare_byte with property value less than 2 hex
1246     // digits.
1247     {
1248         json configFile = i2cCompareByteFile;
1249         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1250             "0x8";
1251         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1252                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1253     }
1254     // Invalid: test i2c_compare_byte with property mask less than 2 hex digits.
1255     {
1256         json configFile = i2cCompareByteFile;
1257         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1258             "0x8";
1259         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1260                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1261     }
1262     // Invalid: test i2c_compare_byte with property register no leading prefix.
1263     {
1264         json configFile = i2cCompareByteFile;
1265         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1266             "82";
1267         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1268                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1269     }
1270     // Invalid: test i2c_compare_byte with property value no leading prefix.
1271     {
1272         json configFile = i2cCompareByteFile;
1273         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1274             "82";
1275         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1276                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1277     }
1278     // Invalid: test i2c_compare_byte with property mask no leading prefix.
1279     {
1280         json configFile = i2cCompareByteFile;
1281         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] = "82";
1282         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1283                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1284     }
1285     // Invalid: test i2c_compare_byte with property register invalid hex digit.
1286     {
1287         json configFile = i2cCompareByteFile;
1288         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["register"] =
1289             "0xG1";
1290         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1291                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1292     }
1293     // Invalid: test i2c_compare_byte with property value invalid hex digit.
1294     {
1295         json configFile = i2cCompareByteFile;
1296         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["value"] =
1297             "0xG1";
1298         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1299                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1300     }
1301     // Invalid: test i2c_compare_byte with property mask invalid hex digit.
1302     {
1303         json configFile = i2cCompareByteFile;
1304         configFile["rules"][0]["actions"][1]["i2c_compare_byte"]["mask"] =
1305             "0xG1";
1306         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1307                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1308     }
1309 }
1310 TEST(ValidateRegulatorsConfigTest, I2CCompareBytes)
1311 {
1312     json i2cCompareBytesFile = validConfigFile;
1313     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1314                        ["register"] = "0x82";
1315     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1316                        ["values"] = {"0x02", "0x73"};
1317     i2cCompareBytesFile["rules"][0]["actions"][1]["i2c_compare_bytes"]
1318                        ["masks"] = {"0x7F", "0x7F"};
1319     // Valid: test i2c_compare_bytes.
1320     {
1321         json configFile = i2cCompareBytesFile;
1322         EXPECT_JSON_VALID(configFile);
1323     }
1324     // Valid: test i2c_compare_bytes with all required properties.
1325     {
1326         json configFile = i2cCompareBytesFile;
1327         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1328             "masks");
1329         EXPECT_JSON_VALID(configFile);
1330     }
1331     // Invalid: test i2c_compare_bytes with no register.
1332     {
1333         json configFile = i2cCompareBytesFile;
1334         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1335             "register");
1336         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1337                             "'register' is a required property");
1338     }
1339     // Invalid: test i2c_compare_bytes with no values.
1340     {
1341         json configFile = i2cCompareBytesFile;
1342         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"].erase(
1343             "values");
1344         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1345                             "'values' is a required property");
1346     }
1347     // Invalid: test i2c_compare_bytes with property values as empty array.
1348     {
1349         json configFile = i2cCompareBytesFile;
1350         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] =
1351             json::array();
1352         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1353                             "[] is too short");
1354     }
1355     // Invalid: test i2c_compare_bytes with property masks as empty array.
1356     {
1357         json configFile = i2cCompareBytesFile;
1358         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] =
1359             json::array();
1360         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1361                             "[] is too short");
1362     }
1363     // Invalid: test i2c_compare_bytes with property register wrong type.
1364     {
1365         json configFile = i2cCompareBytesFile;
1366         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1367             1;
1368         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1369                             "1 is not of type 'string'");
1370     }
1371     // Invalid: test i2c_compare_bytes with property values wrong type.
1372     {
1373         json configFile = i2cCompareBytesFile;
1374         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = 1;
1375         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1376                             "1 is not of type 'array'");
1377     }
1378     // Invalid: test i2c_compare_bytes with property masks wrong type.
1379     {
1380         json configFile = i2cCompareBytesFile;
1381         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = 1;
1382         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1383                             "1 is not of type 'array'");
1384     }
1385     // Invalid: test i2c_compare_bytes with property register more than 2 hex
1386     // digits.
1387     {
1388         json configFile = i2cCompareBytesFile;
1389         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1390             "0x820";
1391         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1392                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1393     }
1394     // Invalid: test i2c_compare_bytes with property values more than 2 hex
1395     // digits.
1396     {
1397         json configFile = i2cCompareBytesFile;
1398         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1399             "0x820";
1400         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1401                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1402     }
1403     // Invalid: test i2c_compare_bytes with property masks more than 2 hex
1404     // digits.
1405     {
1406         json configFile = i2cCompareBytesFile;
1407         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1408             "0x820";
1409         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1410                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1411     }
1412     // Invalid: test i2c_compare_bytes with property register less than 2 hex
1413     // digits.
1414     {
1415         json configFile = i2cCompareBytesFile;
1416         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1417             "0x8";
1418         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1419                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1420     }
1421     // Invalid: test i2c_compare_bytes with property values less than 2 hex
1422     // digits.
1423     {
1424         json configFile = i2cCompareBytesFile;
1425         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1426             "0x8";
1427         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1428                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1429     }
1430     // Invalid: test i2c_compare_bytes with property masks less than 2 hex
1431     // digits.
1432     {
1433         json configFile = i2cCompareBytesFile;
1434         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1435             "0x8";
1436         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1437                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1438     }
1439     // Invalid: test i2c_compare_bytes with property register no leading prefix.
1440     {
1441         json configFile = i2cCompareBytesFile;
1442         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1443             "82";
1444         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1445                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1446     }
1447     // Invalid: test i2c_compare_bytes with property values no leading prefix.
1448     {
1449         json configFile = i2cCompareBytesFile;
1450         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1451             "82";
1452         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1453                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1454     }
1455     // Invalid: test i2c_compare_bytes with property masks no leading prefix.
1456     {
1457         json configFile = i2cCompareBytesFile;
1458         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1459             "82";
1460         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1461                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1462     }
1463     // Invalid: test i2c_compare_bytes with property register invalid hex digit.
1464     {
1465         json configFile = i2cCompareBytesFile;
1466         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
1467             "0xG1";
1468         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1469                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1470     }
1471     // Invalid: test i2c_compare_bytes with property values invalid hex digit.
1472     {
1473         json configFile = i2cCompareBytesFile;
1474         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"][0] =
1475             "0xG1";
1476         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1477                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1478     }
1479     // Invalid: test i2c_compare_bytes with property masks invalid hex digit.
1480     {
1481         json configFile = i2cCompareBytesFile;
1482         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"][0] =
1483             "0xG1";
1484         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1485                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1486     }
1487 }
1488 TEST(ValidateRegulatorsConfigTest, I2CInterface)
1489 {
1490     // Valid: test i2c_interface.
1491     {
1492         json configFile = validConfigFile;
1493         EXPECT_JSON_VALID(configFile);
1494     }
1495     // Invalid: testi2c_interface with no bus.
1496     {
1497         json configFile = validConfigFile;
1498         configFile["chassis"][0]["devices"][0]["i2c_interface"].erase("bus");
1499         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1500                             "'bus' is a required property");
1501     }
1502     // Invalid: test i2c_interface with no address.
1503     {
1504         json configFile = validConfigFile;
1505         configFile["chassis"][0]["devices"][0]["i2c_interface"].erase(
1506             "address");
1507         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1508                             "'address' is a required property");
1509     }
1510     // Invalid: test i2c_interface with property bus wrong type.
1511     {
1512         json configFile = validConfigFile;
1513         configFile["chassis"][0]["devices"][0]["i2c_interface"]["bus"] = true;
1514         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1515                             "True is not of type 'integer'");
1516     }
1517     // Invalid: test i2c_interface with property address wrong
1518     // type.
1519     {
1520         json configFile = validConfigFile;
1521         configFile["chassis"][0]["devices"][0]["i2c_interface"]["address"] =
1522             true;
1523         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1524                             "True is not of type 'string'");
1525     }
1526     // Invalid: test i2c_interface with property bus less than
1527     // 0.
1528     {
1529         json configFile = validConfigFile;
1530         configFile["chassis"][0]["devices"][0]["i2c_interface"]["bus"] = -1;
1531         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1532                             "-1 is less than the minimum of 0");
1533     }
1534     // Invalid: test i2c_interface with property address wrong
1535     // format.
1536     {
1537         json configFile = validConfigFile;
1538         configFile["chassis"][0]["devices"][0]["i2c_interface"]["address"] =
1539             "0x700";
1540         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1541                             "'0x700' does not match '^0x[0-9A-Fa-f]{2}$'");
1542     }
1543 }
1544 TEST(ValidateRegulatorsConfigTest, I2CWriteBit)
1545 {
1546     json i2cWriteBitFile = validConfigFile;
1547     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] =
1548         "0xA0";
1549     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 3;
1550     i2cWriteBitFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = 1;
1551     // Valid: test rule actions i2c_write_bit.
1552     {
1553         json configFile = i2cWriteBitFile;
1554         EXPECT_JSON_VALID(configFile);
1555     }
1556     // Invalid: test i2c_write_bit with no register.
1557     {
1558         json configFile = i2cWriteBitFile;
1559         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("register");
1560         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1561                             "'register' is a required property");
1562     }
1563     // Invalid: test i2c_write_bit with no position.
1564     {
1565         json configFile = i2cWriteBitFile;
1566         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("position");
1567         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1568                             "'position' is a required property");
1569     }
1570     // Invalid: test i2c_write_bit with no value.
1571     {
1572         json configFile = i2cWriteBitFile;
1573         configFile["rules"][0]["actions"][1]["i2c_write_bit"].erase("value");
1574         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1575                             "'value' is a required property");
1576     }
1577     // Invalid: test i2c_write_bit with register wrong type.
1578     {
1579         json configFile = i2cWriteBitFile;
1580         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] = 1;
1581         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1582                             "1 is not of type 'string'");
1583     }
1584     // Invalid: test i2c_write_bit with register wrong format.
1585     {
1586         json configFile = i2cWriteBitFile;
1587         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["register"] =
1588             "0xA00";
1589         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1590                             "'0xA00' does not match '^0x[0-9A-Fa-f]{2}$'");
1591     }
1592     // Invalid: test i2c_write_bit with position wrong type.
1593     {
1594         json configFile = i2cWriteBitFile;
1595         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 3.1;
1596         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1597                             "3.1 is not of type 'integer'");
1598     }
1599     // Invalid: test i2c_write_bit with position greater than 7.
1600     {
1601         json configFile = i2cWriteBitFile;
1602         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = 8;
1603         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1604                             "8 is greater than the maximum of 7");
1605     }
1606     // Invalid: test i2c_write_bit with position less than 0.
1607     {
1608         json configFile = i2cWriteBitFile;
1609         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["position"] = -1;
1610         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1611                             "-1 is less than the minimum of 0");
1612     }
1613     // Invalid: test i2c_write_bit with value wrong type.
1614     {
1615         json configFile = i2cWriteBitFile;
1616         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = "1";
1617         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1618                             "'1' is not of type 'integer'");
1619     }
1620     // Invalid: test i2c_write_bit with value greater than 1.
1621     {
1622         json configFile = i2cWriteBitFile;
1623         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = 2;
1624         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1625                             "2 is greater than the maximum of 1");
1626     }
1627     // Invalid: test i2c_write_bit with value less than 0.
1628     {
1629         json configFile = i2cWriteBitFile;
1630         configFile["rules"][0]["actions"][1]["i2c_write_bit"]["value"] = -1;
1631         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1632                             "-1 is less than the minimum of 0");
1633     }
1634 }
1635 TEST(ValidateRegulatorsConfigTest, I2CWriteByte)
1636 {
1637     json i2cWriteByteFile = validConfigFile;
1638     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1639         "0x82";
1640     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1641         "0x40";
1642     i2cWriteByteFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] =
1643         "0x7F";
1644     // Valid: test i2c_write_byte with all properties.
1645     {
1646         json configFile = i2cWriteByteFile;
1647         EXPECT_JSON_VALID(configFile);
1648     }
1649     // Valid: test i2c_write_byte with all required properties.
1650     {
1651         json configFile = i2cWriteByteFile;
1652         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase("mask");
1653         EXPECT_JSON_VALID(configFile);
1654     }
1655     // Invalid: test i2c_write_byte with no register.
1656     {
1657         json configFile = i2cWriteByteFile;
1658         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase(
1659             "register");
1660         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1661                             "'register' is a required property");
1662     }
1663     // Invalid: test i2c_write_byte with no value.
1664     {
1665         json configFile = i2cWriteByteFile;
1666         configFile["rules"][0]["actions"][1]["i2c_write_byte"].erase("value");
1667         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1668                             "'value' is a required property");
1669     }
1670     // Invalid: test i2c_write_byte with property register wrong type.
1671     {
1672         json configFile = i2cWriteByteFile;
1673         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] = 1;
1674         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1675                             "1 is not of type 'string'");
1676     }
1677     // Invalid: test i2c_write_byte with property value wrong type.
1678     {
1679         json configFile = i2cWriteByteFile;
1680         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = 1;
1681         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1682                             "1 is not of type 'string'");
1683     }
1684     // Invalid: test i2c_write_byte with property mask wrong type.
1685     {
1686         json configFile = i2cWriteByteFile;
1687         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = 1;
1688         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1689                             "1 is not of type 'string'");
1690     }
1691     // Invalid: test i2c_write_byte with property register more than 2 hex
1692     // digits.
1693     {
1694         json configFile = i2cWriteByteFile;
1695         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1696             "0x820";
1697         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1698                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1699     }
1700     // Invalid: test i2c_write_byte with property value more than 2 hex
1701     // digits.
1702     {
1703         json configFile = i2cWriteByteFile;
1704         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1705             "0x820";
1706         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1707                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1708     }
1709     // Invalid: test i2c_write_byte with property mask more than 2 hex digits.
1710     {
1711         json configFile = i2cWriteByteFile;
1712         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] =
1713             "0x820";
1714         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1715                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1716     }
1717     // Invalid: test i2c_write_byte with property register less than 2 hex
1718     // digits.
1719     {
1720         json configFile = i2cWriteByteFile;
1721         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1722             "0x8";
1723         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1724                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1725     }
1726     // Invalid: test i2c_write_byte with property value less than 2 hex
1727     // digits.
1728     {
1729         json configFile = i2cWriteByteFile;
1730         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = "0x8";
1731         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1732                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1733     }
1734     // Invalid: test i2c_write_byte with property mask less than 2 hex digits.
1735     {
1736         json configFile = i2cWriteByteFile;
1737         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "0x8";
1738         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1739                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1740     }
1741     // Invalid: test i2c_write_byte with property register no leading prefix.
1742     {
1743         json configFile = i2cWriteByteFile;
1744         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1745             "82";
1746         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1747                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1748     }
1749     // Invalid: test i2c_write_byte with property value no leading prefix.
1750     {
1751         json configFile = i2cWriteByteFile;
1752         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] = "82";
1753         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1754                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1755     }
1756     // Invalid: test i2c_write_byte with property mask no leading prefix.
1757     {
1758         json configFile = i2cWriteByteFile;
1759         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "82";
1760         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1761                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1762     }
1763     // Invalid: test i2c_write_byte with property register invalid hex digit.
1764     {
1765         json configFile = i2cWriteByteFile;
1766         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["register"] =
1767             "0xG1";
1768         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1769                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1770     }
1771     // Invalid: test i2c_write_byte with property value invalid hex digit.
1772     {
1773         json configFile = i2cWriteByteFile;
1774         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["value"] =
1775             "0xG1";
1776         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1777                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1778     }
1779     // Invalid: test i2c_write_byte with property mask invalid hex digit.
1780     {
1781         json configFile = i2cWriteByteFile;
1782         configFile["rules"][0]["actions"][1]["i2c_write_byte"]["mask"] = "0xG1";
1783         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1784                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1785     }
1786 }
1787 TEST(ValidateRegulatorsConfigTest, I2CWriteBytes)
1788 {
1789     json i2cWriteBytesFile = validConfigFile;
1790     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1791         "0x82";
1792     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
1793         "0x02", "0x73"};
1794     i2cWriteBytesFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
1795         "0x7F", "0x7F"};
1796     // Valid: test i2c_write_bytes.
1797     {
1798         json configFile = i2cWriteBytesFile;
1799         EXPECT_JSON_VALID(configFile);
1800     }
1801     // Valid: test i2c_write_bytes with all required properties.
1802     {
1803         json configFile = i2cWriteBytesFile;
1804         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase("masks");
1805         EXPECT_JSON_VALID(configFile);
1806     }
1807     // Invalid: test i2c_write_bytes with no register.
1808     {
1809         json configFile = i2cWriteBytesFile;
1810         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase(
1811             "register");
1812         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1813                             "'register' is a required property");
1814     }
1815     // Invalid: test i2c_write_bytes with no values.
1816     {
1817         json configFile = i2cWriteBytesFile;
1818         configFile["rules"][0]["actions"][1]["i2c_write_bytes"].erase("values");
1819         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1820                             "'values' is a required property");
1821     }
1822     // Invalid: test i2c_write_bytes with property values as empty array.
1823     {
1824         json configFile = i2cWriteBytesFile;
1825         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] =
1826             json::array();
1827         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1828                             "[] is too short");
1829     }
1830     // Invalid: test i2c_write_bytes with property masks as empty array.
1831     {
1832         json configFile = i2cWriteBytesFile;
1833         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] =
1834             json::array();
1835         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1836                             "[] is too short");
1837     }
1838     // Invalid: test i2c_write_bytes with property register wrong type.
1839     {
1840         json configFile = i2cWriteBytesFile;
1841         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] = 1;
1842         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1843                             "1 is not of type 'string'");
1844     }
1845     // Invalid: test i2c_write_bytes with property values wrong type.
1846     {
1847         json configFile = i2cWriteBytesFile;
1848         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = 1;
1849         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1850                             "1 is not of type 'array'");
1851     }
1852     // Invalid: test i2c_write_bytes with property masks wrong type.
1853     {
1854         json configFile = i2cWriteBytesFile;
1855         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = 1;
1856         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1857                             "1 is not of type 'array'");
1858     }
1859     // Invalid: test i2c_write_bytes with property register more than 2 hex
1860     // digits.
1861     {
1862         json configFile = i2cWriteBytesFile;
1863         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1864             "0x820";
1865         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1866                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1867     }
1868     // Invalid: test i2c_write_bytes with property values more than 2 hex
1869     // digits.
1870     {
1871         json configFile = i2cWriteBytesFile;
1872         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1873             "0x820";
1874         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1875                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1876     }
1877     // Invalid: test i2c_write_bytes with property masks more than 2 hex
1878     // digits.
1879     {
1880         json configFile = i2cWriteBytesFile;
1881         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1882             "0x820";
1883         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1884                             "'0x820' does not match '^0x[0-9A-Fa-f]{2}$'");
1885     }
1886     // Invalid: test i2c_write_bytes with property register less than 2 hex
1887     // digits.
1888     {
1889         json configFile = i2cWriteBytesFile;
1890         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1891             "0x8";
1892         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1893                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1894     }
1895     // Invalid: test i2c_write_bytes with property values less than 2 hex
1896     // digits.
1897     {
1898         json configFile = i2cWriteBytesFile;
1899         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1900             "0x8";
1901         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1902                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1903     }
1904     // Invalid: test i2c_write_bytes with property masks less than 2 hex
1905     // digits.
1906     {
1907         json configFile = i2cWriteBytesFile;
1908         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1909             "0x8";
1910         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1911                             "'0x8' does not match '^0x[0-9A-Fa-f]{2}$'");
1912     }
1913     // Invalid: test i2c_write_bytes with property register no leading prefix.
1914     {
1915         json configFile = i2cWriteBytesFile;
1916         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1917             "82";
1918         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1919                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1920     }
1921     // Invalid: test i2c_write_bytes with property values no leading prefix.
1922     {
1923         json configFile = i2cWriteBytesFile;
1924         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1925             "82";
1926         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1927                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1928     }
1929     // Invalid: test i2c_write_bytes with property masks no leading prefix.
1930     {
1931         json configFile = i2cWriteBytesFile;
1932         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1933             "82";
1934         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1935                             "'82' does not match '^0x[0-9A-Fa-f]{2}$'");
1936     }
1937     // Invalid: test i2c_write_bytes with property register invalid hex digit.
1938     {
1939         json configFile = i2cWriteBytesFile;
1940         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
1941             "0xG1";
1942         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1943                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1944     }
1945     // Invalid: test i2c_write_bytes with property values invalid hex digit.
1946     {
1947         json configFile = i2cWriteBytesFile;
1948         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"][0] =
1949             "0xG1";
1950         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1951                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1952     }
1953     // Invalid: test i2c_write_bytes with property masks invalid hex digit.
1954     {
1955         json configFile = i2cWriteBytesFile;
1956         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"][0] =
1957             "0xG1";
1958         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1959                             "'0xG1' does not match '^0x[0-9A-Fa-f]{2}$'");
1960     }
1961 }
1962 TEST(ValidateRegulatorsConfigTest, If)
1963 {
1964     json ifFile = validConfigFile;
1965     ifFile["rules"][2]["actions"][0]["if"]["condition"]["run_rule"] =
1966         "set_voltage_rule";
1967     ifFile["rules"][2]["actions"][0]["if"]["then"][0]["run_rule"] =
1968         "read_sensors_rule";
1969     ifFile["rules"][2]["actions"][0]["if"]["else"][0]["run_rule"] =
1970         "read_sensors_rule";
1971     ifFile["rules"][2]["id"] = "rule_if";
1972     // Valid: test if.
1973     {
1974         json configFile = ifFile;
1975         EXPECT_JSON_VALID(configFile);
1976     }
1977     // Valid: test if with required properties.
1978     {
1979         json configFile = ifFile;
1980         configFile["rules"][2]["actions"][0]["if"].erase("else");
1981         EXPECT_JSON_VALID(configFile);
1982     }
1983     // Invalid: test if with no property condition.
1984     {
1985         json configFile = ifFile;
1986         configFile["rules"][2]["actions"][0]["if"].erase("condition");
1987         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1988                             "'condition' is a required property");
1989     }
1990     // Invalid: test if with no property then.
1991     {
1992         json configFile = ifFile;
1993         configFile["rules"][2]["actions"][0]["if"].erase("then");
1994         EXPECT_JSON_INVALID(configFile, "Validation failed.",
1995                             "'then' is a required property");
1996     }
1997     // Invalid: test if with property then empty array.
1998     {
1999         json configFile = ifFile;
2000         configFile["rules"][2]["actions"][0]["if"]["then"] = json::array();
2001         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2002                             "[] is too short");
2003     }
2004     // Invalid: test if with property else empty array.
2005     {
2006         json configFile = ifFile;
2007         configFile["rules"][2]["actions"][0]["if"]["else"] = json::array();
2008         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2009                             "[] is too short");
2010     }
2011     // Invalid: test if with property condition wrong type.
2012     {
2013         json configFile = ifFile;
2014         configFile["rules"][2]["actions"][0]["if"]["condition"] = 1;
2015         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2016                             "1 is not of type 'object'");
2017     }
2018     // Invalid: test if with property then wrong type.
2019     {
2020         json configFile = ifFile;
2021         configFile["rules"][2]["actions"][0]["if"]["then"] = 1;
2022         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2023                             "1 is not of type 'array'");
2024     }
2025     // Invalid: test if with property else wrong type.
2026     {
2027         json configFile = ifFile;
2028         configFile["rules"][2]["actions"][0]["if"]["else"] = 1;
2029         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2030                             "1 is not of type 'array'");
2031     }
2032 }
2033 TEST(ValidateRegulatorsConfigTest, Not)
2034 {
2035     json notFile = validConfigFile;
2036     notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["register"] =
2037         "0xA0";
2038     notFile["rules"][0]["actions"][1]["not"]["i2c_compare_byte"]["value"] =
2039         "0xFF";
2040     // Valid: test not.
2041     {
2042         json configFile = notFile;
2043         EXPECT_JSON_VALID(configFile);
2044     }
2045     // Invalid: test not with wrong type.
2046     {
2047         json configFile = notFile;
2048         configFile["rules"][0]["actions"][1]["not"] = 1;
2049         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2050                             "1 is not of type 'object'");
2051     }
2052 }
2053 TEST(ValidateRegulatorsConfigTest, Or)
2054 {
2055     json orFile = validConfigFile;
2056     orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["register"] =
2057         "0xA0";
2058     orFile["rules"][0]["actions"][1]["or"][0]["i2c_compare_byte"]["value"] =
2059         "0x00";
2060     orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["register"] =
2061         "0xA1";
2062     orFile["rules"][0]["actions"][1]["or"][1]["i2c_compare_byte"]["value"] =
2063         "0x00";
2064     // Valid: test or.
2065     {
2066         json configFile = orFile;
2067         EXPECT_JSON_VALID(configFile);
2068     }
2069     // Invalid: test or with empty array.
2070     {
2071         json configFile = orFile;
2072         configFile["rules"][0]["actions"][1]["or"] = json::array();
2073         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2074                             "[] is too short");
2075     }
2076     // Invalid: test or with wrong type.
2077     {
2078         json configFile = orFile;
2079         configFile["rules"][0]["actions"][1]["or"] = 1;
2080         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2081                             "1 is not of type 'array'");
2082     }
2083 }
2084 TEST(ValidateRegulatorsConfigTest, PmbusReadSensor)
2085 {
2086     json pmbusReadSensorFile = validConfigFile;
2087     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
2088         "vout";
2089     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
2090                        ["command"] = "0x8B";
2091     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
2092                        ["format"] = "linear_16";
2093     pmbusReadSensorFile["rules"][0]["actions"][1]["pmbus_read_sensor"]
2094                        ["exponent"] = -8;
2095     // Valid: test pmbus_read_sensor.
2096     {
2097         json configFile = pmbusReadSensorFile;
2098         EXPECT_JSON_VALID(configFile);
2099     }
2100     // Valid: test pmbus_read_sensor with required properties.
2101     {
2102         json configFile = pmbusReadSensorFile;
2103         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
2104             "exponent");
2105         EXPECT_JSON_VALID(configFile);
2106     }
2107     // Invalid: test pmbus_read_sensor with no type.
2108     {
2109         json configFile = pmbusReadSensorFile;
2110         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase("type");
2111         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2112                             "'type' is a required property");
2113     }
2114     // Invalid: test pmbus_read_sensor with no command.
2115     {
2116         json configFile = pmbusReadSensorFile;
2117         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
2118             "command");
2119         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2120                             "'command' is a required property");
2121     }
2122     // Invalid: test pmbus_read_sensor with no format.
2123     {
2124         json configFile = pmbusReadSensorFile;
2125         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"].erase(
2126             "format");
2127         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2128                             "'format' is a required property");
2129     }
2130     // Invalid: test pmbus_read_sensor with property type wrong type.
2131     {
2132         json configFile = pmbusReadSensorFile;
2133         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
2134             true;
2135         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2136                             "True is not of type 'string'");
2137     }
2138     // Invalid: test pmbus_read_sensor with property command wrong type.
2139     {
2140         json configFile = pmbusReadSensorFile;
2141         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
2142             true;
2143         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2144                             "True is not of type 'string'");
2145     }
2146     // Invalid: test pmbus_read_sensor with property format wrong type.
2147     {
2148         json configFile = pmbusReadSensorFile;
2149         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
2150             true;
2151         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2152                             "True is not of type 'string'");
2153     }
2154     // Invalid: test pmbus_read_sensor with property exponent wrong type.
2155     {
2156         json configFile = pmbusReadSensorFile;
2157         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["exponent"] =
2158             true;
2159         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2160                             "True is not of type 'integer'");
2161     }
2162     // Invalid: test pmbus_read_sensor with property type wrong format.
2163     {
2164         json configFile = pmbusReadSensorFile;
2165         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["type"] =
2166             "foo";
2167         EXPECT_JSON_INVALID(
2168             configFile, "Validation failed.",
2169             "'foo' is not one of ['iout', 'iout_peak', 'iout_valley', "
2170             "'pout', 'temperature', 'temperature_peak', 'vout', "
2171             "'vout_peak', 'vout_valley']");
2172     }
2173     // Invalid: test pmbus_read_sensor with property command wrong format.
2174     {
2175         json configFile = pmbusReadSensorFile;
2176         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["command"] =
2177             "0x8B0";
2178         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2179                             "'0x8B0' does not match '^0x[0-9a-fA-F]{2}$'");
2180     }
2181     // Invalid: test pmbus_read_sensor with property format wrong format.
2182     {
2183         json configFile = pmbusReadSensorFile;
2184         configFile["rules"][0]["actions"][1]["pmbus_read_sensor"]["format"] =
2185             "foo";
2186         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2187                             "'foo' is not one of ['linear_11', 'linear_16']");
2188     }
2189 }
2190 TEST(ValidateRegulatorsConfigTest, PmbusWriteVoutCommand)
2191 {
2192     json pmbusWriteVoutCommandFile = validConfigFile;
2193     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
2194                              ["pmbus_write_vout_command"]["volts"] = 1.03;
2195     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
2196                              ["pmbus_write_vout_command"]["format"] = "linear";
2197     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
2198                              ["pmbus_write_vout_command"]["exponent"] = -8;
2199     pmbusWriteVoutCommandFile["rules"][0]["actions"][1]
2200                              ["pmbus_write_vout_command"]["is_verified"] = true;
2201     // Valid: test pmbus_write_vout_command.
2202     {
2203         json configFile = pmbusWriteVoutCommandFile;
2204         EXPECT_JSON_VALID(configFile);
2205     }
2206     // Valid: test pmbus_write_vout_command with required properties.
2207     {
2208         json configFile = pmbusWriteVoutCommandFile;
2209         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
2210             "volts");
2211         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
2212             "exponent");
2213         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
2214             "is_verified");
2215         EXPECT_JSON_VALID(configFile);
2216     }
2217     // Invalid: test pmbus_write_vout_command with no format.
2218     {
2219         json configFile = pmbusWriteVoutCommandFile;
2220         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"].erase(
2221             "format");
2222         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2223                             "'format' is a required property");
2224     }
2225     // Invalid: test pmbus_write_vout_command with property volts wrong type.
2226     {
2227         json configFile = pmbusWriteVoutCommandFile;
2228         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2229                   ["volts"] = true;
2230         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2231                             "True is not of type 'number'");
2232     }
2233     // Invalid: test pmbus_write_vout_command with property format wrong type.
2234     {
2235         json configFile = pmbusWriteVoutCommandFile;
2236         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2237                   ["format"] = true;
2238         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2239                             "True is not of type 'string'");
2240     }
2241     // Invalid: test pmbus_write_vout_command with property exponent wrong type.
2242     {
2243         json configFile = pmbusWriteVoutCommandFile;
2244         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2245                   ["exponent"] = 1.3;
2246         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2247                             "1.3 is not of type 'integer'");
2248     }
2249     // Invalid: test pmbus_write_vout_command with property is_verified wrong
2250     // type.
2251     {
2252         json configFile = pmbusWriteVoutCommandFile;
2253         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2254                   ["is_verified"] = 1;
2255         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2256                             "1 is not of type 'boolean'");
2257     }
2258     // Invalid: test pmbus_write_vout_command with property format wrong format.
2259     {
2260         json configFile = pmbusWriteVoutCommandFile;
2261         configFile["rules"][0]["actions"][1]["pmbus_write_vout_command"]
2262                   ["format"] = "foo";
2263         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2264                             "'foo' is not one of ['linear']");
2265     }
2266 }
2267 TEST(ValidateRegulatorsConfigTest, PresenceDetection)
2268 {
2269     json presenceDetectionFile = validConfigFile;
2270     presenceDetectionFile
2271         ["chassis"][0]["devices"][0]["presence_detection"]["comments"][0] =
2272             "Regulator is only present on the FooBar backplane";
2273     presenceDetectionFile["chassis"][0]["devices"][0]["presence_detection"]
2274                          ["rule_id"] = "set_voltage_rule";
2275     // Valid: test presence_detection with only property rule_id.
2276     {
2277         json configFile = presenceDetectionFile;
2278         EXPECT_JSON_VALID(configFile);
2279     }
2280     // Valid: test presence_detection with only property actions.
2281     {
2282         json configFile = presenceDetectionFile;
2283         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2284             "rule_id");
2285         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2286                   [0]["compare_presence"]["fru"] =
2287                       "system/chassis/motherboard/cpu3";
2288         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2289                   [0]["compare_presence"]["value"] = true;
2290         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2291             "comments");
2292         EXPECT_JSON_VALID(configFile);
2293     }
2294     // Invalid: test presence_detection with both property rule_id and actions.
2295     {
2296         json configFile = presenceDetectionFile;
2297         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2298                   [0]["compare_presence"]["fru"] =
2299                       "system/chassis/motherboard/cpu3";
2300         configFile["chassis"][0]["devices"][0]["presence_detection"]["actions"]
2301                   [0]["compare_presence"]["value"] = true;
2302         EXPECT_JSON_INVALID(
2303             configFile, "Validation failed.",
2304             "{'actions': [{'compare_presence': {'fru': "
2305             "'system/chassis/motherboard/cpu3', 'value': True}}], 'comments': "
2306             "['Regulator is only present on the FooBar backplane'], 'rule_id': "
2307             "'set_voltage_rule'} is valid under each of {'required': "
2308             "['actions']}, {'required': ['rule_id']}");
2309     }
2310     // Invalid: test presence_detection with no rule_id and actions.
2311     {
2312         json configFile = presenceDetectionFile;
2313         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2314             "rule_id");
2315         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2316                             "'rule_id' is a required property");
2317     }
2318     // Invalid: test presence_detection with property comments wrong type.
2319     {
2320         json configFile = presenceDetectionFile;
2321         configFile["chassis"][0]["devices"][0]["presence_detection"]
2322                   ["comments"] = true;
2323         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2324                             "True is not of type 'array'");
2325     }
2326     // Invalid: test presence_detection with property rule_id wrong type.
2327     {
2328         json configFile = presenceDetectionFile;
2329         configFile["chassis"][0]["devices"][0]["presence_detection"]
2330                   ["rule_id"] = true;
2331         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2332                             "True is not of type 'string'");
2333     }
2334     // Invalid: test presence_detection with property actions wrong type.
2335     {
2336         json configFile = presenceDetectionFile;
2337         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2338             "rule_id");
2339         configFile["chassis"][0]["devices"][0]["presence_detection"]
2340                   ["actions"] = true;
2341         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2342                             "True is not of type 'array'");
2343     }
2344     // Invalid: test presence_detection with property rule_id wrong format.
2345     {
2346         json configFile = presenceDetectionFile;
2347         configFile["chassis"][0]["devices"][0]["presence_detection"]
2348                   ["rule_id"] = "id@";
2349         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2350                             "'id@' does not match '^[A-Za-z0-9_]+$'");
2351     }
2352     // Invalid: test presence_detection with property comments empty array.
2353     {
2354         json configFile = presenceDetectionFile;
2355         configFile["chassis"][0]["devices"][0]["presence_detection"]
2356                   ["comments"] = json::array();
2357         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2358                             "[] is too short");
2359     }
2360     // Invalid: test presence_detection with property actions empty array.
2361     {
2362         json configFile = presenceDetectionFile;
2363         configFile["chassis"][0]["devices"][0]["presence_detection"].erase(
2364             "rule_id");
2365         configFile["chassis"][0]["devices"][0]["presence_detection"]
2366                   ["actions"] = json::array();
2367         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2368                             "[] is too short");
2369     }
2370 }
2371 TEST(ValidateRegulatorsConfigTest, Rail)
2372 {
2373     // Valid: test rail.
2374     {
2375         json configFile = validConfigFile;
2376         EXPECT_JSON_VALID(configFile);
2377     }
2378     // Valid: test rail with required properties.
2379     {
2380         json configFile = validConfigFile;
2381         configFile["chassis"][0]["devices"][0]["rails"][0].erase("comments");
2382         configFile["chassis"][0]["devices"][0]["rails"][0].erase(
2383             "configuration");
2384         configFile["chassis"][0]["devices"][0]["rails"][0].erase(
2385             "sensor_monitoring");
2386         EXPECT_JSON_VALID(configFile);
2387     }
2388     // Invalid: test rail with no id.
2389     {
2390         json configFile = validConfigFile;
2391         configFile["chassis"][0]["devices"][0]["rails"][0].erase("id");
2392         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2393                             "'id' is a required property");
2394     }
2395     // Invalid: test rail with comments wrong type.
2396     {
2397         json configFile = validConfigFile;
2398         configFile["chassis"][0]["devices"][0]["rails"][0]["comments"] = true;
2399         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2400                             "True is not of type 'array'");
2401     }
2402     // Invalid: test rail with id wrong type.
2403     {
2404         json configFile = validConfigFile;
2405         configFile["chassis"][0]["devices"][0]["rails"][0]["id"] = true;
2406         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2407                             "True is not of type 'string'");
2408     }
2409     // Invalid: test rail with configuration wrong type.
2410     {
2411         json configFile = validConfigFile;
2412         configFile["chassis"][0]["devices"][0]["rails"][0]["configuration"] =
2413             true;
2414         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2415                             "True is not of type 'object'");
2416     }
2417     // Invalid: test rail with sensor_monitoring wrong type.
2418     {
2419         json configFile = validConfigFile;
2420         configFile["chassis"][0]["devices"][0]["rails"][0]
2421                   ["sensor_monitoring"] = true;
2422         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2423                             "True is not of type 'object'");
2424     }
2425     // Invalid: test rail with comments empty array.
2426     {
2427         json configFile = validConfigFile;
2428         configFile["chassis"][0]["devices"][0]["rails"][0]["comments"] =
2429             json::array();
2430         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2431                             "[] is too short");
2432     }
2433     // Invalid: test rail with id wrong format.
2434     {
2435         json configFile = validConfigFile;
2436         configFile["chassis"][0]["devices"][0]["rails"][0]["id"] = "id~";
2437         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2438                             "'id~' does not match '^[A-Za-z0-9_]+$'");
2439     }
2440 }
2441 TEST(ValidateRegulatorsConfigTest, Rule)
2442 {
2443     // valid test comments property, id property,
2444     // action property specified.
2445     {
2446         json configFile = validConfigFile;
2447         EXPECT_JSON_VALID(configFile);
2448     }
2449 
2450     // valid test rule with no comments
2451     {
2452         json configFile = validConfigFile;
2453         configFile["rules"][0].erase("comments");
2454         EXPECT_JSON_VALID(configFile);
2455     }
2456 
2457     // invalid test comments property has invalid value type
2458     {
2459         json configFile = validConfigFile;
2460         configFile["rules"][0]["comments"] = {1};
2461         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2462                             "1 is not of type 'string'");
2463     }
2464 
2465     // invalid test rule with no ID
2466     {
2467         json configFile = validConfigFile;
2468         configFile["rules"][0].erase("id");
2469         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2470                             "'id' is a required property");
2471     }
2472 
2473     // invalid test id property has invalid value type (not string)
2474     {
2475         json configFile = validConfigFile;
2476         configFile["rules"][0]["id"] = true;
2477         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2478                             "True is not of type 'string'");
2479     }
2480 
2481     // invalid test id property has invalid value
2482     {
2483         json configFile = validConfigFile;
2484         configFile["rules"][0]["id"] = "foo%";
2485         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2486                             "'foo%' does not match '^[A-Za-z0-9_]+$'");
2487     }
2488 
2489     // invalid test rule with no actions property
2490     {
2491         json configFile = validConfigFile;
2492         configFile["rules"][0].erase("actions");
2493         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2494                             "'actions' is a required property");
2495     }
2496 
2497     // valid test rule with multiple actions
2498     {
2499         json configFile = validConfigFile;
2500         configFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
2501         EXPECT_JSON_VALID(configFile);
2502     }
2503 
2504     // invalid test actions property has invalid value type (not an array)
2505     {
2506         json configFile = validConfigFile;
2507         configFile["rules"][0]["actions"] = 1;
2508         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2509                             "1 is not of type 'array'");
2510     }
2511 
2512     // invalid test actions property has invalid value of action
2513     {
2514         json configFile = validConfigFile;
2515         configFile["rules"][0]["actions"][0] = "foo";
2516         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2517                             "'foo' is not of type 'object'");
2518     }
2519 
2520     // invalid test actions property has empty array
2521     {
2522         json configFile = validConfigFile;
2523         configFile["rules"][0]["actions"] = json::array();
2524         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2525                             "[] is too short");
2526     }
2527 }
2528 TEST(ValidateRegulatorsConfigTest, RunRule)
2529 {
2530     json runRuleFile = validConfigFile;
2531     runRuleFile["rules"][0]["actions"][1]["run_rule"] = "read_sensors_rule";
2532     // Valid: test run_rule.
2533     {
2534         json configFile = runRuleFile;
2535         EXPECT_JSON_VALID(configFile);
2536     }
2537     // Invalid: test run_rule wrong type.
2538     {
2539         json configFile = runRuleFile;
2540         configFile["rules"][0]["actions"][1]["run_rule"] = true;
2541         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2542                             "True is not of type 'string'");
2543     }
2544     // Invalid: test run_rule wrong format.
2545     {
2546         json configFile = runRuleFile;
2547         configFile["rules"][0]["actions"][1]["run_rule"] = "set_voltage_rule%";
2548         EXPECT_JSON_INVALID(
2549             configFile, "Validation failed.",
2550             "'set_voltage_rule%' does not match '^[A-Za-z0-9_]+$'");
2551     }
2552 }
2553 TEST(ValidateRegulatorsConfigTest, SensorMonitoring)
2554 {
2555     // Valid: test rails sensor_monitoring with only property rule id.
2556     {
2557         json configFile = validConfigFile;
2558         EXPECT_JSON_VALID(configFile);
2559     }
2560     // Valid: test rails sensor_monitoring with only property actions.
2561     {
2562         json configFile = validConfigFile;
2563         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2564             .erase("rule_id");
2565         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2566                   ["actions"][0]["compare_presence"]["fru"] =
2567                       "system/chassis/motherboard/cpu3";
2568         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2569                   ["actions"][0]["compare_presence"]["value"] = true;
2570         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2571                   ["comments"][0] = "comments";
2572         EXPECT_JSON_VALID(configFile);
2573     }
2574     // Invalid: test rails sensor_monitoring with both property rule_id and
2575     // actions.
2576     {
2577         json configFile = validConfigFile;
2578         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2579                   ["actions"][0]["compare_presence"]["fru"] =
2580                       "system/chassis/motherboard/cpu3";
2581         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2582                   ["actions"][0]["compare_presence"]["value"] = true;
2583         EXPECT_JSON_INVALID(
2584             configFile, "Validation failed.",
2585             "{'actions': [{'compare_presence': {'fru': "
2586             "'system/chassis/motherboard/cpu3', 'value': True}}], 'rule_id': "
2587             "'read_sensors_rule'} is valid under each of {'required': "
2588             "['actions']}, {'required': ['rule_id']}");
2589     }
2590     // Invalid: test rails sensor_monitoring with no rule_id and actions.
2591     {
2592         json configFile = validConfigFile;
2593         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2594             .erase("rule_id");
2595         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2596                             "'rule_id' is a required property");
2597     }
2598     // Invalid: test rails sensor_monitoring with property comments wrong type.
2599     {
2600         json configFile = validConfigFile;
2601         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2602                   ["comments"] = true;
2603         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2604                             "True is not of type 'array'");
2605     }
2606     // Invalid: test rails sensor_monitoring with property rule_id wrong type.
2607     {
2608         json configFile = validConfigFile;
2609         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2610                   ["rule_id"] = true;
2611         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2612                             "True is not of type 'string'");
2613     }
2614     // Invalid: test rails sensor_monitoring with property actions wrong type.
2615     {
2616         json configFile = validConfigFile;
2617         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2618             .erase("rule_id");
2619         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2620                   ["actions"] = true;
2621         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2622                             "True is not of type 'array'");
2623     }
2624     // Invalid: test rails sensor_monitoring with property rule_id wrong format.
2625     {
2626         json configFile = validConfigFile;
2627         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2628                   ["rule_id"] = "id@";
2629         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2630                             "'id@' does not match '^[A-Za-z0-9_]+$'");
2631     }
2632     // Invalid: test rails sensor_monitoring with property comments empty array.
2633     {
2634         json configFile = validConfigFile;
2635         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2636                   ["comments"] = json::array();
2637         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2638                             "[] is too short");
2639     }
2640     // Invalid: test rails sensor_monitoring with property actions empty array.
2641     {
2642         json configFile = validConfigFile;
2643         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2644             .erase("rule_id");
2645         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2646                   ["actions"] = json::array();
2647         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2648                             "[] is too short");
2649     }
2650 }
2651 TEST(ValidateRegulatorsConfigTest, SetDevice)
2652 {
2653     json setDeviceFile = validConfigFile;
2654     setDeviceFile["rules"][0]["actions"][1]["set_device"] = "vdd_regulator";
2655     // Valid: test set_device.
2656     {
2657         json configFile = setDeviceFile;
2658         EXPECT_JSON_VALID(configFile);
2659     }
2660     // Invalid: test set_device wrong type.
2661     {
2662         json configFile = setDeviceFile;
2663         configFile["rules"][0]["actions"][1]["set_device"] = true;
2664         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2665                             "True is not of type 'string'");
2666     }
2667     // Invalid: test set_device wrong format.
2668     {
2669         json configFile = setDeviceFile;
2670         configFile["rules"][0]["actions"][1]["set_device"] = "io_expander2%";
2671         EXPECT_JSON_INVALID(configFile, "Validation failed.",
2672                             "'io_expander2%' does not match '^[A-Za-z0-9_]+$'");
2673     }
2674 }
2675 TEST(ValidateRegulatorsConfigTest, DuplicateRuleID)
2676 {
2677     // Invalid: test duplicate ID in rule.
2678     {
2679         json configFile = validConfigFile;
2680         configFile["rules"][2]["id"] = "set_voltage_rule";
2681         configFile["rules"][2]["actions"][0]["pmbus_write_vout_command"]
2682                   ["format"] = "linear";
2683         EXPECT_JSON_INVALID(configFile, "Error: Duplicate rule ID.", "");
2684     }
2685 }
2686 TEST(ValidateRegulatorsConfigTest, DuplicateChassisNumber)
2687 {
2688     // Invalid: test duplicate number in chassis.
2689     {
2690         json configFile = validConfigFile;
2691         configFile["chassis"][1]["number"] = 1;
2692         EXPECT_JSON_INVALID(configFile, "Error: Duplicate chassis number.", "");
2693     }
2694 }
2695 TEST(ValidateRegulatorsConfigTest, DuplicateDeviceID)
2696 {
2697     // Invalid: test duplicate ID in device.
2698     {
2699         json configFile = validConfigFile;
2700         configFile["chassis"][0]["devices"][1]["id"] = "vdd_regulator";
2701         configFile["chassis"][0]["devices"][1]["is_regulator"] = true;
2702         configFile["chassis"][0]["devices"][1]["fru"] =
2703             "system/chassis/motherboard/regulator1";
2704         configFile["chassis"][0]["devices"][1]["i2c_interface"]["bus"] = 2;
2705         configFile["chassis"][0]["devices"][1]["i2c_interface"]["address"] =
2706             "0x71";
2707         EXPECT_JSON_INVALID(configFile, "Error: Duplicate device ID.", "");
2708     }
2709 }
2710 TEST(ValidateRegulatorsConfigTest, DuplicateRailID)
2711 {
2712     // Invalid: test duplicate ID in rail.
2713     {
2714         json configFile = validConfigFile;
2715         configFile["chassis"][0]["devices"][0]["rails"][1]["id"] = "vdd";
2716         EXPECT_JSON_INVALID(configFile, "Error: Duplicate rail ID.", "");
2717     }
2718 }
2719 TEST(ValidateRegulatorsConfigTest, DuplicateObjectID)
2720 {
2721     // Invalid: test duplicate object ID in device and rail.
2722     {
2723         json configFile = validConfigFile;
2724         configFile["chassis"][0]["devices"][0]["rails"][1]["id"] =
2725             "vdd_regulator";
2726         EXPECT_JSON_INVALID(configFile, "Error: Duplicate ID.", "");
2727     }
2728     // Invalid: test duplicate object ID in device and rule.
2729     {
2730         json configFile = validConfigFile;
2731         configFile["rules"][2]["id"] = "vdd_regulator";
2732         configFile["rules"][2]["actions"][0]["pmbus_write_vout_command"]
2733                   ["format"] = "linear";
2734         EXPECT_JSON_INVALID(configFile, "Error: Duplicate ID.", "");
2735     }
2736     // Invalid: test duplicate object ID in rule and rail.
2737     {
2738         json configFile = validConfigFile;
2739         configFile["chassis"][0]["devices"][0]["rails"][1]["id"] =
2740             "set_voltage_rule";
2741         EXPECT_JSON_INVALID(configFile, "Error: Duplicate ID.", "");
2742     }
2743 }
2744 TEST(ValidateRegulatorsConfigTest, InfiniteLoops)
2745 {
2746     // Invalid: test run_rule with infinite loop (rules run each other).
2747     {
2748         json configFile = validConfigFile;
2749         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2750         configFile["rules"][2]["id"] = "set_voltage_rule1";
2751         configFile["rules"][3]["actions"][0]["run_rule"] = "set_voltage_rule1";
2752         configFile["rules"][3]["id"] = "set_voltage_rule2";
2753         EXPECT_JSON_INVALID(configFile,
2754                             "Infinite loop caused by run_rule actions.", "");
2755     }
2756     // Invalid: test run_rule with infinite loop (rule runs itself).
2757     {
2758         json configFile = validConfigFile;
2759         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule1";
2760         configFile["rules"][2]["id"] = "set_voltage_rule1";
2761         EXPECT_JSON_INVALID(configFile,
2762                             "Infinite loop caused by run_rule actions.", "");
2763     }
2764     // Invalid: test run_rule with infinite loop (indirect loop).
2765     {
2766         json configFile = validConfigFile;
2767         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2768         configFile["rules"][2]["id"] = "set_voltage_rule1";
2769         configFile["rules"][3]["actions"][0]["run_rule"] = "set_voltage_rule3";
2770         configFile["rules"][3]["id"] = "set_voltage_rule2";
2771         configFile["rules"][4]["actions"][0]["run_rule"] = "set_voltage_rule1";
2772         configFile["rules"][4]["id"] = "set_voltage_rule3";
2773         EXPECT_JSON_INVALID(configFile,
2774                             "Infinite loop caused by run_rule actions.", "");
2775     }
2776 }
2777 TEST(ValidateRegulatorsConfigTest, RunRuleValueExists)
2778 {
2779     // Invalid: test run_rule actions specify a rule ID that does not exist.
2780     {
2781         json configFile = validConfigFile;
2782         configFile["rules"][2]["actions"][0]["run_rule"] = "set_voltage_rule2";
2783         configFile["rules"][2]["id"] = "set_voltage_rule1";
2784         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2785     }
2786 }
2787 TEST(ValidateRegulatorsConfigTest, SetDeviceValueExists)
2788 {
2789     // Invalid: test set_device actions specify a device ID that does not exist.
2790     {
2791         json configFile = validConfigFile;
2792         configFile["rules"][2]["actions"][0]["set_device"] = "vdd_regulator2";
2793         configFile["rules"][2]["id"] = "set_voltage_rule1";
2794         EXPECT_JSON_INVALID(configFile, "Error: Device ID does not exist.", "");
2795     }
2796 }
2797 TEST(ValidateRegulatorsConfigTest, RuleIDExists)
2798 {
2799     // Invalid: test rule_id property in configuration specifies a rule ID that
2800     // does not exist.
2801     {
2802         json configFile = validConfigFile;
2803         configFile["chassis"][0]["devices"][0]["configuration"]["rule_id"] =
2804             "set_voltage_rule2";
2805         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2806     }
2807     // Invalid: test rule_id property in presence_detection specifies a rule ID
2808     // that does not exist.
2809     {
2810         json configFile = validConfigFile;
2811         configFile["chassis"][0]["devices"][0]["presence_detection"]
2812                   ["rule_id"] = "set_voltage_rule2";
2813         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2814     }
2815     // Invalid: test rule_id property in sensor_monitoring specifies a rule ID
2816     // that does not exist.
2817     {
2818         json configFile = validConfigFile;
2819         configFile["chassis"][0]["devices"][0]["rails"][0]["sensor_monitoring"]
2820                   ["rule_id"] = "set_voltage_rule2";
2821         EXPECT_JSON_INVALID(configFile, "Error: Rule ID does not exist.", "");
2822     }
2823 }
2824 TEST(ValidateRegulatorsConfigTest, NumberOfElementsInMasks)
2825 {
2826     // Invalid: test number of elements in masks not equal to number in values
2827     // in i2c_compare_bytes.
2828     {
2829         json configFile = validConfigFile;
2830         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["register"] =
2831             "0x82";
2832         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["values"] = {
2833             "0x02", "0x73"};
2834         configFile["rules"][0]["actions"][1]["i2c_compare_bytes"]["masks"] = {
2835             "0x7F"};
2836         EXPECT_JSON_INVALID(configFile,
2837                             "Error: Invalid i2c_compare_bytes action.", "");
2838     }
2839     // Invalid: test number of elements in masks not equal to number in values
2840     // in i2c_write_bytes.
2841     {
2842         json configFile = validConfigFile;
2843         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["register"] =
2844             "0x82";
2845         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["values"] = {
2846             "0x02", "0x73"};
2847         configFile["rules"][0]["actions"][1]["i2c_write_bytes"]["masks"] = {
2848             "0x7F"};
2849         EXPECT_JSON_INVALID(configFile,
2850                             "Error: Invalid i2c_write_bytes action.", "");
2851     }
2852 }
2853 TEST(ValidateRegulatorsConfigTest, CommandLineSyntax)
2854 {
2855     std::string validateTool =
2856         " ../phosphor-regulators/tools/validate-regulators-config.py ";
2857     std::string schema = " -s ";
2858     std::string schemaFile =
2859         " ../phosphor-regulators/schema/config_schema.json ";
2860     std::string configuration = " -c ";
2861     std::string command;
2862     std::string errorMessage;
2863     std::string outputMessage;
2864     std::string outputMessageHelp =
2865         "usage: validate-regulators-config.py [-h] [-s SCHEMA_FILE]";
2866     int valid = 0;
2867 
2868     TemporaryFile tmpFile;
2869     std::string fileName = tmpFile.getPath().string();
2870     writeDataToFile(validConfigFile, fileName);
2871     // Valid: -s specified
2872     {
2873         command = validateTool + "-s " + schemaFile + configuration + fileName;
2874         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2875     }
2876     // Valid: --schema-file specified
2877     {
2878         command = validateTool + "--schema-file " + schemaFile + configuration +
2879                   fileName;
2880         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2881     }
2882     // Valid: -c specified
2883     {
2884         command = validateTool + schema + schemaFile + "-c " + fileName;
2885         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2886     }
2887     // Valid: --configuration-file specified
2888     {
2889         command = validateTool + schema + schemaFile + "--configuration-file " +
2890                   fileName;
2891         expectCommandLineSyntax(errorMessage, outputMessage, command, valid);
2892     }
2893     // Valid: -h specified
2894     {
2895         command = validateTool + "-h ";
2896         expectCommandLineSyntax(errorMessage, outputMessageHelp, command,
2897                                 valid);
2898     }
2899     // Valid: --help specified
2900     {
2901         command = validateTool + "--help ";
2902         expectCommandLineSyntax(errorMessage, outputMessageHelp, command,
2903                                 valid);
2904     }
2905     // Invalid: -c/--configuration-file not specified
2906     {
2907         command = validateTool + schema + schemaFile;
2908         expectCommandLineSyntax("Error: Configuration file is required.",
2909                                 outputMessageHelp, command, 1);
2910     }
2911     // Invalid: -s/--schema-file not specified
2912     {
2913         command = validateTool + configuration + fileName;
2914         expectCommandLineSyntax("Error: Schema file is required.",
2915                                 outputMessageHelp, command, 1);
2916     }
2917     // Invalid: -c specified more than once
2918     {
2919         command = validateTool + schema + schemaFile + "-c -c " + fileName;
2920         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2921     }
2922     // Invalid: -s specified more than once
2923     {
2924         command =
2925             validateTool + "-s -s " + schemaFile + configuration + fileName;
2926         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2927     }
2928     // Invalid: No file name specified after -c
2929     {
2930         command = validateTool + schema + schemaFile + configuration;
2931         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2932     }
2933     // Invalid: No file name specified after -s
2934     {
2935         command = validateTool + schema + configuration + fileName;
2936         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
2937     }
2938     // Invalid: File specified after -c does not exist
2939     {
2940         command = validateTool + schema + schemaFile + configuration +
2941                   "../notExistFile";
2942         expectCommandLineSyntax("Error: Configuration file does not exist.",
2943                                 outputMessageHelp, command, 1);
2944     }
2945     // Invalid: File specified after -s does not exist
2946     {
2947         command = validateTool + schema + "../notExistFile " + configuration +
2948                   fileName;
2949         expectCommandLineSyntax("Error: Schema file does not exist.",
2950                                 outputMessageHelp, command, 1);
2951     }
2952     // Invalid: File specified after -c is not right data format
2953     {
2954         TemporaryFile wrongFormatFile;
2955         std::string wrongFormatFileName = wrongFormatFile.getPath().string();
2956         std::ofstream out(wrongFormatFileName);
2957         out << "foo";
2958         out.close();
2959         command = validateTool + schema + schemaFile + configuration +
2960                   wrongFormatFileName;
2961         expectCommandLineSyntax(
2962             "Error: Configuration file is not in the JSON format.",
2963             outputMessageHelp, command, 1);
2964     }
2965     // Invalid: File specified after -s is not right data format
2966     {
2967         TemporaryFile wrongFormatFile;
2968         std::string wrongFormatFileName = wrongFormatFile.getPath().string();
2969         std::ofstream out(wrongFormatFileName);
2970         out << "foo";
2971         out.close();
2972         command = validateTool + schema + wrongFormatFileName + configuration +
2973                   fileName;
2974         expectCommandLineSyntax("Error: Schema file is not in the JSON format.",
2975                                 outputMessageHelp, command, 1);
2976     }
2977     // Invalid: File specified after -c is not readable
2978     {
2979         TemporaryFile notReadableFile;
2980         std::string notReadableFileName = notReadableFile.getPath().string();
2981         writeDataToFile(validConfigFile, notReadableFileName);
2982         command = validateTool + schema + schemaFile + configuration +
2983                   notReadableFileName;
2984         chmod(notReadableFileName.c_str(), 0222);
2985         expectCommandLineSyntax("Error: Configuration file is not readable.",
2986                                 outputMessageHelp, command, 1);
2987     }
2988     // Invalid: File specified after -s is not readable
2989     {
2990         TemporaryFile notReadableFile;
2991         std::string notReadableFileName = notReadableFile.getPath().string();
2992         writeDataToFile(validConfigFile, notReadableFileName);
2993         command = validateTool + schema + notReadableFileName + configuration +
2994                   fileName;
2995         chmod(notReadableFileName.c_str(), 0222);
2996         expectCommandLineSyntax("Error: Schema file is not readable.",
2997                                 outputMessageHelp, command, 1);
2998     }
2999     // Invalid: Unexpected parameter specified (like -g)
3000     {
3001         command = validateTool + schema + schemaFile + configuration +
3002                   fileName + " -g";
3003         expectCommandLineSyntax(outputMessageHelp, outputMessage, command, 2);
3004     }
3005 }
3006