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; | |
Jun Mukai
2012/05/30 23:51:10
Can you define another struct for custom actions?
| |
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 kUsableData[] = | |
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(kUsableData)); | |
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 kUnusableData[] = | |
316 "{\n" | |
317 " \"conditional\": {\n" | |
318 " \"use\": false,\n" | |
319 " \"value\": \"foo\"\n" | |
320 " }\n" | |
321 "}\n"; | |
322 value.reset(base::JSONReader::Read(kUnusableData)); | |
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 kBrokenData[] = | |
330 "{\n" | |
331 " \"conditional\": {\n" | |
332 " \"value\": \"foo\"\n" | |
333 " }\n" | |
334 "}\n"; | |
335 value.reset(base::JSONReader::Read(kBrokenData)); | |
336 SimpleMessage broken_message; | |
337 EXPECT_FALSE(converter.Convert(*value.get(), &broken_message)); | |
338 } | |
339 | |
340 TEST(JSONValueConverterTest, RepeatedCustomAction) { | |
341 const char kData[] = | |
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(kData)); | |
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 kBrokenData[] = | |
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(kBrokenData)); | |
372 EXPECT_FALSE(converter.Convert(*value.get(), &message)); | |
373 } | |
374 | |
256 } // namespace base | 375 } // namespace base |
OLD | NEW |