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