// 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. import 'dart:io' hide Link; import 'dart:isolate'; import 'package:compiler/src/compiler.dart'; import 'package:expect/async_helper.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 compilerOptions = const []; const List tests = [ 'diamond', 'diamond_and', 'diamond_fuse', 'diamond_or', 'fuse_with_and', 'fuse_with_or', 'two_step', 'two_branch', 'just_fuse', ]; Map> createPerTestOptions() { Map> 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 getDeferredImports(ir.Component component) { List imports = []; for (var library in component.libraries) { for (var import in library.dependencies) { if (import.isDeferred) { imports.add('${library.importUri}#${import.name}'); } } } imports.sort(); 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 [Future]. Future 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, ); isolate.addOnExitListener(receivePort.sendPort); isolate.resume(isolate.pauseCapability!); String? json; await for (var msg in receivePort) { if (msg == null) { receivePort.close(); } else if (sendPort == null) { sendPort = msg; sendPort!.send(imports); } else if (json == null) { json = msg; } else { throw 'Unexpected message $msg'; } } return json!; } Uri getFileInTestFolder(String test, String file) => Platform.script.resolve('data/$test/$file'); Future 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 verifyCompiler(String test, Compiler compiler) async { var json = await compileConstraintsToJson(test, compiler); Expect.equals(getConstraintsJsonFile(test).readAsStringSync(), json); } /// Generates constraint JSON. Future generateJSON(String test, Compiler compiler) async { var json = await compileConstraintsToJson(test, compiler); getConstraintsJsonFile(test).writeAsStringSync(json); } /// 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 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: () { importPrefixes.clear(); }, testedConfigs: allSpecConfigs, verifyCompiler: generateGoldens ? generateJSON : verifyCompiler, ); }); }