| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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 /// | 6 /// |
| 7 /// Runs Dart Dev Compiler on all input in the `codegen` directory and checks | 7 /// Runs Dart Dev Compiler on all input in the `codegen` directory and checks |
| 8 /// that the output is what we expected. | 8 /// that the output is what we expected. |
| 9 library dev_compiler.test.codegen_test; | 9 library dev_compiler.test.codegen_test; |
| 10 | 10 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 import 'multitest.dart' show extractTestsFromMultitest, isMultiTest; | 33 import 'multitest.dart' show extractTestsFromMultitest, isMultiTest; |
| 34 import '../tool/build_sdk.dart' as build_sdk; | 34 import '../tool/build_sdk.dart' as build_sdk; |
| 35 import 'package:dev_compiler/src/compiler/compiler.dart'; | 35 import 'package:dev_compiler/src/compiler/compiler.dart'; |
| 36 | 36 |
| 37 final ArgParser argParser = new ArgParser() | 37 final ArgParser argParser = new ArgParser() |
| 38 ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null); | 38 ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null); |
| 39 | 39 |
| 40 /// The `test/codegen` directory. | 40 /// The `test/codegen` directory. |
| 41 final codegenDir = path.join(testDirectory, 'codegen'); | 41 final codegenDir = path.join(testDirectory, 'codegen'); |
| 42 | 42 |
| 43 /// The `test/codegen/expect` directory. |
| 44 final codegenExpectDir = path.join(codegenDir, 'expect'); |
| 45 |
| 43 /// The generated directory where tests, expanded multitests, and other test | 46 /// The generated directory where tests, expanded multitests, and other test |
| 44 /// support libraries are copied to. | 47 /// support libraries are copied to. |
| 45 /// | 48 /// |
| 46 /// The tests sometimes import utility libraries using a relative path. | 49 /// The tests sometimes import utility libraries using a relative path. |
| 47 /// Likewise, the multitests do too, and one multitest even imports its own | 50 /// Likewise, the multitests do too, and one multitest even imports its own |
| 48 /// non-expanded form (!). To make that simpler, we copy the entire test tree | 51 /// non-expanded form (!). To make that simpler, we copy the entire test tree |
| 49 /// to a generated directory and expand that multitests in there too. | 52 /// to a generated directory and expand that multitests in there too. |
| 50 final codegenTestDir = path.join(repoDirectory, 'gen', 'codegen_tests'); | 53 final codegenTestDir = path.join(repoDirectory, 'gen', 'codegen_tests'); |
| 51 | 54 |
| 52 /// The generated directory where tests and packages compiled to JS are | 55 /// The generated directory where tests and packages compiled to JS are |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 | 101 |
| 99 // Compile each test file to JS and put the result in gen/codegen_output. | 102 // Compile each test file to JS and put the result in gen/codegen_output. |
| 100 for (var testFile in testFiles) { | 103 for (var testFile in testFiles) { |
| 101 var relativePath = path.relative(testFile, from: codegenTestDir); | 104 var relativePath = path.relative(testFile, from: codegenTestDir); |
| 102 | 105 |
| 103 // Only compile the top-level files for generating coverage. | 106 // Only compile the top-level files for generating coverage. |
| 104 if (codeCoverage && path.dirname(relativePath) != ".") continue; | 107 if (codeCoverage && path.dirname(relativePath) != ".") continue; |
| 105 | 108 |
| 106 var name = path.withoutExtension(relativePath); | 109 var name = path.withoutExtension(relativePath); |
| 107 test('dartdevc $name', () { | 110 test('dartdevc $name', () { |
| 108 var outDir = path.join(codegenOutputDir, path.dirname(relativePath)); | 111 var relativeDir = path.dirname(relativePath); |
| 109 _ensureDirectory(outDir); | 112 var outDir = path.join(codegenOutputDir, relativeDir); |
| 113 var expectDir = path.join(codegenExpectDir, relativeDir); |
| 110 | 114 |
| 111 // Check if we need to use special compile options. | 115 // Check if we need to use special compile options. |
| 112 var contents = new File(testFile).readAsStringSync(); | 116 var contents = new File(testFile).readAsStringSync(); |
| 113 var match = | 117 var match = |
| 114 new RegExp(r'// compile options: (.*)').matchAsPrefix(contents); | 118 new RegExp(r'// compile options: (.*)').matchAsPrefix(contents); |
| 115 | 119 |
| 116 var args = defaultOptions.toList(); | 120 var args = defaultOptions.toList(); |
| 117 if (match != null) { | 121 if (match != null) { |
| 118 args.addAll(match.group(1).split(' ')); | 122 args.addAll(match.group(1).split(' ')); |
| 119 } | 123 } |
| 120 var options = | 124 var options = |
| 121 new CompilerOptions.fromArguments(compilerArgParser.parse(args)); | 125 new CompilerOptions.fromArguments(compilerArgParser.parse(args)); |
| 122 | 126 |
| 123 // Collect any other files we've imported. | 127 // Collect any other files we've imported. |
| 124 var files = new Set<String>(); | 128 var files = new Set<String>(); |
| 125 _collectTransitiveImports(contents, files, from: testFile); | 129 _collectTransitiveImports(contents, files, from: testFile); |
| 126 var moduleName = | 130 var moduleName = |
| 127 path.withoutExtension(path.relative(testFile, from: codegenTestDir)); | 131 path.withoutExtension(path.relative(testFile, from: codegenTestDir)); |
| 128 var unit = new BuildUnit(moduleName, path.dirname(testFile), | 132 var unit = new BuildUnit(moduleName, path.dirname(testFile), |
| 129 files.toList(), _moduleForLibrary); | 133 files.toList(), _moduleForLibrary); |
| 130 var module = compiler.compile(unit, options); | 134 var module = compiler.compile(unit, options); |
| 131 _writeModule( | 135 _writeModule( |
| 132 path.join(outDir, path.basenameWithoutExtension(testFile)), module); | 136 path.join(outDir, path.basenameWithoutExtension(testFile)), |
| 137 path.join(expectDir, path.basenameWithoutExtension(testFile)), |
| 138 module); |
| 133 }); | 139 }); |
| 134 } | 140 } |
| 135 | 141 |
| 136 if (codeCoverage) { | 142 if (codeCoverage) { |
| 137 test('build_sdk code coverage', () { | 143 test('build_sdk code coverage', () { |
| 138 return build_sdk.main(['--dart-sdk', sdkDir, '-o', codegenOutputDir]); | 144 return build_sdk.main(['--dart-sdk', sdkDir, '-o', codegenOutputDir]); |
| 139 }); | 145 }); |
| 140 } | 146 } |
| 141 } | 147 } |
| 142 | 148 |
| 143 void _writeModule(String outPath, JSModuleFile result) { | 149 void _writeModule(String outPath, String expectPath, JSModuleFile result) { |
| 144 _ensureDirectory(path.dirname(outPath)); | 150 _ensureDirectory(path.dirname(outPath)); |
| 151 _ensureDirectory(path.dirname(expectPath)); |
| 145 | 152 |
| 146 String errors = result.errors.join('\n'); | 153 String errors = result.errors.join('\n'); |
| 147 if (errors.isNotEmpty && !errors.endsWith('\n')) errors += '\n'; | 154 if (errors.isNotEmpty && !errors.endsWith('\n')) errors += '\n'; |
| 148 new File(outPath + '.txt').writeAsStringSync(errors); | 155 new File(outPath + '.txt').writeAsStringSync(errors); |
| 149 | 156 |
| 150 var jsFile = new File(outPath + '.js'); | 157 var jsFile = new File(outPath + '.js'); |
| 158 var expectFile = new File(expectPath + '.js'); |
| 151 var errorFile = new File(outPath + '.err'); | 159 var errorFile = new File(outPath + '.err'); |
| 152 | 160 |
| 153 if (result.isValid) { | 161 if (result.isValid) { |
| 154 jsFile.writeAsStringSync(result.code); | 162 jsFile.writeAsStringSync(result.code); |
| 155 if (result.sourceMap != null) { | 163 if (result.sourceMap != null) { |
| 156 var mapPath = outPath + '.js.map'; | 164 var mapPath = outPath + '.js.map'; |
| 157 new File(mapPath) | 165 new File(mapPath) |
| 158 .writeAsStringSync(JSON.encode(result.placeSourceMap(mapPath))); | 166 .writeAsStringSync(JSON.encode(result.placeSourceMap(mapPath))); |
| 159 } | 167 } |
| 160 | 168 |
| 169 expectFile.writeAsStringSync(result.code); |
| 170 |
| 161 // There are no errors, so delete any stale ".err" file. | 171 // There are no errors, so delete any stale ".err" file. |
| 162 if (errorFile.existsSync()) { | 172 if (errorFile.existsSync()) { |
| 163 errorFile.deleteSync(); | 173 errorFile.deleteSync(); |
| 164 } | 174 } |
| 165 } else { | 175 } else { |
| 166 // Also write the errors to a '.err' file for easy counting. | 176 // Also write the errors to a '.err' file for easy counting. |
| 167 var moduleName = result.name; | 177 var moduleName = result.name; |
| 168 var libraryName = path.split(moduleName).last; | 178 var libraryName = path.split(moduleName).last; |
| 169 var count = "[error]".allMatches(errors).length; | 179 var count = "[error]".allMatches(errors).length; |
| 170 var text = ''' | 180 var text = ''' |
| 171 dart_library.library('$moduleName', null, [ | 181 dart_library.library('$moduleName', null, [ |
| 172 'dart_sdk', | 182 'dart_sdk', |
| 173 'expect' | 183 'expect' |
| 174 ], function(exports, dart_sdk, expect) { | 184 ], function(exports, dart_sdk, expect) { |
| 175 const message = `DDC Compilation Error: $moduleName has $count errors`; | 185 const message = `DDC Compilation Error: $moduleName has $count errors`; |
| 176 const error = new Error(message); | 186 const error = new Error(message); |
| 177 exports.$libraryName = Object.create(null); | 187 exports.$libraryName = Object.create(null); |
| 178 exports.$libraryName.main = function() { | 188 exports.$libraryName.main = function() { |
| 179 throw error; | 189 throw error; |
| 180 } | 190 } |
| 181 }); | 191 }); |
| 182 '''; | 192 '''; |
| 183 errorFile.writeAsStringSync(text); | 193 errorFile.writeAsStringSync(text); |
| 184 | 194 |
| 185 // There are errors, so delete any stale ".js" file. | 195 // There are errors, so delete any stale ".js" file. |
| 186 if (jsFile.existsSync()) { | 196 if (jsFile.existsSync()) { |
| 187 jsFile.deleteSync(); | 197 jsFile.deleteSync(); |
| 188 } | 198 } |
| 199 |
| 200 // There are errors, so delete any stale expect ".js" file. |
| 201 if (expectFile.existsSync()) { |
| 202 expectFile.deleteSync(); |
| 203 } |
| 204 expectFile.writeAsStringSync("//FAILED TO COMPILE"); |
| 189 } | 205 } |
| 190 } | 206 } |
| 191 | 207 |
| 192 void _buildAllPackages(ModuleCompiler compiler) { | 208 void _buildAllPackages(ModuleCompiler compiler) { |
| 193 group('dartdevc package', () { | 209 group('dartdevc package', () { |
| 194 _buildPackages(compiler, codegenOutputDir); | 210 _buildPackages(compiler, codegenOutputDir, codegenExpectDir); |
| 195 | 211 |
| 196 var packages = ['matcher', 'path', 'stack_trace']; | 212 var packages = ['matcher', 'path', 'stack_trace']; |
| 197 for (var package in packages) { | 213 for (var package in packages) { |
| 198 test(package, () { | 214 test(package, () { |
| 199 _buildPackage(compiler, codegenOutputDir, package); | 215 _buildPackage(compiler, codegenOutputDir, codegenExpectDir, package); |
| 200 }); | 216 }); |
| 201 } | 217 } |
| 202 | 218 |
| 203 test('unittest', () { | 219 test('unittest', () { |
| 204 // Only build files applicable to the web - html_*.dart and its | 220 // Only build files applicable to the web - html_*.dart and its |
| 205 // internal dependences. | 221 // internal dependences. |
| 206 _buildPackage(compiler, codegenOutputDir, "unittest", packageFiles: [ | 222 _buildPackage(compiler, codegenOutputDir, codegenExpectDir, "unittest",
packageFiles: [ |
| 207 'unittest.dart', | 223 'unittest.dart', |
| 208 'html_config.dart', | 224 'html_config.dart', |
| 209 'html_individual_config.dart', | 225 'html_individual_config.dart', |
| 210 'html_enhanced_config.dart' | 226 'html_enhanced_config.dart' |
| 211 ]); | 227 ]); |
| 212 }); | 228 }); |
| 213 }); | 229 }); |
| 214 | 230 |
| 215 test('dartdevc sunflower', () { | 231 test('dartdevc sunflower', () { |
| 216 _buildSunflower(compiler, codegenOutputDir); | 232 _buildSunflower(compiler, codegenOutputDir, codegenExpectDir); |
| 217 }); | 233 }); |
| 218 } | 234 } |
| 219 | 235 |
| 220 void _buildSunflower(ModuleCompiler compiler, String outputDir) { | 236 void _buildSunflower(ModuleCompiler compiler, String outputDir, String expectDir
) { |
| 221 var baseDir = path.join(codegenDir, 'sunflower'); | 237 var baseDir = path.join(codegenDir, 'sunflower'); |
| 222 var files = ['sunflower', 'circle', 'painter'] | 238 var files = ['sunflower', 'circle', 'painter'] |
| 223 .map((f) => path.join(baseDir, '$f.dart')) | 239 .map((f) => path.join(baseDir, '$f.dart')) |
| 224 .toList(); | 240 .toList(); |
| 225 var input = new BuildUnit('sunflower', baseDir, files, _moduleForLibrary); | 241 var input = new BuildUnit('sunflower', baseDir, files, _moduleForLibrary); |
| 226 var options = new CompilerOptions(summarizeApi: false); | 242 var options = new CompilerOptions(summarizeApi: false); |
| 227 | 243 |
| 228 var built = compiler.compile(input, options); | 244 var built = compiler.compile(input, options); |
| 229 _writeModule(path.join(outputDir, 'sunflower', 'sunflower'), built); | 245 _writeModule(path.join(outputDir, 'sunflower', 'sunflower'), |
| 246 path.join(expectDir, 'sunflower', 'sunflower'), built); |
| 230 } | 247 } |
| 231 | 248 |
| 232 void _buildPackages(ModuleCompiler compiler, String outputDir) { | 249 void _buildPackages(ModuleCompiler compiler, String outputDir, String expectDir)
{ |
| 233 // Note: we don't summarize these, as we're going to rely on our in-memory | 250 // Note: we don't summarize these, as we're going to rely on our in-memory |
| 234 // shared analysis context for caching, and `_moduleForLibrary` below | 251 // shared analysis context for caching, and `_moduleForLibrary` below |
| 235 // understands these are from other modules. | 252 // understands these are from other modules. |
| 236 var options = new CompilerOptions(sourceMap: false, summarizeApi: false); | 253 var options = new CompilerOptions(sourceMap: false, summarizeApi: false); |
| 237 | 254 |
| 238 for (var uri in packageUrlMappings.keys) { | 255 for (var uri in packageUrlMappings.keys) { |
| 239 assert(uri.startsWith('package:')); | 256 assert(uri.startsWith('package:')); |
| 240 var uriPath = uri.substring('package:'.length); | 257 var uriPath = uri.substring('package:'.length); |
| 241 var name = path.basenameWithoutExtension(uriPath); | 258 var name = path.basenameWithoutExtension(uriPath); |
| 242 test(name, () { | 259 test(name, () { |
| 243 var input = new BuildUnit(name, codegenDir, [uri], _moduleForLibrary); | 260 var input = new BuildUnit(name, codegenDir, [uri], _moduleForLibrary); |
| 244 var built = compiler.compile(input, options); | 261 var built = compiler.compile(input, options); |
| 245 | 262 |
| 246 var outPath = path.join(outputDir, path.withoutExtension(uriPath)); | 263 var outPath = path.join(outputDir, path.withoutExtension(uriPath)); |
| 247 _writeModule(outPath, built); | 264 var expectPath = path.join(expectDir, path.withoutExtension(uriPath)); |
| 265 _writeModule(outPath, expectPath, built); |
| 248 }); | 266 }); |
| 249 } | 267 } |
| 250 } | 268 } |
| 251 | 269 |
| 252 void _buildPackage(ModuleCompiler compiler, String outputDir, packageName, | 270 void _buildPackage(ModuleCompiler compiler, String outputDir, String expectDir,
packageName, |
| 253 {List<String> packageFiles}) { | 271 {List<String> packageFiles}) { |
| 254 var options = new CompilerOptions(sourceMap: false, summarizeApi: false); | 272 var options = new CompilerOptions(sourceMap: false, summarizeApi: false); |
| 255 | 273 |
| 256 var packageRoot = path.join(codegenDir, 'packages'); | 274 var packageRoot = path.join(codegenDir, 'packages'); |
| 257 var packageInputDir = path.join(packageRoot, packageName); | 275 var packageInputDir = path.join(packageRoot, packageName); |
| 258 List<String> files; | 276 List<String> files; |
| 259 if (packageFiles != null) { | 277 if (packageFiles != null) { |
| 260 // Only collect files transitively reachable from packageFiles. | 278 // Only collect files transitively reachable from packageFiles. |
| 261 var reachable = new Set<String>(); | 279 var reachable = new Set<String>(); |
| 262 for (var file in packageFiles) { | 280 for (var file in packageFiles) { |
| 263 file = path.join(packageInputDir, file); | 281 file = path.join(packageInputDir, file); |
| 264 _collectTransitiveImports(new File(file).readAsStringSync(), reachable, | 282 _collectTransitiveImports(new File(file).readAsStringSync(), reachable, |
| 265 packageRoot: packageRoot, from: file); | 283 packageRoot: packageRoot, from: file); |
| 266 } | 284 } |
| 267 files = reachable.toList(); | 285 files = reachable.toList(); |
| 268 } else { | 286 } else { |
| 269 // Collect all files in the packages directory. | 287 // Collect all files in the packages directory. |
| 270 files = new Directory(packageInputDir) | 288 files = new Directory(packageInputDir) |
| 271 .listSync(recursive: true) | 289 .listSync(recursive: true) |
| 272 .where((entry) => entry.path.endsWith('.dart')) | 290 .where((entry) => entry.path.endsWith('.dart')) |
| 273 .map((entry) => entry.path) | 291 .map((entry) => entry.path) |
| 274 .toList(); | 292 .toList(); |
| 275 } | 293 } |
| 276 | 294 |
| 277 var unit = | 295 var unit = |
| 278 new BuildUnit(packageName, packageInputDir, files, _moduleForLibrary); | 296 new BuildUnit(packageName, packageInputDir, files, _moduleForLibrary); |
| 279 var module = compiler.compile(unit, options); | 297 var module = compiler.compile(unit, options); |
| 280 | 298 |
| 281 var outPath = path.join(outputDir, packageName, packageName); | 299 var outPath = path.join(outputDir, packageName, packageName); |
| 282 _writeModule(outPath, module); | 300 var expectPath = path.join(expectDir, packageName, packageName); |
| 301 _writeModule(outPath, expectPath, module); |
| 283 } | 302 } |
| 284 | 303 |
| 285 String _moduleForLibrary(Source source) { | 304 String _moduleForLibrary(Source source) { |
| 286 var scheme = source.uri.scheme; | 305 var scheme = source.uri.scheme; |
| 287 if (scheme == 'package') { | 306 if (scheme == 'package') { |
| 288 return source.uri.pathSegments.first; | 307 return source.uri.pathSegments.first; |
| 289 } | 308 } |
| 290 throw new Exception('Module not found for library "${source.fullName}"'); | 309 throw new Exception('Module not found for library "${source.fullName}"'); |
| 291 } | 310 } |
| 292 | 311 |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 /// Simplified from ParseDartTask.resolveDirective. | 418 /// Simplified from ParseDartTask.resolveDirective. |
| 400 String _resolveDirective(UriBasedDirective directive) { | 419 String _resolveDirective(UriBasedDirective directive) { |
| 401 StringLiteral uriLiteral = directive.uri; | 420 StringLiteral uriLiteral = directive.uri; |
| 402 String uriContent = uriLiteral.stringValue; | 421 String uriContent = uriLiteral.stringValue; |
| 403 if (uriContent != null) { | 422 if (uriContent != null) { |
| 404 uriContent = uriContent.trim(); | 423 uriContent = uriContent.trim(); |
| 405 directive.uriContent = uriContent; | 424 directive.uriContent = uriContent; |
| 406 } | 425 } |
| 407 return directive.validate() == null ? uriContent : null; | 426 return directive.validate() == null ? uriContent : null; |
| 408 } | 427 } |
| OLD | NEW |