@@ -44,6 +44,17 @@ namespace jse
4444
4545 // ////////// PRIVATE
4646
47+ namespace
48+ {
49+ std::string append_pointer (const std::string &pointer, const std::string &key)
50+ {
51+ if (pointer == " /" )
52+ return " /" + key;
53+ else
54+ return pointer + " /" + key;
55+ }
56+ } // namespace
57+
4758 bool JSE::verify_json (const string &pointer, json &input, const json &rules)
4859 {
4960 // if (pointer == "/common")
@@ -56,14 +67,10 @@ namespace jse
5667 if (matching_rules.empty ())
5768 {
5869 log.push_back (log_item (" warning" , " Unknown entry " + pointer));
59-
60- if (strict)
61- return false ;
62- else
63- return true ;
70+ return !strict;
6471 }
6572
66- // Test all rules, only one must pass, otherwise throw exception
73+ // Test all rules, one and only one must pass, otherwise throw exception
6774 int count = 0 ;
6875 json single_matched_rule;
6976
@@ -76,12 +83,12 @@ namespace jse
7683 }
7784 }
7885
79- if (count == 0 && !matching_rules. empty () )
86+ if (count == 0 )
8087 {
8188 // Before giving up, try boxing a primitive type
8289 if (boxing_primitive && !input.is_array ())
8390 {
84- string new_pointer = (pointer == " / " ? " " : pointer) + " /* " ;
91+ string new_pointer = append_pointer (pointer, " * " ) ;
8592 // Make sure there are some rules for the boxed version before recursively checking
8693 if (collect_pointer (new_pointer, rules).size () > 0 )
8794 if (verify_json (new_pointer, input, rules))
@@ -96,8 +103,7 @@ namespace jse
96103 log.push_back (log_item (" error" , s.str ()));
97104 return false ;
98105 }
99-
100- if (count > 1 )
106+ else if (count > 1 )
101107 {
102108 std::stringstream s;
103109 s << " Multiple rules matched for \" " << pointer << " \" : " << input.dump (/* indent=*/ 4 ) << std::endl;
@@ -110,14 +116,15 @@ namespace jse
110116
111117 // If it passes and if it is a dictionary, then test all childrens
112118 if (input.is_object ())
113- for (auto &i : input.items ())
119+ {
120+ for (const auto &[key, value] : input.items ())
114121 {
115- string new_pointer = (pointer == " / " ? " " : pointer) + " / " + i. key ( );
122+ const string new_pointer = append_pointer (pointer, key);
116123 // first of all, let's check if the specs are correct
117- json defaults = collect_default_rules (new_pointer, rules);
124+ const json defaults = collect_default_rules (new_pointer, rules);
118125
119126 // if it is mandatory, make sure there are no defaults
120- if (single_matched_rule.contains (" required" ) && contained_in_list (i. key () , single_matched_rule[" required" ]))
127+ if (single_matched_rule.contains (" required" ) && contained_in_list (key, single_matched_rule[" required" ]))
121128 {
122129 if (defaults.size () != 0 )
123130 {
@@ -126,7 +133,7 @@ namespace jse
126133 }
127134 }
128135 // if it is optional, there should be only one default in the specs
129- else if (single_matched_rule.contains (" optional" ) && contained_in_list (i. key () , single_matched_rule[" optional" ]))
136+ else if (single_matched_rule.contains (" optional" ) && contained_in_list (key, single_matched_rule[" optional" ]))
130137 {
131138 if (defaults.size () != 1 )
132139 {
@@ -143,50 +150,52 @@ namespace jse
143150 }
144151
145152 // now let's make sure it can be validated
146- if (!verify_json (new_pointer, i. value () , rules))
153+ if (!verify_json (new_pointer, value, rules))
147154 return false ;
148155 }
156+ }
149157
150158 // If the dictionary is valid and has optional fields, add defaults for the optional fields
151159
152- if (input.is_object () || input.is_null ()) // Note: null fields might be objects, and thus might have optional fields
153- if (single_matched_rule.contains (" optional" )) // the object has a list of optional
160+ if ((input.is_object () || input.is_null ()) // Note: null fields might be objects, and thus might have optional fields
161+ && single_matched_rule.contains (" optional" )) // <- the object has a list of optional
162+ {
163+ for (const std::string &key : single_matched_rule[" optional" ]) // for each optional field
154164 {
155- // std::cout << "Before adding: " << input << std::endl;
156- for (auto &i : single_matched_rule[" optional" ]) // for each optional field
157- if (!input.contains (i)) // if not already in the object
158- {
159- string new_pointer = (pointer == " /" ? " " : pointer) + " /" + string (i);
160- json defaults = collect_default_rules (new_pointer, rules); // Find the default
161- if (defaults.size () != 1 )
162- {
163- log.push_back (log_item (" error" , " Inconsistent specifications: " + new_pointer + " is an optional field with " + std::to_string (defaults.size ()) + " default values." ));
164- return false ;
165- }
166- if (defaults[0 ][" default" ] != " skip" )
167- {
168- input[string (i)] = defaults[0 ][" default" ];
169-
170- // Let's validate/inject the default subtree
171- if (!verify_json (new_pointer, input[string (i)], rules))
172- return false ;
173- }
174- }
175- // std::cout << "After adding: " << input << std::endl;
165+ if (input.contains (key)) // skip if already in the object
166+ continue ;
167+
168+ string new_pointer = append_pointer (pointer, key);
169+ json defaults = collect_default_rules (new_pointer, rules); // Find the default
170+ if (defaults.size () != 1 )
171+ {
172+ log.push_back (log_item (" error" , " Inconsistent specifications: " + new_pointer + " is an optional field with " + std::to_string (defaults.size ()) + " default values." ));
173+ return false ;
174+ }
175+ if (defaults[0 ][" default" ] != " skip" )
176+ {
177+ input[key] = defaults[0 ][" default" ];
178+
179+ // Let's validate/inject the default subtree
180+ if (!verify_json (new_pointer, input[key], rules))
181+ return false ;
182+ }
176183 }
184+ }
177185
178186 // In case of a list
179187 // All the elements in the list must pass the test
180188 if (input.is_array ())
181189 {
182190 for (auto &i : input)
183- if (!verify_json ((pointer == " / " ? " " : pointer) + " /* " , i, rules))
191+ if (!verify_json (append_pointer (pointer, " * " ) , i, rules))
184192 return false ;
185193 }
186194
187195 // If they all pass, return true
188196 return true ;
189- };
197+ }
198+
190199 bool JSE::verify_rule (const json &input, const json &rule)
191200 {
192201 // std::cout << "Verifying " << input << std::endl;
@@ -212,7 +221,8 @@ namespace jse
212221 log.push_back (log_item (" error" , " Unknown rule type " + type));
213222 return false ;
214223 }
215- };
224+ }
225+
216226 bool JSE::verify_rule_file (const json &input, const json &rule)
217227 {
218228 assert (rule.at (" type" ) == " file" );
@@ -242,7 +252,8 @@ namespace jse
242252 }
243253
244254 return true ;
245- };
255+ }
256+
246257 bool JSE::verify_rule_folder (const json &input, const json &rule)
247258 {
248259 assert (rule.at (" type" ) == " folder" );
@@ -258,7 +269,8 @@ namespace jse
258269 }
259270
260271 return true ;
261- };
272+ }
273+
262274 bool JSE::verify_rule_float (const json &input, const json &rule)
263275 {
264276 assert (rule.at (" type" ) == " float" );
@@ -273,7 +285,8 @@ namespace jse
273285 return false ;
274286
275287 return true ;
276- };
288+ }
289+
277290 bool JSE::verify_rule_int (const json &input, const json &rule)
278291 {
279292 assert (rule.at (" type" ) == " int" );
@@ -288,7 +301,8 @@ namespace jse
288301 return false ;
289302
290303 return true ;
291- };
304+ }
305+
292306 bool JSE::verify_rule_string (const json &input, const json &rule)
293307 {
294308 assert (rule.at (" type" ) == " string" );
@@ -307,7 +321,7 @@ namespace jse
307321 }
308322
309323 return true ;
310- };
324+ }
311325 bool JSE::verify_rule_object (const json &input, const json &rule)
312326 {
313327 assert (rule.at (" type" ) == " object" );
@@ -320,21 +334,17 @@ namespace jse
320334 if (!input.contains (string (e)))
321335 return false ;
322336
323- if (rule.contains (" type_name" ))
324- if (!input.contains (" type" ) || input[" type" ] != rule[" type_name" ])
325- return false ;
337+ if (rule.contains (" type_name" )
338+ && (!input.contains (" type" ) || input[" type" ] != rule[" type_name" ]) )
339+ return false ;
326340
327341 return true ;
328- };
342+ }
329343 bool JSE::verify_rule_bool (const json &input, const json &rule)
330344 {
331345 assert (rule.at (" type" ) == " bool" );
332-
333- if (!input.is_boolean ())
334- return false ;
335-
336- return true ;
337- };
346+ return input.is_boolean ();
347+ }
338348
339349 bool JSE::verify_rule_list (const json &input, const json &rule)
340350 {
@@ -343,14 +353,14 @@ namespace jse
343353 if (!input.is_array ())
344354 return false ;
345355
346- if (rule.contains (" min" ) && !( input.size () >= rule[" min" ]) )
356+ if (rule.contains (" min" ) && input.size () < rule[" min" ])
347357 return false ;
348358
349- if (rule.contains (" max" ) && !( input.size () <= rule[" max" ]) )
359+ if (rule.contains (" max" ) && input.size () > rule[" max" ])
350360 return false ;
351361
352362 return true ;
353- };
363+ }
354364
355365 json JSE::collect_default_rules (const json &rules)
356366 {
@@ -365,7 +375,7 @@ namespace jse
365375 }
366376
367377 return matching_rules;
368- };
378+ }
369379
370380 json JSE::collect_default_rules (const string &pointer, const json &rules)
371381 {
@@ -380,12 +390,12 @@ namespace jse
380390 }
381391
382392 return matching_rules;
383- };
393+ }
384394
385395 bool JSE::contained_in_list (string item, const json &list)
386396 {
387397 return std::find (list.begin (), list.end (), item) != list.end ();
388- };
398+ }
389399
390400 std::vector<json> JSE::collect_pointer (const string &pointer, const json &rules)
391401 {
@@ -396,7 +406,7 @@ namespace jse
396406 matching_rules.push_back (i);
397407 }
398408 return matching_rules;
399- };
409+ }
400410
401411 json JSE::find_valid_rule (const string &pointer, const json &input, const json &rules)
402412 {
@@ -405,7 +415,7 @@ namespace jse
405415 return i;
406416
407417 return json ();
408- };
418+ }
409419
410420 std::tuple<bool , string> JSE::is_subset_pointer (const string &json, const string &pointer)
411421 {
@@ -480,6 +490,6 @@ namespace jse
480490 }
481491
482492 return {true , buf};
483- };
493+ }
484494
485495} // namespace jse
0 commit comments