| // Copyright (c) 2019, 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 'package:_fe_analyzer_shared/src/messages/severity.dart' | |
| show CfeSeverity; | |
| import 'package:_fe_analyzer_shared/src/testing/id.dart' | |
| show DataRegistry, Id, ActualDataMap; | |
| import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'; | |
| import 'package:kernel/ast.dart'; | |
| import 'package:kernel/target/targets.dart'; | |
| import '../api_prototype/compiler_options.dart' | |
| show CompilerOptions, CfeDiagnosticMessage; | |
| import '../api_prototype/experimental_flags.dart' | |
| show AllowedExperimentalFlags, ExperimentalFlag; | |
| import '../api_prototype/terminal_color_support.dart' | |
| show printDiagnosticMessage; | |
| import '../base/common.dart'; | |
| import '../base/messages.dart' show FormattedMessage; | |
| import '../kernel_generator_impl.dart' show InternalCompilerResult; | |
| import 'compiler_common.dart' show compileScript, toTestUri; | |
| import 'id_extractor.dart' show DataExtractor; | |
| import 'kernel_id_testing.dart'; | |
| export '../base/compiler_context.dart' show CompilerContext; | |
| export '../base/messages.dart' show FormattedMessage; | |
| export '../kernel_generator_impl.dart' show InternalCompilerResult; | |
| /// Test configuration used for testing CFE in its default state. | |
| const CfeTestConfig defaultCfeConfig = const CfeTestConfig(cfeMarker, 'cfe'); | |
| class CfeTestConfig extends TestConfig { | |
| final Map<ExperimentalFlag, bool> explicitExperimentalFlags; | |
| final AllowedExperimentalFlags? allowedExperimentalFlags; | |
| final Uri? librariesSpecificationUri; | |
| final Uri? packageConfigUri; | |
| // TODO(johnniwinther): Tailor support to redefine selected platform | |
| // classes/members only. | |
| final bool compileSdk; | |
| final TestTargetFlags targetFlags; | |
| const new( | |
| super.marker, | |
| super.name, { | |
| this.explicitExperimentalFlags = const {}, | |
| this.allowedExperimentalFlags, | |
| this.librariesSpecificationUri, | |
| this.packageConfigUri, | |
| this.compileSdk = false, | |
| this.targetFlags = const TestTargetFlags(), | |
| }); | |
| /// Called before running test on [testData]. | |
| /// | |
| /// This allows tests to customize the [options] based on the [testData]. | |
| /// | |
| /// A custom object can be returned. This is passed to data computer. | |
| dynamic customizeCompilerOptions( | |
| CompilerOptions options, | |
| TestData testData, | |
| ) => null; | |
| /// Called after running test on [testData] with the resulting | |
| /// [testResultData]. | |
| void onCompilationResult( | |
| MarkerOptions markerOptions, | |
| TestData testData, | |
| CfeTestResultData testResultData, | |
| ) {} | |
| } | |
| abstract class CfeDataComputer<T> | |
| extends | |
| DataComputer< | |
| T, | |
| CfeTestConfig, | |
| InternalCompilerResult, | |
| CfeTestResultData | |
| > { | |
| const new(); | |
| } | |
| /// Auxiliary data from running a test. | |
| class CfeTestResultData | |
| extends TestResultData<CfeTestConfig, InternalCompilerResult> { | |
| /// CustomData is passed from [CfeTestConfig.customizeCompilerOptions]. | |
| final dynamic customData; | |
| new(super.config, this.customData, super.compilerResult); | |
| @override | |
| Component get component => compilerResult.component!; | |
| } | |
| mixin CfeDataRegistryMixin<T> implements DataRegistry<T> { | |
| InternalCompilerResult get compilerResult; | |
| @override | |
| void report(Uri uri, int offset, String message) { | |
| printMessageInLocation( | |
| compilerResult.component!.uriToSource, | |
| uri, | |
| offset, | |
| message, | |
| ); | |
| } | |
| @override | |
| void fail(String message) { | |
| onFailure(message); | |
| } | |
| } | |
| class CfeDataRegistry<T> with DataRegistry<T>, CfeDataRegistryMixin<T> { | |
| @override | |
| final InternalCompilerResult compilerResult; | |
| @override | |
| final ActualDataMap<T> actualMap; | |
| new(this.compilerResult, this.actualMap); | |
| } | |
| abstract class CfeDataExtractor<T> extends DataExtractor<T> | |
| with CfeDataRegistryMixin<T> { | |
| @override | |
| final InternalCompilerResult compilerResult; | |
| new(this.compilerResult, super.actualMap); | |
| } | |
| /// Create the testing URI used for [fileName] in annotated tests. | |
| Uri createUriForFileName(String fileName) => toTestUri(fileName); | |
| void onFailure(String message) => throw new StateError(message); | |
| /// Creates a test runner for [dataComputer] on [testedConfigs]. | |
| RunTestFunction<T> runTestFor<T>( | |
| CfeDataComputer<T> dataComputer, | |
| List<CfeTestConfig> testedConfigs, | |
| ) { | |
| retainDataForTesting = true; | |
| return ( | |
| MarkerOptions markerOptions, | |
| TestData testData, { | |
| required bool testAfterFailures, | |
| required bool verbose, | |
| required bool succinct, | |
| required bool printCode, | |
| Map<String, List<String>>? skipMap, | |
| required Uri nullUri, | |
| }) { | |
| return runTest( | |
| markerOptions, | |
| testData, | |
| dataComputer, | |
| testedConfigs, | |
| testAfterFailures: testAfterFailures, | |
| verbose: verbose, | |
| succinct: succinct, | |
| printCode: printCode, | |
| onFailure: onFailure, | |
| skipMap: skipMap, | |
| nullUri: nullUri, | |
| ); | |
| }; | |
| } | |
| /// Runs [dataComputer] on [testData] for all [testedConfigs]. | |
| /// | |
| /// Returns `true` if an error was encountered. | |
| Future<Map<String, TestResult<T>>> runTest<T>( | |
| MarkerOptions markerOptions, | |
| TestData testData, | |
| CfeDataComputer<T> dataComputer, | |
| List<CfeTestConfig> testedConfigs, { | |
| required bool testAfterFailures, | |
| required bool verbose, | |
| required bool succinct, | |
| required bool printCode, | |
| bool forUserLibrariesOnly = true, | |
| Iterable<Id> globalIds = const <Id>[], | |
| required void onFailure(String message), | |
| Map<String, List<String>>? skipMap, | |
| required Uri nullUri, | |
| }) async { | |
| for (CfeTestConfig config in testedConfigs) { | |
| if (!testData.expectedMaps.containsKey(config.marker)) { | |
| throw new ArgumentError( | |
| "Unexpected test marker '${config.marker}'. " | |
| "Supported markers: ${testData.expectedMaps.keys}.", | |
| ); | |
| } | |
| } | |
| Map<String, TestResult<T>> results = {}; | |
| for (CfeTestConfig config in testedConfigs) { | |
| if (skipForConfig(testData.name, config.marker, skipMap)) { | |
| continue; | |
| } | |
| results[config.marker] = await runTestForConfig( | |
| markerOptions, | |
| testData, | |
| dataComputer, | |
| config, | |
| fatalErrors: !testAfterFailures, | |
| onFailure: onFailure, | |
| verbose: verbose, | |
| succinct: succinct, | |
| printCode: printCode, | |
| nullUri: nullUri, | |
| ); | |
| } | |
| return results; | |
| } | |
| /// Runs [dataComputer] on [testData] for [config]. | |
| /// | |
| /// Returns `true` if an error was encountered. | |
| Future<TestResult<T>> runTestForConfig<T>( | |
| MarkerOptions markerOptions, | |
| TestData testData, | |
| CfeDataComputer<T> dataComputer, | |
| CfeTestConfig config, { | |
| required bool fatalErrors, | |
| required bool verbose, | |
| required bool succinct, | |
| required bool printCode, | |
| bool forUserLibrariesOnly = true, | |
| Iterable<Id> globalIds = const <Id>[], | |
| required void onFailure(String message), | |
| required Uri nullUri, | |
| }) async { | |
| CompilerOptions options = new CompilerOptions(); | |
| List<FormattedMessage> errors = []; | |
| options.onDiagnostic = (CfeDiagnosticMessage message) { | |
| if (message is FormattedMessage && message.severity == CfeSeverity.error) { | |
| errors.add(message); | |
| } | |
| if (!succinct) printDiagnosticMessage(message, print); | |
| }; | |
| options.debugDump = printCode; | |
| options.target = new TestTargetWrapper( | |
| new NoneTarget(config.targetFlags), | |
| config.targetFlags, | |
| ); | |
| options.explicitExperimentalFlags.addAll(config.explicitExperimentalFlags); | |
| options.allowedExperimentalFlagsForTesting = config.allowedExperimentalFlags; | |
| if (config.librariesSpecificationUri != null) { | |
| Set<Uri> testFiles = testData.memorySourceFiles.keys | |
| .map(createUriForFileName) | |
| .toSet(); | |
| if (testFiles.contains(config.librariesSpecificationUri)) { | |
| options.librariesSpecificationUri = config.librariesSpecificationUri; | |
| options.compileSdk = config.compileSdk; | |
| } | |
| } | |
| options.packagesFileUri = config.packageConfigUri; | |
| dynamic customData = config.customizeCompilerOptions(options, testData); | |
| InternalCompilerResult compilerResult = await compileScript( | |
| testData.memorySourceFiles, | |
| options: options, | |
| retainDataForTesting: true, | |
| requireMain: false, | |
| ) as InternalCompilerResult; | |
| CfeTestResultData testResultData = new CfeTestResultData( | |
| config, | |
| customData, | |
| compilerResult, | |
| ); | |
| config.onCompilationResult(markerOptions, testData, testResultData); | |
| return processCompiledResult( | |
| markerOptions, | |
| testData, | |
| dataComputer, | |
| testResultData, | |
| errors, | |
| fatalErrors: fatalErrors, | |
| verbose: verbose, | |
| succinct: succinct, | |
| onFailure: onFailure, | |
| nullUri: nullUri, | |
| ); | |
| } |