| // Copyright (c) 2023, 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' show Directory, File; | |
| import 'package:_fe_analyzer_shared/src/util/options.dart'; | |
| import 'package:front_end/src/api_prototype/experimental_flags.dart' | |
| show | |
| AllowedExperimentalFlags, | |
| ExperimentalFlag, | |
| defaultAllowedExperimentalFlags; | |
| import 'package:kernel/ast.dart' show Component, Version; | |
| import 'package:testing/testing.dart' show TestDescription; | |
| const Option<bool> fixNnbdReleaseVersion = const Option( | |
| '--fix-nnbd-release-version', | |
| const BoolValue(false), | |
| ); | |
| const Option<Uri?> dynamicInterface = const Option( | |
| '--dynamic-interface', | |
| const UriValue(), | |
| ); | |
| const Option<bool> allowDynamicCallsInDynamicModulesOption = const Option( | |
| '--allow-dynamic-calls-in-dynamic-modules', | |
| const BoolValue(false), | |
| ); | |
| const Option<List<String>?> dynamicCallsSelectorAllowListOption = const Option( | |
| '--extra-selectors-allowed-in-dynamic-calls', | |
| const StringListValue(), | |
| ); | |
| const List<Option> testOptionsSpecification = [ | |
| fixNnbdReleaseVersion, | |
| dynamicInterface, | |
| allowDynamicCallsInDynamicModulesOption, | |
| dynamicCallsSelectorAllowListOption, | |
| ]; | |
| class SuiteTestOptions { | |
| final Map<Uri, TestOptions> _testOptions = {}; | |
| /// Computes the test for [description]. | |
| TestOptions computeTestOptions(TestDescription description) { | |
| Directory directory = new File.fromUri(description.uri).parent; | |
| TestOptions? testOptions = _testOptions[directory.uri]; | |
| if (testOptions == null) { | |
| File optionsFile = new File.fromUri( | |
| directory.uri.resolve('test.options'), | |
| ); | |
| Set<Uri> linkDependencies = new Set<Uri>(); | |
| AllowedExperimentalFlags? allowedExperimentalFlags; | |
| Map<ExperimentalFlag, Version>? experimentEnabledVersion; | |
| Map<ExperimentalFlag, Version>? experimentReleasedVersion; | |
| Uri? dynamicInterfaceSpecificationUri; | |
| bool allowDynamicCallsInDynamicModules = false; | |
| List<String> dynamicCallsSelectorAllowList = []; | |
| if (optionsFile.existsSync()) { | |
| List<String> arguments = ParsedOptions.readOptionsFile( | |
| optionsFile.readAsStringSync(), | |
| ); | |
| ParsedOptions parsedOptions = ParsedOptions.parse( | |
| arguments, | |
| testOptionsSpecification, | |
| ); | |
| if (fixNnbdReleaseVersion.read(parsedOptions)) { | |
| // Allow package:allowed_package to use nnbd features from version | |
| // 2.9. | |
| allowedExperimentalFlags = new AllowedExperimentalFlags( | |
| sdkDefaultExperiments: | |
| defaultAllowedExperimentalFlags.sdkDefaultExperiments, | |
| sdkLibraryExperiments: | |
| defaultAllowedExperimentalFlags.sdkLibraryExperiments, | |
| packageExperiments: { | |
| ...defaultAllowedExperimentalFlags.packageExperiments, | |
| 'allowed_package': {ExperimentalFlag.nonNullable}, | |
| }, | |
| ); | |
| experimentEnabledVersion = const { | |
| ExperimentalFlag.nonNullable: const Version(2, 10), | |
| }; | |
| experimentReleasedVersion = const { | |
| ExperimentalFlag.nonNullable: const Version(2, 9), | |
| }; | |
| } | |
| dynamicInterfaceSpecificationUri = dynamicInterface.read(parsedOptions); | |
| allowDynamicCallsInDynamicModules = | |
| allowDynamicCallsInDynamicModulesOption.read(parsedOptions); | |
| dynamicCallsSelectorAllowList = | |
| dynamicCallsSelectorAllowListOption.read(parsedOptions) ?? []; | |
| for (String argument in parsedOptions.arguments) { | |
| Uri uri = description.uri.resolve(argument); | |
| if (!uri.isScheme('package')) { | |
| File f = new File.fromUri(uri); | |
| if (!f.existsSync()) { | |
| throw new UnsupportedError("No file found: $f ($argument)"); | |
| } | |
| uri = f.uri; | |
| } | |
| linkDependencies.add(uri); | |
| } | |
| } | |
| testOptions = new TestOptions( | |
| linkDependencies, | |
| allowedExperimentalFlags: allowedExperimentalFlags, | |
| experimentEnabledVersion: experimentEnabledVersion, | |
| experimentReleasedVersion: experimentReleasedVersion, | |
| dynamicInterfaceSpecificationUri: dynamicInterfaceSpecificationUri, | |
| allowDynamicCallsInDynamicModules: allowDynamicCallsInDynamicModules, | |
| dynamicCallsSelectorAllowList: dynamicCallsSelectorAllowList, | |
| ); | |
| _testOptions[directory.uri] = testOptions; | |
| } | |
| return testOptions; | |
| } | |
| } | |
| /// Options for a single test located within its own subfolder. | |
| /// | |
| /// This is used for instance for defining custom link dependencies and | |
| /// setting up custom experimental flag defaults for a single test. | |
| class TestOptions { | |
| final Set<Uri> linkDependencies; | |
| final AllowedExperimentalFlags? allowedExperimentalFlags; | |
| final Map<ExperimentalFlag, Version>? experimentEnabledVersion; | |
| final Map<ExperimentalFlag, Version>? experimentReleasedVersion; | |
| final Uri? dynamicInterfaceSpecificationUri; | |
| final bool allowDynamicCallsInDynamicModules; | |
| final List<String> dynamicCallsSelectorAllowList; | |
| Component? component; | |
| List<Iterable<String>>? errors; | |
| new( | |
| this.linkDependencies, { | |
| required this.allowedExperimentalFlags, | |
| required this.experimentEnabledVersion, | |
| required this.experimentReleasedVersion, | |
| required this.dynamicInterfaceSpecificationUri, | |
| required this.allowDynamicCallsInDynamicModules, | |
| required this.dynamicCallsSelectorAllowList, | |
| }); | |
| } |