blob: 5cf6ece29573b458aa8073ba304ccd358d52c601 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library test.test.io;
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:test/src/util/io.dart';
import 'package:test/src/utils.dart';
/// The path to the root directory of the `test` package.
final String packageDir = p.dirname(p.dirname(libraryPath(#test.test.io)));
/// The path to the `pub` executable in the current Dart SDK.
final _pubPath = p.absolute(p.join(
p.dirname(Platform.executable),
Platform.isWindows ? 'pub.bat' : 'pub'));
/// The platform-specific message emitted when a nonexistent file is loaded.
final String noSuchFileMessage = Platform.isWindows
? "The system cannot find the file specified."
: "No such file or directory";
/// A decoder that converts raw bytes to a line-by-line stream.
final _lines = UTF8.decoder.fuse(const LineSplitter());
/// A regular expression that matches the output of "pub serve".
final _servingRegExp =
new RegExp(r'^Serving myapp [a-z]+ on http://localhost:(\d+)$');
/// Runs the test executable with the package root set properly.
ProcessResult runTest(List<String> args, {String workingDirectory,
Map<String, String> environment}) {
var allArgs = [
p.absolute(p.join(packageDir, 'bin/test.dart')),
"--package-root=${p.join(packageDir, 'packages')}"
]..addAll(args);
if (environment == null) environment = {};
environment.putIfAbsent("_UNITTEST_USE_COLOR", () => "false");
// TODO(nweiz): Use ScheduledProcess once it's compatible.
return runDart(allArgs, workingDirectory: workingDirectory,
environment: environment);
}
/// Runs Dart.
ProcessResult runDart(List<String> args, {String workingDirectory,
Map<String, String> environment}) {
var allArgs = Platform.executableArguments.map((arg) {
// The package root might be relative, so we need to make it absolute if
// we're going to run in a different working directory.
if (!arg.startsWith("--package-root=")) return arg;
return "--package-root=" +
p.absolute(arg.substring("--package-root=".length));
}).toList()..addAll(args);
// TODO(nweiz): Use ScheduledProcess once it's compatible.
return new _NormalizedProcessResult(Process.runSync(
p.absolute(Platform.executable), allArgs,
workingDirectory: workingDirectory, environment: environment));
}
/// Runs Pub.
ProcessResult runPub(List<String> args, {String workingDirectory,
Map<String, String> environment}) {
// TODO(nweiz): Use ScheduledProcess once it's compatible.
return new _NormalizedProcessResult(Process.runSync(
_pubPath, args,
workingDirectory: workingDirectory, environment: environment));
}
/// Starts the test executable with the package root set properly.
Future<Process> startTest(List<String> args, {String workingDirectory,
Map<String, String> environment}) {
var allArgs = [
p.absolute(p.join(packageDir, 'bin/test.dart')),
"--package-root=${p.join(packageDir, 'packages')}"
]..addAll(args);
if (environment == null) environment = {};
environment.putIfAbsent("_UNITTEST_USE_COLOR", () => "false");
return startDart(allArgs, workingDirectory: workingDirectory,
environment: environment);
}
/// Starts Dart.
Future<Process> startDart(List<String> args, {String workingDirectory,
Map<String, String> environment}) {
var allArgs = Platform.executableArguments.toList()..addAll(args);
// TODO(nweiz): Use ScheduledProcess once it's compatible.
return Process.start(Platform.executable, allArgs,
workingDirectory: workingDirectory, environment: environment);
}
/// Starts Pub.
Future<Process> startPub(List<String> args, {String workingDirectory,
Map<String, String> environment}) {
// TODO(nweiz): Use ScheduledProcess once it's compatible.
return Process.start(_pubPath, args,
workingDirectory: workingDirectory, environment: environment);
}
/// Starts "pub serve".
///
/// This returns a pair of the pub serve process and the port it's serving on.
Future<Pair<Process, int>> startPubServe({List<String> args,
String workingDirectory, Map<String, String> environment}) async {
var allArgs = ['serve', '--port', '0'];
if (args != null) allArgs.addAll(args);
var process = await startPub(allArgs,
workingDirectory: workingDirectory, environment: environment);
var line = await _lines.bind(process.stdout)
.firstWhere(_servingRegExp.hasMatch);
var match = _servingRegExp.firstMatch(line);
return new Pair(process, int.parse(match[1]));
}
/// A wrapper around [ProcessResult] that normalizes the newline format across
/// operating systems.
class _NormalizedProcessResult implements ProcessResult {
final ProcessResult _inner;
int get exitCode => _inner.exitCode;
int get pid => _inner.pid;
final String stdout;
final String stderr;
_NormalizedProcessResult(ProcessResult inner)
: _inner = inner,
stdout = Platform.isWindows
? inner.stdout.replaceAll("\r\n", "\n")
: inner.stdout,
stderr = Platform.isWindows
? inner.stderr.replaceAll("\r\n", "\n")
: inner.stderr;
}