123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/json/json_value_converter.h"
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/json/json_reader.h"
- #include "base/strings/string_piece.h"
- #include "base/values.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- namespace base {
- namespace {
- // Very simple messages.
- struct SimpleMessage {
- enum SimpleEnum {
- FOO,
- BAR,
- };
- int foo;
- std::string bar;
- bool baz;
- bool bstruct;
- SimpleEnum simple_enum;
- std::vector<std::unique_ptr<int>> ints;
- std::vector<std::unique_ptr<std::string>> string_values;
- SimpleMessage() : foo(0), baz(false), bstruct(false), simple_enum(FOO) {}
- static bool ParseSimpleEnum(StringPiece value, SimpleEnum* field) {
- if (value == "foo") {
- *field = FOO;
- return true;
- }
- if (value == "bar") {
- *field = BAR;
- return true;
- }
- return false;
- }
- static bool HasFieldPresent(const base::Value* value, bool* result) {
- *result = value != nullptr;
- return true;
- }
- static bool GetValueString(const base::Value* value, std::string* result) {
- const Value::Dict* dict = value->GetIfDict();
- if (!dict)
- return false;
- const std::string* str = dict->FindString("val");
- if (!str)
- return false;
- if (result)
- *result = *str;
- return true;
- }
- static void RegisterJSONConverter(
- base::JSONValueConverter<SimpleMessage>* converter) {
- converter->RegisterIntField("foo", &SimpleMessage::foo);
- converter->RegisterStringField("bar", &SimpleMessage::bar);
- converter->RegisterBoolField("baz", &SimpleMessage::baz);
- converter->RegisterCustomField<SimpleEnum>(
- "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum);
- converter->RegisterRepeatedInt("ints", &SimpleMessage::ints);
- converter->RegisterCustomValueField<bool>(
- "bstruct", &SimpleMessage::bstruct, &HasFieldPresent);
- converter->RegisterRepeatedCustomValue<std::string>(
- "string_values", &SimpleMessage::string_values, &GetValueString);
- }
- };
- // For nested messages.
- struct NestedMessage {
- double foo;
- SimpleMessage child;
- std::vector<std::unique_ptr<SimpleMessage>> children;
- NestedMessage() : foo(0) {}
- static void RegisterJSONConverter(
- base::JSONValueConverter<NestedMessage>* converter) {
- converter->RegisterDoubleField("foo", &NestedMessage::foo);
- converter->RegisterNestedField("child", &NestedMessage::child);
- converter->RegisterRepeatedMessage("children", &NestedMessage::children);
- }
- };
- } // namespace
- TEST(JSONValueConverterTest, ParseSimpleMessage) {
- const char normal_data[] =
- "{\n"
- " \"foo\": 1,\n"
- " \"bar\": \"bar\",\n"
- " \"baz\": true,\n"
- " \"bstruct\": {},\n"
- " \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
- " \"simple_enum\": \"foo\","
- " \"ints\": [1, 2]"
- "}\n";
- absl::optional<Value> value = base::JSONReader::Read(normal_data);
- ASSERT_TRUE(value);
- SimpleMessage message;
- base::JSONValueConverter<SimpleMessage> converter;
- EXPECT_TRUE(converter.Convert(*value, &message));
- EXPECT_EQ(1, message.foo);
- EXPECT_EQ("bar", message.bar);
- EXPECT_TRUE(message.baz);
- EXPECT_EQ(SimpleMessage::FOO, message.simple_enum);
- EXPECT_EQ(2, static_cast<int>(message.ints.size()));
- ASSERT_EQ(2U, message.string_values.size());
- EXPECT_EQ("value_1", *message.string_values[0]);
- EXPECT_EQ("value_2", *message.string_values[1]);
- EXPECT_EQ(1, *(message.ints[0]));
- EXPECT_EQ(2, *(message.ints[1]));
- }
- TEST(JSONValueConverterTest, ParseNestedMessage) {
- const char normal_data[] =
- "{\n"
- " \"foo\": 1.0,\n"
- " \"child\": {\n"
- " \"foo\": 1,\n"
- " \"bar\": \"bar\",\n"
- " \"bstruct\": {},\n"
- " \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
- " \"baz\": true\n"
- " },\n"
- " \"children\": [{\n"
- " \"foo\": 2,\n"
- " \"bar\": \"foobar\",\n"
- " \"bstruct\": \"\",\n"
- " \"string_values\": [{\"val\": \"value_1\"}],"
- " \"baz\": true\n"
- " },\n"
- " {\n"
- " \"foo\": 3,\n"
- " \"bar\": \"barbaz\",\n"
- " \"baz\": false\n"
- " }]\n"
- "}\n";
- absl::optional<Value> value = base::JSONReader::Read(normal_data);
- ASSERT_TRUE(value);
- NestedMessage message;
- base::JSONValueConverter<NestedMessage> converter;
- EXPECT_TRUE(converter.Convert(*value, &message));
- EXPECT_EQ(1.0, message.foo);
- EXPECT_EQ(1, message.child.foo);
- EXPECT_EQ("bar", message.child.bar);
- EXPECT_TRUE(message.child.baz);
- EXPECT_TRUE(message.child.bstruct);
- ASSERT_EQ(2U, message.child.string_values.size());
- EXPECT_EQ("value_1", *message.child.string_values[0]);
- EXPECT_EQ("value_2", *message.child.string_values[1]);
- EXPECT_EQ(2, static_cast<int>(message.children.size()));
- const SimpleMessage* first_child = message.children[0].get();
- ASSERT_TRUE(first_child);
- EXPECT_EQ(2, first_child->foo);
- EXPECT_EQ("foobar", first_child->bar);
- EXPECT_TRUE(first_child->baz);
- EXPECT_TRUE(first_child->bstruct);
- ASSERT_EQ(1U, first_child->string_values.size());
- EXPECT_EQ("value_1", *first_child->string_values[0]);
- const SimpleMessage* second_child = message.children[1].get();
- ASSERT_TRUE(second_child);
- EXPECT_EQ(3, second_child->foo);
- EXPECT_EQ("barbaz", second_child->bar);
- EXPECT_FALSE(second_child->baz);
- EXPECT_FALSE(second_child->bstruct);
- EXPECT_EQ(0U, second_child->string_values.size());
- }
- TEST(JSONValueConverterTest, ParseFailures) {
- const char normal_data[] =
- "{\n"
- " \"foo\": 1,\n"
- " \"bar\": 2,\n" // "bar" is an integer here.
- " \"baz\": true,\n"
- " \"ints\": [1, 2]"
- "}\n";
- absl::optional<Value> value = base::JSONReader::Read(normal_data);
- ASSERT_TRUE(value);
- SimpleMessage message;
- base::JSONValueConverter<SimpleMessage> converter;
- EXPECT_FALSE(converter.Convert(*value, &message));
- // Do not check the values below. |message| may be modified during
- // Convert() even it fails.
- }
- TEST(JSONValueConverterTest, ParseWithMissingFields) {
- const char normal_data[] =
- "{\n"
- " \"foo\": 1,\n"
- " \"baz\": true,\n"
- " \"ints\": [1, 2]"
- "}\n";
- absl::optional<Value> value = base::JSONReader::Read(normal_data);
- ASSERT_TRUE(value);
- SimpleMessage message;
- base::JSONValueConverter<SimpleMessage> converter;
- // Convert() still succeeds even if the input doesn't have "bar" field.
- EXPECT_TRUE(converter.Convert(*value, &message));
- EXPECT_EQ(1, message.foo);
- EXPECT_TRUE(message.baz);
- EXPECT_EQ(2, static_cast<int>(message.ints.size()));
- EXPECT_EQ(1, *(message.ints[0]));
- EXPECT_EQ(2, *(message.ints[1]));
- }
- TEST(JSONValueConverterTest, EnumParserFails) {
- const char normal_data[] =
- "{\n"
- " \"foo\": 1,\n"
- " \"bar\": \"bar\",\n"
- " \"baz\": true,\n"
- " \"simple_enum\": \"baz\","
- " \"ints\": [1, 2]"
- "}\n";
- absl::optional<Value> value = base::JSONReader::Read(normal_data);
- ASSERT_TRUE(value);
- SimpleMessage message;
- base::JSONValueConverter<SimpleMessage> converter;
- EXPECT_FALSE(converter.Convert(*value, &message));
- // No check the values as mentioned above.
- }
- TEST(JSONValueConverterTest, RepeatedValueErrorInTheMiddle) {
- const char normal_data[] =
- "{\n"
- " \"foo\": 1,\n"
- " \"bar\": \"bar\",\n"
- " \"baz\": true,\n"
- " \"simple_enum\": \"baz\","
- " \"ints\": [1, false]"
- "}\n";
- absl::optional<Value> value = base::JSONReader::Read(normal_data);
- ASSERT_TRUE(value);
- SimpleMessage message;
- base::JSONValueConverter<SimpleMessage> converter;
- EXPECT_FALSE(converter.Convert(*value, &message));
- // No check the values as mentioned above.
- }
- } // namespace base
|