159 lines
5.4 KiB
Dart
159 lines
5.4 KiB
Dart
|
|
// Copyright (c) 2015, 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:async';
|
||
|
|
import 'dart:io';
|
||
|
|
import 'dart:isolate';
|
||
|
|
|
||
|
|
import 'package:path/path.dart' as p;
|
||
|
|
import 'package:test/test.dart';
|
||
|
|
import 'package:test_descriptor/test_descriptor.dart' as d;
|
||
|
|
import 'package:test_process/test_process.dart';
|
||
|
|
|
||
|
|
/// The path to the root directory of the `test` package.
|
||
|
|
final Future<String> packageDir =
|
||
|
|
Isolate.resolvePackageUri(Uri(scheme: 'package', path: 'test/'))
|
||
|
|
.then((uri) {
|
||
|
|
var dir = p.dirname(uri!.path);
|
||
|
|
// If it starts with a `/C:` or other drive letter, remove the leading `/`.
|
||
|
|
if (dir[0] == '/' && dir[2] == ':') dir = dir.substring(1);
|
||
|
|
return dir;
|
||
|
|
});
|
||
|
|
|
||
|
|
/// The path to the `pub` executable in the current Dart SDK.
|
||
|
|
final _pubPath = p.absolute(p.join(p.dirname(Platform.resolvedExecutable),
|
||
|
|
Platform.isWindows ? 'pub.bat' : 'pub'));
|
||
|
|
|
||
|
|
/// The platform-specific message emitted when a nonexistent file is loaded.
|
||
|
|
final String noSuchFileMessage = Platform.isWindows
|
||
|
|
? 'The system cannot find the file specified.'
|
||
|
|
: 'No such file or directory';
|
||
|
|
|
||
|
|
/// An operating system name that's different than the current operating system.
|
||
|
|
final otherOS = Platform.isWindows ? 'mac-os' : 'windows';
|
||
|
|
|
||
|
|
/// Expects that the entire stdout stream of [test] equals [expected].
|
||
|
|
void expectStdoutEquals(TestProcess test, String expected) =>
|
||
|
|
_expectStreamEquals(test.stdoutStream(), expected);
|
||
|
|
|
||
|
|
/// Expects that the entire stderr stream of [test] equals [expected].
|
||
|
|
void expectStderrEquals(TestProcess test, String expected) =>
|
||
|
|
_expectStreamEquals(test.stderrStream(), expected);
|
||
|
|
|
||
|
|
/// Expects that the entirety of the line stream [stream] equals [expected].
|
||
|
|
void _expectStreamEquals(Stream<String> stream, String expected) {
|
||
|
|
expect((() async {
|
||
|
|
var lines = await stream.toList();
|
||
|
|
expect(lines.join('\n').trim(), equals(expected.trim()));
|
||
|
|
})(), completes);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Returns a [StreamMatcher] that asserts that the stream emits strings
|
||
|
|
/// containing each string in [strings] in order.
|
||
|
|
///
|
||
|
|
/// This expects each string in [strings] to match a different string in the
|
||
|
|
/// stream.
|
||
|
|
StreamMatcher containsInOrder(Iterable<String> strings) =>
|
||
|
|
emitsInOrder(strings.map((string) => emitsThrough(contains(string))));
|
||
|
|
|
||
|
|
/// Lazily compile the test package to kernel and re-use that, initialized with
|
||
|
|
/// [precompileTestExecutable].
|
||
|
|
String? _testExecutablePath;
|
||
|
|
|
||
|
|
/// Must be invoked before any call to [runTests], should be invoked in a top
|
||
|
|
/// level `setUpAll` for best caching results.
|
||
|
|
Future<void> precompileTestExecutable() async {
|
||
|
|
if (_testExecutablePath != null) {
|
||
|
|
throw StateError('Test executable already precompiled');
|
||
|
|
}
|
||
|
|
var tmpDirectory = await Directory.systemTemp.createTemp('test');
|
||
|
|
var precompiledPath = p.join(tmpDirectory.path, 'test_runner.dill');
|
||
|
|
var result = await Process.run(Platform.executable, [
|
||
|
|
'compile',
|
||
|
|
'kernel',
|
||
|
|
p.url.join(await packageDir, 'bin', 'test.dart'),
|
||
|
|
'-o',
|
||
|
|
precompiledPath,
|
||
|
|
]);
|
||
|
|
if (result.exitCode != 0) {
|
||
|
|
throw StateError(
|
||
|
|
'Failed to compile test runner:\n${result.stdout}\n${result.stderr}');
|
||
|
|
}
|
||
|
|
|
||
|
|
addTearDown(() async {
|
||
|
|
await tmpDirectory.delete(recursive: true);
|
||
|
|
});
|
||
|
|
_testExecutablePath = precompiledPath;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Runs the test executable with the package root set properly.
|
||
|
|
///
|
||
|
|
/// You must invoke [precompileTestExecutable] before invoking this function.
|
||
|
|
Future<TestProcess> runTest(Iterable<String> args,
|
||
|
|
{String? reporter,
|
||
|
|
String? fileReporter,
|
||
|
|
int? concurrency,
|
||
|
|
Map<String, String>? environment,
|
||
|
|
bool forwardStdio = false,
|
||
|
|
String? packageConfig,
|
||
|
|
Iterable<String>? vmArgs}) async {
|
||
|
|
concurrency ??= 1;
|
||
|
|
var testExecutablePath = _testExecutablePath;
|
||
|
|
if (testExecutablePath == null) {
|
||
|
|
throw StateError(
|
||
|
|
'You must call `precompileTestExecutable` before calling `runTest`');
|
||
|
|
}
|
||
|
|
|
||
|
|
var allArgs = [
|
||
|
|
...?vmArgs,
|
||
|
|
testExecutablePath,
|
||
|
|
'--concurrency=$concurrency',
|
||
|
|
if (reporter != null) '--reporter=$reporter',
|
||
|
|
if (fileReporter != null) '--file-reporter=$fileReporter',
|
||
|
|
...args,
|
||
|
|
];
|
||
|
|
|
||
|
|
environment ??= {};
|
||
|
|
environment.putIfAbsent('_DART_TEST_TESTING', () => 'true');
|
||
|
|
|
||
|
|
return await runDart(allArgs,
|
||
|
|
environment: environment,
|
||
|
|
description: 'dart bin/test.dart',
|
||
|
|
forwardStdio: forwardStdio,
|
||
|
|
packageConfig: packageConfig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Runs Dart.
|
||
|
|
///
|
||
|
|
/// If [packageConfig] is provided then that is passed for the `--packages`
|
||
|
|
/// arg, otherwise the current isolate config is passed.
|
||
|
|
Future<TestProcess> runDart(Iterable<String> args,
|
||
|
|
{Map<String, String>? environment,
|
||
|
|
String? description,
|
||
|
|
bool forwardStdio = false,
|
||
|
|
String? packageConfig}) async {
|
||
|
|
var allArgs = <String>[
|
||
|
|
...Platform.executableArguments.where((arg) =>
|
||
|
|
!arg.startsWith('--package-root=') && !arg.startsWith('--packages=')),
|
||
|
|
'--packages=${packageConfig ?? await Isolate.packageConfig}',
|
||
|
|
...args
|
||
|
|
];
|
||
|
|
|
||
|
|
return await TestProcess.start(
|
||
|
|
p.absolute(Platform.resolvedExecutable), allArgs,
|
||
|
|
workingDirectory: d.sandbox,
|
||
|
|
environment: environment,
|
||
|
|
description: description,
|
||
|
|
forwardStdio: forwardStdio);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Runs Pub.
|
||
|
|
Future<TestProcess> runPub(Iterable<String> args,
|
||
|
|
{Map<String, String>? environment}) {
|
||
|
|
return TestProcess.start(_pubPath, args,
|
||
|
|
workingDirectory: d.sandbox,
|
||
|
|
environment: environment,
|
||
|
|
description: 'pub ${args.first}');
|
||
|
|
}
|