| // 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; | |
| } | |
| } |