b0ca0789be
Add documentation for breakpoint. Fix Instance.pattern documentation. Fix Instance.bytes documentation. Add class field for null instances. Fix documentation of Context and closureContext. Make getObject return Collected for deleted breakpoints. Closes #24247 Closes #24249 Closes #24309 Closes #24325 Closes #24326 Closes #24327 BUG= R=johnmccutchan@google.com Review URL: https://codereview.chromium.org//1341473002 .
424 lines
11 KiB
C++
424 lines
11 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "platform/assert.h"
|
|
#include "platform/json.h"
|
|
#include "vm/json_stream.h"
|
|
#include "vm/unit_test.h"
|
|
#include "vm/dart_api_impl.h"
|
|
|
|
namespace dart {
|
|
|
|
|
|
TEST_CASE(JSON_ScanJSON) {
|
|
const char* msg = "{ \"id\": 5, \"command\" : \"Debugger.pause\" }";
|
|
|
|
JSONScanner scanner(msg);
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenIllegal);
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenLBrace);
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
|
|
EXPECT(scanner.IsStringLiteral("id"));
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenColon);
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenInteger);
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenComma);
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
|
|
EXPECT(scanner.IsStringLiteral("command"));
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenColon);
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
|
|
EXPECT(scanner.IsStringLiteral("Debugger.pause"));
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenRBrace);
|
|
scanner.Scan();
|
|
EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenEOM);
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_SyntaxError) {
|
|
const char* jobj = "{ \"id\": 5, "
|
|
" \"command\" : \"Debugger.stop\"" // Missing comma.
|
|
" \"params\" : { "
|
|
" \"url\" : \"blah.dart\", " // Missing comma.
|
|
" \"line\": 111, "
|
|
" },"
|
|
" \"foo\": \"outer foo\", "
|
|
"}";
|
|
JSONReader reader(jobj);
|
|
bool found;
|
|
|
|
found = reader.Seek("id");
|
|
EXPECT(found);
|
|
EXPECT_EQ(reader.Type(), JSONReader::kInteger);
|
|
found = reader.Seek("params");
|
|
EXPECT(!found);
|
|
EXPECT(reader.Error());
|
|
EXPECT_EQ(reader.Type(), JSONReader::kNone);
|
|
EXPECT_EQ(0, reader.ValueLen());
|
|
EXPECT(reader.ValueChars() == NULL);
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONReader) {
|
|
const char* jobj = "{ \"id\": 5, "
|
|
" \"command\" : \"Debugger.setBreakpoint\","
|
|
" \"params\" : { "
|
|
" \"url\" : \"blah.dart\", "
|
|
" \"foo\" : [null, 1, { }, \"bar\", true, false],"
|
|
" \"line\": 111, "
|
|
" },"
|
|
" \"foo\": \"outer foo\", "
|
|
" \"quote\": \"\\\"\", "
|
|
" \"white\": \"\\t \\n\", "
|
|
"}";
|
|
|
|
JSONReader reader(jobj);
|
|
bool found;
|
|
char s[128];
|
|
|
|
found = reader.Seek("id");
|
|
EXPECT(found);
|
|
EXPECT_EQ(reader.Type(), JSONReader::kInteger);
|
|
found = reader.Seek("foo");
|
|
EXPECT(found);
|
|
EXPECT_EQ(reader.Type(), JSONReader::kString);
|
|
EXPECT(reader.IsStringLiteral("outer foo"));
|
|
|
|
found = reader.Seek("quote");
|
|
EXPECT(found);
|
|
EXPECT_EQ(reader.Type(), JSONReader::kString);
|
|
reader.GetRawValueChars(s, sizeof s);
|
|
EXPECT_STREQ("\\\"", s);
|
|
reader.GetDecodedValueChars(s, sizeof s);
|
|
EXPECT_STREQ("\"", s);
|
|
|
|
found = reader.Seek("white");
|
|
EXPECT(found);
|
|
EXPECT_EQ(reader.Type(), JSONReader::kString);
|
|
reader.GetRawValueChars(s, sizeof s);
|
|
EXPECT_STREQ("\\t \\n", s);
|
|
reader.GetDecodedValueChars(s, sizeof s);
|
|
EXPECT_STREQ("\t \n", s);
|
|
|
|
found = reader.Seek("line");
|
|
EXPECT(!found);
|
|
found = reader.Seek("params");
|
|
EXPECT(found);
|
|
EXPECT_EQ(reader.Type(), JSONReader::kObject);
|
|
reader.Set(reader.ValueChars());
|
|
found = reader.Seek("foo");
|
|
EXPECT(found);
|
|
EXPECT_EQ(reader.Type(), JSONReader::kArray);
|
|
found = reader.Seek("non-existing");
|
|
EXPECT(!found);
|
|
found = reader.Seek("line");
|
|
EXPECT(found);
|
|
EXPECT_EQ(reader.Type(), JSONReader::kInteger);
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_TextBuffer) {
|
|
TextBuffer w(5); // Small enough to make buffer grow at least once.
|
|
w.Printf("{ \"%s\" : %d", "length", 175);
|
|
EXPECT_STREQ("{ \"length\" : 175", w.buf());
|
|
w.Printf(", \"%s\" : \"%s\" }", "command", "stopIt");
|
|
EXPECT_STREQ("{ \"length\" : 175, \"command\" : \"stopIt\" }", w.buf());
|
|
|
|
JSONReader r(w.buf());
|
|
bool found = r.Seek("command");
|
|
EXPECT(found);
|
|
EXPECT_EQ(r.Type(), JSONReader::kString);
|
|
EXPECT(r.IsStringLiteral("stopIt"));
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_Primitives) {
|
|
{
|
|
JSONStream js;
|
|
{
|
|
JSONObject jsobj(&js);
|
|
}
|
|
EXPECT_STREQ("{}", js.ToCString());
|
|
}
|
|
{
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
}
|
|
EXPECT_STREQ("[]", js.ToCString());
|
|
}
|
|
{
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValue(true);
|
|
}
|
|
EXPECT_STREQ("[true]", js.ToCString());
|
|
}
|
|
{
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValue(false);
|
|
}
|
|
EXPECT_STREQ("[false]", js.ToCString());
|
|
}
|
|
{
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValue(static_cast<intptr_t>(4));
|
|
}
|
|
EXPECT_STREQ("[4]", js.ToCString());
|
|
}
|
|
{
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValue(1.0);
|
|
}
|
|
EXPECT_STREQ("[1.000000]", js.ToCString());
|
|
}
|
|
{
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValue("hello");
|
|
}
|
|
EXPECT_STREQ("[\"hello\"]", js.ToCString());
|
|
}
|
|
{
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValueF("h%s", "elo");
|
|
}
|
|
EXPECT_STREQ("[\"helo\"]", js.ToCString());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_Array) {
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValue(true);
|
|
jsarr.AddValue(false);
|
|
}
|
|
EXPECT_STREQ("[true,false]", js.ToCString());
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_Object) {
|
|
JSONStream js;
|
|
{
|
|
JSONObject jsobj(&js);
|
|
jsobj.AddProperty("key1", "a");
|
|
jsobj.AddProperty("key2", "b");
|
|
}
|
|
EXPECT_STREQ("{\"key1\":\"a\",\"key2\":\"b\"}", js.ToCString());
|
|
}
|
|
|
|
TEST_CASE(JSON_JSONStream_NestedObject) {
|
|
JSONStream js;
|
|
{
|
|
JSONObject jsobj(&js);
|
|
JSONObject jsobj1(&jsobj, "key");
|
|
jsobj1.AddProperty("key1", "d");
|
|
}
|
|
EXPECT_STREQ("{\"key\":{\"key1\":\"d\"}}", js.ToCString());
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_ObjectArray) {
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
{
|
|
JSONObject jsobj(&jsarr);
|
|
jsobj.AddProperty("key", "e");
|
|
}
|
|
{
|
|
JSONObject jsobj(&jsarr);
|
|
jsobj.AddProperty("yek", "f");
|
|
}
|
|
}
|
|
EXPECT_STREQ("[{\"key\":\"e\"},{\"yek\":\"f\"}]", js.ToCString());
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_ArrayArray) {
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
{
|
|
JSONArray jsarr1(&jsarr);
|
|
jsarr1.AddValue(static_cast<intptr_t>(4));
|
|
}
|
|
{
|
|
JSONArray jsarr1(&jsarr);
|
|
jsarr1.AddValue(false);
|
|
}
|
|
}
|
|
EXPECT_STREQ("[[4],[false]]", js.ToCString());
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_Printf) {
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValueF("%d %s", 2, "hello");
|
|
}
|
|
EXPECT_STREQ("[\"2 hello\"]", js.ToCString());
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_ObjectPrintf) {
|
|
JSONStream js;
|
|
{
|
|
JSONObject jsobj(&js);
|
|
jsobj.AddPropertyF("key", "%d %s", 2, "hello");
|
|
}
|
|
EXPECT_STREQ("{\"key\":\"2 hello\"}", js.ToCString());
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_DartObject) {
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValue(Object::Handle(Object::null()));
|
|
JSONObject jsobj(&jsarr);
|
|
jsobj.AddProperty("object_key", Object::Handle(Object::null()));
|
|
}
|
|
char buffer[1024];
|
|
ElideJSONSubstring("classes", js.ToCString(), buffer);
|
|
EXPECT_STREQ("[{\"type\":\"@Instance\","
|
|
"\"_vmType\":\"null\","
|
|
"\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"Null\"},"
|
|
"\"kind\":\"Null\","
|
|
"\"fixedId\":true,"
|
|
"\"id\":\"objects\\/null\","
|
|
"\"valueAsString\":\"null\"},"
|
|
"{\"object_key\":"
|
|
"{\"type\":\"@Instance\","
|
|
"\"_vmType\":\"null\","
|
|
"\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"Null\"},"
|
|
"\"kind\":\"Null\","
|
|
"\"fixedId\":true,"
|
|
"\"id\":\"objects\\/null\","
|
|
"\"valueAsString\":\"null\"}}]",
|
|
buffer);
|
|
}
|
|
|
|
TEST_CASE(JSON_JSONStream_EscapedString) {
|
|
JSONStream js;
|
|
{
|
|
JSONArray jsarr(&js);
|
|
jsarr.AddValue("Hel\"\"lo\r\n\t");
|
|
}
|
|
EXPECT_STREQ("[\"Hel\\\"\\\"lo\\r\\n\\t\"]", js.ToCString());
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_DartString) {
|
|
const char* kScriptChars =
|
|
"var ascii = 'Hello, World!';\n"
|
|
"var unicode = '\\u00CE\\u00F1\\u0163\\u00E9r\\u00F1\\u00E5\\u0163"
|
|
"\\u00EE\\u00F6\\u00F1\\u00E5\\u013C\\u00EE\\u017E\\u00E5\\u0163"
|
|
"\\u00EE\\u1EDD\\u00F1';\n"
|
|
"var surrogates = '\\u{1D11E}\\u{1D11E}\\u{1D11E}\\u{1D11E}"
|
|
"\\u{1D11E}';\n"
|
|
"var nullInMiddle = 'This has\\u0000 four words.';";
|
|
|
|
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
|
|
EXPECT_VALID(lib);
|
|
|
|
Dart_Handle result;
|
|
String& obj = String::Handle();
|
|
|
|
{
|
|
result = Dart_GetField(lib, NewString("ascii"));
|
|
EXPECT_VALID(result);
|
|
obj ^= Api::UnwrapHandle(result);
|
|
|
|
JSONStream js;
|
|
{
|
|
JSONObject jsobj(&js);
|
|
jsobj.AddPropertyStr("ascci", obj);;
|
|
}
|
|
EXPECT_STREQ("{\"ascci\":\"Hello, World!\"}", js.ToCString());
|
|
}
|
|
|
|
{
|
|
result = Dart_GetField(lib, NewString("unicode"));
|
|
EXPECT_VALID(result);
|
|
obj ^= Api::UnwrapHandle(result);
|
|
|
|
JSONStream js;
|
|
{
|
|
JSONObject jsobj(&js);
|
|
jsobj.AddPropertyStr("unicode", obj);
|
|
}
|
|
EXPECT_STREQ("{\"unicode\":\"\\u00CE\\u00F1\\u0163\\u00E9r\\u00F1\\u00E5"
|
|
"\\u0163\\u00EE\\u00F6\\u00F1\\u00E5\\u013C\\u00EE\\u017E"
|
|
"\\u00E5\\u0163\\u00EE\\u1EDD\\u00F1\"}", js.ToCString());
|
|
}
|
|
|
|
{
|
|
result = Dart_GetField(lib, NewString("surrogates"));
|
|
EXPECT_VALID(result);
|
|
obj ^= Api::UnwrapHandle(result);
|
|
|
|
JSONStream js;
|
|
{
|
|
JSONObject jsobj(&js);
|
|
jsobj.AddPropertyStr("surrogates", obj);
|
|
}
|
|
EXPECT_STREQ("{\"surrogates\":\"\\uD834\\uDD1E\\uD834\\uDD1E\\uD834\\uDD1E"
|
|
"\\uD834\\uDD1E\\uD834\\uDD1E\"}", js.ToCString());
|
|
}
|
|
|
|
{
|
|
result = Dart_GetField(lib, NewString("nullInMiddle"));
|
|
EXPECT_VALID(result);
|
|
obj ^= Api::UnwrapHandle(result);
|
|
|
|
JSONStream js;
|
|
{
|
|
JSONObject jsobj(&js);
|
|
jsobj.AddPropertyStr("nullInMiddle", obj);
|
|
}
|
|
EXPECT_STREQ("{\"nullInMiddle\":\"This has\\u0000 four words.\"}",
|
|
js.ToCString());
|
|
}
|
|
}
|
|
|
|
|
|
TEST_CASE(JSON_JSONStream_Params) {
|
|
const char* param_keys[] = {"dog", "cat"};
|
|
const char* param_values[] = {"apple", "banana"};
|
|
|
|
JSONStream js;
|
|
EXPECT(js.num_params() == 0);
|
|
js.SetParams(¶m_keys[0], ¶m_values[0], 2);
|
|
EXPECT(js.num_params() == 2);
|
|
EXPECT(!js.HasParam("lizard"));
|
|
EXPECT(js.HasParam("dog"));
|
|
EXPECT(js.HasParam("cat"));
|
|
EXPECT(js.ParamIs("cat", "banana"));
|
|
EXPECT(!js.ParamIs("dog", "banana"));
|
|
}
|
|
|
|
} // namespace dart
|