Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Unified Diff: mojo/public/dart/third_party/test/test/utils.dart

Issue 1346773002: Stop running pub get at gclient sync time and fix build bugs (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: mojo/public/dart/third_party/test/test/utils.dart
diff --git a/mojo/public/dart/third_party/test/test/utils.dart b/mojo/public/dart/third_party/test/test/utils.dart
new file mode 100644
index 0000000000000000000000000000000000000000..5880149aaba33e24b73d15c0eea63f90b2dd8f25
--- /dev/null
+++ b/mojo/public/dart/third_party/test/test/utils.dart
@@ -0,0 +1,282 @@
+// 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.utils;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'package:test/src/backend/invoker.dart';
+import 'package:test/src/backend/live_test.dart';
+import 'package:test/src/backend/metadata.dart';
+import 'package:test/src/backend/state.dart';
+import 'package:test/src/backend/suite.dart';
+import 'package:test/src/runner/application_exception.dart';
+import 'package:test/src/runner/load_exception.dart';
+import 'package:test/src/util/remote_exception.dart';
+import 'package:test/test.dart';
+
+/// The string representation of an untyped closure with no arguments.
+///
+/// This differs between dart2js and the VM.
+final String closureString = (() {}).toString();
+
+// The last state change detected via [expectStates].
+State lastState;
+
+/// Asserts that exactly [states] will be emitted via [liveTest.onStateChange].
+///
+/// The most recent emitted state is stored in [_lastState].
+void expectStates(LiveTest liveTest, Iterable<State> statesIter) {
+ var states = new Queue.from(statesIter);
+ liveTest.onStateChange.listen(expectAsync((state) {
+ lastState = state;
+ expect(state, equals(states.removeFirst()));
+ }, count: states.length, max: states.length));
+}
+
+/// Asserts that errors will be emitted via [liveTest.onError] that match
+/// [validators], in order.
+void expectErrors(LiveTest liveTest, Iterable<Function> validatorsIter) {
+ var validators = new Queue.from(validatorsIter);
+ liveTest.onError.listen(expectAsync((error) {
+ validators.removeFirst()(error.error);
+ }, count: validators.length, max: validators.length));
+}
+
+/// Asserts that [liveTest] will have a single failure with message `"oh no"`.
+void expectSingleFailure(LiveTest liveTest) {
+ expectStates(liveTest, [
+ const State(Status.running, Result.success),
+ const State(Status.complete, Result.failure)
+ ]);
+
+ expectErrors(liveTest, [(error) {
+ expect(lastState.status, equals(Status.complete));
+ expect(error, isTestFailure("oh no"));
+ }]);
+}
+
+/// Asserts that [liveTest] will have a single error, the string `"oh no"`.
+void expectSingleError(LiveTest liveTest) {
+ expectStates(liveTest, [
+ const State(Status.running, Result.success),
+ const State(Status.complete, Result.error)
+ ]);
+
+ expectErrors(liveTest, [(error) {
+ expect(lastState.status, equals(Status.complete));
+ expect(error, equals("oh no"));
+ }]);
+}
+
+/// Returns a matcher that matches a [TestFailure] with the given [message].
+///
+/// [message] can be a string or a [Matcher].
+Matcher isTestFailure(message) => new _IsTestFailure(wrapMatcher(message));
+
+class _IsTestFailure extends Matcher {
+ final Matcher _message;
+
+ _IsTestFailure(this._message);
+
+ bool matches(item, Map matchState) =>
+ item is TestFailure && _message.matches(item.message, matchState);
+
+ Description describe(Description description) =>
+ description.add('a TestFailure with message ').addDescriptionOf(_message);
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState, bool verbose) {
+ if (item is! TestFailure) {
+ return mismatchDescription.addDescriptionOf(item)
+ .add('is not a TestFailure');
+ } else {
+ return mismatchDescription
+ .add('message ')
+ .addDescriptionOf(item.message)
+ .add(' is not ')
+ .addDescriptionOf(_message);
+ }
+ }
+}
+
+/// Returns a matcher that matches a [RemoteException] with the given [message].
+///
+/// [message] can be a string or a [Matcher].
+Matcher isRemoteException(message) =>
+ new _IsRemoteException(wrapMatcher(message));
+
+class _IsRemoteException extends Matcher {
+ final Matcher _message;
+
+ _IsRemoteException(this._message);
+
+ bool matches(item, Map matchState) =>
+ item is RemoteException && _message.matches(item.message, matchState);
+
+ Description describe(Description description) =>
+ description.add('a RemoteException with message ')
+ .addDescriptionOf(_message);
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState, bool verbose) {
+ if (item is! RemoteException) {
+ return mismatchDescription.addDescriptionOf(item)
+ .add('is not a RemoteException');
+ } else {
+ return mismatchDescription
+ .add('message ')
+ .addDescriptionOf(item)
+ .add(' is not ')
+ .addDescriptionOf(_message);
+ }
+ }
+}
+
+/// Returns a matcher that matches a [LoadException] with the given
+/// [innerError].
+///
+/// [innerError] can be a string or a [Matcher].
+Matcher isLoadException(innerError) =>
+ new _IsLoadException(wrapMatcher(innerError));
+
+class _IsLoadException extends Matcher {
+ final Matcher _innerError;
+
+ _IsLoadException(this._innerError);
+
+ bool matches(item, Map matchState) =>
+ item is LoadException && _innerError.matches(item.innerError, matchState);
+
+ Description describe(Description description) =>
+ description.add('a LoadException with message ')
+ .addDescriptionOf(_innerError);
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState, bool verbose) {
+ if (item is! LoadException) {
+ return mismatchDescription.addDescriptionOf(item)
+ .add('is not a LoadException');
+ } else {
+ return mismatchDescription
+ .add('inner error ')
+ .addDescriptionOf(item)
+ .add(' is not ')
+ .addDescriptionOf(_innerError);
+ }
+ }
+}
+
+/// Returns a matcher that matches a [ApplicationException] with the given
+/// [message].
+///
+/// [message] can be a string or a [Matcher].
+Matcher isApplicationException(message) =>
+ new _IsApplicationException(wrapMatcher(message));
+
+class _IsApplicationException extends Matcher {
+ final Matcher _message;
+
+ _IsApplicationException(this._message);
+
+ bool matches(item, Map matchState) =>
+ item is ApplicationException && _message.matches(item.message, matchState);
+
+ Description describe(Description description) =>
+ description.add('a ApplicationException with message ')
+ .addDescriptionOf(_message);
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState, bool verbose) {
+ if (item is! ApplicationException) {
+ return mismatchDescription.addDescriptionOf(item)
+ .add('is not a ApplicationException');
+ } else {
+ return mismatchDescription
+ .add('message ')
+ .addDescriptionOf(item)
+ .add(' is not ')
+ .addDescriptionOf(_message);
+ }
+ }
+}
+
+/// Returns a [Future] that completes after pumping the event queue [times]
+/// times.
+///
+/// By default, this should pump the event queue enough times to allow any code
+/// to run, as long as it's not waiting on some external event.
+Future pumpEventQueue([int times=20]) {
+ if (times == 0) return new Future.value();
+ // Use [new Future] future to allow microtask events to finish. The [new
+ // Future.value] constructor uses scheduleMicrotask itself and would therefore
+ // not wait for microtask callbacks that are scheduled after invoking this
+ // method.
+ return new Future(() => pumpEventQueue(times - 1));
+}
+
+/// Returns a local [LiveTest] that runs [body].
+LiveTest createTest(body()) {
+ var test = new LocalTest("test", new Metadata(), body);
+ var suite = new Suite([test]);
+ return test.load(suite);
+}
+
+/// Runs [body] as a test.
+///
+/// Once it completes, returns the [LiveTest] used to run it.
+Future<LiveTest> runTestBody(body()) async {
+ var liveTest = createTest(body);
+ await liveTest.run();
+ return liveTest;
+}
+
+/// Asserts that [liveTest] has completed and passed.
+///
+/// If the test had any errors, they're surfaced nicely into the outer test.
+void expectTestPassed(LiveTest liveTest) {
+ // Since the test is expected to pass, we forward any current or future errors
+ // to the outer test, because they're definitely unexpected.
+ for (var error in liveTest.errors) {
+ registerException(error.error, error.stackTrace);
+ }
+ liveTest.onError.listen((error) {
+ registerException(error.error, error.stackTrace);
+ });
+
+ expect(liveTest.state.status, equals(Status.complete));
+ expect(liveTest.state.result, equals(Result.success));
+}
+
+/// Asserts that [liveTest] failed with a single [TestFailure] whose message
+/// matches [message].
+void expectTestFailed(LiveTest liveTest, message) {
+ expect(liveTest.state.status, equals(Status.complete));
+ expect(liveTest.state.result, equals(Result.failure));
+ expect(liveTest.errors, hasLength(1));
+ expect(liveTest.errors.first.error, isTestFailure(message));
+}
+
+/// Assert that the [test] callback causes a test to block until [stopBlocking]
+/// is called at some later time.
+///
+/// [stopBlocking] is passed the return value of [test].
+Future expectTestBlocks(test(), stopBlocking(value)) async {
+ var liveTest;
+ var future;
+ liveTest = createTest(() {
+ var value = test();
+ future = pumpEventQueue().then((_) {
+ expect(liveTest.state.status, equals(Status.running));
+ stopBlocking(value);
+ });
+ });
+
+ await liveTest.run();
+ expectTestPassed(liveTest);
+ // Ensure that the outer test doesn't complete until the inner future
+ // completes.
+ return future;
+}

Powered by Google App Engine
This is Rietveld 408576698