// 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
