// 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? 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 { 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 extends DataComputer { const DdcDataComputer(); } /// Creates a test runner for [dataComputer] on [testedConfigs]. RunTestFunction runTestFor( DdcDataComputer dataComputer, List testedConfigs) { return (MarkerOptions markerOptions, TestData testData, {required bool testAfterFailures, required bool verbose, required bool succinct, required bool printCode, Map>? 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>> runTest( MarkerOptions markerOptions, TestData testData, DdcDataComputer dataComputer, List testedConfigs, {required bool testAfterFailures, required bool verbose, required bool succinct, required bool printCode, bool forUserLibrariesOnly = true, Iterable globalIds = const [], required void Function(String message) onFailure, Map>? skipMap, required Uri nullUri}) async { var results = >{}; 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> runTestForConfig(MarkerOptions markerOptions, TestData testData, DdcDataComputer dataComputer, DdcTestConfig config, {required bool fatalErrors, required bool verbose, required bool succinct, required bool printCode, bool forUserLibrariesOnly = true, Iterable globalIds = const [], required void Function(String message) onFailure, required Uri nullUri}) async { var result = await compileFromMemory( testData.memorySourceFiles, testData.entryPoint, explicitExperimentalFlags: config.experimentalFlags); var errors = []; 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 extends DataExtractor { 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); } }