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

Side by Side Diff: tests/compiler/dart2js/sourcemaps/stacktrace_test.dart

Issue 2431223006: Add stacktrace_test (Closed)
Patch Set: Support d8 access on linux/macos Created 4 years, 2 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 unified diff | Download patch
OLDNEW
(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 'dart:async';
6 import 'dart:convert';
7 import 'dart:io';
8
9 import 'package:async_helper/async_helper.dart';
10 import 'package:compiler/compiler_new.dart';
11 import 'package:compiler/src/apiimpl.dart';
12 import 'package:compiler/src/commandline_options.dart';
13 import 'package:compiler/src/dart2js.dart' as entry;
14 import 'package:expect/expect.dart';
15 import 'package:source_maps/source_maps.dart';
16 import 'package:source_maps/src/utils.dart';
17
18 import '../source_map_validator_helper.dart';
19
20 const String EXCEPTION_MARKER = '>ExceptionMarker<';
21 const String INPUT_FILE_NAME = 'in.dart';
22
23 const List<String> TESTS = const <String>[
24 '''
25 main() {
26 @{1:main}throw '$EXCEPTION_MARKER';
27 }
28 ''',
29 '''
30 main() {
31 @{1:main}test();
32 }
33 test() {
34 @{2:test}throw '$EXCEPTION_MARKER';
35 }
36 ''',
37 '''
38 main() {
39 @{1:main}Class.test();
40 }
41 class Class {
42 static test() {
43 @{2:Class.test}throw '$EXCEPTION_MARKER';
44 }
45 }
46 ''',
47 '''
48 main() {
49 var c = new Class();
50 c.@{1:main}test();
51 }
52 class Class {
53 test() {
54 @{2:Class.test}throw '$EXCEPTION_MARKER';
55 }
56 }
57 ''',
58 '''
59 import 'package:expect/expect.dart';
60 main() {
61 var c = @{1:main}new Class();
62 }
63 class Class {
64 @NoInline()
65 Class() {
66 @{2:Class}throw '$EXCEPTION_MARKER';
67 }
68 }
69 ''',
70 ];
71
72 class Test {
73 final String code;
74 final List<StackTraceLine> expectedLines;
75
76 Test(this.code, this.expectedLines);
77 }
78
79 Test processTestCode(String code) {
80 StringBuffer codeBuffer = new StringBuffer();
81 Map<int, StackTraceLine> stackTraceMap = <int, StackTraceLine>{};
82 int index = 0;
83 int lineNo = 1;
84 int columnNo = 1;
85 while (index < code.length) {
Siggi Cherem (dart-lang) 2016/10/27 13:25:19 the code here to compute start-lines seems very si
Johnni Winther 2016/11/02 14:34:30 This is not just for extracting the values but to
86 int charCode = code.codeUnitAt(index);
87 switch (charCode) {
88 case 0x0A:
Siggi Cherem (dart-lang) 2016/10/27 13:25:19 can you define a couple const variables to give th
Johnni Winther 2016/11/02 14:34:30 Done.
89 codeBuffer.write('\n');
90 lineNo++;
91 columnNo = 1;
92 break;
93 case 0x0D:
94 if (index + 1 < code.length && code.codeUnitAt(index + 1) == 0x0A) {
95 index++;
96 }
97 codeBuffer.write('\n');
98 lineNo++;
99 columnNo = 1;
100 break;
101 case 0x40:
102 if (index + 1 < code.length && code.codeUnitAt(index + 1) == 0x7B) {
103 int colonIndex = code.indexOf(':', index);
104 int endIndex = code.indexOf('}', index);
105 int stackTraceIndex =
106 int.parse(code.substring(index + 2, colonIndex));
107 String methodName = code.substring(colonIndex + 1, endIndex);
108 assert(!stackTraceMap.containsKey(stackTraceIndex));
109 stackTraceMap[stackTraceIndex] =
110 new StackTraceLine(methodName, INPUT_FILE_NAME, lineNo, columnNo);
111 index = endIndex;
112 } else {
113 codeBuffer.writeCharCode(charCode);
114 columnNo++;
115 }
116 break;
117 default:
118 codeBuffer.writeCharCode(charCode);
119 columnNo++;
120 }
121 index++;
122 }
123 List<StackTraceLine> expectedLines = <StackTraceLine>[];
124 for (int stackTraceIndex in (stackTraceMap.keys.toList()..sort()).reversed) {
125 expectedLines.add(stackTraceMap[stackTraceIndex]);
126 }
127 return new Test(codeBuffer.toString(), expectedLines);
128 }
129
130 void main(List<String> arguments) {
131 asyncTest(() async {
132 for (String code in TESTS) {
133 await runTest(processTestCode(code));
134 }
135 });
136 }
137
138 Future runTest(Test test) async {
139 Directory tmpDir = await createTempDir();
140 String input = '${tmpDir.path}/$INPUT_FILE_NAME';
141 new File(input).writeAsStringSync(test.code);
142 String output = '${tmpDir.path}/out.js';
143 List<String> arguments = [
144 '-o$output',
145 '--library-root=sdk',
146 '--packages=${Platform.packageConfig}',
147 Flags.useNewSourceInfo,
148 input,
149 ];
150 print("--------------------------------------------------------------------");
151 print("Compiling dart2js ${arguments.join(' ')}\n${test.code}");
152 CompilationResult compilationResult = await entry.internalMain(arguments);
153 Expect.isTrue(compilationResult.isSuccess,
154 "Unsuccessful compilation of test:\n${test.code}");
155 CompilerImpl compiler = compilationResult.compiler;
156 SingleMapping sourceMap = new SingleMapping.fromJson(
157 JSON.decode(new File('$output.map').readAsStringSync()));
158
159 print("Running d8 $output");
160 ProcessResult runResult =
161 Process.runSync(d8executable, [output]);
Siggi Cherem (dart-lang) 2016/10/27 13:25:19 when running test.py, are we guaranteed that the c
Johnni Winther 2016/11/02 14:34:30 We are always running from the root (other unittes
162 String out = '${runResult.stderr}\n${runResult.stdout}';
163 List<String> lines = out.split(new RegExp(r'(\r|\n|\r\n)'));
164 List<StackTraceLine> jsStackTrace = <StackTraceLine>[];
165 bool seenMarker = false;
166 for (String line in lines) {
167 if (seenMarker) {
168 line = line.trim();
169 if (line.startsWith('at ')) {
170 jsStackTrace.add(new StackTraceLine.fromText(line));
171 }
172 } else if (line == EXCEPTION_MARKER) {
173 seenMarker = true;
174 }
175 }
176
177 List<StackTraceLine> dartStackTrace = <StackTraceLine>[];
178 for (StackTraceLine line in jsStackTrace) {
179 TargetEntry targetEntry = _findColumn(line.lineNo - 1, line.columnNo - 1,
180 _findLine(sourceMap, line.lineNo - 1));
181 if (targetEntry == null) {
182 dartStackTrace.add(line);
183 } else {
184 String methodName;
185 if (targetEntry.sourceNameId != 0) {
186 methodName = sourceMap.names[targetEntry.sourceNameId];
187 }
188 String fileName;
189 if (targetEntry.sourceUrlId != 0) {
190 fileName = sourceMap.urls[targetEntry.sourceUrlId];
191 }
192 dartStackTrace.add(new StackTraceLine(methodName, fileName,
193 targetEntry.sourceLine + 1, targetEntry.sourceColumn + 1));
194 }
195 }
196
197 int expectedIndex = 0;
198 for (StackTraceLine line in dartStackTrace) {
199 if (expectedIndex < test.expectedLines.length) {
200 StackTraceLine expectedLine = test.expectedLines[expectedIndex];
201 if (line.methodName == expectedLine.methodName &&
202 line.lineNo == expectedLine.lineNo &&
203 line.columnNo == expectedLine.columnNo) {
204 expectedIndex++;
205 }
206 }
207 }
208 Expect.equals(
209 expectedIndex,
210 test.expectedLines.length,
211 "Missing stack trace lines for test:\n${test.code}\n"
212 "Actual:\n${dartStackTrace.join('\n')}\n"
213 "Expected:\n${test.expectedLines.join('\n')}\n");
214
215 print("Deleting '${tmpDir.path}'.");
216 tmpDir.deleteSync(recursive: true);
217 }
218
219 class StackTraceLine {
220 String methodName;
221 String fileName;
222 int lineNo;
223 int columnNo;
224
225 StackTraceLine(this.methodName, this.fileName, this.lineNo, this.columnNo);
226
227 factory StackTraceLine.fromText(String text) {
Siggi Cherem (dart-lang) 2016/10/27 13:25:19 it might help to add a dartdoc with an example sta
Johnni Winther 2016/11/02 14:34:30 Done.
228 text = text.trim();
229 assert(text.startsWith('at '));
230 text = text.substring('at '.length);
231 String methodName;
232 if (text.endsWith(')')) {
233 int nameEnd = text.indexOf(' (');
234 methodName = text.substring(0, nameEnd);
235 text = text.substring(nameEnd + 2, text.length - 1);
236 }
237 int lineNo;
238 int columnNo;
239 String fileName;
240 int lastColon = text.lastIndexOf(':');
Siggi Cherem (dart-lang) 2016/10/27 13:25:19 idea: consider splitting text by ':' first, then t
Johnni Winther 2016/11/02 14:34:30 Doesn't work on Windows - file names may contain :
Siggi Cherem (dart-lang) 2016/11/02 15:25:24 I see, for this specific case, is it because the d
Johnni Winther 2016/11/03 09:20:18 Alas `t.lastIndexOf(':', i1 - 1);` throws if `i1 -
Johnni Winther 2016/11/03 11:21:10 Should have been: That's why we need to go backwar
241 if (lastColon != -1) {
242 int lastValue =
243 int.parse(text.substring(lastColon + 1), onError: (_) => null);
244 if (lastValue != null) {
245 int secondToLastColon = text.lastIndexOf(':', lastColon - 1);
246 if (secondToLastColon != -1) {
247 int secondToLastValue = int.parse(
248 text.substring(secondToLastColon + 1, lastColon),
249 onError: (_) => null);
250 if (secondToLastValue != null) {
251 lineNo = secondToLastValue;
252 columnNo = lastValue;
253 fileName = text.substring(0, secondToLastColon);
254 } else {
255 lineNo = lastValue;
256 fileName = text.substring(0, lastColon);
257 }
258 } else {
259 lineNo = lastValue;
260 fileName = text.substring(0, lastColon);
261 }
262 } else {
263 fileName = text;
264 }
265 } else {
266 fileName = text;
267 }
268 return new StackTraceLine(methodName, fileName, lineNo, columnNo);
269 }
270
271 String toString() {
272 StringBuffer sb = new StringBuffer();
273 sb.write(' at ');
274 if (methodName != null) {
275 sb.write(methodName);
276 sb.write(' (');
277 sb.write(fileName ?? '?');
278 sb.write(':');
279 sb.write(lineNo);
280 sb.write(':');
281 sb.write(columnNo);
282 sb.write(')');
283 } else {
284 sb.write(fileName ?? '?');
285 sb.write(':');
286 sb.write(lineNo);
287 sb.write(':');
288 sb.write(columnNo);
289 }
290 return sb.toString();
291 }
292 }
293
294 /// Returns [TargetLineEntry] which includes the location in the target [line]
295 /// number. In particular, the resulting entry is the last entry whose line
296 /// number is lower or equal to [line].
297 ///
298 /// Copied from [SingleMapping._findLine].
299 TargetLineEntry _findLine(SingleMapping sourceMap, int line) {
300 int index = binarySearch(sourceMap.lines, (e) => e.line > line);
301 return (index <= 0) ? null : sourceMap.lines[index - 1];
302 }
303
304 /// Returns [TargetEntry] which includes the location denoted by
305 /// [line], [column]. If [lineEntry] corresponds to [line], then this will be
306 /// the last entry whose column is lower or equal than [column]. If
307 /// [lineEntry] corresponds to a line prior to [line], then the result will be
308 /// the very last entry on that line.
309 ///
310 /// Copied from [SingleMapping._findColumn].
311 TargetEntry _findColumn(int line, int column, TargetLineEntry lineEntry) {
312 if (lineEntry == null || lineEntry.entries.length == 0) return null;
313 if (lineEntry.line != line) return lineEntry.entries.last;
314 var entries = lineEntry.entries;
315 int index = binarySearch(entries, (e) => e.column > column);
316 return (index <= 0) ? null : entries[index - 1];
317 }
318
319 /// Returns the path of the d8 executable.
320 String get d8executable {
321 if (Platform.isWindows) {
322 return 'third_party/d8/windows/d8.exe';
323 } else if (Platform.isLinux) {
324 return 'third_party/d8/linux/d8';
325 } else if (Platform.isMacOS) {
326 return 'third_party/d8/macos/d8';
327 }
328 throw new UnsupportedError('Unsupported platform.');
329 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698