blob: f1e4fd4445912e9c9ce1a77e812ec2ce0cc24f32 [file] [log] [blame]
// Copyright (c) 2021, 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.
// @dart = 2.7
import 'dart:io' hide Link;
import 'dart:isolate';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:expect/expect.dart';
import 'package:kernel/ast.dart' as ir;
import '../equivalence/id_equivalence_helper.dart';
import '../deferred_loading/deferred_loading_test_helper.dart';
/// Add in options to pass to the compiler like
/// `Flags.disableTypeInference` or `Flags.disableInlining`
const List<String> compilerOptions = const [];
const List<String> tests = [
Map<String, List<String>> createPerTestOptions() {
Map<String, List<String>> perTestOptions = {};
for (var test in tests) {
Uri constraints = Platform.script.resolve('data/$test/constraints.json');
perTestOptions['$test'] = ['--read-program-split=$constraints'];
return perTestOptions;
/// Returns a list of the deferred imports in a component where each import
/// becomes a string of 'uri#prefix'.
List<String> getDeferredImports(ir.Component component) {
List<String> imports = [];
for (var library in component.libraries) {
for (var import in library.dependencies) {
if (import.isDeferred) {
return imports;
/// A helper function which performs the following steps:
/// 1) Get deferred imports from a given [component]
/// 2) Spawns the supplied [constraintsUri] in its own isolate
/// 3) Passes deferred imports via a port to the spawned isolate
/// 4) Listens for a json string from the spawned isolated and returns the
/// results as a a [Future<String>].
Future<String> constraintsToJson(
ir.Component component, Uri constraintsUri) async {
var imports = getDeferredImports(component);
SendPort sendPort;
var receivePort = ReceivePort();
var isolate = await Isolate.spawnUri(constraintsUri, [], receivePort.sendPort,
paused: true);
String json;
await for (var msg in receivePort) {
if (msg == null) {
} else if (sendPort == null) {
sendPort = msg;
} else if (json == null) {
json = msg;
} else {
throw 'Unexpected message $msg';
return json;
Uri getFileInTestFolder(String test, String file) =>
Future<String> compileConstraintsToJson(String test, Compiler compiler) async {
var constraints = getFileInTestFolder(test, 'constraints.dart');
var component = compiler.componentForTesting;
return constraintsToJson(component, constraints);
File getConstraintsJsonFile(String test) {
var constraintsJsonUri = getFileInTestFolder(test, 'constraints.json');
return File(constraintsJsonUri.toFilePath());
/// Verifies the programmatic API produces the expected JSON.
Future<void> verifyCompiler(String test, Compiler compiler) async {
var json = await compileConstraintsToJson(test, compiler);
Expect.equals(getConstraintsJsonFile(test).readAsStringSync(), json);
/// Generates constraint JSON.
Future<void> generateJSON(String test, Compiler compiler) async {
var json = await compileConstraintsToJson(test, compiler);
/// Compute the [OutputUnit]s for all source files involved in the test, and
/// ensure that the compiler is correctly calculating what is used and what is
/// not. We expect all test entry points to be in the `data` directory and any
/// or all supporting libraries to be in the `libs` folder, starting with the
/// same name as the original file in `data`.
main(List<String> args) {
bool generateGoldens = args.contains('-g');
asyncTest(() async {
Directory dataDir = Directory.fromUri(Platform.script.resolve('data'));
await checkTests(dataDir, const OutputUnitDataComputer(),
options: compilerOptions,
perTestOptions: createPerTestOptions(),
args: args, setUpFunction: () {
testedConfigs: allSpecConfigs,
verifyCompiler: generateGoldens ? generateJSON : verifyCompiler);