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