81a2925ac2
This CL also improves the printed messages to include full suite name and timings. Change-Id: I7e2129fb27a91e6ab56269f0ef4ed2c80bf4e786 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/122788 Commit-Queue: Karl Klose <karlklose@google.com> Reviewed-by: Jonas Termansen <sortie@google.com>
192 lines
6.2 KiB
Dart
192 lines
6.2 KiB
Dart
// Copyright (c) 2016, 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.md file.
|
|
|
|
library testing.run_tests;
|
|
|
|
import 'dart:async' show Future;
|
|
|
|
import 'dart:io' show Directory, File, FileSystemEntity;
|
|
|
|
import 'dart:io' as io show exitCode;
|
|
|
|
import 'dart:isolate' show Isolate;
|
|
|
|
import 'error_handling.dart' show withErrorHandling;
|
|
|
|
import 'test_root.dart' show TestRoot;
|
|
|
|
import 'zone_helper.dart' show runGuarded;
|
|
|
|
import 'log.dart' show enableVerboseOutput, isVerbose, StdoutLogger;
|
|
|
|
import 'run.dart' show SuiteRunner, runProgram;
|
|
|
|
class CommandLine {
|
|
final Set<String> options;
|
|
final List<String> arguments;
|
|
|
|
CommandLine(this.options, this.arguments);
|
|
|
|
bool get verbose => options.contains("--verbose") || options.contains("-v");
|
|
|
|
Set<String> get skip => commaSeparated("--skip=");
|
|
|
|
Set<String> commaSeparated(String prefix) {
|
|
return new Set<String>.from(options.expand((String s) {
|
|
if (!s.startsWith(prefix)) return const [];
|
|
s = s.substring(prefix.length);
|
|
return s.split(",");
|
|
}));
|
|
}
|
|
|
|
Map<String, String> get environment {
|
|
Map<String, String> result = <String, String>{};
|
|
for (String option in options) {
|
|
if (option.startsWith("-D")) {
|
|
int equalIndex = option.indexOf("=");
|
|
if (equalIndex != -1) {
|
|
String key = option.substring(2, equalIndex);
|
|
String value = option.substring(equalIndex + 1);
|
|
result[key] = value;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
Set<String> get selectedSuites {
|
|
return selectors.map((String selector) {
|
|
int index = selector.indexOf("/");
|
|
return index == -1 ? selector : selector.substring(0, index);
|
|
}).toSet();
|
|
}
|
|
|
|
Iterable<String> get selectors => arguments;
|
|
|
|
Future<Uri> get configuration async {
|
|
const String configPrefix = "--config=";
|
|
List<String> configurationPaths = options
|
|
.where((String option) => option.startsWith(configPrefix))
|
|
.map((String option) => option.substring(configPrefix.length))
|
|
.toList();
|
|
if (configurationPaths.length > 1) {
|
|
return fail("Only one --config option is supported");
|
|
}
|
|
String configurationPath;
|
|
if (configurationPaths.length == 1) {
|
|
configurationPath = configurationPaths.single;
|
|
File file = new File(configurationPath);
|
|
if (await file.exists()) {
|
|
// If [configurationPath] exists as a file, use the absolute URI. This
|
|
// handles absolute paths on Windows.
|
|
configurationPath = file.absolute.uri.toString();
|
|
}
|
|
} else {
|
|
configurationPath = "testing.json";
|
|
if (!await new File(configurationPath).exists()) {
|
|
Directory test = new Directory("test");
|
|
if (await test.exists()) {
|
|
List<FileSystemEntity> candidates = await test
|
|
.list(recursive: true, followLinks: false)
|
|
.where((FileSystemEntity entity) {
|
|
return entity is File && entity.uri.path.endsWith("/testing.json");
|
|
}).toList();
|
|
switch (candidates.length) {
|
|
case 0:
|
|
return fail("Couldn't locate: '$configurationPath'.");
|
|
|
|
case 1:
|
|
configurationPath = candidates.single.path;
|
|
break;
|
|
|
|
default:
|
|
return fail(
|
|
"Usage: run_tests.dart [$configPrefix=configuration_file]\n"
|
|
"Where configuration_file is one of:\n "
|
|
"${candidates.map((file) => file.path).join('\n ')}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const StdoutLogger()
|
|
.logMessage("Reading configuration file '$configurationPath'.");
|
|
Uri configuration =
|
|
await Isolate.resolvePackageUri(Uri.base.resolve(configurationPath));
|
|
if (configuration == null ||
|
|
!await new File.fromUri(configuration).exists()) {
|
|
return fail("Couldn't locate: '$configurationPath'.");
|
|
}
|
|
return configuration;
|
|
}
|
|
|
|
static CommandLine parse(List<String> arguments) {
|
|
int index = arguments.indexOf("--");
|
|
Set<String> options;
|
|
if (index != -1) {
|
|
options = new Set<String>.from(arguments.getRange(0, index));
|
|
arguments = arguments.sublist(index + 1);
|
|
} else {
|
|
options = arguments.where((argument) => argument.startsWith("-")).toSet();
|
|
arguments =
|
|
arguments.where((argument) => !argument.startsWith("-")).toList();
|
|
}
|
|
return new CommandLine(options, arguments);
|
|
}
|
|
}
|
|
|
|
fail(String message) {
|
|
print(message);
|
|
io.exitCode = 1;
|
|
return null;
|
|
}
|
|
|
|
main(List<String> arguments) => withErrorHandling(() async {
|
|
CommandLine cl = CommandLine.parse(arguments);
|
|
if (cl.verbose) {
|
|
enableVerboseOutput();
|
|
}
|
|
Map<String, String> environment = cl.environment;
|
|
Uri configuration = await cl.configuration;
|
|
if (configuration == null) return;
|
|
if (!isVerbose) {
|
|
print("Use --verbose to display more details.");
|
|
}
|
|
TestRoot root = await TestRoot.fromUri(configuration);
|
|
SuiteRunner runner = new SuiteRunner(
|
|
root.suites, environment, cl.selectors, cl.selectedSuites, cl.skip);
|
|
String program = await runner.generateDartProgram();
|
|
bool hasAnalyzerSuites = await runner.analyze(root.packages);
|
|
Stopwatch sw = new Stopwatch()..start();
|
|
if (program == null) {
|
|
if (!hasAnalyzerSuites) {
|
|
fail("No tests configured.");
|
|
}
|
|
} else {
|
|
await runProgram(program, root.packages);
|
|
}
|
|
print("Running tests took: ${sw.elapsed}.");
|
|
});
|
|
|
|
Future<void> runTests(Map<String, Function> tests) =>
|
|
withErrorHandling<void>(() async {
|
|
int completed = 0;
|
|
for (String name in tests.keys) {
|
|
const StdoutLogger()
|
|
.logTestStart(completed, 0, tests.length, null, null);
|
|
StringBuffer sb = new StringBuffer();
|
|
try {
|
|
await runGuarded(() {
|
|
print("Running test $name");
|
|
return tests[name]();
|
|
}, printLineOnStdout: sb.writeln);
|
|
const StdoutLogger().logMessage(sb);
|
|
} catch (e) {
|
|
print(sb);
|
|
rethrow;
|
|
}
|
|
const StdoutLogger()
|
|
.logTestComplete(++completed, 0, tests.length, null, null);
|
|
}
|
|
});
|