| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/policy/core/common/schema.h" | 5 #include "components/policy/core/common/schema.h" |
| 6 | 6 |
| 7 #include "components/policy/core/common/schema_internal.h" | 7 #include "components/policy/core/common/schema_internal.h" |
| 8 #include "testing/gtest/include/gtest/gtest.h" | 8 #include "testing/gtest/include/gtest/gtest.h" |
| 9 | 9 |
| 10 namespace policy { | 10 namespace policy { |
| 11 | 11 |
| 12 namespace { | 12 namespace { |
| 13 | 13 |
| 14 #define OBJECT_TYPE "\"type\":\"object\"" | 14 const 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 "}"; |
| 15 | 54 |
| 16 bool ParseFails(const std::string& content) { | 55 bool ParseFails(const std::string& content) { |
| 17 std::string error; | 56 std::string error; |
| 18 Schema schema = Schema::Parse(content, &error); | 57 Schema schema = Schema::Parse(content, &error); |
| 19 if (schema.valid()) | 58 if (schema.valid()) |
| 20 return false; | 59 return false; |
| 21 EXPECT_FALSE(error.empty()); | 60 EXPECT_FALSE(error.empty()); |
| 22 return true; | 61 return true; |
| 23 } | 62 } |
| 24 | 63 |
| 25 } // namespace | 64 } // namespace |
| 26 | 65 |
| 27 TEST(SchemaTest, MinimalSchema) { | 66 TEST(SchemaTest, MinimalSchema) { |
| 28 EXPECT_FALSE(ParseFails( | 67 EXPECT_FALSE(ParseFails("{ \"type\": \"object\" }")); |
| 29 "{" | |
| 30 OBJECT_TYPE | |
| 31 "}")); | |
| 32 } | 68 } |
| 33 | 69 |
| 34 TEST(SchemaTest, InvalidSchemas) { | 70 TEST(SchemaTest, InvalidSchemas) { |
| 35 EXPECT_TRUE(ParseFails("")); | 71 EXPECT_TRUE(ParseFails("")); |
| 36 EXPECT_TRUE(ParseFails("omg")); | 72 EXPECT_TRUE(ParseFails("omg")); |
| 37 EXPECT_TRUE(ParseFails("\"omg\"")); | 73 EXPECT_TRUE(ParseFails("\"omg\"")); |
| 38 EXPECT_TRUE(ParseFails("123")); | 74 EXPECT_TRUE(ParseFails("123")); |
| 39 EXPECT_TRUE(ParseFails("[]")); | 75 EXPECT_TRUE(ParseFails("[]")); |
| 40 EXPECT_TRUE(ParseFails("null")); | 76 EXPECT_TRUE(ParseFails("null")); |
| 41 EXPECT_TRUE(ParseFails("{}")); | 77 EXPECT_TRUE(ParseFails("{}")); |
| 42 | 78 |
| 43 EXPECT_TRUE(ParseFails( | 79 EXPECT_TRUE(ParseFails( |
| 44 "{" | 80 "{" |
| 45 OBJECT_TYPE "," | 81 " \"type\": \"object\"," |
| 46 "\"additionalProperties\": { \"type\":\"object\" }" | 82 "\"additionalProperties\": { \"type\":\"object\" }" |
| 47 "}")); | 83 "}")); |
| 48 | 84 |
| 49 EXPECT_TRUE(ParseFails( | 85 EXPECT_TRUE(ParseFails( |
| 50 "{" | 86 "{" |
| 51 OBJECT_TYPE "," | 87 " \"type\": \"object\"," |
| 52 "\"patternProperties\": { \"a+b*\": { \"type\": \"object\" } }" | 88 " \"patternProperties\": { \"a+b*\": { \"type\": \"object\" } }" |
| 53 "}")); | 89 "}")); |
| 54 | 90 |
| 55 EXPECT_TRUE(ParseFails( | 91 EXPECT_TRUE(ParseFails( |
| 56 "{" | 92 "{" |
| 57 OBJECT_TYPE "," | 93 " \"type\": \"object\"," |
| 58 "\"properties\": { \"Policy\": { \"type\": \"bogus\" } }" | 94 " \"properties\": { \"Policy\": { \"type\": \"bogus\" } }" |
| 59 "}")); | 95 "}")); |
| 60 | 96 |
| 61 EXPECT_TRUE(ParseFails( | 97 EXPECT_TRUE(ParseFails( |
| 62 "{" | 98 "{" |
| 63 OBJECT_TYPE "," | 99 " \"type\": \"object\"," |
| 64 "\"properties\": { \"Policy\": { \"type\": [\"string\", \"number\"] } }" | 100 " \"properties\": { \"Policy\": { \"type\": [\"string\", \"number\"] } }" |
| 65 "}")); | 101 "}")); |
| 66 | 102 |
| 67 EXPECT_TRUE(ParseFails( | 103 EXPECT_TRUE(ParseFails( |
| 68 "{" | 104 "{" |
| 69 OBJECT_TYPE "," | 105 " \"type\": \"object\"," |
| 70 "\"properties\": { \"Policy\": { \"type\": \"any\" } }" | 106 " \"properties\": { \"Policy\": { \"type\": \"any\" } }" |
| 71 "}")); | 107 "}")); |
| 72 } | 108 } |
| 73 | 109 |
| 74 TEST(SchemaTest, Ownership) { | 110 TEST(SchemaTest, Ownership) { |
| 75 std::string error; | 111 std::string error; |
| 76 Schema schema = Schema::Parse( | 112 Schema schema = Schema::Parse( |
| 77 "{" | 113 "{" |
| 78 OBJECT_TYPE "," | 114 " \"type\": \"object\"," |
| 79 "\"properties\": {" | 115 " \"properties\": {" |
| 80 "\"sub\": {" | 116 " \"sub\": {" |
| 81 "\"type\": \"object\"," | 117 " \"type\": \"object\"," |
| 82 "\"properties\": {" | 118 " \"properties\": {" |
| 83 "\"subsub\": { \"type\": \"string\" }" | 119 " \"subsub\": { \"type\": \"string\" }" |
| 84 "}" | 120 " }" |
| 85 "}" | 121 " }" |
| 86 "}" | 122 " }" |
| 87 "}", &error); | 123 "}", &error); |
| 88 ASSERT_TRUE(schema.valid()) << error; | 124 ASSERT_TRUE(schema.valid()) << error; |
| 89 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); | 125 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); |
| 90 | 126 |
| 91 schema = schema.GetKnownProperty("sub"); | 127 schema = schema.GetKnownProperty("sub"); |
| 92 ASSERT_TRUE(schema.valid()); | 128 ASSERT_TRUE(schema.valid()); |
| 93 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); | 129 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); |
| 94 | 130 |
| 95 { | 131 { |
| 96 Schema::Iterator it = schema.GetPropertiesIterator(); | 132 Schema::Iterator it = schema.GetPropertiesIterator(); |
| 97 ASSERT_FALSE(it.IsAtEnd()); | 133 ASSERT_FALSE(it.IsAtEnd()); |
| 98 EXPECT_STREQ("subsub", it.key()); | 134 EXPECT_STREQ("subsub", it.key()); |
| 99 | 135 |
| 100 schema = it.schema(); | 136 schema = it.schema(); |
| 101 it.Advance(); | 137 it.Advance(); |
| 102 EXPECT_TRUE(it.IsAtEnd()); | 138 EXPECT_TRUE(it.IsAtEnd()); |
| 103 } | 139 } |
| 104 | 140 |
| 105 ASSERT_TRUE(schema.valid()); | 141 ASSERT_TRUE(schema.valid()); |
| 106 EXPECT_EQ(base::Value::TYPE_STRING, schema.type()); | 142 EXPECT_EQ(base::Value::TYPE_STRING, schema.type()); |
| 107 | 143 |
| 108 // This test shouldn't leak nor use invalid memory. | 144 // This test shouldn't leak nor use invalid memory. |
| 109 } | 145 } |
| 110 | 146 |
| 111 TEST(SchemaTest, ValidSchema) { | 147 TEST(SchemaTest, ValidSchema) { |
| 112 std::string error; | 148 std::string error; |
| 113 Schema schema = Schema::Parse( | 149 Schema schema = Schema::Parse(kTestSchema, &error); |
| 114 "{" | |
| 115 OBJECT_TYPE "," | |
| 116 "\"properties\": {" | |
| 117 " \"Boolean\": { \"type\": \"boolean\" }," | |
| 118 " \"Integer\": { \"type\": \"integer\" }," | |
| 119 " \"Null\": { \"type\": \"null\" }," | |
| 120 " \"Number\": { \"type\": \"number\" }," | |
| 121 " \"String\": { \"type\": \"string\" }," | |
| 122 " \"Array\": {" | |
| 123 " \"type\": \"array\"," | |
| 124 " \"items\": { \"type\": \"string\" }" | |
| 125 " }," | |
| 126 " \"ArrayOfObjects\": {" | |
| 127 " \"type\": \"array\"," | |
| 128 " \"items\": {" | |
| 129 " \"type\": \"object\"," | |
| 130 " \"properties\": {" | |
| 131 " \"one\": { \"type\": \"string\" }," | |
| 132 " \"two\": { \"type\": \"integer\" }" | |
| 133 " }" | |
| 134 " }" | |
| 135 " }," | |
| 136 " \"ArrayOfArray\": {" | |
| 137 " \"type\": \"array\"," | |
| 138 " \"items\": {" | |
| 139 " \"type\": \"array\"," | |
| 140 " \"items\": { \"type\": \"string\" }" | |
| 141 " }" | |
| 142 " }," | |
| 143 " \"Object\": {" | |
| 144 " \"type\": \"object\"," | |
| 145 " \"properties\": {" | |
| 146 " \"one\": { \"type\": \"boolean\" }," | |
| 147 " \"two\": { \"type\": \"integer\" }" | |
| 148 " }," | |
| 149 " \"additionalProperties\": { \"type\": \"string\" }" | |
| 150 " }" | |
| 151 "}" | |
| 152 "}", &error); | |
| 153 ASSERT_TRUE(schema.valid()) << error; | 150 ASSERT_TRUE(schema.valid()) << error; |
| 154 | 151 |
| 155 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); | 152 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); |
| 156 EXPECT_FALSE(schema.GetProperty("invalid").valid()); | 153 EXPECT_FALSE(schema.GetProperty("invalid").valid()); |
| 157 | 154 |
| 158 Schema sub = schema.GetProperty("Boolean"); | 155 Schema sub = schema.GetProperty("Boolean"); |
| 159 ASSERT_TRUE(sub.valid()); | 156 ASSERT_TRUE(sub.valid()); |
| 160 EXPECT_EQ(base::Value::TYPE_BOOLEAN, sub.type()); | 157 EXPECT_EQ(base::Value::TYPE_BOOLEAN, sub.type()); |
| 161 | 158 |
| 162 sub = schema.GetProperty("Integer"); | 159 sub = schema.GetProperty("Integer"); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 ASSERT_TRUE(it.schema().valid()); | 238 ASSERT_TRUE(it.schema().valid()); |
| 242 EXPECT_EQ(kExpectedProperties[i].expected_type, it.schema().type()); | 239 EXPECT_EQ(kExpectedProperties[i].expected_type, it.schema().type()); |
| 243 it.Advance(); | 240 it.Advance(); |
| 244 } | 241 } |
| 245 EXPECT_TRUE(it.IsAtEnd()); | 242 EXPECT_TRUE(it.IsAtEnd()); |
| 246 } | 243 } |
| 247 | 244 |
| 248 TEST(SchemaTest, Lookups) { | 245 TEST(SchemaTest, Lookups) { |
| 249 std::string error; | 246 std::string error; |
| 250 | 247 |
| 251 Schema schema = Schema::Parse( | 248 Schema schema = Schema::Parse("{ \"type\": \"object\" }", &error); |
| 252 "{" | |
| 253 OBJECT_TYPE | |
| 254 "}", &error); | |
| 255 ASSERT_TRUE(schema.valid()) << error; | 249 ASSERT_TRUE(schema.valid()) << error; |
| 256 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); | 250 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); |
| 257 | 251 |
| 258 // This empty schema should never find named properties. | 252 // This empty schema should never find named properties. |
| 259 EXPECT_FALSE(schema.GetKnownProperty("").valid()); | 253 EXPECT_FALSE(schema.GetKnownProperty("").valid()); |
| 260 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); | 254 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); |
| 261 EXPECT_TRUE(schema.GetPropertiesIterator().IsAtEnd()); | 255 EXPECT_TRUE(schema.GetPropertiesIterator().IsAtEnd()); |
| 262 | 256 |
| 263 schema = Schema::Parse( | 257 schema = Schema::Parse( |
| 264 "{" | 258 "{" |
| 265 OBJECT_TYPE "," | 259 " \"type\": \"object\"," |
| 266 "\"properties\": {" | 260 " \"properties\": {" |
| 267 " \"Boolean\": { \"type\": \"boolean\" }" | 261 " \"Boolean\": { \"type\": \"boolean\" }" |
| 268 "}" | 262 " }" |
| 269 "}", &error); | 263 "}", &error); |
| 270 ASSERT_TRUE(schema.valid()) << error; | 264 ASSERT_TRUE(schema.valid()) << error; |
| 271 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); | 265 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); |
| 272 | 266 |
| 273 EXPECT_FALSE(schema.GetKnownProperty("").valid()); | 267 EXPECT_FALSE(schema.GetKnownProperty("").valid()); |
| 274 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); | 268 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); |
| 275 EXPECT_TRUE(schema.GetKnownProperty("Boolean").valid()); | 269 EXPECT_TRUE(schema.GetKnownProperty("Boolean").valid()); |
| 276 | 270 |
| 277 schema = Schema::Parse( | 271 schema = Schema::Parse( |
| 278 "{" | 272 "{" |
| 279 OBJECT_TYPE "," | 273 " \"type\": \"object\"," |
| 280 "\"properties\": {" | 274 " \"properties\": {" |
| 281 " \"bb\" : { \"type\": \"null\" }," | 275 " \"bb\" : { \"type\": \"null\" }," |
| 282 " \"aa\" : { \"type\": \"boolean\" }," | 276 " \"aa\" : { \"type\": \"boolean\" }," |
| 283 " \"abab\" : { \"type\": \"string\" }," | 277 " \"abab\" : { \"type\": \"string\" }," |
| 284 " \"ab\" : { \"type\": \"number\" }," | 278 " \"ab\" : { \"type\": \"number\" }," |
| 285 " \"aba\" : { \"type\": \"integer\" }" | 279 " \"aba\" : { \"type\": \"integer\" }" |
| 286 "}" | 280 " }" |
| 287 "}", &error); | 281 "}", &error); |
| 288 ASSERT_TRUE(schema.valid()) << error; | 282 ASSERT_TRUE(schema.valid()) << error; |
| 289 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); | 283 ASSERT_EQ(base::Value::TYPE_DICTIONARY, schema.type()); |
| 290 | 284 |
| 291 EXPECT_FALSE(schema.GetKnownProperty("").valid()); | 285 EXPECT_FALSE(schema.GetKnownProperty("").valid()); |
| 292 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); | 286 EXPECT_FALSE(schema.GetKnownProperty("xyz").valid()); |
| 293 | 287 |
| 294 struct { | 288 struct { |
| 295 const char* expected_key; | 289 const char* expected_key; |
| 296 base::Value::Type expected_type; | 290 base::Value::Type expected_type; |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 ASSERT_TRUE(sub.valid()); | 371 ASSERT_TRUE(sub.valid()); |
| 378 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); | 372 ASSERT_EQ(base::Value::TYPE_LIST, sub.type()); |
| 379 Schema subsub = sub.GetItems(); | 373 Schema subsub = sub.GetItems(); |
| 380 ASSERT_TRUE(subsub.valid()); | 374 ASSERT_TRUE(subsub.valid()); |
| 381 ASSERT_EQ(base::Value::TYPE_LIST, subsub.type()); | 375 ASSERT_EQ(base::Value::TYPE_LIST, subsub.type()); |
| 382 Schema subsubsub = subsub.GetItems(); | 376 Schema subsubsub = subsub.GetItems(); |
| 383 ASSERT_TRUE(subsubsub.valid()); | 377 ASSERT_TRUE(subsubsub.valid()); |
| 384 ASSERT_EQ(base::Value::TYPE_STRING, subsubsub.type()); | 378 ASSERT_EQ(base::Value::TYPE_STRING, subsubsub.type()); |
| 385 } | 379 } |
| 386 | 380 |
| 381 TEST(SchemaTest, Validate) { |
| 382 std::string error; |
| 383 Schema schema = Schema::Parse(kTestSchema, &error); |
| 384 ASSERT_TRUE(schema.valid()) << error; |
| 385 |
| 386 base::DictionaryValue bundle; |
| 387 EXPECT_TRUE(schema.Validate(bundle)); |
| 388 |
| 389 // Wrong type, expected integer. |
| 390 bundle.SetBoolean("Integer", true); |
| 391 EXPECT_FALSE(schema.Validate(bundle)); |
| 392 |
| 393 // Wrong type, expected list of strings. |
| 394 { |
| 395 bundle.Clear(); |
| 396 base::ListValue list; |
| 397 list.AppendInteger(1); |
| 398 bundle.Set("Array", list.DeepCopy()); |
| 399 EXPECT_FALSE(schema.Validate(bundle)); |
| 400 } |
| 401 |
| 402 // Wrong type in a sub-object. |
| 403 { |
| 404 bundle.Clear(); |
| 405 base::DictionaryValue dict; |
| 406 dict.SetString("one", "one"); |
| 407 bundle.Set("Object", dict.DeepCopy()); |
| 408 EXPECT_FALSE(schema.Validate(bundle)); |
| 409 } |
| 410 |
| 411 // Unknown name. |
| 412 bundle.Clear(); |
| 413 bundle.SetBoolean("Unknown", true); |
| 414 EXPECT_FALSE(schema.Validate(bundle)); |
| 415 |
| 416 // All of these will be valid. |
| 417 bundle.Clear(); |
| 418 bundle.SetBoolean("Boolean", true); |
| 419 bundle.SetInteger("Integer", 123); |
| 420 bundle.Set("Null", base::Value::CreateNullValue()); |
| 421 bundle.Set("Number", base::Value::CreateDoubleValue(3.14)); |
| 422 bundle.SetString("String", "omg"); |
| 423 |
| 424 { |
| 425 base::ListValue list; |
| 426 list.AppendString("a string"); |
| 427 list.AppendString("another string"); |
| 428 bundle.Set("Array", list.DeepCopy()); |
| 429 } |
| 430 |
| 431 { |
| 432 base::DictionaryValue dict; |
| 433 dict.SetString("one", "string"); |
| 434 dict.SetInteger("two", 2); |
| 435 base::ListValue list; |
| 436 list.Append(dict.DeepCopy()); |
| 437 list.Append(dict.DeepCopy()); |
| 438 bundle.Set("ArrayOfObjects", list.DeepCopy()); |
| 439 } |
| 440 |
| 441 { |
| 442 base::ListValue list; |
| 443 list.AppendString("a string"); |
| 444 list.AppendString("another string"); |
| 445 base::ListValue listlist; |
| 446 listlist.Append(list.DeepCopy()); |
| 447 listlist.Append(list.DeepCopy()); |
| 448 bundle.Set("ArrayOfArray", listlist.DeepCopy()); |
| 449 } |
| 450 |
| 451 { |
| 452 base::DictionaryValue dict; |
| 453 dict.SetBoolean("one", true); |
| 454 dict.SetInteger("two", 2); |
| 455 dict.SetString("additionally", "a string"); |
| 456 dict.SetString("and also", "another string"); |
| 457 bundle.Set("Object", dict.DeepCopy()); |
| 458 } |
| 459 |
| 460 EXPECT_TRUE(schema.Validate(bundle)); |
| 461 |
| 462 bundle.SetString("boom", "bang"); |
| 463 EXPECT_FALSE(schema.Validate(bundle)); |
| 464 } |
| 465 |
| 387 } // namespace policy | 466 } // namespace policy |
| OLD | NEW |