Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(634)

Unified Diff: runtime/vm/source_report_test.cc

Issue 1533653003: Add SourceReport, a class for generating Dart source-level reports. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/source_report.cc ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/source_report_test.cc
diff --git a/runtime/vm/source_report_test.cc b/runtime/vm/source_report_test.cc
new file mode 100644
index 0000000000000000000000000000000000000000..075ac36d472354e93440dc0b2abc13d1ba0dfbac
--- /dev/null
+++ b/runtime/vm/source_report_test.cc
@@ -0,0 +1,412 @@
+// 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 {
+
+static RawObject* ExecuteScript(const char* script) {
+ Dart_Handle h_lib = TestCase::LoadTestScript(script, NULL);
+ EXPECT_VALID(h_lib);
+ Library& lib = Library::Handle();
+ lib ^= Api::UnwrapHandle(h_lib);
+ EXPECT(!lib.IsNull());
+ Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+ return Api::UnwrapHandle(h_lib);
+}
+
+
+TEST_CASE(SourceReport_Coverage_NoCalls) {
+ char buffer[1024];
+ 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);
+ ElideJSONSubstring("libraries", js.ToCString(), buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":"
+
+ // One compiled range, no hits or misses.
+ "[{\"scriptIndex\":0,\"startPos\":0,\"endPos\":5,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[],\"misses\":[]}}],"
+
+ // One script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+ buffer);
+}
+
+
+TEST_CASE(SourceReport_Coverage_SimpleCall) {
+ char buffer[1024];
+ 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);
+ ElideJSONSubstring("classes", js.ToCString(), buffer);
+ ElideJSONSubstring("libraries", buffer, buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":["
+
+ // One range compiled with no hits or misses (helper0).
+ "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":4,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[],\"misses\":[]}},"
+
+ // One range not compiled (helper1).
+ "{\"scriptIndex\":0,\"startPos\":6,\"endPos\":10,\"compiled\":false},"
+
+ // One range with a hit and a miss (main).
+ "{\"scriptIndex\":0,\"startPos\":12,\"endPos\":39,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[23],\"misses\":[32]}}],"
+
+ // Only one script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+ buffer);
+}
+
+
+TEST_CASE(SourceReport_Coverage_ForceCompile) {
+ char buffer[1024];
+ 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);
+ ElideJSONSubstring("classes", js.ToCString(), buffer);
+ ElideJSONSubstring("libraries", buffer, buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":["
+
+ // One range compiled with no hits or misses (helper0).
+ "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":4,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[],\"misses\":[]}},"
+
+ // This range is compiled even though it wasn't called (helper1).
+ "{\"scriptIndex\":0,\"startPos\":6,\"endPos\":10,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[],\"misses\":[]}},"
+
+ // One range with a hit and a miss (main).
+ "{\"scriptIndex\":0,\"startPos\":12,\"endPos\":39,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[23],\"misses\":[32]}}],"
+
+ // Only one script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+ buffer);
+}
+
+
+TEST_CASE(SourceReport_Coverage_NestedFunctions) {
+ char buffer[1024];
+ 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);
+ ElideJSONSubstring("classes", js.ToCString(), buffer);
+ ElideJSONSubstring("libraries", buffer, buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":["
+
+ // One range compiled with one hit (helper0).
+ "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":22,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[18],\"misses\":[]}},"
+
+ // One range not compiled (helper1).
+ "{\"scriptIndex\":0,\"startPos\":24,\"endPos\":28,\"compiled\":false},"
+
+ // One range with a hit and a miss (main).
+ "{\"scriptIndex\":0,\"startPos\":30,\"endPos\":57,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[41],\"misses\":[50]}},"
+
+ // Nested range compiled (nestedHelper0).
+ "{\"scriptIndex\":0,\"startPos\":5,\"endPos\":9,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[],\"misses\":[]}},"
+
+ // Nested range not compiled (nestedHelper1).
+ "{\"scriptIndex\":0,\"startPos\":11,\"endPos\":15,\"compiled\":false}],"
+
+ // Only one script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+ buffer);
+}
+
+
+TEST_CASE(SourceReport_Coverage_RestrictedRange) {
+ char buffer[1024];
+ 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.LookupLocalFunction(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());
+ ElideJSONSubstring("classes", js.ToCString(), buffer);
+ ElideJSONSubstring("libraries", buffer, buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":["
+
+ // One range compiled with one hit (helper0).
+ "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":22,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[18],\"misses\":[]}},"
+
+ // Nested range compiled (nestedHelper0).
+ "{\"scriptIndex\":0,\"startPos\":5,\"endPos\":9,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[],\"misses\":[]}},"
+
+ // Nested range not compiled (nestedHelper1).
+ "{\"scriptIndex\":0,\"startPos\":11,\"endPos\":15,\"compiled\":false}],"
+
+ // Only one script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+ buffer);
+}
+
+
+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\":12,\"endPos\":39,\"compiled\":true,"
+ "\"coverage\":{\"hits\":[23],\"misses\":[32]}",
+ 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);
+}
+
+
+TEST_CASE(SourceReport_CallSites_SimpleCall) {
+ char buffer[1024];
+ 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);
+ ElideJSONSubstring("classes", js.ToCString(), buffer);
+ ElideJSONSubstring("libraries", buffer, buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":["
+
+ // One range compiled with no callsites (helper0).
+ "{\"scriptIndex\":0,\"startPos\":0,\"endPos\":4,\"compiled\":true,"
+ "\"callSites\":[]},"
+
+ // One range not compiled (helper1).
+ "{\"scriptIndex\":0,\"startPos\":6,\"endPos\":10,\"compiled\":false},"
+
+ // One range compiled with one callsite (main).
+ "{\"scriptIndex\":0,\"startPos\":12,\"endPos\":22,\"compiled\":true,"
+ "\"callSites\":["
+ "{\"name\":\"helper0\",\"tokenPos\":17,\"cacheEntries\":["
+ "{\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
+ "\"name\":\"helper0\",\"owner\":{\"type\":\"@Library\",\"fixedId\":true,"
+ "\"id\":\"\",\"name\":\"\",\"uri\":\"test-lib\"},"
+ "\"_kind\":\"RegularFunction\",\"static\":true,\"const\":false,"
+ "\"_intrinsic\":false,\"_native\":false},\"count\":1}]}]}],"
+
+ // One script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+ buffer);
+}
+
+TEST_CASE(SourceReport_CallSites_PolymorphicCall) {
+ char buffer[1024];
+ 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.LookupLocalFunction(String::Handle(String::New("helper"))));
+
+ SourceReport report(SourceReport::kCallSites);
+ JSONStream js;
+ report.PrintJSON(&js, script, helper.token_pos(), helper.end_token_pos());
+ ElideJSONSubstring("classes", js.ToCString(), buffer);
+ ElideJSONSubstring("libraries", buffer, buffer);
+ EXPECT_STREQ(
+ "{\"type\":\"SourceReport\",\"ranges\":["
+
+ // One range...
+ "{\"scriptIndex\":0,\"startPos\":24,\"endPos\":37,\"compiled\":true,"
+
+ // With one call site...
+ "\"callSites\":[{\"name\":\"func\",\"tokenPos\":32,\"cacheEntries\":["
+
+ // First receiver: "Common", called twice.
+ "{\"receiver\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
+ "\"name\":\"Common\"},"
+
+ "\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
+ "\"name\":\"func\","
+ "\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
+ "\"name\":\"Common\"},\"_kind\":\"RegularFunction\","
+ "\"static\":false,\"const\":false,\"_intrinsic\":false,"
+ "\"_native\":false},"
+
+ "\"count\":2},"
+
+ // Second receiver: "Uncommon", called once.
+ "{\"receiver\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
+ "\"name\":\"Uncommon\"},"
+
+ "\"target\":{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
+ "\"name\":\"func\","
+ "\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
+ "\"name\":\"Uncommon\"},\"_kind\":\"RegularFunction\","
+ "\"static\":false,\"const\":false,\"_intrinsic\":false,"
+ "\"_native\":false},"
+
+ "\"count\":1}]}]}],"
+
+ // One script in the script table.
+ "\"scripts\":[{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
+ "\"uri\":\"test-lib\",\"_kind\":\"script\"}]}",
+ buffer);
+}
+
+} // namespace dart
« no previous file with comments | « runtime/vm/source_report.cc ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698