1// Copyright (c) 2015, 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 "vm/source_report.h"
6#include "vm/dart_api_impl.h"
7#include "vm/unit_test.h"
8
9namespace dart {
10
11#ifndef PRODUCT
12
13static ObjectPtr ExecuteScript(const char* script, bool allow_errors = false) {
14 Dart_Handle lib;
15 {
16 TransitionVMToNative transition(Thread::Current());
17 if (allow_errors) {
18 lib = TestCase::LoadTestScriptWithErrors(script, NULL);
19 } else {
20 lib = TestCase::LoadTestScript(script, NULL);
21 }
22 EXPECT_VALID(lib);
23 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
24 EXPECT_VALID(result);
25 }
26 return Api::UnwrapHandle(lib);
27}
28
29ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_NoCalls) {
30 char buffer[1024];
31 const char* kScript =
32 "main() {\n"
33 "}";
34
35 Library& lib = Library::Handle();
36 lib ^= ExecuteScript(kScript);
37 ASSERT(!lib.IsNull());
38 const Script& script =
39 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
40 SourceReport report(SourceReport::kCoverage);
41 JSONStream js;
42 report.PrintJSON(&js, script);
43 ElideJSONSubstring("libraries", js.ToCString(), buffer);
44 EXPECT_STREQ(
45 "{\"type\":\"SourceReport\",\"ranges\":"
46
47 // One compiled range, one hit at function declaration.
48 "[{\"scriptIndex\":0,\"startPos\":0,\"endPos\":9,\"compiled\":true,"
49 "\"coverage\":{\"hits\":[0],\"misses\":[]}}],"
50
51 // One script in the script table.
52 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
53 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
54 buffer);
55}
56
57ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_SimpleCall) {
58 char buffer[1024];
59 const char* kScript =
60 "helper0() {}\n"
61 "helper1() {}\n"
62 "main() {\n"
63 " if (true) {\n"
64 " helper0();\n"
65 " } else {\n"
66 " helper1();\n"
67 " }\n"
68 "}";
69
70 Library& lib = Library::Handle();
71 lib ^= ExecuteScript(kScript);
72 ASSERT(!lib.IsNull());
73 const Script& script =
74 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
75
76 SourceReport report(SourceReport::kCoverage);
77 JSONStream js;
78 report.PrintJSON(&js, script);
79 ElideJSONSubstring("classes", js.ToCString(), buffer);
80 ElideJSONSubstring("libraries", buffer, buffer);
81 EXPECT_STREQ(
82 "{\"type\":\"SourceReport\",\"ranges\":["
83
84 // One range compiled with one hit at function declaration (helper0).
85 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
86 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
87
88 // One range not compiled (helper1).
89 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
90
91 // One range with two hits and a miss (main).
92 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
93 "\"coverage\":{\"hits\":[26,53],\"misses\":[79]}}],"
94
95 // Only one script in the script table.
96 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
97 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
98 buffer);
99}
100
101ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_ForceCompile) {
102 char buffer[1024];
103 const char* kScript =
104 "helper0() {}\n"
105 "helper1() {}\n"
106 "main() {\n"
107 " if (true) {\n"
108 " helper0();\n"
109 " } else {\n"
110 " helper1();\n"
111 " }\n"
112 "}";
113
114 Library& lib = Library::Handle();
115 lib ^= ExecuteScript(kScript);
116 ASSERT(!lib.IsNull());
117 const Script& script =
118 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
119
120 SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
121 JSONStream js;
122 report.PrintJSON(&js, script);
123 ElideJSONSubstring("classes", js.ToCString(), buffer);
124 ElideJSONSubstring("libraries", buffer, buffer);
125
126 EXPECT_STREQ(
127 "{\"type\":\"SourceReport\",\"ranges\":["
128
129 // One range compiled with one hit at function declaration (helper0).
130 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
131 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
132
133 // This range is compiled even though it wasn't called (helper1).
134 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":true,"
135 "\"coverage\":{\"hits\":[],\"misses\":[13]}},"
136
137 // One range with two hits and a miss (main).
138 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
139 "\"coverage\":{\"hits\":[26,53],\"misses\":[79]}}],"
140
141 // Only one script in the script table.
142 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
143 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
144 buffer);
145}
146
147ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_NoForceCompile) {
148 char buffer[1024];
149 const char* kScript =
150 "helper0() {}\n"
151 "class Unused {\n"
152 " helper1() { helper0(); }\n"
153 "}\n"
154 "main() {\n"
155 " helper0();\n"
156 "}";
157
158 Library& lib = Library::Handle();
159 lib ^= ExecuteScript(kScript);
160 ASSERT(!lib.IsNull());
161 const Script& script =
162 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
163
164 SourceReport report(SourceReport::kCoverage);
165 JSONStream js;
166 report.PrintJSON(&js, script);
167 ElideJSONSubstring("classes", js.ToCString(), buffer);
168 ElideJSONSubstring("libraries", buffer, buffer);
169 EXPECT_STREQ(
170 "{\"type\":\"SourceReport\",\"ranges\":["
171
172 // UnusedClass is not compiled.
173 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":55,\"compiled\":false},"
174
175 // helper0 is compiled.
176 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
177 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
178
179 // One range with two hits (main).
180 "{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
181 "\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
182
183 // Only one script in the script table.
184 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
185 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
186 buffer);
187}
188
189ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_ForceCompile) {
190 char buffer[1024];
191 const char* kScript =
192 "helper0() {}\n"
193 "class Unused {\n"
194 " helper1() { helper0(); }\n"
195 "}\n"
196 "main() {\n"
197 " helper0();\n"
198 "}";
199
200 Library& lib = Library::Handle();
201 lib ^= ExecuteScript(kScript);
202 ASSERT(!lib.IsNull());
203 const Script& script =
204 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
205
206 SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
207 JSONStream js;
208 report.PrintJSON(&js, script);
209 ElideJSONSubstring("classes", js.ToCString(), buffer);
210 ElideJSONSubstring("libraries", buffer, buffer);
211 EXPECT_STREQ(
212 "{\"type\":\"SourceReport\",\"ranges\":["
213
214 // UnusedClass.helper1 is compiled.
215 "{\"scriptIndex\":0,\"startPos\":30,\"endPos\":53,\"compiled\":true,"
216 "\"coverage\":{\"hits\":[],\"misses\":[30,42]}},"
217
218 // helper0 is compiled.
219 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
220 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
221
222 // One range with two hits (main).
223 "{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
224 "\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
225
226 // Only one script in the script table.
227 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
228 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
229 buffer);
230}
231
232ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_ForceCompileError) {
233 char buffer[1024];
234 const char* kScript =
235 "helper0() {}\n"
236 "class Unused {\n"
237 " helper1() { helper0()+ }\n" // syntax error
238 "}\n"
239 "main() {\n"
240 " helper0();\n"
241 "}";
242
243 Library& lib = Library::Handle();
244 lib ^= ExecuteScript(kScript, true);
245 ASSERT(!lib.IsNull());
246 const Script& script =
247 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
248
249 SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
250 JSONStream js;
251 report.PrintJSON(&js, script);
252 ElideJSONSubstring("classes", js.ToCString(), buffer);
253 ElideJSONSubstring("libraries", buffer, buffer);
254 EXPECT_STREQ(
255 "{\"type\":\"SourceReport\",\"ranges\":["
256
257 // UnusedClass has a syntax error.
258 "{\"scriptIndex\":0,\"startPos\":30,\"endPos\":53,\"compiled\":false,"
259 "\"error\":{\"type\":\"@Error\",\"_vmType\":\"LanguageError\","
260 "\"kind\":\"LanguageError\",\"id\":\"objects\\/0\","
261 "\"message\":\"'file:\\/\\/\\/test-lib': error: "
262 "\\/test-lib:3:26: "
263 "Error: This couldn't be parsed.\\n"
264 " helper1() { helper0()+ }\\n ^\"}},"
265
266 // helper0 is compiled.
267 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
268 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
269
270 // One range with two hits (main).
271 "{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
272 "\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
273
274 // Only one script in the script table.
275 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
276 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
277 buffer);
278}
279
280ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_NestedFunctions) {
281 char buffer[1024];
282 const char* kScript =
283 "helper0() {\n"
284 " nestedHelper0() {}\n"
285 " nestedHelper1() {}\n"
286 " nestedHelper0();\n"
287 "}\n"
288 "helper1() {}\n"
289 "main() {\n"
290 " if (true) {\n"
291 " helper0();\n"
292 " } else {\n"
293 " helper1();\n"
294 " }\n"
295 "}";
296
297 Library& lib = Library::Handle();
298 lib ^= ExecuteScript(kScript);
299 ASSERT(!lib.IsNull());
300 const Script& script =
301 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
302
303 SourceReport report(SourceReport::kCoverage);
304 JSONStream js;
305 report.PrintJSON(&js, script);
306 ElideJSONSubstring("classes", js.ToCString(), buffer);
307 ElideJSONSubstring("libraries", buffer, buffer);
308
309 EXPECT_STREQ(
310 "{\"type\":\"SourceReport\",\"ranges\":["
311
312 // One range compiled with one hit (helper0).
313 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":73,\"compiled\":true,"
314 "\"coverage\":{\"hits\":[0,69],\"misses\":[]}},"
315
316 // One range not compiled (helper1).
317 "{\"scriptIndex\":0,\"startPos\":75,\"endPos\":86,\"compiled\":false},"
318
319 // One range with two hits and a miss (main).
320 "{\"scriptIndex\":0,\"startPos\":88,\"endPos\":156,\"compiled\":true,"
321 "\"coverage\":{\"hits\":[88,115],\"misses\":[141]}},"
322
323 // Nested range compiled (nestedHelper0).
324 "{\"scriptIndex\":0,\"startPos\":14,\"endPos\":31,\"compiled\":true,"
325 "\"coverage\":{\"hits\":[14],\"misses\":[]}},"
326
327 // Nested range not compiled (nestedHelper1).
328 "{\"scriptIndex\":0,\"startPos\":35,\"endPos\":52,\"compiled\":false}],"
329
330 // Only one script in the script table.
331 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
332 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
333 buffer);
334}
335
336ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_RestrictedRange) {
337 char buffer[1024];
338 const char* kScript =
339 "helper0() {\n"
340 " nestedHelper0() {}\n"
341 " nestedHelper1() {}\n"
342 " nestedHelper0();\n"
343 "}\n"
344 "helper1() {}\n"
345 "main() {\n"
346 " if (true) {\n"
347 " helper0();\n"
348 " } else {\n"
349 " helper1();\n"
350 " }\n"
351 "}";
352
353 Library& lib = Library::Handle();
354 lib ^= ExecuteScript(kScript);
355 ASSERT(!lib.IsNull());
356 const Script& script =
357 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
358 const Function& helper = Function::Handle(
359 lib.LookupLocalFunction(String::Handle(String::New("helper0"))));
360
361 SourceReport report(SourceReport::kCoverage);
362 JSONStream js;
363 // Restrict the report to only helper0 and it's nested functions.
364 report.PrintJSON(&js, script, helper.token_pos(), helper.end_token_pos());
365 ElideJSONSubstring("classes", js.ToCString(), buffer);
366 ElideJSONSubstring("libraries", buffer, buffer);
367
368 EXPECT_STREQ(
369 "{\"type\":\"SourceReport\",\"ranges\":["
370
371 // One range compiled with one hit (helper0).
372 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":73,\"compiled\":true,"
373 "\"coverage\":{\"hits\":[0,69],\"misses\":[]}},"
374
375 // Nested range compiled (nestedHelper0).
376 "{\"scriptIndex\":0,\"startPos\":14,\"endPos\":31,\"compiled\":true,"
377 "\"coverage\":{\"hits\":[14],\"misses\":[]}},"
378
379 // Nested range not compiled (nestedHelper1).
380 "{\"scriptIndex\":0,\"startPos\":35,\"endPos\":52,\"compiled\":false}],"
381
382 // Only one script in the script table.
383 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
384 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
385 buffer);
386}
387
388ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_AllFunctions) {
389 const char* kScript =
390 "helper0() {}\n"
391 "helper1() {}\n"
392 "main() {\n"
393 " if (true) {\n"
394 " helper0();\n"
395 " } else {\n"
396 " helper1();\n"
397 " }\n"
398 "}";
399
400 Library& lib = Library::Handle();
401 lib ^= ExecuteScript(kScript);
402 ASSERT(!lib.IsNull());
403
404 SourceReport report(SourceReport::kCoverage);
405 JSONStream js;
406
407 // We generate a report with all functions in the VM.
408 Script& null_script = Script::Handle();
409 report.PrintJSON(&js, null_script);
410 const char* result = js.ToCString();
411
412 // Sanity check the header.
413 EXPECT_SUBSTRING("{\"type\":\"SourceReport\",\"ranges\":[", result);
414
415 // Make sure that the main function was found.
416 EXPECT_SUBSTRING(
417 "\"startPos\":26,\"endPos\":94,\"compiled\":true,"
418 "\"coverage\":{\"hits\":[26,53],\"misses\":[79]}",
419 result);
420
421 // More than one script is referenced in the report.
422 EXPECT_SUBSTRING("\"scriptIndex\":0", result);
423 EXPECT_SUBSTRING("\"scriptIndex\":1", result);
424 EXPECT_SUBSTRING("\"scriptIndex\":2", result);
425}
426
427ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_AllFunctions_ForceCompile) {
428 const char* kScript =
429 "helper0() {}\n"
430 "helper1() {}\n"
431 "main() {\n"
432 " if (true) {\n"
433 " helper0();\n"
434 " } else {\n"
435 " helper1();\n"
436 " }\n"
437 "}";
438
439 Library& lib = Library::Handle();
440 lib ^= ExecuteScript(kScript);
441 ASSERT(!lib.IsNull());
442
443 SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
444 JSONStream js;
445
446 // We generate a report with all functions in the VM.
447 Script& null_script = Script::Handle();
448 report.PrintJSON(&js, null_script);
449 const char* result = js.ToCString();
450
451 // Sanity check the header.
452 EXPECT_SUBSTRING("{\"type\":\"SourceReport\",\"ranges\":[", result);
453
454 // Make sure that the main function was found.
455 EXPECT_SUBSTRING(
456 "\"startPos\":26,\"endPos\":94,\"compiled\":true,"
457 "\"coverage\":{\"hits\":[26,53],\"misses\":[79]}",
458 result);
459
460 // More than one script is referenced in the report.
461 EXPECT_SUBSTRING("\"scriptIndex\":0", result);
462 EXPECT_SUBSTRING("\"scriptIndex\":1", result);
463 EXPECT_SUBSTRING("\"scriptIndex\":2", result);
464}
465
466ISOLATE_UNIT_TEST_CASE(SourceReport_CallSites_SimpleCall) {
467 char buffer[1024];
468 const char* kScript =
469 "helper0() {}\n"
470 "helper1() {}\n"
471 "main() {\n"
472 " helper0();\n"
473 "}";
474
475 Library& lib = Library::Handle();
476 lib ^= ExecuteScript(kScript);
477 ASSERT(!lib.IsNull());
478 const Script& script =
479 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
480
481 SourceReport report(SourceReport::kCallSites);
482 JSONStream js;
483 report.PrintJSON(&js, script);
484 ElideJSONSubstring("classes", js.ToCString(), buffer);
485 ElideJSONSubstring("libraries", buffer, buffer);
486 EXPECT_STREQ(
487 "{\"type\":\"SourceReport\",\"ranges\":["
488
489 // One range compiled with no callsites (helper0).
490 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
491 "\"callSites\":[]},"
492
493 // One range not compiled (helper1).
494 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
495
496 // One range compiled with one callsite (main).
497 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":48,\"compiled\":true,"
498 "\"callSites\":["
499 "{\"name\":\"helper0\",\"tokenPos\":37,\"cacheEntries\":["
500 "{\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
501 "\"name\":\"helper0\",\"owner\":{\"type\":\"@Library\",\"fixedId\":true,"
502 "\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"},"
503 "\"_kind\":\"RegularFunction\",\"static\":true,\"const\":false,"
504 "\"_intrinsic\":false,\"_native\":false},\"count\":1}]}]}],"
505
506 // One script in the script table.
507 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
508 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
509 buffer);
510}
511
512ISOLATE_UNIT_TEST_CASE(SourceReport_CallSites_PolymorphicCall) {
513 char buffer[1024];
514 const char* kScript =
515 "class Common {\n"
516 " func() {}\n"
517 "}\n"
518 "class Uncommon {\n"
519 " func() {}\n"
520 "}\n"
521 "helper(arg) {\n"
522 " arg.func();\n"
523 "}\n"
524 "main() {\n"
525 " Common common = new Common();\n"
526 " Uncommon uncommon = new Uncommon();\n"
527 " helper(common);\n"
528 " helper(common);\n"
529 " helper(uncommon);\n"
530 "}";
531
532 Library& lib = Library::Handle();
533 lib ^= ExecuteScript(kScript);
534 ASSERT(!lib.IsNull());
535 const Script& script =
536 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
537 const Function& helper = Function::Handle(
538 lib.LookupLocalFunction(String::Handle(String::New("helper"))));
539
540 SourceReport report(SourceReport::kCallSites);
541 JSONStream js;
542 report.PrintJSON(&js, script, helper.token_pos(), helper.end_token_pos());
543 ElideJSONSubstring("classes", js.ToCString(), buffer);
544 ElideJSONSubstring("libraries", buffer, buffer);
545 EXPECT_STREQ(
546 "{\"type\":\"SourceReport\",\"ranges\":["
547
548 // One range...
549 "{\"scriptIndex\":0,\"startPos\":60,\"endPos\":88,\"compiled\":true,"
550
551 // With one call site...
552 "\"callSites\":[{\"name\":\"dyn:func\",\"tokenPos\":80,\"cacheEntries\":["
553
554 // First receiver: "Common", called twice.
555 "{\"receiver\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
556 "\"name\":\"Common\"},"
557
558 "\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
559 "\"name\":\"func\","
560 "\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
561 "\"name\":\"Common\"},\"_kind\":\"RegularFunction\","
562 "\"static\":false,\"const\":false,\"_intrinsic\":false,"
563 "\"_native\":false},"
564
565 "\"count\":2},"
566
567 // Second receiver: "Uncommon", called once.
568 "{\"receiver\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
569 "\"name\":\"Uncommon\"},"
570
571 "\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
572 "\"name\":\"func\","
573 "\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
574 "\"name\":\"Uncommon\"},\"_kind\":\"RegularFunction\","
575 "\"static\":false,\"const\":false,\"_intrinsic\":false,"
576 "\"_native\":false},"
577
578 "\"count\":1}]}]}],"
579
580 // One script in the script table.
581 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
582 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
583 buffer);
584}
585
586ISOLATE_UNIT_TEST_CASE(SourceReport_MultipleReports) {
587 char buffer[1024];
588 const char* kScript =
589 "helper0() {}\n"
590 "helper1() {}\n"
591 "main() {\n"
592 " helper0();\n"
593 "}";
594
595 Library& lib = Library::Handle();
596 lib ^= ExecuteScript(kScript);
597 ASSERT(!lib.IsNull());
598 const Script& script =
599 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
600
601 SourceReport report(SourceReport::kCallSites | SourceReport::kCoverage);
602 JSONStream js;
603 report.PrintJSON(&js, script);
604 ElideJSONSubstring("classes", js.ToCString(), buffer);
605 ElideJSONSubstring("libraries", buffer, buffer);
606 EXPECT_STREQ(
607 "{\"type\":\"SourceReport\",\"ranges\":["
608
609 // One range compiled with no callsites (helper0).
610 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
611 "\"callSites\":[],"
612 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
613
614 // One range not compiled (helper1).
615 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
616
617 // One range compiled with one callsite (main).
618 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":48,\"compiled\":true,"
619 "\"callSites\":["
620 "{\"name\":\"helper0\",\"tokenPos\":37,\"cacheEntries\":["
621 "{\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
622 "\"name\":\"helper0\",\"owner\":{\"type\":\"@Library\",\"fixedId\":true,"
623 "\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"},"
624 "\"_kind\":\"RegularFunction\",\"static\":true,\"const\":false,"
625 "\"_intrinsic\":false,\"_native\":false},\"count\":1}]}],"
626 "\"coverage\":{\"hits\":[26,37],\"misses\":[]}}],"
627
628 // One script in the script table.
629 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
630 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
631 buffer);
632}
633
634ISOLATE_UNIT_TEST_CASE(SourceReport_PossibleBreakpoints_Simple) {
635 char buffer[1024];
636 const char* kScript =
637 "helper0() {}\n"
638 "helper1() {}\n"
639 "main() {\n"
640 " if (true) {\n"
641 " helper0();\n"
642 " } else {\n"
643 " helper1();\n"
644 " }\n"
645 "}";
646
647 Library& lib = Library::Handle();
648 lib ^= ExecuteScript(kScript);
649 ASSERT(!lib.IsNull());
650 const Script& script =
651 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
652
653 SourceReport report(SourceReport::kPossibleBreakpoints);
654 JSONStream js;
655 report.PrintJSON(&js, script);
656 ElideJSONSubstring("classes", js.ToCString(), buffer);
657 ElideJSONSubstring("libraries", buffer, buffer);
658 EXPECT_STREQ(
659 "{\"type\":\"SourceReport\",\"ranges\":["
660
661 // helper0.
662 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
663 "\"possibleBreakpoints\":[7,11]},"
664
665 // One range not compiled (helper1).
666 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
667
668 // main.
669 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
670 "\"possibleBreakpoints\":[30,53,79,94]}],"
671
672 // Only one script in the script table.
673 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
674 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
675 buffer);
676}
677
678ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Issue35453_NoSuchMethod) {
679 char buffer[1024];
680 const char* kScript =
681 "class Foo {\n"
682 " void bar() {}\n"
683 "}\n"
684 "class Unused implements Foo {\n"
685 " dynamic noSuchMethod(_) {}\n"
686 "}\n"
687 "void main() {\n"
688 " Foo().bar();\n"
689 "}\n";
690
691 Library& lib = Library::Handle();
692 lib ^= ExecuteScript(kScript);
693 ASSERT(!lib.IsNull());
694 const Script& script =
695 Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
696
697 SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
698 JSONStream js;
699 report.PrintJSON(&js, script);
700 ElideJSONSubstring("classes", js.ToCString(), buffer);
701 ElideJSONSubstring("libraries", buffer, buffer);
702 EXPECT_STREQ(
703 "{\"type\":\"SourceReport\",\"ranges\":["
704
705 // Foo is hit.
706 "{\"scriptIndex\":0,\"startPos\":14,\"endPos\":26,\"compiled\":true,"
707 "\"coverage\":{\"hits\":[14],\"misses\":[]}},"
708
709 // Unused is missed.
710 "{\"scriptIndex\":0,\"startPos\":62,\"endPos\":87,\"compiled\":true,"
711 "\"coverage\":{\"hits\":[],\"misses\":[62]}},"
712
713 // Main is hit.
714 "{\"scriptIndex\":0,\"startPos\":91,\"endPos\":120,\"compiled\":true,"
715 "\"coverage\":{\"hits\":[91,107,113],\"misses\":[]}}],"
716
717 // Only one script in the script table.
718 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
719 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
720 buffer);
721}
722
723#endif // !PRODUCT
724
725} // namespace dart
726