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'; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
42 }); | 42 }); |
43 | 43 |
44 tearDown(() { | 44 tearDown(() { |
45 if (loggerSub != null) { | 45 if (loggerSub != null) { |
46 loggerSub.cancel(); | 46 loggerSub.cancel(); |
47 loggerSub = null; | 47 loggerSub = null; |
48 } | 48 } |
49 }); | 49 }); |
50 | 50 |
51 var inputDir = path.join(testDirectory, 'codegen'); | 51 var inputDir = path.join(testDirectory, 'codegen'); |
52 var actualDir = path.join(inputDir, 'actual'); | 52 var expectDir = path.join(inputDir, 'expect'); |
53 var paths = new Directory(inputDir) | 53 var paths = new Directory(inputDir) |
54 .listSync() | 54 .listSync() |
55 .where((f) => f is File) | 55 .where((f) => f is File) |
56 .map((f) => f.path) | 56 .map((f) => f.path) |
57 .where((p) => p.endsWith('.dart') && filePattern.hasMatch(p)); | 57 .where((p) => p.endsWith('.dart') && filePattern.hasMatch(p)); |
58 | 58 |
59 compile(String entryPoint, String sdkPath, {bool checkSdk: false, | 59 compile(String entryPoint, String sdkPath, {bool checkSdk: false, |
60 bool serverMode: false, bool sourceMaps: false, String subDir}) { | 60 bool serverMode: false, bool sourceMaps: false, String subDir}) { |
61 // TODO(jmesserly): add a way to specify flags in the test file, so | 61 // TODO(jmesserly): add a way to specify flags in the test file, so |
62 // they're more self-contained. | 62 // they're more self-contained. |
63 var runtimeDir = path.join(path.dirname(testDirectory), 'lib', 'runtime'); | 63 var runtimeDir = path.join(path.dirname(testDirectory), 'lib', 'runtime'); |
64 var options = new CompilerOptions( | 64 var options = new CompilerOptions( |
65 sourceOptions: new SourceResolverOptions( | 65 sourceOptions: new SourceResolverOptions( |
66 entryPointFile: entryPoint, dartSdkPath: sdkPath), | 66 entryPointFile: entryPoint, dartSdkPath: sdkPath), |
67 codegenOptions: new CodegenOptions( | 67 codegenOptions: new CodegenOptions( |
68 outputDir: subDir == null | 68 outputDir: subDir == null |
69 ? actualDir | 69 ? expectDir |
70 : path.join(actualDir, subDir), | 70 : path.join(expectDir, subDir), |
71 emitSourceMaps: sourceMaps, | 71 emitSourceMaps: sourceMaps, |
72 forceCompile: checkSdk), | 72 forceCompile: checkSdk), |
73 useColors: false, | 73 useColors: false, |
74 checkSdk: checkSdk, | 74 checkSdk: checkSdk, |
75 runtimeDir: runtimeDir, | 75 runtimeDir: runtimeDir, |
76 serverMode: serverMode, | 76 serverMode: serverMode, |
77 enableHashing: serverMode); | 77 enableHashing: serverMode); |
78 return new Compiler(options).run(); | 78 return new Compiler(options).run(); |
79 } | 79 } |
80 var realSdk = getSdkDir(arguments).path; | 80 var realSdk = getSdkDir(arguments).path; |
81 | 81 |
82 // Remove old output, and `packages` symlinks which mess up the diff. | 82 // Remove old output, and `packages` symlinks which mess up the diff. |
83 var dir = new Directory(actualDir); | 83 var dir = new Directory(expectDir); |
84 if (dir.existsSync()) dir.deleteSync(recursive: true); | 84 if (dir.existsSync()) dir.deleteSync(recursive: true); |
85 var packagesDirs = new Directory(inputDir) | 85 var packagesDirs = new Directory(inputDir) |
86 .listSync(recursive: true) | 86 .listSync(recursive: true) |
87 .where((d) => d is Directory && path.basename(d.path) == 'packages'); | 87 .where((d) => d is Directory && path.basename(d.path) == 'packages'); |
88 packagesDirs.forEach((d) => d.deleteSync()); | 88 packagesDirs.forEach((d) => d.deleteSync()); |
89 | 89 |
90 for (var filePath in paths) { | 90 for (var filePath in paths) { |
91 var filename = path.basenameWithoutExtension(filePath); | 91 var filename = path.basenameWithoutExtension(filePath); |
92 | 92 |
93 test('devc $filename.dart', () { | 93 test('devc $filename.dart', () { |
94 compilerMessages.writeln('// Messages from compiling $filename.dart'); | 94 compilerMessages.writeln('// Messages from compiling $filename.dart'); |
95 | 95 |
96 // TODO(jmesserly): this was added to get some coverage of source maps | 96 // TODO(jmesserly): this was added to get some coverage of source maps |
97 // We need a more comprehensive strategy to test them. | 97 // We need a more comprehensive strategy to test them. |
98 var sourceMaps = filename == 'map_keys'; | 98 var sourceMaps = filename == 'map_keys'; |
99 var result = compile(filePath, realSdk, sourceMaps: sourceMaps); | 99 var result = compile(filePath, realSdk, sourceMaps: sourceMaps); |
100 var success = !result.failure; | 100 var success = !result.failure; |
101 | 101 |
102 // Write compiler messages to disk. | 102 // Write compiler messages to disk. |
103 new File(path.join(actualDir, '$filename.txt')) | 103 new File(path.join(expectDir, '$filename.txt')) |
104 .writeAsStringSync(compilerMessages.toString()); | 104 .writeAsStringSync(compilerMessages.toString()); |
105 | 105 |
106 var outFile = new File(path.join(actualDir, '$filename.js')); | 106 var outFile = new File(path.join(expectDir, '$filename.js')); |
107 expect(outFile.existsSync(), success, | 107 expect(outFile.existsSync(), success, |
108 reason: '${outFile.path} was created iff compilation succeeds'); | 108 reason: '${outFile.path} was created iff compilation succeeds'); |
109 | 109 |
110 // TODO(jmesserly): ideally we'd diff the output here. For now it | 110 // TODO(jmesserly): ideally we'd diff the output here. For now it |
111 // happens in the containing shell script. | 111 // happens in the containing shell script. |
112 }); | 112 }); |
113 } | 113 } |
114 | 114 |
115 if (Platform.environment.containsKey('COVERALLS_TOKEN')) { | 115 if (Platform.environment.containsKey('COVERALLS_TOKEN')) { |
116 group('sdk', () { | 116 group('sdk', () { |
117 // The analyzer does not bubble exception messages for certain internal | 117 // The analyzer does not bubble exception messages for certain internal |
118 // dart:* library failures, such as failing to find | 118 // dart:* library failures, such as failing to find |
119 // "_internal/libraries.dart". Instead it produces an opaque "failed to | 119 // "_internal/libraries.dart". Instead it produces an opaque "failed to |
120 // instantiate dart:core" message. To remedy this we hook up an analysis | 120 // instantiate dart:core" message. To remedy this we hook up an analysis |
121 // logger that prints these messages. | 121 // logger that prints these messages. |
122 var savedLogger; | 122 var savedLogger; |
123 setUp(() { | 123 setUp(() { |
124 savedLogger = AnalysisEngine.instance.logger; | 124 savedLogger = AnalysisEngine.instance.logger; |
125 AnalysisEngine.instance.logger = new PrintLogger(); | 125 AnalysisEngine.instance.logger = new PrintLogger(); |
126 }); | 126 }); |
127 tearDown(() { | 127 tearDown(() { |
128 AnalysisEngine.instance.logger = savedLogger; | 128 AnalysisEngine.instance.logger = savedLogger; |
129 }); | 129 }); |
130 | 130 |
131 test('devc dart:core', () { | 131 test('devc dart:core', () { |
132 // Get the test SDK. We use a checked in copy so test expectations can | 132 // Get the test SDK. We use a checked in copy so test expectations can |
133 // be generated against a specific SDK version. | 133 // be generated against a specific SDK version. |
134 var testSdk = path.join(testDirectory, 'generated_sdk'); | 134 var testSdk = path.join(testDirectory, 'generated_sdk'); |
135 var result = compile('dart:core', testSdk, checkSdk: true); | 135 var result = compile('dart:core', testSdk, checkSdk: true); |
136 var outputDir = new Directory(path.join(actualDir, 'core')); | 136 var outputDir = new Directory(path.join(expectDir, 'core')); |
137 var outFile = new File(path.join(actualDir, 'dart/core.js')); | 137 var outFile = new File(path.join(expectDir, 'dart/core.js')); |
138 expect(outFile.existsSync(), true, | 138 expect(outFile.existsSync(), true, |
139 reason: '${outFile.path} was created for dart:core'); | 139 reason: '${outFile.path} was created for dart:core'); |
140 }); | 140 }); |
141 }); | 141 }); |
142 } | 142 } |
143 | 143 |
144 var expectedRuntime = | 144 var expectedRuntime = |
145 defaultRuntimeFiles.map((f) => 'dev_compiler/runtime/$f'); | 145 defaultRuntimeFiles.map((f) => 'dev_compiler/runtime/$f'); |
146 | 146 |
147 test('devc jscodegen sunflower.html', () { | 147 test('devc jscodegen sunflower.html', () { |
148 var filePath = path.join(inputDir, 'sunflower', 'sunflower.html'); | 148 var filePath = path.join(inputDir, 'sunflower', 'sunflower.html'); |
149 compilerMessages.writeln('// Messages from compiling sunflower.html'); | 149 compilerMessages.writeln('// Messages from compiling sunflower.html'); |
150 | 150 |
151 var result = compile(filePath, realSdk, subDir: 'sunflower'); | 151 var result = compile(filePath, realSdk, subDir: 'sunflower'); |
152 var success = !result.failure; | 152 var success = !result.failure; |
153 | 153 |
154 // Write compiler messages to disk. | 154 // Write compiler messages to disk. |
155 new File(path.join(actualDir, 'sunflower', 'sunflower.txt')) | 155 new File(path.join(expectDir, 'sunflower', 'sunflower.txt')) |
156 .writeAsStringSync(compilerMessages.toString()); | 156 .writeAsStringSync(compilerMessages.toString()); |
157 | 157 |
158 var expectedFiles = [ | 158 var expectedFiles = [ |
159 'sunflower.html', | 159 'sunflower.html', |
160 'sunflower.js', | 160 'sunflower.js', |
161 'sunflower.css', | 161 'sunflower.css', |
162 'math.png', | 162 'math.png', |
163 ]..addAll(expectedRuntime); | 163 ]..addAll(expectedRuntime); |
164 | 164 |
165 for (var filepath in expectedFiles) { | 165 for (var filepath in expectedFiles) { |
166 var outFile = new File(path.join(actualDir, 'sunflower', filepath)); | 166 var outFile = new File(path.join(expectDir, 'sunflower', filepath)); |
167 expect(outFile.existsSync(), success, | 167 expect(outFile.existsSync(), success, |
168 reason: '${outFile.path} was created iff compilation succeeds'); | 168 reason: '${outFile.path} was created iff compilation succeeds'); |
169 } | 169 } |
170 }); | 170 }); |
171 | 171 |
172 test('devc jscodegen html_input.html', () { | 172 test('devc jscodegen html_input.html', () { |
173 var filePath = path.join(inputDir, 'html_input.html'); | 173 var filePath = path.join(inputDir, 'html_input.html'); |
174 compilerMessages.writeln('// Messages from compiling html_input.html'); | 174 compilerMessages.writeln('// Messages from compiling html_input.html'); |
175 | 175 |
176 var result = compile(filePath, realSdk); | 176 var result = compile(filePath, realSdk); |
177 var success = !result.failure; | 177 var success = !result.failure; |
178 | 178 |
179 // Write compiler messages to disk. | 179 // Write compiler messages to disk. |
180 new File(path.join(actualDir, 'html_input.txt')) | 180 new File(path.join(expectDir, 'html_input.txt')) |
181 .writeAsStringSync(compilerMessages.toString()); | 181 .writeAsStringSync(compilerMessages.toString()); |
182 | 182 |
183 var expectedFiles = [ | 183 var expectedFiles = [ |
184 'html_input.html', | 184 'html_input.html', |
185 'dir/html_input_a.js', | 185 'dir/html_input_a.js', |
186 'dir/html_input_b.js', | 186 'dir/html_input_b.js', |
187 'dir/html_input_c.js', | 187 'dir/html_input_c.js', |
188 'dir/html_input_d.js', | 188 'dir/html_input_d.js', |
189 'dir/html_input_e.js' | 189 'dir/html_input_e.js' |
190 ]..addAll(expectedRuntime); | 190 ]..addAll(expectedRuntime); |
191 | 191 |
192 for (var filepath in expectedFiles) { | 192 for (var filepath in expectedFiles) { |
193 var outFile = new File(path.join(actualDir, filepath)); | 193 var outFile = new File(path.join(expectDir, filepath)); |
194 expect(outFile.existsSync(), success, | 194 expect(outFile.existsSync(), success, |
195 reason: '${outFile.path} was created iff compilation succeeds'); | 195 reason: '${outFile.path} was created iff compilation succeeds'); |
196 } | 196 } |
197 | 197 |
198 var notExpectedFiles = [ | 198 var notExpectedFiles = [ |
199 'dev_compiler/runtime/messages_widget.js', | 199 'dev_compiler/runtime/messages_widget.js', |
200 'dev_compiler/runtime/messages.css' | 200 'dev_compiler/runtime/messages.css' |
201 ]; | 201 ]; |
202 for (var filepath in notExpectedFiles) { | 202 for (var filepath in notExpectedFiles) { |
203 var outFile = new File(path.join(actualDir, filepath)); | 203 var outFile = new File(path.join(expectDir, filepath)); |
204 expect(outFile.existsSync(), isFalse, | 204 expect(outFile.existsSync(), isFalse, |
205 reason: '${outFile.path} should only be generated in server mode'); | 205 reason: '${outFile.path} should only be generated in server mode'); |
206 } | 206 } |
207 }); | 207 }); |
208 | 208 |
209 test('devc jscodegen html_input.html server mode', () { | 209 test('devc jscodegen html_input.html server mode', () { |
210 var filePath = path.join(inputDir, 'html_input.html'); | 210 var filePath = path.join(inputDir, 'html_input.html'); |
211 compilerMessages.writeln('// Messages from compiling html_input.html'); | 211 compilerMessages.writeln('// Messages from compiling html_input.html'); |
212 | 212 |
213 var result = | 213 var result = |
214 compile(filePath, realSdk, serverMode: true, subDir: 'server_mode'); | 214 compile(filePath, realSdk, serverMode: true, subDir: 'server_mode'); |
215 var success = !result.failure; | 215 var success = !result.failure; |
216 | 216 |
217 // Write compiler messages to disk. | 217 // Write compiler messages to disk. |
218 new File(path.join(actualDir, 'server_mode', 'html_input.txt')) | 218 new File(path.join(expectDir, 'server_mode', 'html_input.txt')) |
219 .writeAsStringSync(compilerMessages.toString()); | 219 .writeAsStringSync(compilerMessages.toString()); |
220 | 220 |
221 var expectedFiles = [ | 221 var expectedFiles = [ |
222 'dir/html_input_a.js', | 222 'dir/html_input_a.js', |
223 'dir/html_input_b.js', | 223 'dir/html_input_b.js', |
224 'dir/html_input_c.js', | 224 'dir/html_input_c.js', |
225 'dir/html_input_d.js', | 225 'dir/html_input_d.js', |
226 'dir/html_input_e.js', | 226 'dir/html_input_e.js', |
227 'dev_compiler/runtime/messages_widget.js', | 227 'dev_compiler/runtime/messages_widget.js', |
228 'dev_compiler/runtime/messages.css' | 228 'dev_compiler/runtime/messages.css' |
229 ]..addAll(expectedRuntime); | 229 ]..addAll(expectedRuntime); |
230 | 230 |
231 // Parse the HTML file and verify its contents were expected. | 231 // Parse the HTML file and verify its contents were expected. |
232 var htmlPath = path.join(actualDir, 'server_mode', 'html_input.html'); | 232 var htmlPath = path.join(expectDir, 'server_mode', 'html_input.html'); |
233 var doc = html.parse(new File(htmlPath).readAsStringSync()); | 233 var doc = html.parse(new File(htmlPath).readAsStringSync()); |
234 | 234 |
235 for (var filepath in expectedFiles) { | 235 for (var filepath in expectedFiles) { |
236 var outPath = path.join(actualDir, 'server_mode', filepath); | 236 var outPath = path.join(expectDir, 'server_mode', filepath); |
237 expect(new File(outPath).existsSync(), success, | 237 expect(new File(outPath).existsSync(), success, |
238 reason: '$outPath was created iff compilation succeeds'); | 238 reason: '$outPath was created iff compilation succeeds'); |
239 | 239 |
240 var query; | 240 var query; |
241 if (filepath.endsWith('js')) { | 241 if (filepath.endsWith('js')) { |
242 var hash; | 242 var hash; |
243 if (filepath.startsWith('dev_compiler')) { | 243 if (filepath.startsWith('dev_compiler')) { |
244 hash = computeHashFromFile(outPath); | 244 hash = computeHashFromFile(outPath); |
245 } else { | 245 } else { |
246 // TODO(jmesserly): see if we can get this to return the same | 246 // TODO(jmesserly): see if we can get this to return the same |
247 // answer as computeHashFromFile. | 247 // answer as computeHashFromFile. |
248 hash = computeHash(new File(outPath).readAsStringSync()); | 248 hash = computeHash(new File(outPath).readAsStringSync()); |
249 } | 249 } |
250 query = 'script[src="$filepath?____cached=$hash"]'; | 250 query = 'script[src="$filepath?____cached=$hash"]'; |
251 } else { | 251 } else { |
252 var hash = computeHashFromFile(outPath); | 252 var hash = computeHashFromFile(outPath); |
253 query = 'link[href="$filepath?____cached=$hash"]'; | 253 query = 'link[href="$filepath?____cached=$hash"]'; |
254 } | 254 } |
255 expect(doc.querySelector(query), isNotNull, | 255 expect(doc.querySelector(query), isNotNull, |
256 reason: "should find `$query` in $htmlPath for $outPath"); | 256 reason: "should find `$query` in $htmlPath for $outPath"); |
257 } | 257 } |
258 | 258 |
259 // Clean up the server mode folder, otherwise it causes diff churn. | 259 // Clean up the server mode folder, otherwise it causes diff churn. |
260 var dir = new Directory(path.join(actualDir, 'server_mode')); | 260 var dir = new Directory(path.join(expectDir, 'server_mode')); |
261 if (dir.existsSync()) dir.deleteSync(recursive: true); | 261 if (dir.existsSync()) dir.deleteSync(recursive: true); |
262 }); | 262 }); |
263 } | 263 } |
264 | 264 |
265 /// An implementation of analysis engine's [Logger] that prints. | 265 /// An implementation of analysis engine's [Logger] that prints. |
266 class PrintLogger implements Logger { | 266 class PrintLogger implements Logger { |
267 @override void logError(String message, [CaughtException exception]) { | 267 @override void logError(String message, [CaughtException exception]) { |
268 print('[AnalysisEngine] error $message $exception'); | 268 print('[AnalysisEngine] error $message $exception'); |
269 } | 269 } |
270 | 270 |
271 @override void logError2(String message, Object exception) { | 271 @override void logError2(String message, Object exception) { |
272 print('[AnalysisEngine] error $message $exception'); | 272 print('[AnalysisEngine] error $message $exception'); |
273 } | 273 } |
274 | 274 |
275 void logInformation(String message, [CaughtException exception]) {} | 275 void logInformation(String message, [CaughtException exception]) {} |
276 void logInformation2(String message, Object exception) {} | 276 void logInformation2(String message, Object exception) {} |
277 } | 277 } |
OLD | NEW |