| // 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 <optional> |
| |
| #include "base/json/json_reader.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/values.h" |
| #include "testing/gtest/include/gtest/gtest.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)); |
| std::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)); |
| std::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)); |
| std::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)); |
| std::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)); |
| std::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()); |
| |
| // Negative zero integer. |
| input = "-0,|"; |
| parser.reset(NewTestParser(input)); |
| value = parser->ConsumeNumber(); |
| EXPECT_EQ(',', *parser->pos()); |
| |
| TestLastThree(parser.get()); |
| |
| ASSERT_TRUE(value); |
| ASSERT_TRUE(value->is_double()); |
| EXPECT_EQ(-0.0, value->GetDouble()); |
| |
| // 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()); |
| |
| // Negative zero double. |
| input = "-0.0,|"; |
| parser.reset(NewTestParser(input)); |
| value = parser->ConsumeNumber(); |
| EXPECT_EQ(',', *parser->pos()); |
| |
| TestLastThree(parser.get()); |
| |
| ASSERT_TRUE(value); |
| ASSERT_TRUE(value->is_double()); |
| EXPECT_EQ(-0.0, 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); |
| std::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); |
| std::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); |
| std::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); |
| std::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); |
| std::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); |
| std::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); |
| std::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); |
| std::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); |
| std::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); |
| std::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()); |
| } |
| |
| { |
| JSONParser parser(JSON_PARSE_RFC); |
| std::optional<Value> value = parser.Parse("\"abc\ndef\""); |
| EXPECT_FALSE(value); |
| EXPECT_EQ( |
| JSONParser::FormatErrorMessage(1, 4, JSONParser::kUnsupportedEncoding), |
| parser.GetErrorMessage()); |
| EXPECT_EQ(JSONParser::JSON_UNSUPPORTED_ENCODING, parser.error_code()); |
| } |
| } |
| |
| } // namespace internal |
| } // namespace base |