| 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 |