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/policy/core/common/schema.h" 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/strings/stringprintf.h" 9 #include "components/policy/core/common/schema_internal.h" 10 #include "testing/gtest/include/gtest/gtest.h" 11 12 namespace policy { 13 14 namespace { 15 16 #define TestSchemaValidation(a, b, c, d) \ 17 TestSchemaValidationHelper( \ 18 base::StringPrintf("%s:%i", __FILE__, __LINE__), a, b, c, d) 19 20 const char kTestSchema[] = 21 "{" 22 " \"type\": \"object\"," 23 " \"properties\": {" 24 " \"Boolean\": { \"type\": \"boolean\" }," 25 " \"Integer\": { \"type\": \"integer\" }," 26 " \"Null\": { \"type\": \"null\" }," 27 " \"Number\": { \"type\": \"number\" }," 28 " \"String\": { \"type\": \"string\" }," 29 " \"Array\": {" 30 " \"type\": \"array\"," 31 " \"items\": { \"type\": \"string\" }" 32 " }," 33 " \"ArrayOfObjects\": {" 34 " \"type\": \"array\"," 35 " \"items\": {" 36 " \"type\": \"object\"," 37 " \"properties\": {" 38 " \"one\": { \"type\": \"string\" }," 39 " \"two\": { \"type\": \"integer\" }" 40 " }" 41 " }" 42 " }," 43 " \"ArrayOfArray\": {" 44 " \"type\": \"array\"," 45 " \"items\": {" 46 " \"type\": \"array\"," 47 " \"items\": { \"type\": \"string\" }" 48 " }" 49 " }," 50 " \"Object\": {" 51 " \"type\": \"object\"," 52 " \"properties\": {" 53 " \"one\": { \"type\": \"boolean\" }," 54 " \"two\": { \"type\": \"integer\" }" 55 " }," 56 " \"additionalProperties\": { \"type\": \"string\" }" 57 " }," 58 " \"ObjectOfObject\": {" 59 " \"type\": \"object\"," 60 " \"properties\": {" 61 " \"Object\": {" 62 " \"type\": \"object\"," 63 " \"properties\": {" 64 " \"one\": { \"type\": \"string\" }," 65 " \"two\": { \"type\": \"integer\" }" 66 " }" 67 " }" 68 " }" 69 " }," 70 " \"IntegerWithEnums\": {" 71 " \"type\": \"integer\"," 72 " \"enum\": [1, 2, 3]" 73 " }," 74 " \"IntegerWithEnumsGaps\": {" 75 " \"type\": \"integer\"," 76 " \"enum\": [10, 20, 30]" 77 " }," 78 " \"StringWithEnums\": {" 79 " \"type\": \"string\"," 80 " \"enum\": [\"one\", \"two\", \"three\"]" 81 " }," 82 " \"IntegerWithRange\": {" 83 " \"type\": \"integer\"," 84 " \"minimum\": 1," 85 " \"maximum\": 3" 86 " }," 87 " \"ObjectOfArray\": {" 88 " \"type\": \"object\"," 89 " \"properties\": {" 90 " \"List\": {" 91 " \"type\": \"array\"," 92 " \"items\": { \"type\": \"integer\" }" 93 " }" 94 " }" 95 " }," 96 " \"ArrayOfObjectOfArray\": {" 97 " \"type\": \"array\"," 98 " \"items\": {" 99 " \"type\": \"object\"," 100 " \"properties\": {" 101 " \"List\": {" 102 " \"type\": \"array\"," 103 " \"items\": { \"type\": \"string\" }" 104 " }" 105 " }" 106 " }" 107 " }," 108 " \"StringWithPattern\": {" 109 " \"type\": \"string\"," 110 " \"pattern\": \"^foo+$\"" 111 " }," 112 " \"ObjectWithPatternProperties\": {" 113 " \"type\": \"object\"," 114 " \"patternProperties\": {" 115 " \"^foo+$\": { \"type\": \"integer\" }," 116 " \"^bar+$\": {" 117 " \"type\": \"string\"," 118 " \"enum\": [\"one\", \"two\"]" 119 " }" 120 " }," 121 " \"properties\": {" 122 " \"bar\": {" 123 " \"type\": \"string\"," 124 " \"enum\": [\"one\", \"three\"]" 125 " }" 126 " }" 127 " }" 128 " }" 129 "}"; 130 131 bool ParseFails(const std::string& content) { 132 std::string error; 133 Schema schema = Schema::Parse(content, &error); 134 if (schema.valid()) 135 return false; 136 EXPECT_FALSE(error.empty()); 137 return true; 138 } 139 140 void TestSchemaValidationHelper(const std::string& source, 141 Schema schema, 142 const base::Value& value, 143 SchemaOnErrorStrategy strategy, 144 bool expected_return_value) { 145 std::string error; 146 static const char kNoErrorReturned[] = "No error returned."; 147 148 // Test that Schema::Validate() works as expected. 149 error = kNoErrorReturned; 150 bool returned = schema.Validate(value, strategy, NULL, &error); 151 ASSERT_EQ(expected_return_value, returned) << source << ": " << error; 152 153 // Test that Schema::Normalize() will return the same value as 154 // Schema::Validate(). 155 error = kNoErrorReturned; 156 scoped_ptr<base::Value> cloned_value(value.DeepCopy()); 157 bool touched = false; 158 returned = 159 schema.Normalize(cloned_value.get(), strategy, NULL, &error, &touched); 160 EXPECT_EQ(expected_return_value, returned) << source << ": " << error; 161 162 bool strictly_valid = schema.Validate(value, SCHEMA_STRICT, NULL, &error); 163 EXPECT_EQ(touched, !strictly_valid && returned) << source; 164 165 // Test that Schema::Normalize() have actually dropped invalid and unknown 166 // properties. 167 if (expected_return_value) { 168 EXPECT_TRUE( 169 schema.Validate(*cloned_value.get(), SCHEMA_STRICT, NULL, &error)) 170 << source; 171 EXPECT_TRUE( 172 schema.Normalize(cloned_value.get(), SCHEMA_STRICT, NULL, &error, NULL)) 173 << source; 174 } 175 } 176 177 void TestSchemaValidationWithPath(Schema schema, 178 const base::Value& value, 179 const std::string& expected_failure_path) { 180 std::string error_path = "NOT_SET"; 181 std::string error; 182 183 bool returned = schema.Validate(value, SCHEMA_STRICT, &error_path, &error); 184 ASSERT_FALSE(returned) << error_path; 185 EXPECT_EQ(error_path, expected_failure_path); 186 } 187 188 std::string SchemaObjectWrapper(const std::string& subschema) { 189 return "{" 190 " \"type\": \"object\"," 191 " \"properties\": {" 192 " \"SomePropertyName\":" + subschema + 193 " }" 194 "}"; 195 } 196 197 } // namespace 198 199 TEST(SchemaTest, MinimalSchema) { 200 EXPECT_FALSE(ParseFails("{ \"type\": \"object\" }")); 201 } 202 203 TEST(SchemaTest, InvalidSchemas) { 204 EXPECT_TRUE(ParseFails("")); 205 EXPECT_TRUE(ParseFails("omg")); 206 EXPECT_TRUE(ParseFails("\"omg\"")); 207 EXPECT_TRUE(ParseFails("123")); 208 EXPECT_TRUE(ParseFails("[]")); 209 EXPECT_TRUE(ParseFails("null")); 210 EXPECT_TRUE(ParseFails("{}")); 211 212 EXPECT_TRUE(ParseFails( 213 "{" 214 " \"type\": \"object\"," 215 "\"additionalProperties\": { \"type\":\"object\" }" 216 "}")); 217 218 EXPECT_TRUE(ParseFails( 219 "{" 220 " \"type\": \"object\"," 221 " \"patternProperties\": { \"a+b*\": { \"type\": \"object\" } }" 222 "}")); 223 224 EXPECT_TRUE(ParseFails( 225 "{" 226 " \"type\": \"object\"," 227 " \"properties\": { \"Policy\": { \"type\": \"bogus\" } }" 228 "}")); 229 230 EXPECT_TRUE(ParseFails( 231 "{" 232 " \"type\": \"object\"," 233 " \"properties\": { \"Policy\": { \"type\": [\"string\", \"number\"] } }" 234 "}")); 235 236 EXPECT_TRUE(ParseFails( 237 "{" 238 " \"type\": \"object\"," 239 " \"properties\": { \"Policy\": { \"type\": \"any\" } }" 240 "}")); 241 242 EXPECT_TRUE(ParseFails( 243 "{" 244 " \"type\": \"object\"," 245 " \"properties\": { \"Policy\": 123 }" 246 "}")); 247 248 EXPECT_FALSE(ParseFails( 249 "{" 250 " \"type\": \"object\"," 251 " \"unknown attribute\": \"is ignored\"" 252 "}")); 253 } 254 255 TEST(SchemaTest, Ownership) { 256 std::string error; 257 Schema schema = Schema::Parse( 258 "{" 259 " \"type\": \"object\"," 260 " \"properties\": {" 261 " \"sub\": {" 262 " \"type\": \"object\"," 263 " \"properties\": {" 264 " \"subsub\": { \"type\": \"string\" }" 265 " }" 266 " }" 267 " }" 268 "}", &error); 269 ASSERT_TRUE(schema.valid()) << error; 270 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 271 272 schema = schema.GetKnownProperty("sub"); 273 ASSERT_TRUE(schema.valid()); 274 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 275 276 { 277 Schema::Iterator it = schema.GetPropertiesIterator(); 278 ASSERT_FALSE(it.IsAtEnd()); 279 EXPECT_STREQ("subsub", it.key()); 280 281 schema = it.schema(); 282 it.Advance(); 283 EXPECT_TRUE(it.IsAtEnd()); 284 } 285 286 ASSERT_TRUE(schema.valid()); 287 EXPECT_EQ(base::Value::TYPE_STRING, schema.type()); 288 289 // This test shouldn't leak nor use invalid memory. 290 } 291 292 TEST(SchemaTest, ValidSchema) { 293 std::string error; 294 Schema schema = Schema::Parse(kTestSchema, &error); 295 ASSERT_TRUE(schema.valid()) << error; 296 297 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 298 EXPECT_FALSE(schema.GetProperty("invalid").valid()); 299 300 Schema sub = schema.GetProperty("Boolean"); 301 ASSERT_TRUE(sub.valid()); 302 EXPECT_EQ(base::Value::TYPE_BOOLEAN, sub.type()); 303 304 sub = schema.GetProperty("Integer"); 305 ASSERT_TRUE(sub.valid()); 306 EXPECT_EQ(base::Value::TYPE_INTEGER, sub.type()); 307 308 sub = schema.GetProperty("Null"); 309 ASSERT_TRUE(sub.valid()); 310 EXPECT_EQ(base::Value::TYPE_NULL, sub.type()); 311 312 sub = schema.GetProperty("Number"); 313 ASSERT_TRUE(sub.valid()); 314 EXPECT_EQ(base::Value::TYPE_DOUBLE, sub.type()); 315 316 sub = schema.GetProperty("String"); 317 ASSERT_TRUE(sub.valid()); 318 EXPECT_EQ(base::Value::TYPE_STRING, sub.type()); 319 320 sub = schema.GetProperty("Array"); 321 ASSERT_TRUE(sub.valid()); 322 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 323 sub = sub.GetItems(); 324 ASSERT_TRUE(sub.valid()); 325 EXPECT_EQ(base::Value::TYPE_STRING, sub.type()); 326 327 sub = schema.GetProperty("ArrayOfObjects"); 328 ASSERT_TRUE(sub.valid()); 329 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 330 sub = sub.GetItems(); 331 ASSERT_TRUE(sub.valid()); 332 EXPECT_EQ(base::Value::TYPE_DICTIONARY, sub.type()); 333 Schema subsub = sub.GetProperty("one"); 334 ASSERT_TRUE(subsub.valid()); 335 EXPECT_EQ(base::Value::TYPE_STRING, subsub.type()); 336 subsub = sub.GetProperty("two"); 337 ASSERT_TRUE(subsub.valid()); 338 EXPECT_EQ(base::Value::TYPE_INTEGER, subsub.type()); 339 subsub = sub.GetProperty("invalid"); 340 EXPECT_FALSE(subsub.valid()); 341 342 sub = schema.GetProperty("ArrayOfArray"); 343 ASSERT_TRUE(sub.valid()); 344 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 345 sub = sub.GetItems(); 346 ASSERT_TRUE(sub.valid()); 347 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 348 sub = sub.GetItems(); 349 ASSERT_TRUE(sub.valid()); 350 EXPECT_EQ(base::Value::TYPE_STRING, sub.type()); 351 352 sub = schema.GetProperty("Object"); 353 ASSERT_TRUE(sub.valid()); 354 ASSERT_EQ(base::Value::TYPE_DICTIONARY, sub.type()); 355 subsub = sub.GetProperty("one"); 356 ASSERT_TRUE(subsub.valid()); 357 EXPECT_EQ(base::Value::TYPE_BOOLEAN, subsub.type()); 358 subsub = sub.GetProperty("two"); 359 ASSERT_TRUE(subsub.valid()); 360 EXPECT_EQ(base::Value::TYPE_INTEGER, subsub.type()); 361 subsub = sub.GetProperty("undeclared"); 362 ASSERT_TRUE(subsub.valid()); 363 EXPECT_EQ(base::Value::TYPE_STRING, subsub.type()); 364 365 sub = schema.GetProperty("IntegerWithEnums"); 366 ASSERT_TRUE(sub.valid()); 367 ASSERT_EQ(base::Value::TYPE_INTEGER, sub.type()); 368 369 sub = schema.GetProperty("IntegerWithEnumsGaps"); 370 ASSERT_TRUE(sub.valid()); 371 ASSERT_EQ(base::Value::TYPE_INTEGER, sub.type()); 372 373 sub = schema.GetProperty("StringWithEnums"); 374 ASSERT_TRUE(sub.valid()); 375 ASSERT_EQ(base::Value::TYPE_STRING, sub.type()); 376 377 sub = schema.GetProperty("IntegerWithRange"); 378 ASSERT_TRUE(sub.valid()); 379 ASSERT_EQ(base::Value::TYPE_INTEGER, sub.type()); 380 381 sub = schema.GetProperty("StringWithPattern"); 382 ASSERT_TRUE(sub.valid()); 383 ASSERT_EQ(base::Value::TYPE_STRING, sub.type()); 384 385 sub = schema.GetProperty("ObjectWithPatternProperties"); 386 ASSERT_TRUE(sub.valid()); 387 ASSERT_EQ(base::Value::TYPE_DICTIONARY, sub.type()); 388 389 struct { 390 const char* expected_key; 391 base::Value::Type expected_type; 392 } kExpectedProperties[] = { 393 { "Array", base::Value::TYPE_LIST }, 394 { "ArrayOfArray", base::Value::TYPE_LIST }, 395 { "ArrayOfObjectOfArray", base::Value::TYPE_LIST }, 396 { "ArrayOfObjects", base::Value::TYPE_LIST }, 397 { "Boolean", base::Value::TYPE_BOOLEAN }, 398 { "Integer", base::Value::TYPE_INTEGER }, 399 { "IntegerWithEnums", base::Value::TYPE_INTEGER }, 400 { "IntegerWithEnumsGaps", base::Value::TYPE_INTEGER }, 401 { "IntegerWithRange", base::Value::TYPE_INTEGER }, 402 { "Null", base::Value::TYPE_NULL }, 403 { "Number", base::Value::TYPE_DOUBLE }, 404 { "Object", base::Value::TYPE_DICTIONARY }, 405 { "ObjectOfArray", base::Value::TYPE_DICTIONARY }, 406 { "ObjectOfObject", base::Value::TYPE_DICTIONARY }, 407 { "ObjectWithPatternProperties", base::Value::TYPE_DICTIONARY }, 408 { "String", base::Value::TYPE_STRING }, 409 { "StringWithEnums", base::Value::TYPE_STRING }, 410 { "StringWithPattern", base::Value::TYPE_STRING }, 411 }; 412 Schema::Iterator it = schema.GetPropertiesIterator(); 413 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpectedProperties); ++i) { 414 ASSERT_FALSE(it.IsAtEnd()); 415 EXPECT_STREQ(kExpectedProperties[i].expected_key, it.key()); 416 ASSERT_TRUE(it.schema().valid()); 417 EXPECT_EQ(kExpectedProperties[i].expected_type, it.schema().type()); 418 it.Advance(); 419 } 420 EXPECT_TRUE(it.IsAtEnd()); 421 } 422 423 TEST(SchemaTest, Lookups) { 424 std::string error; 425 426 Schema schema = Schema::Parse("{ \"type\": \"object\" }", &error); 427 ASSERT_TRUE(schema.valid()) << error; 428 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 429 430 // This empty schema should never find named properties. 431 EXPECT_FALSE(schema.GetKnownProperty("").valid()); 432 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); 433 EXPECT_TRUE(schema.GetPropertiesIterator().IsAtEnd()); 434 435 schema = Schema::Parse( 436 "{" 437 " \"type\": \"object\"," 438 " \"properties\": {" 439 " \"Boolean\": { \"type\": \"boolean\" }" 440 " }" 441 "}", &error); 442 ASSERT_TRUE(schema.valid()) << error; 443 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 444 445 EXPECT_FALSE(schema.GetKnownProperty("").valid()); 446 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); 447 EXPECT_TRUE(schema.GetKnownProperty("Boolean").valid()); 448 449 schema = Schema::Parse( 450 "{" 451 " \"type\": \"object\"," 452 " \"properties\": {" 453 " \"bb\" : { \"type\": \"null\" }," 454 " \"aa\" : { \"type\": \"boolean\" }," 455 " \"abab\" : { \"type\": \"string\" }," 456 " \"ab\" : { \"type\": \"number\" }," 457 " \"aba\" : { \"type\": \"integer\" }" 458 " }" 459 "}", &error); 460 ASSERT_TRUE(schema.valid()) << error; 461 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 462 463 EXPECT_FALSE(schema.GetKnownProperty("").valid()); 464 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); 465 466 struct { 467 const char* expected_key; 468 base::Value::Type expected_type; 469 } kExpectedKeys[] = { 470 { "aa", base::Value::TYPE_BOOLEAN }, 471 { "ab", base::Value::TYPE_DOUBLE }, 472 { "aba", base::Value::TYPE_INTEGER }, 473 { "abab", base::Value::TYPE_STRING }, 474 { "bb", base::Value::TYPE_NULL }, 475 }; 476 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpectedKeys); ++i) { 477 Schema sub = schema.GetKnownProperty(kExpectedKeys[i].expected_key); 478 ASSERT_TRUE(sub.valid()); 479 EXPECT_EQ(kExpectedKeys[i].expected_type, sub.type()); 480 } 481 } 482 483 TEST(SchemaTest, Wrap) { 484 const internal::SchemaNode kSchemas[] = { 485 { base::Value::TYPE_DICTIONARY, 0 }, // 0: root node 486 { base::Value::TYPE_BOOLEAN, -1 }, // 1 487 { base::Value::TYPE_INTEGER, -1 }, // 2 488 { base::Value::TYPE_DOUBLE, -1 }, // 3 489 { base::Value::TYPE_STRING, -1 }, // 4 490 { base::Value::TYPE_LIST, 4 }, // 5: list of strings. 491 { base::Value::TYPE_LIST, 5 }, // 6: list of lists of strings. 492 { base::Value::TYPE_INTEGER, 0 }, // 7: integer enumerations. 493 { base::Value::TYPE_INTEGER, 1 }, // 8: ranged integers. 494 { base::Value::TYPE_STRING, 2 }, // 9: string enumerations. 495 { base::Value::TYPE_STRING, 3 }, // 10: string with pattern. 496 }; 497 498 const internal::PropertyNode kPropertyNodes[] = { 499 { "Boolean", 1 }, // 0 500 { "Integer", 2 }, // 1 501 { "Number", 3 }, // 2 502 { "String", 4 }, // 3 503 { "List", 5 }, // 4 504 { "IntEnum", 7 }, // 5 505 { "RangedInt", 8 }, // 6 506 { "StrEnum", 9 }, // 7 507 { "StrPat", 10 }, // 8 508 { "bar+$", 4 }, // 9 509 }; 510 511 const internal::PropertiesNode kProperties[] = { 512 // 0 to 9 (exclusive) are the known properties in kPropertyNodes, 9 is 513 // patternProperties and 6 is the additionalProperties node. 514 { 0, 9, 10, 6 }, 515 }; 516 517 const internal::RestrictionNode kRestriction[] = { 518 {{0, 3}}, // 0: [1, 2, 3] 519 {{5, 1}}, // 1: minimum = 1, maximum = 5 520 {{0, 3}}, // 2: ["one", "two", "three"] 521 {{3, 3}}, // 3: pattern "foo+" 522 }; 523 524 const int kIntEnums[] = {1, 2, 3}; 525 526 const char* kStringEnums[] = { 527 "one", // 0 528 "two", // 1 529 "three", // 2 530 "foo+", // 3 531 }; 532 533 const internal::SchemaData kData = { 534 kSchemas, 535 kPropertyNodes, 536 kProperties, 537 kRestriction, 538 kIntEnums, 539 kStringEnums, 540 }; 541 542 Schema schema = Schema::Wrap(&kData); 543 ASSERT_TRUE(schema.valid()); 544 EXPECT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 545 546 struct { 547 const char* key; 548 base::Value::Type type; 549 } kExpectedProperties[] = { 550 { "Boolean", base::Value::TYPE_BOOLEAN }, 551 { "Integer", base::Value::TYPE_INTEGER }, 552 { "Number", base::Value::TYPE_DOUBLE }, 553 { "String", base::Value::TYPE_STRING }, 554 { "List", base::Value::TYPE_LIST }, 555 { "IntEnum", base::Value::TYPE_INTEGER }, 556 { "RangedInt", base::Value::TYPE_INTEGER }, 557 { "StrEnum", base::Value::TYPE_STRING }, 558 { "StrPat", base::Value::TYPE_STRING }, 559 }; 560 561 Schema::Iterator it = schema.GetPropertiesIterator(); 562 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpectedProperties); ++i) { 563 ASSERT_FALSE(it.IsAtEnd()); 564 EXPECT_STREQ(kExpectedProperties[i].key, it.key()); 565 Schema sub = it.schema(); 566 ASSERT_TRUE(sub.valid()); 567 EXPECT_EQ(kExpectedProperties[i].type, sub.type()); 568 569 if (sub.type() == base::Value::TYPE_LIST) { 570 Schema items = sub.GetItems(); 571 ASSERT_TRUE(items.valid()); 572 EXPECT_EQ(base::Value::TYPE_STRING, items.type()); 573 } 574 575 it.Advance(); 576 } 577 EXPECT_TRUE(it.IsAtEnd()); 578 579 Schema sub = schema.GetAdditionalProperties(); 580 ASSERT_TRUE(sub.valid()); 581 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 582 Schema subsub = sub.GetItems(); 583 ASSERT_TRUE(subsub.valid()); 584 ASSERT_EQ(base::Value::TYPE_LIST, subsub.type()); 585 Schema subsubsub = subsub.GetItems(); 586 ASSERT_TRUE(subsubsub.valid()); 587 ASSERT_EQ(base::Value::TYPE_STRING, subsubsub.type()); 588 589 SchemaList schema_list = schema.GetPatternProperties("barr"); 590 ASSERT_EQ(1u, schema_list.size()); 591 sub = schema_list[0]; 592 ASSERT_TRUE(sub.valid()); 593 EXPECT_EQ(base::Value::TYPE_STRING, sub.type()); 594 595 EXPECT_TRUE(schema.GetPatternProperties("ba").empty()); 596 EXPECT_TRUE(schema.GetPatternProperties("bar+$").empty()); 597 } 598 599 TEST(SchemaTest, Validate) { 600 std::string error; 601 Schema schema = Schema::Parse(kTestSchema, &error); 602 ASSERT_TRUE(schema.valid()) << error; 603 604 base::DictionaryValue bundle; 605 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, true); 606 607 // Wrong type, expected integer. 608 bundle.SetBoolean("Integer", true); 609 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 610 611 // Wrong type, expected list of strings. 612 { 613 bundle.Clear(); 614 base::ListValue list; 615 list.AppendInteger(1); 616 bundle.Set("Array", list.DeepCopy()); 617 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 618 } 619 620 // Wrong type in a sub-object. 621 { 622 bundle.Clear(); 623 base::DictionaryValue dict; 624 dict.SetString("one", "one"); 625 bundle.Set("Object", dict.DeepCopy()); 626 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 627 } 628 629 // Unknown name. 630 bundle.Clear(); 631 bundle.SetBoolean("Unknown", true); 632 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 633 634 // All of these will be valid. 635 bundle.Clear(); 636 bundle.SetBoolean("Boolean", true); 637 bundle.SetInteger("Integer", 123); 638 bundle.Set("Null", base::Value::CreateNullValue()); 639 bundle.Set("Number", base::Value::CreateDoubleValue(3.14)); 640 bundle.SetString("String", "omg"); 641 642 { 643 base::ListValue list; 644 list.AppendString("a string"); 645 list.AppendString("another string"); 646 bundle.Set("Array", list.DeepCopy()); 647 } 648 649 { 650 base::DictionaryValue dict; 651 dict.SetString("one", "string"); 652 dict.SetInteger("two", 2); 653 base::ListValue list; 654 list.Append(dict.DeepCopy()); 655 list.Append(dict.DeepCopy()); 656 bundle.Set("ArrayOfObjects", list.DeepCopy()); 657 } 658 659 { 660 base::ListValue list; 661 list.AppendString("a string"); 662 list.AppendString("another string"); 663 base::ListValue listlist; 664 listlist.Append(list.DeepCopy()); 665 listlist.Append(list.DeepCopy()); 666 bundle.Set("ArrayOfArray", listlist.DeepCopy()); 667 } 668 669 { 670 base::DictionaryValue dict; 671 dict.SetBoolean("one", true); 672 dict.SetInteger("two", 2); 673 dict.SetString("additionally", "a string"); 674 dict.SetString("and also", "another string"); 675 bundle.Set("Object", dict.DeepCopy()); 676 } 677 678 bundle.SetInteger("IntegerWithEnums", 1); 679 bundle.SetInteger("IntegerWithEnumsGaps", 20); 680 bundle.SetString("StringWithEnums", "two"); 681 bundle.SetInteger("IntegerWithRange", 3); 682 683 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, true); 684 685 bundle.SetInteger("IntegerWithEnums", 0); 686 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 687 bundle.SetInteger("IntegerWithEnums", 1); 688 689 bundle.SetInteger("IntegerWithEnumsGaps", 0); 690 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 691 bundle.SetInteger("IntegerWithEnumsGaps", 9); 692 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 693 bundle.SetInteger("IntegerWithEnumsGaps", 10); 694 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, true); 695 bundle.SetInteger("IntegerWithEnumsGaps", 11); 696 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 697 bundle.SetInteger("IntegerWithEnumsGaps", 19); 698 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 699 bundle.SetInteger("IntegerWithEnumsGaps", 21); 700 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 701 bundle.SetInteger("IntegerWithEnumsGaps", 29); 702 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 703 bundle.SetInteger("IntegerWithEnumsGaps", 30); 704 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, true); 705 bundle.SetInteger("IntegerWithEnumsGaps", 31); 706 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 707 bundle.SetInteger("IntegerWithEnumsGaps", 100); 708 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 709 bundle.SetInteger("IntegerWithEnumsGaps", 20); 710 711 bundle.SetString("StringWithEnums", "FOUR"); 712 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 713 bundle.SetString("StringWithEnums", "two"); 714 715 bundle.SetInteger("IntegerWithRange", 4); 716 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 717 bundle.SetInteger("IntegerWithRange", 3); 718 719 // Unknown top level property. 720 bundle.SetString("boom", "bang"); 721 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 722 TestSchemaValidation(schema, bundle, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, true); 723 TestSchemaValidation(schema, bundle, SCHEMA_ALLOW_UNKNOWN, true); 724 TestSchemaValidationWithPath(schema, bundle, ""); 725 bundle.Remove("boom", NULL); 726 727 // Invalid top level property. 728 bundle.SetInteger("Boolean", 12345); 729 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, false); 730 TestSchemaValidation(schema, bundle, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 731 TestSchemaValidation(schema, bundle, SCHEMA_ALLOW_INVALID, true); 732 TestSchemaValidationWithPath(schema, bundle, "Boolean"); 733 bundle.SetBoolean("Boolean", true); 734 735 // Tests on ObjectOfObject. 736 { 737 Schema subschema = schema.GetProperty("ObjectOfObject"); 738 ASSERT_TRUE(subschema.valid()); 739 base::DictionaryValue root; 740 741 // Unknown property. 742 root.SetBoolean("Object.three", false); 743 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 744 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, false); 745 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, true); 746 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 747 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID, true); 748 TestSchemaValidationWithPath(subschema, root, "Object"); 749 root.Remove("Object.three", NULL); 750 751 // Invalid property. 752 root.SetInteger("Object.one", 12345); 753 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 754 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, false); 755 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, false); 756 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 757 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID, true); 758 TestSchemaValidationWithPath(subschema, root, "Object.one"); 759 root.Remove("Object.one", NULL); 760 } 761 762 // Tests on ArrayOfObjects. 763 { 764 Schema subschema = schema.GetProperty("ArrayOfObjects"); 765 ASSERT_TRUE(subschema.valid()); 766 base::ListValue root; 767 768 // Unknown property. 769 base::DictionaryValue* dict_value = new base::DictionaryValue(); 770 dict_value->SetBoolean("three", true); 771 root.Append(dict_value); // Pass ownership to root. 772 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 773 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, false); 774 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, true); 775 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 776 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID, true); 777 TestSchemaValidationWithPath(subschema, root, "items[0]"); 778 root.Remove(root.GetSize() - 1, NULL); 779 780 // Invalid property. 781 dict_value = new base::DictionaryValue(); 782 dict_value->SetBoolean("two", true); 783 root.Append(dict_value); // Pass ownership to root. 784 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 785 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, false); 786 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, false); 787 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 788 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID, true); 789 TestSchemaValidationWithPath(subschema, root, "items[0].two"); 790 root.Remove(root.GetSize() - 1, NULL); 791 } 792 793 // Tests on ObjectOfArray. 794 { 795 Schema subschema = schema.GetProperty("ObjectOfArray"); 796 ASSERT_TRUE(subschema.valid()); 797 base::DictionaryValue root; 798 799 base::ListValue* list_value = new base::ListValue(); 800 root.Set("List", list_value); // Pass ownership to root. 801 802 // Test that there are not errors here. 803 list_value->Append(new base::FundamentalValue(12345)); 804 TestSchemaValidation(subschema, root, SCHEMA_STRICT, true); 805 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, true); 806 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, true); 807 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 808 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID, true); 809 810 // Invalid list item. 811 list_value->Append(new base::StringValue("blabla")); 812 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 813 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, false); 814 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, false); 815 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 816 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID, true); 817 TestSchemaValidationWithPath(subschema, root, "List.items[1]"); 818 } 819 820 // Tests on ArrayOfObjectOfArray. 821 { 822 Schema subschema = schema.GetProperty("ArrayOfObjectOfArray"); 823 ASSERT_TRUE(subschema.valid()); 824 base::ListValue root; 825 826 base::ListValue* list_value = new base::ListValue(); 827 base::DictionaryValue* dict_value = new base::DictionaryValue(); 828 dict_value->Set("List", list_value); // Pass ownership to dict_value. 829 root.Append(dict_value); // Pass ownership to root. 830 831 // Test that there are not errors here. 832 list_value->Append(new base::StringValue("blabla")); 833 TestSchemaValidation(subschema, root, SCHEMA_STRICT, true); 834 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, true); 835 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, true); 836 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 837 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID, true); 838 839 // Invalid list item. 840 list_value->Append(new base::FundamentalValue(12345)); 841 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 842 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN_TOPLEVEL, false); 843 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, false); 844 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID_TOPLEVEL, true); 845 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_INVALID, true); 846 TestSchemaValidationWithPath(subschema, root, "items[0].List.items[1]"); 847 } 848 849 // Tests on StringWithPattern. 850 { 851 Schema subschema = schema.GetProperty("StringWithPattern"); 852 ASSERT_TRUE(subschema.valid()); 853 854 TestSchemaValidation( 855 subschema, base::StringValue("foobar"), SCHEMA_STRICT, false); 856 TestSchemaValidation( 857 subschema, base::StringValue("foo"), SCHEMA_STRICT, true); 858 TestSchemaValidation( 859 subschema, base::StringValue("fo"), SCHEMA_STRICT, false); 860 TestSchemaValidation( 861 subschema, base::StringValue("fooo"), SCHEMA_STRICT, true); 862 TestSchemaValidation( 863 subschema, base::StringValue("^foo+$"), SCHEMA_STRICT, false); 864 } 865 866 // Tests on ObjectWithPatternProperties. 867 { 868 Schema subschema = schema.GetProperty("ObjectWithPatternProperties"); 869 ASSERT_TRUE(subschema.valid()); 870 base::DictionaryValue root; 871 872 ASSERT_EQ(1u, subschema.GetPatternProperties("fooo").size()); 873 ASSERT_EQ(1u, subschema.GetPatternProperties("foo").size()); 874 ASSERT_EQ(1u, subschema.GetPatternProperties("barr").size()); 875 ASSERT_EQ(1u, subschema.GetPatternProperties("bar").size()); 876 ASSERT_EQ(1u, subschema.GetMatchingProperties("fooo").size()); 877 ASSERT_EQ(1u, subschema.GetMatchingProperties("foo").size()); 878 ASSERT_EQ(1u, subschema.GetMatchingProperties("barr").size()); 879 ASSERT_EQ(2u, subschema.GetMatchingProperties("bar").size()); 880 ASSERT_TRUE(subschema.GetPatternProperties("foobar").empty()); 881 882 root.SetInteger("fooo", 123); 883 TestSchemaValidation(subschema, root, SCHEMA_STRICT, true); 884 root.SetBoolean("fooo", false); 885 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 886 root.Remove("fooo", NULL); 887 888 root.SetInteger("foo", 123); 889 TestSchemaValidation(subschema, root, SCHEMA_STRICT, true); 890 root.SetBoolean("foo", false); 891 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 892 root.Remove("foo", NULL); 893 894 root.SetString("barr", "one"); 895 TestSchemaValidation(subschema, root, SCHEMA_STRICT, true); 896 root.SetString("barr", "three"); 897 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 898 root.SetBoolean("barr", false); 899 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 900 root.Remove("barr", NULL); 901 902 root.SetString("bar", "one"); 903 TestSchemaValidation(subschema, root, SCHEMA_STRICT, true); 904 root.SetString("bar", "two"); 905 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 906 root.SetString("bar", "three"); 907 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 908 root.Remove("bar", NULL); 909 910 root.SetInteger("foobar", 123); 911 TestSchemaValidation(subschema, root, SCHEMA_STRICT, false); 912 TestSchemaValidation(subschema, root, SCHEMA_ALLOW_UNKNOWN, true); 913 root.Remove("foobar", NULL); 914 } 915 916 // Test that integer to double promotion is allowed. 917 bundle.SetInteger("Number", 31415); 918 TestSchemaValidation(schema, bundle, SCHEMA_STRICT, true); 919 } 920 921 TEST(SchemaTest, InvalidReferences) { 922 // References to undeclared schemas fail. 923 EXPECT_TRUE(ParseFails( 924 "{" 925 " \"type\": \"object\"," 926 " \"properties\": {" 927 " \"name\": { \"$ref\": \"undeclared\" }" 928 " }" 929 "}")); 930 931 // Can't refer to self. 932 EXPECT_TRUE(ParseFails( 933 "{" 934 " \"type\": \"object\"," 935 " \"properties\": {" 936 " \"name\": {" 937 " \"id\": \"self\"," 938 " \"$ref\": \"self\"" 939 " }" 940 " }" 941 "}")); 942 943 // Duplicated IDs are invalid. 944 EXPECT_TRUE(ParseFails( 945 "{" 946 " \"type\": \"object\"," 947 " \"properties\": {" 948 " \"name\": {" 949 " \"id\": \"x\"," 950 " \"type\": \"string\"" 951 " }," 952 " \"another\": {" 953 " \"id\": \"x\"," 954 " \"type\": \"string\"" 955 " }" 956 " }" 957 "}")); 958 959 // Main object can't be a reference. 960 EXPECT_TRUE(ParseFails( 961 "{" 962 " \"type\": \"object\"," 963 " \"id\": \"main\"," 964 " \"$ref\": \"main\"" 965 "}")); 966 967 EXPECT_TRUE(ParseFails( 968 "{" 969 " \"type\": \"object\"," 970 " \"$ref\": \"main\"" 971 "}")); 972 } 973 974 TEST(SchemaTest, RecursiveReferences) { 975 // Verifies that references can go to a parent schema, to define a 976 // recursive type. 977 std::string error; 978 Schema schema = Schema::Parse( 979 "{" 980 " \"type\": \"object\"," 981 " \"properties\": {" 982 " \"bookmarks\": {" 983 " \"type\": \"array\"," 984 " \"id\": \"ListOfBookmarks\"," 985 " \"items\": {" 986 " \"type\": \"object\"," 987 " \"properties\": {" 988 " \"name\": { \"type\": \"string\" }," 989 " \"url\": { \"type\": \"string\" }," 990 " \"children\": { \"$ref\": \"ListOfBookmarks\" }" 991 " }" 992 " }" 993 " }" 994 " }" 995 "}", &error); 996 ASSERT_TRUE(schema.valid()) << error; 997 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 998 999 Schema parent = schema.GetKnownProperty("bookmarks"); 1000 ASSERT_TRUE(parent.valid()); 1001 ASSERT_EQ(base::Value::TYPE_LIST, parent.type()); 1002 1003 // Check the recursive type a number of times. 1004 for (int i = 0; i < 10; ++i) { 1005 Schema items = parent.GetItems(); 1006 ASSERT_TRUE(items.valid()); 1007 ASSERT_EQ(base::Value::TYPE_DICTIONARY, items.type()); 1008 1009 Schema prop = items.GetKnownProperty("name"); 1010 ASSERT_TRUE(prop.valid()); 1011 ASSERT_EQ(base::Value::TYPE_STRING, prop.type()); 1012 1013 prop = items.GetKnownProperty("url"); 1014 ASSERT_TRUE(prop.valid()); 1015 ASSERT_EQ(base::Value::TYPE_STRING, prop.type()); 1016 1017 prop = items.GetKnownProperty("children"); 1018 ASSERT_TRUE(prop.valid()); 1019 ASSERT_EQ(base::Value::TYPE_LIST, prop.type()); 1020 1021 parent = prop; 1022 } 1023 } 1024 1025 TEST(SchemaTest, UnorderedReferences) { 1026 // Verifies that references and IDs can come in any order. 1027 std::string error; 1028 Schema schema = Schema::Parse( 1029 "{" 1030 " \"type\": \"object\"," 1031 " \"properties\": {" 1032 " \"a\": { \"$ref\": \"shared\" }," 1033 " \"b\": { \"$ref\": \"shared\" }," 1034 " \"c\": { \"$ref\": \"shared\" }," 1035 " \"d\": { \"$ref\": \"shared\" }," 1036 " \"e\": {" 1037 " \"type\": \"boolean\"," 1038 " \"id\": \"shared\"" 1039 " }," 1040 " \"f\": { \"$ref\": \"shared\" }," 1041 " \"g\": { \"$ref\": \"shared\" }," 1042 " \"h\": { \"$ref\": \"shared\" }," 1043 " \"i\": { \"$ref\": \"shared\" }" 1044 " }" 1045 "}", &error); 1046 ASSERT_TRUE(schema.valid()) << error; 1047 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 1048 1049 for (char c = 'a'; c <= 'i'; ++c) { 1050 Schema sub = schema.GetKnownProperty(std::string(1, c)); 1051 ASSERT_TRUE(sub.valid()) << c; 1052 ASSERT_EQ(base::Value::TYPE_BOOLEAN, sub.type()) << c; 1053 } 1054 } 1055 1056 TEST(SchemaTest, AdditionalPropertiesReference) { 1057 // Verifies that "additionalProperties" can be a reference. 1058 std::string error; 1059 Schema schema = Schema::Parse( 1060 "{" 1061 " \"type\": \"object\"," 1062 " \"properties\": {" 1063 " \"policy\": {" 1064 " \"type\": \"object\"," 1065 " \"properties\": {" 1066 " \"foo\": {" 1067 " \"type\": \"boolean\"," 1068 " \"id\": \"FooId\"" 1069 " }" 1070 " }," 1071 " \"additionalProperties\": { \"$ref\": \"FooId\" }" 1072 " }" 1073 " }" 1074 "}", &error); 1075 ASSERT_TRUE(schema.valid()) << error; 1076 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 1077 1078 Schema policy = schema.GetKnownProperty("policy"); 1079 ASSERT_TRUE(policy.valid()); 1080 ASSERT_EQ(base::Value::TYPE_DICTIONARY, policy.type()); 1081 1082 Schema foo = policy.GetKnownProperty("foo"); 1083 ASSERT_TRUE(foo.valid()); 1084 EXPECT_EQ(base::Value::TYPE_BOOLEAN, foo.type()); 1085 1086 Schema additional = policy.GetAdditionalProperties(); 1087 ASSERT_TRUE(additional.valid()); 1088 EXPECT_EQ(base::Value::TYPE_BOOLEAN, additional.type()); 1089 1090 Schema x = policy.GetProperty("x"); 1091 ASSERT_TRUE(x.valid()); 1092 EXPECT_EQ(base::Value::TYPE_BOOLEAN, x.type()); 1093 } 1094 1095 TEST(SchemaTest, ItemsReference) { 1096 // Verifies that "items" can be a reference. 1097 std::string error; 1098 Schema schema = Schema::Parse( 1099 "{" 1100 " \"type\": \"object\"," 1101 " \"properties\": {" 1102 " \"foo\": {" 1103 " \"type\": \"boolean\"," 1104 " \"id\": \"FooId\"" 1105 " }," 1106 " \"list\": {" 1107 " \"type\": \"array\"," 1108 " \"items\": { \"$ref\": \"FooId\" }" 1109 " }" 1110 " }" 1111 "}", &error); 1112 ASSERT_TRUE(schema.valid()) << error; 1113 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 1114 1115 Schema foo = schema.GetKnownProperty("foo"); 1116 ASSERT_TRUE(foo.valid()); 1117 EXPECT_EQ(base::Value::TYPE_BOOLEAN, foo.type()); 1118 1119 Schema list = schema.GetKnownProperty("list"); 1120 ASSERT_TRUE(list.valid()); 1121 ASSERT_EQ(base::Value::TYPE_LIST, list.type()); 1122 1123 Schema items = list.GetItems(); 1124 ASSERT_TRUE(items.valid()); 1125 ASSERT_EQ(base::Value::TYPE_BOOLEAN, items.type()); 1126 } 1127 1128 TEST(SchemaTest, EnumerationRestriction) { 1129 // Enum attribute is a list. 1130 EXPECT_TRUE(ParseFails(SchemaObjectWrapper( 1131 "{" 1132 " \"type\": \"string\"," 1133 " \"enum\": 12" 1134 "}"))); 1135 1136 // Empty enum attributes is not allowed. 1137 EXPECT_TRUE(ParseFails(SchemaObjectWrapper( 1138 "{" 1139 " \"type\": \"integer\"," 1140 " \"enum\": []" 1141 "}"))); 1142 1143 // Enum elements type should be same as stated. 1144 EXPECT_TRUE(ParseFails(SchemaObjectWrapper( 1145 "{" 1146 " \"type\": \"string\"," 1147 " \"enum\": [1, 2, 3]" 1148 "}"))); 1149 1150 EXPECT_FALSE(ParseFails(SchemaObjectWrapper( 1151 "{" 1152 " \"type\": \"integer\"," 1153 " \"enum\": [1, 2, 3]" 1154 "}"))); 1155 1156 EXPECT_FALSE(ParseFails(SchemaObjectWrapper( 1157 "{" 1158 " \"type\": \"string\"," 1159 " \"enum\": [\"1\", \"2\", \"3\"]" 1160 "}"))); 1161 } 1162 1163 TEST(SchemaTest, RangedRestriction) { 1164 EXPECT_TRUE(ParseFails(SchemaObjectWrapper( 1165 "{" 1166 " \"type\": \"integer\"," 1167 " \"minimum\": 10," 1168 " \"maximum\": 5" 1169 "}"))); 1170 1171 EXPECT_FALSE(ParseFails(SchemaObjectWrapper( 1172 "{" 1173 " \"type\": \"integer\"," 1174 " \"minimum\": 10," 1175 " \"maximum\": 20" 1176 "}"))); 1177 } 1178 1179 } // namespace policy 1180