blob: 188e32ec33eec58595b5186b905613b6fdd201ea [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 'dart:io' show Directory, File;
import 'package:test/test.dart';
import '../shared_test_options.dart';
import 'test_compiler.dart';
typedef AdditionalLibrary = ({String name, String source});
class ExpressionCompilerTestDriver {
final SetupCompilerOptions setup;
late Directory _testRootDirectory;
String source;
late Uri input;
late Uri output;
late Uri packages;
late int line;
final List<AdditionalLibrary> additionalLibraries;
ExpressionCompilerTestDriver(
this.setup,
this.source, {
this.additionalLibraries = const [],
}) {
line = _getEvaluationLine(source);
var systemTempDir = Directory.systemTemp;
_testRootDirectory = systemTempDir.createTempSync('expression_eval_test');
var testPackageDirectory = Directory.fromUri(
_testRootDirectory.uri.resolve('test_package/'),
);
output = testPackageDirectory.uri.resolve('test.js');
input = testPackageDirectory.uri.resolve('test.dart');
File.fromUri(input)
..createSync(recursive: true)
..writeAsStringSync(source);
packages = _testRootDirectory.uri.resolve('package_config.json');
var packageDescriptors = [_createPackageDescriptor('test_package')];
for (var library in additionalLibraries) {
var name = library.name;
var source = library.source;
var additionalPackageDirectory = Directory.fromUri(
_testRootDirectory.uri.resolve('$name/'),
);
var additionalFile = additionalPackageDirectory.uri.resolve('$name.dart');
File.fromUri(additionalFile)
..createSync(recursive: true)
..writeAsStringSync(source);
packageDescriptors.add(_createPackageDescriptor(name));
}
File.fromUri(packages)
..createSync()
..writeAsStringSync('''
{
"configVersion": 2,
"packages": [
${packageDescriptors.join(',\n ')}
]
}
''');
}
/// Creates a `packages_config.json` entry for a test package called [name].
static String _createPackageDescriptor(String name) =>
'''{
"name": "$name",
"rootUri": "./$name",
"packageUri": "./"
}''';
void delete() {
_testRootDirectory.deleteSync(recursive: true);
}
Future<TestExpressionCompiler> createCompiler() =>
TestExpressionCompiler.init(
setup,
input: input,
output: output,
packages: packages,
);
Future<TestCompilationResult> compile({
required TestExpressionCompiler compiler,
required Map<String, String> scope,
required String expression,
}) async {
return compiler.compileExpression(
libraryUri: input,
line: line,
column: 1,
scope: scope,
expression: expression,
);
}
void checkResult(
TestCompilationResult result, {
String? expectedError,
dynamic expectedResult,
}) {
var success = expectedError == null;
var message = success ? expectedResult! : expectedError;
expect(
result,
const TypeMatcher<TestCompilationResult>()
.having((r) => r.result!, 'result', _matches(message))
.having((r) => r.isSuccess, 'isSuccess', success),
);
}
Future<void> check({
TestExpressionCompiler? compiler,
required Map<String, String> scope,
required String expression,
String? expectedError,
dynamic expectedResult,
}) async {
compiler ??= await createCompiler();
var result = await compile(
compiler: compiler,
scope: scope,
expression: expression,
);
checkResult(
result,
expectedError: expectedError,
expectedResult: expectedResult,
);
}
Matcher _matches(dynamic matcher) {
if (matcher is Matcher) return matcher;
if (matcher is! String) throw StateError('Unsupported matcher $matcher');
var unIndented = RegExp.escape(matcher).replaceAll(RegExp('[ ]+'), '[ ]*');
return matches(RegExp(unIndented, multiLine: true));
}
static int _getEvaluationLine(String source) {
var placeholderRegExp = RegExp(r'// Breakpoint');
var lines = source.split('\n');
for (var line = 0; line < lines.length; line++) {
var content = lines[line];
if (placeholderRegExp.firstMatch(content) != null) {
return line + 1;
}
}
return -1;
}
}