pkg/matcher: refactored code around data-structure vs execution-based matchers
Also fixed a spelling error.
R=sigmund@google.com
Review URL: https://codereview.chromium.org//438473002
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/matcher@38807 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c18134d..8e7bd6f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.11.1+1
+
+* Refactored libraries and tests.
+
+* Fixed spelling mistake.
+
## 0.11.1
* Added `isNaN` and `isNotNaN` matchers.
diff --git a/lib/matcher.dart b/lib/matcher.dart
index 99fe44b..6fd18cc 100644
--- a/lib/matcher.dart
+++ b/lib/matcher.dart
@@ -16,3 +16,6 @@
export 'src/numeric_matchers.dart';
export 'src/operator_matchers.dart';
export 'src/string_matchers.dart';
+export 'src/throws_matcher.dart';
+export 'src/throws_matchers.dart';
+export 'src/util.dart';
diff --git a/lib/src/core_matchers.dart b/lib/src/core_matchers.dart
index f1a724a..8de3a01 100644
--- a/lib/src/core_matchers.dart
+++ b/lib/src/core_matchers.dart
@@ -4,11 +4,9 @@
library matcher.core_matchers;
-import 'dart:async';
-
import 'description.dart';
-import 'expect.dart';
import 'interfaces.dart';
+import 'util.dart';
/// Returns a matcher that matches empty strings, maps or iterables
/// (including collections).
@@ -390,36 +388,6 @@
description.add('an instance of ${_name}');
}
-/// This can be used to match two kinds of objects:
-///
-/// * A [Function] that throws an exception when called. The function cannot
-/// take any arguments. If you want to test that a function expecting
-/// arguments throws, wrap it in another zero-argument function that calls
-/// the one you want to test.
-///
-/// * A [Future] that completes with an exception. Note that this creates an
-/// asynchronous expectation. The call to `expect()` that includes this will
-/// return immediately and execution will continue. Later, when the future
-/// completes, the actual expectation will run.
-const Matcher throws = const Throws();
-
-/// This can be used to match two kinds of objects:
-///
-/// * A [Function] that throws an exception when called. The function cannot
-/// take any arguments. If you want to test that a function expecting
-/// arguments throws, wrap it in another zero-argument function that calls
-/// the one you want to test.
-///
-/// * A [Future] that completes with an exception. Note that this creates an
-/// asynchronous expectation. The call to `expect()` that includes this will
-/// return immediately and execution will continue. Later, when the future
-/// completes, the actual expectation will run.
-///
-/// In both cases, when an exception is thrown, this will test that the exception
-/// object matches [matcher]. If [matcher] is not an instance of [Matcher], it
-/// will implicitly be treated as `equals(matcher)`.
-Matcher throwsA(matcher) => new Throws(wrapMatcher(matcher));
-
/// A matcher that matches a function call against no exception.
/// The function will be called once. Any exceptions will be silently swallowed.
/// The value passed to expect() should be a reference to the function.
@@ -427,77 +395,6 @@
/// a wrapper will have to be created.
const Matcher returnsNormally = const _ReturnsNormally();
-class Throws extends Matcher {
- final Matcher _matcher;
-
- const Throws([Matcher matcher]) : this._matcher = matcher;
-
- bool matches(item, Map matchState) {
- if (item is! Function && item is! Future) return false;
- if (item is Future) {
- var done = wrapAsync((fn) => fn());
-
- // Queue up an asynchronous expectation that validates when the future
- // completes.
- item.then((value) {
- done(() {
- fail("Expected future to fail, but succeeded with '$value'.");
- });
- }, onError: (error, trace) {
- done(() {
- if (_matcher == null) return;
- var reason;
- if (trace != null) {
- var stackTrace = trace.toString();
- stackTrace = " ${stackTrace.replaceAll("\n", "\n ")}";
- reason = "Actual exception trace:\n$stackTrace";
- }
- expect(error, _matcher, reason: reason);
- });
- });
- // It hasn't failed yet.
- return true;
- }
-
- try {
- item();
- return false;
- } catch (e, s) {
- if (_matcher == null || _matcher.matches(e, matchState)) {
- return true;
- } else {
- addStateInfo(matchState, {'exception': e, 'stack': s});
- return false;
- }
- }
- }
-
- Description describe(Description description) {
- if (_matcher == null) {
- return description.add("throws");
- } else {
- return description.add('throws ').addDescriptionOf(_matcher);
- }
- }
-
- Description describeMismatch(item, Description mismatchDescription,
- Map matchState,
- bool verbose) {
- if (item is! Function && item is! Future) {
- return mismatchDescription.add('is not a Function or Future');
- } else if (_matcher == null || matchState['exception'] == null) {
- return mismatchDescription.add('did not throw');
- } else {
- mismatchDescription. add('threw ').
- addDescriptionOf(matchState['exception']);
- if (verbose) {
- mismatchDescription.add(' at ').add(matchState['stack'].toString());
- }
- return mismatchDescription;
- }
- }
-}
-
class _ReturnsNormally extends Matcher {
const _ReturnsNormally();
diff --git a/lib/src/error_matchers.dart b/lib/src/error_matchers.dart
index dca1759..fd0445c 100644
--- a/lib/src/error_matchers.dart
+++ b/lib/src/error_matchers.dart
@@ -10,9 +10,6 @@
/// A matcher for ArgumentErrors.
const Matcher isArgumentError = const _ArgumentError();
-/// A matcher for functions that throw ArgumentError.
-const Matcher throwsArgumentError = const Throws(isArgumentError);
-
class _ArgumentError extends TypeMatcher {
const _ArgumentError(): super("ArgumentError");
bool matches(item, Map matchState) => item is ArgumentError;
@@ -22,10 +19,6 @@
const Matcher isConcurrentModificationError =
const _ConcurrentModificationError();
-/// A matcher for functions that throw ConcurrentModificationError.
-const Matcher throwsConcurrentModificationError =
- const Throws(isConcurrentModificationError);
-
class _ConcurrentModificationError extends TypeMatcher {
const _ConcurrentModificationError(): super("ConcurrentModificationError");
bool matches(item, Map matchState) => item is ConcurrentModificationError;
@@ -34,10 +27,6 @@
/// A matcher for CyclicInitializationError.
const Matcher isCyclicInitializationError = const _CyclicInitializationError();
-/// A matcher for functions that throw CyclicInitializationError.
-const Matcher throwsCyclicInitializationError =
- const Throws(isCyclicInitializationError);
-
class _CyclicInitializationError extends TypeMatcher {
const _CyclicInitializationError(): super("CyclicInitializationError");
bool matches(item, Map matchState) => item is CyclicInitializationError;
@@ -46,9 +35,6 @@
/// A matcher for Exceptions.
const Matcher isException = const _Exception();
-/// A matcher for functions that throw Exception.
-const Matcher throwsException = const Throws(isException);
-
class _Exception extends TypeMatcher {
const _Exception(): super("Exception");
bool matches(item, Map matchState) => item is Exception;
@@ -62,9 +48,6 @@
/// A matcher for FormatExceptions.
const Matcher isFormatException = const _FormatException();
-/// A matcher for functions that throw FormatException.
-const Matcher throwsFormatException = const Throws(isFormatException);
-
class _FormatException extends TypeMatcher {
const _FormatException(): super("FormatException");
bool matches(item, Map matchState) => item is FormatException;
@@ -73,9 +56,6 @@
/// A matcher for NoSuchMethodErrors.
const Matcher isNoSuchMethodError = const _NoSuchMethodError();
-/// A matcher for functions that throw NoSuchMethodError.
-const Matcher throwsNoSuchMethodError = const Throws(isNoSuchMethodError);
-
class _NoSuchMethodError extends TypeMatcher {
const _NoSuchMethodError(): super("NoSuchMethodError");
bool matches(item, Map matchState) => item is NoSuchMethodError;
@@ -84,9 +64,6 @@
/// A matcher for NullThrownError.
const Matcher isNullThrownError = const _NullThrownError();
-/// A matcher for functions that throw NullThrownError.
-const Matcher throwsNullThrownError = const Throws(isNullThrownError);
-
class _NullThrownError extends TypeMatcher {
const _NullThrownError(): super("NullThrownError");
bool matches(item, Map matchState) => item is NullThrownError;
@@ -95,9 +72,6 @@
/// A matcher for RangeErrors.
const Matcher isRangeError = const _RangeError();
-/// A matcher for functions that throw RangeError.
-const Matcher throwsRangeError = const Throws(isRangeError);
-
class _RangeError extends TypeMatcher {
const _RangeError(): super("RangeError");
bool matches(item, Map matchState) => item is RangeError;
@@ -106,9 +80,6 @@
/// A matcher for StateErrors.
const Matcher isStateError = const _StateError();
-/// A matcher for functions that throw StateError.
-const Matcher throwsStateError = const Throws(isStateError);
-
class _StateError extends TypeMatcher {
const _StateError(): super("StateError");
bool matches(item, Map matchState) => item is StateError;
@@ -117,9 +88,6 @@
/// A matcher for UnimplementedErrors.
const Matcher isUnimplementedError = const _UnimplementedError();
-/// A matcher for functions that throw Exception.
-const Matcher throwsUnimplementedError = const Throws(isUnimplementedError);
-
class _UnimplementedError extends TypeMatcher {
const _UnimplementedError(): super("UnimplementedError");
bool matches(item, Map matchState) => item is UnimplementedError;
@@ -128,9 +96,6 @@
/// A matcher for UnsupportedError.
const Matcher isUnsupportedError = const _UnsupportedError();
-/// A matcher for functions that throw UnsupportedError.
-const Matcher throwsUnsupportedError = const Throws(isUnsupportedError);
-
class _UnsupportedError extends TypeMatcher {
const _UnsupportedError(): super("UnsupportedError");
bool matches(item, Map matchState) => item is UnsupportedError;
diff --git a/lib/src/expect.dart b/lib/src/expect.dart
index 073ef34..bd54747 100644
--- a/lib/src/expect.dart
+++ b/lib/src/expect.dart
@@ -7,6 +7,7 @@
import 'core_matchers.dart';
import 'description.dart';
import 'interfaces.dart';
+import 'util.dart';
/// The objects thrown by the default failure handler.
class TestFailure extends Error {
@@ -17,15 +18,33 @@
String toString() => message;
}
-/// Useful utility for nesting match states.
+/// Failed matches are reported using a default IFailureHandler.
+/// The default implementation simply throws [TestFailure]s;
+/// this can be replaced by some other implementation of
+/// IFailureHandler by calling configureExpectHandler.
+abstract class FailureHandler {
+ /// This handles failures given a textual decription
+ void fail(String reason);
-void addStateInfo(Map matchState, Map values) {
- var innerState = new Map.from(matchState);
- matchState.clear();
- matchState['state'] = innerState;
- matchState.addAll(values);
+ /// This handles failures given the actual [value], the [matcher]
+ /// the [reason] (argument from [expect]), some additonal [matchState]
+ /// generated by the [matcher], and a verbose flag which controls in
+ /// some cases how much [matchState] information is used. It will use
+ /// these to create a detailed error message (typically by calling
+ /// an [ErrorFormatter]) and then call [fail] with this message.
+ void failMatch(actual, Matcher matcher, String reason,
+ Map matchState, bool verbose);
}
+/// The ErrorFormatter type is used for functions that
+/// can be used to build up error reports upon [expect] failures.
+/// There is one built-in implementation ([defaultErrorFormatter])
+/// which is used by the default failure handler. If the failure handler
+/// is replaced it may be desirable to replace the [stringDescription]
+/// error formatter with another.
+typedef String ErrorFormatter(actual, Matcher matcher, String reason,
+ Map matchState, bool verbose);
+
/// Some matchers, like those for Futures and exception testing,
/// can fail in asynchronous sections, and throw exceptions.
/// A user of this library will typically want to catch and handle
@@ -81,20 +100,6 @@
failureHandler.fail(message);
}
-/// Takes an argument and returns an equivalent matcher.
-/// If the argument is already a matcher this does nothing,
-/// else if the argument is a function, it generates a predicate
-/// function matcher, else it generates an equals matcher.
-Matcher wrapMatcher(x) {
- if (x is Matcher) {
- return x;
- } else if (x is Function) {
- return predicate(x);
- } else {
- return equals(x);
- }
-}
-
// The handler for failed asserts.
FailureHandler _assertFailureHandler = null;
diff --git a/lib/src/future_matchers.dart b/lib/src/future_matchers.dart
index 4c5a391..f1d7cb8 100644
--- a/lib/src/future_matchers.dart
+++ b/lib/src/future_matchers.dart
@@ -6,9 +6,9 @@
import 'dart:async';
-import 'core_matchers.dart';
import 'expect.dart';
import 'interfaces.dart';
+import 'util.dart';
/// Matches a [Future] that completes successfully with a value. Note that this
/// creates an asynchronous expectation. The call to `expect()` that includes
diff --git a/lib/src/interfaces.dart b/lib/src/interfaces.dart
index 9fc1107..f3f0755 100644
--- a/lib/src/interfaces.dart
+++ b/lib/src/interfaces.dart
@@ -7,15 +7,6 @@
// To decouple the reporting of errors, and allow for extensibility of
// matchers, we make use of some interfaces.
-/// The ErrorFormatter type is used for functions that
-/// can be used to build up error reports upon [expect] failures.
-/// There is one built-in implementation ([defaultErrorFormatter])
-/// which is used by the default failure handler. If the failure handler
-/// is replaced it may be desirable to replace the [stringDescription]
-/// error formatter with another.
-typedef String ErrorFormatter(actual, Matcher matcher, String reason,
- Map matchState, bool verbose);
-
/// Matchers build up their error messages by appending to
/// Description objects. This interface is implemented by
/// StringDescription. This interface is unlikely to need
@@ -58,7 +49,7 @@
/// This builds a textual description of a specific mismatch. [item]
/// is the value that was tested by [matches]; [matchState] is
/// the [Map] that was passed to and supplemented by [matches]
- /// with additional information about the mismact, and [mismatchDescription]
+ /// with additional information about the mismatch, and [mismatchDescription]
/// is the [Description] that is being built to decribe the mismatch.
/// A few matchers make use of the [verbose] flag to provide detailed
/// information that is not typically included but can be of help in
@@ -66,21 +57,3 @@
Description describeMismatch(item, Description mismatchDescription,
Map matchState, bool verbose) => mismatchDescription;
}
-
-/// Failed matches are reported using a default IFailureHandler.
-/// The default implementation simply throws [TestFailure]s;
-/// this can be replaced by some other implementation of
-/// IFailureHandler by calling configureExpectHandler.
-abstract class FailureHandler {
- /// This handles failures given a textual decription
- void fail(String reason);
-
- /// This handles failures given the actual [value], the [matcher]
- /// the [reason] (argument from [expect]), some additonal [matchState]
- /// generated by the [matcher], and a verbose flag which controls in
- /// some cases how much [matchState] information is used. It will use
- /// these to create a detailed error message (typically by calling
- /// an [ErrorFormatter]) and then call [fail] with this message.
- void failMatch(actual, Matcher matcher, String reason,
- Map matchState, bool verbose);
-}
diff --git a/lib/src/iterable_matchers.dart b/lib/src/iterable_matchers.dart
index ef7afb0..eeea0ee 100644
--- a/lib/src/iterable_matchers.dart
+++ b/lib/src/iterable_matchers.dart
@@ -6,8 +6,8 @@
import 'core_matchers.dart';
import 'description.dart';
-import 'expect.dart';
import 'interfaces.dart';
+import 'util.dart';
/// Returns a matcher which matches [Iterable]s in which all elements
/// match the given [matcher].
diff --git a/lib/src/map_matchers.dart b/lib/src/map_matchers.dart
index a560e50..623b380 100644
--- a/lib/src/map_matchers.dart
+++ b/lib/src/map_matchers.dart
@@ -4,8 +4,8 @@
library matcher.map_matchers;
-import 'expect.dart';
import 'interfaces.dart';
+import 'util.dart';
/// Returns a matcher which matches maps containing the given [value].
Matcher containsValue(value) => new _ContainsValue(value);
diff --git a/lib/src/operator_matchers.dart b/lib/src/operator_matchers.dart
index fb79e8f..a6d23c2 100644
--- a/lib/src/operator_matchers.dart
+++ b/lib/src/operator_matchers.dart
@@ -4,9 +4,8 @@
library matcher.operator_matchers;
-import 'core_matchers.dart';
-import 'expect.dart';
import 'interfaces.dart';
+import 'util.dart';
/// This returns a matcher that inverts [matcher] to its logical negation.
Matcher isNot(matcher) => new _IsNot(wrapMatcher(matcher));
@@ -14,7 +13,7 @@
class _IsNot extends Matcher {
final Matcher _matcher;
- const _IsNot(Matcher this._matcher);
+ const _IsNot(this._matcher);
bool matches(item, Map matchState) => !_matcher.matches(item, matchState);
@@ -103,40 +102,21 @@
}
List<Matcher> _wrapArgs(arg0, arg1, arg2, arg3, arg4, arg5, arg6) {
+ Iterable<Matcher> matchers;
if (arg0 is List) {
- // TODO(kevmoo) throw a more helpful error here if any of these args is
- // not null
- expect(arg1, isNull);
- expect(arg2, isNull);
- expect(arg3, isNull);
- expect(arg4, isNull);
- expect(arg5, isNull);
- expect(arg6, isNull);
+ if (arg1 != null || arg2 != null || arg3 != null || arg4 != null ||
+ arg5 != null || arg6 != null) {
+ throw new ArgumentError('If arg0 is a List, all other arguments must be'
+ ' null.');
+ }
- return arg0.map((a) => wrapMatcher(a)).toList();
+ matchers = arg0;
+ } else {
+ matchers = [arg0, arg1, arg2, arg3, arg4, arg5, arg6]
+ .where((e) => e != null);
}
- List matchers = new List();
- if (arg0 != null) {
- matchers.add(wrapMatcher(arg0));
- }
- if (arg1 != null) {
- matchers.add(wrapMatcher(arg1));
- }
- if (arg2 != null) {
- matchers.add(wrapMatcher(arg2));
- }
- if (arg3 != null) {
- matchers.add(wrapMatcher(arg3));
- }
- if (arg4 != null) {
- matchers.add(wrapMatcher(arg4));
- }
- if (arg5 != null) {
- matchers.add(wrapMatcher(arg5));
- }
- if (arg6 != null) {
- matchers.add(wrapMatcher(arg6));
- }
- return matchers;
+ return matchers
+ .map((e) => wrapMatcher(e))
+ .toList();
}
diff --git a/lib/src/throws_matcher.dart b/lib/src/throws_matcher.dart
new file mode 100644
index 0000000..b3a5323
--- /dev/null
+++ b/lib/src/throws_matcher.dart
@@ -0,0 +1,113 @@
+// Copyright (c) 2014, 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 matcher.throws_matcher;
+
+import 'dart:async';
+
+import 'expect.dart';
+import 'interfaces.dart';
+import 'util.dart';
+
+/// This can be used to match two kinds of objects:
+///
+/// * A [Function] that throws an exception when called. The function cannot
+/// take any arguments. If you want to test that a function expecting
+/// arguments throws, wrap it in another zero-argument function that calls
+/// the one you want to test.
+///
+/// * A [Future] that completes with an exception. Note that this creates an
+/// asynchronous expectation. The call to `expect()` that includes this will
+/// return immediately and execution will continue. Later, when the future
+/// completes, the actual expectation will run.
+const Matcher throws = const Throws();
+
+/// This can be used to match two kinds of objects:
+///
+/// * A [Function] that throws an exception when called. The function cannot
+/// take any arguments. If you want to test that a function expecting
+/// arguments throws, wrap it in another zero-argument function that calls
+/// the one you want to test.
+///
+/// * A [Future] that completes with an exception. Note that this creates an
+/// asynchronous expectation. The call to `expect()` that includes this will
+/// return immediately and execution will continue. Later, when the future
+/// completes, the actual expectation will run.
+///
+/// In both cases, when an exception is thrown, this will test that the exception
+/// object matches [matcher]. If [matcher] is not an instance of [Matcher], it
+/// will implicitly be treated as `equals(matcher)`.
+Matcher throwsA(matcher) => new Throws(wrapMatcher(matcher));
+
+class Throws extends Matcher {
+ final Matcher _matcher;
+
+ const Throws([Matcher matcher]) : this._matcher = matcher;
+
+ bool matches(item, Map matchState) {
+ if (item is! Function && item is! Future) return false;
+ if (item is Future) {
+ var done = wrapAsync((fn) => fn());
+
+ // Queue up an asynchronous expectation that validates when the future
+ // completes.
+ item.then((value) {
+ done(() {
+ fail("Expected future to fail, but succeeded with '$value'.");
+ });
+ }, onError: (error, trace) {
+ done(() {
+ if (_matcher == null) return;
+ var reason;
+ if (trace != null) {
+ var stackTrace = trace.toString();
+ stackTrace = " ${stackTrace.replaceAll("\n", "\n ")}";
+ reason = "Actual exception trace:\n$stackTrace";
+ }
+ expect(error, _matcher, reason: reason);
+ });
+ });
+ // It hasn't failed yet.
+ return true;
+ }
+
+ try {
+ item();
+ return false;
+ } catch (e, s) {
+ if (_matcher == null || _matcher.matches(e, matchState)) {
+ return true;
+ } else {
+ addStateInfo(matchState, {'exception': e, 'stack': s});
+ return false;
+ }
+ }
+ }
+
+ Description describe(Description description) {
+ if (_matcher == null) {
+ return description.add("throws");
+ } else {
+ return description.add('throws ').addDescriptionOf(_matcher);
+ }
+ }
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState,
+ bool verbose) {
+ if (item is! Function && item is! Future) {
+ return mismatchDescription.add('is not a Function or Future');
+ } else if (_matcher == null || matchState['exception'] == null) {
+ return mismatchDescription.add('did not throw');
+ } else {
+ mismatchDescription. add('threw ').
+ addDescriptionOf(matchState['exception']);
+ if (verbose) {
+ mismatchDescription.add(' at ').add(matchState['stack'].toString());
+ }
+ return mismatchDescription;
+ }
+ }
+}
+
diff --git a/lib/src/throws_matchers.dart b/lib/src/throws_matchers.dart
new file mode 100644
index 0000000..35dfb39
--- /dev/null
+++ b/lib/src/throws_matchers.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, 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 matcher.throws_matchers;
+
+import 'error_matchers.dart';
+import 'interfaces.dart';
+import 'throws_matcher.dart';
+
+/// A matcher for functions that throw ArgumentError.
+const Matcher throwsArgumentError = const Throws(isArgumentError);
+
+/// A matcher for functions that throw ConcurrentModificationError.
+const Matcher throwsConcurrentModificationError =
+ const Throws(isConcurrentModificationError);
+
+/// A matcher for functions that throw CyclicInitializationError.
+const Matcher throwsCyclicInitializationError =
+ const Throws(isCyclicInitializationError);
+
+/// A matcher for functions that throw Exception.
+const Matcher throwsException = const Throws(isException);
+
+/// A matcher for functions that throw FormatException.
+const Matcher throwsFormatException = const Throws(isFormatException);
+
+/// A matcher for functions that throw NoSuchMethodError.
+const Matcher throwsNoSuchMethodError = const Throws(isNoSuchMethodError);
+
+/// A matcher for functions that throw NullThrownError.
+const Matcher throwsNullThrownError = const Throws(isNullThrownError);
+
+/// A matcher for functions that throw RangeError.
+const Matcher throwsRangeError = const Throws(isRangeError);
+
+/// A matcher for functions that throw StateError.
+const Matcher throwsStateError = const Throws(isStateError);
+
+/// A matcher for functions that throw Exception.
+const Matcher throwsUnimplementedError = const Throws(isUnimplementedError);
+
+/// A matcher for functions that throw UnsupportedError.
+const Matcher throwsUnsupportedError = const Throws(isUnsupportedError);
diff --git a/lib/src/util.dart b/lib/src/util.dart
new file mode 100644
index 0000000..08cba77
--- /dev/null
+++ b/lib/src/util.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2014, 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 matcher.util;
+
+import 'core_matchers.dart';
+import 'interfaces.dart';
+
+/// Useful utility for nesting match states.
+void addStateInfo(Map matchState, Map values) {
+ var innerState = new Map.from(matchState);
+ matchState.clear();
+ matchState['state'] = innerState;
+ matchState.addAll(values);
+}
+
+/// Takes an argument and returns an equivalent matcher.
+/// If the argument is already a matcher this does nothing,
+/// else if the argument is a function, it generates a predicate
+/// function matcher, else it generates an equals matcher.
+Matcher wrapMatcher(x) {
+ if (x is Matcher) {
+ return x;
+ } else if (x is Function) {
+ return predicate(x);
+ } else {
+ return equals(x);
+ }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 7cf3e9d..c6cb49d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: matcher
-version: 0.11.1
+version: 0.11.1+1
author: Dart Team <misc@dartlang.org>
description: Support for specifying test expectations
homepage: https://pub.dartlang.org/packages/matcher
diff --git a/test/core_matchers_test.dart b/test/core_matchers_test.dart
index cfeddbe..99d10ac 100644
--- a/test/core_matchers_test.dart
+++ b/test/core_matchers_test.dart
@@ -83,38 +83,6 @@
shouldFail(a, isNot(anything), "Expected: not anything Actual: {}");
});
- test('throws', () {
- shouldFail(doesNotThrow, throws,
- matches(
- r"Expected: throws"
- r" Actual: <Closure(: \(\) => dynamic "
- r"from Function 'doesNotThrow': static\.)?>"
- r" Which: did not throw"));
- shouldPass(doesThrow, throws);
- shouldFail(true, throws,
- "Expected: throws"
- " Actual: <true>"
- " Which: is not a Function or Future");
- });
-
- test('throwsA', () {
- shouldPass(doesThrow, throwsA(equals('X')));
- shouldFail(doesThrow, throwsA(equals('Y')),
- matches(
- r"Expected: throws 'Y'"
- r" Actual: <Closure(: \(\) => dynamic "
- r"from Function 'doesThrow': static\.)?>"
- r" Which: threw 'X'"));
- });
-
- test('throwsA', () {
- shouldPass(doesThrow, throwsA(equals('X')));
- shouldFail(doesThrow, throwsA(equals('Y')),
- matches("Expected: throws 'Y'.*"
- "Actual: <Closure.*"
- "Which: threw 'X'"));
- });
-
test('returnsNormally', () {
shouldPass(doesNotThrow, returnsNormally);
shouldFail(doesThrow, returnsNormally,
@@ -209,31 +177,4 @@
shouldPass('cow', predicate((x) => x is String, "an instance of String"));
});
});
-
- group('exception/error matchers', () {
- test('throwsCyclicInitializationError', () {
- expect(() => _Bicycle.foo, throwsCyclicInitializationError);
- });
-
- test('throwsConcurrentModificationError', () {
- expect(() {
- var a = { 'foo': 'bar' };
- for (var k in a.keys) {
- a.remove(k);
- }
- }, throwsConcurrentModificationError);
- });
-
- test('throwsNullThrownError', () {
- expect(() => throw null, throwsNullThrownError);
- });
- });
-}
-
-class _Bicycle {
- static final foo = bar();
-
- static bar() {
- return foo + 1;
- }
}
diff --git a/test/operator_matchers_test.dart b/test/operator_matchers_test.dart
index fd9627a..f82abaa 100644
--- a/test/operator_matchers_test.dart
+++ b/test/operator_matchers_test.dart
@@ -13,16 +13,47 @@
initUtils();
test('anyOf', () {
+ // with a list
shouldFail(0, anyOf([equals(1), equals(2)]),
"Expected: (<1> or <2>) Actual: <0>");
shouldPass(1, anyOf([equals(1), equals(2)]));
+
+ // with individual items
+ shouldFail(0, anyOf(equals(1), equals(2)),
+ "Expected: (<1> or <2>) Actual: <0>");
+ shouldPass(1, anyOf(equals(1), equals(2)));
});
test('allOf', () {
+ // with a list
shouldPass(1, allOf([lessThan(10), greaterThan(0)]));
shouldFail(-1, allOf([lessThan(10), greaterThan(0)]),
"Expected: (a value less than <10> and a value greater than <0>) "
"Actual: <-1> "
"Which: is not a value greater than <0>");
+
+ // with individual items
+ shouldPass(1, allOf(lessThan(10), greaterThan(0)));
+ shouldFail(-1, allOf(lessThan(10), greaterThan(0)),
+ "Expected: (a value less than <10> and a value greater than <0>) "
+ "Actual: <-1> "
+ "Which: is not a value greater than <0>");
+
+ // with maximum items
+ shouldPass(1, allOf(lessThan(10), lessThan(9), lessThan(8), lessThan(7),
+ lessThan(6), lessThan(5), lessThan(4)));
+ shouldFail(4, allOf(lessThan(10), lessThan(9), lessThan(8), lessThan(7),
+ lessThan(6), lessThan(5), lessThan(4)),
+ "Expected: (a value less than <10> and a value less than <9> and a "
+ "value less than <8> and a value less than <7> and a value less than "
+ "<6> and a value less than <5> and a value less than <4>) "
+ "Actual: <4> "
+ "Which: is not a value less than <4>");
+ });
+
+ test('If the first argument is a List, the rest must be null', () {
+ expect(() => allOf([], 5), throwsArgumentError);
+ expect(() => anyOf([], null, null, null, null, null, 42),
+ throwsArgumentError);
});
}
diff --git a/test/throws_matchers_test.dart b/test/throws_matchers_test.dart
new file mode 100644
index 0000000..74ff82d
--- /dev/null
+++ b/test/throws_matchers_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2012, 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 matcher.core_matchers_test;
+
+import 'package:matcher/matcher.dart';
+import 'package:unittest/unittest.dart' show test, group;
+
+import 'test_utils.dart';
+
+void main() {
+ initUtils();
+
+
+ test('throws', () {
+ shouldFail(doesNotThrow, throws,
+ matches(
+ r"Expected: throws"
+ r" Actual: <Closure(: \(\) => dynamic "
+ r"from Function 'doesNotThrow': static\.)?>"
+ r" Which: did not throw"));
+ shouldPass(doesThrow, throws);
+ shouldFail(true, throws,
+ "Expected: throws"
+ " Actual: <true>"
+ " Which: is not a Function or Future");
+ });
+
+ test('throwsA', () {
+ shouldPass(doesThrow, throwsA(equals('X')));
+ shouldFail(doesThrow, throwsA(equals('Y')),
+ matches(
+ r"Expected: throws 'Y'"
+ r" Actual: <Closure(: \(\) => dynamic "
+ r"from Function 'doesThrow': static\.)?>"
+ r" Which: threw 'X'"));
+ });
+
+ test('throwsA', () {
+ shouldPass(doesThrow, throwsA(equals('X')));
+ shouldFail(doesThrow, throwsA(equals('Y')),
+ matches("Expected: throws 'Y'.*"
+ "Actual: <Closure.*"
+ "Which: threw 'X'"));
+ });
+
+
+ group('exception/error matchers', () {
+ test('throwsCyclicInitializationError', () {
+ expect(() => _Bicycle.foo, throwsCyclicInitializationError);
+ });
+
+ test('throwsConcurrentModificationError', () {
+ expect(() {
+ var a = { 'foo': 'bar' };
+ for (var k in a.keys) {
+ a.remove(k);
+ }
+ }, throwsConcurrentModificationError);
+ });
+
+ test('throwsNullThrownError', () {
+ expect(() => throw null, throwsNullThrownError);
+ });
+ });
+}
+
+class _Bicycle {
+ static final foo = bar();
+
+ static bar() {
+ return foo + 1;
+ }
+}
+