50a3bf663b
The way coverage collection was implemented for const constructors was a bit of a hack. After ordinary coverage collection was complete and all ordinary source ranges had been added to the report, SourceReport::CollectConstConstructorCoverageFromScripts would iterate through all the const constructors and add extra ranges to the source report that reported them as being hit. The old ranges were still in the report, reporting the constructors as missed, but the miss was overwritten by the hit when package:coverage turned the source report into a coverage report. That hacky approach didn't work for branch coverage. I've refactored it to gather all those const constructor hits before ordinary coverage gathering, and store the hits in the script table. Then during the ordinary coverage collection flow, when we see one of those const constructors, we mark everything inside the function as hit. This also fixes a related bug that we hadn't noticed before, where calls inside the const constructor were treated as missed. Note: If there are dozens of const constructors in a single script, it might be worth sorting ScriptTableEntry.const_constructor_hits and then binary searching it, but I don't think that's worth doing atm. Bug: https://github.com/dart-lang/tools/issues/513 Fixes: https://github.com/dart-lang/tools/issues/513 Change-Id: Ie66a153fbeaac5b3ecfc9a28a7f8d129ab61114a TEST=source_report_test.cc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/421720 Reviewed-by: Ben Konyi <bkonyi@google.com> Commit-Queue: Liam Appelbe <liama@google.com>
1716 lines
58 KiB
C++
1716 lines
58 KiB
C++
// Copyright (c) 2015, 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 "vm/source_report.h"
|
|
#include "vm/dart_api_impl.h"
|
|
#include "vm/unit_test.h"
|
|
|
|
namespace dart {
|
|
|
|
#ifndef PRODUCT
|
|
|
|
static ObjectPtr ExecuteScript(const char* script, bool allow_errors = false) {
|
|
Dart_Handle lib;
|
|
{
|
|
TransitionVMToNative transition(Thread::Current());
|
|
if (allow_errors) {
|
|
lib = TestCase::LoadTestScriptWithErrors(script, nullptr);
|
|
} else {
|
|
lib = TestCase::LoadTestScript(script, nullptr);
|
|
}
|
|
EXPECT_VALID(lib);
|
|
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
|
|
EXPECT_VALID(result);
|
|
}
|
|
return Api::UnwrapHandle(lib);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_NoCalls) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"main() {\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
SourceReport report(SourceReport::kCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("libraries", json_str, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":"
|
|
|
|
// One compiled range, one hit at function declaration.
|
|
"[{\"scriptIndex\":0,\"startPos\":0,\"endPos\":9,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}}],"
|
|
|
|
// One script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Filters_single) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"main() {\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
|
|
GrowableObjectArray& filters =
|
|
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
|
filters.Add(String::Handle(String::New(RESOLVED_USER_TEST_URI)));
|
|
SourceReport report(SourceReport::kCoverage, filters);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, Script::Handle(Script::null()));
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("libraries", json_str, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":"
|
|
|
|
// One compiled range, one hit at function declaration.
|
|
"[{\"scriptIndex\":0,\"startPos\":0,\"endPos\":9,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}}],"
|
|
|
|
// One script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Filters_empty) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"main() {\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
|
|
GrowableObjectArray& filters =
|
|
GrowableObjectArray::Handle(GrowableObjectArray::New());
|
|
filters.Add(String::Handle(String::New("foo:bar/")));
|
|
SourceReport report(SourceReport::kCoverage, filters);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, Script::Handle(Script::null()));
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("libraries", json_str, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":"
|
|
|
|
// No compiled range.
|
|
"[],"
|
|
|
|
// No script.
|
|
"\"scripts\":[]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_SimpleCall) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" if (true) {\n"
|
|
" helper0();\n"
|
|
" } else {\n"
|
|
" helper1();\n"
|
|
" }\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// One range compiled with one hit at function declaration (helper0).
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}},"
|
|
|
|
// One range not compiled (helper1).
|
|
"{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
|
|
|
|
// One range with two hits and a miss (main).
|
|
"{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[26,53],\"misses\":[79]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_ForceCompile) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" if (true) {\n"
|
|
" helper0();\n"
|
|
" } else {\n"
|
|
" helper1();\n"
|
|
" }\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// One range compiled with one hit at function declaration (helper0).
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}},"
|
|
|
|
// This range is compiled even though it wasn't called (helper1).
|
|
"{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[13]}},"
|
|
|
|
// One range with two hits and a miss (main).
|
|
"{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[26,53],\"misses\":[79]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_NoForceCompile) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"class Unused {\n"
|
|
" helper1() { helper0(); }\n"
|
|
"}\n"
|
|
"main() {\n"
|
|
" helper0();\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// UnusedClass is not compiled.
|
|
"{\"scriptIndex\":0,\"startPos\":13,\"endPos\":55,\"compiled\":false},"
|
|
|
|
// helper0 is compiled.
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}},"
|
|
|
|
// One range with two hits (main).
|
|
"{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_ForceCompile) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"class Unused {\n"
|
|
" helper1() { helper0(); }\n"
|
|
"}\n"
|
|
"main() {\n"
|
|
" helper0();\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// UnusedClass.helper1 is compiled.
|
|
"{\"scriptIndex\":0,\"startPos\":30,\"endPos\":53,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[30,42]}},"
|
|
|
|
// helper0 is compiled.
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}},"
|
|
|
|
// One range with two hits (main).
|
|
"{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_UnusedClass_ForceCompileError) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"class Unused {\n"
|
|
" helper1() { helper0()+ }\n" // syntax error
|
|
"}\n"
|
|
"main() {\n"
|
|
" helper0();\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript, true);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
js.set_id_zone(thread->isolate()->EnsureDefaultServiceIdZone());
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// UnusedClass has a syntax error.
|
|
"{\"scriptIndex\":0,\"startPos\":30,\"endPos\":53,\"compiled\":false,"
|
|
"\"error\":{\"type\":\"@Error\",\"_vmType\":\"LanguageError\","
|
|
"\"kind\":\"LanguageError\",\"id\":\"objects\\/0\\/0\","
|
|
"\"message\":\"'file:\\/\\/\\/test-lib': error: "
|
|
"\\/test-lib:3:26: "
|
|
"Error: This couldn't be parsed.\\n"
|
|
" helper1() { helper0()+ }\\n ^\"}},"
|
|
|
|
// helper0 is compiled.
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}},"
|
|
|
|
// One range with two hits (main).
|
|
"{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_LibrariesAlreadyCompiled) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"class Unused {\n"
|
|
" helper1() { helper0(); }\n"
|
|
"}\n"
|
|
"main() {\n"
|
|
" helper0();\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
Zone* zone = thread->zone();
|
|
ZoneCStringSet* libraries_already_compiled = new (zone) ZoneCStringSet(zone);
|
|
libraries_already_compiled->Insert(RESOLVED_USER_TEST_URI);
|
|
SourceReport report(SourceReport::kCoverage, GrowableObjectArray::Handle(),
|
|
libraries_already_compiled, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// UnusedClass is not compiled.
|
|
"{\"scriptIndex\":0,\"startPos\":13,\"endPos\":55,\"compiled\":false},"
|
|
|
|
// helper0 is compiled.
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}},"
|
|
|
|
// One range with two hits (main).
|
|
"{\"scriptIndex\":0,\"startPos\":57,\"endPos\":79,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[57,68],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_NestedFunctions) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {\n"
|
|
" nestedHelper0() {}\n"
|
|
" nestedHelper1() {}\n"
|
|
" nestedHelper0();\n"
|
|
"}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" if (true) {\n"
|
|
" helper0();\n"
|
|
" } else {\n"
|
|
" helper1();\n"
|
|
" }\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// One range compiled with one hit (helper0).
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":73,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0,56],\"misses\":[]}},"
|
|
|
|
// One range not compiled (helper1).
|
|
"{\"scriptIndex\":0,\"startPos\":75,\"endPos\":86,\"compiled\":false},"
|
|
|
|
// One range with two hits and a miss (main).
|
|
"{\"scriptIndex\":0,\"startPos\":88,\"endPos\":156,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[88,115],\"misses\":[141]}},"
|
|
|
|
// Nested range compiled (nestedHelper0).
|
|
"{\"scriptIndex\":0,\"startPos\":14,\"endPos\":31,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[14],\"misses\":[]}},"
|
|
|
|
// Nested range not compiled (nestedHelper1).
|
|
"{\"scriptIndex\":0,\"startPos\":35,\"endPos\":52,\"compiled\":false}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_RestrictedRange) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {\n"
|
|
" nestedHelper0() {}\n"
|
|
" nestedHelper1() {}\n"
|
|
" nestedHelper0();\n"
|
|
"}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" if (true) {\n"
|
|
" helper0();\n"
|
|
" } else {\n"
|
|
" helper1();\n"
|
|
" }\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
const Function& helper = Function::Handle(
|
|
lib.LookupFunctionAllowPrivate(String::Handle(String::New("helper0"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage);
|
|
JSONStream js;
|
|
// Restrict the report to only helper0 and it's nested functions.
|
|
report.PrintJSON(&js, script, helper.token_pos(), helper.end_token_pos());
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// One range compiled with one hit (helper0).
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":73,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0,56],\"misses\":[]}},"
|
|
|
|
// Nested range compiled (nestedHelper0).
|
|
"{\"scriptIndex\":0,\"startPos\":14,\"endPos\":31,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[14],\"misses\":[]}},"
|
|
|
|
// Nested range not compiled (nestedHelper1).
|
|
"{\"scriptIndex\":0,\"startPos\":35,\"endPos\":52,\"compiled\":false}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_AllFunctions) {
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" if (true) {\n"
|
|
" helper0();\n"
|
|
" } else {\n"
|
|
" helper1();\n"
|
|
" }\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
|
|
SourceReport report(SourceReport::kCoverage);
|
|
JSONStream js;
|
|
|
|
// We generate a report with all functions in the VM.
|
|
Script& null_script = Script::Handle();
|
|
report.PrintJSON(&js, null_script);
|
|
const char* result = js.ToCString();
|
|
|
|
// Sanity check the header.
|
|
EXPECT_SUBSTRING("{\"type\":\"SourceReport\",\"ranges\":[", result);
|
|
|
|
// Make sure that the main function was found.
|
|
EXPECT_SUBSTRING(
|
|
"\"startPos\":26,\"endPos\":94,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[26,53],\"misses\":[79]}",
|
|
result);
|
|
|
|
// More than one script is referenced in the report.
|
|
EXPECT_SUBSTRING("\"scriptIndex\":0", result);
|
|
EXPECT_SUBSTRING("\"scriptIndex\":1", result);
|
|
EXPECT_SUBSTRING("\"scriptIndex\":2", result);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_AllFunctions_ForceCompile) {
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" if (true) {\n"
|
|
" helper0();\n"
|
|
" } else {\n"
|
|
" helper1();\n"
|
|
" }\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
js.set_id_zone(thread->isolate()->EnsureDefaultServiceIdZone());
|
|
|
|
// We generate a report with all functions in the VM.
|
|
Script& null_script = Script::Handle();
|
|
report.PrintJSON(&js, null_script);
|
|
const char* result = js.ToCString();
|
|
|
|
// Sanity check the header.
|
|
EXPECT_SUBSTRING("{\"type\":\"SourceReport\",\"ranges\":[", result);
|
|
|
|
// Make sure that the main function was found.
|
|
EXPECT_SUBSTRING(
|
|
"\"startPos\":26,\"endPos\":94,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[26,53],\"misses\":[79]}",
|
|
result);
|
|
|
|
// More than one script is referenced in the report.
|
|
EXPECT_SUBSTRING("\"scriptIndex\":0", result);
|
|
EXPECT_SUBSTRING("\"scriptIndex\":1", result);
|
|
EXPECT_SUBSTRING("\"scriptIndex\":2", result);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_CallSites_SimpleCall) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 2048;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" helper0();\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCallSites);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// One range compiled with no callsites (helper0).
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"callSites\":[]},"
|
|
|
|
// One range not compiled (helper1).
|
|
"{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
|
|
|
|
// One range compiled with one callsite (main).
|
|
"{\"scriptIndex\":0,\"startPos\":26,\"endPos\":48,\"compiled\":true,"
|
|
"\"callSites\":["
|
|
"{\"name\":\"helper0\",\"tokenPos\":37,\"cacheEntries\":["
|
|
"{\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"helper0\",\"owner\":{\"type\":\"@Library\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"},"
|
|
"\"_kind\":\"RegularFunction\",\"static\":true,\"const\":false,"
|
|
"\"implicit\":false,\"abstract\":false,"
|
|
"\"_intrinsic\":false,\"_native\":false,\"isGetter\":false,"
|
|
"\"isSetter\":false,\"location\":{\"type\":"
|
|
"\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"},"
|
|
"\"tokenPos\":0,\"endTokenPos\":11,\"line\":1,\"column\":1}},\"count\":1}"
|
|
"]}]}],"
|
|
|
|
// One script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_CallSites_PolymorphicCall) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 4096;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"class Common {\n"
|
|
" func() {}\n"
|
|
"}\n"
|
|
"class Uncommon {\n"
|
|
" func() {}\n"
|
|
"}\n"
|
|
"helper(arg) {\n"
|
|
" arg.func();\n"
|
|
"}\n"
|
|
"main() {\n"
|
|
" Common common = new Common();\n"
|
|
" Uncommon uncommon = new Uncommon();\n"
|
|
" helper(common);\n"
|
|
" helper(common);\n"
|
|
" helper(uncommon);\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
const Function& helper = Function::Handle(
|
|
lib.LookupFunctionAllowPrivate(String::Handle(String::New("helper"))));
|
|
|
|
SourceReport report(SourceReport::kCallSites);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script, helper.token_pos(), helper.end_token_pos());
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// One range...
|
|
"{\"scriptIndex\":0,\"startPos\":60,\"endPos\":88,\"compiled\":true,"
|
|
|
|
// With one call site...
|
|
"\"callSites\":[{\"name\":\"dyn:func\",\"tokenPos\":80,\"cacheEntries\":["
|
|
|
|
// First receiver: "Common", called twice.
|
|
"{\"receiver\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"Common\","
|
|
"\"location\":{\"type\":\"SourceLocation\","
|
|
"\"script\":{\"type\":\"@Script\","
|
|
"\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\","
|
|
"\"_kind\":\"kernel\"},\"tokenPos\":0,\"endTokenPos\":27,\"line\":1,"
|
|
"\"column\":1},"
|
|
"\"library\":{\"type\":\"@Library\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"}},"
|
|
|
|
"\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"func\","
|
|
"\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"Common\","
|
|
"\"location\":{\"type\":\"SourceLocation\","
|
|
"\"script\":{\"type\":\"@Script\","
|
|
"\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\","
|
|
"\"_kind\":\"kernel\"},\"tokenPos\":0,\"endTokenPos\":27,\"line\":1,"
|
|
"\"column\":1},"
|
|
"\"library\":{\"type\":\"@Library\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"}"
|
|
"},\"_kind\":\"RegularFunction\","
|
|
"\"static\":false,\"const\":false,\"implicit\":false,\"abstract\":"
|
|
"false,\"_intrinsic\":false,"
|
|
"\"_native\":false,\"isGetter\":false,\"isSetter\":false,"
|
|
"\"location\":{\"type\":\"SourceLocation\","
|
|
"\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\","
|
|
"\"_kind\":\"kernel\"},\"tokenPos\":17,\"endTokenPos\":25,\"line\":2,"
|
|
"\"column\":3}},"
|
|
|
|
"\"count\":2},"
|
|
|
|
// Second receiver: "Uncommon", called once.
|
|
"{\"receiver\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"Uncommon\","
|
|
"\"location\":{\"type\":\"SourceLocation\","
|
|
"\"script\":{\"type\":\"@Script\","
|
|
"\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\","
|
|
"\"_kind\":\"kernel\"},\"tokenPos\":29,\"endTokenPos\":58,\"line\":4,"
|
|
"\"column\":1},"
|
|
"\"library\":{\"type\":\"@Library\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"}},"
|
|
|
|
"\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"func\","
|
|
"\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"Uncommon\","
|
|
"\"location\":{\"type\":\"SourceLocation\","
|
|
"\"script\":{\"type\":\"@Script\","
|
|
"\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\","
|
|
"\"_kind\":\"kernel\"},\"tokenPos\":29,\"endTokenPos\":58,\"line\":4,"
|
|
"\"column\":1},"
|
|
"\"library\":{\"type\":\"@Library\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"}"
|
|
"},\"_kind\":\"RegularFunction\","
|
|
"\"static\":false,\"const\":false,\"implicit\":false,\"abstract\":"
|
|
"false,\"_intrinsic\":false,"
|
|
"\"_native\":false,\"isGetter\":false,\"isSetter\":false,"
|
|
"\"location\":{\"type\":\"SourceLocation\","
|
|
"\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\","
|
|
"\"_kind\":\"kernel\"},\"tokenPos\":48,\"endTokenPos\":56,\"line\":5,"
|
|
"\"column\":3}},"
|
|
|
|
"\"count\":1}]}]}],"
|
|
|
|
// One script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_MultipleReports) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 2048;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" helper0();\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCallSites | SourceReport::kCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// One range compiled with no callsites (helper0).
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"callSites\":[],"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}},"
|
|
|
|
// One range not compiled (helper1).
|
|
"{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
|
|
|
|
// One range compiled with one callsite (main)m
|
|
"{\"scriptIndex\":0,\"startPos\":26,\"endPos\":48,\"compiled\":true,"
|
|
"\"callSites\":[{\"name\":\"helper0\",\"tokenPos\":37,\"cacheEntries\":[{"
|
|
"\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
|
|
"\"name\":\"helper0\",\"owner\":{\"type\":\"@Library\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"name\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\"},\"_"
|
|
"kind\":\"RegularFunction\",\"static\":true,\"const\":false,\"implicit\":"
|
|
"false,\"abstract\":false,\"_"
|
|
"intrinsic\":false,\"_native\":false,\"isGetter\":false,"
|
|
"\"isSetter\":false,\"location\":{\"type\":"
|
|
"\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"},"
|
|
"\"tokenPos\":0,\"endTokenPos\":11,\"line\":1,\"column\":1}},\"count\":1}"
|
|
"]}],\"coverage\":{"
|
|
"\"hits\":[26,37],\"misses\":[]}}],"
|
|
|
|
// One script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_PossibleBreakpoints_Simple) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"helper0() {}\n"
|
|
"helper1() {}\n"
|
|
"main() {\n"
|
|
" if (true) {\n"
|
|
" helper0();\n"
|
|
" } else {\n"
|
|
" helper1();\n"
|
|
" }\n"
|
|
"}";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kPossibleBreakpoints);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// helper0.
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":11,\"compiled\":true,"
|
|
"\"possibleBreakpoints\":[7,11]},"
|
|
|
|
// One range not compiled (helper1).
|
|
"{\"scriptIndex\":0,\"startPos\":13,\"endPos\":24,\"compiled\":false},"
|
|
|
|
// main.
|
|
"{\"scriptIndex\":0,\"startPos\":26,\"endPos\":94,\"compiled\":true,"
|
|
"\"possibleBreakpoints\":[30,53,79,94]}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Issue35453_NoSuchMethod) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"class Foo {\n"
|
|
" void bar() {}\n"
|
|
"}\n"
|
|
"class Unused implements Foo {\n"
|
|
" dynamic noSuchMethod(_) {}\n"
|
|
"}\n"
|
|
"void main() {\n"
|
|
" Foo().bar();\n"
|
|
"}\n";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// Foo is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":14,\"endPos\":26,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[14],\"misses\":[]}},"
|
|
|
|
// Unused is missed.
|
|
"{\"scriptIndex\":0,\"startPos\":62,\"endPos\":87,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[62]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":91,\"endPos\":120,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[91,107,113],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Issue47017_Assert) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"void foo(Object? bar) {\n"
|
|
" assert(bar == null);\n"
|
|
"}\n"
|
|
"void main() {\n"
|
|
" foo(null);\n"
|
|
"}\n";
|
|
|
|
Library& lib = Library::Handle();
|
|
const bool old_asserts = IsolateGroup::Current()->asserts();
|
|
IsolateGroup::Current()->set_asserts(true);
|
|
lib ^= ExecuteScript(kScript);
|
|
IsolateGroup::Current()->set_asserts(old_asserts);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// Foo is hit, and the assert is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":47,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0,33],\"misses\":[]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":49,\"endPos\":76,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[49,65],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_Issue47021_StaticOnlyClasses) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 2048;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"abstract class AllStatic {\n"
|
|
" AllStatic._();\n"
|
|
" static int test() => 123;\n"
|
|
" static int foo = 456;\n"
|
|
"}\n"
|
|
"class NotAbstract {\n"
|
|
" NotAbstract._();\n"
|
|
" static int test() => 123;\n"
|
|
" static int foo = 456;\n"
|
|
"}\n"
|
|
"abstract class NotConstructor {\n"
|
|
" void _() {}\n"
|
|
" static int test() => 123;\n"
|
|
"}\n"
|
|
"abstract class NotPrivate {\n"
|
|
" NotPrivate();\n"
|
|
" static int test() => 123;\n"
|
|
"}\n"
|
|
"abstract class HasParams {\n"
|
|
" HasParams._(int i);\n"
|
|
" static int test() => 123;\n"
|
|
"}\n"
|
|
"abstract class HasFields {\n"
|
|
" HasFields._();\n"
|
|
" static int test() => 123;\n"
|
|
" int foo = 0;\n"
|
|
"}\n"
|
|
"abstract class HasNonStaticFunction {\n"
|
|
" HasNonStaticFunction._();\n"
|
|
" static int test() => 123;\n"
|
|
" int foo() => 456;\n"
|
|
"}\n"
|
|
"abstract class HasSubclass {\n"
|
|
" HasSubclass._();\n"
|
|
" static int test() => 123;\n"
|
|
" static int foo = 456;\n"
|
|
"}\n"
|
|
"abstract class Subclass extends HasSubclass {\n"
|
|
" Subclass() : super._();\n"
|
|
"}\n"
|
|
"void main() {\n"
|
|
" AllStatic.test();\n"
|
|
" NotAbstract.test();\n"
|
|
" NotConstructor.test();\n"
|
|
" NotPrivate.test();\n"
|
|
" HasParams.test();\n"
|
|
" HasFields.test();\n"
|
|
" HasNonStaticFunction.test();\n"
|
|
" HasSubclass.test();\n"
|
|
"}\n";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// Subclass() is missed.
|
|
"{\"scriptIndex\":0,\"startPos\":775,\"endPos\":797,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[775,794]}},"
|
|
|
|
// AllStatic.test() is hit. AllStatic._() is ignored (would be pos: 29).
|
|
"{\"scriptIndex\":0,\"startPos\":46,\"endPos\":70,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[46],\"misses\":[]}},"
|
|
|
|
// HasSubclass._() is missed, not ignored.
|
|
"{\"scriptIndex\":0,\"startPos\":656,\"endPos\":671,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[656]}},"
|
|
|
|
// HasSubclass.test() is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":675,\"endPos\":699,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[675],\"misses\":[]}},"
|
|
|
|
// HasParams._(int i) is missed, not ignored.
|
|
"{\"scriptIndex\":0,\"startPos\":370,\"endPos\":388,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[370]}},"
|
|
|
|
// HasParams.test() is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":392,\"endPos\":416,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[392],\"misses\":[]}},"
|
|
|
|
// NotAbstract._() is missed, not ignored.
|
|
"{\"scriptIndex\":0,\"startPos\":120,\"endPos\":135,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[120]}},"
|
|
|
|
// NotAbstract.test() is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":139,\"endPos\":163,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[139],\"misses\":[]}},"
|
|
|
|
// HasFields._() is missed, not ignored.
|
|
"{\"scriptIndex\":0,\"startPos\":449,\"endPos\":462,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[449]}},"
|
|
|
|
// HasFields.test() is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":466,\"endPos\":490,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[466],\"misses\":[]}},"
|
|
|
|
// NotPrivate() is missed, not ignored.
|
|
"{\"scriptIndex\":0,\"startPos\":297,\"endPos\":309,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[297]}},"
|
|
|
|
// NotPrivate.test() is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":313,\"endPos\":337,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[313],\"misses\":[]}},"
|
|
|
|
// HasNonStaticFunction._() is missed, not ignored.
|
|
"{\"scriptIndex\":0,\"startPos\":549,\"endPos\":573,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[549]}},"
|
|
|
|
// HasNonStaticFunction.test() is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":577,\"endPos\":601,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[577],\"misses\":[]}},"
|
|
|
|
// HasNonStaticFunction.foo() is missed.
|
|
"{\"scriptIndex\":0,\"startPos\":605,\"endPos\":621,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[605]}},"
|
|
|
|
// NotConstructor._() is missed, not ignored.
|
|
"{\"scriptIndex\":0,\"startPos\":225,\"endPos\":235,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[],\"misses\":[225]}},"
|
|
|
|
// NotConstructor.test() is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":239,\"endPos\":263,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[239],\"misses\":[]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":801,\"endPos\":996,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":"
|
|
"[801,827,849,874,895,915,935,966,988],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_IssueCov341_LateFinalVars) {
|
|
// https://github.com/dart-lang/coverage/issues/341
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"int foo(bool bar) {\n"
|
|
" late final int baz;\n"
|
|
" if (bar) {\n"
|
|
" baz = 123;\n"
|
|
" } else {\n"
|
|
" baz = 456;\n"
|
|
" }\n"
|
|
" return baz;\n"
|
|
"}\n"
|
|
"main() {\n"
|
|
" foo(true);\n"
|
|
" foo(false);\n"
|
|
"}\n";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// foo is hit, but the late variable sets and gets are ignored.
|
|
"{\"scriptIndex\":0,\"startPos\":0,\"endPos\":114,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[0],\"misses\":[]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":116,\"endPos\":152,\"compiled\":true,\""
|
|
"coverage\":{\"hits\":[116,127,140],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_IssueCov386_EnhancedEnums) {
|
|
// https://github.com/dart-lang/coverage/issues/386
|
|
// https://github.com/dart-lang/coverage/issues/377
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript =
|
|
"enum FoodType {\n"
|
|
" candy();\n"
|
|
" const FoodType();\n"
|
|
" factory FoodType.candyFactory() => candy;\n"
|
|
"}\n"
|
|
"void main() {\n"
|
|
" final food = FoodType.candyFactory();\n"
|
|
"}\n";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":49,\"endPos\":89,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[49],\"misses\":[]}},"
|
|
|
|
// The enum's constructor, and toString, are not included in the hitmap,
|
|
// but the factory is included.
|
|
"{\"scriptIndex\":0,\"startPos\":93,\"endPos\":147,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[93,131],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Regress95008_RedirectingFactory) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript = R"(
|
|
class A {
|
|
A();
|
|
factory A.foo(int i) = B; // LINE_A
|
|
}
|
|
|
|
class B extends A {
|
|
int i;
|
|
B(this.i); // LINE_B
|
|
}
|
|
|
|
main() {
|
|
A.foo(42);
|
|
}
|
|
)";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// A()
|
|
"{\"scriptIndex\":0,\"startPos\":13,\"endPos\":16,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[13],\"misses\":[]}},"
|
|
|
|
// B()
|
|
"{\"scriptIndex\":0,\"startPos\":90,\"endPos\":99,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[90],\"misses\":[]}},"
|
|
|
|
// main
|
|
"{\"scriptIndex\":0,\"startPos\":114,\"endPos\":136,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[114,127],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Regress53519_Destructuring) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript = R"(
|
|
main() {
|
|
destructure({
|
|
'hello': 'world',
|
|
'count': [1, 2, 3],
|
|
});
|
|
}
|
|
|
|
String destructure(Map<String, dynamic> map) {
|
|
final {'hello': world, 'count': count} = map;
|
|
return 'Hello $world, count: $count';
|
|
}
|
|
)";
|
|
|
|
Library& lib = Library::Handle();
|
|
lib ^= ExecuteScript(kScript);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// main
|
|
"{\"scriptIndex\":0,\"startPos\":1,\"endPos\":78,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[1,12,24,61],\"misses\":[]}},"
|
|
|
|
// destructure
|
|
"{\"scriptIndex\":0,\"startPos\":81,\"endPos\":216,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[81,144,160,214],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_if) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript = R"(
|
|
int ifTest(int x) {
|
|
if (x > 0) {
|
|
if (x > 10) {
|
|
return 10;
|
|
} else {
|
|
return 1;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
main() {
|
|
ifTest(1);
|
|
}
|
|
)";
|
|
|
|
Library& lib = Library::Handle();
|
|
const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
|
|
IsolateGroup::Current()->set_branch_coverage(true);
|
|
lib ^= ExecuteScript(kScript);
|
|
IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kBranchCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// In ifTest, the outer true case is hit, the inner true case is missed,
|
|
// the inner false case is hit, and the outer false case is missed.
|
|
"{\"scriptIndex\":0,\"startPos\":1,\"endPos\":135,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[1,34,82],\"misses\":[52,115]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":138,\"endPos\":160,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[138],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_loops) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript = R"(
|
|
int loopTest() {
|
|
var x = 0;
|
|
|
|
while (x < 10) {
|
|
++x;
|
|
}
|
|
|
|
do {
|
|
++x;
|
|
} while (false);
|
|
|
|
for (int i = 0; i < 10; ++i) {
|
|
++x;
|
|
}
|
|
|
|
for (final i in [1, 2, 3]) {
|
|
++x;
|
|
}
|
|
|
|
return x;
|
|
}
|
|
|
|
main() {
|
|
loopTest();
|
|
}
|
|
)";
|
|
|
|
Library& lib = Library::Handle();
|
|
const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
|
|
IsolateGroup::Current()->set_branch_coverage(true);
|
|
lib ^= ExecuteScript(kScript);
|
|
IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kBranchCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// In loopTest, the while loop, do-while loop, for loop, and for-in loop
|
|
// are all hit.
|
|
"{\"scriptIndex\":0,\"startPos\":1,\"endPos\":205,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[1,49,70,132,177],\"misses\":[]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":208,\"endPos\":231,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[208],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_switch) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript = R"(
|
|
int switchTest(int x) {
|
|
switch (x) {
|
|
case 0:
|
|
return 10;
|
|
case 1:
|
|
return 20;
|
|
default:
|
|
return 30;
|
|
}
|
|
}
|
|
|
|
main() {
|
|
switchTest(1);
|
|
}
|
|
)";
|
|
|
|
Library& lib = Library::Handle();
|
|
const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
|
|
IsolateGroup::Current()->set_branch_coverage(true);
|
|
lib ^= ExecuteScript(kScript);
|
|
IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kBranchCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// In switchTest, the 1 case is hit and the others are missed.
|
|
"{\"scriptIndex\":0,\"startPos\":1,\"endPos\":132,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[1,73],\"misses\":[44,102]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":135,\"endPos\":161,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[135],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_try) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript = R"(
|
|
void tryTestInner() {
|
|
try {
|
|
throw "abc";
|
|
} catch (e) {
|
|
} finally {
|
|
}
|
|
|
|
try {
|
|
throw "def";
|
|
} finally {
|
|
}
|
|
}
|
|
|
|
void tryTestOuter() {
|
|
try {
|
|
tryTestInner();
|
|
} catch (e) {
|
|
}
|
|
}
|
|
|
|
main() {
|
|
tryTestOuter();
|
|
}
|
|
)";
|
|
|
|
Library& lib = Library::Handle();
|
|
const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
|
|
IsolateGroup::Current()->set_branch_coverage(true);
|
|
lib ^= ExecuteScript(kScript);
|
|
IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kBranchCoverage);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// In tryTestInner, the try/catch/finally and the try/finally are all hit,
|
|
// and the try/finally rethrows its exception.
|
|
"{\"scriptIndex\":0,\"startPos\":1,\"endPos\":126,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[1,29,62,76,89,120],\"misses\":[]}},"
|
|
|
|
// In tryTestOuter, the exception thrown by tryTestInner causes both the
|
|
// try and the catch to be hit.
|
|
"{\"scriptIndex\":0,\"startPos\":129,\"endPos\":199,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[129,157,193],\"misses\":[]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":202,\"endPos\":229,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[202],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
|
|
"\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_Coverage_constConstructor) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript = R"(
|
|
abstract class SuperClass {
|
|
const SuperClass();
|
|
}
|
|
|
|
class Class extends SuperClass {
|
|
const Class() :
|
|
super();
|
|
int method() => 123;
|
|
}
|
|
|
|
main() {
|
|
const Class().method();
|
|
}
|
|
)";
|
|
|
|
Library& lib = Library::Handle();
|
|
const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
|
|
IsolateGroup::Current()->set_branch_coverage(true);
|
|
lib ^= ExecuteScript(kScript);
|
|
IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kCoverage, SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// The super class constructor is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":31,\"endPos\":49,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[31],\"misses\":[]}},"
|
|
|
|
// The class constructor is hit, as well as the super() call.
|
|
"{\"scriptIndex\":0,\"startPos\":89,\"endPos\":118,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[89,111],\"misses\":[]}},"
|
|
|
|
// The method is called.
|
|
"{\"scriptIndex\":0,\"startPos\":122,\"endPos\":141,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[122],\"misses\":[]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":146,\"endPos\":181,\"compiled\":true,"
|
|
"\"coverage\":{\"hits\":[146,171],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,"
|
|
"\"id\":\"\",\"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
ISOLATE_UNIT_TEST_CASE(SourceReport_BranchCoverage_constConstructor) {
|
|
// WARNING: This MUST be big enough for the serialized JSON string.
|
|
const int kBufferSize = 1024;
|
|
char buffer[kBufferSize];
|
|
const char* kScript = R"(
|
|
abstract class SuperClass {
|
|
const SuperClass();
|
|
}
|
|
|
|
class Class extends SuperClass {
|
|
const Class() :
|
|
super();
|
|
int method() => 123;
|
|
}
|
|
|
|
main() {
|
|
const Class().method();
|
|
}
|
|
)";
|
|
|
|
Library& lib = Library::Handle();
|
|
const bool old_branch_coverage = IsolateGroup::Current()->branch_coverage();
|
|
IsolateGroup::Current()->set_branch_coverage(true);
|
|
lib ^= ExecuteScript(kScript);
|
|
IsolateGroup::Current()->set_branch_coverage(old_branch_coverage);
|
|
ASSERT(!lib.IsNull());
|
|
const Script& script =
|
|
Script::Handle(lib.LookupScript(String::Handle(String::New("test-lib"))));
|
|
|
|
SourceReport report(SourceReport::kBranchCoverage,
|
|
SourceReport::kForceCompile);
|
|
JSONStream js;
|
|
report.PrintJSON(&js, script);
|
|
const char* json_str = js.ToCString();
|
|
ASSERT(strlen(json_str) < kBufferSize);
|
|
ElideJSONSubstring("classes", json_str, buffer);
|
|
ElideJSONSubstring("libraries", buffer, buffer);
|
|
EXPECT_STREQ(
|
|
"{\"type\":\"SourceReport\",\"ranges\":["
|
|
|
|
// The super class constructor is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":31,\"endPos\":49,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[31],\"misses\":[]}},"
|
|
|
|
// The class constructor is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":89,\"endPos\":118,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[89],\"misses\":[]}},"
|
|
|
|
// The method is called.
|
|
"{\"scriptIndex\":0,\"startPos\":122,\"endPos\":141,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[122],\"misses\":[]}},"
|
|
|
|
// Main is hit.
|
|
"{\"scriptIndex\":0,\"startPos\":146,\"endPos\":181,\"compiled\":true,"
|
|
"\"branchCoverage\":{\"hits\":[146],\"misses\":[]}}],"
|
|
|
|
// Only one script in the script table.
|
|
"\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\""
|
|
"uri\":\"file:\\/\\/\\/test-lib\",\"_kind\":\"kernel\"}]}",
|
|
buffer);
|
|
}
|
|
|
|
#endif // !PRODUCT
|
|
|
|
} // namespace dart
|