blob: d03d11a40e9133fbb3abf21645c4e1c2fb8b12e8 [file] [edit]
// Copyright (c) 2018, 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:dwds/expression_compiler.dart';
import 'package:dwds_test_common/test_sdk_configuration.dart';
import 'package:dwds_test_common/test_sdk_layout.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'package:test_process/test_process.dart';
final _webdevBin = p.absolute(p.join('bin', 'webdev.dart'));
class TestRunner {
late TestSdkConfigurationProvider sdkConfigurationProvider;
late TestSdkLayout sdkLayout;
final bool canaryFeatures;
final ModuleFormat ddcModuleFormat;
final bool webHotReload;
TestRunner({
this.canaryFeatures = false,
this.ddcModuleFormat = ModuleFormat.amd,
this.webHotReload = false,
});
Future<void> setUpAll({bool verbose = false}) async {
// Generate missing SDK assets if needed.
sdkConfigurationProvider = TestSdkConfigurationProvider(
verbose: verbose,
canaryFeatures: canaryFeatures,
ddcModuleFormat: ddcModuleFormat,
);
sdkLayout = sdkConfigurationProvider.sdkLayout;
try {
// Make sure configuration was created correctly.
final configuration = await sdkConfigurationProvider.configuration;
configuration.validate();
} catch (_) {
tearDownAll();
rethrow;
}
}
void tearDownAll() {
sdkConfigurationProvider.dispose();
}
/// Runs 'webdev' with [args] in [workingDirectory], injecting additional
/// flags if necessary.
///
/// Setting [raw] passes [args] without additional processing.
Future<TestProcess> runWebDev(
List<String> args, {
String? workingDirectory,
bool raw = false,
}) async {
final fullArgs = [_webdevBin, ...args];
// 'help' doesn't accept additional args.
final isHelp =
args.contains('help') || args.contains('--help') || args.contains('-h');
if (!raw && !isHelp) {
if (canaryFeatures) {
final dashDashIndex = fullArgs.indexOf('--');
if (dashDashIndex != -1) {
fullArgs.insertAll(dashDashIndex, ['--canary']);
} else {
fullArgs.add('--canary');
}
}
if (webHotReload) {
final dashDashIndex = fullArgs.indexOf('--');
if (dashDashIndex != -1) {
fullArgs.insertAll(dashDashIndex, ['--web-hot-reload']);
} else {
fullArgs.add('--web-hot-reload');
}
}
final moduleFormatStr = ddcModuleFormat == ModuleFormat.ddc
? 'ddc'
: 'amd';
final dashDashIndex = fullArgs.indexOf('--');
final extraArgs = ['--module-format', moduleFormatStr];
if (dashDashIndex != -1) {
fullArgs.insertAll(dashDashIndex, extraArgs);
} else {
fullArgs.addAll(extraArgs);
}
}
return TestProcess.start(
sdkLayout.dartPath,
fullArgs,
workingDirectory: workingDirectory,
);
}
/// Copies [source] to [destination], skipping '.dart_tool' to ignore built
/// output from previous runs.
void _copyCleanDirectory(Directory source, Directory destination) {
destination.createSync(recursive: true);
for (final entity in source.listSync(recursive: false)) {
if (entity is Directory) {
if (p.basename(entity.path) == '.dart_tool') continue;
final newDirectory = Directory(
p.join(destination.absolute.path, p.basename(entity.path)),
);
newDirectory.createSync(recursive: true);
_copyCleanDirectory(entity.absolute, newDirectory);
} else if (entity is File) {
entity.copySync(p.join(destination.path, p.basename(entity.path)));
}
}
}
Future<String> prepareWorkspace() async {
final originalDirectory = _webdevSmokeFixturePath();
final tempDir = Directory.systemTemp.createTempSync('webdev_smoke_');
final exampleDirectory = tempDir.path;
_copyCleanDirectory(Directory(originalDirectory), tempDir);
final process = await TestProcess.start(
sdkLayout.dartPath,
['pub', 'upgrade'],
workingDirectory: exampleDirectory,
environment: getPubEnvironment(),
);
await process.shouldExit(0);
return exampleDirectory;
}
}
Future checkProcessStdout(TestProcess process, List items) async {
for (var item in items) {
if (item is! Matcher) {
item = contains(item);
}
await expectLater(process.stdout, emitsThrough(item));
}
}
/// Returns an environment map that includes `PUB_ENVIRONMENT`.
///
/// Maintains any existing values for this environment var.
/// Adds a new value that flags this is a bot/test and not human usage.
Map<String, String> getPubEnvironment() {
final pubEnvironmentKey = 'PUB_ENVIRONMENT';
var pubEnvironment = Platform.environment[pubEnvironmentKey] ?? '';
if (pubEnvironment.isNotEmpty) {
pubEnvironment = '$pubEnvironment;';
}
pubEnvironment = '${pubEnvironment}bot.pkg.webdev.test';
final environment = {'PUB_ENVIRONMENT': pubEnvironment};
return environment;
}
/// The path to the `_webdev_smoke` fixture in `package:dwds_test_common`.
String _webdevSmokeFixturePath() {
final utilitiesUri = Isolate.resolvePackageUriSync(
Uri.parse('package:dwds_test_common/utilities.dart'),
);
if (utilitiesUri == null) {
throw StateError('Unable to resolve package:dwds_test_common.');
}
// Strip `lib/utilities.dart`.
final packageRoot = p.dirname(p.dirname(utilitiesUri.toFilePath()));
return p.join(packageRoot, 'fixtures', '_webdev_smoke');
}