| // 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 'package:_fe_analyzer_shared/src/testing/id.dart'; |
| import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'; |
| import 'package:front_end/src/api_prototype/codes.dart'; |
| import 'package:front_end/src/api_prototype/experimental_flags.dart' as fe; |
| import 'package:front_end/src/api_prototype/testing.dart'; |
| import 'package:kernel/ast.dart'; |
| |
| import 'memory_compiler.dart'; |
| |
| /// Test configuration used for testing CFE in its default state. |
| const DdcTestConfig defaultDdcConfig = DdcTestConfig(ddcMarker, 'ddc'); |
| |
| class DdcTestConfig extends TestConfig { |
| final Map<fe.ExperimentalFlag, bool>? experimentalFlags; |
| |
| const DdcTestConfig(super.marker, super.name, {this.experimentalFlags}); |
| } |
| |
| /// Convert relative file paths into an absolute Uri as expected by the test |
| /// helpers above. |
| Uri toTestUri(String relativePath) => memoryDirectory.resolve(relativePath); |
| |
| /// Create the testing URI used for [fileName] in annotated tests. |
| Uri createUriForFileName(String fileName) => toTestUri(fileName); |
| |
| /// Helper called when an error is found through the id-testing. |
| void onFailure(String message) => throw StateError(message); |
| |
| /// DDC-specific [TestResultData] which holds a [MemoryCompilerResult] as its |
| /// [compilerResult]. |
| class DdcTestResultData |
| extends TestResultData<TestConfig, MemoryCompilerResult> { |
| DdcTestResultData(super.config, super.compilerResult); |
| |
| @override |
| Component get component => compilerResult.ddcResult.component; |
| } |
| |
| /// Base class for computing id-test data from a DDC compilation. |
| abstract class DdcDataComputer<T> |
| extends |
| DataComputer<T, TestConfig, MemoryCompilerResult, DdcTestResultData> { |
| const DdcDataComputer(); |
| } |
| |
| /// Creates a test runner for [dataComputer] on [testedConfigs]. |
| RunTestFunction<T> runTestFor<T>( |
| DdcDataComputer<T> dataComputer, |
| List<DdcTestConfig> testedConfigs, |
| ) { |
| 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 each [testedConfigs]. |
| Future<Map<String, TestResult<T>>> runTest<T>( |
| MarkerOptions markerOptions, |
| TestData testData, |
| DdcDataComputer<T> dataComputer, |
| List<DdcTestConfig> testedConfigs, { |
| required bool testAfterFailures, |
| required bool verbose, |
| required bool succinct, |
| required bool printCode, |
| bool forUserLibrariesOnly = true, |
| Iterable<Id> globalIds = const <Id>[], |
| required void Function(String message) onFailure, |
| Map<String, List<String>>? skipMap, |
| required Uri nullUri, |
| }) async { |
| var results = <String, TestResult<T>>{}; |
| for (var config in testedConfigs) { |
| results[config.marker] = await runTestForConfig( |
| markerOptions, |
| testData, |
| dataComputer, |
| config, |
| fatalErrors: !testAfterFailures, |
| onFailure: onFailure, |
| verbose: verbose, |
| succinct: succinct, |
| printCode: printCode, |
| nullUri: nullUri, |
| ); |
| } |
| return results; |
| } |
| |
| /// Computes the [TestResult] for running [dataComputer] on [testData] for |
| /// the given test [config]. |
| Future<TestResult<T>> runTestForConfig<T>( |
| MarkerOptions markerOptions, |
| TestData testData, |
| DdcDataComputer<T> dataComputer, |
| DdcTestConfig config, { |
| required bool fatalErrors, |
| required bool verbose, |
| required bool succinct, |
| required bool printCode, |
| bool forUserLibrariesOnly = true, |
| Iterable<Id> globalIds = const <Id>[], |
| required void Function(String message) onFailure, |
| required Uri nullUri, |
| }) async { |
| var result = await compileFromMemory( |
| testData.memorySourceFiles, |
| testData.entryPoint, |
| explicitExperimentalFlags: config.experimentalFlags, |
| ); |
| |
| var errors = <FormattedMessage>[]; |
| for (var error in result.errors) { |
| if (error is FormattedMessage) { |
| errors.add(error); |
| } |
| } |
| var testResultData = DdcTestResultData(config, result); |
| return processCompiledResult( |
| markerOptions, |
| testData, |
| dataComputer, |
| testResultData, |
| errors, |
| fatalErrors: fatalErrors, |
| verbose: verbose, |
| succinct: succinct, |
| onFailure: onFailure, |
| nullUri: nullUri, |
| ); |
| } |
| |
| /// Base class for extracting AST-based test data from a DDC compilation. |
| class DdcDataExtractor<T> extends DataExtractor<T> { |
| final MemoryCompilerResult compilerResult; |
| |
| DdcDataExtractor(this.compilerResult, super.actualMap); |
| |
| @override |
| void fail(String message) { |
| onFailure(message); |
| } |
| |
| @override |
| void report(Uri uri, int offset, String message) { |
| printMessageInLocation( |
| compilerResult.ddcResult.component.uriToSource, |
| uri, |
| offset, |
| message, |
| ); |
| } |
| } |