blob: ba9240bd10a9b7acecb921c07d2e34cc3dcfaac0 [file] [log] [blame] [edit]
// 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,
);
}
}