Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: chrome/common/json_schema/json_schema_validator.cc

Issue 22807004: Moved chrome/common/json_schema to components/json_schema. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed android isolates Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/common/json_schema/json_schema_validator.h"
6
7 #include <algorithm>
8 #include <cfloat>
9 #include <cmath>
10
11 #include "base/json/json_reader.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/values.h"
16 #include "chrome/common/json_schema/json_schema_constants.h"
17 #include "ui/base/l10n/l10n_util.h"
18
19 namespace schema = json_schema_constants;
20
21 namespace {
22
23 double GetNumberValue(const base::Value* value) {
24 double result = 0;
25 CHECK(value->GetAsDouble(&result))
26 << "Unexpected value type: " << value->GetType();
27 return result;
28 }
29
30 bool IsValidType(const std::string& type) {
31 static const char* kValidTypes[] = {
32 schema::kAny,
33 schema::kArray,
34 schema::kBoolean,
35 schema::kInteger,
36 schema::kNull,
37 schema::kNumber,
38 schema::kObject,
39 schema::kString,
40 };
41 const char** end = kValidTypes + arraysize(kValidTypes);
42 return std::find(kValidTypes, end, type) != end;
43 }
44
45 // Maps a schema attribute name to its expected type.
46 struct ExpectedType {
47 const char* key;
48 base::Value::Type type;
49 };
50
51 // Helper for std::lower_bound.
52 bool CompareToString(const ExpectedType& entry, const std::string& key) {
53 return entry.key < key;
54 }
55
56 bool IsValidSchema(const base::DictionaryValue* dict, std::string* error) {
57 // This array must be sorted, so that std::lower_bound can perform a
58 // binary search.
59 static const ExpectedType kExpectedTypes[] = {
60 // Note: kRef == "$ref", kSchema == "$schema"
61 { schema::kRef, base::Value::TYPE_STRING },
62 { schema::kSchema, base::Value::TYPE_STRING },
63
64 { schema::kAdditionalProperties, base::Value::TYPE_DICTIONARY },
65 { schema::kChoices, base::Value::TYPE_LIST },
66 { schema::kDescription, base::Value::TYPE_STRING },
67 { schema::kEnum, base::Value::TYPE_LIST },
68 { schema::kId, base::Value::TYPE_STRING },
69 { schema::kMaxItems, base::Value::TYPE_INTEGER },
70 { schema::kMaxLength, base::Value::TYPE_INTEGER },
71 { schema::kMaximum, base::Value::TYPE_DOUBLE },
72 { schema::kMinItems, base::Value::TYPE_INTEGER },
73 { schema::kMinLength, base::Value::TYPE_INTEGER },
74 { schema::kMinimum, base::Value::TYPE_DOUBLE },
75 { schema::kOptional, base::Value::TYPE_BOOLEAN },
76 { schema::kProperties, base::Value::TYPE_DICTIONARY },
77 { schema::kTitle, base::Value::TYPE_STRING },
78 };
79
80 bool has_type = false;
81 const base::ListValue* list_value = NULL;
82 const base::DictionaryValue* dictionary_value = NULL;
83 std::string string_value;
84
85 for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
86 // Validate the "type" attribute, which may be a string or a list.
87 if (it.key() == schema::kType) {
88 switch (it.value().GetType()) {
89 case base::Value::TYPE_STRING:
90 it.value().GetAsString(&string_value);
91 if (!IsValidType(string_value)) {
92 *error = "Invalid value for type attribute";
93 return false;
94 }
95 break;
96 case base::Value::TYPE_LIST:
97 it.value().GetAsList(&list_value);
98 for (size_t i = 0; i < list_value->GetSize(); ++i) {
99 if (!list_value->GetString(i, &string_value) ||
100 !IsValidType(string_value)) {
101 *error = "Invalid value for type attribute";
102 return false;
103 }
104 }
105 break;
106 default:
107 *error = "Invalid value for type attribute";
108 return false;
109 }
110 has_type = true;
111 continue;
112 }
113
114 // Validate the "items" attribute, which is a schema or a list of schemas.
115 if (it.key() == schema::kItems) {
116 if (it.value().GetAsDictionary(&dictionary_value)) {
117 if (!IsValidSchema(dictionary_value, error)) {
118 DCHECK(!error->empty());
119 return false;
120 }
121 } else if (it.value().GetAsList(&list_value)) {
122 for (size_t i = 0; i < list_value->GetSize(); ++i) {
123 if (!list_value->GetDictionary(i, &dictionary_value)) {
124 *error = base::StringPrintf(
125 "Invalid entry in items attribute at index %d",
126 static_cast<int>(i));
127 return false;
128 }
129 if (!IsValidSchema(dictionary_value, error)) {
130 DCHECK(!error->empty());
131 return false;
132 }
133 }
134 } else {
135 *error = "Invalid value for items attribute";
136 return false;
137 }
138 continue;
139 }
140
141 // All the other attributes have a single valid type.
142 const ExpectedType* end = kExpectedTypes + arraysize(kExpectedTypes);
143 const ExpectedType* entry = std::lower_bound(
144 kExpectedTypes, end, it.key(), CompareToString);
145 if (entry == end || entry->key != it.key()) {
146 *error = base::StringPrintf("Invalid attribute %s", it.key().c_str());
147 return false;
148 }
149 if (!it.value().IsType(entry->type)) {
150 *error = base::StringPrintf("Invalid value for %s attribute",
151 it.key().c_str());
152 return false;
153 }
154
155 // base::Value::TYPE_INTEGER attributes must be >= 0.
156 // This applies to "minItems", "maxItems", "minLength" and "maxLength".
157 if (it.value().IsType(base::Value::TYPE_INTEGER)) {
158 int integer_value;
159 it.value().GetAsInteger(&integer_value);
160 if (integer_value < 0) {
161 *error = base::StringPrintf("Value of %s must be >= 0, got %d",
162 it.key().c_str(), integer_value);
163 return false;
164 }
165 }
166
167 // Validate the "properties" attribute. Each entry maps a key to a schema.
168 if (it.key() == schema::kProperties) {
169 it.value().GetAsDictionary(&dictionary_value);
170 for (base::DictionaryValue::Iterator it(*dictionary_value);
171 !it.IsAtEnd(); it.Advance()) {
172 if (!it.value().GetAsDictionary(&dictionary_value)) {
173 *error = "Invalid value for properties attribute";
174 return false;
175 }
176 if (!IsValidSchema(dictionary_value, error)) {
177 DCHECK(!error->empty());
178 return false;
179 }
180 }
181 }
182
183 // Validate "additionalProperties" attribute, which is a schema.
184 if (it.key() == schema::kAdditionalProperties) {
185 it.value().GetAsDictionary(&dictionary_value);
186 if (!IsValidSchema(dictionary_value, error)) {
187 DCHECK(!error->empty());
188 return false;
189 }
190 }
191
192 // Validate the values contained in an "enum" attribute.
193 if (it.key() == schema::kEnum) {
194 it.value().GetAsList(&list_value);
195 for (size_t i = 0; i < list_value->GetSize(); ++i) {
196 const base::Value* value = NULL;
197 list_value->Get(i, &value);
198 switch (value->GetType()) {
199 case base::Value::TYPE_NULL:
200 case base::Value::TYPE_BOOLEAN:
201 case base::Value::TYPE_INTEGER:
202 case base::Value::TYPE_DOUBLE:
203 case base::Value::TYPE_STRING:
204 break;
205 default:
206 *error = "Invalid value in enum attribute";
207 return false;
208 }
209 }
210 }
211
212 // Validate the schemas contained in a "choices" attribute.
213 if (it.key() == schema::kChoices) {
214 it.value().GetAsList(&list_value);
215 for (size_t i = 0; i < list_value->GetSize(); ++i) {
216 if (!list_value->GetDictionary(i, &dictionary_value)) {
217 *error = "Invalid choices attribute";
218 return false;
219 }
220 if (!IsValidSchema(dictionary_value, error)) {
221 DCHECK(!error->empty());
222 return false;
223 }
224 }
225 }
226 }
227
228 if (!has_type) {
229 *error = "Schema must have a type attribute";
230 return false;
231 }
232
233 return true;
234 }
235
236 } // namespace
237
238
239 JSONSchemaValidator::Error::Error() {
240 }
241
242 JSONSchemaValidator::Error::Error(const std::string& message)
243 : path(message) {
244 }
245
246 JSONSchemaValidator::Error::Error(const std::string& path,
247 const std::string& message)
248 : path(path), message(message) {
249 }
250
251
252 const char JSONSchemaValidator::kUnknownTypeReference[] =
253 "Unknown schema reference: *.";
254 const char JSONSchemaValidator::kInvalidChoice[] =
255 "Value does not match any valid type choices.";
256 const char JSONSchemaValidator::kInvalidEnum[] =
257 "Value does not match any valid enum choices.";
258 const char JSONSchemaValidator::kObjectPropertyIsRequired[] =
259 "Property is required.";
260 const char JSONSchemaValidator::kUnexpectedProperty[] =
261 "Unexpected property.";
262 const char JSONSchemaValidator::kArrayMinItems[] =
263 "Array must have at least * items.";
264 const char JSONSchemaValidator::kArrayMaxItems[] =
265 "Array must not have more than * items.";
266 const char JSONSchemaValidator::kArrayItemRequired[] =
267 "Item is required.";
268 const char JSONSchemaValidator::kStringMinLength[] =
269 "String must be at least * characters long.";
270 const char JSONSchemaValidator::kStringMaxLength[] =
271 "String must not be more than * characters long.";
272 const char JSONSchemaValidator::kStringPattern[] =
273 "String must match the pattern: *.";
274 const char JSONSchemaValidator::kNumberMinimum[] =
275 "Value must not be less than *.";
276 const char JSONSchemaValidator::kNumberMaximum[] =
277 "Value must not be greater than *.";
278 const char JSONSchemaValidator::kInvalidType[] =
279 "Expected '*' but got '*'.";
280 const char JSONSchemaValidator::kInvalidTypeIntegerNumber[] =
281 "Expected 'integer' but got 'number', consider using Math.round().";
282
283
284 // static
285 std::string JSONSchemaValidator::GetJSONSchemaType(const base::Value* value) {
286 switch (value->GetType()) {
287 case base::Value::TYPE_NULL:
288 return schema::kNull;
289 case base::Value::TYPE_BOOLEAN:
290 return schema::kBoolean;
291 case base::Value::TYPE_INTEGER:
292 return schema::kInteger;
293 case base::Value::TYPE_DOUBLE: {
294 double double_value = 0;
295 value->GetAsDouble(&double_value);
296 if (std::abs(double_value) <= std::pow(2.0, DBL_MANT_DIG) &&
297 double_value == floor(double_value)) {
298 return schema::kInteger;
299 } else {
300 return schema::kNumber;
301 }
302 }
303 case base::Value::TYPE_STRING:
304 return schema::kString;
305 case base::Value::TYPE_DICTIONARY:
306 return schema::kObject;
307 case base::Value::TYPE_LIST:
308 return schema::kArray;
309 default:
310 NOTREACHED() << "Unexpected value type: " << value->GetType();
311 return std::string();
312 }
313 }
314
315 // static
316 std::string JSONSchemaValidator::FormatErrorMessage(const std::string& format,
317 const std::string& s1) {
318 std::string ret_val = format;
319 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
320 return ret_val;
321 }
322
323 // static
324 std::string JSONSchemaValidator::FormatErrorMessage(const std::string& format,
325 const std::string& s1,
326 const std::string& s2) {
327 std::string ret_val = format;
328 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
329 ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
330 return ret_val;
331 }
332
333 // static
334 scoped_ptr<base::DictionaryValue> JSONSchemaValidator::IsValidSchema(
335 const std::string& schema,
336 std::string* error) {
337 base::JSONParserOptions options = base::JSON_PARSE_RFC;
338 scoped_ptr<base::Value> json(
339 base::JSONReader::ReadAndReturnError(schema, options, NULL, error));
340 if (!json)
341 return scoped_ptr<base::DictionaryValue>();
342 base::DictionaryValue* dict = NULL;
343 if (!json->GetAsDictionary(&dict)) {
344 *error = "Schema must be a JSON object";
345 return scoped_ptr<base::DictionaryValue>();
346 }
347 if (!::IsValidSchema(dict, error))
348 return scoped_ptr<base::DictionaryValue>();
349 ignore_result(json.release());
350 return make_scoped_ptr(dict);
351 }
352
353 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema)
354 : schema_root_(schema), default_allow_additional_properties_(false) {
355 }
356
357 JSONSchemaValidator::JSONSchemaValidator(base::DictionaryValue* schema,
358 base::ListValue* types)
359 : schema_root_(schema), default_allow_additional_properties_(false) {
360 if (!types)
361 return;
362
363 for (size_t i = 0; i < types->GetSize(); ++i) {
364 base::DictionaryValue* type = NULL;
365 CHECK(types->GetDictionary(i, &type));
366
367 std::string id;
368 CHECK(type->GetString(schema::kId, &id));
369
370 CHECK(types_.find(id) == types_.end());
371 types_[id] = type;
372 }
373 }
374
375 JSONSchemaValidator::~JSONSchemaValidator() {}
376
377 bool JSONSchemaValidator::Validate(const base::Value* instance) {
378 errors_.clear();
379 Validate(instance, schema_root_, std::string());
380 return errors_.empty();
381 }
382
383 void JSONSchemaValidator::Validate(const base::Value* instance,
384 const base::DictionaryValue* schema,
385 const std::string& path) {
386 // If this schema defines itself as reference type, save it in this.types.
387 std::string id;
388 if (schema->GetString(schema::kId, &id)) {
389 TypeMap::iterator iter = types_.find(id);
390 if (iter == types_.end())
391 types_[id] = schema;
392 else
393 DCHECK(iter->second == schema);
394 }
395
396 // If the schema has a $ref property, the instance must validate against
397 // that schema. It must be present in types_ to be referenced.
398 std::string ref;
399 if (schema->GetString(schema::kRef, &ref)) {
400 TypeMap::iterator type = types_.find(ref);
401 if (type == types_.end()) {
402 errors_.push_back(
403 Error(path, FormatErrorMessage(kUnknownTypeReference, ref)));
404 } else {
405 Validate(instance, type->second, path);
406 }
407 return;
408 }
409
410 // If the schema has a choices property, the instance must validate against at
411 // least one of the items in that array.
412 const base::ListValue* choices = NULL;
413 if (schema->GetList(schema::kChoices, &choices)) {
414 ValidateChoices(instance, choices, path);
415 return;
416 }
417
418 // If the schema has an enum property, the instance must be one of those
419 // values.
420 const base::ListValue* enumeration = NULL;
421 if (schema->GetList(schema::kEnum, &enumeration)) {
422 ValidateEnum(instance, enumeration, path);
423 return;
424 }
425
426 std::string type;
427 schema->GetString(schema::kType, &type);
428 CHECK(!type.empty());
429 if (type != schema::kAny) {
430 if (!ValidateType(instance, type, path))
431 return;
432
433 // These casts are safe because of checks in ValidateType().
434 if (type == schema::kObject) {
435 ValidateObject(static_cast<const base::DictionaryValue*>(instance),
436 schema,
437 path);
438 } else if (type == schema::kArray) {
439 ValidateArray(static_cast<const base::ListValue*>(instance),
440 schema, path);
441 } else if (type == schema::kString) {
442 // Intentionally NOT downcasting to StringValue*. TYPE_STRING only implies
443 // GetAsString() can safely be carried out, not that it's a StringValue.
444 ValidateString(instance, schema, path);
445 } else if (type == schema::kNumber || type == schema::kInteger) {
446 ValidateNumber(instance, schema, path);
447 } else if (type != schema::kBoolean && type != schema::kNull) {
448 NOTREACHED() << "Unexpected type: " << type;
449 }
450 }
451 }
452
453 void JSONSchemaValidator::ValidateChoices(const base::Value* instance,
454 const base::ListValue* choices,
455 const std::string& path) {
456 size_t original_num_errors = errors_.size();
457
458 for (size_t i = 0; i < choices->GetSize(); ++i) {
459 const base::DictionaryValue* choice = NULL;
460 CHECK(choices->GetDictionary(i, &choice));
461
462 Validate(instance, choice, path);
463 if (errors_.size() == original_num_errors)
464 return;
465
466 // We discard the error from each choice. We only want to know if any of the
467 // validations succeeded.
468 errors_.resize(original_num_errors);
469 }
470
471 // Now add a generic error that no choices matched.
472 errors_.push_back(Error(path, kInvalidChoice));
473 return;
474 }
475
476 void JSONSchemaValidator::ValidateEnum(const base::Value* instance,
477 const base::ListValue* choices,
478 const std::string& path) {
479 for (size_t i = 0; i < choices->GetSize(); ++i) {
480 const base::Value* choice = NULL;
481 CHECK(choices->Get(i, &choice));
482 switch (choice->GetType()) {
483 case base::Value::TYPE_NULL:
484 case base::Value::TYPE_BOOLEAN:
485 case base::Value::TYPE_STRING:
486 if (instance->Equals(choice))
487 return;
488 break;
489
490 case base::Value::TYPE_INTEGER:
491 case base::Value::TYPE_DOUBLE:
492 if (instance->IsType(base::Value::TYPE_INTEGER) ||
493 instance->IsType(base::Value::TYPE_DOUBLE)) {
494 if (GetNumberValue(choice) == GetNumberValue(instance))
495 return;
496 }
497 break;
498
499 default:
500 NOTREACHED() << "Unexpected type in enum: " << choice->GetType();
501 }
502 }
503
504 errors_.push_back(Error(path, kInvalidEnum));
505 }
506
507 void JSONSchemaValidator::ValidateObject(const base::DictionaryValue* instance,
508 const base::DictionaryValue* schema,
509 const std::string& path) {
510 const base::DictionaryValue* properties = NULL;
511 schema->GetDictionary(schema::kProperties, &properties);
512 if (properties) {
513 for (base::DictionaryValue::Iterator it(*properties); !it.IsAtEnd();
514 it.Advance()) {
515 std::string prop_path = path.empty() ? it.key() : (path + "." + it.key());
516 const base::DictionaryValue* prop_schema = NULL;
517 CHECK(it.value().GetAsDictionary(&prop_schema));
518
519 const base::Value* prop_value = NULL;
520 if (instance->Get(it.key(), &prop_value)) {
521 Validate(prop_value, prop_schema, prop_path);
522 } else {
523 // Properties are required unless there is an optional field set to
524 // 'true'.
525 bool is_optional = false;
526 prop_schema->GetBoolean(schema::kOptional, &is_optional);
527 if (!is_optional) {
528 errors_.push_back(Error(prop_path, kObjectPropertyIsRequired));
529 }
530 }
531 }
532 }
533
534 const base::DictionaryValue* additional_properties_schema = NULL;
535 if (SchemaAllowsAnyAdditionalItems(schema, &additional_properties_schema))
536 return;
537
538 // Validate additional properties.
539 for (base::DictionaryValue::Iterator it(*instance); !it.IsAtEnd();
540 it.Advance()) {
541 if (properties && properties->HasKey(it.key()))
542 continue;
543
544 std::string prop_path = path.empty() ? it.key() : path + "." + it.key();
545 if (!additional_properties_schema) {
546 errors_.push_back(Error(prop_path, kUnexpectedProperty));
547 } else {
548 Validate(&it.value(), additional_properties_schema, prop_path);
549 }
550 }
551 }
552
553 void JSONSchemaValidator::ValidateArray(const base::ListValue* instance,
554 const base::DictionaryValue* schema,
555 const std::string& path) {
556 const base::DictionaryValue* single_type = NULL;
557 size_t instance_size = instance->GetSize();
558 if (schema->GetDictionary(schema::kItems, &single_type)) {
559 int min_items = 0;
560 if (schema->GetInteger(schema::kMinItems, &min_items)) {
561 CHECK(min_items >= 0);
562 if (instance_size < static_cast<size_t>(min_items)) {
563 errors_.push_back(Error(path, FormatErrorMessage(
564 kArrayMinItems, base::IntToString(min_items))));
565 }
566 }
567
568 int max_items = 0;
569 if (schema->GetInteger(schema::kMaxItems, &max_items)) {
570 CHECK(max_items >= 0);
571 if (instance_size > static_cast<size_t>(max_items)) {
572 errors_.push_back(Error(path, FormatErrorMessage(
573 kArrayMaxItems, base::IntToString(max_items))));
574 }
575 }
576
577 // If the items property is a single schema, each item in the array must
578 // validate against that schema.
579 for (size_t i = 0; i < instance_size; ++i) {
580 const base::Value* item = NULL;
581 CHECK(instance->Get(i, &item));
582 std::string i_str = base::UintToString(i);
583 std::string item_path = path.empty() ? i_str : (path + "." + i_str);
584 Validate(item, single_type, item_path);
585 }
586
587 return;
588 }
589
590 // Otherwise, the list must be a tuple type, where each item in the list has a
591 // particular schema.
592 ValidateTuple(instance, schema, path);
593 }
594
595 void JSONSchemaValidator::ValidateTuple(const base::ListValue* instance,
596 const base::DictionaryValue* schema,
597 const std::string& path) {
598 const base::ListValue* tuple_type = NULL;
599 schema->GetList(schema::kItems, &tuple_type);
600 size_t tuple_size = tuple_type ? tuple_type->GetSize() : 0;
601 if (tuple_type) {
602 for (size_t i = 0; i < tuple_size; ++i) {
603 std::string i_str = base::UintToString(i);
604 std::string item_path = path.empty() ? i_str : (path + "." + i_str);
605 const base::DictionaryValue* item_schema = NULL;
606 CHECK(tuple_type->GetDictionary(i, &item_schema));
607 const base::Value* item_value = NULL;
608 instance->Get(i, &item_value);
609 if (item_value && item_value->GetType() != base::Value::TYPE_NULL) {
610 Validate(item_value, item_schema, item_path);
611 } else {
612 bool is_optional = false;
613 item_schema->GetBoolean(schema::kOptional, &is_optional);
614 if (!is_optional) {
615 errors_.push_back(Error(item_path, kArrayItemRequired));
616 return;
617 }
618 }
619 }
620 }
621
622 const base::DictionaryValue* additional_properties_schema = NULL;
623 if (SchemaAllowsAnyAdditionalItems(schema, &additional_properties_schema))
624 return;
625
626 size_t instance_size = instance->GetSize();
627 if (additional_properties_schema) {
628 // Any additional properties must validate against the additionalProperties
629 // schema.
630 for (size_t i = tuple_size; i < instance_size; ++i) {
631 std::string i_str = base::UintToString(i);
632 std::string item_path = path.empty() ? i_str : (path + "." + i_str);
633 const base::Value* item_value = NULL;
634 CHECK(instance->Get(i, &item_value));
635 Validate(item_value, additional_properties_schema, item_path);
636 }
637 } else if (instance_size > tuple_size) {
638 errors_.push_back(Error(path, FormatErrorMessage(
639 kArrayMaxItems, base::UintToString(tuple_size))));
640 }
641 }
642
643 void JSONSchemaValidator::ValidateString(const base::Value* instance,
644 const base::DictionaryValue* schema,
645 const std::string& path) {
646 std::string value;
647 CHECK(instance->GetAsString(&value));
648
649 int min_length = 0;
650 if (schema->GetInteger(schema::kMinLength, &min_length)) {
651 CHECK(min_length >= 0);
652 if (value.size() < static_cast<size_t>(min_length)) {
653 errors_.push_back(Error(path, FormatErrorMessage(
654 kStringMinLength, base::IntToString(min_length))));
655 }
656 }
657
658 int max_length = 0;
659 if (schema->GetInteger(schema::kMaxLength, &max_length)) {
660 CHECK(max_length >= 0);
661 if (value.size() > static_cast<size_t>(max_length)) {
662 errors_.push_back(Error(path, FormatErrorMessage(
663 kStringMaxLength, base::IntToString(max_length))));
664 }
665 }
666
667 CHECK(!schema->HasKey(schema::kPattern)) << "Pattern is not supported.";
668 }
669
670 void JSONSchemaValidator::ValidateNumber(const base::Value* instance,
671 const base::DictionaryValue* schema,
672 const std::string& path) {
673 double value = GetNumberValue(instance);
674
675 // TODO(aa): It would be good to test that the double is not infinity or nan,
676 // but isnan and isinf aren't defined on Windows.
677
678 double minimum = 0;
679 if (schema->GetDouble(schema::kMinimum, &minimum)) {
680 if (value < minimum)
681 errors_.push_back(Error(path, FormatErrorMessage(
682 kNumberMinimum, base::DoubleToString(minimum))));
683 }
684
685 double maximum = 0;
686 if (schema->GetDouble(schema::kMaximum, &maximum)) {
687 if (value > maximum)
688 errors_.push_back(Error(path, FormatErrorMessage(
689 kNumberMaximum, base::DoubleToString(maximum))));
690 }
691 }
692
693 bool JSONSchemaValidator::ValidateType(const base::Value* instance,
694 const std::string& expected_type,
695 const std::string& path) {
696 std::string actual_type = GetJSONSchemaType(instance);
697 if (expected_type == actual_type ||
698 (expected_type == schema::kNumber && actual_type == schema::kInteger)) {
699 return true;
700 } else if (expected_type == schema::kInteger &&
701 actual_type == schema::kNumber) {
702 errors_.push_back(Error(path, kInvalidTypeIntegerNumber));
703 return false;
704 } else {
705 errors_.push_back(Error(path, FormatErrorMessage(
706 kInvalidType, expected_type, actual_type)));
707 return false;
708 }
709 }
710
711 bool JSONSchemaValidator::SchemaAllowsAnyAdditionalItems(
712 const base::DictionaryValue* schema,
713 const base::DictionaryValue** additional_properties_schema) {
714 // If the validator allows additional properties globally, and this schema
715 // doesn't override, then we can exit early.
716 schema->GetDictionary(schema::kAdditionalProperties,
717 additional_properties_schema);
718
719 if (*additional_properties_schema) {
720 std::string additional_properties_type(schema::kAny);
721 CHECK((*additional_properties_schema)->GetString(
722 schema::kType, &additional_properties_type));
723 return additional_properties_type == schema::kAny;
724 } else {
725 return default_allow_additional_properties_;
726 }
727 }
OLDNEW
« no previous file with comments | « chrome/common/json_schema/json_schema_validator.h ('k') | chrome/common/json_schema/json_schema_validator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698