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