Flutter Engine
The Flutter Engine
source_report_test.cc
Go to the documentation of this file.
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 {
17 if (allow_errors) {
19 } else {
20 lib = TestCase::LoadTestScript(script, nullptr);
21 }
22 EXPECT_VALID(lib);
23 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
25 }
26 return Api::UnwrapHandle(lib);
27}
28
29ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_NoCalls) {
30 // WARNING: This MUST be big enough for the serialized JSON string.
31 const int kBufferSize = 1024;
32 char buffer[kBufferSize];
33 const char* kScript =
34 "main() {\n"
35 "}";
36
37 Library& lib = Library::Handle();
38 lib ^= ExecuteScript(kScript);
39 ASSERT(!lib.IsNull());
40 const Script& script =
44 report.PrintJSON(&js, script);
45 const char* json_str = js.ToCString();
46 ASSERT(strlen(json_str) < kBufferSize);
47 ElideJSONSubstring("libraries", json_str, buffer);
48 EXPECT_STREQ(
49 "{\"type\":\"SourceReport\",\"ranges\":"
50
51 // One compiled range, one hit at function declaration.
52 "[{\"scriptIndex\":0,\"startPos\":0,\"endPos\":9,\"compiled\":true,"
53 "\"coverage\":{\"hits\":[0],\"misses\":[]}}],"
54
55 // One script in the script table.
56 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
57 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
58 buffer);
59}
60
61ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Filters_single) {
62 // WARNING: This MUST be big enough for the serialized JSON string.
63 const int kBufferSize = 1024;
64 char buffer[kBufferSize];
65 const char* kScript =
66 "main() {\n"
67 "}";
68
69 Library& lib = Library::Handle();
70 lib ^= ExecuteScript(kScript);
71 ASSERT(!lib.IsNull());
72
73 GrowableObjectArray& filters =
79 const char* json_str = js.ToCString();
80 ASSERT(strlen(json_str) < kBufferSize);
81 ElideJSONSubstring("libraries", json_str, buffer);
82 EXPECT_STREQ(
83 "{\"type\":\"SourceReport\",\"ranges\":"
84
85 // One compiled range, one hit at function declaration.
86 "[{\"scriptIndex\":0,\"startPos\":0,\"endPos\":9,\"compiled\":true,"
87 "\"coverage\":{\"hits\":[0],\"misses\":[]}}],"
88
89 // One script in the script table.
90 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
91 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
92 buffer);
93}
94
95ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Filters_empty) {
96 // WARNING: This MUST be big enough for the serialized JSON string.
97 const int kBufferSize = 1024;
98 char buffer[kBufferSize];
99 const char* kScript =
100 "main() {\n"
101 "}";
102
103 Library& lib = Library::Handle();
104 lib ^= ExecuteScript(kScript);
105 ASSERT(!lib.IsNull());
106
107 GrowableObjectArray& filters =
109 filters.Add(String::Handle(String::New("foo:bar/")));
110 SourceReport report(SourceReport::kCoverage, filters);
113 const char* json_str = js.ToCString();
114 ASSERT(strlen(json_str) < kBufferSize);
115 ElideJSONSubstring("libraries", json_str, buffer);
116 EXPECT_STREQ(
117 "{\"type\":\"SourceReport\",\"ranges\":"
118
119 // No compiled range.
120 "[],"
121
122 // No script.
123 "\"scripts\":[]}",
124 buffer);
125}
126
127ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_SimpleCall) {
128 // WARNING: This MUST be big enough for the serialized JSON string.
129 const int kBufferSize = 1024;
130 char buffer[kBufferSize];
131 const char* kScript =
132 "helper0() {}\n"
133 "helper1() {}\n"
134 "main() {\n"
135 " if (true) {\n"
136 " helper0();\n"
137 " } else {\n"
138 " helper1();\n"
139 " }\n"
140 "}";
141
142 Library& lib = Library::Handle();
143 lib ^= ExecuteScript(kScript);
144 ASSERT(!lib.IsNull());
145 const Script& script =
147
150 report.PrintJSON(&js, script);
151 const char* json_str = js.ToCString();
152 ASSERT(strlen(json_str) < kBufferSize);
153 ElideJSONSubstring("classes", json_str, buffer);
154 ElideJSONSubstring("libraries", buffer, buffer);
155 EXPECT_STREQ(
156 "{\"type\":\"SourceReport\",\"ranges\":["
157
158 // One range compiled with one hit at function declaration (helper0).
159 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
160 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
161
162 // One range not compiled (helper1).
163 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
164
165 // One range with two hits and a miss (main).
166 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
167 "\"coverage\":{\"hits\":[26,53],\"misses\":[79]}}],"
168
169 // Only one script in the script table.
170 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
171 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
172 buffer);
173}
174
175ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_ForceCompile) {
176 // WARNING: This MUST be big enough for the serialized JSON string.
177 const int kBufferSize = 1024;
178 char buffer[kBufferSize];
179 const char* kScript =
180 "helper0() {}\n"
181 "helper1() {}\n"
182 "main() {\n"
183 " if (true) {\n"
184 " helper0();\n"
185 " } else {\n"
186 " helper1();\n"
187 " }\n"
188 "}";
189
190 Library& lib = Library::Handle();
191 lib ^= ExecuteScript(kScript);
192 ASSERT(!lib.IsNull());
193 const Script& script =
195
198 report.PrintJSON(&js, script);
199 const char* json_str = js.ToCString();
200 ASSERT(strlen(json_str) < kBufferSize);
201 ElideJSONSubstring("classes", json_str, buffer);
202 ElideJSONSubstring("libraries", buffer, buffer);
203
204 EXPECT_STREQ(
205 "{\"type\":\"SourceReport\",\"ranges\":["
206
207 // One range compiled with one hit at function declaration (helper0).
208 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
209 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
210
211 // This range is compiled even though it wasn't called (helper1).
212 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":true,"
213 "\"coverage\":{\"hits\":[],\"misses\":[13]}},"
214
215 // One range with two hits and a miss (main).
216 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
217 "\"coverage\":{\"hits\":[26,53],\"misses\":[79]}}],"
218
219 // Only one script in the script table.
220 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
221 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
222 buffer);
223}
224
225ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_NoForceCompile) {
226 // WARNING: This MUST be big enough for the serialized JSON string.
227 const int kBufferSize = 1024;
228 char buffer[kBufferSize];
229 const char* kScript =
230 "helper0() {}\n"
231 "class Unused {\n"
232 " helper1() { helper0(); }\n"
233 "}\n"
234 "main() {\n"
235 " helper0();\n"
236 "}";
237
238 Library& lib = Library::Handle();
239 lib ^= ExecuteScript(kScript);
240 ASSERT(!lib.IsNull());
241 const Script& script =
243
246 report.PrintJSON(&js, script);
247 const char* json_str = js.ToCString();
248 ASSERT(strlen(json_str) < kBufferSize);
249 ElideJSONSubstring("classes", json_str, buffer);
250 ElideJSONSubstring("libraries", buffer, buffer);
251 EXPECT_STREQ(
252 "{\"type\":\"SourceReport\",\"ranges\":["
253
254 // UnusedClass is not compiled.
255 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":55,\"compiled\":false},"
256
257 // helper0 is compiled.
258 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
259 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
260
261 // One range with two hits (main).
262 "{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
263 "\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
264
265 // Only one script in the script table.
266 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
267 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
268 buffer);
269}
270
271ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_ForceCompile) {
272 // WARNING: This MUST be big enough for the serialized JSON string.
273 const int kBufferSize = 1024;
274 char buffer[kBufferSize];
275 const char* kScript =
276 "helper0() {}\n"
277 "class Unused {\n"
278 " helper1() { helper0(); }\n"
279 "}\n"
280 "main() {\n"
281 " helper0();\n"
282 "}";
283
284 Library& lib = Library::Handle();
285 lib ^= ExecuteScript(kScript);
286 ASSERT(!lib.IsNull());
287 const Script& script =
289
292 report.PrintJSON(&js, script);
293 const char* json_str = js.ToCString();
294 ASSERT(strlen(json_str) < kBufferSize);
295 ElideJSONSubstring("classes", json_str, buffer);
296 ElideJSONSubstring("libraries", buffer, buffer);
297 EXPECT_STREQ(
298 "{\"type\":\"SourceReport\",\"ranges\":["
299
300 // UnusedClass.helper1 is compiled.
301 "{\"scriptIndex\":0,\"startPos\":30,\"endPos\":53,\"compiled\":true,"
302 "\"coverage\":{\"hits\":[],\"misses\":[30,42]}},"
303
304 // helper0 is compiled.
305 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
306 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
307
308 // One range with two hits (main).
309 "{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
310 "\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
311
312 // Only one script in the script table.
313 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
314 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
315 buffer);
316}
317
318ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_ForceCompileError) {
319 // WARNING: This MUST be big enough for the serialized JSON string.
320 const int kBufferSize = 1024;
321 char buffer[kBufferSize];
322 const char* kScript =
323 "helper0() {}\n"
324 "class Unused {\n"
325 " helper1() { helper0()+ }\n" // syntax error
326 "}\n"
327 "main() {\n"
328 " helper0();\n"
329 "}";
330
331 Library& lib = Library::Handle();
332 lib ^= ExecuteScript(kScript, true);
333 ASSERT(!lib.IsNull());
334 const Script& script =
336
339 report.PrintJSON(&js, script);
340 const char* json_str = js.ToCString();
341 ASSERT(strlen(json_str) < kBufferSize);
342 ElideJSONSubstring("classes", json_str, buffer);
343 ElideJSONSubstring("libraries", buffer, buffer);
344 EXPECT_STREQ(
345 "{\"type\":\"SourceReport\",\"ranges\":["
346
347 // UnusedClass has a syntax error.
348 "{\"scriptIndex\":0,\"startPos\":30,\"endPos\":53,\"compiled\":false,"
349 "\"error\":{\"type\":\"@Error\",\"_vmType\":\"LanguageError\","
350 "\"kind\":\"LanguageError\",\"id\":\"objects\\/0\","
351 "\"message\":\"'file:\\/\\/\\/test-lib': error: "
352 "\\/test-lib:3:26: "
353 "Error: This couldn't be parsed.\\n"
354 " helper1() { helper0()+ }\\n ^\"}},"
355
356 // helper0 is compiled.
357 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
358 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
359
360 // One range with two hits (main).
361 "{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
362 "\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
363
364 // Only one script in the script table.
365 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
366 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
367 buffer);
368}
369
370ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_LibrariesAlreadyCompiled) {
371 // WARNING: This MUST be big enough for the serialized JSON string.
372 const int kBufferSize = 1024;
373 char buffer[kBufferSize];
374 const char* kScript =
375 "helper0() {}\n"
376 "class Unused {\n"
377 " helper1() { helper0(); }\n"
378 "}\n"
379 "main() {\n"
380 " helper0();\n"
381 "}";
382
383 Library& lib = Library::Handle();
384 lib ^= ExecuteScript(kScript);
385 ASSERT(!lib.IsNull());
386 const Script& script =
388
389 Zone* zone = thread->zone();
390 ZoneCStringSet* libraries_already_compiled = new (zone) ZoneCStringSet(zone);
391 libraries_already_compiled->Insert(RESOLVED_USER_TEST_URI);
393 libraries_already_compiled, SourceReport::kForceCompile);
395 report.PrintJSON(&js, script);
396 const char* json_str = js.ToCString();
397 ASSERT(strlen(json_str) < kBufferSize);
398 ElideJSONSubstring("classes", json_str, buffer);
399 ElideJSONSubstring("libraries", buffer, buffer);
400 EXPECT_STREQ(
401 "{\"type\":\"SourceReport\",\"ranges\":["
402
403 // UnusedClass is not compiled.
404 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":55,\"compiled\":false},"
405
406 // helper0 is compiled.
407 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
408 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
409
410 // One range with two hits (main).
411 "{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
412 "\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
413
414 // Only one script in the script table.
415 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
416 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
417 buffer);
418}
419
420ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_NestedFunctions) {
421 // WARNING: This MUST be big enough for the serialized JSON string.
422 const int kBufferSize = 1024;
423 char buffer[kBufferSize];
424 const char* kScript =
425 "helper0() {\n"
426 " nestedHelper0() {}\n"
427 " nestedHelper1() {}\n"
428 " nestedHelper0();\n"
429 "}\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 const Script& script =
444
447 report.PrintJSON(&js, script);
448 const char* json_str = js.ToCString();
449 ASSERT(strlen(json_str) < kBufferSize);
450 ElideJSONSubstring("classes", json_str, buffer);
451 ElideJSONSubstring("libraries", buffer, buffer);
452
453 EXPECT_STREQ(
454 "{\"type\":\"SourceReport\",\"ranges\":["
455
456 // One range compiled with one hit (helper0).
457 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":73,\"compiled\":true,"
458 "\"coverage\":{\"hits\":[0,56],\"misses\":[]}},"
459
460 // One range not compiled (helper1).
461 "{\"scriptIndex\":0,\"startPos\":75,\"endPos\":86,\"compiled\":false},"
462
463 // One range with two hits and a miss (main).
464 "{\"scriptIndex\":0,\"startPos\":88,\"endPos\":156,\"compiled\":true,"
465 "\"coverage\":{\"hits\":[88,115],\"misses\":[141]}},"
466
467 // Nested range compiled (nestedHelper0).
468 "{\"scriptIndex\":0,\"startPos\":14,\"endPos\":31,\"compiled\":true,"
469 "\"coverage\":{\"hits\":[14],\"misses\":[]}},"
470
471 // Nested range not compiled (nestedHelper1).
472 "{\"scriptIndex\":0,\"startPos\":35,\"endPos\":52,\"compiled\":false}],"
473
474 // Only one script in the script table.
475 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
476 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
477 buffer);
478}
479
480ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_RestrictedRange) {
481 // WARNING: This MUST be big enough for the serialized JSON string.
482 const int kBufferSize = 1024;
483 char buffer[kBufferSize];
484 const char* kScript =
485 "helper0() {\n"
486 " nestedHelper0() {}\n"
487 " nestedHelper1() {}\n"
488 " nestedHelper0();\n"
489 "}\n"
490 "helper1() {}\n"
491 "main() {\n"
492 " if (true) {\n"
493 " helper0();\n"
494 " } else {\n"
495 " helper1();\n"
496 " }\n"
497 "}";
498
499 Library& lib = Library::Handle();
500 lib ^= ExecuteScript(kScript);
501 ASSERT(!lib.IsNull());
502 const Script& script =
504 const Function& helper = Function::Handle(
506
509 // Restrict the report to only helper0 and it's nested functions.
510 report.PrintJSON(&js, script, helper.token_pos(), helper.end_token_pos());
511 const char* json_str = js.ToCString();
512 ASSERT(strlen(json_str) < kBufferSize);
513 ElideJSONSubstring("classes", json_str, buffer);
514 ElideJSONSubstring("libraries", buffer, buffer);
515
516 EXPECT_STREQ(
517 "{\"type\":\"SourceReport\",\"ranges\":["
518
519 // One range compiled with one hit (helper0).
520 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":73,\"compiled\":true,"
521 "\"coverage\":{\"hits\":[0,56],\"misses\":[]}},"
522
523 // Nested range compiled (nestedHelper0).
524 "{\"scriptIndex\":0,\"startPos\":14,\"endPos\":31,\"compiled\":true,"
525 "\"coverage\":{\"hits\":[14],\"misses\":[]}},"
526
527 // Nested range not compiled (nestedHelper1).
528 "{\"scriptIndex\":0,\"startPos\":35,\"endPos\":52,\"compiled\":false}],"
529
530 // Only one script in the script table.
531 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
532 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
533 buffer);
534}
535
536ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_AllFunctions) {
537 const char* kScript =
538 "helper0() {}\n"
539 "helper1() {}\n"
540 "main() {\n"
541 " if (true) {\n"
542 " helper0();\n"
543 " } else {\n"
544 " helper1();\n"
545 " }\n"
546 "}";
547
548 Library& lib = Library::Handle();
549 lib ^= ExecuteScript(kScript);
550 ASSERT(!lib.IsNull());
551
554
555 // We generate a report with all functions in the VM.
556 Script& null_script = Script::Handle();
557 report.PrintJSON(&js, null_script);
558 const char* result = js.ToCString();
559
560 // Sanity check the header.
561 EXPECT_SUBSTRING("{\"type\":\"SourceReport\",\"ranges\":[", result);
562
563 // Make sure that the main function was found.
564 EXPECT_SUBSTRING(
565 "\"startPos\":26,\"endPos\":94,\"compiled\":true,"
566 "\"coverage\":{\"hits\":[26,53],\"misses\":[79]}",
567 result);
568
569 // More than one script is referenced in the report.
570 EXPECT_SUBSTRING("\"scriptIndex\":0", result);
571 EXPECT_SUBSTRING("\"scriptIndex\":1", result);
572 EXPECT_SUBSTRING("\"scriptIndex\":2", result);
573}
574
575ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_AllFunctions_ForceCompile) {
576 const char* kScript =
577 "helper0() {}\n"
578 "helper1() {}\n"
579 "main() {\n"
580 " if (true) {\n"
581 " helper0();\n"
582 " } else {\n"
583 " helper1();\n"
584 " }\n"
585 "}";
586
587 Library& lib = Library::Handle();
588 lib ^= ExecuteScript(kScript);
589 ASSERT(!lib.IsNull());
590
593
594 // We generate a report with all functions in the VM.
595 Script& null_script = Script::Handle();
596 report.PrintJSON(&js, null_script);
597 const char* result = js.ToCString();
598
599 // Sanity check the header.
600 EXPECT_SUBSTRING("{\"type\":\"SourceReport\",\"ranges\":[", result);
601
602 // Make sure that the main function was found.
603 EXPECT_SUBSTRING(
604 "\"startPos\":26,\"endPos\":94,\"compiled\":true,"
605 "\"coverage\":{\"hits\":[26,53],\"misses\":[79]}",
606 result);
607
608 // More than one script is referenced in the report.
609 EXPECT_SUBSTRING("\"scriptIndex\":0", result);
610 EXPECT_SUBSTRING("\"scriptIndex\":1", result);
611 EXPECT_SUBSTRING("\"scriptIndex\":2", result);
612}
613
614ISOLATE_UNIT_TEST_CASE(SourceReport_CallSites_SimpleCall) {
615 // WARNING: This MUST be big enough for the serialized JSON string.
616 const int kBufferSize = 2048;
617 char buffer[kBufferSize];
618 const char* kScript =
619 "helper0() {}\n"
620 "helper1() {}\n"
621 "main() {\n"
622 " helper0();\n"
623 "}";
624
625 Library& lib = Library::Handle();
626 lib ^= ExecuteScript(kScript);
627 ASSERT(!lib.IsNull());
628 const Script& script =
630
633 report.PrintJSON(&js, script);
634 const char* json_str = js.ToCString();
635 ASSERT(strlen(json_str) < kBufferSize);
636 ElideJSONSubstring("classes", json_str, buffer);
637 ElideJSONSubstring("libraries", buffer, buffer);
638 EXPECT_STREQ(
639 "{\"type\":\"SourceReport\",\"ranges\":["
640
641 // One range compiled with no callsites (helper0).
642 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
643 "\"callSites\":[]},"
644
645 // One range not compiled (helper1).
646 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
647
648 // One range compiled with one callsite (main).
649 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":48,\"compiled\":true,"
650 "\"callSites\":["
651 "{\"name\":\"helper0\",\"tokenPos\":37,\"cacheEntries\":["
652 "{\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
653 "\"name\":\"helper0\",\"owner\":{\"type\":\"@Library\",\"fixedId\":true,"
654 "\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"},"
655 "\"_kind\":\"RegularFunction\",\"static\":true,\"const\":false,"
656 "\"implicit\":false,\"abstract\":false,"
657 "\"_intrinsic\":false,\"_native\":false,\"isGetter\":false,"
658 "\"isSetter\":false,\"location\":{\"type\":"
659 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
660 "\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"},"
661 "\"tokenPos\":0,\"endTokenPos\":11,\"line\":1,\"column\":1}},\"count\":1}"
662 "]}]}],"
663
664 // One script in the script table.
665 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
666 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
667 buffer);
668}
669
670ISOLATE_UNIT_TEST_CASE(SourceReport_CallSites_PolymorphicCall) {
671 // WARNING: This MUST be big enough for the serialized JSON string.
672 const int kBufferSize = 4096;
673 char buffer[kBufferSize];
674 const char* kScript =
675 "class Common {\n"
676 " func() {}\n"
677 "}\n"
678 "class Uncommon {\n"
679 " func() {}\n"
680 "}\n"
681 "helper(arg) {\n"
682 " arg.func();\n"
683 "}\n"
684 "main() {\n"
685 " Common common = new Common();\n"
686 " Uncommon uncommon = new Uncommon();\n"
687 " helper(common);\n"
688 " helper(common);\n"
689 " helper(uncommon);\n"
690 "}";
691
692 Library& lib = Library::Handle();
693 lib ^= ExecuteScript(kScript);
694 ASSERT(!lib.IsNull());
695 const Script& script =
697 const Function& helper = Function::Handle(
699
702 report.PrintJSON(&js, script, helper.token_pos(), helper.end_token_pos());
703 const char* json_str = js.ToCString();
704 ASSERT(strlen(json_str) < kBufferSize);
705 ElideJSONSubstring("classes", json_str, buffer);
706 ElideJSONSubstring("libraries", buffer, buffer);
707 EXPECT_STREQ(
708 "{\"type\":\"SourceReport\",\"ranges\":["
709
710 // One range...
711 "{\"scriptIndex\":0,\"startPos\":60,\"endPos\":88,\"compiled\":true,"
712
713 // With one call site...
714 "\"callSites\":[{\"name\":\"dyn:func\",\"tokenPos\":80,\"cacheEntries\":["
715
716 // First receiver: "Common", called twice.
717 "{\"receiver\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
718 "\"name\":\"Common\","
719 "\"location\":{\"type\":\"SourceLocation\","
720 "\"script\":{\"type\":\"@Script\","
721 "\"fixedId\":true,\"id\":\"\","
722 "\"uri\":\"file:\\/\\/\\/test-lib\","
723 "\"_kind\":\"kernel\"},\"tokenPos\":0,\"endTokenPos\":27,\"line\":1,"
724 "\"column\":1},"
725 "\"library\":{\"type\":\"@Library\",\"fixedId\":true,"
726 "\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"}},"
727
728 "\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
729 "\"name\":\"func\","
730 "\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
731 "\"name\":\"Common\","
732 "\"location\":{\"type\":\"SourceLocation\","
733 "\"script\":{\"type\":\"@Script\","
734 "\"fixedId\":true,\"id\":\"\","
735 "\"uri\":\"file:\\/\\/\\/test-lib\","
736 "\"_kind\":\"kernel\"},\"tokenPos\":0,\"endTokenPos\":27,\"line\":1,"
737 "\"column\":1},"
738 "\"library\":{\"type\":\"@Library\",\"fixedId\":true,"
739 "\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"}"
740 "},\"_kind\":\"RegularFunction\","
741 "\"static\":false,\"const\":false,\"implicit\":false,\"abstract\":"
742 "false,\"_intrinsic\":false,"
743 "\"_native\":false,\"isGetter\":false,\"isSetter\":false,"
744 "\"location\":{\"type\":\"SourceLocation\","
745 "\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
746 "\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\","
747 "\"_kind\":\"kernel\"},\"tokenPos\":17,\"endTokenPos\":25,\"line\":2,"
748 "\"column\":3}},"
749
750 "\"count\":2},"
751
752 // Second receiver: "Uncommon", called once.
753 "{\"receiver\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
754 "\"name\":\"Uncommon\","
755 "\"location\":{\"type\":\"SourceLocation\","
756 "\"script\":{\"type\":\"@Script\","
757 "\"fixedId\":true,\"id\":\"\","
758 "\"uri\":\"file:\\/\\/\\/test-lib\","
759 "\"_kind\":\"kernel\"},\"tokenPos\":29,\"endTokenPos\":58,\"line\":4,"
760 "\"column\":1},"
761 "\"library\":{\"type\":\"@Library\",\"fixedId\":true,"
762 "\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"}},"
763
764 "\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
765 "\"name\":\"func\","
766 "\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
767 "\"name\":\"Uncommon\","
768 "\"location\":{\"type\":\"SourceLocation\","
769 "\"script\":{\"type\":\"@Script\","
770 "\"fixedId\":true,\"id\":\"\","
771 "\"uri\":\"file:\\/\\/\\/test-lib\","
772 "\"_kind\":\"kernel\"},\"tokenPos\":29,\"endTokenPos\":58,\"line\":4,"
773 "\"column\":1},"
774 "\"library\":{\"type\":\"@Library\",\"fixedId\":true,"
775 "\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"}"
776 "},\"_kind\":\"RegularFunction\","
777 "\"static\":false,\"const\":false,\"implicit\":false,\"abstract\":"
778 "false,\"_intrinsic\":false,"
779 "\"_native\":false,\"isGetter\":false,\"isSetter\":false,"
780 "\"location\":{\"type\":\"SourceLocation\","
781 "\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
782 "\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\","
783 "\"_kind\":\"kernel\"},\"tokenPos\":48,\"endTokenPos\":56,\"line\":5,"
784 "\"column\":3}},"
785
786 "\"count\":1}]}]}],"
787
788 // One script in the script table.
789 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
790 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
791 buffer);
792}
793
794ISOLATE_UNIT_TEST_CASE(SourceReport_MultipleReports) {
795 // WARNING: This MUST be big enough for the serialized JSON string.
796 const int kBufferSize = 2048;
797 char buffer[kBufferSize];
798 const char* kScript =
799 "helper0() {}\n"
800 "helper1() {}\n"
801 "main() {\n"
802 " helper0();\n"
803 "}";
804
805 Library& lib = Library::Handle();
806 lib ^= ExecuteScript(kScript);
807 ASSERT(!lib.IsNull());
808 const Script& script =
810
813 report.PrintJSON(&js, script);
814 const char* json_str = js.ToCString();
815 ASSERT(strlen(json_str) < kBufferSize);
816 ElideJSONSubstring("classes", json_str, buffer);
817 ElideJSONSubstring("libraries", buffer, buffer);
818 EXPECT_STREQ(
819 "{\"type\":\"SourceReport\",\"ranges\":["
820
821 // One range compiled with no callsites (helper0).
822 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
823 "\"callSites\":[],"
824 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
825
826 // One range not compiled (helper1).
827 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
828
829 // One range compiled with one callsite (main)m
830 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":48,\"compiled\":true,"
831 "\"callSites\":[{\"name\":\"helper0\",\"tokenPos\":37,\"cacheEntries\":[{"
832 "\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
833 "\"name\":\"helper0\",\"owner\":{\"type\":\"@Library\",\"fixedId\":true,"
834 "\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"},\"_"
835 "kind\":\"RegularFunction\",\"static\":true,\"const\":false,\"implicit\":"
836 "false,\"abstract\":false,\"_"
837 "intrinsic\":false,\"_native\":false,\"isGetter\":false,"
838 "\"isSetter\":false,\"location\":{\"type\":"
839 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
840 "\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"},"
841 "\"tokenPos\":0,\"endTokenPos\":11,\"line\":1,\"column\":1}},\"count\":1}"
842 "]}],\"coverage\":{"
843 "\"hits\":[26,37],\"misses\":[]}}],"
844
845 // One script in the script table.
846 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
847 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
848 buffer);
849}
850
851ISOLATE_UNIT_TEST_CASE(SourceReport_PossibleBreakpoints_Simple) {
852 // WARNING: This MUST be big enough for the serialized JSON string.
853 const int kBufferSize = 1024;
854 char buffer[kBufferSize];
855 const char* kScript =
856 "helper0() {}\n"
857 "helper1() {}\n"
858 "main() {\n"
859 " if (true) {\n"
860 " helper0();\n"
861 " } else {\n"
862 " helper1();\n"
863 " }\n"
864 "}";
865
866 Library& lib = Library::Handle();
867 lib ^= ExecuteScript(kScript);
868 ASSERT(!lib.IsNull());
869 const Script& script =
871
874 report.PrintJSON(&js, script);
875 const char* json_str = js.ToCString();
876 ASSERT(strlen(json_str) < kBufferSize);
877 ElideJSONSubstring("classes", json_str, buffer);
878 ElideJSONSubstring("libraries", buffer, buffer);
879 EXPECT_STREQ(
880 "{\"type\":\"SourceReport\",\"ranges\":["
881
882 // helper0.
883 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
884 "\"possibleBreakpoints\":[7,11]},"
885
886 // One range not compiled (helper1).
887 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
888
889 // main.
890 "{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
891 "\"possibleBreakpoints\":[30,53,79,94]}],"
892
893 // Only one script in the script table.
894 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
895 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
896 buffer);
897}
898
899ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Issue35453_NoSuchMethod) {
900 // WARNING: This MUST be big enough for the serialized JSON string.
901 const int kBufferSize = 1024;
902 char buffer[kBufferSize];
903 const char* kScript =
904 "class Foo {\n"
905 " void bar() {}\n"
906 "}\n"
907 "class Unused implements Foo {\n"
908 " dynamic noSuchMethod(_) {}\n"
909 "}\n"
910 "void main() {\n"
911 " Foo().bar();\n"
912 "}\n";
913
914 Library& lib = Library::Handle();
915 lib ^= ExecuteScript(kScript);
916 ASSERT(!lib.IsNull());
917 const Script& script =
919
922 report.PrintJSON(&js, script);
923 const char* json_str = js.ToCString();
924 ASSERT(strlen(json_str) < kBufferSize);
925 ElideJSONSubstring("classes", json_str, buffer);
926 ElideJSONSubstring("libraries", buffer, buffer);
927 EXPECT_STREQ(
928 "{\"type\":\"SourceReport\",\"ranges\":["
929
930 // Foo is hit.
931 "{\"scriptIndex\":0,\"startPos\":14,\"endPos\":26,\"compiled\":true,"
932 "\"coverage\":{\"hits\":[14],\"misses\":[]}},"
933
934 // Unused is missed.
935 "{\"scriptIndex\":0,\"startPos\":62,\"endPos\":87,\"compiled\":true,"
936 "\"coverage\":{\"hits\":[],\"misses\":[62]}},"
937
938 // Main is hit.
939 "{\"scriptIndex\":0,\"startPos\":91,\"endPos\":120,\"compiled\":true,"
940 "\"coverage\":{\"hits\":[91,107,113],\"misses\":[]}}],"
941
942 // Only one script in the script table.
943 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
944 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
945 buffer);
946}
947
948ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Issue47017_Assert) {
949 // WARNING: This MUST be big enough for the serialized JSON string.
950 const int kBufferSize = 1024;
951 char buffer[kBufferSize];
952 const char* kScript =
953 "void foo(Object? bar) {\n"
954 " assert(bar == null);\n"
955 "}\n"
956 "void main() {\n"
957 " foo(null);\n"
958 "}\n";
959
960 Library& lib = Library::Handle();
961 const bool old_asserts = IsolateGroup::Current()->asserts();
963 lib ^= ExecuteScript(kScript);
964 IsolateGroup::Current()->set_asserts(old_asserts);
965 ASSERT(!lib.IsNull());
966 const Script& script =
968
971 report.PrintJSON(&js, script);
972 const char* json_str = js.ToCString();
973 ASSERT(strlen(json_str) < kBufferSize);
974 ElideJSONSubstring("classes", json_str, buffer);
975 ElideJSONSubstring("libraries", buffer, buffer);
976 EXPECT_STREQ(
977 "{\"type\":\"SourceReport\",\"ranges\":["
978
979 // Foo is hit, and the assert is hit.
980 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":47,\"compiled\":true,"
981 "\"coverage\":{\"hits\":[0,33],\"misses\":[]}},"
982
983 // Main is hit.
984 "{\"scriptIndex\":0,\"startPos\":49,\"endPos\":76,\"compiled\":true,"
985 "\"coverage\":{\"hits\":[49,65],\"misses\":[]}}],"
986
987 // Only one script in the script table.
988 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
989 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
990 buffer);
991}
992
993ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Issue47021_StaticOnlyClasses) {
994 // WARNING: This MUST be big enough for the serialized JSON string.
995 const int kBufferSize = 2048;
996 char buffer[kBufferSize];
997 const char* kScript =
998 "abstract class AllStatic {\n"
999 " AllStatic._();\n"
1000 " static int test() => 123;\n"
1001 " static int foo = 456;\n"
1002 "}\n"
1003 "class NotAbstract {\n"
1004 " NotAbstract._();\n"
1005 " static int test() => 123;\n"
1006 " static int foo = 456;\n"
1007 "}\n"
1008 "abstract class NotConstructor {\n"
1009 " void _() {}\n"
1010 " static int test() => 123;\n"
1011 "}\n"
1012 "abstract class NotPrivate {\n"
1013 " NotPrivate();\n"
1014 " static int test() => 123;\n"
1015 "}\n"
1016 "abstract class HasParams {\n"
1017 " HasParams._(int i);\n"
1018 " static int test() => 123;\n"
1019 "}\n"
1020 "abstract class HasFields {\n"
1021 " HasFields._();\n"
1022 " static int test() => 123;\n"
1023 " int foo = 0;\n"
1024 "}\n"
1025 "abstract class HasNonStaticFunction {\n"
1026 " HasNonStaticFunction._();\n"
1027 " static int test() => 123;\n"
1028 " int foo() => 456;\n"
1029 "}\n"
1030 "abstract class HasSubclass {\n"
1031 " HasSubclass._();\n"
1032 " static int test() => 123;\n"
1033 " static int foo = 456;\n"
1034 "}\n"
1035 "abstract class Subclass extends HasSubclass {\n"
1036 " Subclass() : super._();\n"
1037 "}\n"
1038 "void main() {\n"
1039 " AllStatic.test();\n"
1040 " NotAbstract.test();\n"
1041 " NotConstructor.test();\n"
1042 " NotPrivate.test();\n"
1043 " HasParams.test();\n"
1044 " HasFields.test();\n"
1045 " HasNonStaticFunction.test();\n"
1046 " HasSubclass.test();\n"
1047 "}\n";
1048
1049 Library& lib = Library::Handle();
1050 lib ^= ExecuteScript(kScript);
1051 ASSERT(!lib.IsNull());
1052 const Script& script =
1054
1056 JSONStream js;
1057 report.PrintJSON(&js, script);
1058 const char* json_str = js.ToCString();
1059 ASSERT(strlen(json_str) < kBufferSize);
1060 ElideJSONSubstring("classes", json_str, buffer);
1061 ElideJSONSubstring("libraries", buffer, buffer);
1062 EXPECT_STREQ(
1063 "{\"type\":\"SourceReport\",\"ranges\":["
1064
1065 // Subclass() is missed.
1066 "{\"scriptIndex\":0,\"startPos\":775,\"endPos\":797,\"compiled\":true,"
1067 "\"coverage\":{\"hits\":[],\"misses\":[775,794]}},"
1068
1069 // AllStatic.test() is hit. AllStatic._() is ignored (would be pos: 29).
1070 "{\"scriptIndex\":0,\"startPos\":46,\"endPos\":70,\"compiled\":true,"
1071 "\"coverage\":{\"hits\":[46],\"misses\":[]}},"
1072
1073 // HasSubclass._() is missed, not ignored.
1074 "{\"scriptIndex\":0,\"startPos\":656,\"endPos\":671,\"compiled\":true,"
1075 "\"coverage\":{\"hits\":[],\"misses\":[656]}},"
1076
1077 // HasSubclass.test() is hit.
1078 "{\"scriptIndex\":0,\"startPos\":675,\"endPos\":699,\"compiled\":true,"
1079 "\"coverage\":{\"hits\":[675],\"misses\":[]}},"
1080
1081 // HasParams._(int i) is missed, not ignored.
1082 "{\"scriptIndex\":0,\"startPos\":370,\"endPos\":388,\"compiled\":true,"
1083 "\"coverage\":{\"hits\":[],\"misses\":[370]}},"
1084
1085 // HasParams.test() is hit.
1086 "{\"scriptIndex\":0,\"startPos\":392,\"endPos\":416,\"compiled\":true,"
1087 "\"coverage\":{\"hits\":[392],\"misses\":[]}},"
1088
1089 // NotAbstract._() is missed, not ignored.
1090 "{\"scriptIndex\":0,\"startPos\":120,\"endPos\":135,\"compiled\":true,"
1091 "\"coverage\":{\"hits\":[],\"misses\":[120]}},"
1092
1093 // NotAbstract.test() is hit.
1094 "{\"scriptIndex\":0,\"startPos\":139,\"endPos\":163,\"compiled\":true,"
1095 "\"coverage\":{\"hits\":[139],\"misses\":[]}},"
1096
1097 // HasFields._() is missed, not ignored.
1098 "{\"scriptIndex\":0,\"startPos\":449,\"endPos\":462,\"compiled\":true,"
1099 "\"coverage\":{\"hits\":[],\"misses\":[449]}},"
1100
1101 // HasFields.test() is hit.
1102 "{\"scriptIndex\":0,\"startPos\":466,\"endPos\":490,\"compiled\":true,"
1103 "\"coverage\":{\"hits\":[466],\"misses\":[]}},"
1104
1105 // NotPrivate() is missed, not ignored.
1106 "{\"scriptIndex\":0,\"startPos\":297,\"endPos\":309,\"compiled\":true,"
1107 "\"coverage\":{\"hits\":[],\"misses\":[297]}},"
1108
1109 // NotPrivate.test() is hit.
1110 "{\"scriptIndex\":0,\"startPos\":313,\"endPos\":337,\"compiled\":true,"
1111 "\"coverage\":{\"hits\":[313],\"misses\":[]}},"
1112
1113 // HasNonStaticFunction._() is missed, not ignored.
1114 "{\"scriptIndex\":0,\"startPos\":549,\"endPos\":573,\"compiled\":true,"
1115 "\"coverage\":{\"hits\":[],\"misses\":[549]}},"
1116
1117 // HasNonStaticFunction.test() is hit.
1118 "{\"scriptIndex\":0,\"startPos\":577,\"endPos\":601,\"compiled\":true,"
1119 "\"coverage\":{\"hits\":[577],\"misses\":[]}},"
1120
1121 // HasNonStaticFunction.foo() is missed.
1122 "{\"scriptIndex\":0,\"startPos\":605,\"endPos\":621,\"compiled\":true,"
1123 "\"coverage\":{\"hits\":[],\"misses\":[605]}},"
1124
1125 // NotConstructor._() is missed, not ignored.
1126 "{\"scriptIndex\":0,\"startPos\":225,\"endPos\":235,\"compiled\":true,"
1127 "\"coverage\":{\"hits\":[],\"misses\":[225]}},"
1128
1129 // NotConstructor.test() is hit.
1130 "{\"scriptIndex\":0,\"startPos\":239,\"endPos\":263,\"compiled\":true,"
1131 "\"coverage\":{\"hits\":[239],\"misses\":[]}},"
1132
1133 // Main is hit.
1134 "{\"scriptIndex\":0,\"startPos\":801,\"endPos\":996,\"compiled\":true,"
1135 "\"coverage\":{\"hits\":"
1136 "[801,827,849,874,895,915,935,966,988],\"misses\":[]}}],"
1137
1138 // Only one script in the script table.
1139 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1140 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1141 buffer);
1142}
1143
1144ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_IssueCov341_LateFinalVars) {
1145 // https://github.com/dart-lang/coverage/issues/341
1146 // WARNING: This MUST be big enough for the serialized JSON string.
1147 const int kBufferSize = 1024;
1148 char buffer[kBufferSize];
1149 const char* kScript =
1150 "int foo(bool bar) {\n"
1151 " late final int baz;\n"
1152 " if (bar) {\n"
1153 " baz = 123;\n"
1154 " } else {\n"
1155 " baz = 456;\n"
1156 " }\n"
1157 " return baz;\n"
1158 "}\n"
1159 "main() {\n"
1160 " foo(true);\n"
1161 " foo(false);\n"
1162 "}\n";
1163
1164 Library& lib = Library::Handle();
1165 lib ^= ExecuteScript(kScript);
1166 ASSERT(!lib.IsNull());
1167 const Script& script =
1169
1171 JSONStream js;
1172 report.PrintJSON(&js, script);
1173 const char* json_str = js.ToCString();
1174 ASSERT(strlen(json_str) < kBufferSize);
1175 ElideJSONSubstring("classes", json_str, buffer);
1176 ElideJSONSubstring("libraries", buffer, buffer);
1177 EXPECT_STREQ(
1178 "{\"type\":\"SourceReport\",\"ranges\":["
1179
1180 // foo is hit, but the late variable sets and gets are ignored.
1181 "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":114,\"compiled\":true,"
1182 "\"coverage\":{\"hits\":[0],\"misses\":[]}},"
1183
1184 // Main is hit.
1185 "{\"scriptIndex\":0,\"startPos\":116,\"endPos\":152,\"compiled\":true,\""
1186 "coverage\":{\"hits\":[116,127,140],\"misses\":[]}}],"
1187
1188 // Only one script in the script table.
1189 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1190 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1191 buffer);
1192}
1193
1194ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_IssueCov386_EnhancedEnums) {
1195 // https://github.com/dart-lang/coverage/issues/386
1196 // https://github.com/dart-lang/coverage/issues/377
1197 // WARNING: This MUST be big enough for the serialized JSON string.
1198 const int kBufferSize = 1024;
1199 char buffer[kBufferSize];
1200 const char* kScript =
1201 "enum FoodType {\n"
1202 " candy();\n"
1203 " const FoodType();\n"
1204 " factory FoodType.candyFactory() => candy;\n"
1205 "}\n"
1206 "void main() {\n"
1207 " final food = FoodType.candyFactory();\n"
1208 "}\n";
1209
1210 Library& lib = Library::Handle();
1211 lib ^= ExecuteScript(kScript);
1212 ASSERT(!lib.IsNull());
1213 const Script& script =
1215
1217 JSONStream js;
1218 report.PrintJSON(&js, script);
1219 const char* json_str = js.ToCString();
1220 ASSERT(strlen(json_str) < kBufferSize);
1221 ElideJSONSubstring("classes", json_str, buffer);
1222 ElideJSONSubstring("libraries", buffer, buffer);
1223 EXPECT_STREQ(
1224 "{\"type\":\"SourceReport\",\"ranges\":["
1225
1226 // Main is hit.
1227 "{\"scriptIndex\":0,\"startPos\":49,\"endPos\":89,\"compiled\":true,"
1228 "\"coverage\":{\"hits\":[49],\"misses\":[]}},"
1229
1230 // The enum's constructor, and toString, are not included in the hitmap,
1231 // but the factory is included.
1232 "{\"scriptIndex\":0,\"startPos\":93,\"endPos\":147,\"compiled\":true,"
1233 "\"coverage\":{\"hits\":[93,131],\"misses\":[]}}],"
1234
1235 // Only one script in the script table.
1236 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1237 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1238 buffer);
1239}
1240
1241ISOLATE_UNIT_TEST_CASE(SourceReport_Regress95008_RedirectingFactory) {
1242 // WARNING: This MUST be big enough for the serialized JSON string.
1243 const int kBufferSize = 1024;
1244 char buffer[kBufferSize];
1245 const char* kScript = R"(
1246class A {
1247 A();
1248 factory A.foo(int i) = B; // LINE_A
1249}
1250
1251class B extends A {
1252 int i;
1253 B(this.i); // LINE_B
1254}
1255
1256main() {
1257 A.foo(42);
1258}
1259)";
1260
1261 Library& lib = Library::Handle();
1262 lib ^= ExecuteScript(kScript);
1263 ASSERT(!lib.IsNull());
1264 const Script& script =
1266
1268 JSONStream js;
1269 report.PrintJSON(&js, script);
1270 const char* json_str = js.ToCString();
1271 ASSERT(strlen(json_str) < kBufferSize);
1272 ElideJSONSubstring("classes", json_str, buffer);
1273 ElideJSONSubstring("libraries", buffer, buffer);
1274 EXPECT_STREQ(
1275 "{\"type\":\"SourceReport\",\"ranges\":["
1276
1277 // A()
1278 "{\"scriptIndex\":0,\"startPos\":13,\"endPos\":16,\"compiled\":true,"
1279 "\"coverage\":{\"hits\":[13],\"misses\":[]}},"
1280
1281 // B()
1282 "{\"scriptIndex\":0,\"startPos\":90,\"endPos\":99,\"compiled\":true,"
1283 "\"coverage\":{\"hits\":[90],\"misses\":[]}},"
1284
1285 // main
1286 "{\"scriptIndex\":0,\"startPos\":114,\"endPos\":136,\"compiled\":true,"
1287 "\"coverage\":{\"hits\":[114,127],\"misses\":[]}}],"
1288
1289 // Only one script in the script table.
1290 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1291 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1292 buffer);
1293}
1294
1295ISOLATE_UNIT_TEST_CASE(SourceReport_Regress53519_Destructuring) {
1296 // WARNING: This MUST be big enough for the serialized JSON string.
1297 const int kBufferSize = 1024;
1298 char buffer[kBufferSize];
1299 const char* kScript = R"(
1300main() {
1301 destructure({
1302 'hello': 'world',
1303 'count': [1, 2, 3],
1304 });
1305}
1306
1307String destructure(Map<String, dynamic> map) {
1308 final {'hello': world, 'count': count} = map;
1309 return 'Hello $world, count: $count';
1310}
1311)";
1312
1313 Library& lib = Library::Handle();
1314 lib ^= ExecuteScript(kScript);
1315 ASSERT(!lib.IsNull());
1316 const Script& script =
1318
1320 JSONStream js;
1321 report.PrintJSON(&js, script);
1322 const char* json_str = js.ToCString();
1323 ASSERT(strlen(json_str) < kBufferSize);
1324 ElideJSONSubstring("classes", json_str, buffer);
1325 ElideJSONSubstring("libraries", buffer, buffer);
1326 EXPECT_STREQ(
1327 "{\"type\":\"SourceReport\",\"ranges\":["
1328
1329 // main
1330 "{\"scriptIndex\":0,\"startPos\":1,\"endPos\":78,\"compiled\":true,"
1331 "\"coverage\":{\"hits\":[1,12,24,61],\"misses\":[]}},"
1332
1333 // destructure
1334 "{\"scriptIndex\":0,\"startPos\":81,\"endPos\":216,\"compiled\":true,"
1335 "\"coverage\":{\"hits\":[81,144,160,214],\"misses\":[]}}],"
1336
1337 // Only one script in the script table.
1338 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1339 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1340 buffer);
1341}
1342
1343ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_if) {
1344 // WARNING: This MUST be big enough for the serialized JSON string.
1345 const int kBufferSize = 1024;
1346 char buffer[kBufferSize];
1347 const char* kScript = R"(
1348int ifTest(int x) {
1349 if (x > 0) {
1350 if (x > 10) {
1351 return 10;
1352 } else {
1353 return 1;
1354 }
1355 } else {
1356 return 0;
1357 }
1358}
1359
1360main() {
1361 ifTest(1);
1362}
1363)";
1364
1365 Library& lib = Library::Handle();
1366 const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
1368 lib ^= ExecuteScript(kScript);
1369 IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
1370 ASSERT(!lib.IsNull());
1371 const Script& script =
1373
1375 JSONStream js;
1376 report.PrintJSON(&js, script);
1377 const char* json_str = js.ToCString();
1378 ASSERT(strlen(json_str) < kBufferSize);
1379 ElideJSONSubstring("classes", json_str, buffer);
1380 ElideJSONSubstring("libraries", buffer, buffer);
1381 EXPECT_STREQ(
1382 "{\"type\":\"SourceReport\",\"ranges\":["
1383
1384 // In ifTest, the outer true case is hit, the inner true case is missed,
1385 // the inner false case is hit, and the outer false case is missed.
1386 "{\"scriptIndex\":0,\"startPos\":1,\"endPos\":135,\"compiled\":true,"
1387 "\"branchCoverage\":{\"hits\":[1,34,82],\"misses\":[52,115]}},"
1388
1389 // Main is hit.
1390 "{\"scriptIndex\":0,\"startPos\":138,\"endPos\":160,\"compiled\":true,"
1391 "\"branchCoverage\":{\"hits\":[138],\"misses\":[]}}],"
1392
1393 // Only one script in the script table.
1394 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1395 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1396 buffer);
1397}
1398
1399ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_loops) {
1400 // WARNING: This MUST be big enough for the serialized JSON string.
1401 const int kBufferSize = 1024;
1402 char buffer[kBufferSize];
1403 const char* kScript = R"(
1404int loopTest() {
1405 var x = 0;
1406
1407 while (x < 10) {
1408 ++x;
1409 }
1410
1411 do {
1412 ++x;
1413 } while (false);
1414
1415 for (int i = 0; i < 10; ++i) {
1416 ++x;
1417 }
1418
1419 for (final i in [1, 2, 3]) {
1420 ++x;
1421 }
1422
1423 return x;
1424}
1425
1426main() {
1427 loopTest();
1428}
1429)";
1430
1431 Library& lib = Library::Handle();
1432 const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
1434 lib ^= ExecuteScript(kScript);
1435 IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
1436 ASSERT(!lib.IsNull());
1437 const Script& script =
1439
1441 JSONStream js;
1442 report.PrintJSON(&js, script);
1443 const char* json_str = js.ToCString();
1444 ASSERT(strlen(json_str) < kBufferSize);
1445 ElideJSONSubstring("classes", json_str, buffer);
1446 ElideJSONSubstring("libraries", buffer, buffer);
1447 EXPECT_STREQ(
1448 "{\"type\":\"SourceReport\",\"ranges\":["
1449
1450 // In loopTest, the while loop, do-while loop, for loop, and for-in loop
1451 // are all hit.
1452 "{\"scriptIndex\":0,\"startPos\":1,\"endPos\":205,\"compiled\":true,"
1453 "\"branchCoverage\":{\"hits\":[1,49,70,132,177],\"misses\":[]}},"
1454
1455 // Main is hit.
1456 "{\"scriptIndex\":0,\"startPos\":208,\"endPos\":231,\"compiled\":true,"
1457 "\"branchCoverage\":{\"hits\":[208],\"misses\":[]}}],"
1458
1459 // Only one script in the script table.
1460 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1461 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1462 buffer);
1463}
1464
1465ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_switch) {
1466 // WARNING: This MUST be big enough for the serialized JSON string.
1467 const int kBufferSize = 1024;
1468 char buffer[kBufferSize];
1469 const char* kScript = R"(
1470int switchTest(int x) {
1471 switch (x) {
1472 case 0:
1473 return 10;
1474 case 1:
1475 return 20;
1476 default:
1477 return 30;
1478 }
1479}
1480
1481main() {
1482 switchTest(1);
1483}
1484)";
1485
1486 Library& lib = Library::Handle();
1487 const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
1489 lib ^= ExecuteScript(kScript);
1490 IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
1491 ASSERT(!lib.IsNull());
1492 const Script& script =
1494
1496 JSONStream js;
1497 report.PrintJSON(&js, script);
1498 const char* json_str = js.ToCString();
1499 ASSERT(strlen(json_str) < kBufferSize);
1500 ElideJSONSubstring("classes", json_str, buffer);
1501 ElideJSONSubstring("libraries", buffer, buffer);
1502 EXPECT_STREQ(
1503 "{\"type\":\"SourceReport\",\"ranges\":["
1504
1505 // In switchTest, the 1 case is hit and the others are missed.
1506 "{\"scriptIndex\":0,\"startPos\":1,\"endPos\":132,\"compiled\":true,"
1507 "\"branchCoverage\":{\"hits\":[1,73],\"misses\":[44,102]}},"
1508
1509 // Main is hit.
1510 "{\"scriptIndex\":0,\"startPos\":135,\"endPos\":161,\"compiled\":true,"
1511 "\"branchCoverage\":{\"hits\":[135],\"misses\":[]}}],"
1512
1513 // Only one script in the script table.
1514 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1515 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1516 buffer);
1517}
1518
1519ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_try) {
1520 // WARNING: This MUST be big enough for the serialized JSON string.
1521 const int kBufferSize = 1024;
1522 char buffer[kBufferSize];
1523 const char* kScript = R"(
1524void tryTestInner() {
1525 try {
1526 throw "abc";
1527 } catch (e) {
1528 } finally {
1529 }
1530
1531 try {
1532 throw "def";
1533 } finally {
1534 }
1535}
1536
1537void tryTestOuter() {
1538 try {
1539 tryTestInner();
1540 } catch (e) {
1541 }
1542}
1543
1544main() {
1545 tryTestOuter();
1546}
1547)";
1548
1549 Library& lib = Library::Handle();
1550 const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
1552 lib ^= ExecuteScript(kScript);
1553 IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
1554 ASSERT(!lib.IsNull());
1555 const Script& script =
1557
1559 JSONStream js;
1560 report.PrintJSON(&js, script);
1561 const char* json_str = js.ToCString();
1562 ASSERT(strlen(json_str) < kBufferSize);
1563 ElideJSONSubstring("classes", json_str, buffer);
1564 ElideJSONSubstring("libraries", buffer, buffer);
1565 EXPECT_STREQ(
1566 "{\"type\":\"SourceReport\",\"ranges\":["
1567
1568 // In tryTestInner, the try/catch/finally and the try/finally are all hit,
1569 // and the try/finally rethrows its exception.
1570 "{\"scriptIndex\":0,\"startPos\":1,\"endPos\":126,\"compiled\":true,"
1571 "\"branchCoverage\":{\"hits\":[1,29,62,76,89,120],\"misses\":[]}},"
1572
1573 // In tryTestOuter, the exception thrown by tryTestInner causes both the
1574 // try and the catch to be hit.
1575 "{\"scriptIndex\":0,\"startPos\":129,\"endPos\":199,\"compiled\":true,"
1576 "\"branchCoverage\":{\"hits\":[129,157,193],\"misses\":[]}},"
1577
1578 // Main is hit.
1579 "{\"scriptIndex\":0,\"startPos\":202,\"endPos\":229,\"compiled\":true,"
1580 "\"branchCoverage\":{\"hits\":[202],\"misses\":[]}}],"
1581
1582 // Only one script in the script table.
1583 "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
1584 "\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
1585 buffer);
1586}
1587
1588#endif // !PRODUCT
1589
1590} // namespace dart
static const size_t kBufferSize
Definition: SkString.cpp:27
static ObjectPtr UnwrapHandle(Dart_Handle object)
void Insert(typename KeyValueTrait::Pair kv)
Definition: hash_map.h:230
TokenPosition token_pos() const
Definition: object.h:3446
TokenPosition end_token_pos() const
Definition: object.h:3455
void Add(const Object &value, Heap::Space space=Heap::kNew) const
Definition: object.cc:24991
static GrowableObjectArrayPtr New(Heap::Space space=Heap::kNew)
Definition: object.h:11144
static IsolateGroup * Current()
Definition: isolate.h:539
void set_branch_coverage(bool value)
Definition: isolate.h:458
void set_asserts(bool value)
Definition: isolate.h:453
ScriptPtr LookupScript(const String &url, bool useResolvedUri=false) const
Definition: object.cc:14009
FunctionPtr LookupFunctionAllowPrivate(const String &name) const
Definition: object.cc:14084
static ObjectPtr null()
Definition: object.h:433
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
void PrintJSON(JSONStream *js, const Script &script, TokenPosition start_pos=TokenPosition::kMinSource, TokenPosition end_pos=TokenPosition::kMaxSource)
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition: unit_test.cc:436
static Dart_Handle LoadTestScriptWithErrors(const char *script, Dart_NativeEntryResolver resolver=nullptr, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true)
Definition: unit_test.cc:428
static Thread * Current()
Definition: thread.h:362
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
#define ASSERT(E)
GAsyncResult * result
Definition: dart_vm.cc:33
void ElideJSONSubstring(const char *prefix, const char *in, char *out, const char *postfix)
Definition: unit_test.cc:790
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
Dart_Handle NewString(const char *str)
static ObjectPtr ExecuteScript(const char *script, bool allow_errors=false)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
#define RESOLVED_USER_TEST_URI
Definition: unit_test.h:317
#define EXPECT_VALID(handle)
Definition: unit_test.h:643