mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 10:48:25 +00:00
Catch the test_runner codebase up to somewhat modern practices.
- Run dartfmt --fix. This converts JavaDoc comments to "///", removes "new" and extraneous "const", and a couple of other things. - Fix SCREAMING_CAPS constants to lowerCamelCase. - Use collection literals where possible. - Use UI-as-code in a couple of places where it seemed obvious. - Use "var" for more local variables. - Use "const" instead of "final" when possible. - Make members private when possible. Deleted a few that then became obviously unused. - ".length > 0" -> ".isNotEmpty". There are no meaningful changes. Change-Id: Ic6c5a74b2af9b3ebcbe881dbed69f65488bdef09 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105880 Commit-Queue: Bob Nystrom <rnystrom@google.com> Reviewed-by: William Hesse <whesse@google.com>
This commit is contained in:
parent
99e8a9fba5
commit
c1b56a9ea0
|
@ -8,7 +8,7 @@ import 'package:test_runner/src/utils.dart';
|
|||
import 'package:test_runner/src/vendored_pkg/args/args.dart';
|
||||
|
||||
void main(List<String> arguments) {
|
||||
var parser = new ArgParser();
|
||||
var parser = ArgParser();
|
||||
parser.addOption('port',
|
||||
abbr: 'p',
|
||||
help: 'The main server port we wish to respond to requests.',
|
||||
|
@ -33,7 +33,7 @@ void main(List<String> arguments) {
|
|||
if (args['help'] as bool) {
|
||||
print(parser.getUsage());
|
||||
} else {
|
||||
var servers = new TestingServers(
|
||||
var servers = TestingServers(
|
||||
args['build-directory'] as String,
|
||||
args['csp'] as bool,
|
||||
Runtime.find(args['runtime'] as String),
|
||||
|
|
|
@ -2,13 +2,11 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* Simple command line interface to launching browsers.
|
||||
* Uses the browser_controller framework.
|
||||
* The usage is:
|
||||
* DARTBIN launch_browser.dart BROWSER_NAME URL
|
||||
* DARTBIN should be the checked in stable binary.
|
||||
*/
|
||||
/// Simple command line interface to launching browsers.
|
||||
/// Uses the browser_controller framework.
|
||||
/// The usage is:
|
||||
/// DARTBIN launch_browser.dart BROWSER_NAME URL
|
||||
/// DARTBIN should be the checked in stable binary.
|
||||
|
||||
import 'package:test_runner/src/browser_controller.dart';
|
||||
import 'package:test_runner/src/configuration.dart';
|
||||
|
@ -16,7 +14,7 @@ import 'package:test_runner/src/configuration.dart';
|
|||
void printHelp() {
|
||||
print("Usage pattern:");
|
||||
print("launch_browser.dart browser url");
|
||||
print("Supported browsers: ${Browser.SUPPORTED_BROWSERS}");
|
||||
print("Supported browsers: ${Browser.supportedBrowsers}");
|
||||
}
|
||||
|
||||
void main(List<String> arguments) {
|
||||
|
@ -34,10 +32,10 @@ void main(List<String> arguments) {
|
|||
}
|
||||
|
||||
var runtime = Runtime.find(name);
|
||||
var configuration = new TestConfiguration(
|
||||
configuration: new Configuration(
|
||||
var configuration = TestConfiguration(
|
||||
configuration: Configuration(
|
||||
"dummy configuration", null, null, null, runtime, null));
|
||||
var executable = configuration.browserLocation;
|
||||
var browser = new Browser.byRuntime(runtime, executable);
|
||||
var browser = Browser.byRuntime(runtime, executable);
|
||||
browser.start(arguments[1]);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ void main(List<String> arguments) {
|
|||
Repository.uri = Uri.base;
|
||||
var configurations = <TestConfiguration>[];
|
||||
for (var argument in arguments) {
|
||||
configurations.addAll(new OptionsParser().parse(argument.split(" ")));
|
||||
configurations.addAll(OptionsParser().parse(argument.split(" ")));
|
||||
}
|
||||
testConfigurations(configurations);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import "package:test_runner/src/test_configurations.dart";
|
|||
/// Runs all of the tests specified by the given command line [arguments].
|
||||
void main(List<String> arguments) {
|
||||
// Parse the command line arguments to a configuration.
|
||||
var parser = new OptionsParser();
|
||||
var parser = OptionsParser();
|
||||
var configurations = parser.parse(arguments);
|
||||
if (configurations == null || configurations.isEmpty) return;
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
// Copyright (c) 2013, 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.
|
||||
|
||||
library android;
|
||||
|
||||
import "dart:async";
|
||||
import "dart:convert" show LineSplitter, utf8;
|
||||
import "dart:core";
|
||||
|
@ -30,18 +27,16 @@ class AdbCommandResult {
|
|||
"stderr:\n ${stderr.trim()}\n"
|
||||
"exitCode: $exitCode\n"
|
||||
"timedOut: $timedOut";
|
||||
throw new Exception(error);
|
||||
throw Exception(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [_executeCommand] will write [stdin] to the standard input of the created
|
||||
* process and will return a tuple (stdout, stderr).
|
||||
*
|
||||
* If the exit code of the process was nonzero it will complete with an error.
|
||||
* If starting the process failed, it will complete with an error as well.
|
||||
*/
|
||||
/// [_executeCommand] will write [stdin] to the standard input of the created
|
||||
/// process and will return a tuple (stdout, stderr).
|
||||
///
|
||||
/// If the exit code of the process was nonzero it will complete with an error.
|
||||
/// If starting the process failed, it will complete with an error as well.
|
||||
Future<AdbCommandResult> _executeCommand(String executable, List<String> args,
|
||||
{String stdin, Duration timeout}) {
|
||||
Future<String> getOutput(Stream<List<int>> stream) {
|
||||
|
@ -61,7 +56,7 @@ Future<AdbCommandResult> _executeCommand(String executable, List<String> args,
|
|||
Timer timer;
|
||||
bool timedOut = false;
|
||||
if (timeout != null) {
|
||||
timer = new Timer(timeout, () {
|
||||
timer = Timer(timeout, () {
|
||||
timedOut = true;
|
||||
process.kill(ProcessSignal.sigterm);
|
||||
timer = null;
|
||||
|
@ -76,40 +71,36 @@ Future<AdbCommandResult> _executeCommand(String executable, List<String> args,
|
|||
if (timer != null) timer.cancel();
|
||||
|
||||
String command = "$executable ${args.join(' ')}";
|
||||
return new AdbCommandResult(command, results[0] as String,
|
||||
results[1] as String, results[2] as int, timedOut);
|
||||
return AdbCommandResult(command, results[0] as String, results[1] as String,
|
||||
results[2] as int, timedOut);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to loop through all adb ports.
|
||||
*
|
||||
* The ports come in pairs:
|
||||
* - even number: console connection
|
||||
* - odd number: adb connection
|
||||
* Note that this code doesn't check if the ports are used.
|
||||
*/
|
||||
/// Helper class to loop through all adb ports.
|
||||
///
|
||||
/// The ports come in pairs:
|
||||
/// - even number: console connection
|
||||
/// - odd number: adb connection
|
||||
/// Note that this code doesn't check if the ports are used.
|
||||
class AdbServerPortPool {
|
||||
static int MIN_PORT = 5554;
|
||||
static int MAX_PORT = 5584;
|
||||
static const _minPort = 5554;
|
||||
static const _maxPort = 5584;
|
||||
|
||||
static int _nextPort = MIN_PORT;
|
||||
static int _nextPort = _minPort;
|
||||
|
||||
static int next() {
|
||||
var port = _nextPort;
|
||||
if (port > MAX_PORT) {
|
||||
throw new Exception("All ports are used.");
|
||||
}
|
||||
if (port > _maxPort) throw Exception("All ports are used.");
|
||||
|
||||
_nextPort += 2;
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the interface to the emulator.
|
||||
* New emulators can be launched by calling the static [launchNewEmulator]
|
||||
* method.
|
||||
*/
|
||||
/// Represents the interface to the emulator.
|
||||
///
|
||||
/// New emulators can be launched by calling the static [launchNewEmulator]
|
||||
/// method.
|
||||
class AndroidEmulator {
|
||||
int _port;
|
||||
Process _emulatorProcess;
|
||||
|
@ -123,14 +114,14 @@ class AndroidEmulator {
|
|||
var portNumber = AdbServerPortPool.next();
|
||||
var args = ['-avd', '$avdName', '-port', "$portNumber" /*, '-gpu', 'on'*/];
|
||||
return Process.start("emulator64-arm", args).then((Process process) {
|
||||
var adbDevice = new AdbDevice('emulator-$portNumber');
|
||||
return new AndroidEmulator._private(portNumber, adbDevice, process);
|
||||
var adbDevice = AdbDevice('emulator-$portNumber');
|
||||
return AndroidEmulator._private(portNumber, adbDevice, process);
|
||||
});
|
||||
}
|
||||
|
||||
AndroidEmulator._private(this._port, this._adbDevice, this._emulatorProcess) {
|
||||
Stream<String> getLines(Stream s) {
|
||||
return s.transform(utf8.decoder).transform(new LineSplitter());
|
||||
return s.transform(utf8.decoder).transform(LineSplitter());
|
||||
}
|
||||
|
||||
getLines(_emulatorProcess.stdout).listen((line) {
|
||||
|
@ -145,7 +136,7 @@ class AndroidEmulator {
|
|||
}
|
||||
|
||||
Future<bool> kill() {
|
||||
var completer = new Completer<bool>();
|
||||
var completer = Completer<bool>();
|
||||
if (_emulatorProcess.kill()) {
|
||||
_emulatorProcess.exitCode.then((exitCode) {
|
||||
// TODO: Should we use exitCode to do something clever?
|
||||
|
@ -163,9 +154,7 @@ class AndroidEmulator {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to create avd device configurations.
|
||||
*/
|
||||
/// Helper class to create avd device configurations.
|
||||
class AndroidHelper {
|
||||
static Future createAvd(String name, String target) async {
|
||||
var args = [
|
||||
|
@ -186,29 +175,23 @@ class AndroidHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for communicating with an emulator or with a real device.
|
||||
*/
|
||||
/// Used for communicating with an emulator or with a real device.
|
||||
class AdbDevice {
|
||||
static const _adbServerStartupTime = const Duration(seconds: 3);
|
||||
static const _adbServerStartupTime = Duration(seconds: 3);
|
||||
String _deviceId;
|
||||
Map<String, String> _cachedData = new Map<String, String>();
|
||||
Map<String, String> _cachedData = {};
|
||||
|
||||
String get deviceId => _deviceId;
|
||||
|
||||
AdbDevice(this._deviceId);
|
||||
|
||||
/**
|
||||
* Blocks execution until the device is online
|
||||
*/
|
||||
/// Blocks execution until the device is online.
|
||||
Future waitForDevice() {
|
||||
return _adbCommand(['wait-for-device']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls the 'sys.boot_completed' property. Returns as soon as the property is
|
||||
* 1.
|
||||
*/
|
||||
/// Polls the 'sys.boot_completed' property. Returns as soon as the property
|
||||
/// is 1.
|
||||
Future<Null> waitForBootCompleted() async {
|
||||
while (true) {
|
||||
try {
|
||||
|
@ -216,71 +199,57 @@ class AdbDevice {
|
|||
await _adbCommand(['shell', 'getprop', 'sys.boot_completed']);
|
||||
if (result.stdout.trim() == '1') return;
|
||||
} catch (_) {}
|
||||
await new Future<Null>.delayed(const Duration(seconds: 2));
|
||||
await Future<Null>.delayed(const Duration(seconds: 2));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put adb in root mode.
|
||||
*/
|
||||
/// Put adb in root mode.
|
||||
Future<bool> adbRoot() {
|
||||
var adbRootCompleter = new Completer<bool>();
|
||||
var adbRootCompleter = Completer<bool>();
|
||||
_adbCommand(['root']).then((_) {
|
||||
// TODO: Figure out a way to wait until the adb daemon was restarted in
|
||||
// 'root mode' on the device.
|
||||
new Timer(_adbServerStartupTime, () => adbRootCompleter.complete(true));
|
||||
Timer(_adbServerStartupTime, () => adbRootCompleter.complete(true));
|
||||
}).catchError((error) => adbRootCompleter.completeError(error));
|
||||
return adbRootCompleter.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download data form the device.
|
||||
*/
|
||||
/// Download data from the device.
|
||||
Future pullData(Path remote, Path local) {
|
||||
return _adbCommand(['pull', '$remote', '$local']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload data to the device.
|
||||
*/
|
||||
/// Upload data to the device.
|
||||
Future pushData(Path local, Path remote) {
|
||||
return _adbCommand(['push', '$local', '$remote']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload data to the device, unless [local] is the same as the most recently
|
||||
* used source for [remote].
|
||||
*/
|
||||
/// Upload data to the device, unless [local] is the same as the most recently
|
||||
/// used source for [remote].
|
||||
Future<AdbCommandResult> pushCachedData(String local, String remote) {
|
||||
if (_cachedData[remote] == local) {
|
||||
return new Future.value(
|
||||
new AdbCommandResult("Skipped cached push", "", "", 0, false));
|
||||
return Future.value(
|
||||
AdbCommandResult("Skipped cached push", "", "", 0, false));
|
||||
}
|
||||
_cachedData[remote] = local;
|
||||
return _adbCommand(['push', local, remote]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change permission of directory recursively.
|
||||
*/
|
||||
/// Change permission of directory recursively.
|
||||
Future chmod(String mode, Path directory) {
|
||||
var arguments = ['shell', 'chmod', '-R', mode, '$directory'];
|
||||
return _adbCommand(arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install an application on the device.
|
||||
*/
|
||||
/// Install an application on the device.
|
||||
Future installApk(Path filename) {
|
||||
return _adbCommand(
|
||||
['install', '-i', 'com.google.android.feedback', '-r', '$filename']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the given intent on the device.
|
||||
*/
|
||||
/// Start the given intent on the device.
|
||||
Future startActivity(Intent intent) {
|
||||
var arguments = [
|
||||
return _adbCommand([
|
||||
'shell',
|
||||
'am',
|
||||
'start',
|
||||
|
@ -288,35 +257,24 @@ class AdbDevice {
|
|||
'-a',
|
||||
intent.action,
|
||||
'-n',
|
||||
"${intent.package}/${intent.activity}"
|
||||
];
|
||||
if (intent.dataUri != null) {
|
||||
arguments.addAll(['-d', intent.dataUri]);
|
||||
}
|
||||
return _adbCommand(arguments);
|
||||
"${intent.package}/${intent.activity}",
|
||||
if (intent.dataUri != null) ...['-d', intent.dataUri]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force to stop everything associated with [package].
|
||||
*/
|
||||
/// Force to stop everything associated with [package].
|
||||
Future forceStop(String package) {
|
||||
var arguments = ['shell', 'am', 'force-stop', package];
|
||||
return _adbCommand(arguments);
|
||||
return _adbCommand(['shell', 'am', 'force-stop', package]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set system property name to value.
|
||||
*/
|
||||
/// Set system property name to value.
|
||||
Future setProp(String name, String value) {
|
||||
return _adbCommand(['shell', 'setprop', name, value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill all background processes.
|
||||
*/
|
||||
/// Kill all background processes.
|
||||
Future killAll() {
|
||||
var arguments = ['shell', 'am', 'kill-all'];
|
||||
return _adbCommand(arguments);
|
||||
return _adbCommand(['shell', 'am', 'kill-all']);
|
||||
}
|
||||
|
||||
Future<AdbCommandResult> runAdbCommand(List<String> adbArgs,
|
||||
|
@ -327,28 +285,27 @@ class AdbDevice {
|
|||
|
||||
Future<AdbCommandResult> runAdbShellCommand(List<String> shellArgs,
|
||||
{Duration timeout}) async {
|
||||
const MARKER = 'AdbShellExitCode: ';
|
||||
const marker = 'AdbShellExitCode: ';
|
||||
|
||||
// The exitcode of 'adb shell ...' can be 0 even though the command failed
|
||||
// with a non-zero exit code. We therefore explicitly print it to stdout and
|
||||
// search for it.
|
||||
|
||||
var args = ['shell', "${shellArgs.join(' ')} ; echo $MARKER \$?"];
|
||||
AdbCommandResult result = await _executeCommand(
|
||||
"adb", _deviceSpecificArgs(args),
|
||||
var args = ['shell', "${shellArgs.join(' ')} ; echo $marker \$?"];
|
||||
var result = await _executeCommand("adb", _deviceSpecificArgs(args),
|
||||
timeout: timeout);
|
||||
int exitCode = result.exitCode;
|
||||
var exitCode = result.exitCode;
|
||||
var lines = result.stdout
|
||||
.split('\n')
|
||||
.where((line) => line.trim().length > 0)
|
||||
.where((line) => line.trim().isNotEmpty)
|
||||
.toList();
|
||||
if (lines.length > 0) {
|
||||
int index = lines.last.indexOf(MARKER);
|
||||
if (lines.isNotEmpty) {
|
||||
int index = lines.last.indexOf(marker);
|
||||
if (index >= 0) {
|
||||
exitCode =
|
||||
int.parse(lines.last.substring(index + MARKER.length).trim());
|
||||
int.parse(lines.last.substring(index + marker.length).trim());
|
||||
if (exitCode > 128 && exitCode <= 128 + 31) {
|
||||
// Return negative exit codes for signals 1..31 (128+N for signal N)
|
||||
// Return negative exit codes for signals 1..31 (128+N for signal N).
|
||||
exitCode = 128 - exitCode;
|
||||
}
|
||||
} else {
|
||||
|
@ -369,7 +326,7 @@ class AdbDevice {
|
|||
assert(result.exitCode != 0);
|
||||
}
|
||||
}
|
||||
return new AdbCommandResult(result.command, result.stdout, result.stderr,
|
||||
return AdbCommandResult(result.command, result.stdout, result.stderr,
|
||||
exitCode, result.timedOut);
|
||||
}
|
||||
|
||||
|
@ -389,17 +346,15 @@ class AdbDevice {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to list all adb devices available.
|
||||
*/
|
||||
/// Helper to list all adb devices available.
|
||||
class AdbHelper {
|
||||
static RegExp _deviceLineRegexp =
|
||||
new RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true);
|
||||
RegExp(r'^([a-zA-Z0-9_-]+)[ \t]+device$', multiLine: true);
|
||||
|
||||
static Future<List<String>> listDevices() {
|
||||
return Process.run('adb', ['devices']).then((ProcessResult result) {
|
||||
if (result.exitCode != 0) {
|
||||
throw new Exception("Could not list devices [stdout: ${result.stdout},"
|
||||
throw Exception("Could not list devices [stdout: ${result.stdout},"
|
||||
"stderr: ${result.stderr}]");
|
||||
}
|
||||
return _deviceLineRegexp
|
||||
|
@ -410,9 +365,7 @@ class AdbHelper {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an android intent.
|
||||
*/
|
||||
/// Represents an android intent.
|
||||
class Intent {
|
||||
String action;
|
||||
String package;
|
||||
|
@ -422,12 +375,10 @@ class Intent {
|
|||
Intent(this.action, this.package, this.activity, [this.dataUri]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers all available devices and supports acquire/release.
|
||||
*/
|
||||
/// Discovers all available devices and supports acquire/release.
|
||||
class AdbDevicePool {
|
||||
final Queue<AdbDevice> _idleDevices = new Queue<AdbDevice>();
|
||||
final Queue<Completer> _waiter = new Queue<Completer>();
|
||||
final Queue<AdbDevice> _idleDevices = Queue();
|
||||
final Queue<Completer<AdbDevice>> _waiter = Queue();
|
||||
|
||||
AdbDevicePool(List<AdbDevice> idleDevices) {
|
||||
_idleDevices.addAll(idleDevices);
|
||||
|
@ -435,28 +386,28 @@ class AdbDevicePool {
|
|||
|
||||
static Future<AdbDevicePool> create() async {
|
||||
var names = await AdbHelper.listDevices();
|
||||
var devices = names.map((id) => new AdbDevice(id)).toList();
|
||||
var devices = names.map((id) => AdbDevice(id)).toList();
|
||||
if (devices.length == 0) {
|
||||
throw new Exception('No android devices found. '
|
||||
throw Exception('No android devices found. '
|
||||
'Please make sure "adb devices" shows your device!');
|
||||
}
|
||||
print("Found ${devices.length} Android devices.");
|
||||
return new AdbDevicePool(devices);
|
||||
return AdbDevicePool(devices);
|
||||
}
|
||||
|
||||
Future<AdbDevice> acquireDevice() async {
|
||||
if (_idleDevices.length > 0) {
|
||||
if (_idleDevices.isNotEmpty) {
|
||||
return _idleDevices.removeFirst();
|
||||
} else {
|
||||
var completer = new Completer<AdbDevice>();
|
||||
var completer = Completer<AdbDevice>();
|
||||
_waiter.add(completer);
|
||||
return completer.future;
|
||||
}
|
||||
}
|
||||
|
||||
void releaseDevice(AdbDevice device) {
|
||||
if (_waiter.length > 0) {
|
||||
Completer completer = _waiter.removeFirst();
|
||||
if (_waiter.isNotEmpty) {
|
||||
var completer = _waiter.removeFirst();
|
||||
completer.complete(device);
|
||||
} else {
|
||||
_idleDevices.add(device);
|
||||
|
|
|
@ -14,59 +14,55 @@ import 'path.dart';
|
|||
import 'reset_safari.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
typedef void BrowserDoneCallback(BrowserTestOutput output);
|
||||
typedef void TestChangedCallback(String browserId, String output, int testId);
|
||||
typedef BrowserTest NextTestCallback(String browserId);
|
||||
typedef BrowserDoneCallback = void Function(BrowserTestOutput output);
|
||||
typedef TestChangedCallback = void Function(
|
||||
String browserId, String output, int testId);
|
||||
typedef NextTestCallback = BrowserTest Function(String browserId);
|
||||
|
||||
class BrowserOutput {
|
||||
final StringBuffer stdout = new StringBuffer();
|
||||
final StringBuffer stderr = new StringBuffer();
|
||||
final StringBuffer eventLog = new StringBuffer();
|
||||
final StringBuffer stdout = StringBuffer();
|
||||
final StringBuffer stderr = StringBuffer();
|
||||
final StringBuffer eventLog = StringBuffer();
|
||||
}
|
||||
|
||||
/** Class describing the interface for communicating with browsers. */
|
||||
/// Class describing the interface for communicating with browsers.
|
||||
abstract class Browser {
|
||||
BrowserOutput _allBrowserOutput = new BrowserOutput();
|
||||
BrowserOutput _testBrowserOutput = new BrowserOutput();
|
||||
BrowserOutput _allBrowserOutput = BrowserOutput();
|
||||
BrowserOutput _testBrowserOutput = BrowserOutput();
|
||||
|
||||
// This is called after the process is closed, before the done future
|
||||
// is completed.
|
||||
// Subclasses can use this to cleanup any browser specific resources
|
||||
// (temp directories, profiles, etc). The function is expected to do
|
||||
// it's work synchronously.
|
||||
/// This is called after the process is closed, before the done future
|
||||
/// is completed.
|
||||
///
|
||||
/// Subclasses can use this to cleanup any browser specific resources
|
||||
/// (temp directories, profiles, etc). The function is expected to do
|
||||
/// it's work synchronously.
|
||||
Function _cleanup;
|
||||
|
||||
/** The version of the browser - normally set when starting a browser */
|
||||
/// The version of the browser - normally set when starting a browser
|
||||
String version = "";
|
||||
|
||||
// The path to the browser executable.
|
||||
/// The path to the browser executable.
|
||||
String _binary;
|
||||
|
||||
/**
|
||||
* The underlying process - don't mess directly with this if you don't
|
||||
* know what you are doing (this is an interactive process that needs
|
||||
* special treatment to not leak).
|
||||
*/
|
||||
/// The underlying process - don't mess directly with this if you don't
|
||||
/// know what you are doing (this is an interactive process that needs
|
||||
/// special treatment to not leak).
|
||||
Process process;
|
||||
|
||||
Function logger;
|
||||
|
||||
/**
|
||||
* Id of the browser
|
||||
*/
|
||||
/// Id of the browser.
|
||||
String id;
|
||||
|
||||
/**
|
||||
* Reset the browser to a known configuration on start-up.
|
||||
* Browser specific implementations are free to ignore this.
|
||||
*/
|
||||
/// Reset the browser to a known configuration on start-up.
|
||||
/// Browser specific implementations are free to ignore this.
|
||||
static bool resetBrowserConfiguration = false;
|
||||
|
||||
/** Print everything (stdout, stderr, usageLog) whenever we add to it */
|
||||
/// Print everything (stdout, stderr, usageLog) whenever we add to it
|
||||
bool debugPrint = false;
|
||||
|
||||
// This future returns when the process exits. It is also the return value
|
||||
// of close()
|
||||
/// This future returns when the process exits. It is also the return value
|
||||
/// of close()
|
||||
Future done;
|
||||
|
||||
Browser();
|
||||
|
@ -76,18 +72,18 @@ abstract class Browser {
|
|||
Browser browser;
|
||||
switch (runtime) {
|
||||
case Runtime.firefox:
|
||||
browser = new Firefox();
|
||||
browser = Firefox();
|
||||
break;
|
||||
case Runtime.chrome:
|
||||
browser = new Chrome();
|
||||
browser = Chrome();
|
||||
break;
|
||||
case Runtime.safari:
|
||||
browser = new Safari();
|
||||
browser = Safari();
|
||||
break;
|
||||
case Runtime.ie9:
|
||||
case Runtime.ie10:
|
||||
case Runtime.ie11:
|
||||
browser = new IE();
|
||||
browser = IE();
|
||||
break;
|
||||
default:
|
||||
throw "unreachable";
|
||||
|
@ -97,7 +93,7 @@ abstract class Browser {
|
|||
return browser;
|
||||
}
|
||||
|
||||
static const List<String> SUPPORTED_BROWSERS = const [
|
||||
static const List<String> supportedBrowsers = [
|
||||
'safari',
|
||||
'ff',
|
||||
'firefox',
|
||||
|
@ -113,11 +109,11 @@ abstract class Browser {
|
|||
|
||||
// TODO(kustermann): add standard support for chrome on android
|
||||
static bool supportedBrowser(String name) {
|
||||
return SUPPORTED_BROWSERS.contains(name);
|
||||
return supportedBrowsers.contains(name);
|
||||
}
|
||||
|
||||
void _logEvent(String event) {
|
||||
String toLog = "$this ($id) - $event \n";
|
||||
var toLog = "$this ($id) - $event \n";
|
||||
if (debugPrint) print("usageLog: $toLog");
|
||||
if (logger != null) logger(toLog);
|
||||
|
||||
|
@ -150,14 +146,12 @@ abstract class Browser {
|
|||
return done;
|
||||
} else {
|
||||
_logEvent("The process is already dead.");
|
||||
return new Future.value(true);
|
||||
return Future.value(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the browser using the supplied argument.
|
||||
* This sets up the error handling and usage logging.
|
||||
*/
|
||||
/// Start the browser using the supplied argument.
|
||||
/// This sets up the error handling and usage logging.
|
||||
Future<bool> startBrowserProcess(String command, List<String> arguments,
|
||||
{Map<String, String> environment}) {
|
||||
return Process.start(command, arguments, environment: environment)
|
||||
|
@ -166,14 +160,14 @@ abstract class Browser {
|
|||
process = startedProcess;
|
||||
// Used to notify when exiting, and as a return value on calls to
|
||||
// close().
|
||||
var doneCompleter = new Completer<bool>();
|
||||
var doneCompleter = Completer<bool>();
|
||||
done = doneCompleter.future;
|
||||
|
||||
Completer stdoutDone = new Completer<Null>();
|
||||
Completer stderrDone = new Completer<Null>();
|
||||
var stdoutDone = Completer<Null>();
|
||||
var stderrDone = Completer<Null>();
|
||||
|
||||
bool stdoutIsDone = false;
|
||||
bool stderrIsDone = false;
|
||||
var stdoutIsDone = false;
|
||||
var stderrIsDone = false;
|
||||
StreamSubscription stdoutSubscription;
|
||||
StreamSubscription stderrSubscription;
|
||||
|
||||
|
@ -226,9 +220,8 @@ abstract class Browser {
|
|||
_logEvent("Browser closed with exitcode $exitCode");
|
||||
|
||||
if (!stdoutIsDone || !stderrIsDone) {
|
||||
watchdogTimer = new Timer(MAX_STDIO_DELAY, () {
|
||||
DebugLogger.warning(
|
||||
"$MAX_STDIO_DELAY_PASSED_MESSAGE (browser: $this)");
|
||||
watchdogTimer = Timer(maxStdioDelay, () {
|
||||
DebugLogger.warning("$maxStdioDelayPassedMessage (browser: $this)");
|
||||
watchdogTimer = null;
|
||||
stdoutSubscription.cancel();
|
||||
stderrSubscription.cancel();
|
||||
|
@ -253,26 +246,20 @@ abstract class Browser {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the output that was written so far to stdout/stderr/eventLog.
|
||||
*/
|
||||
/// Get the output that was written so far to stdout/stderr/eventLog.
|
||||
BrowserOutput get allBrowserOutput => _allBrowserOutput;
|
||||
BrowserOutput get testBrowserOutput => _testBrowserOutput;
|
||||
|
||||
void resetTestBrowserOutput() {
|
||||
_testBrowserOutput = new BrowserOutput();
|
||||
_testBrowserOutput = BrowserOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add useful info about the browser to the _testBrowserOutput.stdout,
|
||||
* where it will be reported for failing tests. Used to report which
|
||||
* android device a failing test is running on.
|
||||
*/
|
||||
/// Add useful info about the browser to the _testBrowserOutput.stdout,
|
||||
/// where it will be reported for failing tests. Used to report which
|
||||
/// android device a failing test is running on.
|
||||
void logBrowserInfoToTestBrowserOutput() {}
|
||||
|
||||
String toString();
|
||||
|
||||
/** Starts the browser loading the given url */
|
||||
/// Starts the browser loading the given url
|
||||
Future<bool> start(String url);
|
||||
|
||||
/// Called when the driver page is requested, that is, when the browser first
|
||||
|
@ -280,13 +267,11 @@ abstract class Browser {
|
|||
/// browser process has started and opened its first window.
|
||||
///
|
||||
/// This is used by [Safari] to ensure the browser window has focus.
|
||||
Future<Null> onDriverPageRequested() => new Future<Null>.value();
|
||||
Future<Null> onDriverPageRequested() => Future.value();
|
||||
}
|
||||
|
||||
class Safari extends Browser {
|
||||
/**
|
||||
* We get the safari version by parsing a version file
|
||||
*/
|
||||
/// We get the safari version by parsing a version file
|
||||
static const String versionFile =
|
||||
"/Applications/Safari.app/Contents/version.plist";
|
||||
|
||||
|
@ -297,17 +282,17 @@ class Safari extends Browser {
|
|||
Future<bool> resetConfiguration() async {
|
||||
if (!Browser.resetBrowserConfiguration) return true;
|
||||
|
||||
var completer = new Completer<Null>();
|
||||
var completer = Completer<Null>();
|
||||
handleUncaughtError(error, StackTrace stackTrace) {
|
||||
if (!completer.isCompleted) {
|
||||
completer.completeError(error, stackTrace);
|
||||
} else {
|
||||
throw new AsyncError(error, stackTrace);
|
||||
throw AsyncError(error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Zone parent = Zone.current;
|
||||
ZoneSpecification specification = new ZoneSpecification(
|
||||
var parent = Zone.current;
|
||||
var specification = ZoneSpecification(
|
||||
print: (Zone self, ZoneDelegate delegate, Zone zone, String line) {
|
||||
delegate.run(parent, () {
|
||||
_logEvent(line);
|
||||
|
@ -315,7 +300,7 @@ class Safari extends Browser {
|
|||
});
|
||||
Future zoneWrapper() {
|
||||
Uri safariUri = Uri.base.resolve(safariBundleLocation);
|
||||
return new Future(() => killAndResetSafari(bundle: safariUri))
|
||||
return Future(() => killAndResetSafari(bundle: safariUri))
|
||||
.then(completer.complete);
|
||||
}
|
||||
|
||||
|
@ -335,28 +320,25 @@ class Safari extends Browser {
|
|||
}
|
||||
|
||||
Future<String> getVersion() {
|
||||
/**
|
||||
* Example of the file:
|
||||
* <?xml version="1.0" encoding="UTF-8"?>
|
||||
* <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
* <plist version="1.0">
|
||||
* <dict>
|
||||
* <key>BuildVersion</key>
|
||||
* <string>2</string>
|
||||
* <key>CFBundleShortVersionString</key>
|
||||
* <string>6.0.4</string>
|
||||
* <key>CFBundleVersion</key>
|
||||
* <string>8536.29.13</string>
|
||||
* <key>ProjectName</key>
|
||||
* <string>WebBrowser</string>
|
||||
* <key>SourceVersion</key>
|
||||
* <string>7536029013000000</string>
|
||||
* </dict>
|
||||
* </plist>
|
||||
*/
|
||||
File f = new File(versionFile);
|
||||
return f.readAsLines().then((content) {
|
||||
bool versionOnNextLine = false;
|
||||
// Example of the file:
|
||||
// <?xml version="1.0" encoding="UTF-8"?>
|
||||
// <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
// <plist version="1.0">
|
||||
// <dict>
|
||||
// <key>BuildVersion</key>
|
||||
// <string>2</string>
|
||||
// <key>CFBundleShortVersionString</key>
|
||||
// <string>6.0.4</string>
|
||||
// <key>CFBundleVersion</key>
|
||||
// <string>8536.29.13</string>
|
||||
// <key>ProjectName</key>
|
||||
// <string>WebBrowser</string>
|
||||
// <key>SourceVersion</key>
|
||||
// <string>7536029013000000</string>
|
||||
// </dict>
|
||||
// </plist>
|
||||
return File(versionFile).readAsLines().then((content) {
|
||||
var versionOnNextLine = false;
|
||||
for (var line in content) {
|
||||
if (versionOnNextLine) return line;
|
||||
if (line.contains("CFBundleShortVersionString")) {
|
||||
|
@ -368,7 +350,7 @@ class Safari extends Browser {
|
|||
}
|
||||
|
||||
Future<Null> _createLaunchHTML(String path, String url) async {
|
||||
var file = new File("$path/launch.html");
|
||||
var file = File("$path/launch.html");
|
||||
var randomFile = await file.open(mode: FileMode.write);
|
||||
var content = '<script language="JavaScript">location = "$url"</script>';
|
||||
await randomFile.writeString(content);
|
||||
|
@ -444,7 +426,7 @@ class Chrome extends Browser {
|
|||
_version = "Can't get version on windows";
|
||||
// We still validate that the binary exists so that we can give good
|
||||
// feedback.
|
||||
return new File(_binary).exists().then((exists) {
|
||||
return File(_binary).exists().then((exists) {
|
||||
if (!exists) {
|
||||
_logEvent("Chrome binary not available.");
|
||||
_logEvent("Make sure $_binary is a valid program for running chrome");
|
||||
|
@ -478,7 +460,7 @@ class Chrome extends Browser {
|
|||
_logEvent(
|
||||
"Error: failed to delete Chrome user-data-dir ${userDir.path}"
|
||||
", will try again in 40 seconds: $e");
|
||||
new Timer(new Duration(seconds: 40), () {
|
||||
Timer(Duration(seconds: 40), () {
|
||||
try {
|
||||
userDir.deleteSync(recursive: true);
|
||||
} catch (e) {
|
||||
|
@ -556,7 +538,7 @@ class IE extends Browser {
|
|||
}
|
||||
|
||||
var localAppData = Platform.environment['LOCALAPPDATA'];
|
||||
Directory dir = new Directory("$localAppData\\Microsoft\\"
|
||||
Directory dir = Directory("$localAppData\\Microsoft\\"
|
||||
"Internet Explorer\\Recovery");
|
||||
return dir.delete(recursive: true).then((_) {
|
||||
return true;
|
||||
|
@ -594,22 +576,20 @@ class AndroidChrome extends Browser {
|
|||
AndroidChrome(this._adbDevice);
|
||||
|
||||
Future<bool> start(String url) {
|
||||
var chromeIntent =
|
||||
new Intent(viewAction, chromePackage, chromeActivity, url);
|
||||
var chromeIntent = Intent(viewAction, chromePackage, chromeActivity, url);
|
||||
var turnScreenOnIntent =
|
||||
new Intent(mainAction, turnScreenOnPackage, turnScreenOnActivity);
|
||||
Intent(mainAction, turnScreenOnPackage, turnScreenOnActivity);
|
||||
|
||||
var testing_resources_dir =
|
||||
new Path('third_party/android_testing_resources');
|
||||
if (!new Directory(testing_resources_dir.toNativePath()).existsSync()) {
|
||||
DebugLogger.error("$testing_resources_dir doesn't exist. Exiting now.");
|
||||
var testingResourcesDir = Path('third_party/android_testing_resources');
|
||||
if (!Directory(testingResourcesDir.toNativePath()).existsSync()) {
|
||||
DebugLogger.error("$testingResourcesDir doesn't exist. Exiting now.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
var chromeAPK = testing_resources_dir.append('com.android.chrome-1.apk');
|
||||
var turnScreenOnAPK = testing_resources_dir.append('TurnScreenOn.apk');
|
||||
var chromeConfDir = testing_resources_dir.append('chrome_configuration');
|
||||
var chromeConfDirRemote = new Path('/data/user/0/com.android.chrome/');
|
||||
var chromeAPK = testingResourcesDir.append('com.android.chrome-1.apk');
|
||||
var turnScreenOnAPK = testingResourcesDir.append('TurnScreenOn.apk');
|
||||
var chromeConfDir = testingResourcesDir.append('chrome_configuration');
|
||||
var chromeConfDirRemote = Path('/data/user/0/com.android.chrome/');
|
||||
|
||||
return _adbDevice.waitForBootCompleted().then((_) {
|
||||
return _adbDevice.forceStop(chromeIntent.package);
|
||||
|
@ -638,7 +618,7 @@ class AndroidChrome extends Browser {
|
|||
return _adbDevice.killAll().then((_) => true);
|
||||
});
|
||||
}
|
||||
return new Future.value(true);
|
||||
return Future.value(true);
|
||||
}
|
||||
|
||||
void logBrowserInfoToTestBrowserOutput() {
|
||||
|
@ -658,7 +638,7 @@ class Firefox extends Browser {
|
|||
'user_pref("dom.max_script_run_time", 0);';
|
||||
|
||||
void _createPreferenceFile(String path) {
|
||||
var file = new File("$path/user.js");
|
||||
var file = File("$path/user.js");
|
||||
var randomFile = file.openSync(mode: FileMode.write);
|
||||
randomFile.writeStringSync(enablePopUp);
|
||||
randomFile.writeStringSync(disableDefaultCheck);
|
||||
|
@ -673,7 +653,7 @@ class Firefox extends Browser {
|
|||
if (versionResult.exitCode != 0) {
|
||||
_logEvent("Failed to firefox get version");
|
||||
_logEvent("Make sure $_binary is a valid program for running firefox");
|
||||
return new Future.value(false);
|
||||
return Future.value(false);
|
||||
}
|
||||
version = versionResult.stdout as String;
|
||||
_logEvent("Got version: $version");
|
||||
|
@ -690,7 +670,7 @@ class Firefox extends Browser {
|
|||
"-new-instance",
|
||||
url
|
||||
];
|
||||
var environment = new Map<String, String>.from(Platform.environment);
|
||||
var environment = Map<String, String>.from(Platform.environment);
|
||||
environment["MOZ_CRASHREPORTER_DISABLE"] = "1";
|
||||
return startBrowserProcess(_binary, args, environment: environment);
|
||||
});
|
||||
|
@ -703,9 +683,7 @@ class Firefox extends Browser {
|
|||
String toString() => "Firefox";
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the current state of a browser used for testing.
|
||||
*/
|
||||
/// Describes the current state of a browser used for testing.
|
||||
class BrowserStatus {
|
||||
Browser browser;
|
||||
BrowserTest currentTest;
|
||||
|
@ -716,14 +694,12 @@ class BrowserStatus {
|
|||
BrowserTest lastTest;
|
||||
bool timeout = false;
|
||||
Timer nextTestTimeout;
|
||||
Stopwatch timeSinceRestart = new Stopwatch()..start();
|
||||
Stopwatch timeSinceRestart = Stopwatch()..start();
|
||||
|
||||
BrowserStatus(Browser this.browser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a single test to be run in the browser.
|
||||
*/
|
||||
/// Describes a single test to be run in the browser.
|
||||
class BrowserTest {
|
||||
// TODO(ricow): Add timeout callback instead of the string passing hack.
|
||||
BrowserDoneCallback doneCallback;
|
||||
|
@ -763,7 +739,7 @@ class BrowserTestOutput {
|
|||
|
||||
BrowserTestOutput(this.delayUntilTestStarted, this.duration,
|
||||
this.lastKnownMessage, this.browserOutput,
|
||||
{this.didTimeout: false});
|
||||
{this.didTimeout = false});
|
||||
}
|
||||
|
||||
/// Encapsulates all the functionality for running tests in browsers.
|
||||
|
@ -776,12 +752,12 @@ class BrowserTestOutput {
|
|||
/// driver page to the browsers, serves tests, and receives results and
|
||||
/// requests back from the browsers.
|
||||
class BrowserTestRunner {
|
||||
static const int MAX_NEXT_TEST_TIMEOUTS = 10;
|
||||
static const Duration NEXT_TEST_TIMEOUT = const Duration(seconds: 120);
|
||||
static const Duration RESTART_BROWSER_INTERVAL = const Duration(seconds: 60);
|
||||
static const int _maxNextTestTimeouts = 10;
|
||||
static const Duration _nextTestTimeout = Duration(seconds: 120);
|
||||
static const Duration _restartBrowserInterval = Duration(seconds: 60);
|
||||
|
||||
/// If the queue was recently empty, don't start another browser.
|
||||
static const Duration MIN_NONEMPTY_QUEUE_TIME = const Duration(seconds: 1);
|
||||
static const Duration _minNonemptyQueueTime = Duration(seconds: 1);
|
||||
|
||||
final TestConfiguration configuration;
|
||||
final BrowserTestingServer testingServer;
|
||||
|
@ -789,7 +765,8 @@ class BrowserTestRunner {
|
|||
final String localIp;
|
||||
int maxNumBrowsers;
|
||||
int numBrowsers = 0;
|
||||
// Used to send back logs from the browser (start, stop etc)
|
||||
|
||||
/// Used to send back logs from the browser (start, stop etc.).
|
||||
Function logger;
|
||||
|
||||
int browserIdCounter = 1;
|
||||
|
@ -797,7 +774,7 @@ class BrowserTestRunner {
|
|||
bool testingServerStarted = false;
|
||||
bool underTermination = false;
|
||||
int numBrowserGetTestTimeouts = 0;
|
||||
DateTime lastEmptyTestQueueTime = new DateTime.now();
|
||||
DateTime lastEmptyTestQueueTime = DateTime.now();
|
||||
String _currentStartingBrowserId;
|
||||
List<BrowserTest> testQueue = [];
|
||||
Map<String, BrowserStatus> browserStatus = {};
|
||||
|
@ -805,26 +782,26 @@ class BrowserTestRunner {
|
|||
Map<String, AdbDevice> adbDeviceMapping = {};
|
||||
List<AdbDevice> idleAdbDevices;
|
||||
|
||||
// This cache is used to guarantee that we never see double reporting.
|
||||
// If we do we need to provide developers with this information.
|
||||
// We don't add urls to the cache until we have run it.
|
||||
/// This cache is used to guarantee that we never see double reporting.
|
||||
/// If we do we need to provide developers with this information.
|
||||
/// We don't add urls to the cache until we have run it.
|
||||
Map<int, String> testCache = {};
|
||||
|
||||
Map<int, String> doubleReportingOutputs = {};
|
||||
List<String> timedOut = [];
|
||||
|
||||
// We will start a new browser when the test queue hasn't been empty
|
||||
// recently, we have fewer than maxNumBrowsers browsers, and there is
|
||||
// no other browser instance currently starting up.
|
||||
/// We will start a new browser when the test queue hasn't been empty
|
||||
/// recently, we have fewer than maxNumBrowsers browsers, and there is
|
||||
/// no other browser instance currently starting up.
|
||||
bool get queueWasEmptyRecently {
|
||||
return testQueue.isEmpty ||
|
||||
new DateTime.now().difference(lastEmptyTestQueueTime) <
|
||||
MIN_NONEMPTY_QUEUE_TIME;
|
||||
DateTime.now().difference(lastEmptyTestQueueTime) <
|
||||
_minNonemptyQueueTime;
|
||||
}
|
||||
|
||||
// While a browser is starting, but has not requested its first test, its
|
||||
// browserId is stored in _currentStartingBrowserId.
|
||||
// When no browser is currently starting, _currentStartingBrowserId is null.
|
||||
/// While a browser is starting, but has not requested its first test, its
|
||||
/// browserId is stored in _currentStartingBrowserId.
|
||||
/// When no browser is currently starting, _currentStartingBrowserId is null.
|
||||
bool get aBrowserIsCurrentlyStarting => _currentStartingBrowserId != null;
|
||||
void markCurrentlyStarting(String id) {
|
||||
_currentStartingBrowserId = id;
|
||||
|
@ -838,7 +815,7 @@ class BrowserTestRunner {
|
|||
TestConfiguration configuration, String localIp, this.maxNumBrowsers)
|
||||
: configuration = configuration,
|
||||
localIp = localIp,
|
||||
testingServer = new BrowserTestingServer(configuration, localIp,
|
||||
testingServer = BrowserTestingServer(configuration, localIp,
|
||||
Browser.requiresFocus(configuration.runtime.name)) {
|
||||
testingServer.testRunner = this;
|
||||
}
|
||||
|
@ -852,7 +829,7 @@ class BrowserTestRunner {
|
|||
..nextTestCallBack = getNextTest;
|
||||
if (configuration.runtime == Runtime.chromeOnAndroid) {
|
||||
var idbNames = await AdbHelper.listDevices();
|
||||
idleAdbDevices = new List.from(idbNames.map((id) => new AdbDevice(id)));
|
||||
idleAdbDevices = List.from(idbNames.map((id) => AdbDevice(id)));
|
||||
maxNumBrowsers = min(maxNumBrowsers, idleAdbDevices.length);
|
||||
}
|
||||
testingServerStarted = true;
|
||||
|
@ -861,6 +838,7 @@ class BrowserTestRunner {
|
|||
|
||||
/// requestBrowser() is called whenever we might want to start an additional
|
||||
/// browser instance.
|
||||
///
|
||||
/// It is called when starting the BrowserTestRunner, and whenever a browser
|
||||
/// is killed, whenever a new test is enqueued, or whenever a browser
|
||||
/// finishes a test.
|
||||
|
@ -885,17 +863,17 @@ class BrowserTestRunner {
|
|||
if (configuration.runtime == Runtime.chromeOnAndroid) {
|
||||
AdbDevice device = idleAdbDevices.removeLast();
|
||||
adbDeviceMapping[id] = device;
|
||||
browser = new AndroidChrome(device);
|
||||
browser = AndroidChrome(device);
|
||||
} else {
|
||||
var path = configuration.browserLocation;
|
||||
browser = new Browser.byRuntime(
|
||||
browser = Browser.byRuntime(
|
||||
configuration.runtime, path, configuration.isChecked);
|
||||
browser.logger = logger;
|
||||
}
|
||||
|
||||
browser.id = id;
|
||||
markCurrentlyStarting(id);
|
||||
var status = new BrowserStatus(browser);
|
||||
var status = BrowserStatus(browser);
|
||||
browserStatus[id] = status;
|
||||
numBrowsers++;
|
||||
status.nextTestTimeout = createNextTestTimer(status);
|
||||
|
@ -928,7 +906,7 @@ class BrowserTestRunner {
|
|||
testCache[testId] = status.currentTest.url;
|
||||
|
||||
// Report that the test is finished now
|
||||
var browserTestOutput = new BrowserTestOutput(
|
||||
var browserTestOutput = BrowserTestOutput(
|
||||
status.currentTest.delayUntilTestStarted,
|
||||
status.currentTest.stopwatch.elapsed,
|
||||
output,
|
||||
|
@ -987,7 +965,7 @@ class BrowserTestRunner {
|
|||
await status.browser.close();
|
||||
var lastKnownMessage =
|
||||
'Dom could not be fetched, since the test timed out.';
|
||||
if (status.currentTest.lastKnownMessage.length > 0) {
|
||||
if (status.currentTest.lastKnownMessage.isNotEmpty) {
|
||||
lastKnownMessage = status.currentTest.lastKnownMessage;
|
||||
}
|
||||
if (status.lastTest != null) {
|
||||
|
@ -996,7 +974,7 @@ class BrowserTestRunner {
|
|||
// Wait until the browser is closed before reporting the test as timeout.
|
||||
// This will enable us to capture stdout/stderr from the browser
|
||||
// (which might provide us with information about what went wrong).
|
||||
var browserTestOutput = new BrowserTestOutput(
|
||||
var browserTestOutput = BrowserTestOutput(
|
||||
status.currentTest.delayUntilTestStarted,
|
||||
status.currentTest.stopwatch.elapsed,
|
||||
lastKnownMessage,
|
||||
|
@ -1041,7 +1019,7 @@ class BrowserTestRunner {
|
|||
// had flaky timeouts, and this may help.
|
||||
if ((configuration.runtime == Runtime.ie10 ||
|
||||
configuration.runtime == Runtime.ie11) &&
|
||||
status.timeSinceRestart.elapsed > RESTART_BROWSER_INTERVAL) {
|
||||
status.timeSinceRestart.elapsed > _restartBrowserInterval) {
|
||||
var id = status.browser.id;
|
||||
// Reset stopwatch so we don't trigger again before restarting.
|
||||
status.timeout = true;
|
||||
|
@ -1058,7 +1036,7 @@ class BrowserTestRunner {
|
|||
BrowserTest test = testQueue.removeLast();
|
||||
// If our queue isn't empty, try starting more browsers
|
||||
if (testQueue.isEmpty) {
|
||||
lastEmptyTestQueueTime = new DateTime.now();
|
||||
lastEmptyTestQueueTime = DateTime.now();
|
||||
} else {
|
||||
requestBrowser();
|
||||
}
|
||||
|
@ -1079,7 +1057,7 @@ class BrowserTestRunner {
|
|||
}
|
||||
|
||||
status.currentTest.timeoutTimer = createTimeoutTimer(test, status);
|
||||
status.currentTest.stopwatch = new Stopwatch()..start();
|
||||
status.currentTest.stopwatch = Stopwatch()..start();
|
||||
|
||||
// Reset the test specific output information (stdout, stderr) on the
|
||||
// browser, since a new test is being started.
|
||||
|
@ -1090,7 +1068,7 @@ class BrowserTestRunner {
|
|||
|
||||
/// Creates a timer that is active while a test is running on a browser.
|
||||
Timer createTimeoutTimer(BrowserTest test, BrowserStatus status) {
|
||||
return new Timer(new Duration(seconds: test.timeout), () {
|
||||
return Timer(Duration(seconds: test.timeout), () {
|
||||
handleTimeout(status);
|
||||
});
|
||||
}
|
||||
|
@ -1098,7 +1076,7 @@ class BrowserTestRunner {
|
|||
/// Creates a timer that is active while no test is running on the
|
||||
/// browser. It has finished one test, and it has not requested a new test.
|
||||
Timer createNextTestTimer(BrowserStatus status) {
|
||||
return new Timer(BrowserTestRunner.NEXT_TEST_TIMEOUT, () {
|
||||
return Timer(BrowserTestRunner._nextTestTimeout, () {
|
||||
handleNextTestTimeout(status);
|
||||
});
|
||||
}
|
||||
|
@ -1108,7 +1086,7 @@ class BrowserTestRunner {
|
|||
"Browser timed out before getting next test. Restarting");
|
||||
if (status.timeout) return;
|
||||
numBrowserGetTestTimeouts++;
|
||||
if (numBrowserGetTestTimeouts >= MAX_NEXT_TEST_TIMEOUTS) {
|
||||
if (numBrowserGetTestTimeouts >= _maxNextTestTimeouts) {
|
||||
DebugLogger.error(
|
||||
"Too many browser timeouts before getting next test. Terminating");
|
||||
terminate().then((_) => exit(1));
|
||||
|
@ -1169,21 +1147,20 @@ class BrowserTestRunner {
|
|||
}
|
||||
}
|
||||
|
||||
/// Interface of the testing server:
|
||||
///
|
||||
/// GET /driver/BROWSER_ID -- This will get the driver page to fetch
|
||||
/// and run tests ...
|
||||
/// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id"
|
||||
/// where url is the test to run, and id is the id of the test.
|
||||
/// If there are currently no available tests the waitSignal is send
|
||||
/// back. If we are in the process of terminating the terminateSignal
|
||||
/// is send back and the browser will stop requesting new tasks.
|
||||
/// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed
|
||||
/// test
|
||||
class BrowserTestingServer {
|
||||
final TestConfiguration configuration;
|
||||
|
||||
/// Interface of the testing server:
|
||||
///
|
||||
/// GET /driver/BROWSER_ID -- This will get the driver page to fetch
|
||||
/// and run tests ...
|
||||
/// GET /next_test/BROWSER_ID -- returns "WAIT" "TERMINATE" or "url#id"
|
||||
/// where url is the test to run, and id is the id of the test.
|
||||
/// If there are currently no available tests the waitSignal is send
|
||||
/// back. If we are in the process of terminating the terminateSignal
|
||||
/// is send back and the browser will stop requesting new tasks.
|
||||
/// POST /report/BROWSER_ID?id=NUM -- sends back the dom of the executed
|
||||
/// test
|
||||
|
||||
final String localIp;
|
||||
final bool requiresFocus;
|
||||
BrowserTestRunner testRunner;
|
||||
|
@ -1216,11 +1193,11 @@ class BrowserTestingServer {
|
|||
void setupErrorServer(HttpServer server) {
|
||||
errorReportingServer = server;
|
||||
void errorReportingHandler(HttpRequest request) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
var buffer = StringBuffer();
|
||||
request.transform(utf8.decoder).listen((data) {
|
||||
buffer.write(data);
|
||||
}, onDone: () {
|
||||
String back = buffer.toString();
|
||||
var back = buffer.toString();
|
||||
request.response.headers.set("Access-Control-Allow-Origin", "*");
|
||||
request.response.done.catchError((error) {
|
||||
DebugLogger.error("Error getting error from browser"
|
||||
|
@ -1278,15 +1255,15 @@ class BrowserTestingServer {
|
|||
textResponse = getDriverPage(browserId(request, driverPath));
|
||||
request.response.headers.set('Content-Type', 'text/html');
|
||||
} else if (request.uri.path.startsWith(nextTestPath)) {
|
||||
textResponse = new Future<String>.value(
|
||||
getNextTest(browserId(request, nextTestPath)));
|
||||
textResponse =
|
||||
Future.value(getNextTest(browserId(request, nextTestPath)));
|
||||
request.response.headers.set('Content-Type', 'text/plain');
|
||||
} else {
|
||||
textResponse = new Future<String>.value("");
|
||||
textResponse = Future.value("");
|
||||
}
|
||||
request.response.done.catchError((error) async {
|
||||
if (!underTermination) {
|
||||
String text = await textResponse;
|
||||
var text = await textResponse;
|
||||
print("URI ${request.uri}");
|
||||
print("text $text");
|
||||
throw "Error returning content to browser: $error";
|
||||
|
@ -1307,11 +1284,11 @@ class BrowserTestingServer {
|
|||
|
||||
void handleReport(HttpRequest request, String browserId, int testId,
|
||||
{bool isStatusUpdate}) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
var buffer = StringBuffer();
|
||||
request.transform(utf8.decoder).listen((data) {
|
||||
buffer.write(data);
|
||||
}, onDone: () {
|
||||
String back = buffer.toString();
|
||||
var back = buffer.toString();
|
||||
request.response.close();
|
||||
if (isStatusUpdate) {
|
||||
testStatusUpdateCallBack(browserId, back, testId);
|
||||
|
@ -1325,14 +1302,14 @@ class BrowserTestingServer {
|
|||
}
|
||||
|
||||
void handleStarted(HttpRequest request, String browserId, int testId) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
var buffer = StringBuffer();
|
||||
// If an error occurs while receiving the data from the request stream,
|
||||
// we don't handle it specially. We can safely ignore it, since the started
|
||||
// events are not crucial.
|
||||
request.transform(utf8.decoder).listen((data) {
|
||||
buffer.write(data);
|
||||
}, onDone: () {
|
||||
String back = buffer.toString();
|
||||
var back = buffer.toString();
|
||||
request.response.close();
|
||||
testStartedCallBack(browserId, back, testId);
|
||||
}, onError: (error) {
|
||||
|
@ -1365,7 +1342,7 @@ class BrowserTestingServer {
|
|||
await testRunner.browserStatus[browserId].browser.onDriverPageRequested();
|
||||
var errorReportingUrl =
|
||||
"http://$localIp:${errorReportingServer.port}/$browserId";
|
||||
String driverContent = """
|
||||
var driverContent = """
|
||||
<!DOCTYPE html><html>
|
||||
<head>
|
||||
<title>Driving page</title>
|
||||
|
|
|
@ -7,10 +7,10 @@ import 'path.dart';
|
|||
import 'test_suite.dart';
|
||||
|
||||
class Co19TestSuite extends StandardTestSuite {
|
||||
RegExp _testRegExp = new RegExp(r"t[0-9]{2}.dart$");
|
||||
static final _testRegExp = RegExp(r"t[0-9]{2}.dart$");
|
||||
|
||||
Co19TestSuite(TestConfiguration configuration, String selector)
|
||||
: super(configuration, selector, new Path("tests/$selector/src"), [
|
||||
: super(configuration, selector, Path("tests/$selector/src"), [
|
||||
"tests/$selector/$selector-co19.status",
|
||||
"tests/$selector/$selector-analyzer.status",
|
||||
"tests/$selector/$selector-runtime.status",
|
||||
|
|
|
@ -18,7 +18,7 @@ import 'utils.dart';
|
|||
class Command {
|
||||
static Command browserTest(String url, TestConfiguration configuration,
|
||||
{bool retry}) {
|
||||
return new BrowserTestCommand._(url, configuration, retry);
|
||||
return BrowserTestCommand._(url, configuration, retry);
|
||||
}
|
||||
|
||||
static Command compilation(
|
||||
|
@ -28,9 +28,9 @@ class Command {
|
|||
String executable,
|
||||
List<String> arguments,
|
||||
Map<String, String> environment,
|
||||
{bool alwaysCompile: false,
|
||||
{bool alwaysCompile = false,
|
||||
String workingDirectory}) {
|
||||
return new CompilationCommand._(displayName, outputFile, alwaysCompile,
|
||||
return CompilationCommand._(displayName, outputFile, alwaysCompile,
|
||||
bootstrapDependencies, executable, arguments, environment,
|
||||
workingDirectory: workingDirectory);
|
||||
}
|
||||
|
@ -43,36 +43,35 @@ class Command {
|
|||
List<String> arguments,
|
||||
Map<String, String> environment,
|
||||
List<String> batchArgs) {
|
||||
return new VMKernelCompilationCommand._(outputFile, neverSkipCompilation,
|
||||
return VMKernelCompilationCommand._(outputFile, neverSkipCompilation,
|
||||
bootstrapDependencies, executable, arguments, environment, batchArgs);
|
||||
}
|
||||
|
||||
static Command analysis(String executable, List<String> arguments,
|
||||
Map<String, String> environmentOverrides) {
|
||||
return new AnalysisCommand._(executable, arguments, environmentOverrides);
|
||||
return AnalysisCommand._(executable, arguments, environmentOverrides);
|
||||
}
|
||||
|
||||
static Command compareAnalyzerCfe(String executable, List<String> arguments,
|
||||
Map<String, String> environmentOverrides) {
|
||||
return new CompareAnalyzerCfeCommand._(
|
||||
return CompareAnalyzerCfeCommand._(
|
||||
executable, arguments, environmentOverrides);
|
||||
}
|
||||
|
||||
static Command specParse(String executable, List<String> arguments,
|
||||
Map<String, String> environmentOverrides) {
|
||||
return new SpecParseCommand._(executable, arguments, environmentOverrides);
|
||||
return SpecParseCommand._(executable, arguments, environmentOverrides);
|
||||
}
|
||||
|
||||
static Command vm(String executable, List<String> arguments,
|
||||
Map<String, String> environmentOverrides) {
|
||||
return new VmCommand._(executable, arguments, environmentOverrides);
|
||||
return VmCommand._(executable, arguments, environmentOverrides);
|
||||
}
|
||||
|
||||
static Command vmBatch(String executable, String tester,
|
||||
List<String> arguments, Map<String, String> environmentOverrides,
|
||||
{bool checked: true}) {
|
||||
return new VmBatchCommand._(
|
||||
executable, tester, arguments, environmentOverrides,
|
||||
{bool checked = true}) {
|
||||
return VmBatchCommand._(executable, tester, arguments, environmentOverrides,
|
||||
checked: checked);
|
||||
}
|
||||
|
||||
|
@ -83,37 +82,36 @@ class Command {
|
|||
List<String> arguments,
|
||||
bool useBlobs,
|
||||
bool useElf) {
|
||||
return new AdbPrecompilationCommand._(precompiledRunner, processTest,
|
||||
return AdbPrecompilationCommand._(precompiledRunner, processTest,
|
||||
testDirectory, arguments, useBlobs, useElf);
|
||||
}
|
||||
|
||||
static Command adbDartk(String precompiledRunner, String processTest,
|
||||
String script, List<String> arguments, List<String> extraLibraries) {
|
||||
return new AdbDartkCommand._(
|
||||
return AdbDartkCommand._(
|
||||
precompiledRunner, processTest, script, arguments, extraLibraries);
|
||||
}
|
||||
|
||||
static Command jsCommandLine(
|
||||
String displayName, String executable, List<String> arguments,
|
||||
[Map<String, String> environment]) {
|
||||
return new JSCommandlineCommand._(
|
||||
return JSCommandlineCommand._(
|
||||
displayName, executable, arguments, environment);
|
||||
}
|
||||
|
||||
static Command process(
|
||||
String displayName, String executable, List<String> arguments,
|
||||
[Map<String, String> environment, String workingDirectory]) {
|
||||
return new ProcessCommand._(
|
||||
return ProcessCommand._(
|
||||
displayName, executable, arguments, environment, workingDirectory);
|
||||
}
|
||||
|
||||
static Command copy(String sourceDirectory, String destinationDirectory) {
|
||||
return new CleanDirectoryCopyCommand._(
|
||||
sourceDirectory, destinationDirectory);
|
||||
return CleanDirectoryCopyCommand._(sourceDirectory, destinationDirectory);
|
||||
}
|
||||
|
||||
static Command makeSymlink(String link, String target) {
|
||||
return new MakeSymlinkCommand._(link, target);
|
||||
return MakeSymlinkCommand._(link, target);
|
||||
}
|
||||
|
||||
static Command fasta(
|
||||
|
@ -124,7 +122,7 @@ class Command {
|
|||
List<String> arguments,
|
||||
Map<String, String> environment,
|
||||
Uri workingDirectory) {
|
||||
return new FastaCompilationCommand._(
|
||||
return FastaCompilationCommand._(
|
||||
compilerLocation,
|
||||
outputFile.toFilePath(),
|
||||
bootstrapDependencies,
|
||||
|
@ -163,7 +161,7 @@ class Command {
|
|||
|
||||
int get hashCode {
|
||||
if (_cachedHashCode == null) {
|
||||
var builder = new HashCodeBuilder();
|
||||
var builder = HashCodeBuilder();
|
||||
_buildHashCode(builder);
|
||||
_cachedHashCode = builder.value;
|
||||
}
|
||||
|
@ -234,7 +232,7 @@ class ProcessCommand extends Command {
|
|||
deepJsonCompare(environmentOverrides, other.environmentOverrides);
|
||||
|
||||
String get reproductionCommand {
|
||||
var env = new StringBuffer();
|
||||
var env = StringBuffer();
|
||||
environmentOverrides?.forEach((key, value) =>
|
||||
(io.Platform.operatingSystem == 'windows')
|
||||
? env.write('set $key=${escapeCommandLineArgument(value)} & ')
|
||||
|
@ -292,7 +290,7 @@ class CompilationCommand extends ProcessCommand {
|
|||
bool get outputIsUpToDate {
|
||||
if (_alwaysCompile) return false;
|
||||
|
||||
var file = new io.File(new Path("$outputFile.deps").toNativePath());
|
||||
var file = io.File(Path("$outputFile.deps").toNativePath());
|
||||
if (!file.existsSync()) return false;
|
||||
|
||||
var lines = file.readAsLinesSync();
|
||||
|
@ -306,7 +304,7 @@ class CompilationCommand extends ProcessCommand {
|
|||
|
||||
dependencies.addAll(_bootstrapDependencies);
|
||||
var jsOutputLastModified = TestUtils.lastModifiedCache
|
||||
.getLastModified(new Uri(scheme: 'file', path: outputFile));
|
||||
.getLastModified(Uri(scheme: 'file', path: outputFile));
|
||||
if (jsOutputLastModified == null) return false;
|
||||
|
||||
for (var dependency in dependencies) {
|
||||
|
@ -374,12 +372,12 @@ class FastaCompilationCommand extends CompilationCommand {
|
|||
String relativizeAndEscape(String argument) {
|
||||
if (workingDirectory != null) {
|
||||
argument = argument.replaceAll(
|
||||
workingDirectory, new Uri.directory(".").toFilePath());
|
||||
workingDirectory, Uri.directory(".").toFilePath());
|
||||
}
|
||||
return escapeCommandLineArgument(argument);
|
||||
}
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
StringBuffer buffer = StringBuffer();
|
||||
if (workingDirectory != null && !io.Platform.isWindows) {
|
||||
buffer.write("(cd ");
|
||||
buffer.write(escapeCommandLineArgument(workingDirectory));
|
||||
|
@ -561,7 +559,7 @@ class VmBatchCommand extends ProcessCommand implements VmCommand {
|
|||
|
||||
VmBatchCommand._(String executable, String dartFile, List<String> arguments,
|
||||
Map<String, String> environmentOverrides,
|
||||
{this.checked: true, int index = 0})
|
||||
{this.checked = true, int index = 0})
|
||||
: this.dartFile = dartFile,
|
||||
super._('vm-batch', executable, arguments, environmentOverrides, null,
|
||||
index);
|
||||
|
@ -705,24 +703,24 @@ class CleanDirectoryCopyCommand extends ScriptCommand {
|
|||
"Copying '$_sourceDirectory' to '$_destinationDirectory'.";
|
||||
|
||||
Future<ScriptCommandOutput> run() {
|
||||
var watch = new Stopwatch()..start();
|
||||
var watch = Stopwatch()..start();
|
||||
|
||||
var destination = new io.Directory(_destinationDirectory);
|
||||
var destination = io.Directory(_destinationDirectory);
|
||||
|
||||
return destination.exists().then((bool exists) {
|
||||
Future cleanDirectoryFuture;
|
||||
if (exists) {
|
||||
cleanDirectoryFuture = TestUtils.deleteDirectory(_destinationDirectory);
|
||||
} else {
|
||||
cleanDirectoryFuture = new Future.value(null);
|
||||
cleanDirectoryFuture = Future.value(null);
|
||||
}
|
||||
return cleanDirectoryFuture.then((_) {
|
||||
return TestUtils.copyDirectory(_sourceDirectory, _destinationDirectory);
|
||||
});
|
||||
}).then((_) {
|
||||
return new ScriptCommandOutput(this, Expectation.pass, "", watch.elapsed);
|
||||
return ScriptCommandOutput(this, Expectation.pass, "", watch.elapsed);
|
||||
}).catchError((error) {
|
||||
return new ScriptCommandOutput(
|
||||
return ScriptCommandOutput(
|
||||
this, Expectation.fail, "An error occured: $error.", watch.elapsed);
|
||||
});
|
||||
}
|
||||
|
@ -754,21 +752,21 @@ class MakeSymlinkCommand extends ScriptCommand {
|
|||
"Make symbolic link '$_link' (target: $_target)'.";
|
||||
|
||||
Future<ScriptCommandOutput> run() {
|
||||
var watch = new Stopwatch()..start();
|
||||
var targetFile = new io.Directory(_target);
|
||||
var watch = Stopwatch()..start();
|
||||
var targetFile = io.Directory(_target);
|
||||
return targetFile.exists().then((bool targetExists) {
|
||||
if (!targetExists) {
|
||||
throw new Exception("Target '$_target' does not exist");
|
||||
throw Exception("Target '$_target' does not exist");
|
||||
}
|
||||
var link = new io.Link(_link);
|
||||
var link = io.Link(_link);
|
||||
|
||||
return link.exists().then((bool exists) {
|
||||
if (exists) link.deleteSync();
|
||||
}).then((_) => link.create(_target));
|
||||
}).then((_) {
|
||||
return new ScriptCommandOutput(this, Expectation.pass, "", watch.elapsed);
|
||||
return ScriptCommandOutput(this, Expectation.pass, "", watch.elapsed);
|
||||
}).catchError((error) {
|
||||
return new ScriptCommandOutput(
|
||||
return ScriptCommandOutput(
|
||||
this, Expectation.fail, "An error occured: $error.", watch.elapsed);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'package:status_file/expectation.dart';
|
|||
import 'browser_controller.dart';
|
||||
import 'command.dart';
|
||||
import 'configuration.dart';
|
||||
import 'process_queue.dart';
|
||||
import 'test_progress.dart';
|
||||
import 'test_case.dart';
|
||||
import 'utils.dart';
|
||||
|
@ -149,7 +150,7 @@ class CommandOutput extends UniqueObject {
|
|||
}
|
||||
|
||||
class BrowserTestJsonResult {
|
||||
static const _allowedTypes = const [
|
||||
static const _allowedTypes = [
|
||||
'sync_exception',
|
||||
'window_onerror',
|
||||
'script_onerror',
|
||||
|
@ -211,7 +212,7 @@ class BrowserTestJsonResult {
|
|||
dom = '$dom\n';
|
||||
}
|
||||
|
||||
return new BrowserTestJsonResult(
|
||||
return BrowserTestJsonResult(
|
||||
_getOutcome(messagesByType), dom, events as List<dynamic>);
|
||||
}
|
||||
} catch (error) {
|
||||
|
@ -311,7 +312,7 @@ class BrowserCommandOutput extends CommandOutput
|
|||
}
|
||||
}
|
||||
|
||||
return new BrowserCommandOutput._internal(command, result, outcome,
|
||||
return BrowserCommandOutput._internal(command, result, outcome,
|
||||
parsedResult, encodeUtf8(""), encodeUtf8(stderr));
|
||||
}
|
||||
|
||||
|
@ -528,7 +529,7 @@ class AnalysisCommandOutput extends CommandOutput {
|
|||
// Parse a line delimited by the | character using \ as an escape character
|
||||
// like: FOO|BAR|FOO\|BAR|FOO\\BAZ as 4 fields: FOO BAR FOO|BAR FOO\BAZ
|
||||
List<String> splitMachineError(String line) {
|
||||
var field = new StringBuffer();
|
||||
var field = StringBuffer();
|
||||
var result = <String>[];
|
||||
var escaped = false;
|
||||
for (var i = 0; i < line.length; i++) {
|
||||
|
@ -540,7 +541,7 @@ class AnalysisCommandOutput extends CommandOutput {
|
|||
escaped = false;
|
||||
if (c == '|') {
|
||||
result.add(field.toString());
|
||||
field = new StringBuffer();
|
||||
field = StringBuffer();
|
||||
continue;
|
||||
}
|
||||
field.write(c);
|
||||
|
@ -1022,40 +1023,40 @@ CommandOutput createCommandOutput(Command command, int exitCode, bool timedOut,
|
|||
List<int> stdout, List<int> stderr, Duration time, bool compilationSkipped,
|
||||
[int pid = 0]) {
|
||||
if (command is AnalysisCommand) {
|
||||
return new AnalysisCommandOutput(
|
||||
return AnalysisCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
|
||||
} else if (command is CompareAnalyzerCfeCommand) {
|
||||
return new CompareAnalyzerCfeCommandOutput(
|
||||
return CompareAnalyzerCfeCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
|
||||
} else if (command is SpecParseCommand) {
|
||||
return new SpecParseCommandOutput(
|
||||
return SpecParseCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
|
||||
} else if (command is VmCommand) {
|
||||
return new VMCommandOutput(
|
||||
return VMCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, pid);
|
||||
} else if (command is VMKernelCompilationCommand) {
|
||||
return new VMKernelCompilationCommandOutput(
|
||||
return VMKernelCompilationCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
|
||||
} else if (command is AdbPrecompilationCommand) {
|
||||
return new VMCommandOutput(
|
||||
return VMCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, pid);
|
||||
} else if (command is CompilationCommand) {
|
||||
if (command.displayName == 'precompiler' ||
|
||||
command.displayName == 'app_jit') {
|
||||
return new VMCommandOutput(
|
||||
return VMCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, pid);
|
||||
} else if (command.displayName == 'dartdevc') {
|
||||
return new DevCompilerCommandOutput(command, exitCode, timedOut, stdout,
|
||||
return DevCompilerCommandOutput(command, exitCode, timedOut, stdout,
|
||||
stderr, time, compilationSkipped, pid);
|
||||
}
|
||||
return new CompilationCommandOutput(
|
||||
return CompilationCommandOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time, compilationSkipped);
|
||||
} else if (command is JSCommandlineCommand) {
|
||||
return new JSCommandLineOutput(
|
||||
return JSCommandLineOutput(
|
||||
command, exitCode, timedOut, stdout, stderr, time);
|
||||
}
|
||||
|
||||
return new CommandOutput(command, exitCode, timedOut, stdout, stderr, time,
|
||||
return CommandOutput(command, exitCode, timedOut, stdout, stderr, time,
|
||||
compilationSkipped, pid);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,29 +53,28 @@ abstract class CompilerConfiguration {
|
|||
factory CompilerConfiguration(TestConfiguration configuration) {
|
||||
switch (configuration.compiler) {
|
||||
case Compiler.dart2analyzer:
|
||||
return new AnalyzerCompilerConfiguration(configuration);
|
||||
return AnalyzerCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.compareAnalyzerCfe:
|
||||
return new CompareAnalyzerCfeCompilerConfiguration(configuration);
|
||||
return CompareAnalyzerCfeCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.dart2js:
|
||||
return new Dart2jsCompilerConfiguration(configuration);
|
||||
return Dart2jsCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.dartdevc:
|
||||
return new DevCompilerConfiguration(configuration);
|
||||
return DevCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.dartdevk:
|
||||
return new DevCompilerConfiguration(configuration);
|
||||
return DevCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.appJit:
|
||||
return new AppJitCompilerConfiguration(configuration,
|
||||
previewDart2: false);
|
||||
return AppJitCompilerConfiguration(configuration, previewDart2: false);
|
||||
|
||||
case Compiler.appJitk:
|
||||
return new AppJitCompilerConfiguration(configuration);
|
||||
return AppJitCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.precompiler:
|
||||
return new PrecompilerCompilerConfiguration(configuration,
|
||||
return PrecompilerCompilerConfiguration(configuration,
|
||||
previewDart2: false);
|
||||
|
||||
case Compiler.dartk:
|
||||
|
@ -83,24 +82,24 @@ abstract class CompilerConfiguration {
|
|||
configuration.architecture == Architecture.simarm ||
|
||||
configuration.architecture == Architecture.simarm64 ||
|
||||
configuration.system == System.android) {
|
||||
return new VMKernelCompilerConfiguration(configuration);
|
||||
return VMKernelCompilerConfiguration(configuration);
|
||||
}
|
||||
return new NoneCompilerConfiguration(configuration);
|
||||
return NoneCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.dartkb:
|
||||
return new VMKernelCompilerConfiguration(configuration);
|
||||
return VMKernelCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.dartkp:
|
||||
return new PrecompilerCompilerConfiguration(configuration);
|
||||
return PrecompilerCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.specParser:
|
||||
return new SpecParserCompilerConfiguration(configuration);
|
||||
return SpecParserCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.fasta:
|
||||
return new FastaCompilerConfiguration(configuration);
|
||||
return FastaCompilerConfiguration(configuration);
|
||||
|
||||
case Compiler.none:
|
||||
return new NoneCompilerConfiguration(configuration);
|
||||
return NoneCompilerConfiguration(configuration);
|
||||
}
|
||||
|
||||
throw "unreachable";
|
||||
|
@ -134,7 +133,7 @@ abstract class CompilerConfiguration {
|
|||
String tempDir,
|
||||
List<String> arguments,
|
||||
Map<String, String> environmentOverrides) {
|
||||
return new CommandArtifact([], null, null);
|
||||
return CommandArtifact([], null, null);
|
||||
}
|
||||
|
||||
List<String> computeCompilerArguments(
|
||||
|
@ -224,7 +223,7 @@ class VMKernelCompilerConfiguration extends CompilerConfiguration
|
|||
final commands = <Command>[
|
||||
computeCompileToKernelCommand(tempDir, arguments, environmentOverrides),
|
||||
];
|
||||
return new CommandArtifact(commands, tempKernelFile(tempDir),
|
||||
return CommandArtifact(commands, tempKernelFile(tempDir),
|
||||
'application/kernel-ir-fully-linked');
|
||||
}
|
||||
|
||||
|
@ -274,7 +273,7 @@ class VMKernelCompilerConfiguration extends CompilerConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
typedef List<String> CompilerArgumentsFunction(
|
||||
typedef CompilerArgumentsFunction = List<String> Function(
|
||||
List<String> globalArguments, String previousCompilerOutput);
|
||||
|
||||
class PipelineCommand {
|
||||
|
@ -285,7 +284,7 @@ class PipelineCommand {
|
|||
|
||||
factory PipelineCommand.runWithGlobalArguments(
|
||||
CompilerConfiguration configuration) {
|
||||
return new PipelineCommand._(configuration,
|
||||
return PipelineCommand._(configuration,
|
||||
(List<String> globalArguments, String previousOutput) {
|
||||
assert(previousOutput == null);
|
||||
return globalArguments;
|
||||
|
@ -294,7 +293,7 @@ class PipelineCommand {
|
|||
|
||||
factory PipelineCommand.runWithDartOrKernelFile(
|
||||
CompilerConfiguration configuration) {
|
||||
return new PipelineCommand._(configuration,
|
||||
return PipelineCommand._(configuration,
|
||||
(List<String> globalArguments, String previousOutput) {
|
||||
var filtered = globalArguments
|
||||
.where((name) => name.endsWith('.dart') || name.endsWith('.dill'))
|
||||
|
@ -306,7 +305,7 @@ class PipelineCommand {
|
|||
|
||||
factory PipelineCommand.runWithPreviousKernelOutput(
|
||||
CompilerConfiguration configuration) {
|
||||
return new PipelineCommand._(configuration,
|
||||
return PipelineCommand._(configuration,
|
||||
(List<String> globalArguments, String previousOutput) {
|
||||
assert(previousOutput.endsWith('.dill'));
|
||||
return _replaceDartFiles(globalArguments, previousOutput);
|
||||
|
@ -349,8 +348,7 @@ class ComposedCompilerConfiguration extends CompilerConfiguration {
|
|||
allCommands.addAll(artifact.commands);
|
||||
}
|
||||
|
||||
return new CommandArtifact(
|
||||
allCommands, artifact.filename, artifact.mimeType);
|
||||
return CommandArtifact(allCommands, artifact.filename, artifact.mimeType);
|
||||
}
|
||||
|
||||
List<String> computeCompilerArguments(
|
||||
|
@ -438,7 +436,7 @@ class Dart2xCompilerConfiguration extends CompilerConfiguration {
|
|||
_configuration.buildDirectory,
|
||||
() => [
|
||||
Uri.base
|
||||
.resolveUri(new Uri.directory(_configuration.buildDirectory))
|
||||
.resolveUri(Uri.directory(_configuration.buildDirectory))
|
||||
.resolve('dart-sdk/bin/snapshots/dart2js.dart.snapshot')
|
||||
]);
|
||||
}
|
||||
|
@ -480,7 +478,7 @@ class Dart2jsCompilerConfiguration extends Dart2xCompilerConfiguration {
|
|||
// TODO(athom): input filename extraction is copied from DDC. Maybe this
|
||||
// should be passed to computeCompilationArtifact, instead?
|
||||
var inputFile = arguments.last;
|
||||
var inputFilename = (new Uri.file(inputFile)).pathSegments.last;
|
||||
var inputFilename = (Uri.file(inputFile)).pathSegments.last;
|
||||
var out = "$tempDir/${inputFilename.replaceAll('.dart', '.js')}";
|
||||
var babel = _configuration.babel;
|
||||
var babelOut = out;
|
||||
|
@ -494,7 +492,7 @@ class Dart2jsCompilerConfiguration extends Dart2xCompilerConfiguration {
|
|||
commands.add(computeBabelCommand(out, babelOut, babel));
|
||||
}
|
||||
|
||||
return new CommandArtifact(commands, babelOut, 'application/javascript');
|
||||
return CommandArtifact(commands, babelOut, 'application/javascript');
|
||||
}
|
||||
|
||||
List<String> computeRuntimeArguments(
|
||||
|
@ -506,8 +504,8 @@ class Dart2jsCompilerConfiguration extends Dart2xCompilerConfiguration {
|
|||
List<String> originalArguments,
|
||||
CommandArtifact artifact) {
|
||||
Uri sdk = _useSdk
|
||||
? new Uri.directory(_configuration.buildDirectory).resolve('dart-sdk/')
|
||||
: new Uri.directory(Repository.dir.toNativePath()).resolve('sdk/');
|
||||
? Uri.directory(_configuration.buildDirectory).resolve('dart-sdk/')
|
||||
: Uri.directory(Repository.dir.toNativePath()).resolve('sdk/');
|
||||
Uri preambleDir = sdk.resolve('lib/_internal/js_runtime/lib/preambles/');
|
||||
return runtimeConfiguration.dart2jsPreambles(preambleDir)
|
||||
..add(artifact.filename);
|
||||
|
@ -589,7 +587,7 @@ class DevCompilerConfiguration extends CompilerConfiguration {
|
|||
// at the built summary file location.
|
||||
var sdkSummaryFile =
|
||||
useDillFormat ? 'kernel/ddc_sdk.dill' : 'ddc_sdk.sum';
|
||||
var sdkSummary = new Path(_configuration.buildDirectory)
|
||||
var sdkSummary = Path(_configuration.buildDirectory)
|
||||
.append("/gen/utils/dartdevc/$sdkSummaryFile")
|
||||
.absolute
|
||||
.toNativePath();
|
||||
|
@ -600,7 +598,7 @@ class DevCompilerConfiguration extends CompilerConfiguration {
|
|||
if (!useKernel) {
|
||||
// TODO(jmesserly): library-root needs to be removed.
|
||||
args.addAll(
|
||||
["--library-root", new Path(inputFile).directoryPath.toNativePath()]);
|
||||
["--library-root", Path(inputFile).directoryPath.toNativePath()]);
|
||||
}
|
||||
|
||||
args.addAll([
|
||||
|
@ -622,15 +620,14 @@ class DevCompilerConfiguration extends CompilerConfiguration {
|
|||
// Since the summaries for the packages are not near the tests, we give
|
||||
// dartdevc explicit module paths for each one. When the test is run, we
|
||||
// will tell require.js where to find each package's compiled JS.
|
||||
var summary = new Path(_configuration.buildDirectory)
|
||||
var summary = Path(_configuration.buildDirectory)
|
||||
.append("/gen/utils/dartdevc/$pkgDir/$package.$pkgExtension")
|
||||
.absolute
|
||||
.toNativePath();
|
||||
args.add("$summary=$package");
|
||||
}
|
||||
|
||||
var inputDir =
|
||||
new Path(inputFile).append("..").canonicalize().toNativePath();
|
||||
var inputDir = Path(inputFile).append("..").canonicalize().toNativePath();
|
||||
var displayName = useKernel ? 'dartdevk' : 'dartdevc';
|
||||
return Command.compilation(displayName, outputFile, bootstrapDependencies(),
|
||||
computeCompilerPath(), args, environment,
|
||||
|
@ -646,10 +643,10 @@ class DevCompilerConfiguration extends CompilerConfiguration {
|
|||
// computeCompilerArguments() to here seems hacky. Is there a cleaner way?
|
||||
var sharedOptions = arguments.sublist(0, arguments.length - 1);
|
||||
var inputFile = arguments.last;
|
||||
var inputFilename = (new Uri.file(inputFile)).pathSegments.last;
|
||||
var inputFilename = (Uri.file(inputFile)).pathSegments.last;
|
||||
var outputFile = "$tempDir/${inputFilename.replaceAll('.dart', '.js')}";
|
||||
|
||||
return new CommandArtifact(
|
||||
return CommandArtifact(
|
||||
[_createCommand(inputFile, outputFile, sharedOptions, environment)],
|
||||
outputFile,
|
||||
"application/javascript");
|
||||
|
@ -669,7 +666,7 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
|
|||
bool get _isAot => true;
|
||||
|
||||
PrecompilerCompilerConfiguration(TestConfiguration configuration,
|
||||
{this.previewDart2: true})
|
||||
{this.previewDart2 = true})
|
||||
: super._subclass(configuration);
|
||||
|
||||
int get timeoutMultiplier {
|
||||
|
@ -703,7 +700,7 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
|
|||
}
|
||||
}
|
||||
|
||||
return new CommandArtifact(
|
||||
return CommandArtifact(
|
||||
commands, '$tempDir', 'application/dart-precompiled');
|
||||
}
|
||||
|
||||
|
@ -913,7 +910,7 @@ class AppJitCompilerConfiguration extends CompilerConfiguration {
|
|||
final bool previewDart2;
|
||||
|
||||
AppJitCompilerConfiguration(TestConfiguration configuration,
|
||||
{this.previewDart2: true})
|
||||
{this.previewDart2 = true})
|
||||
: super._subclass(configuration);
|
||||
|
||||
int get timeoutMultiplier {
|
||||
|
@ -926,7 +923,7 @@ class AppJitCompilerConfiguration extends CompilerConfiguration {
|
|||
CommandArtifact computeCompilationArtifact(String tempDir,
|
||||
List<String> arguments, Map<String, String> environmentOverrides) {
|
||||
var snapshot = "$tempDir/out.jitsnapshot";
|
||||
return new CommandArtifact(
|
||||
return CommandArtifact(
|
||||
[computeCompilationCommand(tempDir, arguments, environmentOverrides)],
|
||||
snapshot,
|
||||
'application/dart-snapshot');
|
||||
|
@ -1013,7 +1010,7 @@ class AnalyzerCompilerConfiguration extends CompilerConfiguration {
|
|||
List<String> arguments, Map<String, String> environmentOverrides) {
|
||||
arguments = arguments.toList();
|
||||
if (!previewDart2) {
|
||||
throw new ArgumentError('--no-preview-dart-2 not supported');
|
||||
throw ArgumentError('--no-preview-dart-2 not supported');
|
||||
}
|
||||
if (_configuration.useAnalyzerCfe) {
|
||||
arguments.add('--use-cfe');
|
||||
|
@ -1023,7 +1020,7 @@ class AnalyzerCompilerConfiguration extends CompilerConfiguration {
|
|||
}
|
||||
|
||||
// Since this is not a real compilation, no artifacts are produced.
|
||||
return new CommandArtifact([
|
||||
return CommandArtifact([
|
||||
Command.analysis(computeCompilerPath(), arguments, environmentOverrides)
|
||||
], null, null);
|
||||
}
|
||||
|
@ -1059,11 +1056,11 @@ class CompareAnalyzerCfeCompilerConfiguration extends CompilerConfiguration {
|
|||
List<String> arguments, Map<String, String> environmentOverrides) {
|
||||
arguments = arguments.toList();
|
||||
if (!previewDart2) {
|
||||
throw new ArgumentError('--no-preview-dart-2 not supported');
|
||||
throw ArgumentError('--no-preview-dart-2 not supported');
|
||||
}
|
||||
|
||||
// Since this is not a real compilation, no artifacts are produced.
|
||||
return new CommandArtifact([
|
||||
return CommandArtifact([
|
||||
Command.compareAnalyzerCfe(
|
||||
computeCompilerPath(), arguments, environmentOverrides)
|
||||
], null, null);
|
||||
|
@ -1093,7 +1090,7 @@ class SpecParserCompilerConfiguration extends CompilerConfiguration {
|
|||
arguments = arguments.toList();
|
||||
|
||||
// Since this is not a real compilation, no artifacts are produced.
|
||||
return new CommandArtifact([
|
||||
return CommandArtifact([
|
||||
Command.specParse(computeCompilerPath(), arguments, environmentOverrides)
|
||||
], null, null);
|
||||
}
|
||||
|
@ -1112,7 +1109,7 @@ class SpecParserCompilerConfiguration extends CompilerConfiguration {
|
|||
|
||||
abstract class VMKernelCompilerMixin {
|
||||
static final noCausalAsyncStacksRegExp =
|
||||
new RegExp('--no[_-]causal[_-]async[_-]stacks');
|
||||
RegExp('--no[_-]causal[_-]async[_-]stacks');
|
||||
|
||||
TestConfiguration get _configuration;
|
||||
|
||||
|
@ -1127,7 +1124,7 @@ abstract class VMKernelCompilerMixin {
|
|||
List<Uri> bootstrapDependencies();
|
||||
|
||||
String tempKernelFile(String tempDir) =>
|
||||
new Path('$tempDir/out.dill').toNativePath();
|
||||
Path('$tempDir/out.dill').toNativePath();
|
||||
|
||||
Command computeCompileToKernelCommand(String tempDir, List<String> arguments,
|
||||
Map<String, String> environmentOverrides) {
|
||||
|
@ -1202,7 +1199,7 @@ class FastaCompilerConfiguration extends CompilerConfiguration {
|
|||
|
||||
factory FastaCompilerConfiguration(TestConfiguration configuration) {
|
||||
var buildDirectory =
|
||||
Uri.base.resolveUri(new Uri.directory(configuration.buildDirectory));
|
||||
Uri.base.resolveUri(Uri.directory(configuration.buildDirectory));
|
||||
|
||||
var dillDir = buildDirectory;
|
||||
if (configuration.useSdk) {
|
||||
|
@ -1214,7 +1211,7 @@ class FastaCompilerConfiguration extends CompilerConfiguration {
|
|||
|
||||
var vmExecutable = buildDirectory
|
||||
.resolve(configuration.useSdk ? "dart-sdk/bin/dart" : "dart");
|
||||
return new FastaCompilerConfiguration._(
|
||||
return FastaCompilerConfiguration._(
|
||||
platformDill, vmExecutable, configuration);
|
||||
}
|
||||
|
||||
|
@ -1232,7 +1229,7 @@ class FastaCompilerConfiguration extends CompilerConfiguration {
|
|||
CommandArtifact computeCompilationArtifact(String tempDir,
|
||||
List<String> arguments, Map<String, String> environmentOverrides) {
|
||||
var output =
|
||||
Uri.base.resolveUri(new Uri.directory(tempDir)).resolve("out.dill");
|
||||
Uri.base.resolveUri(Uri.directory(tempDir)).resolve("out.dill");
|
||||
var outputFileName = output.toFilePath();
|
||||
|
||||
var compilerArguments = <String>['--verify'];
|
||||
|
@ -1244,7 +1241,7 @@ class FastaCompilerConfiguration extends CompilerConfiguration {
|
|||
["-o", outputFileName, "--platform", _platformDill.toFilePath()]);
|
||||
compilerArguments.addAll(arguments);
|
||||
|
||||
return new CommandArtifact([
|
||||
return CommandArtifact([
|
||||
Command.fasta(
|
||||
_compilerLocation,
|
||||
output,
|
||||
|
@ -1264,7 +1261,7 @@ class FastaCompilerConfiguration extends CompilerConfiguration {
|
|||
List<String> dart2jsOptions,
|
||||
List<String> ddcOptions,
|
||||
List<String> args) {
|
||||
List<String> arguments = new List<String>.from(sharedOptions);
|
||||
List<String> arguments = List<String>.from(sharedOptions);
|
||||
arguments.addAll(_configuration.sharedOptions);
|
||||
for (String argument in args) {
|
||||
if (argument == "--ignore-unrecognized-flags") continue;
|
||||
|
|
|
@ -173,7 +173,7 @@ class TestConfiguration {
|
|||
|
||||
TestingServers get servers {
|
||||
if (_servers == null) {
|
||||
throw new StateError("Servers have not been started yet.");
|
||||
throw StateError("Servers have not been started yet.");
|
||||
}
|
||||
return _servers;
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ class TestConfiguration {
|
|||
|
||||
String get windowsSdkPath {
|
||||
if (!Platform.isWindows) {
|
||||
throw new StateError(
|
||||
throw StateError(
|
||||
"Should not use windowsSdkPath when not running on Windows.");
|
||||
}
|
||||
|
||||
|
@ -263,8 +263,8 @@ class TestConfiguration {
|
|||
// When running tests on Windows, use cdb from depot_tools to dump
|
||||
// stack traces of tests timing out.
|
||||
try {
|
||||
var path = new Path("build/win_toolchain.json").toNativePath();
|
||||
var text = new File(path).readAsStringSync();
|
||||
var path = Path("build/win_toolchain.json").toNativePath();
|
||||
var text = File(path).readAsStringSync();
|
||||
_windowsSdkPath = jsonDecode(text)['win_sdk'] as String;
|
||||
} on dynamic {
|
||||
// Ignore errors here. If win_sdk is not found, stack trace dumping
|
||||
|
@ -293,29 +293,29 @@ class TestConfiguration {
|
|||
|
||||
if (location != null) return location;
|
||||
|
||||
const locations = const {
|
||||
Runtime.firefox: const {
|
||||
const locations = {
|
||||
Runtime.firefox: {
|
||||
System.win: 'C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe',
|
||||
System.linux: 'firefox',
|
||||
System.mac: '/Applications/Firefox.app/Contents/MacOS/firefox'
|
||||
},
|
||||
Runtime.chrome: const {
|
||||
Runtime.chrome: {
|
||||
System.win:
|
||||
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
||||
System.mac:
|
||||
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
||||
System.linux: 'google-chrome'
|
||||
},
|
||||
Runtime.safari: const {
|
||||
Runtime.safari: {
|
||||
System.mac: '/Applications/Safari.app/Contents/MacOS/Safari'
|
||||
},
|
||||
Runtime.ie9: const {
|
||||
Runtime.ie9: {
|
||||
System.win: 'C:\\Program Files\\Internet Explorer\\iexplore.exe'
|
||||
},
|
||||
Runtime.ie10: const {
|
||||
Runtime.ie10: {
|
||||
System.win: 'C:\\Program Files\\Internet Explorer\\iexplore.exe'
|
||||
},
|
||||
Runtime.ie11: const {
|
||||
Runtime.ie11: {
|
||||
System.win: 'C:\\Program Files\\Internet Explorer\\iexplore.exe'
|
||||
}
|
||||
};
|
||||
|
@ -332,12 +332,12 @@ class TestConfiguration {
|
|||
RuntimeConfiguration _runtimeConfiguration;
|
||||
|
||||
RuntimeConfiguration get runtimeConfiguration =>
|
||||
_runtimeConfiguration ??= new RuntimeConfiguration(this);
|
||||
_runtimeConfiguration ??= RuntimeConfiguration(this);
|
||||
|
||||
CompilerConfiguration _compilerConfiguration;
|
||||
|
||||
CompilerConfiguration get compilerConfiguration =>
|
||||
_compilerConfiguration ??= new CompilerConfiguration(this);
|
||||
_compilerConfiguration ??= CompilerConfiguration(this);
|
||||
|
||||
/// Determines if this configuration has a compatible compiler and runtime
|
||||
/// and other valid fields.
|
||||
|
@ -377,7 +377,7 @@ class TestConfiguration {
|
|||
/// server for cross-domain tests can be found by calling
|
||||
/// `getCrossOriginPortNumber()`.
|
||||
Future startServers() {
|
||||
_servers = new TestingServers(
|
||||
_servers = TestingServers(
|
||||
buildDirectory, isCsp, runtime, null, packageRoot, packages);
|
||||
var future = servers.startServers(localIP,
|
||||
port: testServerPort, crossOriginPort: testServerCrossOriginPort);
|
||||
|
@ -414,8 +414,8 @@ class TestConfiguration {
|
|||
var normal = '$modeName$os$arch';
|
||||
var cross = '$modeName${os}X$arch';
|
||||
var outDir = system.outputDirectory;
|
||||
var normalDir = new Directory(new Path('$outDir$normal').toNativePath());
|
||||
var crossDir = new Directory(new Path('$outDir$cross').toNativePath());
|
||||
var normalDir = Directory(Path('$outDir$normal').toNativePath());
|
||||
var crossDir = Directory(Path('$outDir$cross').toNativePath());
|
||||
|
||||
if (normalDir.existsSync() && crossDir.existsSync()) {
|
||||
throw "You can't have both $normalDir and $crossDir. We don't know which"
|
||||
|
@ -468,18 +468,18 @@ class TestConfiguration {
|
|||
}
|
||||
|
||||
class Progress {
|
||||
static const compact = const Progress._('compact');
|
||||
static const color = const Progress._('color');
|
||||
static const line = const Progress._('line');
|
||||
static const verbose = const Progress._('verbose');
|
||||
static const silent = const Progress._('silent');
|
||||
static const status = const Progress._('status');
|
||||
static const buildbot = const Progress._('buildbot');
|
||||
static const diff = const Progress._('diff');
|
||||
static const compact = Progress._('compact');
|
||||
static const color = Progress._('color');
|
||||
static const line = Progress._('line');
|
||||
static const verbose = Progress._('verbose');
|
||||
static const silent = Progress._('silent');
|
||||
static const status = Progress._('status');
|
||||
static const buildbot = Progress._('buildbot');
|
||||
static const diff = Progress._('diff');
|
||||
|
||||
static final List<String> names = _all.keys.toList();
|
||||
|
||||
static final _all = new Map<String, Progress>.fromIterable(
|
||||
static final _all = Map<String, Progress>.fromIterable(
|
||||
[compact, color, line, verbose, silent, status, buildbot, diff],
|
||||
key: (progress) => (progress as Progress).name);
|
||||
|
||||
|
@ -487,7 +487,7 @@ class Progress {
|
|||
var progress = _all[name];
|
||||
if (progress != null) return progress;
|
||||
|
||||
throw new ArgumentError('Unknown progress type "$name".');
|
||||
throw ArgumentError('Unknown progress type "$name".');
|
||||
}
|
||||
|
||||
final String name;
|
||||
|
|
|
@ -12,7 +12,7 @@ import 'utils.dart';
|
|||
/// The graph exposes a few broadcast streams that can be subscribed to in
|
||||
/// order to be notified of modifications to the graph.
|
||||
class Graph<T> {
|
||||
final _nodes = new Set<Node<T>>();
|
||||
final _nodes = <Node<T>>{};
|
||||
final _stateCounts = <NodeState, int>{};
|
||||
bool _isSealed = false;
|
||||
|
||||
|
@ -29,11 +29,11 @@ class Graph<T> {
|
|||
final StreamController<Null> _sealedController;
|
||||
|
||||
factory Graph() {
|
||||
var added = new StreamController<Node<T>>();
|
||||
var changed = new StreamController<StateChangedEvent<T>>();
|
||||
var sealed = new StreamController<Null>();
|
||||
var added = StreamController<Node<T>>();
|
||||
var changed = StreamController<StateChangedEvent<T>>();
|
||||
var sealed = StreamController<Null>();
|
||||
|
||||
return new Graph._(
|
||||
return Graph._(
|
||||
added,
|
||||
added.stream.asBroadcastStream(),
|
||||
changed,
|
||||
|
@ -74,7 +74,7 @@ class Graph<T> {
|
|||
{bool timingDependency = false}) {
|
||||
assert(!_isSealed);
|
||||
|
||||
var node = new Node._(userData, timingDependency);
|
||||
var node = Node._(userData, timingDependency);
|
||||
_nodes.add(node);
|
||||
|
||||
for (var dependency in dependencies) {
|
||||
|
@ -99,8 +99,7 @@ class Graph<T> {
|
|||
_stateCounts.putIfAbsent(state, () => 0);
|
||||
_stateCounts[state] += 1;
|
||||
|
||||
_emitEvent(
|
||||
_changedController, new StateChangedEvent(node, fromState, state));
|
||||
_emitEvent(_changedController, StateChangedEvent(node, fromState, state));
|
||||
}
|
||||
|
||||
/// We emit events asynchronously so the graph can be build up in small
|
||||
|
@ -117,8 +116,8 @@ class Node<T> extends UniqueObject {
|
|||
final T data;
|
||||
final bool timingDependency;
|
||||
NodeState _state = NodeState.initialized;
|
||||
final Set<Node<T>> _dependencies = new Set();
|
||||
final Set<Node<T>> _neededFor = new Set();
|
||||
final Set<Node<T>> _dependencies = {};
|
||||
final Set<Node<T>> _neededFor = {};
|
||||
|
||||
Node._(this.data, this.timingDependency);
|
||||
|
||||
|
@ -128,13 +127,13 @@ class Node<T> extends UniqueObject {
|
|||
}
|
||||
|
||||
class NodeState {
|
||||
static const initialized = const NodeState._("Initialized");
|
||||
static const waiting = const NodeState._("Waiting");
|
||||
static const enqueuing = const NodeState._("Enqueuing");
|
||||
static const processing = const NodeState._("Running");
|
||||
static const successful = const NodeState._("Successful");
|
||||
static const failed = const NodeState._("Failed");
|
||||
static const unableToRun = const NodeState._("UnableToRun");
|
||||
static const initialized = NodeState._("Initialized");
|
||||
static const waiting = NodeState._("Waiting");
|
||||
static const enqueuing = NodeState._("Enqueuing");
|
||||
static const processing = NodeState._("Running");
|
||||
static const successful = NodeState._("Successful");
|
||||
static const failed = NodeState._("Failed");
|
||||
static const unableToRun = NodeState._("UnableToRun");
|
||||
|
||||
final String name;
|
||||
|
||||
|
|
|
@ -6,38 +6,37 @@ import 'package:status_file/environment.dart';
|
|||
|
||||
import 'configuration.dart';
|
||||
|
||||
typedef String _LookUpFunction(TestConfiguration configuration);
|
||||
typedef bool _BoolLookUpFunction(TestConfiguration configuration);
|
||||
typedef _LookUpFunction = String Function(TestConfiguration configuration);
|
||||
typedef _BoolLookUpFunction = bool Function(TestConfiguration configuration);
|
||||
|
||||
// TODO(29756): Instead of synthesized negated variables like "unchecked",
|
||||
// consider adding support for "!" to status expressions.
|
||||
final _variables = {
|
||||
"analyzer": new _Variable.bool((c) => c.compiler == Compiler.dart2analyzer),
|
||||
"analyzer_use_fasta_parser":
|
||||
new _Variable.bool((c) => c.useAnalyzerFastaParser),
|
||||
"arch": new _Variable((c) => c.architecture.name, Architecture.names),
|
||||
"browser": new _Variable.bool((c) => c.runtime.isBrowser),
|
||||
"builder_tag": new _Variable((c) => c.builderTag ?? "", const []),
|
||||
"checked": new _Variable.bool((c) => c.isChecked),
|
||||
"compiler": new _Variable((c) => c.compiler.name, Compiler.names),
|
||||
"csp": new _Variable.bool((c) => c.isCsp),
|
||||
"enable_asserts": new _Variable.bool((c) => c.useEnableAsserts),
|
||||
"fasta": new _Variable.bool((c) => c.usesFasta),
|
||||
"host_checked": new _Variable.bool((c) => c.isHostChecked),
|
||||
"host_unchecked": new _Variable.bool((c) => !c.isHostChecked),
|
||||
"hot_reload": new _Variable.bool((c) => c.hotReload),
|
||||
"hot_reload_rollback": new _Variable.bool((c) => c.hotReloadRollback),
|
||||
"ie": new _Variable.bool((c) => c.runtime.isIE),
|
||||
"jscl": new _Variable.bool((c) => c.runtime.isJSCommandLine),
|
||||
"minified": new _Variable.bool((c) => c.isMinified),
|
||||
"mode": new _Variable((c) => c.mode.name, Mode.names),
|
||||
"no_preview_dart_2": new _Variable.bool((c) => c.noPreviewDart2),
|
||||
"preview_dart_2": new _Variable.bool((c) => !c.noPreviewDart2),
|
||||
"runtime": new _Variable(_runtimeName, _runtimeNames),
|
||||
"spec_parser": new _Variable.bool((c) => c.compiler == Compiler.specParser),
|
||||
"strong": new _Variable.bool((c) => !c.noPreviewDart2),
|
||||
"system": new _Variable(_systemName, _systemNames),
|
||||
"use_sdk": new _Variable.bool((c) => c.useSdk)
|
||||
"analyzer": _Variable.bool((c) => c.compiler == Compiler.dart2analyzer),
|
||||
"analyzer_use_fasta_parser": _Variable.bool((c) => c.useAnalyzerFastaParser),
|
||||
"arch": _Variable((c) => c.architecture.name, Architecture.names),
|
||||
"browser": _Variable.bool((c) => c.runtime.isBrowser),
|
||||
"builder_tag": _Variable((c) => c.builderTag ?? "", const []),
|
||||
"checked": _Variable.bool((c) => c.isChecked),
|
||||
"compiler": _Variable((c) => c.compiler.name, Compiler.names),
|
||||
"csp": _Variable.bool((c) => c.isCsp),
|
||||
"enable_asserts": _Variable.bool((c) => c.useEnableAsserts),
|
||||
"fasta": _Variable.bool((c) => c.usesFasta),
|
||||
"host_checked": _Variable.bool((c) => c.isHostChecked),
|
||||
"host_unchecked": _Variable.bool((c) => !c.isHostChecked),
|
||||
"hot_reload": _Variable.bool((c) => c.hotReload),
|
||||
"hot_reload_rollback": _Variable.bool((c) => c.hotReloadRollback),
|
||||
"ie": _Variable.bool((c) => c.runtime.isIE),
|
||||
"jscl": _Variable.bool((c) => c.runtime.isJSCommandLine),
|
||||
"minified": _Variable.bool((c) => c.isMinified),
|
||||
"mode": _Variable((c) => c.mode.name, Mode.names),
|
||||
"no_preview_dart_2": _Variable.bool((c) => c.noPreviewDart2),
|
||||
"preview_dart_2": _Variable.bool((c) => !c.noPreviewDart2),
|
||||
"runtime": _Variable(_runtimeName, _runtimeNames),
|
||||
"spec_parser": _Variable.bool((c) => c.compiler == Compiler.specParser),
|
||||
"strong": _Variable.bool((c) => !c.noPreviewDart2),
|
||||
"system": _Variable(_systemName, _systemNames),
|
||||
"use_sdk": _Variable.bool((c) => c.useSdk)
|
||||
};
|
||||
|
||||
/// Gets the name of the runtime as it appears in status files.
|
||||
|
@ -103,7 +102,7 @@ class ConfigurationEnvironment implements Environment {
|
|||
if (variable == null) {
|
||||
// This shouldn't happen since we validate variables before evaluating
|
||||
// expressions.
|
||||
throw new ArgumentError('Unknown variable "$variable".');
|
||||
throw ArgumentError('Unknown variable "$variable".');
|
||||
}
|
||||
|
||||
return variable.lookUp(_configuration);
|
||||
|
|
|
@ -27,16 +27,16 @@ class ExpectationSet {
|
|||
final Map<String, RegExp> _globCache = {};
|
||||
|
||||
/// The root of the expectation tree.
|
||||
final _PathNode _tree = new _PathNode();
|
||||
final _PathNode _tree = _PathNode();
|
||||
|
||||
/// Reads the expectations defined by the status files at [statusFilePaths]
|
||||
/// when in [configuration].
|
||||
ExpectationSet.read(
|
||||
List<String> statusFilePaths, TestConfiguration configuration) {
|
||||
try {
|
||||
var environment = new ConfigurationEnvironment(configuration);
|
||||
var environment = ConfigurationEnvironment(configuration);
|
||||
for (var path in statusFilePaths) {
|
||||
var file = new StatusFile.read(path);
|
||||
var file = StatusFile.read(path);
|
||||
file.validate(environment);
|
||||
for (var section in file.sections) {
|
||||
if (section.isEnabled(environment)) {
|
||||
|
@ -60,11 +60,11 @@ class ExpectationSet {
|
|||
for (var part in entry.path.split('/')) {
|
||||
if (part.contains("*")) {
|
||||
var regExp = _globCache.putIfAbsent(part, () {
|
||||
return new RegExp("^" + part.replaceAll("*", ".*") + r"$");
|
||||
return RegExp("^" + part.replaceAll("*", ".*") + r"$");
|
||||
});
|
||||
tree = tree.regExpChildren.putIfAbsent(regExp, () => new _PathNode());
|
||||
tree = tree.regExpChildren.putIfAbsent(regExp, () => _PathNode());
|
||||
} else {
|
||||
tree = tree.stringChildren.putIfAbsent(part, () => new _PathNode());
|
||||
tree = tree.stringChildren.putIfAbsent(part, () => _PathNode());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ class ExpectationSet {
|
|||
/// checks that the anchored regular expression "^$keyComponent\$" matches
|
||||
/// the corresponding filename component.
|
||||
Set<Expectation> expectations(String path) {
|
||||
var result = new Set<Expectation>();
|
||||
var result = <Expectation>{};
|
||||
_tree.walk(path.split('/'), 0, result);
|
||||
|
||||
// If no status files modified the expectation, default to the test passing.
|
||||
|
@ -105,7 +105,7 @@ class _PathNode {
|
|||
|
||||
/// The test expectatations that any test within this directory should
|
||||
/// include.
|
||||
final Set<Expectation> expectations = new Set();
|
||||
final Set<Expectation> expectations = {};
|
||||
|
||||
/// Walks the list of path [parts], starting at [index] adding any
|
||||
/// expectations to [result] from this node and any of its matching children.
|
||||
|
|
|
@ -77,7 +77,7 @@ import "test_suite.dart";
|
|||
import "utils.dart";
|
||||
|
||||
/// Until legacy multitests are ported we need to support both /// and //#
|
||||
final _multitestMarker = new RegExp(r"//[/#]");
|
||||
final _multitestMarker = RegExp(r"//[/#]");
|
||||
|
||||
final _multitestOutcomes = [
|
||||
'ok',
|
||||
|
@ -92,7 +92,7 @@ final _multitestOutcomes = [
|
|||
|
||||
void extractTestsFromMultitest(Path filePath, Map<String, String> tests,
|
||||
Map<String, Set<String>> outcomes) {
|
||||
var contents = new File(filePath.toNativePath()).readAsStringSync();
|
||||
var contents = File(filePath.toNativePath()).readAsStringSync();
|
||||
|
||||
var firstNewline = contents.indexOf('\n');
|
||||
var lineSeparator =
|
||||
|
@ -105,8 +105,8 @@ void extractTestsFromMultitest(Path filePath, Map<String, String> tests,
|
|||
var testsAsLines = <String, List<String>>{};
|
||||
|
||||
// Add the default case with key "none".
|
||||
testsAsLines['none'] = <String>[];
|
||||
outcomes['none'] = new Set<String>();
|
||||
testsAsLines['none'] = [];
|
||||
outcomes['none'] = {};
|
||||
|
||||
var lineCount = 0;
|
||||
for (var line in lines) {
|
||||
|
@ -114,12 +114,12 @@ void extractTestsFromMultitest(Path filePath, Map<String, String> tests,
|
|||
var annotation = _Annotation.tryParse(line);
|
||||
if (annotation != null) {
|
||||
testsAsLines.putIfAbsent(
|
||||
annotation.key, () => new List<String>.from(testsAsLines["none"]));
|
||||
annotation.key, () => List<String>.from(testsAsLines["none"]));
|
||||
// Add line to test with annotation.key as key, empty line to the rest.
|
||||
for (var key in testsAsLines.keys) {
|
||||
testsAsLines[key].add(annotation.key == key ? line : "");
|
||||
}
|
||||
outcomes.putIfAbsent(annotation.key, () => new Set<String>());
|
||||
outcomes.putIfAbsent(annotation.key, () => <String>{});
|
||||
if (annotation.rest != 'continued') {
|
||||
for (var nextOutcome in annotation.outcomes) {
|
||||
if (_multitestOutcomes.contains(nextOutcome)) {
|
||||
|
@ -165,8 +165,7 @@ void extractTestsFromMultitest(Path filePath, Map<String, String> tests,
|
|||
Future doMultitest(Path filePath, String outputDir, Path suiteDir,
|
||||
CreateTest doTest, bool hotReload) {
|
||||
void writeFile(String filepath, String content) {
|
||||
final File file = new File(filepath);
|
||||
|
||||
var file = File(filepath);
|
||||
if (file.existsSync()) {
|
||||
var oldContent = file.readAsStringSync();
|
||||
if (oldContent == content) {
|
||||
|
@ -190,7 +189,7 @@ Future doMultitest(Path filePath, String outputDir, Path suiteDir,
|
|||
var importsToCopy = _findAllRelativeImports(filePath);
|
||||
var futureCopies = <Future>[];
|
||||
for (var relativeImport in importsToCopy) {
|
||||
var importPath = new Path(relativeImport);
|
||||
var importPath = Path(relativeImport);
|
||||
// Make sure the target directory exists.
|
||||
var importDir = importPath.directoryPath;
|
||||
if (!importDir.isEmpty) {
|
||||
|
@ -249,12 +248,12 @@ class _Annotation {
|
|||
.split(_multitestMarker)[1]
|
||||
.split(':')
|
||||
.map((s) => s.trim())
|
||||
.where((s) => s.length > 0)
|
||||
.where((s) => s.isNotEmpty)
|
||||
.toList();
|
||||
|
||||
if (parts.length <= 1) return null;
|
||||
|
||||
return new _Annotation._(parts[0], parts[1]);
|
||||
return _Annotation._(parts[0], parts[1]);
|
||||
}
|
||||
|
||||
final String key;
|
||||
|
@ -272,9 +271,9 @@ class _Annotation {
|
|||
/// Finds all relative imports and copies them into the directory with the
|
||||
/// generated tests.
|
||||
Set<String> _findAllRelativeImports(Path topLibrary) {
|
||||
var found = new Set<String>();
|
||||
var found = <String>{};
|
||||
var libraryDir = topLibrary.directoryPath;
|
||||
var relativeImportRegExp = new RegExp(
|
||||
var relativeImportRegExp = RegExp(
|
||||
'^(?:@.*\\s+)?' // Allow for a meta-data annotation.
|
||||
'(import|part)'
|
||||
'\\s+["\']'
|
||||
|
@ -283,7 +282,7 @@ Set<String> _findAllRelativeImports(Path topLibrary) {
|
|||
'["\']');
|
||||
|
||||
processFile(Path filePath) {
|
||||
var file = new File(filePath.toNativePath());
|
||||
var file = File(filePath.toNativePath());
|
||||
for (var line in file.readAsLinesSync()) {
|
||||
var match = relativeImportRegExp.firstMatch(line);
|
||||
if (match == null) continue;
|
||||
|
@ -327,10 +326,10 @@ String _suiteNameFromPath(Path suiteDir) {
|
|||
Path _createMultitestDirectory(
|
||||
String outputDir, Path suiteDir, Path sourceDir) {
|
||||
var relative = sourceDir.relativeTo(suiteDir);
|
||||
var path = new Path(outputDir)
|
||||
var path = Path(outputDir)
|
||||
.append('generated_tests')
|
||||
.append(_suiteNameFromPath(suiteDir))
|
||||
.join(relative);
|
||||
TestUtils.mkdirRecursive(Path.workingDirectory, path);
|
||||
return new Path(new File(path.toNativePath()).absolute.path);
|
||||
return Path(File(path.toNativePath()).absolute.path);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import 'path.dart';
|
|||
import 'repository.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
const _defaultTestSelectors = const [
|
||||
const _defaultTestSelectors = [
|
||||
'samples',
|
||||
'standalone',
|
||||
'standalone_2',
|
||||
|
@ -82,9 +82,9 @@ enum _OptionValueType { bool, int, string }
|
|||
/// Parses command line arguments and produces a test runner configuration.
|
||||
class OptionsParser {
|
||||
static final List<_Option> _options = [
|
||||
new _Option('mode', 'Mode in which to run the tests.',
|
||||
_Option('mode', 'Mode in which to run the tests.',
|
||||
abbr: 'm', values: ['all']..addAll(Mode.names)),
|
||||
new _Option(
|
||||
_Option(
|
||||
'compiler',
|
||||
'''How the Dart code should be compiled or statically processed.
|
||||
|
||||
|
@ -102,7 +102,7 @@ dartkp: Compile the Dart code into Kernel and then Kernel into AOT
|
|||
spec_parser: Parse Dart code using the specification parser.''',
|
||||
abbr: 'c',
|
||||
values: Compiler.names),
|
||||
new _Option(
|
||||
_Option(
|
||||
'runtime',
|
||||
'''Where the tests should be run.
|
||||
vm: Run Dart code on the standalone Dart VM.
|
||||
|
@ -126,7 +126,7 @@ self_check: Pass each test or its compiled output to every file under
|
|||
none: No runtime, compile only.''',
|
||||
abbr: 'r',
|
||||
values: Runtime.names),
|
||||
new _Option(
|
||||
_Option(
|
||||
'arch',
|
||||
'''The architecture to run tests for.
|
||||
|
||||
|
@ -140,54 +140,51 @@ simdbc, simdbc64''',
|
|||
values: ['all']..addAll(Architecture.names),
|
||||
defaultsTo: Architecture.x64.name,
|
||||
hide: true),
|
||||
new _Option('system', 'The operating system to run tests on.',
|
||||
_Option('system', 'The operating system to run tests on.',
|
||||
abbr: 's',
|
||||
values: System.names,
|
||||
defaultsTo: Platform.operatingSystem,
|
||||
hide: true),
|
||||
new _Option(
|
||||
_Option(
|
||||
'named_configuration',
|
||||
'''The named test configuration that supplies the values for all
|
||||
test options, specifying how tests should be run.''',
|
||||
abbr: 'n',
|
||||
hide: true),
|
||||
new _Option.bool('strong', 'Deprecated, no-op.', hide: true),
|
||||
_Option.bool('strong', 'Deprecated, no-op.', hide: true),
|
||||
// TODO(sigmund): rename flag once we migrate all dart2js bots to the test
|
||||
// matrix.
|
||||
new _Option.bool('host_checked', 'Run compiler with assertions enabled.',
|
||||
_Option.bool('host_checked', 'Run compiler with assertions enabled.',
|
||||
hide: true),
|
||||
new _Option.bool('minified', 'Enable minification in the compiler.',
|
||||
_Option.bool('minified', 'Enable minification in the compiler.',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
'csp', 'Run tests under Content Security Policy restrictions.',
|
||||
_Option.bool('csp', 'Run tests under Content Security Policy restrictions.',
|
||||
hide: true),
|
||||
new _Option.bool('fast_tests',
|
||||
_Option.bool('fast_tests',
|
||||
'Only run tests that are not marked `Slow` or `Timeout`.'),
|
||||
new _Option.bool('enable_asserts',
|
||||
_Option.bool('enable_asserts',
|
||||
'Pass the --enable-asserts flag to dart2js or to the vm.'),
|
||||
new _Option.bool('no_preview_dart_2',
|
||||
_Option.bool('no_preview_dart_2',
|
||||
'Enable legacy Dart 1 behavior for some runtimes and compilers.',
|
||||
hide: true),
|
||||
new _Option.bool('use_cfe', 'Pass the --use-cfe flag to analyzer',
|
||||
hide: true),
|
||||
new _Option.bool('analyzer_use_fasta_parser',
|
||||
_Option.bool('use_cfe', 'Pass the --use-cfe flag to analyzer', hide: true),
|
||||
_Option.bool('analyzer_use_fasta_parser',
|
||||
'Pass the --use-fasta-parser flag to analyzer',
|
||||
hide: true),
|
||||
|
||||
new _Option.bool('hot_reload', 'Run hot reload stress tests.', hide: true),
|
||||
new _Option.bool(
|
||||
'hot_reload_rollback', 'Run hot reload rollback stress tests.',
|
||||
_Option.bool('hot_reload', 'Run hot reload stress tests.', hide: true),
|
||||
_Option.bool('hot_reload_rollback', 'Run hot reload rollback stress tests.',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
_Option.bool(
|
||||
'use_blobs', 'Use mmap instead of shared libraries for precompilation.',
|
||||
hide: true),
|
||||
new _Option.bool('use_elf',
|
||||
_Option.bool('use_elf',
|
||||
'Directly generate an ELF shared libraries for precompilation.',
|
||||
hide: true),
|
||||
new _Option.bool('keep_generated_files', 'Keep any generated files.',
|
||||
_Option.bool('keep_generated_files', 'Keep any generated files.',
|
||||
abbr: 'k'),
|
||||
new _Option.int('timeout', 'Timeout in seconds.', abbr: 't'),
|
||||
new _Option(
|
||||
_Option.int('timeout', 'Timeout in seconds.', abbr: 't'),
|
||||
_Option(
|
||||
'progress',
|
||||
'''Progress indication mode.
|
||||
|
||||
|
@ -196,130 +193,126 @@ compact, color, line, verbose, silent, status, buildbot, diff''',
|
|||
abbr: 'p',
|
||||
values: Progress.names,
|
||||
defaultsTo: Progress.compact.name),
|
||||
new _Option('step_name', 'Step name for use by -pbuildbot.', hide: true),
|
||||
new _Option.bool('report',
|
||||
_Option('step_name', 'Step name for use by -pbuildbot.', hide: true),
|
||||
_Option.bool('report',
|
||||
'Print a summary report of the number of tests, by expectation.',
|
||||
hide: true),
|
||||
new _Option.int('tasks', 'The number of parallel tasks to run.',
|
||||
_Option.int('tasks', 'The number of parallel tasks to run.',
|
||||
abbr: 'j', defaultsTo: Platform.numberOfProcessors),
|
||||
new _Option.int('shards',
|
||||
_Option.int('shards',
|
||||
'The number of instances that the tests will be sharded over.',
|
||||
defaultsTo: 1, hide: true),
|
||||
new _Option.int(
|
||||
_Option.int(
|
||||
'shard', 'The index of this instance when running in sharded mode.',
|
||||
defaultsTo: 1, hide: true),
|
||||
new _Option.bool('help', 'Print list of options.', abbr: 'h'),
|
||||
new _Option.int('repeat', 'How many times each test is run', defaultsTo: 1),
|
||||
new _Option.bool('verbose', 'Verbose output.', abbr: 'v'),
|
||||
new _Option.bool('verify-ir', 'Verify kernel IR.', hide: true),
|
||||
new _Option.bool('no-tree-shake', 'Disable kernel IR tree shaking.',
|
||||
_Option.bool('help', 'Print list of options.', abbr: 'h'),
|
||||
_Option.int('repeat', 'How many times each test is run', defaultsTo: 1),
|
||||
_Option.bool('verbose', 'Verbose output.', abbr: 'v'),
|
||||
_Option.bool('verify-ir', 'Verify kernel IR.', hide: true),
|
||||
_Option.bool('no-tree-shake', 'Disable kernel IR tree shaking.',
|
||||
hide: true),
|
||||
new _Option.bool('list', 'List tests only, do not run them.'),
|
||||
new _Option.bool('list-configurations', 'Output list of configurations.'),
|
||||
new _Option.bool('list_status_files',
|
||||
_Option.bool('list', 'List tests only, do not run them.'),
|
||||
_Option.bool('list-configurations', 'Output list of configurations.'),
|
||||
_Option.bool('list_status_files',
|
||||
'List status files for test-suites. Do not run any test suites.',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
'clean_exit', 'Exit 0 if tests ran and results were output.',
|
||||
_Option.bool('clean_exit', 'Exit 0 if tests ran and results were output.',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
_Option.bool(
|
||||
'silent_failures',
|
||||
"Don't complain about failing tests. This is useful when in "
|
||||
"combination with --write-results.",
|
||||
hide: true),
|
||||
new _Option.bool('report_in_json',
|
||||
_Option.bool('report_in_json',
|
||||
'When listing with --list, output result summary in JSON.',
|
||||
hide: true),
|
||||
new _Option.bool('time', 'Print timing information after running tests.'),
|
||||
new _Option('dart', 'Path to dart executable.', hide: true),
|
||||
new _Option('gen-snapshot', 'Path to gen_snapshot executable.', hide: true),
|
||||
new _Option('firefox', 'Path to firefox browser executable.', hide: true),
|
||||
new _Option('chrome', 'Path to chrome browser executable.', hide: true),
|
||||
new _Option('safari', 'Path to safari browser executable.', hide: true),
|
||||
new _Option.bool('use_sdk', '''Use compiler or runtime from the SDK.'''),
|
||||
_Option.bool('time', 'Print timing information after running tests.'),
|
||||
_Option('dart', 'Path to dart executable.', hide: true),
|
||||
_Option('gen-snapshot', 'Path to gen_snapshot executable.', hide: true),
|
||||
_Option('firefox', 'Path to firefox browser executable.', hide: true),
|
||||
_Option('chrome', 'Path to chrome browser executable.', hide: true),
|
||||
_Option('safari', 'Path to safari browser executable.', hide: true),
|
||||
_Option.bool('use_sdk', '''Use compiler or runtime from the SDK.'''),
|
||||
// TODO(rnystrom): This does not appear to be used. Remove?
|
||||
new _Option('build_directory',
|
||||
_Option('build_directory',
|
||||
'The name of the build directory, where products are placed.',
|
||||
hide: true),
|
||||
new _Option('output_directory',
|
||||
_Option('output_directory',
|
||||
'The name of the output directory for storing log files.',
|
||||
defaultsTo: "logs", hide: true),
|
||||
new _Option.bool('noBatch', 'Do not run tests in batch mode.', hide: true),
|
||||
new _Option.bool('dart2js_batch', 'Run dart2js tests in batch mode.',
|
||||
_Option.bool('noBatch', 'Do not run tests in batch mode.', hide: true),
|
||||
_Option.bool('dart2js_batch', 'Run dart2js tests in batch mode.',
|
||||
hide: true),
|
||||
new _Option.bool('write_debug_log',
|
||||
_Option.bool('write_debug_log',
|
||||
'Don\'t write debug messages to stdout but rather to a logfile.',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
_Option.bool(
|
||||
'write_results',
|
||||
'Write results to a "${TestUtils.resultsFileName}" json file '
|
||||
'located at the debug_output_directory.',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
_Option.bool(
|
||||
'write_logs',
|
||||
'Include the stdout and stderr of tests that don\'t match expectations '
|
||||
'in the "${TestUtils.logsFileName}" file',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
_Option.bool(
|
||||
'reset_browser_configuration',
|
||||
'''Browser specific reset of configuration.
|
||||
|
||||
Warning: Using this option may remove your bookmarks and other
|
||||
settings.''',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
_Option.bool(
|
||||
'copy_coredumps',
|
||||
'''If we see a crash that we did not expect, copy the core dumps to
|
||||
"/tmp".''',
|
||||
hide: true),
|
||||
new _Option(
|
||||
_Option(
|
||||
'local_ip',
|
||||
'''IP address the HTTP servers should listen on. This address is also
|
||||
used for browsers to connect to.''',
|
||||
defaultsTo: '127.0.0.1',
|
||||
hide: true),
|
||||
new _Option.int('test_server_port', 'Port for test http server.',
|
||||
_Option.int('test_server_port', 'Port for test http server.',
|
||||
defaultsTo: 0, hide: true),
|
||||
new _Option.int('test_server_cross_origin_port',
|
||||
_Option.int('test_server_cross_origin_port',
|
||||
'Port for test http server cross origin.',
|
||||
defaultsTo: 0, hide: true),
|
||||
new _Option.int('test_driver_port', 'Port for http test driver server.',
|
||||
_Option.int('test_driver_port', 'Port for http test driver server.',
|
||||
defaultsTo: 0, hide: true),
|
||||
new _Option.int(
|
||||
_Option.int(
|
||||
'test_driver_error_port', 'Port for http test driver server errors.',
|
||||
defaultsTo: 0, hide: true),
|
||||
new _Option('test_list', 'File containing a list of tests to be executed',
|
||||
_Option('test_list', 'File containing a list of tests to be executed',
|
||||
hide: true),
|
||||
new _Option('tests', 'A newline separated list of tests to be executed'),
|
||||
new _Option(
|
||||
_Option('tests', 'A newline separated list of tests to be executed'),
|
||||
_Option(
|
||||
'builder_tag',
|
||||
'''Machine specific options that is not captured by the regular test
|
||||
options. Used to be able to make sane updates to the status files.''',
|
||||
hide: true),
|
||||
new _Option('vm_options', 'Extra options to send to the VM when running.',
|
||||
_Option('vm_options', 'Extra options to send to the VM when running.',
|
||||
hide: true),
|
||||
new _Option(
|
||||
'dart2js_options', 'Extra options for dart2js compilation step.',
|
||||
_Option('dart2js_options', 'Extra options for dart2js compilation step.',
|
||||
hide: true),
|
||||
new _Option('shared_options', 'Extra shared options.', hide: true),
|
||||
new _Option(
|
||||
_Option('shared_options', 'Extra shared options.', hide: true),
|
||||
_Option(
|
||||
'babel',
|
||||
'''Transforms dart2js output with Babel. The value must be
|
||||
Babel options JSON.''',
|
||||
hide: true),
|
||||
new _Option(
|
||||
'suite_dir', 'Additional directory to add to the testing matrix.',
|
||||
_Option('suite_dir', 'Additional directory to add to the testing matrix.',
|
||||
hide: true),
|
||||
new _Option('package_root', 'The package root to use for testing.',
|
||||
_Option('package_root', 'The package root to use for testing.', hide: true),
|
||||
_Option('packages', 'The package spec file to use for testing.',
|
||||
hide: true),
|
||||
new _Option('packages', 'The package spec file to use for testing.',
|
||||
hide: true),
|
||||
new _Option(
|
||||
_Option(
|
||||
'exclude_suite',
|
||||
'''Exclude suites from default selector, only works when no selector
|
||||
has been specified on the command line.''',
|
||||
hide: true),
|
||||
new _Option.bool(
|
||||
_Option.bool(
|
||||
'skip_compilation',
|
||||
'''
|
||||
Skip the compilation step, using the compilation artifacts left in
|
||||
|
@ -328,7 +321,7 @@ false positves and negatives, but can be useful for quick and
|
|||
dirty offline testing when not making changes that affect the
|
||||
compiler.''',
|
||||
hide: true),
|
||||
new _Option.bool('print_passing_stdout',
|
||||
_Option.bool('print_passing_stdout',
|
||||
'Print the stdout of passing, as well as failing, tests.',
|
||||
hide: true)
|
||||
];
|
||||
|
@ -583,8 +576,7 @@ compiler.''',
|
|||
// observatory_ui, and remove observatory_ui from the original
|
||||
// selectors. The only mutable value in the map is the selectors, so a
|
||||
// shallow copy is safe.
|
||||
var observatoryConfiguration =
|
||||
new Map<String, dynamic>.from(configuration);
|
||||
var observatoryConfiguration = Map<String, dynamic>.from(configuration);
|
||||
var observatorySelectors = {
|
||||
'observatory_ui': selectors['observatory_ui']
|
||||
};
|
||||
|
@ -688,8 +680,8 @@ compiler.''',
|
|||
var namedConfiguration =
|
||||
getNamedConfiguration(data["named_configuration"] as String);
|
||||
var innerConfiguration = namedConfiguration ??
|
||||
new Configuration("custom configuration", architecture,
|
||||
compiler, mode, runtime, system,
|
||||
Configuration("custom configuration", architecture, compiler,
|
||||
mode, runtime, system,
|
||||
timeout: data["timeout"] as int,
|
||||
enableAsserts: data["enable_asserts"] as bool,
|
||||
useAnalyzerCfe: data["use_cfe"] as bool,
|
||||
|
@ -708,7 +700,7 @@ compiler.''',
|
|||
babel: data['babel'] as String,
|
||||
builderTag: data["builder_tag"] as String,
|
||||
previewDart2: true);
|
||||
var configuration = new TestConfiguration(
|
||||
var configuration = TestConfiguration(
|
||||
configuration: innerConfiguration,
|
||||
progress: Progress.find(data["progress"] as String),
|
||||
selectors: selectors,
|
||||
|
@ -817,7 +809,7 @@ compiler.''',
|
|||
_fail("Error: '$suite/$pattern'. Only one test selection"
|
||||
" pattern is allowed to start with '$suite/'");
|
||||
}
|
||||
selectorMap[suite] = new RegExp(pattern);
|
||||
selectorMap[suite] = RegExp(pattern);
|
||||
}
|
||||
|
||||
return selectorMap;
|
||||
|
@ -825,7 +817,7 @@ compiler.''',
|
|||
|
||||
/// Print out usage information.
|
||||
void _printHelp({bool verbose}) {
|
||||
var buffer = new StringBuffer();
|
||||
var buffer = StringBuffer();
|
||||
|
||||
buffer.writeln('''The Dart SDK's internal test runner.
|
||||
|
||||
|
|
134
pkg/test_runner/lib/src/output_log.dart
Normal file
134
pkg/test_runner/lib/src/output_log.dart
Normal file
|
@ -0,0 +1,134 @@
|
|||
// Copyright (c) 2019, 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:convert';
|
||||
import 'dart:io';
|
||||
|
||||
/// An OutputLog records the output from a test, but truncates it if
|
||||
/// it is longer than [_maxHead] characters, and just keeps the head and
|
||||
/// the last [_tailLength] characters of the output.
|
||||
class OutputLog implements StreamConsumer<List<int>> {
|
||||
static const _maxHead = 500 * 1024;
|
||||
static const _tailLength = 10 * 1024;
|
||||
|
||||
List<int> _head = [];
|
||||
List<int> _tail;
|
||||
List<int> complete;
|
||||
bool _dataDropped = false;
|
||||
StreamSubscription _subscription;
|
||||
|
||||
bool _hasNonUtf8 = false;
|
||||
bool get hasNonUtf8 => _hasNonUtf8;
|
||||
|
||||
void add(List<int> data) {
|
||||
if (complete != null) {
|
||||
throw StateError("Cannot add to OutputLog after calling toList");
|
||||
}
|
||||
if (_tail == null) {
|
||||
_head.addAll(data);
|
||||
if (_head.length > _maxHead) {
|
||||
_tail = _head.sublist(_maxHead);
|
||||
_head.length = _maxHead;
|
||||
}
|
||||
} else {
|
||||
_tail.addAll(data);
|
||||
}
|
||||
if (_tail != null && _tail.length > 2 * _tailLength) {
|
||||
_tail = _truncatedTail();
|
||||
_dataDropped = true;
|
||||
}
|
||||
}
|
||||
|
||||
List<int> _truncatedTail() => _tail.length > _tailLength
|
||||
? _tail.sublist(_tail.length - _tailLength)
|
||||
: _tail;
|
||||
|
||||
void _checkUtf8(List<int> data) {
|
||||
try {
|
||||
utf8.decode(data, allowMalformed: false);
|
||||
} on FormatException {
|
||||
_hasNonUtf8 = true;
|
||||
var malformed = utf8.decode(data, allowMalformed: true);
|
||||
data
|
||||
..clear()
|
||||
..addAll(utf8.encode(malformed))
|
||||
..addAll("""
|
||||
*****************************************************************************
|
||||
test.dart: The output of this test contained non-UTF8 formatted data.
|
||||
*****************************************************************************
|
||||
"""
|
||||
.codeUnits);
|
||||
}
|
||||
}
|
||||
|
||||
List<int> toList() {
|
||||
if (complete == null) {
|
||||
complete = _head;
|
||||
if (_dataDropped) {
|
||||
complete.addAll("""
|
||||
*****************************************************************************
|
||||
test.dart: Data was removed due to excessive length. If you need the limit to
|
||||
be increased, please contact dart-engprod or file an issue.
|
||||
*****************************************************************************
|
||||
"""
|
||||
.codeUnits);
|
||||
complete.addAll(_truncatedTail());
|
||||
} else if (_tail != null) {
|
||||
complete.addAll(_tail);
|
||||
}
|
||||
_head = null;
|
||||
_tail = null;
|
||||
_checkUtf8(complete);
|
||||
}
|
||||
return complete;
|
||||
}
|
||||
|
||||
@override
|
||||
Future addStream(Stream<List<int>> stream) {
|
||||
_subscription = stream.listen(this.add);
|
||||
return _subscription.asFuture();
|
||||
}
|
||||
|
||||
@override
|
||||
Future close() {
|
||||
toList();
|
||||
return _subscription?.cancel();
|
||||
}
|
||||
|
||||
Future cancel() {
|
||||
return _subscription?.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/// An [OutputLog] that tees the output to a file as well.
|
||||
class FileOutputLog extends OutputLog {
|
||||
File _outputFile;
|
||||
IOSink _sink;
|
||||
|
||||
FileOutputLog(this._outputFile);
|
||||
|
||||
@override
|
||||
void add(List<int> data) {
|
||||
super.add(data);
|
||||
_sink ??= _outputFile.openWrite();
|
||||
_sink.add(data);
|
||||
}
|
||||
|
||||
@override
|
||||
Future close() {
|
||||
return Future.wait([
|
||||
super.close(),
|
||||
if (_sink != null) _sink.flush().whenComplete(_sink.close)
|
||||
]);
|
||||
}
|
||||
|
||||
@override
|
||||
Future cancel() {
|
||||
return Future.wait([
|
||||
super.cancel(),
|
||||
if (_sink != null) _sink.flush().whenComplete(_sink.close)
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ import 'dart:math';
|
|||
|
||||
// TODO: Remove this class, and use the URI class for all path manipulation.
|
||||
class Path {
|
||||
static Path workingDirectory = new Path(Directory.current.path);
|
||||
static Path workingDirectory = Path(Directory.current.path);
|
||||
|
||||
final String _path;
|
||||
final bool isWindowsShare;
|
||||
|
@ -67,7 +67,7 @@ class Path {
|
|||
// Throws exception if an impossible case is reached.
|
||||
if (base.isAbsolute != isAbsolute ||
|
||||
base.isWindowsShare != isWindowsShare) {
|
||||
throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
|
||||
throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
|
||||
" Path and base must both be relative, or both absolute.\n"
|
||||
" Arguments: $_path.relativeTo($base)");
|
||||
}
|
||||
|
@ -87,22 +87,22 @@ class Path {
|
|||
if (basePath[1] != _path[1]) {
|
||||
// Replace the drive letter in basePath with that from _path.
|
||||
basePath = '/${_path[1]}:/${basePath.substring(4)}';
|
||||
base = new Path(basePath);
|
||||
base = Path(basePath);
|
||||
}
|
||||
} else {
|
||||
throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
|
||||
throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
|
||||
" Base path and target path are on different Windows drives.\n"
|
||||
" Arguments: $_path.relativeTo($base)");
|
||||
}
|
||||
} else if (baseHasDrive != pathHasDrive) {
|
||||
throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
|
||||
throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
|
||||
" Base path must start with a drive letter if and "
|
||||
"only if target path does.\n"
|
||||
" Arguments: $_path.relativeTo($base)");
|
||||
}
|
||||
}
|
||||
if (_path.startsWith(basePath)) {
|
||||
if (_path == basePath) return new Path('.');
|
||||
if (_path == basePath) return Path('.');
|
||||
// There must be a '/' at the end of the match, or immediately after.
|
||||
int matchEnd = basePath.length;
|
||||
if (_path[matchEnd - 1] == '/' || _path[matchEnd] == '/') {
|
||||
|
@ -110,7 +110,7 @@ class Path {
|
|||
while (matchEnd < _path.length && _path[matchEnd] == '/') {
|
||||
matchEnd++;
|
||||
}
|
||||
return new Path(_path.substring(matchEnd)).canonicalize();
|
||||
return Path(_path.substring(matchEnd)).canonicalize();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,10 +127,10 @@ class Path {
|
|||
while (common < length && pathSegments[common] == baseSegments[common]) {
|
||||
common++;
|
||||
}
|
||||
final segments = new List<String>();
|
||||
final segments = List<String>();
|
||||
|
||||
if (common < baseSegments.length && baseSegments[common] == '..') {
|
||||
throw new ArgumentError("Invalid case of Path.relativeTo(base):\n"
|
||||
throw ArgumentError("Invalid case of Path.relativeTo(base):\n"
|
||||
" Base path has more '..'s than path does.\n"
|
||||
" Arguments: $_path.relativeTo($base)");
|
||||
}
|
||||
|
@ -146,22 +146,21 @@ class Path {
|
|||
if (hasTrailingSeparator) {
|
||||
segments.add('');
|
||||
}
|
||||
return new Path(segments.join('/'));
|
||||
return Path(segments.join('/'));
|
||||
}
|
||||
|
||||
Path join(Path further) {
|
||||
if (further.isAbsolute) {
|
||||
throw new ArgumentError(
|
||||
"Path.join called with absolute Path as argument.");
|
||||
throw ArgumentError("Path.join called with absolute Path as argument.");
|
||||
}
|
||||
if (isEmpty) {
|
||||
return further.canonicalize();
|
||||
}
|
||||
if (hasTrailingSeparator) {
|
||||
var joined = new Path._internal('$_path${further}', isWindowsShare);
|
||||
var joined = Path._internal('$_path${further}', isWindowsShare);
|
||||
return joined.canonicalize();
|
||||
}
|
||||
var joined = new Path._internal('$_path/${further}', isWindowsShare);
|
||||
var joined = Path._internal('$_path/${further}', isWindowsShare);
|
||||
return joined.canonicalize();
|
||||
}
|
||||
|
||||
|
@ -250,7 +249,7 @@ class Path {
|
|||
segmentsToJoin.add('');
|
||||
}
|
||||
}
|
||||
return new Path._internal(segmentsToJoin.join('/'), isWindowsShare);
|
||||
return Path._internal(segmentsToJoin.join('/'), isWindowsShare);
|
||||
}
|
||||
|
||||
String toNativePath() {
|
||||
|
@ -281,11 +280,11 @@ class Path {
|
|||
|
||||
Path append(String finalSegment) {
|
||||
if (isEmpty) {
|
||||
return new Path._internal(finalSegment, isWindowsShare);
|
||||
return Path._internal(finalSegment, isWindowsShare);
|
||||
} else if (hasTrailingSeparator) {
|
||||
return new Path._internal('$_path$finalSegment', isWindowsShare);
|
||||
return Path._internal('$_path$finalSegment', isWindowsShare);
|
||||
} else {
|
||||
return new Path._internal('$_path/$finalSegment', isWindowsShare);
|
||||
return Path._internal('$_path/$finalSegment', isWindowsShare);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,10 +303,10 @@ class Path {
|
|||
|
||||
Path get directoryPath {
|
||||
int pos = _path.lastIndexOf('/');
|
||||
if (pos < 0) return new Path('');
|
||||
if (pos < 0) return Path('');
|
||||
while (pos > 0 && _path[pos - 1] == '/') --pos;
|
||||
var dirPath = (pos > 0) ? _path.substring(0, pos) : '/';
|
||||
return new Path._internal(dirPath, isWindowsShare);
|
||||
return Path._internal(dirPath, isWindowsShare);
|
||||
}
|
||||
|
||||
String get filename {
|
||||
|
|
1191
pkg/test_runner/lib/src/process_queue.dart
Normal file
1191
pkg/test_runner/lib/src/process_queue.dart
Normal file
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,7 @@ import 'path.dart';
|
|||
/// Provides information about the surrounding Dart repository.
|
||||
class Repository {
|
||||
/// File path pointing to the root directory of the Dart checkout.
|
||||
static Path get dir => new Path(uri.toFilePath());
|
||||
static Path get dir => Path(uri.toFilePath());
|
||||
|
||||
/// The URI pointing to the root of the Dart checkout.
|
||||
///
|
||||
|
|
|
@ -34,7 +34,7 @@ final List<String> safariSettings = <String>[
|
|||
"Library/Preferences/$safari.plist",
|
||||
];
|
||||
|
||||
const Duration defaultPollDelay = const Duration(milliseconds: 1);
|
||||
const Duration defaultPollDelay = Duration(milliseconds: 1);
|
||||
|
||||
final String cpgi = "$safari.ContentPageGroupIdentifier";
|
||||
|
||||
|
@ -97,12 +97,12 @@ final String knownSafariPreference = '''
|
|||
}
|
||||
''';
|
||||
|
||||
Future<Null> get pollDelay => new Future.delayed(defaultPollDelay);
|
||||
Future<Null> get pollDelay => Future.delayed(defaultPollDelay);
|
||||
|
||||
String signalArgument(String defaultSignal,
|
||||
{bool force: false, bool testOnly: false}) {
|
||||
{bool force = false, bool testOnly = false}) {
|
||||
if (force && testOnly) {
|
||||
throw new ArgumentError("[force] and [testOnly] can't both be true.");
|
||||
throw ArgumentError("[force] and [testOnly] can't both be true.");
|
||||
}
|
||||
if (force) return "-KILL";
|
||||
if (testOnly) return "-0";
|
||||
|
@ -110,7 +110,7 @@ String signalArgument(String defaultSignal,
|
|||
}
|
||||
|
||||
Future<int> kill(List<String> pids,
|
||||
{bool force: false, bool testOnly: false}) async {
|
||||
{bool force = false, bool testOnly = false}) async {
|
||||
var arguments = [signalArgument("-TERM", force: force, testOnly: testOnly)]
|
||||
..addAll(pids);
|
||||
var result = await Process.run(killLocation, arguments);
|
||||
|
@ -118,7 +118,7 @@ Future<int> kill(List<String> pids,
|
|||
}
|
||||
|
||||
Future<int> pkill(String pattern,
|
||||
{bool force: false, bool testOnly: false}) async {
|
||||
{bool force = false, bool testOnly = false}) async {
|
||||
var arguments = [
|
||||
signalArgument("-HUP", force: force, testOnly: testOnly),
|
||||
pattern
|
||||
|
@ -130,7 +130,7 @@ Future<int> pkill(String pattern,
|
|||
Uri validatedBundleName(Uri bundle) {
|
||||
if (bundle == null) return Uri.base.resolve(defaultSafariBundleLocation);
|
||||
if (!bundle.path.endsWith("/")) {
|
||||
throw new ArgumentError("Bundle ('$bundle') must end with a slash ('/').");
|
||||
throw ArgumentError("Bundle ('$bundle') must end with a slash ('/').");
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ Future<Null> killSafari({Uri bundle}) async {
|
|||
var stdout = result.stdout as String;
|
||||
var pids =
|
||||
stdout.split("\n").where((String line) => !line.isEmpty).toList();
|
||||
var timer = new Timer(const Duration(seconds: 10), () {
|
||||
var timer = Timer(const Duration(seconds: 10), () {
|
||||
print("Kill -9 Safari $pids");
|
||||
kill(pids, force: true);
|
||||
});
|
||||
|
@ -156,7 +156,7 @@ Future<Null> killSafari({Uri bundle}) async {
|
|||
}
|
||||
timer.cancel();
|
||||
}
|
||||
var timer = new Timer(const Duration(seconds: 10), () {
|
||||
var timer = Timer(const Duration(seconds: 10), () {
|
||||
print("Kill -9 $safari");
|
||||
pkill(safari, force: true);
|
||||
});
|
||||
|
@ -170,12 +170,12 @@ Future<Null> killSafari({Uri bundle}) async {
|
|||
}
|
||||
|
||||
Future<Null> deleteIfExists(Uri uri) async {
|
||||
var directory = new Directory.fromUri(uri);
|
||||
var directory = Directory.fromUri(uri);
|
||||
if (await directory.exists()) {
|
||||
print("Deleting directory '$uri'.");
|
||||
await directory.delete(recursive: true);
|
||||
} else {
|
||||
var file = new File.fromUri(uri);
|
||||
var file = File.fromUri(uri);
|
||||
if (await file.exists()) {
|
||||
print("Deleting file '$uri'.");
|
||||
await file.delete();
|
||||
|
|
|
@ -28,31 +28,31 @@ abstract class RuntimeConfiguration {
|
|||
case Runtime.ie9:
|
||||
case Runtime.safari:
|
||||
// TODO(ahe): Replace this with one or more browser runtimes.
|
||||
return new DummyRuntimeConfiguration();
|
||||
return DummyRuntimeConfiguration();
|
||||
|
||||
case Runtime.jsshell:
|
||||
return new JsshellRuntimeConfiguration();
|
||||
return JsshellRuntimeConfiguration();
|
||||
|
||||
case Runtime.d8:
|
||||
return new D8RuntimeConfiguration();
|
||||
return D8RuntimeConfiguration();
|
||||
|
||||
case Runtime.none:
|
||||
return new NoneRuntimeConfiguration();
|
||||
return NoneRuntimeConfiguration();
|
||||
|
||||
case Runtime.vm:
|
||||
if (configuration.system == System.android) {
|
||||
return new DartkAdbRuntimeConfiguration();
|
||||
return DartkAdbRuntimeConfiguration();
|
||||
}
|
||||
return new StandaloneDartRuntimeConfiguration();
|
||||
return StandaloneDartRuntimeConfiguration();
|
||||
|
||||
case Runtime.dartPrecompiled:
|
||||
if (configuration.system == System.android) {
|
||||
return new DartPrecompiledAdbRuntimeConfiguration(
|
||||
return DartPrecompiledAdbRuntimeConfiguration(
|
||||
useBlobs: configuration.useBlobs,
|
||||
useElf: configuration.useElf,
|
||||
);
|
||||
} else {
|
||||
return new DartPrecompiledRuntimeConfiguration(
|
||||
return DartPrecompiledRuntimeConfiguration(
|
||||
useBlobs: configuration.useBlobs,
|
||||
useElf: configuration.useElf,
|
||||
);
|
||||
|
@ -60,7 +60,7 @@ abstract class RuntimeConfiguration {
|
|||
break;
|
||||
|
||||
case Runtime.selfCheck:
|
||||
return new SelfCheckRuntimeConfiguration();
|
||||
return SelfCheckRuntimeConfiguration();
|
||||
}
|
||||
throw "unreachable";
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ abstract class RuntimeConfiguration {
|
|||
|
||||
int timeoutMultiplier(
|
||||
{Mode mode,
|
||||
bool isChecked: false,
|
||||
bool isReload: false,
|
||||
bool isChecked = false,
|
||||
bool isReload = false,
|
||||
Architecture arch}) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -89,9 +89,7 @@ abstract class RuntimeConfiguration {
|
|||
throw "Unimplemented runtime '$runtimeType'";
|
||||
}
|
||||
|
||||
/**
|
||||
* The output directory for this suite's configuration.
|
||||
*/
|
||||
/// The output directory for this suite's configuration.
|
||||
String get buildDir => _configuration.buildDirectory;
|
||||
|
||||
List<String> dart2jsPreambles(Uri preambleDir) => [];
|
||||
|
@ -237,8 +235,8 @@ class DartVmRuntimeConfiguration extends RuntimeConfiguration {
|
|||
|
||||
int timeoutMultiplier(
|
||||
{Mode mode,
|
||||
bool isChecked: false,
|
||||
bool isReload: false,
|
||||
bool isChecked = false,
|
||||
bool isReload = false,
|
||||
Architecture arch}) {
|
||||
var multiplier = 1;
|
||||
|
||||
|
@ -389,7 +387,7 @@ class SelfCheckRuntimeConfiguration extends DartVmRuntimeConfiguration {
|
|||
|
||||
void searchForSelfCheckers() {
|
||||
Uri pkg = Repository.uri.resolve('pkg');
|
||||
for (var entry in new Directory.fromUri(pkg).listSync(recursive: true)) {
|
||||
for (var entry in Directory.fromUri(pkg).listSync(recursive: true)) {
|
||||
if (entry is File && entry.path.endsWith('_self_check.dart')) {
|
||||
selfCheckers.add(entry.path);
|
||||
}
|
||||
|
|
|
@ -84,13 +84,13 @@ void ensureBuild(Iterable<String> modes, Iterable<String> archs) {
|
|||
if (result.exitCode != 0) {
|
||||
print('ERROR');
|
||||
print(result.stderr);
|
||||
throw new Exception('Error while building.');
|
||||
throw Exception('Error while building.');
|
||||
}
|
||||
print('Done building.');
|
||||
}
|
||||
|
||||
void sanityCheck(String output) {
|
||||
var splitter = new LineSplitter();
|
||||
var splitter = LineSplitter();
|
||||
var lines = splitter.convert(output);
|
||||
// Looks like this:
|
||||
// Total: 15556 tests
|
||||
|
@ -104,16 +104,15 @@ void sanityCheck(String output) {
|
|||
}
|
||||
if (count != total) {
|
||||
print('Count: $count, total: $total');
|
||||
throw new Exception(
|
||||
'Count and total do not align. Please validate manually.');
|
||||
throw Exception('Count and total do not align. Please validate manually.');
|
||||
}
|
||||
}
|
||||
|
||||
void main(List<String> args) {
|
||||
var combinations = _combinations[Platform.operatingSystem];
|
||||
|
||||
var arches = new Set<String>();
|
||||
var modes = new Set<String>();
|
||||
var arches = <String>{};
|
||||
var modes = <String>{};
|
||||
|
||||
if (args.contains('--simple')) {
|
||||
arches = ['ia32'].toSet();
|
||||
|
@ -155,7 +154,7 @@ void main(List<String> args) {
|
|||
if (result.exitCode != 0) {
|
||||
print(result.stdout);
|
||||
print(result.stderr);
|
||||
throw new Exception("Error running: ${args.join(" ")}");
|
||||
throw Exception("Error running: ${args.join(" ")}");
|
||||
}
|
||||
|
||||
// Find "JSON:"
|
||||
|
|
|
@ -8,7 +8,7 @@ import "package:status_file/expectation.dart";
|
|||
|
||||
import "test_case.dart";
|
||||
|
||||
final summaryReport = new SummaryReport();
|
||||
final summaryReport = SummaryReport();
|
||||
|
||||
class SummaryReport {
|
||||
int _total = 0;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -12,43 +12,38 @@ import 'co19_test_config.dart';
|
|||
import 'configuration.dart';
|
||||
import 'path.dart';
|
||||
import 'test_progress.dart';
|
||||
import 'test_case.dart';
|
||||
import 'process_queue.dart';
|
||||
import 'test_suite.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
/**
|
||||
* The directories that contain test suites which follow the conventions
|
||||
* required by [StandardTestSuite]'s forDirectory constructor.
|
||||
* New test suites should follow this convention because it makes it much
|
||||
* simpler to add them to test.dart. Existing test suites should be
|
||||
* moved to here, if possible.
|
||||
*/
|
||||
/// The directories that contain test suites which follow the conventions
|
||||
/// required by [StandardTestSuite]'s forDirectory constructor.
|
||||
/// New test suites should follow this convention because it makes it much
|
||||
/// simpler to add them to test.dart. Existing test suites should be
|
||||
/// moved to here, if possible.
|
||||
final TEST_SUITE_DIRECTORIES = [
|
||||
new Path('third_party/pkg/dartdoc'),
|
||||
new Path('pkg'),
|
||||
new Path('third_party/pkg_tested'),
|
||||
new Path('runtime/tests/vm'),
|
||||
new Path('runtime/observatory/tests/service'),
|
||||
new Path('runtime/observatory/tests/observatory_ui'),
|
||||
new Path('samples'),
|
||||
new Path('samples-dev'),
|
||||
new Path('tests/compiler/dart2js'),
|
||||
new Path('tests/compiler/dart2js_extra'),
|
||||
new Path('tests/compiler/dart2js_native'),
|
||||
new Path('tests/compiler/dartdevc_native'),
|
||||
new Path('tests/corelib_2'),
|
||||
new Path('tests/kernel'),
|
||||
new Path('tests/language_2'),
|
||||
new Path('tests/lib_2'),
|
||||
new Path('tests/standalone'),
|
||||
new Path('tests/standalone_2'),
|
||||
new Path('tests/ffi'),
|
||||
new Path('utils/tests/peg'),
|
||||
Path('third_party/pkg/dartdoc'),
|
||||
Path('pkg'),
|
||||
Path('third_party/pkg_tested'),
|
||||
Path('runtime/tests/vm'),
|
||||
Path('runtime/observatory/tests/service'),
|
||||
Path('runtime/observatory/tests/observatory_ui'),
|
||||
Path('samples'),
|
||||
Path('samples-dev'),
|
||||
Path('tests/compiler/dart2js'),
|
||||
Path('tests/compiler/dart2js_extra'),
|
||||
Path('tests/compiler/dart2js_native'),
|
||||
Path('tests/compiler/dartdevc_native'),
|
||||
Path('tests/corelib_2'),
|
||||
Path('tests/kernel'),
|
||||
Path('tests/language_2'),
|
||||
Path('tests/lib_2'),
|
||||
Path('tests/standalone'),
|
||||
Path('tests/standalone_2'),
|
||||
Path('tests/ffi'),
|
||||
Path('utils/tests/peg'),
|
||||
];
|
||||
|
||||
// This file is created by gclient runhooks.
|
||||
final VS_TOOLCHAIN_FILE = new Path("build/win_toolchain.json");
|
||||
|
||||
Future testConfigurations(List<TestConfiguration> configurations) async {
|
||||
var startTime = DateTime.now();
|
||||
var startStopwatch = Stopwatch()..start();
|
||||
|
@ -120,20 +115,20 @@ Future testConfigurations(List<TestConfiguration> configurations) async {
|
|||
|
||||
// If we specifically pass in a suite only run that.
|
||||
if (configuration.suiteDirectory != null) {
|
||||
var suitePath = new Path(configuration.suiteDirectory);
|
||||
testSuites.add(new PKGTestSuite(configuration, suitePath));
|
||||
var suitePath = Path(configuration.suiteDirectory);
|
||||
testSuites.add(PKGTestSuite(configuration, suitePath));
|
||||
} else {
|
||||
for (var testSuiteDir in TEST_SUITE_DIRECTORIES) {
|
||||
var name = testSuiteDir.filename;
|
||||
if (configuration.selectors.containsKey(name)) {
|
||||
testSuites.add(
|
||||
new StandardTestSuite.forDirectory(configuration, testSuiteDir));
|
||||
testSuites
|
||||
.add(StandardTestSuite.forDirectory(configuration, testSuiteDir));
|
||||
}
|
||||
}
|
||||
|
||||
for (var key in configuration.selectors.keys) {
|
||||
if (key == 'co19_2') {
|
||||
testSuites.add(new Co19TestSuite(configuration, key));
|
||||
testSuites.add(Co19TestSuite(configuration, key));
|
||||
} else if ((configuration.compiler == Compiler.none ||
|
||||
configuration.compiler == Compiler.dartk ||
|
||||
configuration.compiler == Compiler.dartkb) &&
|
||||
|
@ -141,10 +136,10 @@ Future testConfigurations(List<TestConfiguration> configurations) async {
|
|||
key == 'vm') {
|
||||
// vm tests contain both cc tests (added here) and dart tests (added
|
||||
// in [TEST_SUITE_DIRECTORIES]).
|
||||
testSuites.add(new VMTestSuite(configuration));
|
||||
testSuites.add(VMTestSuite(configuration));
|
||||
} else if (configuration.compiler == Compiler.dart2analyzer) {
|
||||
if (key == 'analyze_library') {
|
||||
testSuites.add(new AnalyzeLibraryTestSuite(configuration));
|
||||
testSuites.add(AnalyzeLibraryTestSuite(configuration));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,49 +183,49 @@ Future testConfigurations(List<TestConfiguration> configurations) async {
|
|||
progressIndicator = Progress.compact;
|
||||
formatter = Formatter.color;
|
||||
printFailures = false;
|
||||
eventListener.add(new StatusFileUpdatePrinter());
|
||||
eventListener.add(StatusFileUpdatePrinter());
|
||||
}
|
||||
if (firstConf.silentFailures) {
|
||||
printFailures = false;
|
||||
}
|
||||
eventListener.add(new SummaryPrinter());
|
||||
eventListener.add(SummaryPrinter());
|
||||
if (printFailures) {
|
||||
// The buildbot has it's own failure summary since it needs to wrap it
|
||||
// into '@@@'-annotated sections.
|
||||
var printFailureSummary = progressIndicator != Progress.buildbot;
|
||||
eventListener.add(new TestFailurePrinter(printFailureSummary, formatter));
|
||||
eventListener.add(TestFailurePrinter(printFailureSummary, formatter));
|
||||
}
|
||||
if (firstConf.printPassingStdout) {
|
||||
eventListener.add(new PassingStdoutPrinter(formatter));
|
||||
eventListener.add(PassingStdoutPrinter(formatter));
|
||||
}
|
||||
eventListener.add(ProgressIndicator.fromProgress(
|
||||
progressIndicator, startTime, formatter));
|
||||
if (printTiming) {
|
||||
eventListener.add(new TimingPrinter(startTime));
|
||||
eventListener.add(TimingPrinter(startTime));
|
||||
}
|
||||
eventListener.add(new SkippedCompilationsPrinter());
|
||||
eventListener.add(SkippedCompilationsPrinter());
|
||||
if (progressIndicator == Progress.status) {
|
||||
eventListener.add(new TimedProgressPrinter());
|
||||
eventListener.add(TimedProgressPrinter());
|
||||
}
|
||||
}
|
||||
|
||||
if (firstConf.writeResults) {
|
||||
eventListener.add(new ResultWriter(firstConf, startTime, startStopwatch));
|
||||
eventListener.add(ResultWriter(firstConf, startTime, startStopwatch));
|
||||
}
|
||||
|
||||
if (firstConf.copyCoreDumps) {
|
||||
eventListener.add(new UnexpectedCrashLogger());
|
||||
eventListener.add(UnexpectedCrashLogger());
|
||||
}
|
||||
|
||||
// The only progress indicator when listing tests should be the
|
||||
// the summary printer.
|
||||
if (listTests) {
|
||||
eventListener.add(new SummaryPrinter(jsonOnly: reportInJson));
|
||||
eventListener.add(SummaryPrinter(jsonOnly: reportInJson));
|
||||
} else {
|
||||
if (!firstConf.cleanExit) {
|
||||
eventListener.add(new ExitCodeSetter());
|
||||
eventListener.add(ExitCodeSetter());
|
||||
}
|
||||
eventListener.add(new IgnoredTestMonitor());
|
||||
eventListener.add(IgnoredTestMonitor());
|
||||
}
|
||||
|
||||
// If any of the configurations need to access android devices we'll first
|
||||
|
@ -250,6 +245,6 @@ Future testConfigurations(List<TestConfiguration> configurations) async {
|
|||
|
||||
// [firstConf] is needed here, since the ProcessQueue needs to know the
|
||||
// settings of 'noBatch' and 'local_ip'
|
||||
new ProcessQueue(firstConf, maxProcesses, maxBrowserProcesses, startTime,
|
||||
ProcessQueue(firstConf, maxProcesses, maxBrowserProcesses, startTime,
|
||||
testSuites, eventListener, allTestsFinished, verbose, adbDevicePool);
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@ import 'utils.dart';
|
|||
/// Controls how message strings are processed before being displayed.
|
||||
class Formatter {
|
||||
/// Messages are left as-is.
|
||||
static const normal = const Formatter._();
|
||||
static const normal = Formatter._();
|
||||
|
||||
/// Messages are wrapped in ANSI escape codes to color them for display on a
|
||||
/// terminal.
|
||||
static const color = const _ColorFormatter();
|
||||
static const color = _ColorFormatter();
|
||||
|
||||
const Formatter._();
|
||||
|
||||
|
@ -143,16 +143,16 @@ class UnexpectedCrashLogger extends EventListener {
|
|||
// folder next to core dumps and name them
|
||||
// `binary.${mode}_${arch}_${binary_name}`.
|
||||
final binName = lastCommand.executable;
|
||||
final binFile = new File(binName);
|
||||
final binBaseName = new Path(binName).filename;
|
||||
final binFile = File(binName);
|
||||
final binBaseName = Path(binName).filename;
|
||||
if (!archivedBinaries.containsKey(binName) && binFile.existsSync()) {
|
||||
final archived = "binary.${mode}_${arch}_${binBaseName}";
|
||||
TestUtils.copyFile(new Path(binName), new Path(archived));
|
||||
TestUtils.copyFile(Path(binName), Path(archived));
|
||||
// On Windows also copy PDB file for the binary.
|
||||
if (Platform.isWindows) {
|
||||
final pdbPath = new Path("$binName.pdb");
|
||||
if (new File(pdbPath.toNativePath()).existsSync()) {
|
||||
TestUtils.copyFile(pdbPath, new Path("$archived.pdb"));
|
||||
final pdbPath = Path("$binName.pdb");
|
||||
if (File(pdbPath.toNativePath()).existsSync()) {
|
||||
TestUtils.copyFile(pdbPath, Path("$archived.pdb"));
|
||||
}
|
||||
}
|
||||
archivedBinaries[binName] = archived;
|
||||
|
@ -160,11 +160,11 @@ class UnexpectedCrashLogger extends EventListener {
|
|||
|
||||
final kernelServiceBaseName = 'kernel-service.dart.snapshot';
|
||||
final kernelService =
|
||||
new File('${binFile.parent.path}/$kernelServiceBaseName');
|
||||
File('${binFile.parent.path}/$kernelServiceBaseName');
|
||||
if (!archivedBinaries.containsKey(kernelService) &&
|
||||
kernelService.existsSync()) {
|
||||
final archived = "binary.${mode}_${arch}_${kernelServiceBaseName}";
|
||||
TestUtils.copyFile(new Path(kernelService.path), new Path(archived));
|
||||
TestUtils.copyFile(Path(kernelService.path), Path(archived));
|
||||
archivedBinaries[kernelServiceBaseName] = archived;
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ class UnexpectedCrashLogger extends EventListener {
|
|||
RandomAccessFile unexpectedCrashesFile;
|
||||
try {
|
||||
unexpectedCrashesFile =
|
||||
new File('unexpected-crashes').openSync(mode: FileMode.append);
|
||||
File('unexpected-crashes').openSync(mode: FileMode.append);
|
||||
unexpectedCrashesFile.writeStringSync(
|
||||
"${test.displayName},${pid},${binaries.join(',')}\n");
|
||||
} catch (e) {
|
||||
|
@ -216,8 +216,8 @@ class SummaryPrinter extends EventListener {
|
|||
}
|
||||
|
||||
class TimingPrinter extends EventListener {
|
||||
final _command2testCases = new Map<Command, List<TestCase>>();
|
||||
final _commandOutputs = new Set<CommandOutput>();
|
||||
final _commandToTestCases = <Command, List<TestCase>>{};
|
||||
final _commandOutputs = <CommandOutput>{};
|
||||
DateTime _startTime;
|
||||
|
||||
TimingPrinter(this._startTime);
|
||||
|
@ -226,22 +226,22 @@ class TimingPrinter extends EventListener {
|
|||
for (var commandOutput in testCase.commandOutputs.values) {
|
||||
var command = commandOutput.command;
|
||||
_commandOutputs.add(commandOutput);
|
||||
_command2testCases.putIfAbsent(command, () => <TestCase>[]);
|
||||
_command2testCases[command].add(testCase);
|
||||
_commandToTestCases.putIfAbsent(command, () => <TestCase>[]);
|
||||
_commandToTestCases[command].add(testCase);
|
||||
}
|
||||
}
|
||||
|
||||
void allDone() {
|
||||
Duration d = (new DateTime.now()).difference(_startTime);
|
||||
var d = DateTime.now().difference(_startTime);
|
||||
print('\n--- Total time: ${_timeString(d)} ---');
|
||||
var outputs = _commandOutputs.toList();
|
||||
outputs.sort((a, b) {
|
||||
return b.time.inMilliseconds - a.time.inMilliseconds;
|
||||
});
|
||||
for (int i = 0; i < 20 && i < outputs.length; i++) {
|
||||
for (var i = 0; i < 20 && i < outputs.length; i++) {
|
||||
var commandOutput = outputs[i];
|
||||
var command = commandOutput.command;
|
||||
var testCases = _command2testCases[command];
|
||||
var testCases = _commandToTestCases[command];
|
||||
|
||||
var testCasesDescription = testCases.map((testCase) {
|
||||
return "${testCase.configurationString}/${testCase.displayName}";
|
||||
|
@ -255,7 +255,7 @@ class TimingPrinter extends EventListener {
|
|||
}
|
||||
|
||||
class StatusFileUpdatePrinter extends EventListener {
|
||||
var statusToConfigs = new Map<String, List<String>>();
|
||||
var statusToConfigs = <String, List<String>>{};
|
||||
var _failureSummary = <String>[];
|
||||
|
||||
void done(TestCase test) {
|
||||
|
@ -399,7 +399,7 @@ class PassingStdoutPrinter extends EventListener {
|
|||
void done(TestCase test) {
|
||||
if (!test.unexpectedOutput) {
|
||||
var lines = <String>[];
|
||||
var output = new OutputWriter(_formatter, lines);
|
||||
var output = OutputWriter(_formatter, lines);
|
||||
for (final command in test.commands) {
|
||||
var commandOutput = test.commandOutputs[command];
|
||||
if (commandOutput == null) continue;
|
||||
|
@ -422,15 +422,15 @@ class ProgressIndicator extends EventListener {
|
|||
Progress progress, DateTime startTime, Formatter formatter) {
|
||||
switch (progress) {
|
||||
case Progress.compact:
|
||||
return new CompactProgressIndicator(startTime, formatter);
|
||||
return CompactProgressIndicator(startTime, formatter);
|
||||
case Progress.line:
|
||||
return new LineProgressIndicator();
|
||||
return LineProgressIndicator();
|
||||
case Progress.verbose:
|
||||
return new VerboseProgressIndicator(startTime);
|
||||
return VerboseProgressIndicator(startTime);
|
||||
case Progress.status:
|
||||
return new ProgressIndicator(startTime);
|
||||
return ProgressIndicator(startTime);
|
||||
case Progress.buildbot:
|
||||
return new BuildbotProgressIndicator(startTime);
|
||||
return BuildbotProgressIndicator(startTime);
|
||||
}
|
||||
|
||||
throw "unreachable";
|
||||
|
@ -491,7 +491,7 @@ class CompactProgressIndicator extends CompactIndicator {
|
|||
var progressPadded = (_allTestsKnown ? percent : '--').padLeft(3);
|
||||
var passedPadded = _passedTests.toString().padLeft(5);
|
||||
var failedPadded = _failedTests.toString().padLeft(5);
|
||||
var elapsed = (new DateTime.now()).difference(_startTime);
|
||||
var elapsed = (DateTime.now()).difference(_startTime);
|
||||
var progressLine = '\r[${_timeString(elapsed)} | $progressPadded% | '
|
||||
'+${_formatter.passed(passedPadded)} | '
|
||||
'-${_formatter.failed(failedPadded)}]';
|
||||
|
@ -604,7 +604,7 @@ class OutputWriter {
|
|||
List<String> _buildFailureOutput(TestCase test,
|
||||
[Formatter formatter = Formatter.normal]) {
|
||||
var lines = <String>[];
|
||||
var output = new OutputWriter(formatter, lines);
|
||||
var output = OutputWriter(formatter, lines);
|
||||
_writeFailureStatus(test, formatter, output);
|
||||
_writeFailureOutput(test, formatter, output);
|
||||
_writeFailureReproductionCommands(test, formatter, output);
|
||||
|
@ -614,7 +614,7 @@ List<String> _buildFailureOutput(TestCase test,
|
|||
List<String> _buildFailureLog(TestCase test) {
|
||||
final formatter = Formatter.normal;
|
||||
final lines = <String>[];
|
||||
final output = new OutputWriter(formatter, lines);
|
||||
final output = OutputWriter(formatter, lines);
|
||||
_writeFailureOutput(test, formatter, output);
|
||||
_writeFailureReproductionCommands(test, formatter, output);
|
||||
return lines;
|
||||
|
@ -717,7 +717,7 @@ class ResultWriter extends EventListener {
|
|||
|
||||
void done(TestCase test) {
|
||||
if (_configuration != test.configuration) {
|
||||
throw new Exception("Two configurations in the same run. "
|
||||
throw Exception("Two configurations in the same run. "
|
||||
"Cannot output results for multiple configurations.");
|
||||
}
|
||||
final name = test.displayName;
|
||||
|
|
|
@ -2,16 +2,14 @@
|
|||
// 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.
|
||||
|
||||
/**
|
||||
* Classes and methods for enumerating and preparing tests.
|
||||
*
|
||||
* This library includes:
|
||||
*
|
||||
* - Creating tests by listing all the Dart files in certain directories,
|
||||
* and creating [TestCase]s for those files that meet the relevant criteria.
|
||||
* - Preparing tests, including copying files and frameworks to temporary
|
||||
* directories, and computing the command line and arguments to be run.
|
||||
*/
|
||||
/// Classes and methods for enumerating and preparing tests.
|
||||
///
|
||||
/// This library includes:
|
||||
///
|
||||
/// - Creating tests by listing all the Dart files in certain directories,
|
||||
/// and creating [TestCase]s for those files that meet the relevant criteria.
|
||||
/// - Preparing tests, including copying files and frameworks to temporary
|
||||
/// directories, and computing the command line and arguments to be run.
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
@ -20,7 +18,6 @@ import "package:status_file/expectation.dart";
|
|||
|
||||
import 'browser.dart';
|
||||
import 'command.dart';
|
||||
import 'compiler_configuration.dart';
|
||||
import 'configuration.dart';
|
||||
import 'expectation_set.dart';
|
||||
import 'multitest.dart';
|
||||
|
@ -32,59 +29,54 @@ import 'test_configurations.dart';
|
|||
import 'testing_servers.dart';
|
||||
import 'utils.dart';
|
||||
|
||||
RegExp multiHtmlTestGroupRegExp = new RegExp(r"\s*[^/]\s*group\('[^,']*");
|
||||
RegExp multiHtmlTestRegExp = new RegExp(r"useHtmlIndividualConfiguration\(\)");
|
||||
// Require at least one non-space character before '//[/#]'
|
||||
RegExp multiTestRegExp = new RegExp(r"\S *"
|
||||
r"//[#/] \w+:(.*)");
|
||||
RegExp dartExtension = new RegExp(r'\.dart$');
|
||||
RegExp _multiHtmlTestGroupRegExp = RegExp(r"\s*[^/]\s*group\('[^,']*");
|
||||
RegExp _multiHtmlTestRegExp = RegExp(r"useHtmlIndividualConfiguration\(\)");
|
||||
|
||||
/**
|
||||
* A simple function that tests [arg] and returns `true` or `false`.
|
||||
*/
|
||||
typedef bool Predicate<T>(T arg);
|
||||
/// Require at least one non-space character before '//[/#]'.
|
||||
RegExp _multiTestRegExp = RegExp(r"\S *//[#/] \w+:(.*)");
|
||||
|
||||
typedef void CreateTest(Path filePath, Path originTestPath,
|
||||
typedef TestCaseEvent = void Function(TestCase testCase);
|
||||
|
||||
/// A simple function that tests [arg] and returns `true` or `false`.
|
||||
typedef Predicate<T> = bool Function(T arg);
|
||||
|
||||
typedef CreateTest = void Function(Path filePath, Path originTestPath,
|
||||
{bool hasSyntaxError,
|
||||
bool hasCompileError,
|
||||
bool hasRuntimeError,
|
||||
bool hasStaticWarning,
|
||||
String multitestKey});
|
||||
|
||||
typedef void VoidFunction();
|
||||
typedef VoidFunction = void Function();
|
||||
|
||||
/**
|
||||
* Calls [function] asynchronously. Returns a future that completes with the
|
||||
* result of the function. If the function is `null`, returns a future that
|
||||
* completes immediately with `null`.
|
||||
*/
|
||||
/// Calls [function] asynchronously. Returns a future that completes with the
|
||||
/// result of the function. If the function is `null`, returns a future that
|
||||
/// completes immediately with `null`.
|
||||
Future asynchronously<T>(T function()) {
|
||||
if (function == null) return new Future<T>.value(null);
|
||||
if (function == null) return Future<T>.value(null);
|
||||
|
||||
var completer = new Completer<T>();
|
||||
var completer = Completer<T>();
|
||||
Timer.run(() => completer.complete(function()));
|
||||
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
/** A completer that waits until all added [Future]s complete. */
|
||||
/// A completer that waits until all added [Future]s complete.
|
||||
// TODO(rnystrom): Copied from web_components. Remove from here when it gets
|
||||
// added to dart:core. (See #6626.)
|
||||
class FutureGroup {
|
||||
static const _FINISHED = -1;
|
||||
static const _finished = -1;
|
||||
int _pending = 0;
|
||||
Completer<List> _completer = new Completer<List>();
|
||||
final List<Future> futures = <Future>[];
|
||||
Completer<List> _completer = Completer();
|
||||
final List<Future> futures = [];
|
||||
bool wasCompleted = false;
|
||||
|
||||
/**
|
||||
* Wait for [task] to complete (assuming this barrier has not already been
|
||||
* marked as completed, otherwise you'll get an exception indicating that a
|
||||
* future has already been completed).
|
||||
*/
|
||||
/// Wait for [task] to complete (assuming this barrier has not already been
|
||||
/// marked as completed, otherwise you'll get an exception indicating that a
|
||||
/// future has already been completed).
|
||||
void add(Future task) {
|
||||
if (_pending == _FINISHED) {
|
||||
throw new Exception("FutureFutureAlreadyCompleteException");
|
||||
if (_pending == _finished) {
|
||||
throw Exception("FutureFutureAlreadyCompleteException");
|
||||
}
|
||||
_pending++;
|
||||
var handledTaskFuture = task.catchError((e, StackTrace s) {
|
||||
|
@ -95,7 +87,7 @@ class FutureGroup {
|
|||
}).then((_) {
|
||||
_pending--;
|
||||
if (_pending == 0) {
|
||||
_pending = _FINISHED;
|
||||
_pending = _finished;
|
||||
if (!wasCompleted) {
|
||||
_completer.complete(futures);
|
||||
wasCompleted = true;
|
||||
|
@ -108,18 +100,17 @@ class FutureGroup {
|
|||
Future<List> get future => _completer.future;
|
||||
}
|
||||
|
||||
/**
|
||||
* A TestSuite represents a collection of tests. It creates a [TestCase]
|
||||
* object for each test to be run, and passes the test cases to a callback.
|
||||
*
|
||||
* Most TestSuites represent a directory or directory tree containing tests,
|
||||
* and a status file containing the expected results when these tests are run.
|
||||
*/
|
||||
/// A TestSuite represents a collection of tests. It creates a [TestCase]
|
||||
/// object for each test to be run, and passes the test cases to a callback.
|
||||
///
|
||||
/// Most TestSuites represent a directory or directory tree containing tests,
|
||||
/// and a status file containing the expected results when these tests are run.
|
||||
abstract class TestSuite {
|
||||
final TestConfiguration configuration;
|
||||
final String suiteName;
|
||||
final List<String> statusFilePaths;
|
||||
// This function is set by subclasses before enqueueing starts.
|
||||
|
||||
/// This function is set by subclasses before enqueueing starts.
|
||||
Function doTest;
|
||||
Map<String, String> _environmentOverrides;
|
||||
|
||||
|
@ -131,24 +122,18 @@ abstract class TestSuite {
|
|||
_environmentOverrides['DART_SUPPRESS_WER'] = '1';
|
||||
if (configuration.copyCoreDumps) {
|
||||
_environmentOverrides['DART_CRASHPAD_HANDLER'] =
|
||||
new Path(buildDir + '/crashpad_handler.exe')
|
||||
.absolute
|
||||
.toNativePath();
|
||||
Path(buildDir + '/crashpad_handler.exe').absolute.toNativePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> get environmentOverrides => _environmentOverrides;
|
||||
|
||||
/**
|
||||
* The output directory for this suite's configuration.
|
||||
*/
|
||||
/// The output directory for this suite's configuration.
|
||||
String get buildDir => configuration.buildDirectory;
|
||||
|
||||
/**
|
||||
* The path to the compiler for this suite's configuration. Returns `null` if
|
||||
* no compiler should be used.
|
||||
*/
|
||||
/// The path to the compiler for this suite's configuration. Returns `null` if
|
||||
/// no compiler should be used.
|
||||
String get compilerPath {
|
||||
var compilerConfiguration = configuration.compilerConfiguration;
|
||||
if (!compilerConfiguration.hasCompiler) return null;
|
||||
|
@ -159,25 +144,23 @@ abstract class TestSuite {
|
|||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the callback function onTest with a [TestCase] argument for each
|
||||
* test in the suite. When all tests have been processed, call [onDone].
|
||||
*
|
||||
* The [testCache] argument provides a persistent store that can be used to
|
||||
* cache information about the test suite, so that directories do not need
|
||||
* to be listed each time.
|
||||
*/
|
||||
/// Call the callback function onTest with a [TestCase] argument for each
|
||||
/// test in the suite. When all tests have been processed, call [onDone].
|
||||
///
|
||||
/// The [testCache] argument provides a persistent store that can be used to
|
||||
/// cache information about the test suite, so that directories do not need
|
||||
/// to be listed each time.
|
||||
Future forEachTest(
|
||||
TestCaseEvent onTest, Map<String, List<TestInformation>> testCache,
|
||||
[VoidFunction onDone]);
|
||||
|
||||
// This function will be called for every TestCase of this test suite.
|
||||
// It will
|
||||
// - handle sharding
|
||||
// - update SummaryReport
|
||||
// - handle SKIP/SKIP_BY_DESIGN markers
|
||||
// - test if the selector matches
|
||||
// and will enqueue the test (if necessary).
|
||||
/// This function will be called for every TestCase of this test suite.
|
||||
/// It will:
|
||||
/// - handle sharding
|
||||
/// - update SummaryReport
|
||||
/// - handle SKIP/SKIP_BY_DESIGN markers
|
||||
/// - test if the selector matches
|
||||
/// and will enqueue the test (if necessary).
|
||||
void enqueueNewTestCase(
|
||||
String testName, List<Command> commands, Set<Expectation> expectations,
|
||||
[TestInformation info]) {
|
||||
|
@ -196,8 +179,7 @@ abstract class TestSuite {
|
|||
}
|
||||
|
||||
var negative = info != null ? isNegative(info) : false;
|
||||
var testCase = new TestCase(
|
||||
displayName, commands, configuration, expectations,
|
||||
var testCase = TestCase(displayName, commands, configuration, expectations,
|
||||
info: info);
|
||||
if (negative &&
|
||||
configuration.runtimeConfiguration.shouldSkipNegativeTests) {
|
||||
|
@ -264,20 +246,20 @@ abstract class TestSuite {
|
|||
relative = relative.directoryPath.append(relative.filenameWithoutExtension);
|
||||
String testUniqueName = TestUtils.getShortName(relative.toString());
|
||||
|
||||
Path generatedTestPath = new Path(buildDir)
|
||||
Path generatedTestPath = Path(buildDir)
|
||||
.append('generated_$name')
|
||||
.append(dirname)
|
||||
.append(testUniqueName);
|
||||
|
||||
TestUtils.mkdirRecursive(new Path('.'), generatedTestPath);
|
||||
return new File(generatedTestPath.toNativePath())
|
||||
TestUtils.mkdirRecursive(Path('.'), generatedTestPath);
|
||||
return File(generatedTestPath.toNativePath())
|
||||
.absolute
|
||||
.path
|
||||
.replaceAll('\\', '/');
|
||||
}
|
||||
|
||||
String buildTestCaseDisplayName(Path suiteDir, Path originTestPath,
|
||||
{String multitestName: ""}) {
|
||||
{String multitestName = ""}) {
|
||||
Path testNamePath = originTestPath.relativeTo(suiteDir);
|
||||
var directory = testNamePath.directoryPath;
|
||||
var filenameWithoutExt = testNamePath.filenameWithoutExtension;
|
||||
|
@ -294,11 +276,8 @@ abstract class TestSuite {
|
|||
return testName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a directories for generated assets (tests, html files,
|
||||
* pubspec checkouts ...).
|
||||
*/
|
||||
|
||||
/// Create a directories for generated assets (tests, html files,
|
||||
/// pubspec checkouts ...).
|
||||
String createOutputDirectory(Path testPath) {
|
||||
var checked = configuration.isChecked ? '-checked' : '';
|
||||
var legacy = configuration.noPreviewDart2 ? '-legacy' : '';
|
||||
|
@ -355,7 +334,7 @@ class VMTestSuite extends TestSuite {
|
|||
// For listing the tests we use the '$runnerName.host' binary if it exists
|
||||
// and use '$runnerName' if it doesn't.
|
||||
var hostBinary = '$targetRunnerPath.host$binarySuffix';
|
||||
if (new File(hostBinary).existsSync()) {
|
||||
if (File(hostBinary).existsSync()) {
|
||||
hostRunnerPath = hostBinary;
|
||||
} else {
|
||||
hostRunnerPath = targetRunnerPath;
|
||||
|
@ -368,10 +347,10 @@ class VMTestSuite extends TestSuite {
|
|||
|
||||
var statusFiles =
|
||||
statusFilePaths.map((statusFile) => "$dartDir/$statusFile").toList();
|
||||
var expectations = new ExpectationSet.read(statusFiles, configuration);
|
||||
var expectations = ExpectationSet.read(statusFiles, configuration);
|
||||
|
||||
try {
|
||||
for (VmUnitTest test in await _listTests(hostRunnerPath)) {
|
||||
for (VMUnitTest test in await _listTests(hostRunnerPath)) {
|
||||
_addTest(expectations, test);
|
||||
}
|
||||
|
||||
|
@ -384,7 +363,7 @@ class VMTestSuite extends TestSuite {
|
|||
}
|
||||
}
|
||||
|
||||
void _addTest(ExpectationSet testExpectations, VmUnitTest test) {
|
||||
void _addTest(ExpectationSet testExpectations, VMUnitTest test) {
|
||||
final fullName = 'cc/${test.name}';
|
||||
var expectations = testExpectations.expectations(fullName);
|
||||
|
||||
|
@ -416,7 +395,7 @@ class VMTestSuite extends TestSuite {
|
|||
final filename = configuration.architecture == Architecture.x64
|
||||
? '$buildDir/gen/kernel-service.dart.snapshot'
|
||||
: '$buildDir/gen/kernel_service.dill';
|
||||
final dfePath = new Path(filename).absolute.toNativePath();
|
||||
final dfePath = Path(filename).absolute.toNativePath();
|
||||
// '--dfe' has to be the first argument for run_vm_test to pick it up.
|
||||
args.insert(0, '--dfe=$dfePath');
|
||||
}
|
||||
|
@ -431,7 +410,7 @@ class VMTestSuite extends TestSuite {
|
|||
enqueueNewTestCase(fullName, [command], expectations, testInfo);
|
||||
}
|
||||
|
||||
Future<Iterable<VmUnitTest>> _listTests(String runnerPath) async {
|
||||
Future<Iterable<VMUnitTest>> _listTests(String runnerPath) async {
|
||||
var result = await Process.run(runnerPath, ["--list"]);
|
||||
if (result.exitCode != 0) {
|
||||
throw "Failed to list tests: '$runnerPath --list'. "
|
||||
|
@ -444,16 +423,16 @@ class VMTestSuite extends TestSuite {
|
|||
.where((name) => name.isNotEmpty)
|
||||
.map((String line) {
|
||||
final parts = line.split(' ');
|
||||
return VmUnitTest(parts[0].trim(), parts.skip(1).single);
|
||||
return VMUnitTest(parts[0].trim(), parts.skip(1).single);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class VmUnitTest {
|
||||
class VMUnitTest {
|
||||
final String name;
|
||||
final String expectation;
|
||||
|
||||
VmUnitTest(this.name, this.expectation);
|
||||
VMUnitTest(this.name, this.expectation);
|
||||
}
|
||||
|
||||
class TestInformation {
|
||||
|
@ -475,16 +454,14 @@ class TestInformation {
|
|||
this.hasCompileError,
|
||||
this.hasRuntimeError,
|
||||
this.hasStaticWarning,
|
||||
{this.multitestKey: '',
|
||||
this.hasCrash: false}) {
|
||||
{this.multitestKey = '',
|
||||
this.hasCrash = false}) {
|
||||
assert(filePath.isAbsolute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A standard [TestSuite] implementation that searches for tests in a
|
||||
* directory, and creates [TestCase]s that compile and/or run them.
|
||||
*/
|
||||
/// A standard [TestSuite] implementation that searches for tests in a
|
||||
/// directory, and creates [TestCase]s that compile and/or run them.
|
||||
class StandardTestSuite extends TestSuite {
|
||||
final Path suiteDir;
|
||||
ExpectationSet testExpectations;
|
||||
|
@ -498,26 +475,26 @@ class StandardTestSuite extends TestSuite {
|
|||
|
||||
StandardTestSuite(TestConfiguration configuration, String suiteName,
|
||||
Path suiteDirectory, List<String> statusFilePaths,
|
||||
{bool recursive: false})
|
||||
{bool recursive = false})
|
||||
: dartDir = Repository.dir,
|
||||
listRecursively = recursive,
|
||||
suiteDir = Repository.dir.join(suiteDirectory),
|
||||
extraVmOptions = configuration.vmOptions,
|
||||
super(configuration, suiteName, statusFilePaths) {
|
||||
// Initialize _dart2JsBootstrapDependencies
|
||||
// Initialize _dart2JsBootstrapDependencies.
|
||||
if (!configuration.useSdk) {
|
||||
_dart2JsBootstrapDependencies = [];
|
||||
} else {
|
||||
_dart2JsBootstrapDependencies = [
|
||||
Uri.base
|
||||
.resolveUri(new Uri.directory(buildDir))
|
||||
.resolveUri(Uri.directory(buildDir))
|
||||
.resolve('dart-sdk/bin/snapshots/dart2js.dart.snapshot')
|
||||
];
|
||||
}
|
||||
|
||||
// Initialize _testListPossibleFilenames
|
||||
// Initialize _testListPossibleFilenames.
|
||||
if (configuration.testList != null) {
|
||||
_testListPossibleFilenames = Set<String>();
|
||||
_testListPossibleFilenames = <String>{};
|
||||
for (String s in configuration.testList) {
|
||||
if (s.startsWith("$suiteName/")) {
|
||||
s = s.substring(s.indexOf('/') + 1);
|
||||
|
@ -537,46 +514,44 @@ class StandardTestSuite extends TestSuite {
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize _selectorFilenameRegExp
|
||||
String pattern = configuration.selectors[suiteName].pattern;
|
||||
// Initialize _selectorFilenameRegExp.
|
||||
var pattern = configuration.selectors[suiteName].pattern;
|
||||
if (pattern.contains("/")) {
|
||||
String lastPart = pattern.substring(pattern.lastIndexOf("/") + 1);
|
||||
var lastPart = pattern.substring(pattern.lastIndexOf("/") + 1);
|
||||
// If the selector is a multitest name ending in a number or 'none'
|
||||
// we also accept test file names that don't contain that last part.
|
||||
if (int.tryParse(lastPart) != null || lastPart == "none") {
|
||||
pattern = pattern.substring(0, pattern.lastIndexOf("/"));
|
||||
}
|
||||
}
|
||||
_selectorFilenameRegExp = new RegExp(pattern);
|
||||
_selectorFilenameRegExp = RegExp(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a test suite whose file organization matches an expected structure.
|
||||
* To use this, your suite should look like:
|
||||
*
|
||||
* dart/
|
||||
* path/
|
||||
* to/
|
||||
* mytestsuite/
|
||||
* mytestsuite.status
|
||||
* example1_test.dart
|
||||
* example2_test.dart
|
||||
* example3_test.dart
|
||||
*
|
||||
* The important parts:
|
||||
*
|
||||
* * The leaf directory name is the name of your test suite.
|
||||
* * The status file uses the same name.
|
||||
* * Test files are directly in that directory and end in "_test.dart".
|
||||
*
|
||||
* If you follow that convention, then you can construct one of these like:
|
||||
*
|
||||
* new StandardTestSuite.forDirectory(configuration, 'path/to/mytestsuite');
|
||||
*
|
||||
* instead of having to create a custom [StandardTestSuite] subclass. In
|
||||
* particular, if you add 'path/to/mytestsuite' to [TEST_SUITE_DIRECTORIES]
|
||||
* in test.dart, this will all be set up for you.
|
||||
*/
|
||||
/// Creates a test suite whose file organization matches an expected structure.
|
||||
/// To use this, your suite should look like:
|
||||
///
|
||||
/// dart/
|
||||
/// path/
|
||||
/// to/
|
||||
/// mytestsuite/
|
||||
/// mytestsuite.status
|
||||
/// example1_test.dart
|
||||
/// example2_test.dart
|
||||
/// example3_test.dart
|
||||
///
|
||||
/// The important parts:
|
||||
///
|
||||
/// * The leaf directory name is the name of your test suite.
|
||||
/// * The status file uses the same name.
|
||||
/// * Test files are directly in that directory and end in "_test.dart".
|
||||
///
|
||||
/// If you follow that convention, then you can construct one of these like:
|
||||
///
|
||||
/// new StandardTestSuite.forDirectory(configuration, 'path/to/mytestsuite');
|
||||
///
|
||||
/// instead of having to create a custom [StandardTestSuite] subclass. In
|
||||
/// particular, if you add 'path/to/mytestsuite' to [TEST_SUITE_DIRECTORIES]
|
||||
/// in test.dart, this will all be set up for you.
|
||||
factory StandardTestSuite.forDirectory(
|
||||
TestConfiguration configuration, Path directory) {
|
||||
var name = directory.filename;
|
||||
|
@ -594,7 +569,7 @@ class StandardTestSuite extends TestSuite {
|
|||
'$directory/${name}_vm.status',
|
||||
];
|
||||
|
||||
return new StandardTestSuite(configuration, name, directory, status_paths,
|
||||
return StandardTestSuite(configuration, name, directory, status_paths,
|
||||
recursive: true);
|
||||
}
|
||||
|
||||
|
@ -627,28 +602,26 @@ class StandardTestSuite extends TestSuite {
|
|||
if (onDone != null) onDone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the status files and completes with the parsed expectations.
|
||||
*/
|
||||
/// Reads the status files and completes with the parsed expectations.
|
||||
ExpectationSet readExpectations() {
|
||||
var statusFiles = statusFilePaths.where((String statusFilePath) {
|
||||
var file = new File(dartDir.append(statusFilePath).toNativePath());
|
||||
var file = File(dartDir.append(statusFilePath).toNativePath());
|
||||
return file.existsSync();
|
||||
}).map((statusFilePath) {
|
||||
return dartDir.append(statusFilePath).toNativePath();
|
||||
}).toList();
|
||||
|
||||
return new ExpectationSet.read(statusFiles, configuration);
|
||||
return ExpectationSet.read(statusFiles, configuration);
|
||||
}
|
||||
|
||||
Future enqueueTests() {
|
||||
Directory dir = new Directory(suiteDir.toNativePath());
|
||||
Directory dir = Directory(suiteDir.toNativePath());
|
||||
return dir.exists().then((exists) {
|
||||
if (!exists) {
|
||||
print('Directory containing tests missing: ${suiteDir.toNativePath()}');
|
||||
return new Future.value(null);
|
||||
return Future.value(null);
|
||||
} else {
|
||||
var group = new FutureGroup();
|
||||
var group = FutureGroup();
|
||||
enqueueDirectory(dir, group);
|
||||
return group.future;
|
||||
}
|
||||
|
@ -679,7 +652,7 @@ class StandardTestSuite extends TestSuite {
|
|||
|
||||
if (!isTestFile(filename)) return;
|
||||
|
||||
var optionsFromFile = readOptionsFromFile(new Uri.file(filename));
|
||||
var optionsFromFile = readOptionsFromFile(Uri.file(filename));
|
||||
CreateTest createTestCase = makeTestCaseCreator(optionsFromFile);
|
||||
|
||||
if (optionsFromFile['isMultitest'] as bool) {
|
||||
|
@ -709,11 +682,11 @@ class StandardTestSuite extends TestSuite {
|
|||
if (optionsFromFile['packageRoot'] == null &&
|
||||
optionsFromFile['packages'] == null) {
|
||||
if (configuration.packageRoot != null) {
|
||||
packageRoot = new Path(configuration.packageRoot);
|
||||
packageRoot = Path(configuration.packageRoot);
|
||||
optionsFromFile['packageRoot'] = packageRoot.toNativePath();
|
||||
}
|
||||
if (configuration.packages != null) {
|
||||
Path packages = new Path(configuration.packages);
|
||||
Path packages = Path(configuration.packages);
|
||||
optionsFromFile['packages'] = packages.toNativePath();
|
||||
}
|
||||
}
|
||||
|
@ -801,23 +774,22 @@ class StandardTestSuite extends TestSuite {
|
|||
var path = info.filePath;
|
||||
if (vmOptionsVariant != 0) {
|
||||
// Ensure a unique directory for each test case.
|
||||
path = path.join(new Path(vmOptionsVariant.toString()));
|
||||
path = path.join(Path(vmOptionsVariant.toString()));
|
||||
}
|
||||
tempDir = createCompilationOutputDirectory(path);
|
||||
|
||||
var otherResources =
|
||||
info.optionsFromFile['otherResources'] as List<String>;
|
||||
for (var name in otherResources) {
|
||||
var namePath = new Path(name);
|
||||
var namePath = Path(name);
|
||||
var fromPath = info.filePath.directoryPath.join(namePath);
|
||||
new File('$tempDir/$name').parent.createSync(recursive: true);
|
||||
new File(fromPath.toNativePath()).copySync('$tempDir/$name');
|
||||
File('$tempDir/$name').parent.createSync(recursive: true);
|
||||
File(fromPath.toNativePath()).copySync('$tempDir/$name');
|
||||
}
|
||||
}
|
||||
|
||||
CommandArtifact compilationArtifact =
|
||||
compilerConfiguration.computeCompilationArtifact(
|
||||
tempDir, compileTimeArguments, environmentOverrides);
|
||||
var compilationArtifact = compilerConfiguration.computeCompilationArtifact(
|
||||
tempDir, compileTimeArguments, environmentOverrides);
|
||||
if (!configuration.skipCompilation) {
|
||||
commands.addAll(compilationArtifact.commands);
|
||||
}
|
||||
|
@ -835,20 +807,19 @@ class StandardTestSuite extends TestSuite {
|
|||
s.replaceAll("__RANDOM__", "${Random().nextInt(0x7fffffff)}"))
|
||||
.toList();
|
||||
|
||||
List<String> runtimeArguments =
|
||||
compilerConfiguration.computeRuntimeArguments(
|
||||
configuration.runtimeConfiguration,
|
||||
info,
|
||||
vmOptions,
|
||||
sharedOptions,
|
||||
dartOptions,
|
||||
args,
|
||||
compilationArtifact);
|
||||
var runtimeArguments = compilerConfiguration.computeRuntimeArguments(
|
||||
configuration.runtimeConfiguration,
|
||||
info,
|
||||
vmOptions,
|
||||
sharedOptions,
|
||||
dartOptions,
|
||||
args,
|
||||
compilationArtifact);
|
||||
|
||||
Map<String, String> environment = environmentOverrides;
|
||||
var environment = environmentOverrides;
|
||||
var extraEnv = info.optionsFromFile['environment'] as Map<String, String>;
|
||||
if (extraEnv != null) {
|
||||
environment = new Map.from(environment)..addAll(extraEnv);
|
||||
environment = {...environment, ...extraEnv};
|
||||
}
|
||||
|
||||
return commands
|
||||
|
@ -865,10 +836,10 @@ class StandardTestSuite extends TestSuite {
|
|||
{bool hasSyntaxError,
|
||||
bool hasCompileError,
|
||||
bool hasRuntimeError,
|
||||
bool hasStaticWarning: false,
|
||||
bool hasStaticWarning = false,
|
||||
String multitestKey}) {
|
||||
// Cache the test information for each test case.
|
||||
var info = new TestInformation(filePath, originTestPath, optionsFromFile,
|
||||
var info = TestInformation(filePath, originTestPath, optionsFromFile,
|
||||
hasSyntaxError, hasCompileError, hasRuntimeError, hasStaticWarning,
|
||||
multitestKey: multitestKey);
|
||||
cachedTests.add(info);
|
||||
|
@ -876,30 +847,30 @@ class StandardTestSuite extends TestSuite {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* _createUrlPathFromFile takes a [file], which is either located in the dart
|
||||
* or in the build directory, and will return a String representing
|
||||
* the relative path to either the dart or the build directory.
|
||||
* Thus, the returned [String] will be the path component of the URL
|
||||
* corresponding to [file] (the http server serves files relative to the
|
||||
* dart/build directories).
|
||||
*/
|
||||
/// Takes a [file], which is either located in the dart or in the build
|
||||
/// directory, and returns a String representing the relative path to either
|
||||
/// the dart or the build directory.
|
||||
///
|
||||
/// Thus, the returned [String] will be the path component of the URL
|
||||
/// corresponding to [file] (the HTTP server serves files relative to the
|
||||
/// dart/build directories).
|
||||
String _createUrlPathFromFile(Path file) {
|
||||
file = file.absolute;
|
||||
|
||||
var relativeBuildDir = new Path(configuration.buildDirectory);
|
||||
var relativeBuildDir = Path(configuration.buildDirectory);
|
||||
var buildDir = relativeBuildDir.absolute;
|
||||
var dartDir = Repository.dir.absolute;
|
||||
|
||||
var fileString = file.toString();
|
||||
if (fileString.startsWith(buildDir.toString())) {
|
||||
var fileRelativeToBuildDir = file.relativeTo(buildDir);
|
||||
return "/$PREFIX_BUILDDIR/$fileRelativeToBuildDir";
|
||||
return "/$prefixBuildDir/$fileRelativeToBuildDir";
|
||||
} else if (fileString.startsWith(dartDir.toString())) {
|
||||
var fileRelativeToDartDir = file.relativeTo(dartDir);
|
||||
return "/$PREFIX_DARTDIR/$fileRelativeToDartDir";
|
||||
return "/$prefixDartDir/$fileRelativeToDartDir";
|
||||
}
|
||||
// Unreachable
|
||||
|
||||
// Unreachable.
|
||||
print("Cannot create URL for path $file. Not in build or dart directory.");
|
||||
exit(1);
|
||||
return null;
|
||||
|
@ -918,7 +889,7 @@ class StandardTestSuite extends TestSuite {
|
|||
if (subtestName != null) {
|
||||
parameters['group'] = subtestName;
|
||||
}
|
||||
return new Uri(
|
||||
return Uri(
|
||||
scheme: 'http',
|
||||
host: configuration.localIP,
|
||||
port: serverPort,
|
||||
|
@ -954,7 +925,7 @@ class StandardTestSuite extends TestSuite {
|
|||
|
||||
// Use existing HTML document if available.
|
||||
String content;
|
||||
var customHtml = new File(
|
||||
var customHtml = File(
|
||||
info.filePath.directoryPath.append('$nameNoExt.html').toNativePath());
|
||||
if (customHtml.existsSync()) {
|
||||
outputDir = tempDir;
|
||||
|
@ -963,18 +934,18 @@ class StandardTestSuite extends TestSuite {
|
|||
} else {
|
||||
// Synthesize an HTML file for the test.
|
||||
if (configuration.compiler == Compiler.dart2js) {
|
||||
var scriptPath = _createUrlPathFromFile(
|
||||
new Path('$compilationTempDir/$nameNoExt.js'));
|
||||
var scriptPath =
|
||||
_createUrlPathFromFile(Path('$compilationTempDir/$nameNoExt.js'));
|
||||
content = dart2jsHtml(fileName, scriptPath);
|
||||
} else {
|
||||
var jsDir =
|
||||
new Path(compilationTempDir).relativeTo(Repository.dir).toString();
|
||||
Path(compilationTempDir).relativeTo(Repository.dir).toString();
|
||||
content = dartdevcHtml(nameNoExt, jsDir, configuration.compiler);
|
||||
}
|
||||
}
|
||||
|
||||
var htmlPath = '$tempDir/test.html';
|
||||
new File(htmlPath).writeAsStringSync(content);
|
||||
File(htmlPath).writeAsStringSync(content);
|
||||
|
||||
// Construct the command(s) that compile all the inputs needed by the
|
||||
// browser test.
|
||||
|
@ -1019,7 +990,7 @@ class StandardTestSuite extends TestSuite {
|
|||
// Construct the command that executes the browser test.
|
||||
commands = commands.toList();
|
||||
|
||||
var htmlPathSubtest = _createUrlPathFromFile(new Path(htmlPath));
|
||||
var htmlPathSubtest = _createUrlPathFromFile(Path(htmlPath));
|
||||
var fullHtmlPath = _uriForBrowserTest(htmlPathSubtest, subtestName);
|
||||
|
||||
commands.add(Command.browserTest(fullHtmlPath, configuration,
|
||||
|
@ -1034,7 +1005,7 @@ class StandardTestSuite extends TestSuite {
|
|||
Path filePath, Map<String, dynamic> optionsFromFile) {
|
||||
var args = configuration.standardOptions.toList();
|
||||
|
||||
String packages = packagesArgument(optionsFromFile['packageRoot'] as String,
|
||||
var packages = packagesArgument(optionsFromFile['packageRoot'] as String,
|
||||
optionsFromFile['packages'] as String);
|
||||
if (packages != null) {
|
||||
args.add(packages);
|
||||
|
@ -1067,74 +1038,72 @@ class StandardTestSuite extends TestSuite {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special options for individual tests are currently specified in various
|
||||
* ways: with comments directly in test files, by using certain imports, or by
|
||||
* creating additional files in the test directories.
|
||||
*
|
||||
* Here is a list of options that are used by 'test.dart' today:
|
||||
* - Flags can be passed to the vm process that runs the test by adding a
|
||||
* comment to the test file:
|
||||
*
|
||||
* // VMOptions=--flag1 --flag2
|
||||
*
|
||||
* - Flags can be passed to dart2js, vm or dartdevc by adding a comment to
|
||||
* the test file:
|
||||
*
|
||||
* // SharedOptions=--flag1 --flag2
|
||||
*
|
||||
* - Flags can be passed to dart2js by adding a comment to the test file:
|
||||
*
|
||||
* // dart2jsOptions=--flag1 --flag2
|
||||
*
|
||||
* - Flags can be passed to the dart script that contains the test also
|
||||
* using comments, as follows:
|
||||
*
|
||||
* // DartOptions=--flag1 --flag2
|
||||
*
|
||||
* - Extra environment variables can be passed to the process that runs
|
||||
* the test by adding comment(s) to the test file:
|
||||
*
|
||||
* // Environment=ENV_VAR1=foo bar
|
||||
* // Environment=ENV_VAR2=bazz
|
||||
*
|
||||
* - Most tests are not web tests, but can (and will be) wrapped within
|
||||
* an HTML file and another script file to test them also on browser
|
||||
* environments (e.g. language and corelib tests are run this way).
|
||||
* We deduce that if a file with the same name as the test, but ending in
|
||||
* .html instead of .dart exists, the test was intended to be a web test
|
||||
* and no wrapping is necessary.
|
||||
*
|
||||
* // SharedObjects=foobar
|
||||
*
|
||||
* - This test requires libfoobar.so, libfoobar.dylib or foobar.dll to be
|
||||
* in the system linker path of the VM.
|
||||
*
|
||||
* - 'test.dart' assumes tests fail if
|
||||
* the process returns a non-zero exit code (in the case of web tests, we
|
||||
* check for PASS/FAIL indications in the test output).
|
||||
*
|
||||
* This method is static as the map is cached and shared amongst
|
||||
* configurations, so it may not use [configuration].
|
||||
*/
|
||||
/// Special options for individual tests are currently specified in various
|
||||
/// ways: with comments directly in test files, by using certain imports, or
|
||||
/// by creating additional files in the test directories.
|
||||
///
|
||||
/// Here is a list of options that are used by 'test.dart' today:
|
||||
/// - Flags can be passed to the vm process that runs the test by adding a
|
||||
/// comment to the test file:
|
||||
///
|
||||
/// // VMOptions=--flag1 --flag2
|
||||
///
|
||||
/// - Flags can be passed to dart2js, vm or dartdevc by adding a comment to
|
||||
/// the test file:
|
||||
///
|
||||
/// // SharedOptions=--flag1 --flag2
|
||||
///
|
||||
/// - Flags can be passed to dart2js by adding a comment to the test file:
|
||||
///
|
||||
/// // dart2jsOptions=--flag1 --flag2
|
||||
///
|
||||
/// - Flags can be passed to the dart script that contains the test also
|
||||
/// using comments, as follows:
|
||||
///
|
||||
/// // DartOptions=--flag1 --flag2
|
||||
///
|
||||
/// - Extra environment variables can be passed to the process that runs
|
||||
/// the test by adding comment(s) to the test file:
|
||||
///
|
||||
/// // Environment=ENV_VAR1=foo bar
|
||||
/// // Environment=ENV_VAR2=bazz
|
||||
///
|
||||
/// - Most tests are not web tests, but can (and will be) wrapped within
|
||||
/// an HTML file and another script file to test them also on browser
|
||||
/// environments (e.g. language and corelib tests are run this way).
|
||||
/// We deduce that if a file with the same name as the test, but ending in
|
||||
/// .html instead of .dart exists, the test was intended to be a web test
|
||||
/// and no wrapping is necessary.
|
||||
///
|
||||
/// // SharedObjects=foobar
|
||||
///
|
||||
/// - This test requires libfoobar.so, libfoobar.dylib or foobar.dll to be
|
||||
/// in the system linker path of the VM.
|
||||
///
|
||||
/// - 'test.dart' assumes tests fail if
|
||||
/// the process returns a non-zero exit code (in the case of web tests, we
|
||||
/// check for PASS/FAIL indications in the test output).
|
||||
///
|
||||
/// This method is static as the map is cached and shared amongst
|
||||
/// configurations, so it may not use [configuration].
|
||||
Map<String, dynamic> readOptionsFromFile(Uri uri) {
|
||||
if (uri.path.endsWith('.dill')) {
|
||||
return optionsFromKernelFile();
|
||||
}
|
||||
RegExp testOptionsRegExp = new RegExp(r"// VMOptions=(.*)");
|
||||
RegExp environmentRegExp = new RegExp(r"// Environment=(.*)");
|
||||
RegExp otherResourcesRegExp = new RegExp(r"// OtherResources=(.*)");
|
||||
RegExp sharedObjectsRegExp = new RegExp(r"// SharedObjects=(.*)");
|
||||
RegExp packageRootRegExp = new RegExp(r"// PackageRoot=(.*)");
|
||||
RegExp packagesRegExp = new RegExp(r"// Packages=(.*)");
|
||||
RegExp isolateStubsRegExp = new RegExp(r"// IsolateStubs=(.*)");
|
||||
var testOptionsRegExp = RegExp(r"// VMOptions=(.*)");
|
||||
var environmentRegExp = RegExp(r"// Environment=(.*)");
|
||||
var otherResourcesRegExp = RegExp(r"// OtherResources=(.*)");
|
||||
var sharedObjectsRegExp = RegExp(r"// SharedObjects=(.*)");
|
||||
var packageRootRegExp = RegExp(r"// PackageRoot=(.*)");
|
||||
var packagesRegExp = RegExp(r"// Packages=(.*)");
|
||||
var isolateStubsRegExp = RegExp(r"// IsolateStubs=(.*)");
|
||||
// TODO(gram) Clean these up once the old directives are not supported.
|
||||
RegExp domImportRegExp = new RegExp(
|
||||
var domImportRegExp = RegExp(
|
||||
r"^[#]?import.*dart:(html|web_audio|indexed_db|svg|web_sql)",
|
||||
multiLine: true);
|
||||
|
||||
var bytes = new File.fromUri(uri).readAsBytesSync();
|
||||
String contents = decodeUtf8(bytes);
|
||||
var bytes = File.fromUri(uri).readAsBytesSync();
|
||||
var contents = decodeUtf8(bytes);
|
||||
bytes = null;
|
||||
|
||||
// Find the options in the file.
|
||||
|
@ -1151,11 +1120,11 @@ class StandardTestSuite extends TestSuite {
|
|||
s.split(' ').where((e) => e != '').toList();
|
||||
|
||||
List<String> singleListOfOptions(String name) {
|
||||
var matches = new RegExp('// $name=(.*)').allMatches(contents);
|
||||
var matches = RegExp('// $name=(.*)').allMatches(contents);
|
||||
List<String> options;
|
||||
for (var match in matches) {
|
||||
if (options != null) {
|
||||
throw new Exception(
|
||||
throw Exception(
|
||||
'More than one "// $name=" line in test ${uri.toFilePath()}');
|
||||
}
|
||||
options = wordSplit(match[1]);
|
||||
|
@ -1176,10 +1145,10 @@ class StandardTestSuite extends TestSuite {
|
|||
|
||||
matches = environmentRegExp.allMatches(contents);
|
||||
for (var match in matches) {
|
||||
final String envDef = match[1];
|
||||
final int pos = envDef.indexOf('=');
|
||||
final String name = (pos < 0) ? envDef : envDef.substring(0, pos);
|
||||
final String value = (pos < 0) ? '' : envDef.substring(pos + 1);
|
||||
var envDef = match[1];
|
||||
var pos = envDef.indexOf('=');
|
||||
var name = (pos < 0) ? envDef : envDef.substring(0, pos);
|
||||
var value = (pos < 0) ? '' : envDef.substring(pos + 1);
|
||||
environment ??= <String, String>{};
|
||||
environment[name] = value;
|
||||
}
|
||||
|
@ -1187,7 +1156,7 @@ class StandardTestSuite extends TestSuite {
|
|||
matches = packageRootRegExp.allMatches(contents);
|
||||
for (var match in matches) {
|
||||
if (packageRoot != null || packages != null) {
|
||||
throw new Exception(
|
||||
throw Exception(
|
||||
'More than one "// Package... line in test ${uri.toFilePath()}');
|
||||
}
|
||||
packageRoot = match[1];
|
||||
|
@ -1195,15 +1164,14 @@ class StandardTestSuite extends TestSuite {
|
|||
// PackageRoot=none means that no packages or package-root option
|
||||
// should be given. Any other value overrides package-root and
|
||||
// removes any packages option. Don't use with // Packages=.
|
||||
packageRoot =
|
||||
uri.resolveUri(new Uri.directory(packageRoot)).toFilePath();
|
||||
packageRoot = uri.resolveUri(Uri.directory(packageRoot)).toFilePath();
|
||||
}
|
||||
}
|
||||
|
||||
matches = packagesRegExp.allMatches(contents);
|
||||
for (var match in matches) {
|
||||
if (packages != null || packageRoot != null) {
|
||||
throw new Exception(
|
||||
throw Exception(
|
||||
'More than one "// Package..." line in test ${uri.toFilePath()}');
|
||||
}
|
||||
packages = match[1];
|
||||
|
@ -1211,7 +1179,7 @@ class StandardTestSuite extends TestSuite {
|
|||
// Packages=none means that no packages or package-root option
|
||||
// should be given. Any other value overrides packages and removes
|
||||
// any package-root option. Don't use with // PackageRoot=.
|
||||
packages = uri.resolveUri(new Uri.file(packages)).toFilePath();
|
||||
packages = uri.resolveUri(Uri.file(packages)).toFilePath();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1227,14 +1195,14 @@ class StandardTestSuite extends TestSuite {
|
|||
sharedObjects.addAll(wordSplit(match[1]));
|
||||
}
|
||||
|
||||
var isMultitest = multiTestRegExp.hasMatch(contents);
|
||||
var isMultiHtmlTest = multiHtmlTestRegExp.hasMatch(contents);
|
||||
var isMultitest = _multiTestRegExp.hasMatch(contents);
|
||||
var isMultiHtmlTest = _multiHtmlTestRegExp.hasMatch(contents);
|
||||
var isolateMatch = isolateStubsRegExp.firstMatch(contents);
|
||||
var isolateStubs = isolateMatch != null ? isolateMatch[1] : '';
|
||||
var containsDomImport = domImportRegExp.hasMatch(contents);
|
||||
|
||||
var subtestNames = <String>[];
|
||||
var matchesIter = multiHtmlTestGroupRegExp.allMatches(contents).iterator;
|
||||
var matchesIter = _multiHtmlTestGroupRegExp.allMatches(contents).iterator;
|
||||
while (matchesIter.moveNext() && isMultiHtmlTest) {
|
||||
var fullMatch = matchesIter.current.group(0);
|
||||
subtestNames.add(fullMatch.substring(fullMatch.indexOf("'") + 1));
|
||||
|
@ -1294,10 +1262,10 @@ class StandardTestSuite extends TestSuite {
|
|||
|
||||
Map<String, dynamic> optionsFromKernelFile() {
|
||||
return const {
|
||||
"vmOptions": const [const <String>[]],
|
||||
"sharedOptions": const <String>[],
|
||||
"dart2jsOptions": const <String>[],
|
||||
"dartOptions": const <String>[],
|
||||
"vmOptions": [<String>[]],
|
||||
"sharedOptions": <String>[],
|
||||
"dart2jsOptions": <String>[],
|
||||
"dartOptions": <String>[],
|
||||
"packageRoot": null,
|
||||
"packages": null,
|
||||
"hasSyntaxError": false,
|
||||
|
@ -1306,14 +1274,14 @@ class StandardTestSuite extends TestSuite {
|
|||
"hasStaticWarning": false,
|
||||
"isMultitest": false,
|
||||
"isMultiHtmlTest": false,
|
||||
"subtestNames": const [],
|
||||
"subtestNames": [],
|
||||
"isolateStubs": '',
|
||||
"containsDomImport": false,
|
||||
};
|
||||
}
|
||||
|
||||
List<List<String>> getVmOptions(Map<String, dynamic> optionsFromFile) {
|
||||
const compilers = const [
|
||||
const compilers = [
|
||||
Compiler.none,
|
||||
Compiler.dartk,
|
||||
Compiler.dartkb,
|
||||
|
@ -1323,7 +1291,7 @@ class StandardTestSuite extends TestSuite {
|
|||
Compiler.appJitk,
|
||||
];
|
||||
|
||||
const runtimes = const [Runtime.none, Runtime.dartPrecompiled, Runtime.vm];
|
||||
const runtimes = [Runtime.none, Runtime.dartPrecompiled, Runtime.vm];
|
||||
|
||||
var needsVmOptions = compilers.contains(configuration.compiler) &&
|
||||
runtimes.contains(configuration.runtime);
|
||||
|
@ -1346,7 +1314,7 @@ class PKGTestSuite extends StandardTestSuite {
|
|||
var dir = filePath.directoryPath;
|
||||
var nameNoExt = filePath.filenameWithoutExtension;
|
||||
var customHtmlPath = dir.append('$nameNoExt.html');
|
||||
var customHtml = new File(customHtmlPath.toNativePath());
|
||||
var customHtml = File(customHtmlPath.toNativePath());
|
||||
if (!customHtml.existsSync()) {
|
||||
super._enqueueBrowserTest(
|
||||
packageRoot, packages, info, testName, expectations);
|
||||
|
@ -1361,7 +1329,7 @@ class PKGTestSuite extends StandardTestSuite {
|
|||
|
||||
class AnalyzeLibraryTestSuite extends StandardTestSuite {
|
||||
static Path _libraryPath(TestConfiguration configuration) =>
|
||||
new Path(configuration.useSdk
|
||||
Path(configuration.useSdk
|
||||
? '${configuration.buildDirectory}/dart-sdk'
|
||||
: 'sdk');
|
||||
|
||||
|
@ -1375,9 +1343,9 @@ class AnalyzeLibraryTestSuite extends StandardTestSuite {
|
|||
const ['--fatal-warnings', '--fatal-type-errors', '--sdk-warnings'];
|
||||
|
||||
Future enqueueTests() {
|
||||
var group = new FutureGroup();
|
||||
var group = FutureGroup();
|
||||
|
||||
var dir = new Directory(suiteDir.append('lib').toNativePath());
|
||||
var dir = Directory(suiteDir.append('lib').toNativePath());
|
||||
if (dir.existsSync()) {
|
||||
enqueueDirectory(dir, group);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import 'package:test_runner/src/utils.dart';
|
|||
|
||||
class DispatchingServer {
|
||||
HttpServer server;
|
||||
Map<String, Function> _handlers = new Map<String, Function>();
|
||||
Map<String, Function> _handlers = {};
|
||||
Function _notFound;
|
||||
|
||||
DispatchingServer(
|
||||
|
@ -57,16 +57,14 @@ class DispatchingServer {
|
|||
/// In case a path does not refer to a file but rather to a directory, a
|
||||
/// directory listing will be displayed.
|
||||
|
||||
const PREFIX_BUILDDIR = 'root_build';
|
||||
const PREFIX_DARTDIR = 'root_dart';
|
||||
const prefixBuildDir = 'root_build';
|
||||
const prefixDartDir = 'root_dart';
|
||||
|
||||
/**
|
||||
* Runs a set of servers that are initialized specifically for the needs of our
|
||||
* test framework, such as dealing with package-root.
|
||||
*/
|
||||
/// Runs a set of servers that are initialized specifically for the needs of our
|
||||
/// test framework, such as dealing with package-root.
|
||||
class TestingServers {
|
||||
static final _CACHE_EXPIRATION_IN_SECONDS = 30;
|
||||
static final _HARMLESS_REQUEST_PATH_ENDINGS = [
|
||||
static final _cacheExpirationSeconds = 30;
|
||||
static final _harmlessRequestPathSuffixes = [
|
||||
"/apple-touch-icon.png",
|
||||
"/apple-touch-icon-precomposed.png",
|
||||
"/favicon.ico",
|
||||
|
@ -91,20 +89,20 @@ class TestingServers {
|
|||
String dartDirectory,
|
||||
String packageRoot,
|
||||
String packages]) {
|
||||
_buildDirectory = Uri.base.resolveUri(new Uri.directory(buildDirectory));
|
||||
_buildDirectory = Uri.base.resolveUri(Uri.directory(buildDirectory));
|
||||
if (dartDirectory == null) {
|
||||
_dartDirectory = Repository.uri;
|
||||
} else {
|
||||
_dartDirectory = Uri.base.resolveUri(new Uri.directory(dartDirectory));
|
||||
_dartDirectory = Uri.base.resolveUri(Uri.directory(dartDirectory));
|
||||
}
|
||||
if (packageRoot == null) {
|
||||
if (packages == null) {
|
||||
_packages = _dartDirectory.resolve('.packages');
|
||||
} else {
|
||||
_packages = new Uri.file(packages);
|
||||
_packages = Uri.file(packages);
|
||||
}
|
||||
} else {
|
||||
_packageRoot = new Uri.directory(packageRoot);
|
||||
_packageRoot = Uri.directory(packageRoot);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,20 +114,19 @@ class TestingServers {
|
|||
|
||||
DispatchingServer get server => _server;
|
||||
|
||||
/**
|
||||
* [startServers] will start two Http servers.
|
||||
* The first server listens on [port] and sets
|
||||
* "Access-Control-Allow-Origin: *"
|
||||
* The second server listens on [crossOriginPort] and sets
|
||||
* "Access-Control-Allow-Origin: client:port1
|
||||
* "Access-Control-Allow-Credentials: true"
|
||||
*/
|
||||
/// [startServers] will start two Http servers.
|
||||
///
|
||||
/// The first server listens on [port] and sets
|
||||
/// "Access-Control-Allow-Origin: *"
|
||||
/// The second server listens on [crossOriginPort] and sets
|
||||
/// "Access-Control-Allow-Origin: client:port1
|
||||
/// "Access-Control-Allow-Credentials: true"
|
||||
Future startServers(String host,
|
||||
{int port: 0, int crossOriginPort: 0}) async {
|
||||
{int port = 0, int crossOriginPort = 0}) async {
|
||||
if (_packages != null) {
|
||||
_resolver = await SyncPackageResolver.loadConfig(_packages);
|
||||
} else {
|
||||
_resolver = new SyncPackageResolver.root(_packageRoot);
|
||||
_resolver = SyncPackageResolver.root(_packageRoot);
|
||||
}
|
||||
_server = await _startHttpServer(host, port: port);
|
||||
await _startHttpServer(host,
|
||||
|
@ -142,7 +139,7 @@ class TestingServers {
|
|||
var script = _dartDirectory.resolve('pkg/test_runner/bin/http_server.dart');
|
||||
var buildDirectory = _buildDirectory.toFilePath();
|
||||
|
||||
var command = [
|
||||
return [
|
||||
dart,
|
||||
script.toFilePath(),
|
||||
'-p',
|
||||
|
@ -152,20 +149,13 @@ class TestingServers {
|
|||
'--network',
|
||||
network,
|
||||
'--build-directory=$buildDirectory',
|
||||
'--runtime=${runtime.name}'
|
||||
];
|
||||
|
||||
if (useContentSecurityPolicy) {
|
||||
command.add('--csp');
|
||||
}
|
||||
|
||||
if (_packages != null) {
|
||||
command.add('--packages=${_packages.toFilePath()}');
|
||||
} else if (_packageRoot != null) {
|
||||
command.add('--package-root=${_packageRoot.toFilePath()}');
|
||||
}
|
||||
|
||||
return command.join(' ');
|
||||
'--runtime=${runtime.name}',
|
||||
if (useContentSecurityPolicy) '--csp',
|
||||
if (_packages != null)
|
||||
'--packages=${_packages.toFilePath()}'
|
||||
else if (_packageRoot != null)
|
||||
'--package-root=${_packageRoot.toFilePath()}'
|
||||
].join(' ');
|
||||
}
|
||||
|
||||
void stopServers() {
|
||||
|
@ -179,17 +169,17 @@ class TestingServers {
|
|||
}
|
||||
|
||||
Future<DispatchingServer> _startHttpServer(String host,
|
||||
{int port: 0, int allowedPort: -1}) {
|
||||
{int port = 0, int allowedPort = -1}) {
|
||||
return HttpServer.bind(host, port).then((HttpServer httpServer) {
|
||||
var server = new DispatchingServer(httpServer, _onError, _sendNotFound);
|
||||
var server = DispatchingServer(httpServer, _onError, _sendNotFound);
|
||||
server.addHandler('/echo', _handleEchoRequest);
|
||||
server.addHandler('/ws', _handleWebSocketRequest);
|
||||
fileHandler(HttpRequest request) {
|
||||
_handleFileOrDirectoryRequest(request, allowedPort);
|
||||
}
|
||||
|
||||
server.addHandler('/$PREFIX_BUILDDIR', fileHandler);
|
||||
server.addHandler('/$PREFIX_DARTDIR', fileHandler);
|
||||
server.addHandler('/$prefixBuildDir', fileHandler);
|
||||
server.addHandler('/$prefixDartDir', fileHandler);
|
||||
server.addHandler('/packages', fileHandler);
|
||||
_serverList.add(httpServer);
|
||||
return server;
|
||||
|
@ -200,13 +190,12 @@ class TestingServers {
|
|||
HttpRequest request, int allowedPort) async {
|
||||
// Enable browsers to cache file/directory responses.
|
||||
var response = request.response;
|
||||
response.headers
|
||||
.set("Cache-Control", "max-age=$_CACHE_EXPIRATION_IN_SECONDS");
|
||||
response.headers.set("Cache-Control", "max-age=$_cacheExpirationSeconds");
|
||||
try {
|
||||
var path = _getFileUriFromRequestUri(request.uri);
|
||||
if (path != null) {
|
||||
var file = new File.fromUri(path);
|
||||
var directory = new Directory.fromUri(path);
|
||||
var file = File.fromUri(path);
|
||||
var directory = Directory.fromUri(path);
|
||||
if (await file.exists()) {
|
||||
_sendFileContent(request, response, allowedPort, file);
|
||||
} else if (await directory.exists()) {
|
||||
|
@ -218,9 +207,9 @@ class TestingServers {
|
|||
} else {
|
||||
if (request.uri.path == '/') {
|
||||
var entries = [
|
||||
new _Entry('root_dart', 'root_dart/'),
|
||||
new _Entry('root_build', 'root_build/'),
|
||||
new _Entry('echo', 'echo')
|
||||
_Entry('root_dart', 'root_dart/'),
|
||||
_Entry('root_build', 'root_build/'),
|
||||
_Entry('echo', 'echo')
|
||||
];
|
||||
_sendDirectoryListing(entries, request, response);
|
||||
} else {
|
||||
|
@ -269,32 +258,32 @@ class TestingServers {
|
|||
if (pathSegments.length == 0) return null;
|
||||
int packagesIndex = pathSegments.indexOf('packages');
|
||||
if (packagesIndex != -1) {
|
||||
var packageUri = new Uri(
|
||||
var packageUri = Uri(
|
||||
scheme: 'package',
|
||||
pathSegments: pathSegments.skip(packagesIndex + 1));
|
||||
return _resolver.resolveUri(packageUri);
|
||||
}
|
||||
if (pathSegments[0] == PREFIX_BUILDDIR) {
|
||||
if (pathSegments[0] == prefixBuildDir) {
|
||||
return _buildDirectory.resolve(pathSegments.skip(1).join('/'));
|
||||
}
|
||||
if (pathSegments[0] == PREFIX_DARTDIR) {
|
||||
if (pathSegments[0] == prefixDartDir) {
|
||||
return _dartDirectory.resolve(pathSegments.skip(1).join('/'));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<List<_Entry>> _listDirectory(Directory directory) {
|
||||
var completer = new Completer<List<_Entry>>();
|
||||
var completer = Completer<List<_Entry>>();
|
||||
var entries = <_Entry>[];
|
||||
|
||||
directory.list().listen((FileSystemEntity fse) {
|
||||
var segments = fse.uri.pathSegments;
|
||||
if (fse is File) {
|
||||
var filename = segments.last;
|
||||
entries.add(new _Entry(filename, filename));
|
||||
entries.add(_Entry(filename, filename));
|
||||
} else if (fse is Directory) {
|
||||
var dirname = segments[segments.length - 2];
|
||||
entries.add(new _Entry(dirname, '$dirname/'));
|
||||
entries.add(_Entry(dirname, '$dirname/'));
|
||||
}
|
||||
}, onDone: () {
|
||||
completer.complete(entries);
|
||||
|
@ -392,7 +381,7 @@ class TestingServers {
|
|||
|
||||
void _sendNotFound(HttpRequest request) {
|
||||
bool isHarmlessPath(String path) {
|
||||
return _HARMLESS_REQUEST_PATH_ENDINGS.any((pattern) {
|
||||
return _harmlessRequestPathSuffixes.any((pattern) {
|
||||
return path.contains(pattern);
|
||||
});
|
||||
}
|
||||
|
@ -431,7 +420,7 @@ class TestingServers {
|
|||
}
|
||||
}
|
||||
|
||||
// Helper class for displaying directory listings.
|
||||
/// Helper class for displaying directory listings.
|
||||
class _Entry implements Comparable<_Entry> {
|
||||
final String name;
|
||||
final String displayName;
|
||||
|
|
|
@ -9,17 +9,17 @@ import 'dart:convert';
|
|||
import 'configuration.dart';
|
||||
import 'path.dart';
|
||||
|
||||
// This is the maximum time we expect stdout/stderr of subprocesses to deliver
|
||||
// data after we've got the exitCode.
|
||||
const Duration MAX_STDIO_DELAY = const Duration(seconds: 30);
|
||||
/// This is the maximum time we expect stdout/stderr of subprocesses to deliver
|
||||
/// data after we've got the exitCode.
|
||||
const Duration maxStdioDelay = Duration(seconds: 30);
|
||||
|
||||
String MAX_STDIO_DELAY_PASSED_MESSAGE =
|
||||
final maxStdioDelayPassedMessage =
|
||||
"""Not waiting for stdout/stderr from subprocess anymore
|
||||
($MAX_STDIO_DELAY passed). Please note that this could be an indicator
|
||||
($maxStdioDelay passed). Please note that this could be an indicator
|
||||
that there is a hanging process which we were unable to kill.""";
|
||||
|
||||
/// The names of the packages that are available for use in tests.
|
||||
const testPackages = const [
|
||||
const testPackages = [
|
||||
"async_helper",
|
||||
"collection",
|
||||
"expect",
|
||||
|
@ -34,12 +34,10 @@ const testPackages = const [
|
|||
class DebugLogger {
|
||||
static IOSink _sink;
|
||||
|
||||
/**
|
||||
* If [path] was null, the DebugLogger will write messages to stdout.
|
||||
*/
|
||||
/// If [path] was null, the DebugLogger will write messages to stdout.
|
||||
static void init(Path path) {
|
||||
if (path != null) {
|
||||
_sink = new File(path.toNativePath()).openWrite(mode: FileMode.append);
|
||||
_sink = File(path.toNativePath()).openWrite(mode: FileMode.append);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,18 +80,19 @@ class DebugLogger {
|
|||
}
|
||||
}
|
||||
|
||||
static String get _datetime => "${new DateTime.now()}";
|
||||
static String get _datetime => "${DateTime.now()}";
|
||||
}
|
||||
|
||||
String prettifyJson(Object json, {int startIndentation: 0, int shiftWidth: 6}) {
|
||||
String prettifyJson(Object json,
|
||||
{int startIndentation = 0, int shiftWidth = 6}) {
|
||||
int currentIndentation = startIndentation;
|
||||
var buffer = new StringBuffer();
|
||||
var buffer = StringBuffer();
|
||||
|
||||
String indentationString() {
|
||||
return new List.filled(currentIndentation, ' ').join('');
|
||||
return List.filled(currentIndentation, ' ').join('');
|
||||
}
|
||||
|
||||
addString(String s, {bool indentation: true, bool newLine: true}) {
|
||||
addString(String s, {bool indentation = true, bool newLine = true}) {
|
||||
if (indentation) {
|
||||
buffer.write(indentationString());
|
||||
}
|
||||
|
@ -102,7 +101,7 @@ String prettifyJson(Object json, {int startIndentation: 0, int shiftWidth: 6}) {
|
|||
}
|
||||
|
||||
prettifyJsonInternal(Object obj,
|
||||
{bool indentation: true, bool newLine: true}) {
|
||||
{bool indentation = true, bool newLine = true}) {
|
||||
if (obj is List) {
|
||||
addString("[", indentation: indentation);
|
||||
currentIndentation += shiftWidth;
|
||||
|
@ -132,15 +131,13 @@ String prettifyJson(Object json, {int startIndentation: 0, int shiftWidth: 6}) {
|
|||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* [areByteArraysEqual] compares a range of bytes from [buffer1] with a
|
||||
* range of bytes from [buffer2].
|
||||
*
|
||||
* Returns [true] if the [count] bytes in [buffer1] (starting at
|
||||
* [offset1]) match the [count] bytes in [buffer2] (starting at
|
||||
* [offset2]).
|
||||
* Otherwise [false] is returned.
|
||||
*/
|
||||
/// [areByteArraysEqual] compares a range of bytes from [buffer1] with a
|
||||
/// range of bytes from [buffer2].
|
||||
///
|
||||
/// Returns [true] if the [count] bytes in [buffer1] (starting at
|
||||
/// [offset1]) match the [count] bytes in [buffer2] (starting at
|
||||
/// [offset2]).
|
||||
/// Otherwise [false] is returned.
|
||||
bool areByteArraysEqual(
|
||||
List<int> buffer1, int offset1, List<int> buffer2, int offset2, int count) {
|
||||
if ((offset1 + count) > buffer1.length ||
|
||||
|
@ -156,12 +153,10 @@ bool areByteArraysEqual(
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* [findBytes] searches for [pattern] in [data] beginning at [startPos].
|
||||
*
|
||||
* Returns [true] if [pattern] was found in [data].
|
||||
* Otherwise [false] is returned.
|
||||
*/
|
||||
/// [findBytes] searches for [pattern] in [data] beginning at [startPos].
|
||||
///
|
||||
/// Returns [true] if [pattern] was found in [data].
|
||||
/// Otherwise [false] is returned.
|
||||
int findBytes(List<int> data, List<int> pattern, [int startPos = 0]) {
|
||||
// TODO(kustermann): Use one of the fast string-matching algorithms!
|
||||
for (int i = startPos; i < (data.length - pattern.length); i++) {
|
||||
|
@ -201,7 +196,7 @@ List<String> decodeLines(List<int> output) {
|
|||
}
|
||||
|
||||
String indent(String string, int numSpaces) {
|
||||
var spaces = new List.filled(numSpaces, ' ').join('');
|
||||
var spaces = List.filled(numSpaces, ' ').join('');
|
||||
return string
|
||||
.replaceAll('\r\n', '\n')
|
||||
.split('\n')
|
||||
|
@ -232,8 +227,8 @@ String niceTime(Duration duration) {
|
|||
}
|
||||
}
|
||||
|
||||
// This function is pretty stupid and only puts quotes around an argument if
|
||||
// it the argument contains a space.
|
||||
/// This function is pretty stupid and only puts quotes around an argument if
|
||||
/// it the argument contains a space.
|
||||
String escapeCommandLineArgument(String argument) {
|
||||
if (argument.contains(' ')) {
|
||||
return '"$argument"';
|
||||
|
@ -263,7 +258,7 @@ class HashCodeBuilder {
|
|||
addJson(object[key]);
|
||||
}
|
||||
} else {
|
||||
throw new Exception("Can't build hashcode for non json-like object "
|
||||
throw Exception("Can't build hashcode for non json-like object "
|
||||
"(${object.runtimeType})");
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +291,7 @@ bool deepJsonCompare(Object a, Object b) {
|
|||
}
|
||||
return false;
|
||||
} else {
|
||||
throw new Exception("Can't compare two non json-like objects "
|
||||
throw Exception("Can't compare two non json-like objects "
|
||||
"(a: ${a.runtimeType}, b: ${b.runtimeType})");
|
||||
}
|
||||
}
|
||||
|
@ -315,57 +310,51 @@ class UniqueObject {
|
|||
class LastModifiedCache {
|
||||
Map<String, DateTime> _cache = <String, DateTime>{};
|
||||
|
||||
/**
|
||||
* Returns the last modified date of the given [uri].
|
||||
*
|
||||
* The return value will be cached for future queries. If [uri] is a local
|
||||
* file, it's last modified [Date] will be returned. If the file does not
|
||||
* exist, null will be returned instead.
|
||||
* In case [uri] is not a local file, this method will always return
|
||||
* the current date.
|
||||
*/
|
||||
/// Returns the last modified date of the given [uri].
|
||||
///
|
||||
/// The return value will be cached for future queries. If [uri] is a local
|
||||
/// file, it's last modified [Date] will be returned. If the file does not
|
||||
/// exist, null will be returned instead.
|
||||
/// In case [uri] is not a local file, this method will always return
|
||||
/// the current date.
|
||||
DateTime getLastModified(Uri uri) {
|
||||
if (uri.scheme == "file") {
|
||||
if (_cache.containsKey(uri.path)) {
|
||||
return _cache[uri.path];
|
||||
}
|
||||
var file = new File(new Path(uri.path).toNativePath());
|
||||
var file = File(Path(uri.path).toNativePath());
|
||||
_cache[uri.path] = file.existsSync() ? file.lastModifiedSync() : null;
|
||||
return _cache[uri.path];
|
||||
}
|
||||
return new DateTime.now();
|
||||
return DateTime.now();
|
||||
}
|
||||
}
|
||||
|
||||
class ExistsCache {
|
||||
Map<String, bool> _cache = <String, bool>{};
|
||||
|
||||
/**
|
||||
* Returns true if the file in [path] exists, false otherwise.
|
||||
*
|
||||
* The information will be cached.
|
||||
*/
|
||||
/// Returns true if the file in [path] exists, false otherwise.
|
||||
///
|
||||
/// The information will be cached.
|
||||
bool doesFileExist(String path) {
|
||||
if (!_cache.containsKey(path)) {
|
||||
_cache[path] = new File(path).existsSync();
|
||||
_cache[path] = File(path).existsSync();
|
||||
}
|
||||
return _cache[path];
|
||||
}
|
||||
}
|
||||
|
||||
class TestUtils {
|
||||
static LastModifiedCache lastModifiedCache = new LastModifiedCache();
|
||||
static ExistsCache existsCache = new ExistsCache();
|
||||
static LastModifiedCache lastModifiedCache = LastModifiedCache();
|
||||
static ExistsCache existsCache = ExistsCache();
|
||||
|
||||
/**
|
||||
* Creates a directory using a [relativePath] to an existing
|
||||
* [base] directory if that [relativePath] does not already exist.
|
||||
*/
|
||||
/// Creates a directory using a [relativePath] to an existing
|
||||
/// [base] directory if that [relativePath] does not already exist.
|
||||
static Directory mkdirRecursive(Path base, Path relativePath) {
|
||||
if (relativePath.isAbsolute) {
|
||||
base = new Path('/');
|
||||
base = Path('/');
|
||||
}
|
||||
Directory dir = new Directory(base.toNativePath());
|
||||
Directory dir = Directory(base.toNativePath());
|
||||
assert(dir.existsSync());
|
||||
var segments = relativePath.segments();
|
||||
for (String segment in segments) {
|
||||
|
@ -376,7 +365,7 @@ class TestUtils {
|
|||
// Skip the directory creation for a path like "/E:".
|
||||
continue;
|
||||
}
|
||||
dir = new Directory(base.toNativePath());
|
||||
dir = Directory(base.toNativePath());
|
||||
if (!dir.existsSync()) {
|
||||
dir.createSync();
|
||||
}
|
||||
|
@ -385,23 +374,19 @@ class TestUtils {
|
|||
return dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep a map of files copied to avoid race conditions.
|
||||
*/
|
||||
/// Keep a map of files copied to avoid race conditions.
|
||||
static Map<String, Future> _copyFilesMap = {};
|
||||
|
||||
/**
|
||||
* Copy a [source] file to a new place.
|
||||
* Assumes that the directory for [dest] already exists.
|
||||
*/
|
||||
/// Copy a [source] file to a new place.
|
||||
/// Assumes that the directory for [dest] already exists.
|
||||
static Future copyFile(Path source, Path dest) {
|
||||
return _copyFilesMap.putIfAbsent(dest.toNativePath(),
|
||||
() => new File(source.toNativePath()).copy(dest.toNativePath()));
|
||||
() => File(source.toNativePath()).copy(dest.toNativePath()));
|
||||
}
|
||||
|
||||
static Future copyDirectory(String source, String dest) {
|
||||
source = new Path(source).toNativePath();
|
||||
dest = new Path(dest).toNativePath();
|
||||
source = Path(source).toNativePath();
|
||||
dest = Path(dest).toNativePath();
|
||||
|
||||
var executable = 'cp';
|
||||
var args = ['-Rp', source, dest];
|
||||
|
@ -411,7 +396,7 @@ class TestUtils {
|
|||
}
|
||||
return Process.run(executable, args).then((ProcessResult result) {
|
||||
if (result.exitCode != 0) {
|
||||
throw new Exception("Failed to execute '$executable "
|
||||
throw Exception("Failed to execute '$executable "
|
||||
"${args.join(' ')}'.");
|
||||
}
|
||||
});
|
||||
|
@ -422,18 +407,18 @@ class TestUtils {
|
|||
// deleting them. Use the system tools to delete our long paths.
|
||||
// See issue 16264.
|
||||
if (Platform.operatingSystem == 'windows') {
|
||||
var native_path = new Path(path).toNativePath();
|
||||
var native_path = Path(path).toNativePath();
|
||||
// Running this in a shell sucks, but rmdir is not part of the standard
|
||||
// path.
|
||||
return Process.run('rmdir', ['/s', '/q', native_path], runInShell: true)
|
||||
.then((ProcessResult result) {
|
||||
if (result.exitCode != 0) {
|
||||
throw new Exception('Can\'t delete path $native_path. '
|
||||
throw Exception('Can\'t delete path $native_path. '
|
||||
'This path might be too long');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
var dir = new Directory(path);
|
||||
var dir = Directory(path);
|
||||
return dir.delete(recursive: true);
|
||||
}
|
||||
}
|
||||
|
@ -459,7 +444,7 @@ class TestUtils {
|
|||
}
|
||||
}
|
||||
|
||||
static final debugLogFilePath = new Path(".debug.log");
|
||||
static final debugLogFilePath = Path(".debug.log");
|
||||
|
||||
/// If test.py was invoked with '--write-results' it will write
|
||||
/// test outcomes to this file in the '--output-directory'.
|
||||
|
@ -479,10 +464,11 @@ class TestUtils {
|
|||
}
|
||||
}
|
||||
|
||||
static int shortNameCounter = 0; // Make unique short file names on Windows.
|
||||
/// Make unique short file names on Windows.
|
||||
static int shortNameCounter = 0;
|
||||
|
||||
static String getShortName(String path) {
|
||||
const pathReplacements = const {
|
||||
const pathReplacements = {
|
||||
"tests_co19_src_Language_12_Expressions_14_Function_Invocation_":
|
||||
"co19_fn_invoke_",
|
||||
"tests_co19_src_LayoutTests_fast_css_getComputedStyle_getComputedStyle-":
|
||||
|
|
|
@ -7,7 +7,7 @@ import 'package:expect/expect.dart';
|
|||
import 'package:test_runner/src/dependency_graph.dart';
|
||||
|
||||
main() {
|
||||
var graph = new Graph<int>();
|
||||
var graph = Graph<int>();
|
||||
var numberOfEvents = 0;
|
||||
var addEventAssertions = [];
|
||||
var changeEventAssertions = [];
|
||||
|
|
|
@ -6,6 +6,6 @@ import 'dart:io';
|
|||
|
||||
main(List<String> arguments) {
|
||||
var outputFile = arguments[0];
|
||||
var file = new File(outputFile);
|
||||
var file = File(outputFile);
|
||||
file.createSync();
|
||||
}
|
||||
|
|
|
@ -27,10 +27,8 @@ import 'package:test_runner/src/path.dart';
|
|||
import 'package:test_runner/src/repository.dart';
|
||||
import 'package:test_runner/src/test_case.dart';
|
||||
|
||||
/**
|
||||
* This class is reponsible for setting up the files necessary for this test
|
||||
* as well as touching a file.
|
||||
*/
|
||||
/// This class is reponsible for setting up the files necessary for this test
|
||||
/// as well as touching a file.
|
||||
class FileUtils {
|
||||
Directory tempDir;
|
||||
File testJs;
|
||||
|
@ -59,7 +57,7 @@ class FileUtils {
|
|||
}
|
||||
if (createJsDeps) {
|
||||
testJsDeps = _createFile(testJsDepsFilePath);
|
||||
var path = new Path(tempDir.path).append("test.dart").absolute;
|
||||
var path = Path(tempDir.path).append("test.dart").absolute;
|
||||
_writeToFile(testJsDeps, "file://$path");
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +69,7 @@ class FileUtils {
|
|||
if (testSnapshot != null) testSnapshot.deleteSync();
|
||||
|
||||
// if the script did run, it created this file, so we need to delete it
|
||||
File file = new File(scriptOutputPath.toNativePath());
|
||||
File file = File(scriptOutputPath.toNativePath());
|
||||
if (file.existsSync()) {
|
||||
file.deleteSync();
|
||||
}
|
||||
|
@ -80,25 +78,23 @@ class FileUtils {
|
|||
}
|
||||
|
||||
Path get scriptOutputPath {
|
||||
return new Path(tempDir.path)
|
||||
.append('created_if_command_did_run.txt')
|
||||
.absolute;
|
||||
return Path(tempDir.path).append('created_if_command_did_run.txt').absolute;
|
||||
}
|
||||
|
||||
Path get testDartFilePath {
|
||||
return new Path(tempDir.path).append('test.dart').absolute;
|
||||
return Path(tempDir.path).append('test.dart').absolute;
|
||||
}
|
||||
|
||||
Path get testJsFilePath {
|
||||
return new Path(tempDir.path).append('test.js').absolute;
|
||||
return Path(tempDir.path).append('test.js').absolute;
|
||||
}
|
||||
|
||||
Path get testJsDepsFilePath {
|
||||
return new Path(tempDir.path).append('test.js.deps').absolute;
|
||||
return Path(tempDir.path).append('test.js.deps').absolute;
|
||||
}
|
||||
|
||||
Path get testSnapshotFilePath {
|
||||
return new Path(tempDir.path).append('test_dart2js.snapshot').absolute;
|
||||
return Path(tempDir.path).append('test_dart2js.snapshot').absolute;
|
||||
}
|
||||
|
||||
void touchFile(File file) {
|
||||
|
@ -107,8 +103,8 @@ class FileUtils {
|
|||
|
||||
void _writeToFile(File file, String content) {
|
||||
if (content != null) {
|
||||
var fd = new File(file.resolveSymbolicLinksSync())
|
||||
.openSync(mode: FileMode.write);
|
||||
var fd =
|
||||
File(file.resolveSymbolicLinksSync()).openSync(mode: FileMode.write);
|
||||
fd.writeStringSync(content);
|
||||
fd.closeSync();
|
||||
}
|
||||
|
@ -119,7 +115,7 @@ class FileUtils {
|
|||
}
|
||||
|
||||
File _createFile(Path path) {
|
||||
var file = new File(path.toNativePath());
|
||||
var file = File(path.toNativePath());
|
||||
file.createSync();
|
||||
return file;
|
||||
}
|
||||
|
@ -137,10 +133,10 @@ class CommandCompletedHandler {
|
|||
if (_shouldHaveRun) {
|
||||
Expect.equals(0, output.stdout.length);
|
||||
Expect.isTrue(
|
||||
new File(fileUtils.scriptOutputPath.toNativePath()).existsSync());
|
||||
File(fileUtils.scriptOutputPath.toNativePath()).existsSync());
|
||||
} else {
|
||||
Expect.isFalse(
|
||||
new File(fileUtils.scriptOutputPath.toNativePath()).existsSync());
|
||||
File(fileUtils.scriptOutputPath.toNativePath()).existsSync());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,37 +160,37 @@ void main() {
|
|||
// This script is in [sdk]/pkg/test_runner/test.
|
||||
Repository.uri = Platform.script.resolve('../../..');
|
||||
|
||||
var fs_noTestJs = new FileUtils(
|
||||
var fs_noTestJs = FileUtils(
|
||||
createJs: false,
|
||||
createJsDeps: true,
|
||||
createDart: true,
|
||||
createSnapshot: true);
|
||||
var fs_noTestJsDeps = new FileUtils(
|
||||
var fs_noTestJsDeps = FileUtils(
|
||||
createJs: true,
|
||||
createJsDeps: false,
|
||||
createDart: true,
|
||||
createSnapshot: true);
|
||||
var fs_noTestDart = new FileUtils(
|
||||
var fs_noTestDart = FileUtils(
|
||||
createJs: true,
|
||||
createJsDeps: true,
|
||||
createDart: false,
|
||||
createSnapshot: true);
|
||||
var fs_noTestSnapshot = new FileUtils(
|
||||
var fs_noTestSnapshot = FileUtils(
|
||||
createJs: true,
|
||||
createJsDeps: true,
|
||||
createDart: true,
|
||||
createSnapshot: false);
|
||||
var fs_notUpToDate_snapshot = new FileUtils(
|
||||
var fs_notUpToDate_snapshot = FileUtils(
|
||||
createJs: true,
|
||||
createJsDeps: true,
|
||||
createDart: true,
|
||||
createSnapshot: true);
|
||||
var fs_notUpToDate_dart = new FileUtils(
|
||||
var fs_notUpToDate_dart = FileUtils(
|
||||
createJs: true,
|
||||
createJsDeps: true,
|
||||
createDart: true,
|
||||
createSnapshot: true);
|
||||
var fs_upToDate = new FileUtils(
|
||||
var fs_upToDate = FileUtils(
|
||||
createJs: true,
|
||||
createJsDeps: true,
|
||||
createDart: true,
|
||||
|
@ -215,9 +211,9 @@ void main() {
|
|||
fs_upToDate.touchFile(fs_upToDate.testJs);
|
||||
|
||||
Future runTest(String name, FileUtils fileUtils, bool shouldRun) {
|
||||
var completedHandler = new CommandCompletedHandler(fileUtils, shouldRun);
|
||||
var completedHandler = CommandCompletedHandler(fileUtils, shouldRun);
|
||||
var command = makeCompilationCommand(name, fileUtils) as ProcessCommand;
|
||||
var process = new RunningProcess(command, 60);
|
||||
var process = RunningProcess(command, 60);
|
||||
return process.run().then((CommandOutput output) {
|
||||
completedHandler.processCompletedTest(output);
|
||||
});
|
||||
|
@ -250,5 +246,5 @@ void main() {
|
|||
|
||||
// We need to wait some time to make sure that the files we 'touch' get a
|
||||
// bigger timestamp than the old ones
|
||||
new Timer(new Duration(seconds: 1), touchFilesAndRunTests);
|
||||
Timer(Duration(seconds: 1), touchFilesAndRunTests);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import "package:status_file/expectation.dart";
|
|||
import "package:test_runner/src/command.dart";
|
||||
import "package:test_runner/src/configuration.dart";
|
||||
import "package:test_runner/src/options.dart";
|
||||
import "package:test_runner/src/process_queue.dart";
|
||||
import "package:test_runner/src/repository.dart";
|
||||
import "package:test_runner/src/test_case.dart";
|
||||
import "package:test_runner/src/test_suite.dart";
|
||||
|
@ -41,10 +42,8 @@ class TestController {
|
|||
numCompletedTests++;
|
||||
if (testCase.displayName == "fail-unexpected") {
|
||||
if (!testCase.unexpectedOutput) {
|
||||
var stdout =
|
||||
new String.fromCharCodes(testCase.lastCommandOutput.stdout);
|
||||
var stderr =
|
||||
new String.fromCharCodes(testCase.lastCommandOutput.stderr);
|
||||
var stdout = String.fromCharCodes(testCase.lastCommandOutput.stdout);
|
||||
var stderr = String.fromCharCodes(testCase.lastCommandOutput.stderr);
|
||||
print("stdout = [$stdout]");
|
||||
print("stderr = [$stderr]");
|
||||
throw "Test case ${testCase.displayName} passed unexpectedly, "
|
||||
|
@ -52,10 +51,8 @@ class TestController {
|
|||
}
|
||||
} else {
|
||||
if (testCase.unexpectedOutput) {
|
||||
var stdout =
|
||||
new String.fromCharCodes(testCase.lastCommandOutput.stdout);
|
||||
var stderr =
|
||||
new String.fromCharCodes(testCase.lastCommandOutput.stderr);
|
||||
var stdout = String.fromCharCodes(testCase.lastCommandOutput.stdout);
|
||||
var stderr = String.fromCharCodes(testCase.lastCommandOutput.stderr);
|
||||
print("stdout = [$stdout]");
|
||||
print("stderr = [$stderr]");
|
||||
throw "Test case ${testCase.displayName} failed, "
|
||||
|
@ -121,24 +118,18 @@ class CustomTestSuite extends TestSuite {
|
|||
|
||||
TestCase _makeTestCase(String name, timeout, Command command,
|
||||
Iterable<Expectation> expectations) {
|
||||
var configuration = new OptionsParser().parse(['--timeout', '$timeout'])[0];
|
||||
return new TestCase(name, [command], configuration,
|
||||
new Set<Expectation>.from(expectations));
|
||||
var configuration = OptionsParser().parse(['--timeout', '$timeout'])[0];
|
||||
return TestCase(
|
||||
name, [command], configuration, Set<Expectation>.from(expectations));
|
||||
}
|
||||
}
|
||||
|
||||
void testProcessQueue() {
|
||||
var maxProcesses = 2;
|
||||
var maxBrowserProcesses = maxProcesses;
|
||||
var config = new OptionsParser().parse(['--noBatch'])[0];
|
||||
new ProcessQueue(
|
||||
config,
|
||||
maxProcesses,
|
||||
maxBrowserProcesses,
|
||||
new DateTime.now(),
|
||||
[new CustomTestSuite(config)],
|
||||
[new EventListener()],
|
||||
TestController.finished);
|
||||
var config = OptionsParser().parse(['--noBatch'])[0];
|
||||
ProcessQueue(config, maxProcesses, maxBrowserProcesses, DateTime.now(),
|
||||
[CustomTestSuite(config)], [EventListener()], TestController.finished);
|
||||
}
|
||||
|
||||
class EventListener extends progress.EventListener {
|
||||
|
@ -165,7 +156,7 @@ void main(List<String> arguments) {
|
|||
break;
|
||||
case 'timeout':
|
||||
// This process should be killed by the test after DEFAULT_TIMEOUT
|
||||
new Timer(new Duration(hours: 42), () {});
|
||||
Timer(Duration(hours: 42), () {});
|
||||
break;
|
||||
default:
|
||||
throw "Unknown option ${arguments[0]} passed to test_runner_test";
|
||||
|
@ -183,7 +174,7 @@ String getProcessTestFileName() {
|
|||
var extension = getPlatformExecutableExtension();
|
||||
var executable = Platform.executable;
|
||||
var dirIndex = executable.lastIndexOf('dart');
|
||||
var buffer = new StringBuffer(executable.substring(0, dirIndex));
|
||||
var buffer = StringBuffer(executable.substring(0, dirIndex));
|
||||
buffer.write('process_test$extension');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
|
|
@ -15,32 +15,20 @@ import 'package:test_runner/src/configuration.dart';
|
|||
import 'package:test_runner/src/options.dart';
|
||||
import 'package:test_runner/src/test_configurations.dart';
|
||||
|
||||
const List<String> COMMON_ARGUMENTS = const <String>[
|
||||
const List<String> _commonArguments = <String>[
|
||||
'--report',
|
||||
'--progress=diff',
|
||||
'co19'
|
||||
];
|
||||
|
||||
const List<List<String>> COMMAND_LINES = const <List<String>>[
|
||||
const <String>['-mrelease,debug', '-rvm', '-cnone'],
|
||||
const <String>['-mrelease,debug', '-rvm', '-cnone', '--checked'],
|
||||
const <String>['-mrelease', '-rnone', '-cdart2analyzer'],
|
||||
const <String>['-mrelease', '-rd8', '-cdart2js', '--use-sdk'],
|
||||
const <String>[
|
||||
'-mrelease',
|
||||
'-rd8,jsshell',
|
||||
'-cdart2js',
|
||||
'--use-sdk',
|
||||
'--minified'
|
||||
],
|
||||
const <String>[
|
||||
'-mrelease',
|
||||
'-rd8,jsshell',
|
||||
'-cdart2js',
|
||||
'--use-sdk',
|
||||
'--checked'
|
||||
],
|
||||
const <String>[
|
||||
const List<List<String>> _commandLines = <List<String>>[
|
||||
<String>['-mrelease,debug', '-rvm', '-cnone'],
|
||||
<String>['-mrelease,debug', '-rvm', '-cnone', '--checked'],
|
||||
<String>['-mrelease', '-rnone', '-cdart2analyzer'],
|
||||
<String>['-mrelease', '-rd8', '-cdart2js', '--use-sdk'],
|
||||
<String>['-mrelease', '-rd8,jsshell', '-cdart2js', '--use-sdk', '--minified'],
|
||||
<String>['-mrelease', '-rd8,jsshell', '-cdart2js', '--use-sdk', '--checked'],
|
||||
<String>[
|
||||
'-mrelease',
|
||||
'-rd8,jsshell',
|
||||
'-cdart2js',
|
||||
|
@ -51,17 +39,17 @@ const List<List<String>> COMMAND_LINES = const <List<String>>[
|
|||
];
|
||||
|
||||
void main(List<String> args) {
|
||||
var optionsParser = new OptionsParser();
|
||||
var optionsParser = OptionsParser();
|
||||
var configurations = <TestConfiguration>[];
|
||||
for (var commandLine in COMMAND_LINES) {
|
||||
for (var commandLine in _commandLines) {
|
||||
var arguments = <String>[];
|
||||
arguments.addAll(COMMON_ARGUMENTS);
|
||||
arguments.addAll(_commonArguments);
|
||||
arguments.addAll(args);
|
||||
arguments.addAll(commandLine);
|
||||
configurations.addAll(optionsParser.parse(arguments));
|
||||
}
|
||||
|
||||
if (configurations != null || configurations.length > 0) {
|
||||
if (configurations != null || configurations.isNotEmpty) {
|
||||
testConfigurations(configurations);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue