blob: 2a8975ec83e20bbf5507a57245612e86eac024ed [file] [log] [blame]
// Copyright (c) 2017, 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.md file.
library test.kernel.reify.suite;
import 'dart:async' show Future;
import 'dart:io' show Directory, File, Platform;
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:kernel/analyzer/loader.dart'
show DartLoader, DartOptions, createDartSdk;
import 'package:kernel/target/targets.dart' show Target, TargetFlags, getTarget;
import 'package:kernel/repository.dart' show Repository;
import 'kernel_chain.dart'
show MatchExpectation, Print, ReadDill, SanityCheck, WriteDill;
import 'package:testing/testing.dart'
show
Chain,
ChainContext,
Result,
StdioProcess,
Step,
TestDescription,
runMe;
import 'package:kernel/ast.dart' show Program;
import 'package:kernel/transformations/closure_conversion.dart'
as closure_conversion;
import 'package:kernel/transformations/generic_types_reification.dart'
as generic_types_reification;
import 'package:package_config/discovery.dart' show loadPackagesFile;
class TestContext extends ChainContext {
final Uri vm;
final Uri packages;
final DartOptions options;
final DartSdk dartSdk;
final List<Step> steps;
TestContext(String sdk, this.vm, Uri packages, bool strongMode, this.dartSdk,
bool updateExpectations)
: packages = packages,
options = new DartOptions(
strongMode: strongMode,
sdk: sdk,
packagePath: packages.toFilePath()),
steps = <Step>[
const Kernel(),
const Print(),
const SanityCheck(),
const ClosureConversion(),
const GenericTypesReification(),
const Print(),
const SanityCheck(),
new MatchExpectation(".expect",
updateExpectations: updateExpectations),
const WriteDill(),
const ReadDill(),
const Run(),
];
Future<DartLoader> createLoader() async {
Repository repository = new Repository();
return new DartLoader(repository, options, await loadPackagesFile(packages),
dartSdk: dartSdk);
}
}
enum Environment {
directory,
file,
}
Future<String> getEnvironmentVariable(
String name, Environment kind, String undefined, notFound(String n)) async {
String result = Platform.environment[name];
if (result == null) {
throw undefined;
}
switch (kind) {
case Environment.directory:
if (!await new Directory(result).exists()) throw notFound(result);
break;
case Environment.file:
if (!await new File(result).exists()) throw notFound(result);
break;
}
return result;
}
Future<bool> fileExists(Uri base, String path) async {
return await new File.fromUri(base.resolve(path)).exists();
}
Future<TestContext> createContext(
Chain suite, Map<String, String> environment) async {
const String suggestion = """Try building the patched SDK by running
'tools/build.py patched_sdk'""";
// TODO(karlklose): The path is different on MacOS.
String sdk = "out/DebugX64/patched_sdk/";
Uri sdkUri = Uri.base.resolve(sdk);
const String asyncDart = "lib/async/async.dart";
if (!await fileExists(sdkUri, asyncDart)) {
throw "Couldn't find the patched SDK. $suggestion";
}
const String asyncSources = "lib/async/async_sources.gypi";
if (await fileExists(sdkUri, asyncSources)) {
throw "Found '$asyncSources' in '$sdk', so it isn't a patched SDK. "
"$suggestion";
}
// TODO(karlklose): select the VM based on the mode.
Uri vm = Uri.base.resolve("out/ReleaseX64/dart");
Uri packages = Uri.base.resolve(".packages");
bool strongMode = false;
bool updateExpectations = environment["updateExpectations"] == "true";
return new TestContext(sdk, vm, packages, strongMode,
createDartSdk(sdk, strongMode: strongMode), updateExpectations);
}
class Kernel extends Step<TestDescription, Program, TestContext> {
const Kernel();
String get name => "kernel";
Future<Result<Program>> run(
TestDescription description, TestContext testContext) async {
try {
DartLoader loader = await testContext.createLoader();
Target target = getTarget(
"vm", new TargetFlags(strongMode: testContext.options.strongMode));
// reifyTarget is used to add the GTR-specific runtime libraries
// when the program is being loaded
Target reifyTarget = getTarget(
"vmreify",
new TargetFlags(
strongMode: testContext.options.strongMode,
kernelRuntime: Platform.script.resolve('../../runtime/')));
String path = description.file.path;
Uri uri = Uri.base.resolve(path);
Program program = loader.loadProgram(uri, target: reifyTarget);
for (var error in loader.errors) {
return fail(program, "$error");
}
target
..performModularTransformations(program)
..performGlobalTransformations(program);
return pass(program);
} catch (e, s) {
return crash(e, s);
}
}
}
class ClosureConversion extends Step<Program, Program, TestContext> {
const ClosureConversion();
String get name => "closure conversion";
Future<Result<Program>> run(Program program, TestContext testContext) async {
try {
program = closure_conversion.transformProgram(program);
return pass(program);
} catch (e, s) {
return crash(e, s);
}
}
}
class GenericTypesReification extends Step<Program, Program, TestContext> {
const GenericTypesReification();
String get name => "generic types reification";
Future<Result<Program>> run(Program program, TestContext testContext) async {
try {
program = generic_types_reification.transformProgram(program);
return pass(program);
} catch (e, s) {
return crash(e, s);
}
}
}
class Run extends Step<Uri, int, TestContext> {
const Run();
String get name => "run";
Future<Result<int>> run(Uri uri, TestContext context) async {
File generated = new File.fromUri(uri);
StdioProcess process;
try {
process =
await StdioProcess.run(context.vm.toFilePath(), [generated.path]);
print(process.output);
} finally {
generated.parent.delete(recursive: true);
}
return process.toResult();
}
}
main(List<String> arguments) => runMe(arguments, createContext, "testing.json");