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 "components/policy/core/common/schema_internal.h" 8#include "testing/gtest/include/gtest/gtest.h" 9 10namespace policy { 11 12namespace { 13 14const char kTestSchema[] = 15 "{" 16 " \"type\": \"object\"," 17 " \"properties\": {" 18 " \"Boolean\": { \"type\": \"boolean\" }," 19 " \"Integer\": { \"type\": \"integer\" }," 20 " \"Null\": { \"type\": \"null\" }," 21 " \"Number\": { \"type\": \"number\" }," 22 " \"String\": { \"type\": \"string\" }," 23 " \"Array\": {" 24 " \"type\": \"array\"," 25 " \"items\": { \"type\": \"string\" }" 26 " }," 27 " \"ArrayOfObjects\": {" 28 " \"type\": \"array\"," 29 " \"items\": {" 30 " \"type\": \"object\"," 31 " \"properties\": {" 32 " \"one\": { \"type\": \"string\" }," 33 " \"two\": { \"type\": \"integer\" }" 34 " }" 35 " }" 36 " }," 37 " \"ArrayOfArray\": {" 38 " \"type\": \"array\"," 39 " \"items\": {" 40 " \"type\": \"array\"," 41 " \"items\": { \"type\": \"string\" }" 42 " }" 43 " }," 44 " \"Object\": {" 45 " \"type\": \"object\"," 46 " \"properties\": {" 47 " \"one\": { \"type\": \"boolean\" }," 48 " \"two\": { \"type\": \"integer\" }" 49 " }," 50 " \"additionalProperties\": { \"type\": \"string\" }" 51 " }" 52 " }" 53 "}"; 54 55bool ParseFails(const std::string& content) { 56 std::string error; 57 Schema schema = Schema::Parse(content, &error); 58 if (schema.valid()) 59 return false; 60 EXPECT_FALSE(error.empty()); 61 return true; 62} 63 64} // namespace 65 66TEST(SchemaTest, MinimalSchema) { 67 EXPECT_FALSE(ParseFails("{ \"type\": \"object\" }")); 68} 69 70TEST(SchemaTest, InvalidSchemas) { 71 EXPECT_TRUE(ParseFails("")); 72 EXPECT_TRUE(ParseFails("omg")); 73 EXPECT_TRUE(ParseFails("\"omg\"")); 74 EXPECT_TRUE(ParseFails("123")); 75 EXPECT_TRUE(ParseFails("[]")); 76 EXPECT_TRUE(ParseFails("null")); 77 EXPECT_TRUE(ParseFails("{}")); 78 79 EXPECT_TRUE(ParseFails( 80 "{" 81 " \"type\": \"object\"," 82 "\"additionalProperties\": { \"type\":\"object\" }" 83 "}")); 84 85 EXPECT_TRUE(ParseFails( 86 "{" 87 " \"type\": \"object\"," 88 " \"patternProperties\": { \"a+b*\": { \"type\": \"object\" } }" 89 "}")); 90 91 EXPECT_TRUE(ParseFails( 92 "{" 93 " \"type\": \"object\"," 94 " \"properties\": { \"Policy\": { \"type\": \"bogus\" } }" 95 "}")); 96 97 EXPECT_TRUE(ParseFails( 98 "{" 99 " \"type\": \"object\"," 100 " \"properties\": { \"Policy\": { \"type\": [\"string\", \"number\"] } }" 101 "}")); 102 103 EXPECT_TRUE(ParseFails( 104 "{" 105 " \"type\": \"object\"," 106 " \"properties\": { \"Policy\": { \"type\": \"any\" } }" 107 "}")); 108 109 EXPECT_TRUE(ParseFails( 110 "{" 111 " \"type\": \"object\"," 112 " \"properties\": { \"Policy\": 123 }" 113 "}")); 114 115 EXPECT_FALSE(ParseFails( 116 "{" 117 " \"type\": \"object\"," 118 " \"unknown attribute\": \"is ignored\"" 119 "}")); 120} 121 122TEST(SchemaTest, Ownership) { 123 std::string error; 124 Schema schema = Schema::Parse( 125 "{" 126 " \"type\": \"object\"," 127 " \"properties\": {" 128 " \"sub\": {" 129 " \"type\": \"object\"," 130 " \"properties\": {" 131 " \"subsub\": { \"type\": \"string\" }" 132 " }" 133 " }" 134 " }" 135 "}", &error); 136 ASSERT_TRUE(schema.valid()) << error; 137 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 138 139 schema = schema.GetKnownProperty("sub"); 140 ASSERT_TRUE(schema.valid()); 141 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 142 143 { 144 Schema::Iterator it = schema.GetPropertiesIterator(); 145 ASSERT_FALSE(it.IsAtEnd()); 146 EXPECT_STREQ("subsub", it.key()); 147 148 schema = it.schema(); 149 it.Advance(); 150 EXPECT_TRUE(it.IsAtEnd()); 151 } 152 153 ASSERT_TRUE(schema.valid()); 154 EXPECT_EQ(base::Value::TYPE_STRING, schema.type()); 155 156 // This test shouldn't leak nor use invalid memory. 157} 158 159TEST(SchemaTest, ValidSchema) { 160 std::string error; 161 Schema schema = Schema::Parse(kTestSchema, &error); 162 ASSERT_TRUE(schema.valid()) << error; 163 164 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 165 EXPECT_FALSE(schema.GetProperty("invalid").valid()); 166 167 Schema sub = schema.GetProperty("Boolean"); 168 ASSERT_TRUE(sub.valid()); 169 EXPECT_EQ(base::Value::TYPE_BOOLEAN, sub.type()); 170 171 sub = schema.GetProperty("Integer"); 172 ASSERT_TRUE(sub.valid()); 173 EXPECT_EQ(base::Value::TYPE_INTEGER, sub.type()); 174 175 sub = schema.GetProperty("Null"); 176 ASSERT_TRUE(sub.valid()); 177 EXPECT_EQ(base::Value::TYPE_NULL, sub.type()); 178 179 sub = schema.GetProperty("Number"); 180 ASSERT_TRUE(sub.valid()); 181 EXPECT_EQ(base::Value::TYPE_DOUBLE, sub.type()); 182 183 sub = schema.GetProperty("String"); 184 ASSERT_TRUE(sub.valid()); 185 EXPECT_EQ(base::Value::TYPE_STRING, sub.type()); 186 187 sub = schema.GetProperty("Array"); 188 ASSERT_TRUE(sub.valid()); 189 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 190 sub = sub.GetItems(); 191 ASSERT_TRUE(sub.valid()); 192 EXPECT_EQ(base::Value::TYPE_STRING, sub.type()); 193 194 sub = schema.GetProperty("ArrayOfObjects"); 195 ASSERT_TRUE(sub.valid()); 196 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 197 sub = sub.GetItems(); 198 ASSERT_TRUE(sub.valid()); 199 EXPECT_EQ(base::Value::TYPE_DICTIONARY, sub.type()); 200 Schema subsub = sub.GetProperty("one"); 201 ASSERT_TRUE(subsub.valid()); 202 EXPECT_EQ(base::Value::TYPE_STRING, subsub.type()); 203 subsub = sub.GetProperty("two"); 204 ASSERT_TRUE(subsub.valid()); 205 EXPECT_EQ(base::Value::TYPE_INTEGER, subsub.type()); 206 subsub = sub.GetProperty("invalid"); 207 EXPECT_FALSE(subsub.valid()); 208 209 sub = schema.GetProperty("ArrayOfArray"); 210 ASSERT_TRUE(sub.valid()); 211 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 212 sub = sub.GetItems(); 213 ASSERT_TRUE(sub.valid()); 214 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 215 sub = sub.GetItems(); 216 ASSERT_TRUE(sub.valid()); 217 EXPECT_EQ(base::Value::TYPE_STRING, sub.type()); 218 219 sub = schema.GetProperty("Object"); 220 ASSERT_TRUE(sub.valid()); 221 ASSERT_EQ(base::Value::TYPE_DICTIONARY, sub.type()); 222 subsub = sub.GetProperty("one"); 223 ASSERT_TRUE(subsub.valid()); 224 EXPECT_EQ(base::Value::TYPE_BOOLEAN, subsub.type()); 225 subsub = sub.GetProperty("two"); 226 ASSERT_TRUE(subsub.valid()); 227 EXPECT_EQ(base::Value::TYPE_INTEGER, subsub.type()); 228 subsub = sub.GetProperty("undeclared"); 229 ASSERT_TRUE(subsub.valid()); 230 EXPECT_EQ(base::Value::TYPE_STRING, subsub.type()); 231 232 struct { 233 const char* expected_key; 234 base::Value::Type expected_type; 235 } kExpectedProperties[] = { 236 { "Array", base::Value::TYPE_LIST }, 237 { "ArrayOfArray", base::Value::TYPE_LIST }, 238 { "ArrayOfObjects", base::Value::TYPE_LIST }, 239 { "Boolean", base::Value::TYPE_BOOLEAN }, 240 { "Integer", base::Value::TYPE_INTEGER }, 241 { "Null", base::Value::TYPE_NULL }, 242 { "Number", base::Value::TYPE_DOUBLE }, 243 { "Object", base::Value::TYPE_DICTIONARY }, 244 { "String", base::Value::TYPE_STRING }, 245 }; 246 Schema::Iterator it = schema.GetPropertiesIterator(); 247 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpectedProperties); ++i) { 248 ASSERT_FALSE(it.IsAtEnd()); 249 EXPECT_STREQ(kExpectedProperties[i].expected_key, it.key()); 250 ASSERT_TRUE(it.schema().valid()); 251 EXPECT_EQ(kExpectedProperties[i].expected_type, it.schema().type()); 252 it.Advance(); 253 } 254 EXPECT_TRUE(it.IsAtEnd()); 255} 256 257TEST(SchemaTest, Lookups) { 258 std::string error; 259 260 Schema schema = Schema::Parse("{ \"type\": \"object\" }", &error); 261 ASSERT_TRUE(schema.valid()) << error; 262 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 263 264 // This empty schema should never find named properties. 265 EXPECT_FALSE(schema.GetKnownProperty("").valid()); 266 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); 267 EXPECT_TRUE(schema.GetPropertiesIterator().IsAtEnd()); 268 269 schema = Schema::Parse( 270 "{" 271 " \"type\": \"object\"," 272 " \"properties\": {" 273 " \"Boolean\": { \"type\": \"boolean\" }" 274 " }" 275 "}", &error); 276 ASSERT_TRUE(schema.valid()) << error; 277 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 278 279 EXPECT_FALSE(schema.GetKnownProperty("").valid()); 280 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); 281 EXPECT_TRUE(schema.GetKnownProperty("Boolean").valid()); 282 283 schema = Schema::Parse( 284 "{" 285 " \"type\": \"object\"," 286 " \"properties\": {" 287 " \"bb\" : { \"type\": \"null\" }," 288 " \"aa\" : { \"type\": \"boolean\" }," 289 " \"abab\" : { \"type\": \"string\" }," 290 " \"ab\" : { \"type\": \"number\" }," 291 " \"aba\" : { \"type\": \"integer\" }" 292 " }" 293 "}", &error); 294 ASSERT_TRUE(schema.valid()) << error; 295 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 296 297 EXPECT_FALSE(schema.GetKnownProperty("").valid()); 298 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); 299 300 struct { 301 const char* expected_key; 302 base::Value::Type expected_type; 303 } kExpectedKeys[] = { 304 { "aa", base::Value::TYPE_BOOLEAN }, 305 { "ab", base::Value::TYPE_DOUBLE }, 306 { "aba", base::Value::TYPE_INTEGER }, 307 { "abab", base::Value::TYPE_STRING }, 308 { "bb", base::Value::TYPE_NULL }, 309 }; 310 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpectedKeys); ++i) { 311 Schema sub = schema.GetKnownProperty(kExpectedKeys[i].expected_key); 312 ASSERT_TRUE(sub.valid()); 313 EXPECT_EQ(kExpectedKeys[i].expected_type, sub.type()); 314 } 315} 316 317TEST(SchemaTest, Wrap) { 318 const internal::SchemaNode kSchemas[] = { 319 { base::Value::TYPE_DICTIONARY, 0 }, // 0: root node 320 { base::Value::TYPE_BOOLEAN, -1 }, // 1 321 { base::Value::TYPE_INTEGER, -1 }, // 2 322 { base::Value::TYPE_DOUBLE, -1 }, // 3 323 { base::Value::TYPE_STRING, -1 }, // 4 324 { base::Value::TYPE_LIST, 4 }, // 5: list of strings. 325 { base::Value::TYPE_LIST, 5 }, // 6: list of lists of strings. 326 }; 327 328 const internal::PropertyNode kPropertyNodes[] = { 329 { "Boolean", 1 }, 330 { "Integer", 2 }, 331 { "Number", 3 }, 332 { "String", 4 }, 333 { "List", 5 }, 334 }; 335 336 const internal::PropertiesNode kProperties[] = { 337 // Properties 0 to 5 (exclusive) are known, from kPropertyNodes. 338 // SchemaNode offset 6 is for additionalProperties (list of lists). 339 { 0, 5, 6 }, 340 }; 341 342 const internal::SchemaData kData = { 343 kSchemas, 344 kPropertyNodes, 345 kProperties, 346 }; 347 348 Schema schema = Schema::Wrap(&kData); 349 ASSERT_TRUE(schema.valid()); 350 EXPECT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 351 352 struct { 353 const char* key; 354 base::Value::Type type; 355 } kExpectedProperties[] = { 356 { "Boolean", base::Value::TYPE_BOOLEAN }, 357 { "Integer", base::Value::TYPE_INTEGER }, 358 { "Number", base::Value::TYPE_DOUBLE }, 359 { "String", base::Value::TYPE_STRING }, 360 { "List", base::Value::TYPE_LIST }, 361 }; 362 363 Schema::Iterator it = schema.GetPropertiesIterator(); 364 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kExpectedProperties); ++i) { 365 ASSERT_FALSE(it.IsAtEnd()); 366 EXPECT_STREQ(kExpectedProperties[i].key, it.key()); 367 Schema sub = it.schema(); 368 ASSERT_TRUE(sub.valid()); 369 EXPECT_EQ(kExpectedProperties[i].type, sub.type()); 370 371 if (sub.type() == base::Value::TYPE_LIST) { 372 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 373 Schema items = sub.GetItems(); 374 ASSERT_TRUE(items.valid()); 375 EXPECT_EQ(base::Value::TYPE_STRING, items.type()); 376 } 377 378 it.Advance(); 379 } 380 EXPECT_TRUE(it.IsAtEnd()); 381 382 Schema sub = schema.GetAdditionalProperties(); 383 ASSERT_TRUE(sub.valid()); 384 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); 385 Schema subsub = sub.GetItems(); 386 ASSERT_TRUE(subsub.valid()); 387 ASSERT_EQ(base::Value::TYPE_LIST, subsub.type()); 388 Schema subsubsub = subsub.GetItems(); 389 ASSERT_TRUE(subsubsub.valid()); 390 ASSERT_EQ(base::Value::TYPE_STRING, subsubsub.type()); 391} 392 393TEST(SchemaTest, Validate) { 394 std::string error; 395 Schema schema = Schema::Parse(kTestSchema, &error); 396 ASSERT_TRUE(schema.valid()) << error; 397 398 base::DictionaryValue bundle; 399 EXPECT_TRUE(schema.Validate(bundle)); 400 401 // Wrong type, expected integer. 402 bundle.SetBoolean("Integer", true); 403 EXPECT_FALSE(schema.Validate(bundle)); 404 405 // Wrong type, expected list of strings. 406 { 407 bundle.Clear(); 408 base::ListValue list; 409 list.AppendInteger(1); 410 bundle.Set("Array", list.DeepCopy()); 411 EXPECT_FALSE(schema.Validate(bundle)); 412 } 413 414 // Wrong type in a sub-object. 415 { 416 bundle.Clear(); 417 base::DictionaryValue dict; 418 dict.SetString("one", "one"); 419 bundle.Set("Object", dict.DeepCopy()); 420 EXPECT_FALSE(schema.Validate(bundle)); 421 } 422 423 // Unknown name. 424 bundle.Clear(); 425 bundle.SetBoolean("Unknown", true); 426 EXPECT_FALSE(schema.Validate(bundle)); 427 428 // All of these will be valid. 429 bundle.Clear(); 430 bundle.SetBoolean("Boolean", true); 431 bundle.SetInteger("Integer", 123); 432 bundle.Set("Null", base::Value::CreateNullValue()); 433 bundle.Set("Number", base::Value::CreateDoubleValue(3.14)); 434 bundle.SetString("String", "omg"); 435 436 { 437 base::ListValue list; 438 list.AppendString("a string"); 439 list.AppendString("another string"); 440 bundle.Set("Array", list.DeepCopy()); 441 } 442 443 { 444 base::DictionaryValue dict; 445 dict.SetString("one", "string"); 446 dict.SetInteger("two", 2); 447 base::ListValue list; 448 list.Append(dict.DeepCopy()); 449 list.Append(dict.DeepCopy()); 450 bundle.Set("ArrayOfObjects", list.DeepCopy()); 451 } 452 453 { 454 base::ListValue list; 455 list.AppendString("a string"); 456 list.AppendString("another string"); 457 base::ListValue listlist; 458 listlist.Append(list.DeepCopy()); 459 listlist.Append(list.DeepCopy()); 460 bundle.Set("ArrayOfArray", listlist.DeepCopy()); 461 } 462 463 { 464 base::DictionaryValue dict; 465 dict.SetBoolean("one", true); 466 dict.SetInteger("two", 2); 467 dict.SetString("additionally", "a string"); 468 dict.SetString("and also", "another string"); 469 bundle.Set("Object", dict.DeepCopy()); 470 } 471 472 EXPECT_TRUE(schema.Validate(bundle)); 473 474 bundle.SetString("boom", "bang"); 475 EXPECT_FALSE(schema.Validate(bundle)); 476 477} 478TEST(SchemaTest, InvalidReferences) { 479 // References to undeclared schemas fail. 480 EXPECT_TRUE(ParseFails( 481 "{" 482 " \"type\": \"object\"," 483 " \"properties\": {" 484 " \"name\": { \"$ref\": \"undeclared\" }" 485 " }" 486 "}")); 487 488 // Can't refer to self. 489 EXPECT_TRUE(ParseFails( 490 "{" 491 " \"type\": \"object\"," 492 " \"properties\": {" 493 " \"name\": {" 494 " \"id\": \"self\"," 495 " \"$ref\": \"self\"" 496 " }" 497 " }" 498 "}")); 499 500 // Duplicated IDs are invalid. 501 EXPECT_TRUE(ParseFails( 502 "{" 503 " \"type\": \"object\"," 504 " \"properties\": {" 505 " \"name\": {" 506 " \"id\": \"x\"," 507 " \"type\": \"string\"" 508 " }," 509 " \"another\": {" 510 " \"id\": \"x\"," 511 " \"type\": \"string\"" 512 " }" 513 " }" 514 "}")); 515 516 // Main object can't be a reference. 517 EXPECT_TRUE(ParseFails( 518 "{" 519 " \"type\": \"object\"," 520 " \"id\": \"main\"," 521 " \"$ref\": \"main\"" 522 "}")); 523 524 EXPECT_TRUE(ParseFails( 525 "{" 526 " \"type\": \"object\"," 527 " \"$ref\": \"main\"" 528 "}")); 529} 530 531TEST(SchemaTest, RecursiveReferences) { 532 // Verifies that references can go to a parent schema, to define a 533 // recursive type. 534 std::string error; 535 Schema schema = Schema::Parse( 536 "{" 537 " \"type\": \"object\"," 538 " \"properties\": {" 539 " \"bookmarks\": {" 540 " \"type\": \"array\"," 541 " \"id\": \"ListOfBookmarks\"," 542 " \"items\": {" 543 " \"type\": \"object\"," 544 " \"properties\": {" 545 " \"name\": { \"type\": \"string\" }," 546 " \"url\": { \"type\": \"string\" }," 547 " \"children\": { \"$ref\": \"ListOfBookmarks\" }" 548 " }" 549 " }" 550 " }" 551 " }" 552 "}", &error); 553 ASSERT_TRUE(schema.valid()) << error; 554 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 555 556 Schema parent = schema.GetKnownProperty("bookmarks"); 557 ASSERT_TRUE(parent.valid()); 558 ASSERT_EQ(base::Value::TYPE_LIST, parent.type()); 559 560 // Check the recursive type a number of times. 561 for (int i = 0; i < 10; ++i) { 562 Schema items = parent.GetItems(); 563 ASSERT_TRUE(items.valid()); 564 ASSERT_EQ(base::Value::TYPE_DICTIONARY, items.type()); 565 566 Schema prop = items.GetKnownProperty("name"); 567 ASSERT_TRUE(prop.valid()); 568 ASSERT_EQ(base::Value::TYPE_STRING, prop.type()); 569 570 prop = items.GetKnownProperty("url"); 571 ASSERT_TRUE(prop.valid()); 572 ASSERT_EQ(base::Value::TYPE_STRING, prop.type()); 573 574 prop = items.GetKnownProperty("children"); 575 ASSERT_TRUE(prop.valid()); 576 ASSERT_EQ(base::Value::TYPE_LIST, prop.type()); 577 578 parent = prop; 579 } 580} 581 582TEST(SchemaTest, UnorderedReferences) { 583 // Verifies that references and IDs can come in any order. 584 std::string error; 585 Schema schema = Schema::Parse( 586 "{" 587 " \"type\": \"object\"," 588 " \"properties\": {" 589 " \"a\": { \"$ref\": \"shared\" }," 590 " \"b\": { \"$ref\": \"shared\" }," 591 " \"c\": { \"$ref\": \"shared\" }," 592 " \"d\": { \"$ref\": \"shared\" }," 593 " \"e\": {" 594 " \"type\": \"boolean\"," 595 " \"id\": \"shared\"" 596 " }," 597 " \"f\": { \"$ref\": \"shared\" }," 598 " \"g\": { \"$ref\": \"shared\" }," 599 " \"h\": { \"$ref\": \"shared\" }," 600 " \"i\": { \"$ref\": \"shared\" }" 601 " }" 602 "}", &error); 603 ASSERT_TRUE(schema.valid()) << error; 604 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 605 606 for (char c = 'a'; c <= 'i'; ++c) { 607 Schema sub = schema.GetKnownProperty(std::string(1, c)); 608 ASSERT_TRUE(sub.valid()) << c; 609 ASSERT_EQ(base::Value::TYPE_BOOLEAN, sub.type()) << c; 610 } 611} 612 613TEST(SchemaTest, AdditionalPropertiesReference) { 614 // Verifies that "additionalProperties" can be a reference. 615 std::string error; 616 Schema schema = Schema::Parse( 617 "{" 618 " \"type\": \"object\"," 619 " \"properties\": {" 620 " \"policy\": {" 621 " \"type\": \"object\"," 622 " \"properties\": {" 623 " \"foo\": {" 624 " \"type\": \"boolean\"," 625 " \"id\": \"FooId\"" 626 " }" 627 " }," 628 " \"additionalProperties\": { \"$ref\": \"FooId\" }" 629 " }" 630 " }" 631 "}", &error); 632 ASSERT_TRUE(schema.valid()) << error; 633 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 634 635 Schema policy = schema.GetKnownProperty("policy"); 636 ASSERT_TRUE(policy.valid()); 637 ASSERT_EQ(base::Value::TYPE_DICTIONARY, policy.type()); 638 639 Schema foo = policy.GetKnownProperty("foo"); 640 ASSERT_TRUE(foo.valid()); 641 EXPECT_EQ(base::Value::TYPE_BOOLEAN, foo.type()); 642 643 Schema additional = policy.GetAdditionalProperties(); 644 ASSERT_TRUE(additional.valid()); 645 EXPECT_EQ(base::Value::TYPE_BOOLEAN, additional.type()); 646 647 Schema x = policy.GetProperty("x"); 648 ASSERT_TRUE(x.valid()); 649 EXPECT_EQ(base::Value::TYPE_BOOLEAN, x.type()); 650} 651 652TEST(SchemaTest, ItemsReference) { 653 // Verifies that "items" can be a reference. 654 std::string error; 655 Schema schema = Schema::Parse( 656 "{" 657 " \"type\": \"object\"," 658 " \"properties\": {" 659 " \"foo\": {" 660 " \"type\": \"boolean\"," 661 " \"id\": \"FooId\"" 662 " }," 663 " \"list\": {" 664 " \"type\": \"array\"," 665 " \"items\": { \"$ref\": \"FooId\" }" 666 " }" 667 " }" 668 "}", &error); 669 ASSERT_TRUE(schema.valid()) << error; 670 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); 671 672 Schema foo = schema.GetKnownProperty("foo"); 673 ASSERT_TRUE(foo.valid()); 674 EXPECT_EQ(base::Value::TYPE_BOOLEAN, foo.type()); 675 676 Schema list = schema.GetKnownProperty("list"); 677 ASSERT_TRUE(list.valid()); 678 ASSERT_EQ(base::Value::TYPE_LIST, list.type()); 679 680 Schema items = list.GetItems(); 681 ASSERT_TRUE(items.valid()); 682 ASSERT_EQ(base::Value::TYPE_BOOLEAN, items.type()); 683} 684 685 686} // namespace policy 687