310 lines
8.7 KiB
C++
310 lines
8.7 KiB
C++
|
|
// Copyright 2012 The Chromium Authors
|
||
|
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
|
// found in the LICENSE file.
|
||
|
|
|
||
|
|
#include "base/json/json_parser.h"
|
||
|
|
|
||
|
|
#include <stddef.h>
|
||
|
|
|
||
|
|
#include <memory>
|
||
|
|
|
||
|
|
#include "base/json/json_reader.h"
|
||
|
|
#include "base/memory/ptr_util.h"
|
||
|
|
#include "base/values.h"
|
||
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
||
|
|
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||
|
|
|
||
|
|
namespace base {
|
||
|
|
namespace internal {
|
||
|
|
|
||
|
|
class JSONParserTest : public testing::Test {
|
||
|
|
public:
|
||
|
|
JSONParser* NewTestParser(const std::string& input,
|
||
|
|
int options = JSON_PARSE_RFC) {
|
||
|
|
JSONParser* parser = new JSONParser(options);
|
||
|
|
parser->input_ = input;
|
||
|
|
parser->index_ = 0;
|
||
|
|
return parser;
|
||
|
|
}
|
||
|
|
|
||
|
|
void TestLastThree(JSONParser* parser) {
|
||
|
|
EXPECT_EQ(',', *parser->PeekChar());
|
||
|
|
parser->ConsumeChar();
|
||
|
|
EXPECT_EQ('|', *parser->PeekChar());
|
||
|
|
parser->ConsumeChar();
|
||
|
|
EXPECT_EQ('\0', *parser->pos());
|
||
|
|
EXPECT_EQ(static_cast<size_t>(parser->index_), parser->input_.length());
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
TEST_F(JSONParserTest, NextChar) {
|
||
|
|
std::string input("Hello world");
|
||
|
|
std::unique_ptr<JSONParser> parser(NewTestParser(input));
|
||
|
|
|
||
|
|
EXPECT_EQ('H', *parser->pos());
|
||
|
|
for (size_t i = 1; i < input.length(); ++i) {
|
||
|
|
parser->ConsumeChar();
|
||
|
|
EXPECT_EQ(input[i], *parser->PeekChar());
|
||
|
|
}
|
||
|
|
parser->ConsumeChar();
|
||
|
|
EXPECT_EQ('\0', *parser->pos());
|
||
|
|
EXPECT_EQ(static_cast<size_t>(parser->index_), parser->input_.length());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(JSONParserTest, ConsumeString) {
|
||
|
|
std::string input("\"test\",|");
|
||
|
|
std::unique_ptr<JSONParser> parser(NewTestParser(input));
|
||
|
|
absl::optional<Value> value(parser->ConsumeString());
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_string());
|
||
|
|
EXPECT_EQ("test", value->GetString());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(JSONParserTest, ConsumeList) {
|
||
|
|
std::string input("[true, false],|");
|
||
|
|
std::unique_ptr<JSONParser> parser(NewTestParser(input));
|
||
|
|
absl::optional<Value> value(parser->ConsumeList());
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
Value::List* list = value->GetIfList();
|
||
|
|
ASSERT_TRUE(list);
|
||
|
|
EXPECT_EQ(2u, list->size());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(JSONParserTest, ConsumeDictionary) {
|
||
|
|
std::string input("{\"abc\":\"def\"},|");
|
||
|
|
std::unique_ptr<JSONParser> parser(NewTestParser(input));
|
||
|
|
absl::optional<Value> value(parser->ConsumeDictionary());
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
const Value::Dict* value_dict = value->GetIfDict();
|
||
|
|
ASSERT_TRUE(value_dict);
|
||
|
|
const std::string* str = value_dict->FindString("abc");
|
||
|
|
ASSERT_TRUE(str);
|
||
|
|
EXPECT_EQ("def", *str);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(JSONParserTest, ConsumeLiterals) {
|
||
|
|
// Literal |true|.
|
||
|
|
std::string input("true,|");
|
||
|
|
std::unique_ptr<JSONParser> parser(NewTestParser(input));
|
||
|
|
absl::optional<Value> value(parser->ConsumeLiteral());
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_bool());
|
||
|
|
EXPECT_TRUE(value->GetBool());
|
||
|
|
|
||
|
|
// Literal |false|.
|
||
|
|
input = "false,|";
|
||
|
|
parser.reset(NewTestParser(input));
|
||
|
|
value = parser->ConsumeLiteral();
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_bool());
|
||
|
|
EXPECT_FALSE(value->GetBool());
|
||
|
|
|
||
|
|
// Literal |null|.
|
||
|
|
input = "null,|";
|
||
|
|
parser.reset(NewTestParser(input));
|
||
|
|
value = parser->ConsumeLiteral();
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
EXPECT_TRUE(value->is_none());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(JSONParserTest, ConsumeNumbers) {
|
||
|
|
// Integer.
|
||
|
|
std::string input("1234,|");
|
||
|
|
std::unique_ptr<JSONParser> parser(NewTestParser(input));
|
||
|
|
absl::optional<Value> value(parser->ConsumeNumber());
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_int());
|
||
|
|
EXPECT_EQ(1234, value->GetInt());
|
||
|
|
|
||
|
|
// Negative integer.
|
||
|
|
input = "-1234,|";
|
||
|
|
parser.reset(NewTestParser(input));
|
||
|
|
value = parser->ConsumeNumber();
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_int());
|
||
|
|
EXPECT_EQ(-1234, value->GetInt());
|
||
|
|
|
||
|
|
// Double.
|
||
|
|
input = "12.34,|";
|
||
|
|
parser.reset(NewTestParser(input));
|
||
|
|
value = parser->ConsumeNumber();
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_double());
|
||
|
|
EXPECT_EQ(12.34, value->GetDouble());
|
||
|
|
|
||
|
|
// Scientific.
|
||
|
|
input = "42e3,|";
|
||
|
|
parser.reset(NewTestParser(input));
|
||
|
|
value = parser->ConsumeNumber();
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_double());
|
||
|
|
EXPECT_EQ(42000, value->GetDouble());
|
||
|
|
|
||
|
|
// Negative scientific.
|
||
|
|
input = "314159e-5,|";
|
||
|
|
parser.reset(NewTestParser(input));
|
||
|
|
value = parser->ConsumeNumber();
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_double());
|
||
|
|
EXPECT_EQ(3.14159, value->GetDouble());
|
||
|
|
|
||
|
|
// Positive scientific.
|
||
|
|
input = "0.42e+3,|";
|
||
|
|
parser.reset(NewTestParser(input));
|
||
|
|
value = parser->ConsumeNumber();
|
||
|
|
EXPECT_EQ(',', *parser->pos());
|
||
|
|
|
||
|
|
TestLastThree(parser.get());
|
||
|
|
|
||
|
|
ASSERT_TRUE(value);
|
||
|
|
ASSERT_TRUE(value->is_double());
|
||
|
|
EXPECT_EQ(420, value->GetDouble());
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_F(JSONParserTest, ErrorMessages) {
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse("[42]");
|
||
|
|
EXPECT_TRUE(value);
|
||
|
|
EXPECT_TRUE(parser.GetErrorMessage().empty());
|
||
|
|
EXPECT_EQ(0, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test each of the error conditions
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse("{},{}");
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(JSONParser::FormatErrorMessage(
|
||
|
|
1, 3, JSONParser::kUnexpectedDataAfterRoot),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_UNEXPECTED_DATA_AFTER_ROOT, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
std::string nested_json;
|
||
|
|
for (int i = 0; i < 201; ++i) {
|
||
|
|
nested_json.insert(nested_json.begin(), '[');
|
||
|
|
nested_json.append(1, ']');
|
||
|
|
}
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse(nested_json);
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(
|
||
|
|
JSONParser::FormatErrorMessage(1, 200, JSONParser::kTooMuchNesting),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_TOO_MUCH_NESTING, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse("[1,]");
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONParser::kTrailingComma),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_TRAILING_COMMA, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse("{foo:\"bar\"}");
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(JSONParser::FormatErrorMessage(
|
||
|
|
1, 2, JSONParser::kUnquotedDictionaryKey),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_UNQUOTED_DICTIONARY_KEY, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse("{\"foo\":\"bar\",}");
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONParser::kTrailingComma),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_TRAILING_COMMA, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse("[nu]");
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONParser::kSyntaxError),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_SYNTAX_ERROR, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC | JSON_ALLOW_X_ESCAPES);
|
||
|
|
absl::optional<Value> value = parser.Parse("[\"xxx\\xq\"]");
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse("[\"xxx\\uq\"]");
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
JSONParser parser(JSON_PARSE_RFC);
|
||
|
|
absl::optional<Value> value = parser.Parse("[\"xxx\\q\"]");
|
||
|
|
EXPECT_FALSE(value);
|
||
|
|
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONParser::kInvalidEscape),
|
||
|
|
parser.GetErrorMessage());
|
||
|
|
EXPECT_EQ(JSONParser::JSON_INVALID_ESCAPE, parser.error_code());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace internal
|
||
|
|
} // namespace base
|