OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "base/json/json_value_converter.h" | 5 #include "base/json/json_value_converter.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/values.h" | 10 #include "base/values.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 enum SimpleEnum { | 22 enum SimpleEnum { |
23 FOO, BAR, | 23 FOO, BAR, |
24 }; | 24 }; |
25 int foo; | 25 int foo; |
26 std::string bar; | 26 std::string bar; |
27 bool baz; | 27 bool baz; |
28 bool bstruct; | 28 bool bstruct; |
29 SimpleEnum simple_enum; | 29 SimpleEnum simple_enum; |
30 ScopedVector<int> ints; | 30 ScopedVector<int> ints; |
31 ScopedVector<std::string> string_values; | 31 ScopedVector<std::string> string_values; |
| 32 std::string conditional; |
| 33 std::string email_href; |
| 34 std::string home_href; |
32 SimpleMessage() : foo(0), baz(false), bstruct(false) {} | 35 SimpleMessage() : foo(0), baz(false), bstruct(false) {} |
33 | 36 |
34 static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) { | 37 static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) { |
35 if (value == "foo") { | 38 if (value == "foo") { |
36 *field = FOO; | 39 *field = FOO; |
37 return true; | 40 return true; |
38 } else if (value == "bar") { | 41 } else if (value == "bar") { |
39 *field = BAR; | 42 *field = BAR; |
40 return true; | 43 return true; |
41 } | 44 } |
42 return false; | 45 return false; |
43 } | 46 } |
44 | 47 |
45 static bool HasFieldPresent(const base::Value* value, bool* result) { | 48 static bool HasFieldPresent(const base::Value* value, bool* result) { |
46 *result = value != NULL; | 49 *result = value != NULL; |
47 return true; | 50 return true; |
48 } | 51 } |
49 | 52 |
50 static bool GetValueString(const base::Value* value, std::string* result) { | 53 static bool GetValueString(const base::Value* value, std::string* result) { |
51 const base::DictionaryValue* dict = NULL; | 54 const base::DictionaryValue* dict = NULL; |
52 if (!value->GetAsDictionary(&dict)) | 55 if (!value->GetAsDictionary(&dict)) |
53 return false; | 56 return false; |
54 | 57 |
55 if (!dict->GetString("val", result)) | 58 if (!dict->GetString("val", result)) |
56 return false; | 59 return false; |
57 | 60 |
58 return true; | 61 return true; |
59 } | 62 } |
60 | 63 |
| 64 // Inspects the passed-in DictionaryValue's "use" field. If true, copies the |
| 65 // "value" field to the message's |conditional| member. |
| 66 static bool HandleConditionalField(const base::Value* value, |
| 67 SimpleMessage* object) { |
| 68 const base::DictionaryValue* dict = NULL; |
| 69 if (!value->GetAsDictionary(&dict)) |
| 70 return false; |
| 71 |
| 72 bool use = false; |
| 73 std::string string_value; |
| 74 if (!dict->GetBoolean("use", &use) || |
| 75 !dict->GetString("value", &string_value)) { |
| 76 return false; |
| 77 } |
| 78 if (use) |
| 79 object->conditional = string_value; |
| 80 return true; |
| 81 } |
| 82 |
| 83 // Inspects the passed-in DictionaryValue's "type" field and uses it to |
| 84 // determine which of the message's members should store the "href" field. |
| 85 static bool HandleUrl(const base::Value* value, SimpleMessage* object) { |
| 86 const base::DictionaryValue* dict = NULL; |
| 87 if (!value->GetAsDictionary(&dict)) |
| 88 return false; |
| 89 |
| 90 std::string type, href; |
| 91 if (!dict->GetString("type", &type) || !dict->GetString("href", &href)) |
| 92 return false; |
| 93 |
| 94 if (type == "email") |
| 95 object->email_href = href; |
| 96 else if (type == "home") |
| 97 object->home_href = href; |
| 98 |
| 99 return true; |
| 100 } |
| 101 |
61 static void RegisterJSONConverter( | 102 static void RegisterJSONConverter( |
62 base::JSONValueConverter<SimpleMessage>* converter) { | 103 base::JSONValueConverter<SimpleMessage>* converter) { |
63 converter->RegisterIntField("foo", &SimpleMessage::foo); | 104 converter->RegisterIntField("foo", &SimpleMessage::foo); |
64 converter->RegisterStringField("bar", &SimpleMessage::bar); | 105 converter->RegisterStringField("bar", &SimpleMessage::bar); |
65 converter->RegisterBoolField("baz", &SimpleMessage::baz); | 106 converter->RegisterBoolField("baz", &SimpleMessage::baz); |
66 converter->RegisterCustomField<SimpleEnum>( | 107 converter->RegisterCustomField<SimpleEnum>( |
67 "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum); | 108 "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum); |
68 converter->RegisterRepeatedInt("ints", &SimpleMessage::ints); | 109 converter->RegisterRepeatedInt("ints", &SimpleMessage::ints); |
69 converter->RegisterCustomValueField<bool>("bstruct", | 110 converter->RegisterCustomValueField<bool>("bstruct", |
70 &SimpleMessage::bstruct, | 111 &SimpleMessage::bstruct, |
71 &HasFieldPresent); | 112 &HasFieldPresent); |
72 converter->RegisterRepeatedCustomValue<std::string>( | 113 converter->RegisterRepeatedCustomValue<std::string>( |
73 "string_values", | 114 "string_values", |
74 &SimpleMessage::string_values, | 115 &SimpleMessage::string_values, |
75 &GetValueString); | 116 &GetValueString); |
| 117 converter->RegisterCustomAction("conditional", &HandleConditionalField); |
| 118 converter->RegisterRepeatedCustomAction("url", &HandleUrl); |
76 } | 119 } |
77 }; | 120 }; |
78 | 121 |
79 // For nested messages. | 122 // For nested messages. |
80 struct NestedMessage { | 123 struct NestedMessage { |
81 double foo; | 124 double foo; |
82 SimpleMessage child; | 125 SimpleMessage child; |
83 ScopedVector<SimpleMessage> children; | 126 ScopedVector<SimpleMessage> children; |
84 | 127 |
85 NestedMessage() : foo(0) {} | 128 NestedMessage() : foo(0) {} |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 " \"ints\": [1, false]" | 289 " \"ints\": [1, false]" |
247 "}\n"; | 290 "}\n"; |
248 | 291 |
249 scoped_ptr<Value> value(base::JSONReader::Read(normal_data)); | 292 scoped_ptr<Value> value(base::JSONReader::Read(normal_data)); |
250 SimpleMessage message; | 293 SimpleMessage message; |
251 base::JSONValueConverter<SimpleMessage> converter; | 294 base::JSONValueConverter<SimpleMessage> converter; |
252 EXPECT_FALSE(converter.Convert(*value.get(), &message)); | 295 EXPECT_FALSE(converter.Convert(*value.get(), &message)); |
253 // No check the values as mentioned above. | 296 // No check the values as mentioned above. |
254 } | 297 } |
255 | 298 |
| 299 TEST(JSONValueConverterTest, CustomAction) { |
| 300 // The handler for the "conditional" field checks if the nested dictionary's |
| 301 // "use" field is true and copies its "value" parameter if so. |
| 302 const char usable_data[] = |
| 303 "{\n" |
| 304 " \"conditional\": {\n" |
| 305 " \"use\": true,\n" |
| 306 " \"value\": \"foo\"\n" |
| 307 " }\n" |
| 308 "}\n"; |
| 309 scoped_ptr<Value> value(base::JSONReader::Read(usable_data)); |
| 310 SimpleMessage usable_message; |
| 311 base::JSONValueConverter<SimpleMessage> converter; |
| 312 EXPECT_TRUE(converter.Convert(*value.get(), &usable_message)); |
| 313 EXPECT_EQ("foo", usable_message.conditional); |
| 314 |
| 315 const char non_usable_data[] = |
| 316 "{\n" |
| 317 " \"conditional\": {\n" |
| 318 " \"use\": false,\n" |
| 319 " \"value\": \"foo\"\n" |
| 320 " }\n" |
| 321 "}\n"; |
| 322 value.reset(base::JSONReader::Read(non_usable_data)); |
| 323 SimpleMessage non_usable_message; |
| 324 EXPECT_TRUE(converter.Convert(*value.get(), &non_usable_message)); |
| 325 EXPECT_EQ("", non_usable_message.conditional); |
| 326 |
| 327 // If we pass data that makes the custom handler return false (a missing "use" |
| 328 // field, in this case), conversion should fail. |
| 329 const char broken_data[] = |
| 330 "{\n" |
| 331 " \"conditional\": {\n" |
| 332 " \"value\": \"foo\"\n" |
| 333 " }\n" |
| 334 "}\n"; |
| 335 value.reset(base::JSONReader::Read(broken_data)); |
| 336 SimpleMessage broken_message; |
| 337 EXPECT_FALSE(converter.Convert(*value.get(), &broken_message)); |
| 338 } |
| 339 |
| 340 TEST(JSONValueConverterTest, RepeatedCustomAction) { |
| 341 const char data[] = |
| 342 "{\n" |
| 343 " \"url\": [\n" |
| 344 " {\"type\": \"search\",\n" |
| 345 " \"href\": \"http://www.google.com/\"},\n" |
| 346 " {\"type\": \"home\",\n" |
| 347 " \"href\": \"http://www.example.org/\"},\n" |
| 348 " {\"type\": \"email\",\n" |
| 349 " \"href\": \"mailto:me@example.org\"}\n" |
| 350 " ]\n" |
| 351 "}\n"; |
| 352 scoped_ptr<Value> value(base::JSONReader::Read(data)); |
| 353 SimpleMessage message; |
| 354 base::JSONValueConverter<SimpleMessage> converter; |
| 355 EXPECT_TRUE(converter.Convert(*value.get(), &message)); |
| 356 EXPECT_EQ("mailto:me@example.org", message.email_href); |
| 357 EXPECT_EQ("http://www.example.org/", message.home_href); |
| 358 |
| 359 // If we pass data that makes the custom handler return false (a missing |
| 360 // "type" field for one of the entries, in this case), conversion should fail. |
| 361 const char broken_data[] = |
| 362 "{\n" |
| 363 " \"url\": [\n" |
| 364 " {\"type\": \"search\",\n" |
| 365 " \"href\": \"http://www.google.com/\"},\n" |
| 366 " {\"href\": \"http://www.example.org/\"},\n" |
| 367 " {\"type\": \"email\",\n" |
| 368 " \"href\": \"mailto:me@example.org\"}\n" |
| 369 " ]\n" |
| 370 "}\n"; |
| 371 value.reset(base::JSONReader::Read(broken_data)); |
| 372 EXPECT_FALSE(converter.Convert(*value.get(), &message)); |
| 373 } |
| 374 |
256 } // namespace base | 375 } // namespace base |
OLD | NEW |