Files
sdk/pkg/dev_compiler/test/codegen_test.dart
T

228 lines
8.3 KiB
Dart

// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// 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;
import 'dart:io';
import 'package:cli_util/cli_util.dart' show getSdkDir;
import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine, Logger;
import 'package:analyzer/src/generated/java_engine.dart' show CaughtException;
import 'package:args/args.dart';
import 'package:cli_util/cli_util.dart' show getSdkDir;
import 'package:dev_compiler/devc.dart';
import 'package:dev_compiler/src/options.dart';
import 'package:logging/logging.dart' show Level;
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
final ArgParser argParser = new ArgParser()
..addOption('dart-sdk', help: 'Dart SDK Path', defaultsTo: null)
..addFlag('dart-gen',
abbr: 'd', help: 'Generate dart output', defaultsTo: false);
main(arguments) {
if (arguments == null) arguments = [];
ArgResults args = argParser.parse(arguments);
var script = Platform.script.path;
var dartGen = args['dart-gen'];
var filePattern = new RegExp(args.rest.length > 0 ? args.rest[0] : '.');
var compilerMessages = new StringBuffer();
var loggerSub;
setUp(() {
compilerMessages.clear();
loggerSub = setupLogger(Level.CONFIG, compilerMessages.writeln);
});
tearDown(() {
if (loggerSub != null) {
loggerSub.cancel();
loggerSub = null;
}
});
var testDir = path.absolute(path.dirname(script));
var inputDir = dartGen
? path.join(testDir, 'dart_codegen')
: path.join(testDir, 'codegen');
var actualDir = path.join(inputDir, 'actual');
var paths = new Directory(inputDir)
.listSync()
.where((f) => f is File)
.map((f) => f.path)
.where((p) => p.endsWith('.dart') && filePattern.hasMatch(p));
compile(String entryPoint, String sdkPath,
{bool checkSdk: false, bool serverMode: false}) {
var options = new CompilerOptions(
outputDir: serverMode ? path.join(actualDir, 'server_mode') : actualDir,
useColors: false,
outputDart: dartGen,
formatOutput: dartGen,
emitSourceMaps: false,
forceCompile: checkSdk,
cheapTestFormat: checkSdk,
checkSdk: checkSdk,
entryPointFile: entryPoint,
dartSdkPath: sdkPath,
serverMode: serverMode);
return new Compiler(options).run();
}
var realSdk = getSdkDir(arguments).path;
// Validate that old output is gone before running.
// TODO(jmesserly): it'd be nice to do all cleanup here, including removing
// pub's 'packages' symlinks which mess up the diff. That way this test
// can be self contained instead of depending on a shell script.
if (new Directory(actualDir).existsSync()) {
throw 'Old compiler output should be cleaned up first. Use ./test/test.sh';
}
for (var filePath in paths) {
var filename = path.basenameWithoutExtension(filePath);
test('devc $filename.dart', () {
compilerMessages.writeln('// Messages from compiling $filename.dart');
var result = compile(filePath, realSdk);
var success = !result.failure;
// Write compiler messages to disk.
new File(path.join(actualDir, '$filename.txt'))
.writeAsStringSync(compilerMessages.toString());
var outFile = dartGen
? new File(path.join(actualDir, '$filename/$filename.dart'))
: new File(path.join(actualDir, '$filename.js'));
expect(outFile.existsSync(), success,
reason: '${outFile.path} was created iff compilation succeeds');
// TODO(jmesserly): ideally we'd diff the output here. For now it
// happens in the containing shell script.
});
}
group('sdk', () {
// The analyzer does not bubble exception messages for certain internal
// dart:* library failures, such as failing to find
// "_internal/libraries.dart". Instead it produces an opaque "failed to
// instantiate dart:core" message. To remedy this we hook up an analysis
// logger that prints these messages.
var savedLogger;
setUp(() {
savedLogger = AnalysisEngine.instance.logger;
AnalysisEngine.instance.logger = new PrintLogger();
});
tearDown(() {
AnalysisEngine.instance.logger = savedLogger;
});
test('devc dart:core', () {
// Get the test SDK. We use a checked in copy so test expectations can be
// generated against a specific SDK version.
// TODO(jmesserly): eventually we should track compiler messages.
// For now we're just trying to get decent code generation.
var testSdk = dartGen
? path.join(testDir, '..', 'tool', 'input_sdk')
: path.join(testDir, 'generated_sdk');
var result = compile('dart:core', testSdk, checkSdk: true);
var outputDir = new Directory(path.join(actualDir, 'core'));
var outFile = dartGen
? new File(path.join(actualDir, 'core/core'))
: new File(path.join(actualDir, 'dart/core.js'));
expect(outFile.existsSync(), true,
reason: '${outFile.path} was created for dart:core');
});
});
if (!dartGen) {
test('devc jscodegen html_input.html', () {
var filePath = path.join(inputDir, 'html_input.html');
compilerMessages.writeln('// Messages from compiling html_input.html');
var result = compile(filePath, realSdk);
var success = !result.failure;
// Write compiler messages to disk.
new File(path.join(actualDir, 'html_input.txt'))
.writeAsStringSync(compilerMessages.toString());
var expectedFiles = [
'html_input.html',
'dir/html_input_a.js',
'dir/html_input_b.js',
'dir/html_input_c.js',
'dir/html_input_d.js',
'dir/html_input_e.js',
'dev_compiler/runtime/dart_core.js',
'dev_compiler/runtime/dart_runtime.js',
'dev_compiler/runtime/harmony_feature_check.js',
];
for (var filepath in expectedFiles) {
var outFile = new File(path.join(actualDir, filepath));
expect(outFile.existsSync(), success,
reason: '${outFile.path} was created iff compilation succeeds');
}
var notExpectedFiles = [
'dev_compiler/runtime/messages_widget.js',
'dev_compiler/runtime/messages.css'
];
for (var filepath in notExpectedFiles) {
var outFile = new File(path.join(actualDir, filepath));
expect(outFile.existsSync(), isFalse,
reason: '${outFile.path} should only be generated in server mode');
}
});
test('devc jscodegen html_input.html server mode', () {
var filePath = path.join(inputDir, 'html_input.html');
compilerMessages.writeln('// Messages from compiling html_input.html');
var result = compile(filePath, realSdk, serverMode: true);
var success = !result.failure;
// Write compiler messages to disk.
new File(path.join(actualDir, 'server_mode', 'html_input.txt'))
.writeAsStringSync(compilerMessages.toString());
var expectedFiles = [
'html_input.html',
'dir/html_input_a.js',
'dir/html_input_b.js',
'dir/html_input_c.js',
'dir/html_input_d.js',
'dir/html_input_e.js',
'dev_compiler/runtime/dart_core.js',
'dev_compiler/runtime/dart_runtime.js',
'dev_compiler/runtime/harmony_feature_check.js',
'dev_compiler/runtime/messages_widget.js',
'dev_compiler/runtime/messages.css'
];
for (var filepath in expectedFiles) {
var outFile = new File(path.join(actualDir, 'server_mode', filepath));
expect(outFile.existsSync(), success,
reason: '${outFile.path} was created iff compilation succeeds');
}
});
}
}
/// An implementation of analysis engine's [Logger] that prints.
class PrintLogger implements Logger {
@override void logError(String message, [CaughtException exception]) {
print('[AnalysisEngine] error $message $exception');
}
@override void logError2(String message, Object exception) {
print('[AnalysisEngine] error $message $exception');
}
void logInformation(String message, [CaughtException exception]) {}
void logInformation2(String message, Object exception) {}
}