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

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

Issue 2431223006: Add stacktrace_test (Closed)
Patch Set: Updated cf. comments. Created 4 years, 1 month 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 const int _LF = 0x0A;
80 const int _CR = 0x0D;
81 const int _LBRACE = 0x7B;
82
83
84 Test processTestCode(String code) {
85 StringBuffer codeBuffer = new StringBuffer();
86 Map<int, StackTraceLine> stackTraceMap = <int, StackTraceLine>{};
87 int index = 0;
88 int lineNo = 1;
89 int columnNo = 1;
90 while (index < code.length) {
91 int charCode = code.codeUnitAt(index);
92 switch (charCode) {
93 case _LF:
94 codeBuffer.write('\n');
95 lineNo++;
96 columnNo = 1;
97 break;
98 case _CR:
99 if (index + 1 < code.length && code.codeUnitAt(index + 1) == _LF) {
100 index++;
101 }
102 codeBuffer.write('\n');
103 lineNo++;
104 columnNo = 1;
105 break;
106 case 0x40:
107 if (index + 1 < code.length && code.codeUnitAt(index + 1) == _LBRACE) {
108 int colonIndex = code.indexOf(':', index);
109 int endIndex = code.indexOf('}', index);
110 int stackTraceIndex =
111 int.parse(code.substring(index + 2, colonIndex));
112 String methodName = code.substring(colonIndex + 1, endIndex);
113 assert(!stackTraceMap.containsKey(stackTraceIndex));
114 stackTraceMap[stackTraceIndex] =
115 new StackTraceLine(methodName, INPUT_FILE_NAME, lineNo, columnNo);
116 index = endIndex;
117 } else {
118 codeBuffer.writeCharCode(charCode);
119 columnNo++;
120 }
121 break;
122 default:
123 codeBuffer.writeCharCode(charCode);
124 columnNo++;
125 }
126 index++;
127 }
128 List<StackTraceLine> expectedLines = <StackTraceLine>[];
129 for (int stackTraceIndex in (stackTraceMap.keys.toList()..sort()).reversed) {
130 expectedLines.add(stackTraceMap[stackTraceIndex]);
131 }
132 return new Test(codeBuffer.toString(), expectedLines);
133 }
134
135 void main(List<String> arguments) {
136 asyncTest(() async {
137 for (String code in TESTS) {
138 await runTest(processTestCode(code));
139 }
140 });
141 }
142
143 Future runTest(Test test) async {
144 Directory tmpDir = await createTempDir();
145 String input = '${tmpDir.path}/$INPUT_FILE_NAME';
146 new File(input).writeAsStringSync(test.code);
147 String output = '${tmpDir.path}/out.js';
148 List<String> arguments = [
149 '-o$output',
150 '--library-root=sdk',
151 '--packages=${Platform.packageConfig}',
152 Flags.useNewSourceInfo,
153 input,
154 ];
155 print("--------------------------------------------------------------------");
156 print("Compiling dart2js ${arguments.join(' ')}\n${test.code}");
157 CompilationResult compilationResult = await entry.internalMain(arguments);
158 Expect.isTrue(compilationResult.isSuccess,
159 "Unsuccessful compilation of test:\n${test.code}");
160 CompilerImpl compiler = compilationResult.compiler;
161 SingleMapping sourceMap = new SingleMapping.fromJson(
162 JSON.decode(new File('$output.map').readAsStringSync()));
163
164 print("Running d8 $output");
165 ProcessResult runResult =
166 Process.runSync(d8executable, [output]);
167 String out = '${runResult.stderr}\n${runResult.stdout}';
168 List<String> lines = out.split(new RegExp(r'(\r|\n|\r\n)'));
169 List<StackTraceLine> jsStackTrace = <StackTraceLine>[];
170 bool seenMarker = false;
171 for (String line in lines) {
172 if (seenMarker) {
173 line = line.trim();
174 if (line.startsWith('at ')) {
175 jsStackTrace.add(new StackTraceLine.fromText(line));
176 }
177 } else if (line == EXCEPTION_MARKER) {
178 seenMarker = true;
179 }
180 }
181
182 List<StackTraceLine> dartStackTrace = <StackTraceLine>[];
183 for (StackTraceLine line in jsStackTrace) {
184 TargetEntry targetEntry = _findColumn(line.lineNo - 1, line.columnNo - 1,
185 _findLine(sourceMap, line.lineNo - 1));
186 if (targetEntry == null) {
187 dartStackTrace.add(line);
188 } else {
189 String methodName;
190 if (targetEntry.sourceNameId != 0) {
191 methodName = sourceMap.names[targetEntry.sourceNameId];
192 }
193 String fileName;
194 if (targetEntry.sourceUrlId != 0) {
195 fileName = sourceMap.urls[targetEntry.sourceUrlId];
196 }
197 dartStackTrace.add(new StackTraceLine(methodName, fileName,
198 targetEntry.sourceLine + 1, targetEntry.sourceColumn + 1));
199 }
200 }
201
202 int expectedIndex = 0;
203 for (StackTraceLine line in dartStackTrace) {
204 if (expectedIndex < test.expectedLines.length) {
205 StackTraceLine expectedLine = test.expectedLines[expectedIndex];
206 if (line.methodName == expectedLine.methodName &&
207 line.lineNo == expectedLine.lineNo &&
208 line.columnNo == expectedLine.columnNo) {
209 expectedIndex++;
210 }
211 }
212 }
213 Expect.equals(
214 expectedIndex,
215 test.expectedLines.length,
216 "Missing stack trace lines for test:\n${test.code}\n"
217 "Actual:\n${dartStackTrace.join('\n')}\n"
218 "Expected:\n${test.expectedLines.join('\n')}\n");
219
220 print("Deleting '${tmpDir.path}'.");
221 tmpDir.deleteSync(recursive: true);
222 }
223
224 class StackTraceLine {
225 String methodName;
226 String fileName;
227 int lineNo;
228 int columnNo;
229
230 StackTraceLine(this.methodName, this.fileName, this.lineNo, this.columnNo);
231
232 /// Creates a [StackTraceLine] by parsing a d8 stack trace line [text]. The
233 /// expected formats are
234 ///
235 /// at <methodName>(<fileName>:<lineNo>:<columnNo>)
236 /// at <methodName>(<fileName>:<lineNo>)
237 /// at <methodName>(<fileName>)
238 /// at <fileName>:<lineNo>:<columnNo>
239 /// at <fileName>:<lineNo>
240 /// at <fileName>
241 ///
242 factory StackTraceLine.fromText(String text) {
243 text = text.trim();
244 assert(text.startsWith('at '));
245 text = text.substring('at '.length);
246 String methodName;
247 if (text.endsWith(')')) {
248 int nameEnd = text.indexOf(' (');
249 methodName = text.substring(0, nameEnd);
250 text = text.substring(nameEnd + 2, text.length - 1);
251 }
252 int lineNo;
253 int columnNo;
254 String fileName;
255 int lastColon = text.lastIndexOf(':');
256 if (lastColon != -1) {
257 int lastValue =
258 int.parse(text.substring(lastColon + 1), onError: (_) => null);
259 if (lastValue != null) {
260 int secondToLastColon = text.lastIndexOf(':', lastColon - 1);
261 if (secondToLastColon != -1) {
262 int secondToLastValue = int.parse(
263 text.substring(secondToLastColon + 1, lastColon),
264 onError: (_) => null);
265 if (secondToLastValue != null) {
266 lineNo = secondToLastValue;
267 columnNo = lastValue;
268 fileName = text.substring(0, secondToLastColon);
269 } else {
270 lineNo = lastValue;
271 fileName = text.substring(0, lastColon);
272 }
273 } else {
274 lineNo = lastValue;
275 fileName = text.substring(0, lastColon);
276 }
277 } else {
278 fileName = text;
279 }
280 } else {
281 fileName = text;
282 }
283 return new StackTraceLine(methodName, fileName, lineNo, columnNo);
284 }
285
286 String toString() {
287 StringBuffer sb = new StringBuffer();
288 sb.write(' at ');
289 if (methodName != null) {
290 sb.write(methodName);
291 sb.write(' (');
292 sb.write(fileName ?? '?');
293 sb.write(':');
294 sb.write(lineNo);
295 sb.write(':');
296 sb.write(columnNo);
297 sb.write(')');
298 } else {
299 sb.write(fileName ?? '?');
300 sb.write(':');
301 sb.write(lineNo);
302 sb.write(':');
303 sb.write(columnNo);
304 }
305 return sb.toString();
306 }
307 }
308
309 /// Returns [TargetLineEntry] which includes the location in the target [line]
310 /// number. In particular, the resulting entry is the last entry whose line
311 /// number is lower or equal to [line].
312 ///
313 /// Copied from [SingleMapping._findLine].
314 TargetLineEntry _findLine(SingleMapping sourceMap, int line) {
315 int index = binarySearch(sourceMap.lines, (e) => e.line > line);
316 return (index <= 0) ? null : sourceMap.lines[index - 1];
317 }
318
319 /// Returns [TargetEntry] which includes the location denoted by
320 /// [line], [column]. If [lineEntry] corresponds to [line], then this will be
321 /// the last entry whose column is lower or equal than [column]. If
322 /// [lineEntry] corresponds to a line prior to [line], then the result will be
323 /// the very last entry on that line.
324 ///
325 /// Copied from [SingleMapping._findColumn].
326 TargetEntry _findColumn(int line, int column, TargetLineEntry lineEntry) {
327 if (lineEntry == null || lineEntry.entries.length == 0) return null;
328 if (lineEntry.line != line) return lineEntry.entries.last;
329 var entries = lineEntry.entries;
330 int index = binarySearch(entries, (e) => e.column > column);
331 return (index <= 0) ? null : entries[index - 1];
332 }
333
334 /// Returns the path of the d8 executable.
335 String get d8executable {
336 if (Platform.isWindows) {
337 return 'third_party/d8/windows/d8.exe';
338 } else if (Platform.isLinux) {
339 return 'third_party/d8/linux/d8';
340 } else if (Platform.isMacOS) {
341 return 'third_party/d8/macos/d8';
342 }
343 throw new UnsupportedError('Unsupported platform.');
344 }
OLDNEW
« no previous file with comments | « tests/compiler/dart2js/sourcemaps/save.dart ('k') | tests/compiler/dart2js/sourcemaps/trace_graph.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698