OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016, 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 import 'package:source_span/source_span.dart'; |
| 6 import 'package:test/test.dart'; |
| 7 import 'package:vm_service_client/vm_service_client.dart'; |
| 8 |
| 9 import 'utils.dart'; |
| 10 |
| 11 const _mainContent = r""" |
| 12 print("one"); |
| 13 print("two"); |
| 14 |
| 15 if (false) { |
| 16 print("three"); |
| 17 print("four"); |
| 18 } |
| 19 |
| 20 Isolate.current.kill(); |
| 21 """; |
| 22 |
| 23 void main() { |
| 24 VMServiceClient client; |
| 25 VMIsolateRef isolate; |
| 26 |
| 27 tearDown(() { |
| 28 if (client != null) client.close(); |
| 29 }); |
| 30 |
| 31 group('getSourceReport for a script with one range', () { |
| 32 setUp(() async { |
| 33 client = await runAndConnect(main: _mainContent); |
| 34 |
| 35 isolate = (await client.getVM()).isolates.single; |
| 36 |
| 37 await isolate.waitUntilPaused(); |
| 38 }); |
| 39 |
| 40 test("returns a valid source report", () async { |
| 41 var report = await isolate.getSourceReport( |
| 42 includeCoverageReport: false, includePossibleBreakpoints: false); |
| 43 |
| 44 expect(report.ranges, hasLength(greaterThan(1))); |
| 45 |
| 46 var range = report.ranges.singleWhere((range) => |
| 47 range.script.uri.toString().startsWith('data:application/dart')); |
| 48 |
| 49 expect(range.compiled, isTrue); |
| 50 |
| 51 var script = await range.script.load(); |
| 52 |
| 53 var runnableIsolate = await isolate.loadRunnable(); |
| 54 |
| 55 var rootLib = await runnableIsolate.rootLibrary.load(); |
| 56 var mainFunction = await rootLib.functions['main'].load(); |
| 57 |
| 58 var mainLocation = script.sourceSpan(mainFunction.location); |
| 59 |
| 60 var startLocation = script.sourceLocation(range.location.token); |
| 61 expect(startLocation, mainLocation.start); |
| 62 |
| 63 var endLocation = script.sourceLocation(range.location.end); |
| 64 expect(endLocation, mainLocation.end); |
| 65 |
| 66 expect(range.hits, isNull); |
| 67 expect(range.misses, isNull); |
| 68 expect(range.possibleBreakpoints, isNull); |
| 69 }); |
| 70 |
| 71 test("reports accurate coverage information", () async { |
| 72 var report = |
| 73 await isolate.getSourceReport(includePossibleBreakpoints: false); |
| 74 |
| 75 var range = report.ranges.singleWhere((range) => |
| 76 range.script.uri.toString().startsWith('data:application/dart')); |
| 77 expect(range.possibleBreakpoints, isNull); |
| 78 |
| 79 var script = await range.script.load(); |
| 80 |
| 81 var hitLines = |
| 82 range.hits.map((token) => script.sourceLocation(token).line).toSet(); |
| 83 expect(hitLines, [ |
| 84 6, // new ReceivePort(); |
| 85 7, // print("one"); |
| 86 8, // print("two"); |
| 87 15, // Isolate.current.kill(); |
| 88 17 // VM inserts an extra hit on the last line of an async function |
| 89 ]); |
| 90 |
| 91 // The line that are not executed – two within the `if (false)` block |
| 92 var missedLines = |
| 93 range.misses.map((token) => script.sourceLocation(token).line); |
| 94 expect(missedLines, [11, 12]); |
| 95 }); |
| 96 |
| 97 test("reports accurate breakpoint information", () async { |
| 98 var report = await isolate.getSourceReport(includeCoverageReport: false); |
| 99 |
| 100 var range = report.ranges.singleWhere((range) => |
| 101 range.script.uri.toString().startsWith('data:application/dart')); |
| 102 |
| 103 expect(range.hits, isNull); |
| 104 expect(range.misses, isNull); |
| 105 |
| 106 var script = await range.script.load(); |
| 107 expect(range.possibleBreakpoints, isNotEmpty); |
| 108 |
| 109 // represents the unique set of lines that can have breakpoints |
| 110 var breakPointLines = range.possibleBreakpoints |
| 111 .map((token) => script.sourceLocation(token).line) |
| 112 .toSet(); |
| 113 expect(breakPointLines, [ |
| 114 4, // main entry point |
| 115 6, // new ReceivePort(); |
| 116 7, // print("one"); |
| 117 8, // print("two"); |
| 118 11, // print("three"); |
| 119 12, // print("four"); |
| 120 15, // Isolate.current.kill(); |
| 121 17 // VM considers the last line of an async function breakpoint-able |
| 122 ]); |
| 123 }); |
| 124 |
| 125 test("behaves correctly including coverage and breakpoints", () async { |
| 126 var report = await isolate.getSourceReport( |
| 127 includeCoverageReport: true, includePossibleBreakpoints: true); |
| 128 |
| 129 var range = report.ranges.singleWhere((range) => |
| 130 range.script.uri.toString().startsWith('data:application/dart')); |
| 131 |
| 132 expect(range.hits, isNotEmpty); |
| 133 expect(range.misses, isNotEmpty); |
| 134 expect(range.possibleBreakpoints, isNotEmpty); |
| 135 }); |
| 136 }); |
| 137 |
| 138 group('getSourceReport with a multi-range script', () { |
| 139 VMScript script; |
| 140 VMLibrary rootLib; |
| 141 VMSourceLocation mainLocation; |
| 142 FileSpan mainFunctionSpan; |
| 143 VMSourceLocation unusedFieldLocation; |
| 144 |
| 145 setUp(() async { |
| 146 client = await runAndConnect( |
| 147 topLevel: r'''final unusedField = 5; |
| 148 |
| 149 int unusedFunction(a, b) { |
| 150 return a + b; |
| 151 } |
| 152 |
| 153 void unusedFunction2(value) { |
| 154 print(value); |
| 155 }''', |
| 156 main: _mainContent); |
| 157 |
| 158 isolate = (await client.getVM()).isolates.single; |
| 159 |
| 160 await isolate.waitUntilPaused(); |
| 161 |
| 162 var runnableIsolate = await isolate.loadRunnable(); |
| 163 rootLib = await runnableIsolate.rootLibrary.load(); |
| 164 script = await rootLib.scripts.single.load(); |
| 165 |
| 166 var mainFunction = await rootLib.functions['main'].load(); |
| 167 mainLocation = mainFunction.location; |
| 168 mainFunctionSpan = script.sourceSpan(mainLocation); |
| 169 |
| 170 var unusedFieldRef = rootLib.fields['unusedField']; |
| 171 var unusedField = await unusedFieldRef.load(); |
| 172 unusedFieldLocation = unusedField.location; |
| 173 }); |
| 174 |
| 175 test("reports valid data with default arguments", () async { |
| 176 var report = await script.getSourceReport(); |
| 177 |
| 178 expect(report.ranges, hasLength(3)); |
| 179 |
| 180 var firstRange = report.ranges.first; |
| 181 expect(firstRange.compiled, isFalse); |
| 182 expect(firstRange.hits, isNull); |
| 183 expect(firstRange.misses, isNull); |
| 184 expect(firstRange.possibleBreakpoints, isNull); |
| 185 |
| 186 // TODO(kevmoo): it'd be nice if pkg/matcher had isBefore, isAfter |
| 187 // https://github.com/dart-lang/matcher/issues/34 |
| 188 expect(script.sourceSpan(firstRange.location).compareTo(mainFunctionSpan), |
| 189 isNegative); |
| 190 |
| 191 var lastRange = report.ranges.last; |
| 192 expect(lastRange.compiled, isTrue); |
| 193 expect(script.sourceSpan(lastRange.location), equals(mainFunctionSpan)); |
| 194 }); |
| 195 |
| 196 test("reports all ranged compiled with forceCompile: true", () async { |
| 197 var report = await script.getSourceReport(forceCompile: true); |
| 198 |
| 199 expect(report.ranges, hasLength(3)); |
| 200 |
| 201 var firstRange = report.ranges.first; |
| 202 expect(firstRange.compiled, isTrue); |
| 203 |
| 204 var secondRange = report.ranges.last; |
| 205 expect(secondRange.compiled, isTrue); |
| 206 }); |
| 207 |
| 208 test("reports a valid subrange with the location argument", () async { |
| 209 var report = await script.getSourceReport(location: mainLocation); |
| 210 |
| 211 expect(script.sourceSpan(report.ranges.single.location), |
| 212 equals(mainFunctionSpan)); |
| 213 }); |
| 214 |
| 215 test("throws if a zero-length location is used", () async { |
| 216 expect(script.getSourceReport(location: unusedFieldLocation), |
| 217 throwsArgumentError); |
| 218 }); |
| 219 }); |
| 220 } |
OLD | NEW |