| 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 '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 '../annotated_code_helper.dart'; |
| 19 import '../memory_compiler.dart'; |
| 20 import '../source_map_validator_helper.dart'; |
| 21 |
| 22 const List<String> TESTS = const <String>[ |
| 23 ''' |
| 24 @{main}main() { |
| 25 @{main}} |
| 26 ''', |
| 27 ''' |
| 28 @{main}main() { |
| 29 @{+main}throw ''; |
| 30 @{main}} |
| 31 ''', |
| 32 ''' |
| 33 @{main}main() { |
| 34 @{main}return 0; |
| 35 @{main}} |
| 36 ''', |
| 37 ''' |
| 38 import 'package:expect/expect.dart'; |
| 39 @{main}main() { |
| 40 @{main}test(); |
| 41 @{main}} |
| 42 |
| 43 @NoInline() |
| 44 @{test}test() { |
| 45 @{test}} |
| 46 ''', |
| 47 ]; |
| 48 |
| 49 class Test { |
| 50 final String annotatedCode; |
| 51 final String code; |
| 52 final List<SourceLocation> expectedLocations; |
| 53 |
| 54 Test(this.annotatedCode, this.code, this.expectedLocations); |
| 55 } |
| 56 |
| 57 Test processTestCode(String code, {bool useNewSourceInfo}) { |
| 58 List<SourceLocation> expectedLocations = <SourceLocation>[]; |
| 59 AnnotatedCode annotatedCode = new AnnotatedCode.fromText(code); |
| 60 for (Annotation annotation in annotatedCode.annotations) { |
| 61 String methodName; |
| 62 if (annotation.text.startsWith('-')) { |
| 63 // Expect only in old source maps |
| 64 if (useNewSourceInfo) continue; |
| 65 methodName = annotation.text.substring(1); |
| 66 } else if (annotation.text.startsWith('+')) { |
| 67 // Expect only in new source maps |
| 68 if (!useNewSourceInfo) continue; |
| 69 methodName = annotation.text.substring(1); |
| 70 } else { |
| 71 methodName = annotation.text; |
| 72 } |
| 73 expectedLocations.add( |
| 74 new SourceLocation(methodName, annotation.lineNo, annotation.columnNo)); |
| 75 } |
| 76 return new Test(code, annotatedCode.sourceCode, expectedLocations); |
| 77 } |
| 78 |
| 79 void main(List<String> arguments) { |
| 80 bool verbose = false; |
| 81 bool printJs = false; |
| 82 bool writeJs = false; |
| 83 List<int> indices; |
| 84 for (String arg in arguments) { |
| 85 if (arg == '-v') { |
| 86 verbose = true; |
| 87 } else if (arg == '--print-js') { |
| 88 printJs = true; |
| 89 } else if (arg == '--write-js') { |
| 90 writeJs = true; |
| 91 } else { |
| 92 int index = int.parse(arg, onError: (_) => null); |
| 93 if (index != null) { |
| 94 indices ??= <int>[]; |
| 95 if (index < 0 || index >= TESTS.length * 2) { |
| 96 print('Index $index out of bounds: [0;${TESTS.length - 1}]'); |
| 97 } else { |
| 98 indices.add(index); |
| 99 } |
| 100 } |
| 101 } |
| 102 } |
| 103 if (indices == null) { |
| 104 indices = new List<int>.generate(TESTS.length * 2, (i) => i); |
| 105 } |
| 106 asyncTest(() async { |
| 107 for (int index in indices) { |
| 108 bool useNewSourceInfo = index % 2 == 1; |
| 109 await runTest( |
| 110 index, |
| 111 processTestCode(TESTS[index ~/ 2], |
| 112 useNewSourceInfo: useNewSourceInfo), |
| 113 printJs: printJs, |
| 114 writeJs: writeJs, |
| 115 verbose: verbose, |
| 116 useNewSourceInfo: useNewSourceInfo); |
| 117 } |
| 118 }); |
| 119 } |
| 120 |
| 121 Future runTest(int index, Test test, |
| 122 {bool printJs: false, |
| 123 bool writeJs, |
| 124 bool verbose: false, |
| 125 bool useNewSourceInfo: false}) async { |
| 126 print("--$index------------------------------------------------------------"); |
| 127 print("Compiling dart2js ${useNewSourceInfo ? Flags.useNewSourceInfo : ''}\n" |
| 128 "${test.annotatedCode}"); |
| 129 OutputCollector collector = new OutputCollector(); |
| 130 List<String> options = <String>['--out=out.js', '--source-map=out.js.map']; |
| 131 if (useNewSourceInfo) { |
| 132 options.add(Flags.useNewSourceInfo); |
| 133 } |
| 134 CompilationResult compilationResult = await runCompiler( |
| 135 entryPoint: Uri.parse('memory:main.dart'), |
| 136 memorySourceFiles: {'main.dart': test.code}, |
| 137 outputProvider: collector, |
| 138 options: options); |
| 139 Expect.isTrue(compilationResult.isSuccess, |
| 140 "Unsuccessful compilation of test:\n${test.code}"); |
| 141 String sourceMapText = collector.getOutput('', 'js.map'); |
| 142 SingleMapping sourceMap = parse(sourceMapText); |
| 143 if (writeJs) { |
| 144 new File('out.js').writeAsStringSync(collector.getOutput('', 'js')); |
| 145 new File('out.js.map').writeAsStringSync(sourceMapText); |
| 146 } |
| 147 |
| 148 Set<SourceLocation> expectedLocations = test.expectedLocations.toSet(); |
| 149 List<SourceLocation> actualLocations = <SourceLocation>[]; |
| 150 List<SourceLocation> extraLocations = <SourceLocation>[]; |
| 151 for (TargetLineEntry targetLineEntry in sourceMap.lines) { |
| 152 for (TargetEntry targetEntry in targetLineEntry.entries) { |
| 153 if (targetEntry.sourceUrlId != null && |
| 154 sourceMap.urls[targetEntry.sourceUrlId] == 'memory:main.dart') { |
| 155 String methodName; |
| 156 if (targetEntry.sourceNameId != null) { |
| 157 methodName = sourceMap.names[targetEntry.sourceNameId]; |
| 158 } |
| 159 SourceLocation location = new SourceLocation(methodName, |
| 160 targetEntry.sourceLine + 1, targetEntry.sourceColumn + 1); |
| 161 actualLocations.add(location); |
| 162 if (!expectedLocations.remove(location)) { |
| 163 extraLocations.add(location); |
| 164 } |
| 165 } |
| 166 } |
| 167 } |
| 168 |
| 169 if (expectedLocations.isNotEmpty) { |
| 170 print('--Missing source locations:---------------------------------------'); |
| 171 AnnotatedCode annotatedCode = new AnnotatedCode(test.code, []); |
| 172 expectedLocations.forEach( |
| 173 (l) => annotatedCode.addAnnotation(l.lineNo, l.columnNo, l.methodName)); |
| 174 print(annotatedCode.toText()); |
| 175 print('------------------------------------------------------------------'); |
| 176 Expect.isTrue( |
| 177 expectedLocations.isEmpty, |
| 178 "Missing source locations:\n${test.code}\n" |
| 179 "Actual:\n${actualLocations.join('\n')}\n" |
| 180 "Missing:\n${expectedLocations.join('\n')}\n"); |
| 181 } |
| 182 if (extraLocations.isNotEmpty) { |
| 183 print('--Extra source locations:-----------------------------------------'); |
| 184 AnnotatedCode annotatedCode = new AnnotatedCode(test.code, []); |
| 185 extraLocations.forEach( |
| 186 (l) => annotatedCode.addAnnotation(l.lineNo, l.columnNo, l.methodName)); |
| 187 print(annotatedCode.toText()); |
| 188 print('------------------------------------------------------------------'); |
| 189 Expect.isTrue( |
| 190 extraLocations.isEmpty, |
| 191 "Extra source locations:\n${test.code}\n" |
| 192 "Actual:\n${actualLocations.join('\n')}\n" |
| 193 "Extra:\n${extraLocations.join('\n')}\n"); |
| 194 } |
| 195 } |
| 196 |
| 197 class SourceLocation { |
| 198 final String methodName; |
| 199 final int lineNo; |
| 200 final int columnNo; |
| 201 |
| 202 SourceLocation(this.methodName, this.lineNo, this.columnNo); |
| 203 |
| 204 int get hashCode => |
| 205 methodName.hashCode * 13 + lineNo.hashCode * 17 + columnNo.hashCode * 19; |
| 206 |
| 207 bool operator ==(other) { |
| 208 if (identical(this, other)) return true; |
| 209 if (other is! SourceLocation) return false; |
| 210 return methodName == other.methodName && |
| 211 lineNo == other.lineNo && |
| 212 columnNo == other.columnNo; |
| 213 } |
| 214 |
| 215 String toString() => '$methodName:$lineNo:$columnNo'; |
| 216 } |
| OLD | NEW |