| Index: utils/tests/pub/test_pub.dart
|
| diff --git a/utils/tests/pub/test_pub.dart b/utils/tests/pub/test_pub.dart
|
| deleted file mode 100644
|
| index f5cb82c3841bebf3b36463419229bd949daa74ac..0000000000000000000000000000000000000000
|
| --- a/utils/tests/pub/test_pub.dart
|
| +++ /dev/null
|
| @@ -1,637 +0,0 @@
|
| -// 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.
|
| -
|
| -/// Test infrastructure for testing pub. Unlike typical unit tests, most pub
|
| -/// tests are integration tests that stage some stuff on the file system, run
|
| -/// pub, and then validate the results. This library provides an API to build
|
| -/// tests like that.
|
| -library test_pub;
|
| -
|
| -import 'dart:async';
|
| -import 'dart:collection' show Queue;
|
| -import 'dart:io' hide sleep;
|
| -import 'dart:json' as json;
|
| -import 'dart:math';
|
| -import 'dart:uri';
|
| -import 'dart:utf';
|
| -
|
| -import 'package:http/testing.dart';
|
| -import 'package:oauth2/oauth2.dart' as oauth2;
|
| -import 'package:pathos/path.dart' as path;
|
| -import 'package:scheduled_test/scheduled_process.dart';
|
| -import 'package:scheduled_test/scheduled_server.dart';
|
| -import 'package:scheduled_test/scheduled_test.dart';
|
| -import 'package:yaml/yaml.dart';
|
| -
|
| -import '../../pub/entrypoint.dart';
|
| -// TODO(rnystrom): Using "gitlib" as the prefix here is ugly, but "git" collides
|
| -// with the git descriptor method. Maybe we should try to clean up the top level
|
| -// scope a bit?
|
| -import '../../pub/git.dart' as gitlib;
|
| -import '../../pub/git_source.dart';
|
| -import '../../pub/hosted_source.dart';
|
| -import '../../pub/http.dart';
|
| -import '../../pub/io.dart';
|
| -import '../../pub/path_source.dart';
|
| -import '../../pub/safe_http_server.dart';
|
| -import '../../pub/system_cache.dart';
|
| -import '../../pub/utils.dart';
|
| -import '../../pub/validator.dart';
|
| -import 'command_line_config.dart';
|
| -import 'descriptor.dart' as d;
|
| -
|
| -/// This should be called at the top of a test file to set up an appropriate
|
| -/// test configuration for the machine running the tests.
|
| -initConfig() {
|
| - // If we aren't running on the bots, use the human-friendly config.
|
| - if (!runningOnBuildbot) {
|
| - unittestConfiguration = new CommandLineConfiguration();
|
| - }
|
| -}
|
| -
|
| -/// Returns whether we're running on a Dart build bot.
|
| -bool get runningOnBuildbot =>
|
| - Platform.environment.containsKey('BUILDBOT_BUILDERNAME');
|
| -
|
| -/// The current [HttpServer] created using [serve].
|
| -var _server;
|
| -
|
| -/// The list of paths that have been requested from the server since the last
|
| -/// call to [getRequestedPaths].
|
| -final _requestedPaths = <String>[];
|
| -
|
| -/// The cached value for [_portCompleter].
|
| -Completer<int> _portCompleterCache;
|
| -
|
| -/// The completer for [port].
|
| -Completer<int> get _portCompleter {
|
| - if (_portCompleterCache != null) return _portCompleterCache;
|
| - _portCompleterCache = new Completer<int>();
|
| - currentSchedule.onComplete.schedule(() {
|
| - _portCompleterCache = null;
|
| - }, 'clearing the port completer');
|
| - return _portCompleterCache;
|
| -}
|
| -
|
| -/// A future that will complete to the port used for the current server.
|
| -Future<int> get port => _portCompleter.future;
|
| -
|
| -/// Gets the list of paths that have been requested from the server since the
|
| -/// last time this was called (or since the server was first spun up).
|
| -Future<List<String>> getRequestedPaths() {
|
| - return schedule(() {
|
| - var paths = _requestedPaths.toList();
|
| - _requestedPaths.clear();
|
| - return paths;
|
| - });
|
| -}
|
| -
|
| -/// Creates an HTTP server to serve [contents] as static files. This server will
|
| -/// exist only for the duration of the pub run.
|
| -///
|
| -/// Subsequent calls to [serve] will replace the previous server.
|
| -void serve([List<d.Descriptor> contents]) {
|
| - var baseDir = d.dir("serve-dir", contents);
|
| -
|
| - schedule(() {
|
| - return _closeServer().then((_) {
|
| - return SafeHttpServer.bind("127.0.0.1", 0).then((server) {
|
| - _server = server;
|
| - server.listen((request) {
|
| - var response = request.response;
|
| - try {
|
| - var path = request.uri.path.replaceFirst("/", "");
|
| -
|
| - if (_requestedPaths == null) _requestedPaths = <String>[];
|
| - _requestedPaths.add(path);
|
| -
|
| - response.persistentConnection = false;
|
| - var stream = baseDir.load(path);
|
| -
|
| - new ByteStream(stream).toBytes().then((data) {
|
| - response.statusCode = 200;
|
| - response.contentLength = data.length;
|
| - response.add(data);
|
| - response.close();
|
| - }).catchError((e) {
|
| - response.statusCode = 404;
|
| - response.contentLength = 0;
|
| - response.close();
|
| - });
|
| - } catch (e) {
|
| - currentSchedule.signalError(e);
|
| - response.statusCode = 500;
|
| - response.close();
|
| - return;
|
| - }
|
| - });
|
| - _portCompleter.complete(_server.port);
|
| - currentSchedule.onComplete.schedule(_closeServer);
|
| - return null;
|
| - });
|
| - });
|
| - }, 'starting a server serving:\n${baseDir.describe()}');
|
| -}
|
| -
|
| -/// Closes [_server]. Returns a [Future] that will complete after the [_server]
|
| -/// is closed.
|
| -Future _closeServer() {
|
| - if (_server == null) return new Future.value();
|
| - _server.close();
|
| - _server = null;
|
| - _portCompleterCache = null;
|
| - // TODO(nweiz): Remove this once issue 4155 is fixed. Pumping the event loop
|
| - // *seems* to be enough to ensure that the server is actually closed, but I'm
|
| - // putting this at 10ms to be safe.
|
| - return sleep(10);
|
| -}
|
| -
|
| -/// The [d.DirectoryDescriptor] describing the server layout of packages that
|
| -/// are being served via [servePackages]. This is `null` if [servePackages] has
|
| -/// not yet been called for this test.
|
| -d.DirectoryDescriptor _servedPackageDir;
|
| -
|
| -/// A map from package names to version numbers to YAML-serialized pubspecs for
|
| -/// those packages. This represents the packages currently being served by
|
| -/// [servePackages], and is `null` if [servePackages] has not yet been called
|
| -/// for this test.
|
| -Map<String, Map<String, String>> _servedPackages;
|
| -
|
| -/// Creates an HTTP server that replicates the structure of pub.dartlang.org.
|
| -/// [pubspecs] is a list of unserialized pubspecs representing the packages to
|
| -/// serve.
|
| -///
|
| -/// Subsequent calls to [servePackages] will add to the set of packages that
|
| -/// are being served. Previous packages will continue to be served.
|
| -void servePackages(List<Map> pubspecs) {
|
| - if (_servedPackages == null || _servedPackageDir == null) {
|
| - _servedPackages = <String, Map<String, String>>{};
|
| - _servedPackageDir = d.dir('packages', []);
|
| - serve([_servedPackageDir]);
|
| -
|
| - currentSchedule.onComplete.schedule(() {
|
| - _servedPackages = null;
|
| - _servedPackageDir = null;
|
| - }, 'cleaning up served packages');
|
| - }
|
| -
|
| - schedule(() {
|
| - return awaitObject(pubspecs).then((resolvedPubspecs) {
|
| - for (var spec in resolvedPubspecs) {
|
| - var name = spec['name'];
|
| - var version = spec['version'];
|
| - var versions = _servedPackages.putIfAbsent(
|
| - name, () => <String, String>{});
|
| - versions[version] = yaml(spec);
|
| - }
|
| -
|
| - _servedPackageDir.contents.clear();
|
| - for (var name in _servedPackages.keys) {
|
| - var versions = _servedPackages[name].keys.toList();
|
| - _servedPackageDir.contents.addAll([
|
| - d.file('$name.json', json.stringify({'versions': versions})),
|
| - d.dir(name, [
|
| - d.dir('versions', flatten(versions.map((version) {
|
| - return [
|
| - d.file('$version.yaml', _servedPackages[name][version]),
|
| - d.tar('$version.tar.gz', [
|
| - d.file('pubspec.yaml', _servedPackages[name][version]),
|
| - d.libDir(name, '$name $version')
|
| - ])
|
| - ];
|
| - })))
|
| - ])
|
| - ]);
|
| - }
|
| - });
|
| - }, 'initializing the package server');
|
| -}
|
| -
|
| -/// Converts [value] into a YAML string.
|
| -String yaml(value) => json.stringify(value);
|
| -
|
| -/// The full path to the created sandbox directory for an integration test.
|
| -String get sandboxDir => _sandboxDir;
|
| -String _sandboxDir;
|
| -
|
| -/// The path of the package cache directory used for tests. Relative to the
|
| -/// sandbox directory.
|
| -final String cachePath = "cache";
|
| -
|
| -/// The path of the mock SDK directory used for tests. Relative to the sandbox
|
| -/// directory.
|
| -final String sdkPath = "sdk";
|
| -
|
| -/// The path of the mock app directory used for tests. Relative to the sandbox
|
| -/// directory.
|
| -final String appPath = "myapp";
|
| -
|
| -/// The path of the packages directory in the mock app used for tests. Relative
|
| -/// to the sandbox directory.
|
| -final String packagesPath = "$appPath/packages";
|
| -
|
| -/// Set to true when the current batch of scheduled events should be aborted.
|
| -bool _abortScheduled = false;
|
| -
|
| -/// Defines an integration test. The [body] should schedule a series of
|
| -/// operations which will be run asynchronously.
|
| -void integration(String description, void body()) =>
|
| - _integration(description, body, test);
|
| -
|
| -/// Like [integration], but causes only this test to run.
|
| -void solo_integration(String description, void body()) =>
|
| - _integration(description, body, solo_test);
|
| -
|
| -void _integration(String description, void body(), [Function testFn]) {
|
| - testFn(description, () {
|
| - // The windows bots are very slow, so we increase the default timeout.
|
| - if (Platform.operatingSystem == "windows") {
|
| - currentSchedule.timeout = new Duration(seconds: 10);
|
| - }
|
| -
|
| - // By default, don't capture stack traces since they slow the tests way
|
| - // down. To debug failing tests, comment this out.
|
| - currentSchedule.captureStackTraces =
|
| - new Options().arguments.contains('--trace');
|
| -
|
| - // Ensure the SDK version is always available.
|
| - d.dir(sdkPath, [
|
| - d.file('version', '0.1.2.3')
|
| - ]).create();
|
| -
|
| - _sandboxDir = createTempDir();
|
| - d.defaultRoot = sandboxDir;
|
| - currentSchedule.onComplete.schedule(() => deleteEntry(_sandboxDir),
|
| - 'deleting the sandbox directory');
|
| -
|
| - // Schedule the test.
|
| - body();
|
| - });
|
| -}
|
| -
|
| -/// Get the path to the root "util/test/pub" directory containing the pub
|
| -/// tests.
|
| -String get testDirectory {
|
| - var dir = new Options().script;
|
| - while (path.basename(dir) != 'pub') dir = path.dirname(dir);
|
| -
|
| - return path.absolute(dir);
|
| -}
|
| -
|
| -/// Schedules renaming (moving) the directory at [from] to [to], both of which
|
| -/// are assumed to be relative to [sandboxDir].
|
| -void scheduleRename(String from, String to) {
|
| - schedule(
|
| - () => renameDir(
|
| - path.join(sandboxDir, from),
|
| - path.join(sandboxDir, to)),
|
| - 'renaming $from to $to');
|
| -}
|
| -
|
| -/// Schedules creating a symlink at path [symlink] that points to [target],
|
| -/// both of which are assumed to be relative to [sandboxDir].
|
| -void scheduleSymlink(String target, String symlink) {
|
| - schedule(
|
| - () => createSymlink(
|
| - path.join(sandboxDir, target),
|
| - path.join(sandboxDir, symlink)),
|
| - 'symlinking $target to $symlink');
|
| -}
|
| -
|
| -/// Schedules a call to the Pub command-line utility. Runs Pub with [args] and
|
| -/// validates that its results match [output], [error], and [exitCode].
|
| -void schedulePub({List args, Pattern output, Pattern error,
|
| - Future<Uri> tokenEndpoint, int exitCode: 0}) {
|
| - var pub = startPub(args: args, tokenEndpoint: tokenEndpoint);
|
| - pub.shouldExit(exitCode);
|
| -
|
| - expect(Future.wait([
|
| - pub.remainingStdout(),
|
| - pub.remainingStderr()
|
| - ]).then((results) {
|
| - var failures = [];
|
| - _validateOutput(failures, 'stdout', output, results[0].split('\n'));
|
| - _validateOutput(failures, 'stderr', error, results[1].split('\n'));
|
| - if (!failures.isEmpty) throw new TestFailure(failures.join('\n'));
|
| - }), completes);
|
| -}
|
| -
|
| -/// Like [startPub], but runs `pub lish` in particular with [server] used both
|
| -/// as the OAuth2 server (with "/token" as the token endpoint) and as the
|
| -/// package server.
|
| -///
|
| -/// Any futures in [args] will be resolved before the process is started.
|
| -ScheduledProcess startPublish(ScheduledServer server, {List args}) {
|
| - var tokenEndpoint = server.url.then((url) =>
|
| - url.resolve('/token').toString());
|
| - if (args == null) args = [];
|
| - args = flatten(['lish', '--server', tokenEndpoint, args]);
|
| - return startPub(args: args, tokenEndpoint: tokenEndpoint);
|
| -}
|
| -
|
| -/// Handles the beginning confirmation process for uploading a packages.
|
| -/// Ensures that the right output is shown and then enters "y" to confirm the
|
| -/// upload.
|
| -void confirmPublish(ScheduledProcess pub) {
|
| - // TODO(rnystrom): This is overly specific and inflexible regarding different
|
| - // test packages. Should validate this a little more loosely.
|
| - expect(pub.nextLine(), completion(equals('Publishing "test_pkg" 1.0.0:')));
|
| - expect(pub.nextLine(), completion(equals("|-- LICENSE")));
|
| - expect(pub.nextLine(), completion(equals("|-- lib")));
|
| - expect(pub.nextLine(), completion(equals("| '-- test_pkg.dart")));
|
| - expect(pub.nextLine(), completion(equals("'-- pubspec.yaml")));
|
| - expect(pub.nextLine(), completion(equals("")));
|
| -
|
| - pub.writeLine("y");
|
| -}
|
| -
|
| -/// Starts a Pub process and returns a [ScheduledProcess] that supports
|
| -/// interaction with that process.
|
| -///
|
| -/// Any futures in [args] will be resolved before the process is started.
|
| -ScheduledProcess startPub({List args, Future<Uri> tokenEndpoint}) {
|
| - String pathInSandbox(String relPath) {
|
| - return path.join(path.absolute(sandboxDir), relPath);
|
| - }
|
| -
|
| - ensureDir(pathInSandbox(appPath));
|
| -
|
| - // Find a Dart executable we can use to spawn. Use the same one that was
|
| - // used to run this script itself.
|
| - var dartBin = new Options().executable;
|
| -
|
| - // If the executable looks like a path, get its full path. That way we
|
| - // can still find it when we spawn it with a different working directory.
|
| - if (dartBin.contains(Platform.pathSeparator)) {
|
| - dartBin = new File(dartBin).fullPathSync();
|
| - }
|
| -
|
| - // Find the main pub entrypoint.
|
| - var pubPath = path.join(testDirectory, '..', '..', 'pub', 'pub.dart');
|
| -
|
| - var dartArgs = ['--package-root=$_packageRoot/', '--checked', pubPath,
|
| - '--trace'];
|
| - dartArgs.addAll(args);
|
| -
|
| - if (tokenEndpoint == null) tokenEndpoint = new Future.value();
|
| - var optionsFuture = tokenEndpoint.then((tokenEndpoint) {
|
| - var options = new ProcessOptions();
|
| - options.workingDirectory = pathInSandbox(appPath);
|
| - // TODO(nweiz): remove this when issue 9294 is fixed.
|
| - options.environment = new Map.from(Platform.environment);
|
| - options.environment['PUB_CACHE'] = pathInSandbox(cachePath);
|
| - options.environment['DART_SDK'] = pathInSandbox(sdkPath);
|
| - if (tokenEndpoint != null) {
|
| - options.environment['_PUB_TEST_TOKEN_ENDPOINT'] =
|
| - tokenEndpoint.toString();
|
| - }
|
| - return options;
|
| - });
|
| -
|
| - return new ScheduledProcess.start(dartBin, dartArgs, options: optionsFuture,
|
| - description: args.isEmpty ? 'pub' : 'pub ${args.first}');
|
| -}
|
| -
|
| -/// Whether pub is running from within the Dart SDK, as opposed to from the Dart
|
| -/// source repository.
|
| -bool get _runningFromSdk => path.dirname(relativeToPub('..')) == 'util';
|
| -
|
| -// TODO(nweiz): use the built-in mechanism for accessing this once it exists
|
| -// (issue 9119).
|
| -/// The path to the `packages` directory from which pub loads its dependencies.
|
| -String get _packageRoot {
|
| - if (_runningFromSdk) {
|
| - return path.absolute(relativeToPub(path.join('..', '..', 'packages')));
|
| - } else {
|
| - return path.absolute(path.join(
|
| - path.dirname(new Options().executable), '..', '..', 'packages'));
|
| - }
|
| -}
|
| -
|
| -/// Skips the current test if Git is not installed. This validates that the
|
| -/// current test is running on a buildbot in which case we expect git to be
|
| -/// installed. If we are not running on the buildbot, we will instead see if
|
| -/// git is installed and skip the test if not. This way, users don't need to
|
| -/// have git installed to run the tests locally (unless they actually care
|
| -/// about the pub git tests).
|
| -///
|
| -/// This will also increase the [Schedule] timeout to 30 seconds on Windows,
|
| -/// where Git runs really slowly.
|
| -void ensureGit() {
|
| - if (Platform.operatingSystem == "windows") {
|
| - currentSchedule.timeout = new Duration(seconds: 30);
|
| - }
|
| -
|
| - schedule(() {
|
| - return gitlib.isInstalled.then((installed) {
|
| - if (installed) return;
|
| - if (runningOnBuildbot) return;
|
| - currentSchedule.abort();
|
| - });
|
| - }, 'ensuring that Git is installed');
|
| -}
|
| -
|
| -/// Use [client] as the mock HTTP client for this test.
|
| -///
|
| -/// Note that this will only affect HTTP requests made via http.dart in the
|
| -/// parent process.
|
| -void useMockClient(MockClient client) {
|
| - var oldInnerClient = httpClient.inner;
|
| - httpClient.inner = client;
|
| - currentSchedule.onComplete.schedule(() {
|
| - httpClient.inner = oldInnerClient;
|
| - }, 'de-activating the mock client');
|
| -}
|
| -
|
| -/// Describes a map representing a library package with the given [name],
|
| -/// [version], and [dependencies].
|
| -Map packageMap(String name, String version, [List dependencies]) {
|
| - var package = {
|
| - "name": name,
|
| - "version": version,
|
| - "author": "Nathan Weizenbaum <nweiz@google.com>",
|
| - "homepage": "http://pub.dartlang.org",
|
| - "description": "A package, I guess."
|
| - };
|
| - if (dependencies != null) {
|
| - package["dependencies"] = dependencyListToMap(dependencies);
|
| - }
|
| - return package;
|
| -}
|
| -
|
| -/// Describes a map representing a dependency on a package in the package
|
| -/// repository.
|
| -Map dependencyMap(String name, [String versionConstraint]) {
|
| - var url = port.then((p) => "http://localhost:$p");
|
| - var dependency = {"hosted": {"name": name, "url": url}};
|
| - if (versionConstraint != null) dependency["version"] = versionConstraint;
|
| - return dependency;
|
| -}
|
| -
|
| -/// Converts a list of dependencies as passed to [package] into a hash as used
|
| -/// in a pubspec.
|
| -Future<Map> dependencyListToMap(List<Map> dependencies) {
|
| - return awaitObject(dependencies).then((resolvedDependencies) {
|
| - var result = <String, Map>{};
|
| - for (var dependency in resolvedDependencies) {
|
| - var keys = dependency.keys.where((key) => key != "version");
|
| - var sourceName = only(keys);
|
| - var source;
|
| - switch (sourceName) {
|
| - case "git":
|
| - source = new GitSource();
|
| - break;
|
| - case "hosted":
|
| - source = new HostedSource();
|
| - break;
|
| - case "path":
|
| - source = new PathSource();
|
| - break;
|
| - default:
|
| - throw new Exception('Unknown source "$sourceName"');
|
| - }
|
| -
|
| - result[_packageName(sourceName, dependency[sourceName])] = dependency;
|
| - }
|
| - return result;
|
| - });
|
| -}
|
| -
|
| -/// Return the name for the package described by [description] and from
|
| -/// [sourceName].
|
| -String _packageName(String sourceName, description) {
|
| - switch (sourceName) {
|
| - case "git":
|
| - var url = description is String ? description : description['url'];
|
| - // TODO(rnystrom): Using path.basename on a URL is hacky. If we add URL
|
| - // support to pkg/pathos, should use an explicit builder for that.
|
| - return path.basename(url.replaceFirst(new RegExp(r"(\.git)?/?$"), ""));
|
| - case "hosted":
|
| - if (description is String) return description;
|
| - return description['name'];
|
| - case "path":
|
| - return path.basename(description);
|
| - case "sdk":
|
| - return description;
|
| - default:
|
| - return description;
|
| - }
|
| -}
|
| -
|
| -/// Compares the [actual] output from running pub with [expected]. For [String]
|
| -/// patterns, ignores leading and trailing whitespace differences and tries to
|
| -/// report the offending difference in a nice way. For other [Pattern]s, just
|
| -/// reports whether the output contained the pattern.
|
| -void _validateOutput(List<String> failures, String pipe, Pattern expected,
|
| - List<String> actual) {
|
| - if (expected == null) return;
|
| -
|
| - if (expected is RegExp) {
|
| - _validateOutputRegex(failures, pipe, expected, actual);
|
| - } else {
|
| - _validateOutputString(failures, pipe, expected, actual);
|
| - }
|
| -}
|
| -
|
| -void _validateOutputRegex(List<String> failures, String pipe,
|
| - RegExp expected, List<String> actual) {
|
| - var actualText = actual.join('\n');
|
| - if (actualText.contains(expected)) return;
|
| -
|
| - if (actual.length == 0) {
|
| - failures.add('Expected $pipe to match "${expected.pattern}" but got none.');
|
| - } else {
|
| - failures.add('Expected $pipe to match "${expected.pattern}" but got:');
|
| - failures.addAll(actual.map((line) => '| $line'));
|
| - }
|
| -}
|
| -
|
| -void _validateOutputString(List<String> failures, String pipe,
|
| - String expectedText, List<String> actual) {
|
| - final expected = expectedText.split('\n');
|
| -
|
| - // Strip off the last line. This lets us have expected multiline strings
|
| - // where the closing ''' is on its own line. It also fixes '' expected output
|
| - // to expect zero lines of output, not a single empty line.
|
| - if (expected.last.trim() == '') {
|
| - expected.removeLast();
|
| - }
|
| -
|
| - var results = [];
|
| - var failed = false;
|
| -
|
| - // Compare them line by line to see which ones match.
|
| - var length = max(expected.length, actual.length);
|
| - for (var i = 0; i < length; i++) {
|
| - if (i >= actual.length) {
|
| - // Missing output.
|
| - failed = true;
|
| - results.add('? ${expected[i]}');
|
| - } else if (i >= expected.length) {
|
| - // Unexpected extra output.
|
| - failed = true;
|
| - results.add('X ${actual[i]}');
|
| - } else {
|
| - var expectedLine = expected[i].trim();
|
| - var actualLine = actual[i].trim();
|
| -
|
| - if (expectedLine != actualLine) {
|
| - // Mismatched lines.
|
| - failed = true;
|
| - results.add('X ${actual[i]}');
|
| - } else {
|
| - // Output is OK, but include it in case other lines are wrong.
|
| - results.add('| ${actual[i]}');
|
| - }
|
| - }
|
| - }
|
| -
|
| - // If any lines mismatched, show the expected and actual.
|
| - if (failed) {
|
| - failures.add('Expected $pipe:');
|
| - failures.addAll(expected.map((line) => '| $line'));
|
| - failures.add('Got:');
|
| - failures.addAll(results);
|
| - }
|
| -}
|
| -
|
| -/// A function that creates a [Validator] subclass.
|
| -typedef Validator ValidatorCreator(Entrypoint entrypoint);
|
| -
|
| -/// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled
|
| -/// Future that contains the errors and warnings produced by that validator.
|
| -Future<Pair<List<String>, List<String>>> schedulePackageValidation(
|
| - ValidatorCreator fn) {
|
| - return schedule(() {
|
| - var cache = new SystemCache.withSources(path.join(sandboxDir, cachePath));
|
| -
|
| - return new Future.sync(() {
|
| - var validator = fn(new Entrypoint(path.join(sandboxDir, appPath), cache));
|
| - return validator.validate().then((_) {
|
| - return new Pair(validator.errors, validator.warnings);
|
| - });
|
| - });
|
| - }, "validating package");
|
| -}
|
| -
|
| -/// A matcher that matches a Pair.
|
| -Matcher pairOf(Matcher firstMatcher, Matcher lastMatcher) =>
|
| - new _PairMatcher(firstMatcher, lastMatcher);
|
| -
|
| -class _PairMatcher extends BaseMatcher {
|
| - final Matcher _firstMatcher;
|
| - final Matcher _lastMatcher;
|
| -
|
| - _PairMatcher(this._firstMatcher, this._lastMatcher);
|
| -
|
| - bool matches(item, MatchState matchState) {
|
| - if (item is! Pair) return false;
|
| - return _firstMatcher.matches(item.first, matchState) &&
|
| - _lastMatcher.matches(item.last, matchState);
|
| - }
|
| -
|
| - Description describe(Description description) {
|
| - description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]);
|
| - }
|
| -}
|
|
|