1 // Copyright 2013 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 "components/json_schema/json_schema_validator_unittest_base.h"
6 
7 #include <cfloat>
8 #include <cmath>
9 #include <limits>
10 #include <memory>
11 
12 #include "base/base_paths.h"
13 #include "base/files/file_util.h"
14 #include "base/json/json_file_value_serializer.h"
15 #include "base/logging.h"
16 #include "base/path_service.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "components/json_schema/json_schema_constants.h"
20 #include "components/json_schema/json_schema_validator.h"
21 
22 namespace schema = json_schema_constants;
23 
24 namespace {
25 
26 #define TEST_SOURCE base::StringPrintf("%s:%i", __FILE__, __LINE__)
27 
LoadValue(const std::string & filename)28 base::Value* LoadValue(const std::string& filename) {
29   base::FilePath path;
30   base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
31   path = path.AppendASCII("components")
32              .AppendASCII("test")
33              .AppendASCII("data")
34              .AppendASCII("json_schema")
35              .AppendASCII(filename);
36   EXPECT_TRUE(base::PathExists(path));
37 
38   std::string error_message;
39   JSONFileValueDeserializer deserializer(path);
40   base::Value* result =
41       deserializer.Deserialize(nullptr, &error_message).release();
42   if (!result)
43     ADD_FAILURE() << "Could not parse JSON: " << error_message;
44   return result;
45 }
46 
LoadValue(const std::string & filename,base::Value::Type type)47 base::Value* LoadValue(const std::string& filename, base::Value::Type type) {
48   std::unique_ptr<base::Value> result(LoadValue(filename));
49   if (!result)
50     return nullptr;
51   if (result->type() != type) {
52     ADD_FAILURE() << "Expected type " << type << ", got: " << result->type();
53     return nullptr;
54   }
55   return result.release();
56 }
57 
LoadList(const std::string & filename)58 base::ListValue* LoadList(const std::string& filename) {
59   return static_cast<base::ListValue*>(
60       LoadValue(filename, base::Value::Type::LIST));
61 }
62 
LoadDictionary(const std::string & filename)63 base::DictionaryValue* LoadDictionary(const std::string& filename) {
64   return static_cast<base::DictionaryValue*>(
65       LoadValue(filename, base::Value::Type::DICTIONARY));
66 }
67 
68 }  // namespace
69 
70 
JSONSchemaValidatorTestBase()71 JSONSchemaValidatorTestBase::JSONSchemaValidatorTestBase() {
72 }
73 
RunTests()74 void JSONSchemaValidatorTestBase::RunTests() {
75   TestComplex();
76   TestStringPattern();
77   TestEnum();
78   TestChoices();
79   TestExtends();
80   TestObject();
81   TestTypeReference();
82   TestArrayTuple();
83   TestArrayNonTuple();
84   TestString();
85   TestNumber();
86   TestTypeClassifier();
87   TestTypes();
88 }
89 
TestComplex()90 void JSONSchemaValidatorTestBase::TestComplex() {
91   std::unique_ptr<base::DictionaryValue> schema(
92       LoadDictionary("complex_schema.json"));
93   std::unique_ptr<base::ListValue> instance(LoadList("complex_instance.json"));
94 
95   ASSERT_TRUE(schema.get());
96   ASSERT_TRUE(instance.get());
97 
98   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
99   instance->Remove(instance->GetSize() - 1, nullptr);
100   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
101   instance->Append(std::make_unique<base::DictionaryValue>());
102   ExpectNotValid(
103       TEST_SOURCE, instance.get(), schema.get(), nullptr, "1",
104       JSONSchemaValidator::FormatErrorMessage(
105           JSONSchemaValidator::kInvalidType, schema::kNumber, schema::kObject));
106   instance->Remove(instance->GetSize() - 1, nullptr);
107 
108   base::DictionaryValue* item = nullptr;
109   ASSERT_TRUE(instance->GetDictionary(0, &item));
110   item->SetString("url", "xxxxxxxxxxx");
111 
112   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "0.url",
113                  JSONSchemaValidator::FormatErrorMessage(
114                      JSONSchemaValidator::kStringMaxLength, "10"));
115 }
116 
TestStringPattern()117 void JSONSchemaValidatorTestBase::TestStringPattern() {
118   std::unique_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
119   schema->SetString(schema::kType, schema::kString);
120   schema->SetString(schema::kPattern, "foo+");
121 
122   ExpectValid(TEST_SOURCE,
123               std::unique_ptr<base::Value>(new base::Value("foo")).get(),
124               schema.get(), nullptr);
125   ExpectValid(TEST_SOURCE,
126               std::unique_ptr<base::Value>(new base::Value("foooooo")).get(),
127               schema.get(), nullptr);
128   ExpectNotValid(TEST_SOURCE,
129                  std::unique_ptr<base::Value>(new base::Value("bar")).get(),
130                  schema.get(), nullptr, std::string(),
131                  JSONSchemaValidator::FormatErrorMessage(
132                      JSONSchemaValidator::kStringPattern, "foo+"));
133 }
134 
TestEnum()135 void JSONSchemaValidatorTestBase::TestEnum() {
136   std::unique_ptr<base::DictionaryValue> schema(
137       LoadDictionary("enum_schema.json"));
138 
139   ExpectValid(TEST_SOURCE,
140               std::unique_ptr<base::Value>(new base::Value("foo")).get(),
141               schema.get(), nullptr);
142   ExpectValid(TEST_SOURCE,
143               std::unique_ptr<base::Value>(new base::Value(42)).get(),
144               schema.get(), nullptr);
145   ExpectValid(TEST_SOURCE,
146               std::unique_ptr<base::Value>(new base::Value(false)).get(),
147               schema.get(), nullptr);
148 
149   ExpectNotValid(
150       TEST_SOURCE, std::unique_ptr<base::Value>(new base::Value("42")).get(),
151       schema.get(), nullptr, std::string(), JSONSchemaValidator::kInvalidEnum);
152   ExpectNotValid(TEST_SOURCE, std::make_unique<base::Value>().get(),
153                  schema.get(), nullptr, std::string(),
154                  JSONSchemaValidator::kInvalidEnum);
155 }
156 
TestChoices()157 void JSONSchemaValidatorTestBase::TestChoices() {
158   std::unique_ptr<base::DictionaryValue> schema(
159       LoadDictionary("choices_schema.json"));
160 
161   ExpectValid(TEST_SOURCE, std::make_unique<base::Value>().get(), schema.get(),
162               nullptr);
163   ExpectValid(TEST_SOURCE,
164               std::unique_ptr<base::Value>(new base::Value(42)).get(),
165               schema.get(), nullptr);
166 
167   std::unique_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
168   instance->SetString("foo", "bar");
169   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
170 
171   ExpectNotValid(TEST_SOURCE,
172                  std::unique_ptr<base::Value>(new base::Value("foo")).get(),
173                  schema.get(), nullptr, std::string(),
174                  JSONSchemaValidator::kInvalidChoice);
175   ExpectNotValid(TEST_SOURCE,
176                  std::unique_ptr<base::Value>(new base::ListValue()).get(),
177                  schema.get(), nullptr, std::string(),
178                  JSONSchemaValidator::kInvalidChoice);
179 
180   instance->SetInteger("foo", 42);
181   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr,
182                  std::string(), JSONSchemaValidator::kInvalidChoice);
183 }
184 
TestExtends()185 void JSONSchemaValidatorTestBase::TestExtends() {
186   // TODO(aa): JS only
187 }
188 
TestObject()189 void JSONSchemaValidatorTestBase::TestObject() {
190   std::unique_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
191   schema->SetString(schema::kType, schema::kObject);
192   schema->SetString("properties.foo.type", schema::kString);
193   schema->SetString("properties.bar.type", schema::kInteger);
194 
195   std::unique_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
196   instance->SetString("foo", "foo");
197   instance->SetInteger("bar", 42);
198 
199   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
200 
201   instance->SetBoolean("extra", true);
202   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "extra",
203                  JSONSchemaValidator::kUnexpectedProperty);
204   instance->Remove("extra", nullptr);
205 
206   instance->Remove("bar", nullptr);
207   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "bar",
208                  JSONSchemaValidator::kObjectPropertyIsRequired);
209 
210   instance->SetString("bar", "42");
211   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "bar",
212                  JSONSchemaValidator::FormatErrorMessage(
213                      JSONSchemaValidator::kInvalidType, schema::kInteger,
214                      schema::kString));
215   instance->SetInteger("bar", 42);
216 
217   // Test "patternProperties".
218   instance->SetInteger("extra", 42);
219   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "extra",
220                  JSONSchemaValidator::kUnexpectedProperty);
221   schema->SetString("patternProperties.extra+.type",
222                     schema::kInteger);
223   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
224   instance->Remove("extra", nullptr);
225   instance->SetInteger("extraaa", 42);
226   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
227   instance->Remove("extraaa", nullptr);
228   instance->SetInteger("extr", 42);
229   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "extr",
230                  JSONSchemaValidator::kUnexpectedProperty);
231   instance->Remove("extr", nullptr);
232   schema->Remove(schema::kPatternProperties, nullptr);
233 
234   // Test "patternProperties" and "properties" schemas are both checked if
235   // applicable.
236   schema->SetString("patternProperties.fo+.type", schema::kInteger);
237   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "foo",
238                  JSONSchemaValidator::FormatErrorMessage(
239                      JSONSchemaValidator::kInvalidType, schema::kInteger,
240                      schema::kString));
241   instance->SetInteger("foo", 123);
242   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "foo",
243                  JSONSchemaValidator::FormatErrorMessage(
244                      JSONSchemaValidator::kInvalidType, schema::kString,
245                      schema::kInteger));
246   instance->SetString("foo", "foo");
247   schema->Remove(schema::kPatternProperties, nullptr);
248 
249   // Test additional properties.
250   base::DictionaryValue* additional_properties = schema->SetDictionary(
251       schema::kAdditionalProperties, std::make_unique<base::DictionaryValue>());
252   additional_properties->SetString(schema::kType, schema::kAny);
253 
254   instance->SetBoolean("extra", true);
255   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
256 
257   instance->SetString("extra", "foo");
258   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
259 
260   additional_properties->SetString(schema::kType, schema::kBoolean);
261   instance->SetBoolean("extra", true);
262   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
263 
264   instance->SetString("extra", "foo");
265   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "extra",
266                  JSONSchemaValidator::FormatErrorMessage(
267                      JSONSchemaValidator::kInvalidType, schema::kBoolean,
268                      schema::kString));
269   instance->Remove("extra", nullptr);
270 
271   base::DictionaryValue* properties = nullptr;
272   base::DictionaryValue* bar_property = nullptr;
273   ASSERT_TRUE(schema->GetDictionary(schema::kProperties, &properties));
274   ASSERT_TRUE(properties->GetDictionary("bar", &bar_property));
275 
276   bar_property->SetBoolean(schema::kOptional, true);
277   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
278   instance->Remove("bar", nullptr);
279   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
280   instance->Set("bar", std::make_unique<base::Value>());
281   ExpectNotValid(
282       TEST_SOURCE, instance.get(), schema.get(), nullptr, "bar",
283       JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
284                                               schema::kInteger, schema::kNull));
285   instance->SetString("bar", "42");
286   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "bar",
287                  JSONSchemaValidator::FormatErrorMessage(
288                      JSONSchemaValidator::kInvalidType, schema::kInteger,
289                      schema::kString));
290 
291   // Verify that JSON parser handles dot in "patternProperties" well.
292   schema.reset(LoadDictionary("pattern_properties_dot.json"));
293   ASSERT_TRUE(schema->GetDictionary(schema::kPatternProperties, &properties));
294   ASSERT_TRUE(properties->HasKey("^.$"));
295 
296   instance.reset(new base::DictionaryValue());
297   instance->SetString("a", "whatever");
298   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
299   instance->SetString("foo", "bar");
300   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "foo",
301                  JSONSchemaValidator::kUnexpectedProperty);
302 }
303 
TestTypeReference()304 void JSONSchemaValidatorTestBase::TestTypeReference() {
305   std::unique_ptr<base::ListValue> types(LoadList("reference_types.json"));
306   ASSERT_TRUE(types.get());
307 
308   std::unique_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
309   schema->SetString(schema::kType, schema::kObject);
310   schema->SetString("properties.foo.type", schema::kString);
311   schema->SetString("properties.bar.$ref", "Max10Int");
312   schema->SetString("properties.baz.$ref", "MinLengthString");
313 
314   std::unique_ptr<base::DictionaryValue> schema_inline(
315       new base::DictionaryValue());
316   schema_inline->SetString(schema::kType, schema::kObject);
317   schema_inline->SetString("properties.foo.type", schema::kString);
318   schema_inline->SetString("properties.bar.id", "NegativeInt");
319   schema_inline->SetString("properties.bar.type", schema::kInteger);
320   schema_inline->SetInteger("properties.bar.maximum", 0);
321   schema_inline->SetString("properties.baz.$ref", "NegativeInt");
322 
323   std::unique_ptr<base::DictionaryValue> instance(new base::DictionaryValue());
324   instance->SetString("foo", "foo");
325   instance->SetInteger("bar", 4);
326   instance->SetString("baz", "ab");
327 
328   std::unique_ptr<base::DictionaryValue> instance_inline(
329       new base::DictionaryValue());
330   instance_inline->SetString("foo", "foo");
331   instance_inline->SetInteger("bar", -4);
332   instance_inline->SetInteger("baz", -2);
333 
334   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), types.get());
335   ExpectValid(TEST_SOURCE, instance_inline.get(), schema_inline.get(), nullptr);
336 
337   // Validation failure, but successful schema reference.
338   instance->SetString("baz", "a");
339   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), types.get(),
340                  "baz", JSONSchemaValidator::FormatErrorMessage(
341                      JSONSchemaValidator::kStringMinLength, "2"));
342 
343   instance_inline->SetInteger("bar", 20);
344   ExpectNotValid(TEST_SOURCE, instance_inline.get(), schema_inline.get(),
345                  nullptr, "bar",
346                  JSONSchemaValidator::FormatErrorMessage(
347                      JSONSchemaValidator::kNumberMaximum, "0"));
348 
349   // Remove MinLengthString type.
350   types->Remove(types->GetSize() - 1, nullptr);
351   instance->SetString("baz", "ab");
352   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), types.get(),
353                  "bar", JSONSchemaValidator::FormatErrorMessage(
354                      JSONSchemaValidator::kUnknownTypeReference,
355                      "Max10Int"));
356 
357   // Remove internal type "NegativeInt".
358   schema_inline->Remove("properties.bar", nullptr);
359   instance_inline->Remove("bar", nullptr);
360   ExpectNotValid(
361       TEST_SOURCE, instance_inline.get(), schema_inline.get(), nullptr, "baz",
362       JSONSchemaValidator::FormatErrorMessage(
363           JSONSchemaValidator::kUnknownTypeReference, "NegativeInt"));
364 }
365 
TestArrayTuple()366 void JSONSchemaValidatorTestBase::TestArrayTuple() {
367   std::unique_ptr<base::DictionaryValue> schema(
368       LoadDictionary("array_tuple_schema.json"));
369   ASSERT_TRUE(schema.get());
370 
371   std::unique_ptr<base::ListValue> instance(new base::ListValue());
372   instance->AppendString("42");
373   instance->AppendInteger(42);
374 
375   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
376 
377   instance->AppendString("anything");
378   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr,
379                  std::string(),
380                  JSONSchemaValidator::FormatErrorMessage(
381                      JSONSchemaValidator::kArrayMaxItems, "2"));
382 
383   instance->Remove(1, nullptr);
384   instance->Remove(1, nullptr);
385   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "1",
386                  JSONSchemaValidator::kArrayItemRequired);
387 
388   instance->Set(0, std::make_unique<base::Value>(42));
389   instance->AppendInteger(42);
390   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "0",
391                  JSONSchemaValidator::FormatErrorMessage(
392                      JSONSchemaValidator::kInvalidType, schema::kString,
393                      schema::kInteger));
394 
395   base::DictionaryValue* additional_properties = schema->SetDictionary(
396       schema::kAdditionalProperties, std::make_unique<base::DictionaryValue>());
397   additional_properties->SetString(schema::kType, schema::kAny);
398   instance->Set(0, std::make_unique<base::Value>("42"));
399   instance->AppendString("anything");
400   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
401   instance->Set(2, std::make_unique<base::ListValue>());
402   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
403 
404   additional_properties->SetString(schema::kType, schema::kBoolean);
405   ExpectNotValid(
406       TEST_SOURCE, instance.get(), schema.get(), nullptr, "2",
407       JSONSchemaValidator::FormatErrorMessage(
408           JSONSchemaValidator::kInvalidType, schema::kBoolean, schema::kArray));
409   instance->Set(2, std::make_unique<base::Value>(false));
410   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
411 
412   base::ListValue* items_schema = nullptr;
413   base::DictionaryValue* item0_schema = nullptr;
414   ASSERT_TRUE(schema->GetList(schema::kItems, &items_schema));
415   ASSERT_TRUE(items_schema->GetDictionary(0, &item0_schema));
416   item0_schema->SetBoolean(schema::kOptional, true);
417   instance->Remove(2, nullptr);
418   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
419   // TODO(aa): I think this is inconsistent with the handling of NULL+optional
420   // for objects.
421   instance->Set(0, std::make_unique<base::Value>());
422   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
423   instance->Set(0, std::make_unique<base::Value>(42));
424   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "0",
425                  JSONSchemaValidator::FormatErrorMessage(
426                      JSONSchemaValidator::kInvalidType, schema::kString,
427                      schema::kInteger));
428 }
429 
TestArrayNonTuple()430 void JSONSchemaValidatorTestBase::TestArrayNonTuple() {
431   std::unique_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
432   schema->SetString(schema::kType, schema::kArray);
433   schema->SetString("items.type", schema::kString);
434   schema->SetInteger(schema::kMinItems, 2);
435   schema->SetInteger(schema::kMaxItems, 3);
436 
437   std::unique_ptr<base::ListValue> instance(new base::ListValue());
438   instance->AppendString("x");
439   instance->AppendString("x");
440 
441   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
442   instance->AppendString("x");
443   ExpectValid(TEST_SOURCE, instance.get(), schema.get(), nullptr);
444 
445   instance->AppendString("x");
446   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr,
447                  std::string(),
448                  JSONSchemaValidator::FormatErrorMessage(
449                      JSONSchemaValidator::kArrayMaxItems, "3"));
450   instance->Remove(1, nullptr);
451   instance->Remove(1, nullptr);
452   instance->Remove(1, nullptr);
453   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr,
454                  std::string(),
455                  JSONSchemaValidator::FormatErrorMessage(
456                      JSONSchemaValidator::kArrayMinItems, "2"));
457 
458   instance->Remove(1, nullptr);
459   instance->AppendInteger(42);
460   ExpectNotValid(TEST_SOURCE, instance.get(), schema.get(), nullptr, "1",
461                  JSONSchemaValidator::FormatErrorMessage(
462                      JSONSchemaValidator::kInvalidType, schema::kString,
463                      schema::kInteger));
464 }
465 
TestString()466 void JSONSchemaValidatorTestBase::TestString() {
467   std::unique_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
468   schema->SetString(schema::kType, schema::kString);
469   schema->SetInteger(schema::kMinLength, 1);
470   schema->SetInteger(schema::kMaxLength, 10);
471 
472   ExpectValid(TEST_SOURCE,
473               std::unique_ptr<base::Value>(new base::Value("x")).get(),
474               schema.get(), nullptr);
475   ExpectValid(TEST_SOURCE,
476               std::unique_ptr<base::Value>(new base::Value("xxxxxxxxxx")).get(),
477               schema.get(), nullptr);
478 
479   ExpectNotValid(
480       TEST_SOURCE,
481       std::unique_ptr<base::Value>(new base::Value(std::string())).get(),
482       schema.get(), nullptr, std::string(),
483       JSONSchemaValidator::FormatErrorMessage(
484           JSONSchemaValidator::kStringMinLength, "1"));
485   ExpectNotValid(
486       TEST_SOURCE,
487       std::unique_ptr<base::Value>(new base::Value("xxxxxxxxxxx")).get(),
488       schema.get(), nullptr, std::string(),
489       JSONSchemaValidator::FormatErrorMessage(
490           JSONSchemaValidator::kStringMaxLength, "10"));
491 }
492 
TestNumber()493 void JSONSchemaValidatorTestBase::TestNumber() {
494   std::unique_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
495   schema->SetString(schema::kType, schema::kNumber);
496   schema->SetInteger(schema::kMinimum, 1);
497   schema->SetInteger(schema::kMaximum, 100);
498   schema->SetInteger("maxDecimal", 2);
499 
500   ExpectValid(TEST_SOURCE,
501               std::unique_ptr<base::Value>(new base::Value(1)).get(),
502               schema.get(), nullptr);
503   ExpectValid(TEST_SOURCE,
504               std::unique_ptr<base::Value>(new base::Value(50)).get(),
505               schema.get(), nullptr);
506   ExpectValid(TEST_SOURCE,
507               std::unique_ptr<base::Value>(new base::Value(100)).get(),
508               schema.get(), nullptr);
509   ExpectValid(TEST_SOURCE,
510               std::unique_ptr<base::Value>(new base::Value(88.88)).get(),
511               schema.get(), nullptr);
512 
513   ExpectNotValid(TEST_SOURCE,
514                  std::unique_ptr<base::Value>(new base::Value(0.5)).get(),
515                  schema.get(), nullptr, std::string(),
516                  JSONSchemaValidator::FormatErrorMessage(
517                      JSONSchemaValidator::kNumberMinimum, "1"));
518   ExpectNotValid(TEST_SOURCE,
519                  std::unique_ptr<base::Value>(new base::Value(100.1)).get(),
520                  schema.get(), nullptr, std::string(),
521                  JSONSchemaValidator::FormatErrorMessage(
522                      JSONSchemaValidator::kNumberMaximum, "100"));
523 }
524 
TestTypeClassifier()525 void JSONSchemaValidatorTestBase::TestTypeClassifier() {
526   EXPECT_EQ(std::string(schema::kBoolean),
527             JSONSchemaValidator::GetJSONSchemaType(
528                 std::unique_ptr<base::Value>(new base::Value(true)).get()));
529   EXPECT_EQ(std::string(schema::kBoolean),
530             JSONSchemaValidator::GetJSONSchemaType(
531                 std::unique_ptr<base::Value>(new base::Value(false)).get()));
532 
533   // It doesn't matter whether the C++ type is 'integer' or 'real'. If the
534   // number is integral and within the representable range of integers in
535   // double, it's classified as 'integer'.
536   EXPECT_EQ(std::string(schema::kInteger),
537             JSONSchemaValidator::GetJSONSchemaType(
538                 std::unique_ptr<base::Value>(new base::Value(42)).get()));
539   EXPECT_EQ(std::string(schema::kInteger),
540             JSONSchemaValidator::GetJSONSchemaType(
541                 std::unique_ptr<base::Value>(new base::Value(0)).get()));
542   EXPECT_EQ(std::string(schema::kInteger),
543             JSONSchemaValidator::GetJSONSchemaType(
544                 std::unique_ptr<base::Value>(new base::Value(42)).get()));
545   EXPECT_EQ(
546       std::string(schema::kInteger),
547       JSONSchemaValidator::GetJSONSchemaType(
548           std::unique_ptr<base::Value>(new base::Value(pow(2.0, DBL_MANT_DIG)))
549               .get()));
550   EXPECT_EQ(
551       std::string(schema::kInteger),
552       JSONSchemaValidator::GetJSONSchemaType(
553           std::unique_ptr<base::Value>(new base::Value(pow(-2.0, DBL_MANT_DIG)))
554               .get()));
555 
556   // "number" is only used for non-integral numbers, or numbers beyond what
557   // double can accurately represent.
558   EXPECT_EQ(std::string(schema::kNumber),
559             JSONSchemaValidator::GetJSONSchemaType(
560                 std::unique_ptr<base::Value>(new base::Value(88.8)).get()));
561   EXPECT_EQ(std::string(schema::kNumber),
562             JSONSchemaValidator::GetJSONSchemaType(
563                 std::unique_ptr<base::Value>(
564                     new base::Value(pow(2.0, DBL_MANT_DIG) * 2))
565                     .get()));
566   EXPECT_EQ(std::string(schema::kNumber),
567             JSONSchemaValidator::GetJSONSchemaType(
568                 std::unique_ptr<base::Value>(
569                     new base::Value(pow(-2.0, DBL_MANT_DIG) * 2))
570                     .get()));
571 
572   EXPECT_EQ(std::string(schema::kString),
573             JSONSchemaValidator::GetJSONSchemaType(
574                 std::unique_ptr<base::Value>(new base::Value("foo")).get()));
575   EXPECT_EQ(std::string(schema::kArray),
576             JSONSchemaValidator::GetJSONSchemaType(
577                 std::unique_ptr<base::Value>(new base::ListValue()).get()));
578   EXPECT_EQ(
579       std::string(schema::kObject),
580       JSONSchemaValidator::GetJSONSchemaType(
581           std::unique_ptr<base::Value>(new base::DictionaryValue()).get()));
582   EXPECT_EQ(std::string(schema::kNull),
583             JSONSchemaValidator::GetJSONSchemaType(
584                 std::make_unique<base::Value>().get()));
585 }
586 
TestTypes()587 void JSONSchemaValidatorTestBase::TestTypes() {
588   std::unique_ptr<base::DictionaryValue> schema(new base::DictionaryValue());
589 
590   // valid
591   schema->SetString(schema::kType, schema::kObject);
592   ExpectValid(TEST_SOURCE,
593               std::unique_ptr<base::Value>(new base::DictionaryValue()).get(),
594               schema.get(), nullptr);
595 
596   schema->SetString(schema::kType, schema::kArray);
597   ExpectValid(TEST_SOURCE,
598               std::unique_ptr<base::Value>(new base::ListValue()).get(),
599               schema.get(), nullptr);
600 
601   schema->SetString(schema::kType, schema::kString);
602   ExpectValid(TEST_SOURCE,
603               std::unique_ptr<base::Value>(new base::Value("foobar")).get(),
604               schema.get(), nullptr);
605 
606   schema->SetString(schema::kType, schema::kNumber);
607   ExpectValid(TEST_SOURCE,
608               std::unique_ptr<base::Value>(new base::Value(88.8)).get(),
609               schema.get(), nullptr);
610   ExpectValid(TEST_SOURCE,
611               std::unique_ptr<base::Value>(new base::Value(42)).get(),
612               schema.get(), nullptr);
613   ExpectValid(TEST_SOURCE,
614               std::unique_ptr<base::Value>(new base::Value(42)).get(),
615               schema.get(), nullptr);
616   ExpectValid(TEST_SOURCE,
617               std::unique_ptr<base::Value>(new base::Value(0)).get(),
618               schema.get(), nullptr);
619 
620   schema->SetString(schema::kType, schema::kInteger);
621   ExpectValid(TEST_SOURCE,
622               std::unique_ptr<base::Value>(new base::Value(42)).get(),
623               schema.get(), nullptr);
624   ExpectValid(TEST_SOURCE,
625               std::unique_ptr<base::Value>(new base::Value(42)).get(),
626               schema.get(), nullptr);
627   ExpectValid(TEST_SOURCE,
628               std::unique_ptr<base::Value>(new base::Value(0)).get(),
629               schema.get(), nullptr);
630   ExpectValid(
631       TEST_SOURCE,
632       std::unique_ptr<base::Value>(new base::Value(pow(2.0, DBL_MANT_DIG)))
633           .get(),
634       schema.get(), nullptr);
635   ExpectValid(
636       TEST_SOURCE,
637       std::unique_ptr<base::Value>(new base::Value(pow(-2.0, DBL_MANT_DIG)))
638           .get(),
639       schema.get(), nullptr);
640 
641   schema->SetString(schema::kType, schema::kBoolean);
642   ExpectValid(TEST_SOURCE,
643               std::unique_ptr<base::Value>(new base::Value(false)).get(),
644               schema.get(), nullptr);
645   ExpectValid(TEST_SOURCE,
646               std::unique_ptr<base::Value>(new base::Value(true)).get(),
647               schema.get(), nullptr);
648 
649   schema->SetString(schema::kType, schema::kNull);
650   ExpectValid(TEST_SOURCE, std::make_unique<base::Value>().get(), schema.get(),
651               nullptr);
652 
653   // not valid
654   schema->SetString(schema::kType, schema::kObject);
655   ExpectNotValid(
656       TEST_SOURCE, std::unique_ptr<base::Value>(new base::ListValue()).get(),
657       schema.get(), nullptr, std::string(),
658       JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
659                                               schema::kObject, schema::kArray));
660 
661   schema->SetString(schema::kType, schema::kObject);
662   ExpectNotValid(
663       TEST_SOURCE, std::make_unique<base::Value>().get(), schema.get(), nullptr,
664       std::string(),
665       JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
666                                               schema::kObject, schema::kNull));
667 
668   schema->SetString(schema::kType, schema::kArray);
669   ExpectNotValid(
670       TEST_SOURCE, std::unique_ptr<base::Value>(new base::Value(42)).get(),
671       schema.get(), nullptr, std::string(),
672       JSONSchemaValidator::FormatErrorMessage(
673           JSONSchemaValidator::kInvalidType, schema::kArray, schema::kInteger));
674 
675   schema->SetString(schema::kType, schema::kString);
676   ExpectNotValid(TEST_SOURCE,
677                  std::unique_ptr<base::Value>(new base::Value(42)).get(),
678                  schema.get(), nullptr, std::string(),
679                  JSONSchemaValidator::FormatErrorMessage(
680                      JSONSchemaValidator::kInvalidType, schema::kString,
681                      schema::kInteger));
682 
683   schema->SetString(schema::kType, schema::kNumber);
684   ExpectNotValid(
685       TEST_SOURCE, std::unique_ptr<base::Value>(new base::Value("42")).get(),
686       schema.get(), nullptr, std::string(),
687       JSONSchemaValidator::FormatErrorMessage(
688           JSONSchemaValidator::kInvalidType, schema::kNumber, schema::kString));
689 
690   schema->SetString(schema::kType, schema::kInteger);
691   ExpectNotValid(TEST_SOURCE,
692                  std::unique_ptr<base::Value>(new base::Value(88.8)).get(),
693                  schema.get(), nullptr, std::string(),
694                  JSONSchemaValidator::kInvalidTypeIntegerNumber);
695 
696   schema->SetString(schema::kType, schema::kBoolean);
697   ExpectNotValid(TEST_SOURCE,
698                  std::unique_ptr<base::Value>(new base::Value(1)).get(),
699                  schema.get(), nullptr, std::string(),
700                  JSONSchemaValidator::FormatErrorMessage(
701                      JSONSchemaValidator::kInvalidType, schema::kBoolean,
702                      schema::kInteger));
703 
704   schema->SetString(schema::kType, schema::kNull);
705   ExpectNotValid(
706       TEST_SOURCE, std::unique_ptr<base::Value>(new base::Value(false)).get(),
707       schema.get(), nullptr, std::string(),
708       JSONSchemaValidator::FormatErrorMessage(JSONSchemaValidator::kInvalidType,
709                                               schema::kNull, schema::kBoolean));
710 }
711