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