1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/assert.h"
6#include "platform/text_buffer.h"
7#include "vm/dart_api_impl.h"
8#include "vm/json_stream.h"
9#include "vm/unit_test.h"
10
11namespace dart {
12
13#ifndef PRODUCT
14
15TEST_CASE(JSON_TextBuffer) {
16 TextBuffer w(5); // Small enough to make buffer grow at least once.
17 w.Printf("{ \"%s\" : %d", "length", 175);
18 EXPECT_STREQ("{ \"length\" : 175", w.buffer());
19 w.Printf(", \"%s\" : \"%s\" }", "command", "stopIt");
20 EXPECT_STREQ("{ \"length\" : 175, \"command\" : \"stopIt\" }", w.buffer());
21}
22
23TEST_CASE(JSON_JSONStream_Primitives) {
24 {
25 JSONStream js;
26 { JSONObject jsobj(&js); }
27 EXPECT_STREQ("{}", js.ToCString());
28 }
29 {
30 JSONStream js;
31 { JSONArray jsarr(&js); }
32 EXPECT_STREQ("[]", js.ToCString());
33 }
34 {
35 JSONStream js;
36 {
37 JSONArray jsarr(&js);
38 jsarr.AddValue(true);
39 }
40 EXPECT_STREQ("[true]", js.ToCString());
41 }
42 {
43 JSONStream js;
44 {
45 JSONArray jsarr(&js);
46 jsarr.AddValue(false);
47 }
48 EXPECT_STREQ("[false]", js.ToCString());
49 }
50 {
51 JSONStream js;
52 {
53 JSONArray jsarr(&js);
54 jsarr.AddValue(static_cast<intptr_t>(4));
55 }
56 EXPECT_STREQ("[4]", js.ToCString());
57 }
58 {
59 JSONStream js;
60 {
61 JSONArray jsarr(&js);
62 jsarr.AddValue(1.0);
63 }
64 EXPECT_STREQ("[1.0]", js.ToCString());
65 }
66 {
67 JSONStream js;
68 {
69 JSONArray jsarr(&js);
70 jsarr.AddValue("hello");
71 }
72 EXPECT_STREQ("[\"hello\"]", js.ToCString());
73 }
74 {
75 JSONStream js;
76 {
77 JSONArray jsarr(&js);
78 jsarr.AddValueF("h%s", "elo");
79 }
80 EXPECT_STREQ("[\"helo\"]", js.ToCString());
81 }
82}
83
84TEST_CASE(JSON_JSONStream_Array) {
85 JSONStream js;
86 {
87 JSONArray jsarr(&js);
88 jsarr.AddValue(true);
89 jsarr.AddValue(false);
90 }
91 EXPECT_STREQ("[true,false]", js.ToCString());
92}
93
94TEST_CASE(JSON_JSONStream_Object) {
95 JSONStream js;
96 {
97 JSONObject jsobj(&js);
98 jsobj.AddProperty("key1", "a");
99 jsobj.AddProperty("key2", "b");
100 }
101 EXPECT_STREQ("{\"key1\":\"a\",\"key2\":\"b\"}", js.ToCString());
102}
103
104TEST_CASE(JSON_JSONStream_NestedObject) {
105 JSONStream js;
106 {
107 JSONObject jsobj(&js);
108 JSONObject jsobj1(&jsobj, "key");
109 jsobj1.AddProperty("key1", "d");
110 }
111 EXPECT_STREQ("{\"key\":{\"key1\":\"d\"}}", js.ToCString());
112}
113
114TEST_CASE(JSON_JSONStream_ObjectArray) {
115 JSONStream js;
116 {
117 JSONArray jsarr(&js);
118 {
119 JSONObject jsobj(&jsarr);
120 jsobj.AddProperty("key", "e");
121 }
122 {
123 JSONObject jsobj(&jsarr);
124 jsobj.AddProperty("yek", "f");
125 }
126 }
127 EXPECT_STREQ("[{\"key\":\"e\"},{\"yek\":\"f\"}]", js.ToCString());
128}
129
130TEST_CASE(JSON_JSONStream_ArrayArray) {
131 JSONStream js;
132 {
133 JSONArray jsarr(&js);
134 {
135 JSONArray jsarr1(&jsarr);
136 jsarr1.AddValue(static_cast<intptr_t>(4));
137 }
138 {
139 JSONArray jsarr1(&jsarr);
140 jsarr1.AddValue(false);
141 }
142 }
143 EXPECT_STREQ("[[4],[false]]", js.ToCString());
144}
145
146TEST_CASE(JSON_JSONStream_Printf) {
147 JSONStream js;
148 {
149 JSONArray jsarr(&js);
150 jsarr.AddValueF("%d %s", 2, "hello");
151 }
152 EXPECT_STREQ("[\"2 hello\"]", js.ToCString());
153}
154
155TEST_CASE(JSON_JSONStream_ObjectPrintf) {
156 JSONStream js;
157 {
158 JSONObject jsobj(&js);
159 jsobj.AddPropertyF("key", "%d %s", 2, "hello");
160 }
161 EXPECT_STREQ("{\"key\":\"2 hello\"}", js.ToCString());
162}
163
164ISOLATE_UNIT_TEST_CASE(JSON_JSONStream_DartObject) {
165 JSONStream js;
166 {
167 JSONArray jsarr(&js);
168 jsarr.AddValue(Object::Handle(Object::null()));
169 JSONObject jsobj(&jsarr);
170 jsobj.AddProperty("object_key", Object::Handle(Object::null()));
171 }
172 char buffer[1024];
173 ElideJSONSubstring("classes", js.ToCString(), buffer);
174 EXPECT_STREQ(
175 "[{\"type\":\"@Instance\","
176 "\"_vmType\":\"null\","
177 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
178 "\"name\":\"Null\"},"
179 "\"kind\":\"Null\","
180 "\"fixedId\":true,"
181 "\"id\":\"objects\\/null\","
182 "\"valueAsString\":\"null\"},"
183 "{\"object_key\":"
184 "{\"type\":\"@Instance\","
185 "\"_vmType\":\"null\","
186 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
187 "\"name\":\"Null\"},"
188 "\"kind\":\"Null\","
189 "\"fixedId\":true,"
190 "\"id\":\"objects\\/null\","
191 "\"valueAsString\":\"null\"}}]",
192 buffer);
193}
194
195TEST_CASE(JSON_JSONStream_EscapedString) {
196 JSONStream js;
197 {
198 JSONArray jsarr(&js);
199 jsarr.AddValue("Hel\"\"lo\r\n\t");
200 }
201 EXPECT_STREQ("[\"Hel\\\"\\\"lo\\r\\n\\t\"]", js.ToCString());
202}
203
204TEST_CASE(JSON_JSONStream_DartString) {
205 const char* kScriptChars =
206 "var ascii = 'Hello, World!';\n"
207 "var unicode = '\\u00CE\\u00F1\\u0163\\u00E9r\\u00F1\\u00E5\\u0163"
208 "\\u00EE\\u00F6\\u00F1\\u00E5\\u013C\\u00EE\\u017E\\u00E5\\u0163"
209 "\\u00EE\\u1EDD\\u00F1';\n"
210 "var surrogates = '\\u{1D11E}\\u{1D11E}\\u{1D11E}"
211 "\\u{1D11E}\\u{1D11E}';\n"
212 "var wrongEncoding = '\\u{1D11E}' + surrogates[0] + '\\u{1D11E}';"
213 "var nullInMiddle = 'This has\\u0000 four words.';";
214
215 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
216 EXPECT_VALID(lib);
217
218 Dart_Handle result;
219 TransitionNativeToVM transition1(thread);
220 String& obj = String::Handle();
221
222 auto do_test = [&](const char* field_name, const char* expected) {
223 {
224 TransitionVMToNative to_native(thread);
225 result = Dart_GetField(lib, NewString(field_name));
226 EXPECT_VALID(result);
227 }
228
229 obj ^= Api::UnwrapHandle(result);
230
231 {
232 JSONStream js;
233 {
234 JSONObject jsobj(&js);
235 EXPECT(!jsobj.AddPropertyStr(field_name, obj));
236 }
237 EXPECT_STREQ(expected, js.ToCString());
238 }
239 };
240
241 {
242 TransitionVMToNative to_native(thread);
243 result = Dart_GetField(lib, NewString("ascii"));
244 EXPECT_VALID(result);
245 }
246
247 obj ^= Api::UnwrapHandle(result);
248
249 {
250 JSONStream js;
251 {
252 JSONObject jsobj(&js);
253 EXPECT(jsobj.AddPropertyStr("subrange", obj, 1, 4));
254 }
255 EXPECT_STREQ("{\"subrange\":\"ello\"}", js.ToCString());
256 }
257
258 do_test("ascii", "{\"ascii\":\"Hello, World!\"}");
259 do_test("unicode", "{\"unicode\":\"Îñţérñåţîöñåļîžåţîờñ\"}");
260 do_test("surrogates", "{\"surrogates\":\"𝄞𝄞𝄞𝄞𝄞\"}");
261 do_test("wrongEncoding", "{\"wrongEncoding\":\"𝄞\\uD834𝄞\"}");
262 do_test("nullInMiddle", "{\"nullInMiddle\":\"This has\\u0000 four words.\"}");
263}
264
265TEST_CASE(JSON_JSONStream_Params) {
266 const char* param_keys[] = {"dog", "cat"};
267 const char* param_values[] = {"apple", "banana"};
268
269 JSONStream js;
270 EXPECT(js.num_params() == 0);
271 js.SetParams(&param_keys[0], &param_values[0], 2);
272 EXPECT(js.num_params() == 2);
273 EXPECT(!js.HasParam("lizard"));
274 EXPECT(js.HasParam("dog"));
275 EXPECT(js.HasParam("cat"));
276 EXPECT(js.ParamIs("cat", "banana"));
277 EXPECT(!js.ParamIs("dog", "banana"));
278}
279
280#endif // !PRODUCT
281
282} // namespace dart
283