blob: 8be6ecb2376aa3b784c73441974e6ea735c843a5 [file] [log] [blame]
// Copyright (c) 2016 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 "third_party/blink/renderer/core/inspector/protocol/Protocol.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/inspector_protocol/crdtp/json.h"
namespace blink {
using protocol::DictionaryValue;
using protocol::ListValue;
using protocol::Value;
static std::unique_ptr<protocol::Value> ParseJSON(const String& string) {
std::vector<uint8_t> cbor;
if (string.Is8Bit()) {
crdtp::json::ConvertJSONToCBOR(
crdtp::span<uint8_t>(string.Characters8(), string.length()), &cbor);
} else {
crdtp::json::ConvertJSONToCBOR(
crdtp::span<uint16_t>(
reinterpret_cast<const uint16_t*>(string.Characters16()),
string.length()),
&cbor);
}
return protocol::Value::parseBinary(cbor.data(), cbor.size());
}
TEST(ProtocolParserTest, Reading) {
Value* tmp_value;
std::unique_ptr<Value> root;
std::unique_ptr<Value> root2;
String str_val;
int int_val = 0;
// some whitespace checking
root = ParseJSON(" null ");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeNull, root->type());
// Invalid JSON string
root = ParseJSON("nu");
EXPECT_FALSE(root.get());
// Simple bool
root = ParseJSON("true ");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeBoolean, root->type());
// Embedded comment
root = ParseJSON("40 /*/");
EXPECT_FALSE(root.get());
root = ParseJSON("/* comment */null");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeNull, root->type());
root = ParseJSON("40 /* comment */");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeInteger, root->type());
EXPECT_TRUE(root->asInteger(&int_val));
EXPECT_EQ(40, int_val);
root = ParseJSON("/**/ 40 /* multi-line\n comment */ // more comment");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeInteger, root->type());
EXPECT_TRUE(root->asInteger(&int_val));
EXPECT_EQ(40, int_val);
root = ParseJSON("true // comment");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeBoolean, root->type());
root = ParseJSON("/* comment */\"sample string\"");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->asString(&str_val));
EXPECT_EQ("sample string", str_val);
root = ParseJSON("[1, /* comment, 2 ] */ \n 3]");
ASSERT_TRUE(root.get());
ListValue* list = ListValue::cast(root.get());
ASSERT_TRUE(list);
EXPECT_EQ(2u, list->size());
tmp_value = list->at(0);
ASSERT_TRUE(tmp_value);
EXPECT_TRUE(tmp_value->asInteger(&int_val));
EXPECT_EQ(1, int_val);
tmp_value = list->at(1);
ASSERT_TRUE(tmp_value);
EXPECT_TRUE(tmp_value->asInteger(&int_val));
EXPECT_EQ(3, int_val);
root = ParseJSON("[1, /*a*/2, 3]");
ASSERT_TRUE(root.get());
list = ListValue::cast(root.get());
ASSERT_TRUE(list);
EXPECT_EQ(3u, list->size());
root = ParseJSON("/* comment **/42");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeInteger, root->type());
EXPECT_TRUE(root->asInteger(&int_val));
EXPECT_EQ(42, int_val);
root = ParseJSON(
"/* comment **/\n"
"// */ 43\n"
"44");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeInteger, root->type());
EXPECT_TRUE(root->asInteger(&int_val));
EXPECT_EQ(44, int_val);
// Test number formats
root = ParseJSON("43");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeInteger, root->type());
EXPECT_TRUE(root->asInteger(&int_val));
EXPECT_EQ(43, int_val);
// According to RFC4627, oct, hex, and leading zeros are invalid JSON.
root = ParseJSON("043");
EXPECT_FALSE(root.get());
root = ParseJSON("0x43");
EXPECT_FALSE(root.get());
root = ParseJSON("00");
EXPECT_FALSE(root.get());
// Test 0 (which needs to be special cased because of the leading zero
// clause).
root = ParseJSON("0");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeInteger, root->type());
int_val = 1;
EXPECT_TRUE(root->asInteger(&int_val));
EXPECT_EQ(0, int_val);
// Numbers that overflow ints should succeed, being internally promoted to
// storage as doubles
root = ParseJSON("2147483648");
ASSERT_TRUE(root.get());
double double_val;
EXPECT_EQ(Value::TypeDouble, root->type());
double_val = 0.0;
EXPECT_TRUE(root->asDouble(&double_val));
EXPECT_DOUBLE_EQ(2147483648.0, double_val);
root = ParseJSON("-2147483649");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeDouble, root->type());
double_val = 0.0;
EXPECT_TRUE(root->asDouble(&double_val));
EXPECT_DOUBLE_EQ(-2147483649.0, double_val);
// Parse a double
root = ParseJSON("43.1");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeDouble, root->type());
double_val = 0.0;
EXPECT_TRUE(root->asDouble(&double_val));
EXPECT_DOUBLE_EQ(43.1, double_val);
root = ParseJSON("4.3e-1");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeDouble, root->type());
double_val = 0.0;
EXPECT_TRUE(root->asDouble(&double_val));
EXPECT_DOUBLE_EQ(.43, double_val);
root = ParseJSON("2.1e0");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeDouble, root->type());
double_val = 0.0;
EXPECT_TRUE(root->asDouble(&double_val));
EXPECT_DOUBLE_EQ(2.1, double_val);
root = ParseJSON("2.1e+0001");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeInteger, root->type());
double_val = 0.0;
EXPECT_TRUE(root->asDouble(&double_val));
EXPECT_DOUBLE_EQ(21.0, double_val);
root = ParseJSON("0.01");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeDouble, root->type());
double_val = 0.0;
EXPECT_TRUE(root->asDouble(&double_val));
EXPECT_DOUBLE_EQ(0.01, double_val);
root = ParseJSON("1.00");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeInteger, root->type());
double_val = 0.0;
EXPECT_TRUE(root->asDouble(&double_val));
EXPECT_DOUBLE_EQ(1.0, double_val);
// Fractional parts must have a digit before and after the decimal point.
root = ParseJSON("1.");
EXPECT_FALSE(root.get());
root = ParseJSON(".1");
EXPECT_FALSE(root.get());
root = ParseJSON("1.e10");
EXPECT_FALSE(root.get());
// Exponent must have a digit following the 'e'.
root = ParseJSON("1e");
EXPECT_FALSE(root.get());
root = ParseJSON("1E");
EXPECT_FALSE(root.get());
root = ParseJSON("1e1.");
EXPECT_FALSE(root.get());
root = ParseJSON("1e1.0");
EXPECT_FALSE(root.get());
// INF/-INF/NaN are not valid
root = ParseJSON("NaN");
EXPECT_FALSE(root.get());
root = ParseJSON("nan");
EXPECT_FALSE(root.get());
root = ParseJSON("inf");
EXPECT_FALSE(root.get());
// Invalid number formats
root = ParseJSON("4.3.1");
EXPECT_FALSE(root.get());
root = ParseJSON("4e3.1");
EXPECT_FALSE(root.get());
// Test string parser
root = ParseJSON("\"hello world\"");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeString, root->type());
EXPECT_TRUE(root->asString(&str_val));
EXPECT_EQ("hello world", str_val);
// Empty string
root = ParseJSON("\"\"");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeString, root->type());
EXPECT_TRUE(root->asString(&str_val));
EXPECT_EQ("", str_val);
// Test basic string escapes
root = ParseJSON("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\"");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeString, root->type());
EXPECT_TRUE(root->asString(&str_val));
EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val);
// Test hex and unicode escapes including the null character.
root = ParseJSON("\"\\x41\\x00\\u1234\"");
EXPECT_FALSE(root.get());
// Test invalid strings
root = ParseJSON("\"no closing quote");
EXPECT_FALSE(root.get());
root = ParseJSON("\"\\z invalid escape char\"");
EXPECT_FALSE(root.get());
root = ParseJSON("\"not enough escape chars\\u123\"");
EXPECT_FALSE(root.get());
root = ParseJSON("\"extra backslash at end of input\\\"");
EXPECT_FALSE(root.get());
// Basic array
root = ParseJSON("[true, false, null]");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeArray, root->type());
list = ListValue::cast(root.get());
ASSERT_TRUE(list);
EXPECT_EQ(3U, list->size());
// Empty array
root = ParseJSON("[]");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeArray, root->type());
list = ListValue::cast(root.get());
ASSERT_TRUE(list);
EXPECT_EQ(0U, list->size());
// Nested arrays
root = ParseJSON("[[true], [], [false, [], [null]], null]");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeArray, root->type());
list = ListValue::cast(root.get());
ASSERT_TRUE(list);
EXPECT_EQ(4U, list->size());
// Invalid, missing close brace.
root = ParseJSON("[[true], [], [false, [], [null]], null");
EXPECT_FALSE(root.get());
// Invalid, too many commas
root = ParseJSON("[true,, null]");
EXPECT_FALSE(root.get());
// Invalid, no commas
root = ParseJSON("[true null]");
EXPECT_FALSE(root.get());
// Invalid, trailing comma
root = ParseJSON("[true,]");
EXPECT_FALSE(root.get());
root = ParseJSON("[true]");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeArray, root->type());
list = ListValue::cast(root.get());
ASSERT_TRUE(list);
EXPECT_EQ(1U, list->size());
tmp_value = list->at(0);
ASSERT_TRUE(tmp_value);
EXPECT_EQ(Value::TypeBoolean, tmp_value->type());
bool bool_value = false;
EXPECT_TRUE(tmp_value->asBoolean(&bool_value));
EXPECT_TRUE(bool_value);
// Don't allow empty elements.
root = ParseJSON("[,]");
EXPECT_FALSE(root.get());
root = ParseJSON("[true,,]");
EXPECT_FALSE(root.get());
root = ParseJSON("[,true,]");
EXPECT_FALSE(root.get());
root = ParseJSON("[true,,false]");
EXPECT_FALSE(root.get());
// Test objects
root = ParseJSON("{}");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeObject, root->type());
// The three test cases in the loop differ only by their newlines; therefore
// the same assertions are valid.
for (const char* test :
{"{\"number\":9.87654321, \"null\":null , \"S\" : \"str\" }",
"{\n"
" \"number\":9.87654321,\n"
" \"null\":null,\n"
" \"S\":\"str\"\n"
"}\n",
"{\r\n"
" \"number\":9.87654321,\r\n"
" \"null\":null,\r\n"
" \"S\":\"str\"\r\n"
"}\r\n"}) {
root = ParseJSON(String(test));
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeObject, root->type());
DictionaryValue* object_val = DictionaryValue::cast(root.get());
ASSERT_TRUE(object_val);
double_val = 0.0;
EXPECT_TRUE(object_val->getDouble("number", &double_val));
EXPECT_DOUBLE_EQ(9.87654321, double_val);
Value* null_val = object_val->get("null");
ASSERT_TRUE(null_val);
EXPECT_EQ(Value::TypeNull, null_val->type());
EXPECT_TRUE(object_val->getString("S", &str_val));
EXPECT_EQ("str", str_val);
}
// Test nesting
root = ParseJSON("{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeObject, root->type());
DictionaryValue* object_val = DictionaryValue::cast(root.get());
ASSERT_TRUE(object_val);
DictionaryValue* inner_object = object_val->getObject("inner");
ASSERT_TRUE(inner_object);
ListValue* inner_array = inner_object->getArray("array");
ASSERT_TRUE(inner_array);
EXPECT_EQ(1U, inner_array->size());
bool_value = true;
EXPECT_TRUE(object_val->getBoolean("false", &bool_value));
EXPECT_FALSE(bool_value);
inner_object = object_val->getObject("d");
EXPECT_TRUE(inner_object);
// Test keys with periods
root = ParseJSON("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeObject, root->type());
object_val = DictionaryValue::cast(root.get());
ASSERT_TRUE(object_val);
int integer_value = 0;
EXPECT_TRUE(object_val->getInteger("a.b", &integer_value));
EXPECT_EQ(3, integer_value);
EXPECT_TRUE(object_val->getInteger("c", &integer_value));
EXPECT_EQ(2, integer_value);
inner_object = object_val->getObject("d.e.f");
ASSERT_TRUE(inner_object);
EXPECT_EQ(1U, inner_object->size());
EXPECT_TRUE(inner_object->getInteger("g.h.i.j", &integer_value));
EXPECT_EQ(1, integer_value);
root = ParseJSON("{\"a\":{\"b\":2},\"a.b\":1}");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeObject, root->type());
object_val = DictionaryValue::cast(root.get());
ASSERT_TRUE(object_val);
inner_object = object_val->getObject("a");
ASSERT_TRUE(inner_object);
EXPECT_TRUE(inner_object->getInteger("b", &integer_value));
EXPECT_EQ(2, integer_value);
EXPECT_TRUE(object_val->getInteger("a.b", &integer_value));
EXPECT_EQ(1, integer_value);
// Invalid, no closing brace
root = ParseJSON("{\"a\": true");
EXPECT_FALSE(root.get());
// Invalid, keys must be quoted
root = ParseJSON("{foo:true}");
EXPECT_FALSE(root.get());
// Invalid, trailing comma
root = ParseJSON("{\"a\":true,}");
EXPECT_FALSE(root.get());
// Invalid, too many commas
root = ParseJSON("{\"a\":true,,\"b\":false}");
EXPECT_FALSE(root.get());
// Invalid, no separator
root = ParseJSON("{\"a\" \"b\"}");
EXPECT_FALSE(root.get());
// Invalid, lone comma.
root = ParseJSON("{,}");
EXPECT_FALSE(root.get());
root = ParseJSON("{\"a\":true,,}");
EXPECT_FALSE(root.get());
root = ParseJSON("{,\"a\":true}");
EXPECT_FALSE(root.get());
root = ParseJSON("{\"a\":true,,\"b\":false}");
EXPECT_FALSE(root.get());
// Test stack overflow
StringBuilder evil;
evil.ReserveCapacity(2000000);
for (int i = 0; i < 1000000; ++i)
evil.Append('[');
for (int i = 0; i < 1000000; ++i)
evil.Append(']');
root = ParseJSON(evil.ToString());
EXPECT_FALSE(root.get());
// A few thousand adjacent lists is fine.
StringBuilder not_evil;
not_evil.ReserveCapacity(15010);
not_evil.Append('[');
for (int i = 0; i < 5000; ++i)
not_evil.Append("[],");
not_evil.Append("[]]");
root = ParseJSON(not_evil.ToString());
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeArray, root->type());
list = ListValue::cast(root.get());
ASSERT_TRUE(list);
EXPECT_EQ(5001U, list->size());
// Test utf8 encoded input
root = ParseJSON("\"\\xe7\\xbd\\x91\\xe9\\xa1\\xb5\"");
ASSERT_FALSE(root.get());
// Test utf16 encoded strings.
root = ParseJSON("\"\\u20ac3,14\"");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeString, root->type());
EXPECT_TRUE(root->asString(&str_val));
UChar tmp2[] = {0x20ac, 0x33, 0x2c, 0x31, 0x34};
EXPECT_EQ(String(tmp2, 5), str_val);
root = ParseJSON("\"\\ud83d\\udca9\\ud83d\\udc6c\"");
ASSERT_TRUE(root.get());
EXPECT_EQ(Value::TypeString, root->type());
EXPECT_TRUE(root->asString(&str_val));
UChar tmp3[] = {0xd83d, 0xdca9, 0xd83d, 0xdc6c};
EXPECT_EQ(String(tmp3, 4), str_val);
// Test literal root objects.
root = ParseJSON("null");
EXPECT_EQ(Value::TypeNull, root->type());
root = ParseJSON("true");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->asBoolean(&bool_value));
EXPECT_TRUE(bool_value);
root = ParseJSON("10");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->asInteger(&integer_value));
EXPECT_EQ(10, integer_value);
root = ParseJSON("\"root\"");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->asString(&str_val));
EXPECT_EQ("root", str_val);
}
TEST(ProtocolParserTest, InvalidSanity) {
const char* const kInvalidJson[] = {
"/* test *", "{\"foo\"", "{\"foo\":", " [", "\"\\u123g\"", "{\n\"eh:\n}",
"////", "*/**/", "/**/", "/*/", "//**/"};
for (size_t i = 0; i < 11; ++i) {
std::unique_ptr<Value> result = ParseJSON(kInvalidJson[i]);
EXPECT_FALSE(result.get());
}
}
} // namespace blink