Index: test/codegen_test.dart |
diff --git a/test/codegen_test.dart b/test/codegen_test.dart |
index 8e13891b9f76236f3e7181f2383ed90e07c2b6b3..c2157088166e8f477da07737f1426546c3f9a2c8 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 repoDirectory, 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,48 @@ 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(repoDirectory, 'gen', 'codegen_tests'); |
+ |
+/// The generated directory where tests and packages compiled to JS are |
+/// output. |
+final codegenOutputDir = path.join(repoDirectory, '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(repoDirectory, 'gen', 'patched_sdk'); |
+ var sdkSummaryFile = |
+ path.join(testDirectory, '..', 'lib', 'runtime', 'dart_sdk.sum'); |
+ var analyzerOptions = new AnalyzerOptions( |
+ customUrlMappings: packageUrlMappings, |
+ dartSdkSummaryPath: sdkSummaryFile); |
+ var compiler = new ModuleCompiler(analyzerOptions); |
+ |
+ // Build packages tests depend on. |
+ _buildAllPackages(compiler); |
+ |
var testDirs = [ |
'language', |
'corelib', |
@@ -47,105 +88,60 @@ main(arguments) { |
path.join('lib', 'typed_data') |
]; |
- var multitests = expandMultiTests(testDirs, filePattern); |
+ // Copy all of the test files and expanded multitest files to |
+ // gen/codegen_tests. We'll compile from there. |
+ var testFiles = _setUpTests(testDirs, filePattern); |
- // Build packages tests depend on |
- var sdkSummaryFile = |
- path.join(testDirectory, '..', 'lib', 'runtime', 'dart_sdk.sum'); |
- var analyzerOptions = new AnalyzerOptions( |
- customUrlMappings: packageUrlMappings, |
- dartSdkSummaryPath: sdkSummaryFile); |
- var compiler = new ModuleCompiler(analyzerOptions); |
+ // Our default compiler options. Individual tests can override these. |
+ var defaultOptions = ['--no-source-map', '--no-summarize']; |
+ var compilerArgParser = CompilerOptions.addArguments(new ArgParser()); |
- group('dartdevc package', () { |
- _buildPackages(compiler, expectDir); |
+ // 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('matcher', () { |
- _buildPackage(compiler, expectDir, "matcher"); |
- }); |
+ // Only compile the top-level files for generating coverage. |
+ if (codeCoverage && path.dirname(relativePath) != ".") continue; |
- test('unittest', () { |
- // Only build files applicable to the web - html_*.dart and its |
- // internal dependences. |
- _buildPackage(compiler, expectDir, "unittest", packageFiles: [ |
- 'unittest.dart', |
- 'html_config.dart', |
- 'html_individual_config.dart', |
- 'html_enhanced_config.dart' |
- ]); |
- }); |
+ var name = path.withoutExtension(relativePath); |
+ test('dartdevc $name', () { |
+ var outDir = path.join(codegenOutputDir, path.dirname(relativePath)); |
+ _ensureDirectory(outDir); |
- test('stack_trace', () { |
- _buildPackage(compiler, expectDir, "stack_trace"); |
- }); |
+ // Check if we need to use special compile options. |
+ var contents = new File(testFile).readAsStringSync(); |
+ var match = |
+ new RegExp(r'// compile options: (.*)').matchAsPrefix(contents); |
- test('path', () { |
- _buildPackage(compiler, expectDir, "path"); |
- }); |
- }); |
- |
- test('dartdevc sunflower', () { |
- _buildSunflower(compiler, expectDir); |
- }); |
- |
- // Our default compiler options. Individual tests can override these. |
- var defaultOptions = ['--no-source-map', '--no-summarize']; |
- var compilerArgParser = CompilerOptions.addArguments(new ArgParser()); |
- |
- 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); |
+ var module = compiler.compile(unit, options); |
+ _writeModule( |
+ path.join(outDir, path.basenameWithoutExtension(testFile)), module); |
}); |
} |
if (codeCoverage) { |
test('build_sdk code coverage', () { |
- var generatedSdkDir = |
- path.join(testDirectory, '..', 'tool', 'generated_sdk'); |
- 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'; |
@@ -177,8 +173,36 @@ 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', 'path', 'stack_trace']; |
+ for (var package in packages) { |
+ test(package, () { |
+ _buildPackage(compiler, codegenOutputDir, package); |
+ }); |
+ } |
+ |
+ test('unittest', () { |
+ // Only build files applicable to the web - html_*.dart and its |
+ // internal dependences. |
+ _buildPackage(compiler, codegenOutputDir, "unittest", packageFiles: [ |
+ 'unittest.dart', |
+ 'html_config.dart', |
+ 'html_individual_config.dart', |
+ 'html_enhanced_config.dart' |
+ ]); |
+ }); |
+ }); |
+ |
+ 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(); |
@@ -186,10 +210,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. |
@@ -200,33 +224,33 @@ 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, |
{List<String> packageFiles}) { |
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); |
List<String> files; |
if (packageFiles != null) { |
- // Only collect files transitively reachable from packageFiles |
+ // Only collect files transitively reachable from packageFiles. |
var reachable = new Set<String>(); |
- for (var f in packageFiles) { |
- f = path.join(packageInputDir, f); |
- _collectTransitiveImports(new File(f).readAsStringSync(), reachable, |
- packageRoot: packageRoot, from: f); |
+ for (var file in packageFiles) { |
+ file = path.join(packageInputDir, file); |
+ _collectTransitiveImports(new File(file).readAsStringSync(), reachable, |
+ packageRoot: packageRoot, from: file); |
} |
files = reachable.toList(); |
} else { |
- // Collect all files in the packages directory |
+ // Collect all files in the packages directory. |
files = new Directory(packageInputDir) |
.listSync(recursive: true) |
.where((entry) => entry.path.endsWith('.dart')) |
@@ -238,7 +262,7 @@ void _buildPackage(ModuleCompiler compiler, String expectDir, packageName, |
new BuildUnit(packageName, packageInputDir, files, _moduleForLibrary); |
var module = compiler.compile(unit, options); |
- var outPath = path.join(expectDir, packageName, packageName); |
+ var outPath = path.join(outputDir, packageName, packageName); |
_writeModule(outPath, module); |
} |
@@ -250,62 +274,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 |