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