json_value_converter_unittest.cc revision 0d205d712abd16eeed2f5d5b1052a367d23a223f
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
3// found in the LICENSE file.
4
5#include "base/json/json_value_converter.h"
6
7#include <string>
8#include <vector>
9
10#include "base/json/json_reader.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/memory/scoped_vector.h"
13#include "base/strings/string_piece.h"
14#include "base/values.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17namespace base {
18namespace {
19
20// Very simple messages.
21struct SimpleMessage {
22  enum SimpleEnum {
23    FOO, BAR,
24  };
25  int foo;
26  std::string bar;
27  bool baz;
28  bool bstruct;
29  SimpleEnum simple_enum;
30  ScopedVector<int> ints;
31  ScopedVector<std::string> string_values;
32  SimpleMessage() : foo(0), baz(false), bstruct(false), simple_enum(FOO) {}
33
34  static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) {
35    if (value == "foo") {
36      *field = FOO;
37      return true;
38    } else if (value == "bar") {
39      *field = BAR;
40      return true;
41    }
42    return false;
43  }
44
45  static bool HasFieldPresent(const base::Value* value, bool* result) {
46    *result = value != NULL;
47    return true;
48  }
49
50  static bool GetValueString(const base::Value* value, std::string* result) {
51    const base::DictionaryValue* dict = NULL;
52    if (!value->GetAsDictionary(&dict))
53      return false;
54
55    if (!dict->GetString("val", result))
56      return false;
57
58    return true;
59  }
60
61  static void RegisterJSONConverter(
62      base::JSONValueConverter<SimpleMessage>* converter) {
63    converter->RegisterIntField("foo", &SimpleMessage::foo);
64    converter->RegisterStringField("bar", &SimpleMessage::bar);
65    converter->RegisterBoolField("baz", &SimpleMessage::baz);
66    converter->RegisterCustomField<SimpleEnum>(
67        "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum);
68    converter->RegisterRepeatedInt("ints", &SimpleMessage::ints);
69    converter->RegisterCustomValueField<bool>("bstruct",
70                                              &SimpleMessage::bstruct,
71                                              &HasFieldPresent);
72    converter->RegisterRepeatedCustomValue<std::string>(
73        "string_values",
74        &SimpleMessage::string_values,
75        &GetValueString);
76  }
77};
78
79// For nested messages.
80struct NestedMessage {
81  double foo;
82  SimpleMessage child;
83  ScopedVector<SimpleMessage> children;
84
85  NestedMessage() : foo(0) {}
86
87  static void RegisterJSONConverter(
88      base::JSONValueConverter<NestedMessage>* converter) {
89    converter->RegisterDoubleField("foo", &NestedMessage::foo);
90    converter->RegisterNestedField("child", &NestedMessage::child);
91    converter->RegisterRepeatedMessage("children", &NestedMessage::children);
92  }
93};
94
95}  // namespace
96
97TEST(JSONValueConverterTest, ParseSimpleMessage) {
98  const char normal_data[] =
99      "{\n"
100      "  \"foo\": 1,\n"
101      "  \"bar\": \"bar\",\n"
102      "  \"baz\": true,\n"
103      "  \"bstruct\": {},\n"
104      "  \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
105      "  \"simple_enum\": \"foo\","
106      "  \"ints\": [1, 2]"
107      "}\n";
108
109  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
110  SimpleMessage message;
111  base::JSONValueConverter<SimpleMessage> converter;
112  EXPECT_TRUE(converter.Convert(*value.get(), &message));
113
114  EXPECT_EQ(1, message.foo);
115  EXPECT_EQ("bar", message.bar);
116  EXPECT_TRUE(message.baz);
117  EXPECT_EQ(SimpleMessage::FOO, message.simple_enum);
118  EXPECT_EQ(2, static_cast<int>(message.ints.size()));
119  ASSERT_EQ(2U, message.string_values.size());
120  EXPECT_EQ("value_1", *message.string_values[0]);
121  EXPECT_EQ("value_2", *message.string_values[1]);
122  EXPECT_EQ(1, *(message.ints[0]));
123  EXPECT_EQ(2, *(message.ints[1]));
124}
125
126TEST(JSONValueConverterTest, ParseNestedMessage) {
127  const char normal_data[] =
128      "{\n"
129      "  \"foo\": 1.0,\n"
130      "  \"child\": {\n"
131      "    \"foo\": 1,\n"
132      "    \"bar\": \"bar\",\n"
133      "    \"bstruct\": {},\n"
134      "    \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
135      "    \"baz\": true\n"
136      "  },\n"
137      "  \"children\": [{\n"
138      "    \"foo\": 2,\n"
139      "    \"bar\": \"foobar\",\n"
140      "    \"bstruct\": \"\",\n"
141      "    \"string_values\": [{\"val\": \"value_1\"}],"
142      "    \"baz\": true\n"
143      "  },\n"
144      "  {\n"
145      "    \"foo\": 3,\n"
146      "    \"bar\": \"barbaz\",\n"
147      "    \"baz\": false\n"
148      "  }]\n"
149      "}\n";
150
151  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
152  NestedMessage message;
153  base::JSONValueConverter<NestedMessage> converter;
154  EXPECT_TRUE(converter.Convert(*value.get(), &message));
155
156  EXPECT_EQ(1.0, message.foo);
157  EXPECT_EQ(1, message.child.foo);
158  EXPECT_EQ("bar", message.child.bar);
159  EXPECT_TRUE(message.child.baz);
160  EXPECT_TRUE(message.child.bstruct);
161  ASSERT_EQ(2U, message.child.string_values.size());
162  EXPECT_EQ("value_1", *message.child.string_values[0]);
163  EXPECT_EQ("value_2", *message.child.string_values[1]);
164
165  EXPECT_EQ(2, static_cast<int>(message.children.size()));
166  const SimpleMessage* first_child = message.children[0];
167  ASSERT_TRUE(first_child);
168  EXPECT_EQ(2, first_child->foo);
169  EXPECT_EQ("foobar", first_child->bar);
170  EXPECT_TRUE(first_child->baz);
171  EXPECT_TRUE(first_child->bstruct);
172  ASSERT_EQ(1U, first_child->string_values.size());
173  EXPECT_EQ("value_1", *first_child->string_values[0]);
174
175  const SimpleMessage* second_child = message.children[1];
176  ASSERT_TRUE(second_child);
177  EXPECT_EQ(3, second_child->foo);
178  EXPECT_EQ("barbaz", second_child->bar);
179  EXPECT_FALSE(second_child->baz);
180  EXPECT_FALSE(second_child->bstruct);
181  EXPECT_EQ(0U, second_child->string_values.size());
182}
183
184TEST(JSONValueConverterTest, ParseFailures) {
185  const char normal_data[] =
186      "{\n"
187      "  \"foo\": 1,\n"
188      "  \"bar\": 2,\n" // "bar" is an integer here.
189      "  \"baz\": true,\n"
190      "  \"ints\": [1, 2]"
191      "}\n";
192
193  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
194  SimpleMessage message;
195  base::JSONValueConverter<SimpleMessage> converter;
196  EXPECT_FALSE(converter.Convert(*value.get(), &message));
197  // Do not check the values below.  |message| may be modified during
198  // Convert() even it fails.
199}
200
201TEST(JSONValueConverterTest, ParseWithMissingFields) {
202  const char normal_data[] =
203      "{\n"
204      "  \"foo\": 1,\n"
205      "  \"baz\": true,\n"
206      "  \"ints\": [1, 2]"
207      "}\n";
208
209  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
210  SimpleMessage message;
211  base::JSONValueConverter<SimpleMessage> converter;
212  // Convert() still succeeds even if the input doesn't have "bar" field.
213  EXPECT_TRUE(converter.Convert(*value.get(), &message));
214
215  EXPECT_EQ(1, message.foo);
216  EXPECT_TRUE(message.baz);
217  EXPECT_EQ(2, static_cast<int>(message.ints.size()));
218  EXPECT_EQ(1, *(message.ints[0]));
219  EXPECT_EQ(2, *(message.ints[1]));
220}
221
222TEST(JSONValueConverterTest, EnumParserFails) {
223  const char normal_data[] =
224      "{\n"
225      "  \"foo\": 1,\n"
226      "  \"bar\": \"bar\",\n"
227      "  \"baz\": true,\n"
228      "  \"simple_enum\": \"baz\","
229      "  \"ints\": [1, 2]"
230      "}\n";
231
232  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
233  SimpleMessage message;
234  base::JSONValueConverter<SimpleMessage> converter;
235  EXPECT_FALSE(converter.Convert(*value.get(), &message));
236  // No check the values as mentioned above.
237}
238
239TEST(JSONValueConverterTest, RepeatedValueErrorInTheMiddle) {
240  const char normal_data[] =
241      "{\n"
242      "  \"foo\": 1,\n"
243      "  \"bar\": \"bar\",\n"
244      "  \"baz\": true,\n"
245      "  \"simple_enum\": \"baz\","
246      "  \"ints\": [1, false]"
247      "}\n";
248
249  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
250  SimpleMessage message;
251  base::JSONValueConverter<SimpleMessage> converter;
252  EXPECT_FALSE(converter.Convert(*value.get(), &message));
253  // No check the values as mentioned above.
254}
255
256}  // namespace base
257