Chromium Code Reviews| Index: test/codegen_test.dart |
| diff --git a/test/codegen_test.dart b/test/codegen_test.dart |
| index cf67d164bf04ab808287b4d87d590d9f2694204f..5167b79b42490743006aa5b319770a235b98eee1 100644 |
| --- a/test/codegen_test.dart |
| +++ b/test/codegen_test.dart |
| @@ -3,10 +3,15 @@ |
| // BSD-style license that can be found in the LICENSE file. |
| /// Tests code generation. |
| +/// |
| /// Runs Dart Dev Compiler on all input in the `codegen` directory and checks |
| /// that the output is what we expected. |
| library dev_compiler.test.codegen_test; |
| +// TODO(rnystrom): This doesn't actually run any tests any more. It just |
| +// compiles stuff. This should be changed to not use unittest and just be a |
| +// regular program that outputs files. |
| + |
| import 'dart:convert' show JSON; |
| import 'dart:io' show Directory, File, Platform; |
| import 'package:args/args.dart' show ArgParser, ArgResults; |
| @@ -24,7 +29,7 @@ import 'package:analyzer/src/generated/source.dart' show Source; |
| import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions; |
| import 'package:dev_compiler/src/compiler/compiler.dart' |
| show BuildUnit, CompilerOptions, ModuleCompiler; |
| -import 'testing.dart' show testDirectory; |
| +import 'testing.dart' show ddcDirectory, testDirectory; |
| import 'multitest.dart' show extractTestsFromMultitest, isMultiTest; |
| import '../tool/build_sdk.dart' as build_sdk; |
| import 'package:dev_compiler/src/compiler/compiler.dart'; |
| @@ -32,12 +37,45 @@ import 'package:dev_compiler/src/compiler/compiler.dart'; |
| final ArgParser argParser = new ArgParser() |
| ..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null); |
| +/// The `test/codegen` directory. |
| +final codegenDir = path.join(testDirectory, 'codegen'); |
| + |
| +/// The generated directory where tests, expanded multitests, and other test |
| +/// support libraries are copied to. |
| +/// |
| +/// The tests sometimes import utility libraries using a relative path. |
| +/// Likewise, the multitests do too, and one multitest even imports its own |
| +/// non-expanded form (!). To make that simpler, we copy the entire test tree |
| +/// to a generated directory and expand that multitests in there too. |
| +final codegenTestDir = path.join(ddcDirectory, 'gen', 'codegen_tests'); |
| + |
| +/// The generated directory where tests and packages compiled to JS are |
| +/// output. |
| +final codegenOutputDir = path.join(ddcDirectory, 'gen', 'codegen_output'); |
| + |
| +// TODO(jmesserly): switch this to a .packages file. |
| +final packageUrlMappings = { |
| + 'package:expect/expect.dart': path.join(codegenDir, 'expect.dart'), |
| + 'package:async_helper/async_helper.dart': |
| + path.join(codegenDir, 'async_helper.dart'), |
| + 'package:js/js.dart': path.join(codegenDir, 'packages', 'js', 'js.dart') |
| +}; |
| + |
| +final codeCoverage = Platform.environment.containsKey('COVERALLS_TOKEN'); |
| + |
| main(arguments) { |
| if (arguments == null) arguments = []; |
| ArgResults args = argParser.parse(arguments); |
| var filePattern = new RegExp(args.rest.length > 0 ? args.rest[0] : '.'); |
| - var expectDir = path.join(inputDir, 'expect'); |
| + var sdkDir = path.join(ddcDirectory, 'gen', 'patched_sdk'); |
| + var analyzerOptions = new AnalyzerOptions( |
| + customUrlMappings: packageUrlMappings, dartSdkPath: sdkDir); |
| + var compiler = new ModuleCompiler(analyzerOptions); |
| + |
| + // Build packages tests depend on. |
| + _buildAllPackages(compiler); |
| + |
| var testDirs = [ |
| 'language', |
| 'corelib', |
| @@ -47,94 +85,60 @@ main(arguments) { |
| path.join('lib', 'typed_data') |
| ]; |
| - var multitests = expandMultiTests(testDirs, filePattern); |
| - |
| - // Build packages tests depend on |
| - var generatedSdkDir = path.join(testDirectory, '..', 'tool', 'generated_sdk'); |
| - var analyzerOptions = new AnalyzerOptions( |
| - customUrlMappings: packageUrlMappings, dartSdkPath: generatedSdkDir); |
| - var compiler = new ModuleCompiler(analyzerOptions); |
| - |
| - group('dartdevc package', () { |
| - _buildPackages(compiler, expectDir); |
| - |
| - test('matcher', () { |
| - _buildPackage(compiler, expectDir, "matcher"); |
| - }); |
| + // Copy all of the test files and expanded multitest files to |
| + // gen/codegen_tests. We'll compile from there. |
| + var testFiles = _setUpTests(testDirs, filePattern); |
| - test('unittest', () { |
| - _buildPackage(compiler, expectDir, "unittest"); |
| - }); |
| + // Our default compiler options. Individual tests can override these. |
| + var defaultOptions = ['--no-source-map', '--no-summarize']; |
| + var compilerArgParser = CompilerOptions.addArguments(new ArgParser()); |
| - test('stack_trace', () { |
| - _buildPackage(compiler, expectDir, "stack_trace"); |
| - }); |
| + // Compile each test file to JS and put the result in gen/codegen_output. |
| + for (var testFile in testFiles) { |
| + var relativePath = path.relative(testFile, from: codegenTestDir); |
| - test('path', () { |
| - _buildPackage(compiler, expectDir, "path"); |
| - }); |
| - }); |
| + // Only compile the top-level files for generating coverage. |
| + if (codeCoverage && path.dirname(relativePath) != ".") continue; |
| - test('dartdevc sunflower', () { |
| - _buildSunflower(compiler, expectDir); |
| - }); |
| + var name = path.withoutExtension(relativePath); |
| + test('dartdevc $name', () { |
| + var outDir = path.join(codegenOutputDir, path.dirname(relativePath)); |
| + _ensureDirectory(outDir); |
| - // Our default compiler options. Individual tests can override these. |
| - var defaultOptions = ['--no-source-map', '--no-summarize']; |
| - var compilerArgParser = CompilerOptions.addArguments(new ArgParser()); |
| + // Check if we need to use special compile options. |
| + var contents = new File(testFile).readAsStringSync(); |
| + var match = |
| + new RegExp(r'// compile options: (.*)').matchAsPrefix(contents); |
| - var allDirs = [null]; |
| - allDirs.addAll(testDirs); |
| - for (var dir in allDirs) { |
| - if (codeCoverage && dir != null) continue; |
| - |
| - group('dartdevc ' + path.join('test', 'codegen', dir), () { |
| - var outDir = new Directory(path.join(expectDir, dir)); |
| - if (!outDir.existsSync()) outDir.createSync(recursive: true); |
| - |
| - var baseDir = path.join(inputDir, dir); |
| - var testFiles = _findTests(baseDir, filePattern); |
| - for (var filePath in testFiles) { |
| - if (multitests.contains(filePath)) continue; |
| - |
| - var filename = path.basenameWithoutExtension(filePath); |
| - |
| - test('$filename.dart', () { |
| - // Check if we need to use special compile options. |
| - var contents = new File(filePath).readAsStringSync(); |
| - var match = |
| - new RegExp(r'// compile options: (.*)').matchAsPrefix(contents); |
| - |
| - var args = new List.from(defaultOptions); |
| - if (match != null) { |
| - args.addAll(match.group(1).split(' ')); |
| - } |
| - var options = |
| - new CompilerOptions.fromArguments(compilerArgParser.parse(args)); |
| - |
| - // Collect any other files we've imported. |
| - var files = new Set<String>(); |
| - _collectTransitiveImports(contents, files, from: filePath); |
| - var moduleName = |
| - path.withoutExtension(path.relative(filePath, from: inputDir)); |
| - var unit = new BuildUnit( |
| - moduleName, baseDir, files.toList(), _moduleForLibrary); |
| - var module = compiler.compile(unit, options); |
| - _writeModule(path.join(outDir.path, filename), module); |
| - }); |
| + var args = defaultOptions.toList(); |
| + if (match != null) { |
| + args.addAll(match.group(1).split(' ')); |
| } |
| + var options = |
| + new CompilerOptions.fromArguments(compilerArgParser.parse(args)); |
| + |
| + // Collect any other files we've imported. |
| + var files = new Set<String>(); |
| + _collectTransitiveImports(contents, files, from: testFile); |
| + var moduleName = |
| + path.withoutExtension(path.relative(testFile, from: codegenTestDir)); |
| + var unit = new BuildUnit( |
| + moduleName, path.dirname(testFile), files.toList(), _moduleForLibrary); |
|
Jennifer Messerly
2016/05/17 17:43:52
some long lines
Bob Nystrom
2016/05/18 00:12:58
Oops! Done.
|
| + var module = compiler.compile(unit, options); |
| + _writeModule(path.join(outDir, path.basenameWithoutExtension(testFile)), module); |
| + |
| }); |
| } |
| if (codeCoverage) { |
| test('build_sdk code coverage', () { |
| - return build_sdk.main(['--dart-sdk', generatedSdkDir, '-o', expectDir]); |
| + return build_sdk.main(['--dart-sdk', sdkDir, '-o', codegenOutputDir]); |
| }); |
| } |
| } |
| void _writeModule(String outPath, JSModuleFile result) { |
| - new Directory(path.dirname(outPath)).createSync(recursive: true); |
| + _ensureDirectory(path.dirname(outPath)); |
| String errors = result.errors.join('\n'); |
| if (errors.isNotEmpty && !errors.endsWith('\n')) errors += '\n'; |
| @@ -166,8 +170,25 @@ void _writeModule(String outPath, JSModuleFile result) { |
| } |
| } |
| -void _buildSunflower(ModuleCompiler compiler, String expectDir) { |
| - var baseDir = path.join(inputDir, 'sunflower'); |
| +void _buildAllPackages(ModuleCompiler compiler) { |
| + group('dartdevc package', () { |
| + _buildPackages(compiler, codegenOutputDir); |
| + |
| + var packages = ['matcher', 'unittest', 'stack_trace', 'path']; |
| + for (var package in packages) { |
| + test(package, () { |
| + _buildPackage(compiler, codegenOutputDir, package); |
| + }); |
| + } |
| + }); |
| + |
| + test('dartdevc sunflower', () { |
| + _buildSunflower(compiler, codegenOutputDir); |
| + }); |
| +} |
| + |
| +void _buildSunflower(ModuleCompiler compiler, String outputDir) { |
| + var baseDir = path.join(codegenDir, 'sunflower'); |
| var files = ['sunflower', 'circle', 'painter'] |
| .map((f) => path.join(baseDir, '$f.dart')) |
| .toList(); |
| @@ -175,10 +196,10 @@ void _buildSunflower(ModuleCompiler compiler, String expectDir) { |
| var options = new CompilerOptions(summarizeApi: false); |
| var built = compiler.compile(input, options); |
| - _writeModule(path.join(expectDir, 'sunflower', 'sunflower'), built); |
| + _writeModule(path.join(outputDir, 'sunflower', 'sunflower'), built); |
| } |
| -void _buildPackages(ModuleCompiler compiler, String expectDir) { |
| +void _buildPackages(ModuleCompiler compiler, String outputDir) { |
| // Note: we don't summarize these, as we're going to rely on our in-memory |
| // shared analysis context for caching, and `_moduleForLibrary` below |
| // understands these are from other modules. |
| @@ -189,19 +210,19 @@ void _buildPackages(ModuleCompiler compiler, String expectDir) { |
| var uriPath = uri.substring('package:'.length); |
| var name = path.basenameWithoutExtension(uriPath); |
| test(name, () { |
| - var input = new BuildUnit(name, inputDir, [uri], _moduleForLibrary); |
| + var input = new BuildUnit(name, codegenDir, [uri], _moduleForLibrary); |
| var built = compiler.compile(input, options); |
| - var outPath = path.join(expectDir, path.withoutExtension(uriPath)); |
| + var outPath = path.join(outputDir, path.withoutExtension(uriPath)); |
| _writeModule(outPath, built); |
| }); |
| } |
| } |
| -void _buildPackage(ModuleCompiler compiler, String expectDir, packageName) { |
| +void _buildPackage(ModuleCompiler compiler, String outputDir, packageName) { |
| var options = new CompilerOptions(sourceMap: false, summarizeApi: false); |
| - var packageRoot = path.join(inputDir, 'packages'); |
| + var packageRoot = path.join(codegenDir, 'packages'); |
| var packageInputDir = path.join(packageRoot, packageName); |
| var files = new Directory(packageInputDir).listSync(recursive: true); |
| @@ -215,7 +236,7 @@ void _buildPackage(ModuleCompiler compiler, String expectDir, packageName) { |
| _moduleForLibrary); |
| var module = compiler.compile(unit, options); |
| - var outPath = path.join(expectDir, packageName, packageName); |
| + var outPath = path.join(outputDir, packageName, packageName); |
| _writeModule(outPath, module); |
| } |
| @@ -227,62 +248,79 @@ String _moduleForLibrary(Source source) { |
| throw new Exception('Module not found for library "${source.fullName}"'); |
| } |
| -/// Expands wacky multitests into a bunch of test files. |
| -/// |
| -/// We'll compile each one as if it was an input. |
| -/// NOTE: this will write the individual test files to disk. |
| -Set<String> expandMultiTests(List testDirs, RegExp filePattern) { |
| - var multitests = new Set<String>(); |
| +List<String> _setUpTests(List<String> testDirs, RegExp filePattern) { |
| + var testFiles = []; |
| for (var testDir in testDirs) { |
| - var fullDir = path.join(inputDir, testDir); |
| - var testFiles = _findTests(fullDir, filePattern); |
| - |
| - for (var filePath in testFiles) { |
| - if (filePath.endsWith('_multi.dart')) continue; |
| - |
| - var contents = new File(filePath).readAsStringSync(); |
| - if (isMultiTest(contents)) { |
| - multitests.add(filePath); |
| + for (var file in _listFiles(path.join(codegenDir, testDir), filePattern, |
| + recursive: true)) { |
| + var relativePath = path.relative(file, from: codegenDir); |
| + var outputPath = path.join(codegenTestDir, relativePath); |
| + |
| + _ensureDirectory(path.dirname(outputPath)); |
| + |
| + // Copy it over. We do this even for multitests because import_self_test |
| + // is a multitest, yet imports its own unexpanded form (!). |
| + new File(file).copySync(outputPath); |
| + |
| + if (file.endsWith("_test.dart")) { |
| + var contents = new File(file).readAsStringSync(); |
| + |
| + if (isMultiTest(contents)) { |
| + // It's a multitest, so expand it and add all of the variants. |
| + var tests = <String, String>{}; |
| + var outcomes = <String, Set<String>>{}; |
| + extractTestsFromMultitest(file, contents, tests, outcomes); |
| + |
| + var fileName = path.basenameWithoutExtension(file); |
| + var outputDir = path.dirname(outputPath); |
| + tests.forEach((name, contents) { |
| + var multiFile = |
| + path.join(outputDir, '${fileName}_${name}_multi.dart'); |
| + testFiles.add(multiFile); |
| + |
| + new File(multiFile).writeAsStringSync(contents); |
| + }); |
| + } else { |
| + // It's a single test suite. |
| + testFiles.add(outputPath); |
| + } |
| + } |
| + } |
| + } |
| - var tests = new Map<String, String>(); |
| - var outcomes = new Map<String, Set<String>>(); |
| - extractTestsFromMultitest(filePath, contents, tests, outcomes); |
| + // Also include the other special files that live at the top level directory. |
| + for (var file in _listFiles(codegenDir, filePattern)) { |
| + var relativePath = path.relative(file, from: codegenDir); |
| + var outputPath = path.join(codegenTestDir, relativePath); |
| - var filename = path.basenameWithoutExtension(filePath); |
| - tests.forEach((name, contents) { |
| - new File(path.join(fullDir, '${filename}_${name}_multi.dart')) |
| - .writeAsStringSync(contents); |
| - }); |
| - } |
| + new File(file).copySync(outputPath); |
| + if (file.endsWith(".dart")) { |
| + testFiles.add(outputPath); |
| } |
| } |
| - return multitests; |
| + |
| + return testFiles; |
| } |
| -// TODO(jmesserly): switch this to a .packages file. |
| -final packageUrlMappings = { |
| - 'package:expect/expect.dart': path.join(inputDir, 'expect.dart'), |
| - 'package:async_helper/async_helper.dart': |
| - path.join(inputDir, 'async_helper.dart'), |
| - 'package:js/js.dart': path.join(inputDir, 'packages', 'js', 'js.dart') |
| -}; |
| +/// Recursively creates [dir] if it doesn't exist. |
| +void _ensureDirectory(String dir) { |
| + new Directory(dir).createSync(recursive: true); |
| +} |
| -final codeCoverage = Platform.environment.containsKey('COVERALLS_TOKEN'); |
| +/// Lists all of the files within [dir] that match [filePattern]. |
| +Iterable<String> _listFiles(String dir, RegExp filePattern, |
| + {bool recursive: false}) { |
| + return new Directory(dir) |
| + .listSync(recursive: recursive, followLinks: false) |
| + .where((entry) { |
| + if (entry is! File) return false; |
| -final inputDir = path.join(testDirectory, 'codegen'); |
| - |
| -Iterable<String> _findTests(String dir, RegExp filePattern) { |
| - var files = new Directory(dir) |
| - .listSync() |
| - .where((f) => f is File) |
| - .map((f) => f.path) |
| - .where((p) => p.endsWith('.dart') && filePattern.hasMatch(p)); |
| - if (dir != inputDir) { |
| - files = files |
| - .where((p) => p.endsWith('_test.dart') || p.endsWith('_multi.dart')); |
| - } |
| - return files; |
| + var filePath = entry.path; |
| + if (!filePattern.hasMatch(filePath)) return false; |
| + |
| + return true; |
| + }).map((file) => file.path); |
| } |
| /// Parse directives from [contents] and find the complete set of transitive |