blob: 930d4106889ab82da6a07f5a013461b36ecb3daa [file] [log] [blame]
// 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);
}
}