OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /// Tests code generation. | 5 /// Tests code generation. |
6 /// Runs Dart Dev Compiler on all input in the `codegen` directory and checks | 6 /// Runs Dart Dev Compiler on all input in the `codegen` directory and checks |
7 /// that the output is what we expected. | 7 /// that the output is what we expected. |
8 library dev_compiler.test.codegen_test; | 8 library dev_compiler.test.codegen_test; |
9 | 9 |
10 import 'dart:io'; | 10 import 'dart:io'; |
11 import 'package:cli_util/cli_util.dart' show getSdkDir; | 11 import 'package:analyzer/src/generated/engine.dart' |
12 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine, Logger; | 12 show AnalysisContext, AnalysisEngine, Logger; |
13 import 'package:analyzer/src/generated/java_engine.dart' show CaughtException; | 13 import 'package:analyzer/src/generated/java_engine.dart' show CaughtException; |
14 import 'package:args/args.dart'; | 14 import 'package:args/args.dart'; |
15 import 'package:logging/logging.dart' show Level; | 15 import 'package:logging/logging.dart' show Level; |
16 import 'package:path/path.dart' as path; | 16 import 'package:path/path.dart' as path; |
17 import 'package:test/test.dart'; | 17 import 'package:test/test.dart'; |
18 | 18 |
19 import 'package:dev_compiler/devc.dart'; | 19 import 'package:dev_compiler/devc.dart'; |
| 20 import 'package:dev_compiler/strong_mode.dart'; |
| 21 import 'package:dev_compiler/src/compiler.dart' show defaultRuntimeFiles; |
20 import 'package:dev_compiler/src/options.dart'; | 22 import 'package:dev_compiler/src/options.dart'; |
21 import 'package:dev_compiler/src/dependency_graph.dart' | |
22 show defaultRuntimeFiles; | |
23 import 'package:dev_compiler/src/utils.dart' | |
24 show computeHash, computeHashFromFile; | |
25 import 'package:html/parser.dart' as html; | |
26 | 23 |
27 import 'test_util.dart' show testDirectory; | 24 import 'testing.dart' show realSdkContext, testDirectory; |
28 | 25 |
29 final ArgParser argParser = new ArgParser() | 26 final ArgParser argParser = new ArgParser() |
30 ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null); | 27 ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null); |
31 | 28 |
32 main(arguments) { | 29 main(arguments) { |
33 if (arguments == null) arguments = []; | 30 if (arguments == null) arguments = []; |
34 ArgResults args = argParser.parse(arguments); | 31 ArgResults args = argParser.parse(arguments); |
35 var filePattern = new RegExp(args.rest.length > 0 ? args.rest[0] : '.'); | 32 var filePattern = new RegExp(args.rest.length > 0 ? args.rest[0] : '.'); |
36 var compilerMessages = new StringBuffer(); | 33 var compilerMessages = new StringBuffer(); |
37 var loggerSub; | 34 var loggerSub; |
(...skipping 11 matching lines...) Expand all Loading... |
49 }); | 46 }); |
50 | 47 |
51 var inputDir = path.join(testDirectory, 'codegen'); | 48 var inputDir = path.join(testDirectory, 'codegen'); |
52 var expectDir = path.join(inputDir, 'expect'); | 49 var expectDir = path.join(inputDir, 'expect'); |
53 var paths = new Directory(inputDir) | 50 var paths = new Directory(inputDir) |
54 .listSync() | 51 .listSync() |
55 .where((f) => f is File) | 52 .where((f) => f is File) |
56 .map((f) => f.path) | 53 .map((f) => f.path) |
57 .where((p) => p.endsWith('.dart') && filePattern.hasMatch(p)); | 54 .where((p) => p.endsWith('.dart') && filePattern.hasMatch(p)); |
58 | 55 |
59 compile(String entryPoint, String sdkPath, {bool checkSdk: false, | 56 bool compile(String entryPoint, AnalysisContext context, |
60 bool serverMode: false, bool sourceMaps: false, String subDir}) { | 57 {bool checkSdk: false, bool sourceMaps: false, String subDir}) { |
61 // TODO(jmesserly): add a way to specify flags in the test file, so | 58 // TODO(jmesserly): add a way to specify flags in the test file, so |
62 // they're more self-contained. | 59 // they're more self-contained. |
63 var runtimeDir = path.join(path.dirname(testDirectory), 'lib', 'runtime'); | 60 var runtimeDir = path.join(path.dirname(testDirectory), 'lib', 'runtime'); |
64 var options = new CompilerOptions( | 61 var options = new CompilerOptions( |
65 sourceOptions: new SourceResolverOptions( | |
66 entryPointFile: entryPoint, dartSdkPath: sdkPath), | |
67 codegenOptions: new CodegenOptions( | 62 codegenOptions: new CodegenOptions( |
68 outputDir: subDir == null | 63 outputDir: subDir == null |
69 ? expectDir | 64 ? expectDir |
70 : path.join(expectDir, subDir), | 65 : path.join(expectDir, subDir), |
71 emitSourceMaps: sourceMaps, | 66 emitSourceMaps: sourceMaps, |
72 forceCompile: checkSdk), | 67 forceCompile: checkSdk), |
73 useColors: false, | 68 useColors: false, |
74 checkSdk: checkSdk, | 69 checkSdk: checkSdk, |
75 runtimeDir: runtimeDir, | 70 runtimeDir: runtimeDir, |
76 serverMode: serverMode, | 71 inputs: [entryPoint]); |
77 enableHashing: serverMode); | 72 var reporter = createErrorReporter(context, options); |
78 return new Compiler(options).run(); | 73 return new BatchCompiler(context, options, reporter: reporter).run(); |
79 } | 74 } |
80 var realSdk = getSdkDir(arguments).path; | |
81 | 75 |
82 // Remove old output, and `packages` symlinks which mess up the diff. | 76 // Remove old output, and `packages` symlinks which mess up the diff. |
83 var dir = new Directory(expectDir); | 77 var dir = new Directory(expectDir); |
84 if (dir.existsSync()) dir.deleteSync(recursive: true); | 78 if (dir.existsSync()) dir.deleteSync(recursive: true); |
85 var packagesDirs = new Directory(inputDir) | 79 var packagesDirs = new Directory(inputDir) |
86 .listSync(recursive: true) | 80 .listSync(recursive: true) |
87 .where((d) => d is Directory && path.basename(d.path) == 'packages'); | 81 .where((d) => d is Directory && path.basename(d.path) == 'packages'); |
88 packagesDirs.forEach((d) => d.deleteSync()); | 82 packagesDirs.forEach((d) => d.deleteSync()); |
89 | 83 |
90 for (var filePath in paths) { | 84 for (var filePath in paths) { |
91 var filename = path.basenameWithoutExtension(filePath); | 85 var filename = path.basenameWithoutExtension(filePath); |
92 | 86 |
93 test('devc $filename.dart', () { | 87 test('devc $filename.dart', () { |
94 compilerMessages.writeln('// Messages from compiling $filename.dart'); | 88 compilerMessages.writeln('// Messages from compiling $filename.dart'); |
95 | 89 |
96 // TODO(jmesserly): this was added to get some coverage of source maps | 90 // TODO(jmesserly): this was added to get some coverage of source maps |
97 // We need a more comprehensive strategy to test them. | 91 // We need a more comprehensive strategy to test them. |
98 var sourceMaps = filename == 'map_keys'; | 92 var sourceMaps = filename == 'map_keys'; |
99 var result = compile(filePath, realSdk, sourceMaps: sourceMaps); | 93 var success = compile(filePath, realSdkContext, sourceMaps: sourceMaps); |
100 var success = !result.failure; | |
101 | 94 |
102 // Write compiler messages to disk. | 95 // Write compiler messages to disk. |
103 new File(path.join(expectDir, '$filename.txt')) | 96 new File(path.join(expectDir, '$filename.txt')) |
104 .writeAsStringSync(compilerMessages.toString()); | 97 .writeAsStringSync(compilerMessages.toString()); |
105 | 98 |
106 var outFile = new File(path.join(expectDir, '$filename.js')); | 99 var outFile = new File(path.join(expectDir, '$filename.js')); |
107 expect(outFile.existsSync(), success, | 100 expect(outFile.existsSync(), success, |
108 reason: '${outFile.path} was created iff compilation succeeds'); | 101 reason: '${outFile.path} was created iff compilation succeeds'); |
109 | 102 |
110 // TODO(jmesserly): ideally we'd diff the output here. For now it | 103 // TODO(jmesserly): ideally we'd diff the output here. For now it |
(...skipping 11 matching lines...) Expand all Loading... |
122 var savedLogger; | 115 var savedLogger; |
123 setUp(() { | 116 setUp(() { |
124 savedLogger = AnalysisEngine.instance.logger; | 117 savedLogger = AnalysisEngine.instance.logger; |
125 AnalysisEngine.instance.logger = new PrintLogger(); | 118 AnalysisEngine.instance.logger = new PrintLogger(); |
126 }); | 119 }); |
127 tearDown(() { | 120 tearDown(() { |
128 AnalysisEngine.instance.logger = savedLogger; | 121 AnalysisEngine.instance.logger = savedLogger; |
129 }); | 122 }); |
130 | 123 |
131 test('devc dart:core', () { | 124 test('devc dart:core', () { |
| 125 var testSdkContext = createAnalysisContextWithSources( |
| 126 new StrongModeOptions(), new SourceResolverOptions( |
| 127 dartSdkPath: path.join( |
| 128 testDirectory, '..', 'tool', 'generated_sdk'))); |
| 129 |
132 // Get the test SDK. We use a checked in copy so test expectations can | 130 // Get the test SDK. We use a checked in copy so test expectations can |
133 // be generated against a specific SDK version. | 131 // be generated against a specific SDK version. |
134 var testSdk = path.join(testDirectory, '..', 'tool', 'generated_sdk'); | 132 compile('dart:core', testSdkContext, checkSdk: true); |
135 compile('dart:core', testSdk, checkSdk: true); | |
136 new Directory(path.join(expectDir, 'core')); | |
137 var outFile = new File(path.join(expectDir, 'dart/core.js')); | 133 var outFile = new File(path.join(expectDir, 'dart/core.js')); |
138 expect(outFile.existsSync(), true, | 134 expect(outFile.existsSync(), true, |
139 reason: '${outFile.path} was created for dart:core'); | 135 reason: '${outFile.path} was created for dart:core'); |
140 }); | 136 }); |
141 }); | 137 }); |
142 } | 138 } |
143 | 139 |
144 var expectedRuntime = | 140 var expectedRuntime = |
145 defaultRuntimeFiles.map((f) => 'dev_compiler/runtime/$f'); | 141 defaultRuntimeFiles.map((f) => 'dev_compiler/runtime/$f'); |
146 | 142 |
147 test('devc jscodegen sunflower.html', () { | 143 test('devc jscodegen sunflower.html', () { |
148 var filePath = path.join(inputDir, 'sunflower', 'sunflower.html'); | 144 var filePath = path.join(inputDir, 'sunflower', 'sunflower.html'); |
149 compilerMessages.writeln('// Messages from compiling sunflower.html'); | 145 compilerMessages.writeln('// Messages from compiling sunflower.html'); |
150 | 146 |
151 var result = compile(filePath, realSdk, subDir: 'sunflower'); | 147 var success = compile(filePath, realSdkContext, subDir: 'sunflower'); |
152 var success = !result.failure; | |
153 | 148 |
154 // Write compiler messages to disk. | 149 // Write compiler messages to disk. |
155 new File(path.join(expectDir, 'sunflower', 'sunflower.txt')) | 150 new File(path.join(expectDir, 'sunflower', 'sunflower.txt')) |
156 .writeAsStringSync(compilerMessages.toString()); | 151 .writeAsStringSync(compilerMessages.toString()); |
157 | 152 |
158 var expectedFiles = [ | 153 var expectedFiles = [ |
159 'sunflower.html', | 154 'sunflower.html', |
160 'sunflower.js', | 155 'sunflower.js', |
161 'sunflower.css', | |
162 'math.png', | |
163 ]..addAll(expectedRuntime); | 156 ]..addAll(expectedRuntime); |
164 | 157 |
165 for (var filepath in expectedFiles) { | 158 for (var filepath in expectedFiles) { |
166 var outFile = new File(path.join(expectDir, 'sunflower', filepath)); | 159 var outFile = new File(path.join(expectDir, 'sunflower', filepath)); |
167 expect(outFile.existsSync(), success, | 160 expect(outFile.existsSync(), success, |
168 reason: '${outFile.path} was created iff compilation succeeds'); | 161 reason: '${outFile.path} was created iff compilation succeeds'); |
169 } | 162 } |
170 }); | 163 }); |
171 | 164 |
172 test('devc jscodegen html_input.html', () { | 165 test('devc jscodegen html_input.html', () { |
173 var filePath = path.join(inputDir, 'html_input.html'); | 166 var filePath = path.join(inputDir, 'html_input.html'); |
174 compilerMessages.writeln('// Messages from compiling html_input.html'); | 167 compilerMessages.writeln('// Messages from compiling html_input.html'); |
175 | 168 |
176 var result = compile(filePath, realSdk); | 169 var success = compile(filePath, realSdkContext); |
177 var success = !result.failure; | |
178 | 170 |
179 // Write compiler messages to disk. | 171 // Write compiler messages to disk. |
180 new File(path.join(expectDir, 'html_input.txt')) | 172 new File(path.join(expectDir, 'html_input.txt')) |
181 .writeAsStringSync(compilerMessages.toString()); | 173 .writeAsStringSync(compilerMessages.toString()); |
182 | 174 |
183 var expectedFiles = [ | 175 var expectedFiles = [ |
184 'html_input.html', | 176 'html_input.html', |
185 'dir/html_input_a.js', | 177 'dir/html_input_a.js', |
186 'dir/html_input_b.js', | 178 'dir/html_input_b.js', |
187 'dir/html_input_c.js', | 179 'dir/html_input_c.js', |
188 'dir/html_input_d.js', | 180 'dir/html_input_d.js', |
189 'dir/html_input_e.js' | 181 'dir/html_input_e.js' |
190 ]..addAll(expectedRuntime); | 182 ]..addAll(expectedRuntime); |
191 | 183 |
192 for (var filepath in expectedFiles) { | 184 for (var filepath in expectedFiles) { |
193 var outFile = new File(path.join(expectDir, filepath)); | 185 var outFile = new File(path.join(expectDir, filepath)); |
194 expect(outFile.existsSync(), success, | 186 expect(outFile.existsSync(), success, |
195 reason: '${outFile.path} was created iff compilation succeeds'); | 187 reason: '${outFile.path} was created iff compilation succeeds'); |
196 } | 188 } |
197 | |
198 var notExpectedFiles = [ | |
199 'dev_compiler/runtime/messages_widget.js', | |
200 'dev_compiler/runtime/messages.css' | |
201 ]; | |
202 for (var filepath in notExpectedFiles) { | |
203 var outFile = new File(path.join(expectDir, filepath)); | |
204 expect(outFile.existsSync(), isFalse, | |
205 reason: '${outFile.path} should only be generated in server mode'); | |
206 } | |
207 }); | |
208 | |
209 test('devc jscodegen html_input.html server mode', () { | |
210 var filePath = path.join(inputDir, 'html_input.html'); | |
211 compilerMessages.writeln('// Messages from compiling html_input.html'); | |
212 | |
213 var result = | |
214 compile(filePath, realSdk, serverMode: true, subDir: 'server_mode'); | |
215 var success = !result.failure; | |
216 | |
217 // Write compiler messages to disk. | |
218 new File(path.join(expectDir, 'server_mode', 'html_input.txt')) | |
219 .writeAsStringSync(compilerMessages.toString()); | |
220 | |
221 var expectedFiles = [ | |
222 'dir/html_input_a.js', | |
223 'dir/html_input_b.js', | |
224 'dir/html_input_c.js', | |
225 'dir/html_input_d.js', | |
226 'dir/html_input_e.js', | |
227 'dev_compiler/runtime/messages_widget.js', | |
228 'dev_compiler/runtime/messages.css' | |
229 ]..addAll(expectedRuntime); | |
230 | |
231 // Parse the HTML file and verify its contents were expected. | |
232 var htmlPath = path.join(expectDir, 'server_mode', 'html_input.html'); | |
233 var doc = html.parse(new File(htmlPath).readAsStringSync()); | |
234 | |
235 for (var filepath in expectedFiles) { | |
236 var outPath = path.join(expectDir, 'server_mode', filepath); | |
237 expect(new File(outPath).existsSync(), success, | |
238 reason: '$outPath was created iff compilation succeeds'); | |
239 | |
240 var query; | |
241 if (filepath.endsWith('js')) { | |
242 var hash; | |
243 if (filepath.startsWith('dev_compiler')) { | |
244 hash = computeHashFromFile(outPath); | |
245 } else { | |
246 // TODO(jmesserly): see if we can get this to return the same | |
247 // answer as computeHashFromFile. | |
248 hash = computeHash(new File(outPath).readAsStringSync()); | |
249 } | |
250 query = 'script[src="$filepath?____cached=$hash"]'; | |
251 } else { | |
252 var hash = computeHashFromFile(outPath); | |
253 query = 'link[href="$filepath?____cached=$hash"]'; | |
254 } | |
255 expect(doc.querySelector(query), isNotNull, | |
256 reason: "should find `$query` in $htmlPath for $outPath"); | |
257 } | |
258 | |
259 // Clean up the server mode folder, otherwise it causes diff churn. | |
260 var dir = new Directory(path.join(expectDir, 'server_mode')); | |
261 if (dir.existsSync()) dir.deleteSync(recursive: true); | |
262 }); | 189 }); |
263 } | 190 } |
264 | 191 |
265 /// An implementation of analysis engine's [Logger] that prints. | 192 /// An implementation of analysis engine's [Logger] that prints. |
266 class PrintLogger implements Logger { | 193 class PrintLogger implements Logger { |
267 @override void logError(String message, [CaughtException exception]) { | 194 @override void logError(String message, [CaughtException exception]) { |
268 print('[AnalysisEngine] error $message $exception'); | 195 print('[AnalysisEngine] error $message $exception'); |
269 } | 196 } |
270 | 197 |
271 @override void logError2(String message, Object exception) { | 198 @override void logError2(String message, Object exception) { |
272 print('[AnalysisEngine] error $message $exception'); | 199 print('[AnalysisEngine] error $message $exception'); |
273 } | 200 } |
274 | 201 |
275 void logInformation(String message, [CaughtException exception]) {} | 202 void logInformation(String message, [CaughtException exception]) {} |
276 void logInformation2(String message, Object exception) {} | 203 void logInformation2(String message, Object exception) {} |
277 } | 204 } |
OLD | NEW |