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

Unified Diff: lib/unittest/collection_matchers.dart

Issue 10441104: New expectation functions plus convert old tests to use these. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 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
« no previous file with comments | « no previous file | lib/unittest/core_matchers.dart » ('j') | lib/unittest/core_matchers.dart » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/unittest/collection_matchers.dart
===================================================================
--- lib/unittest/collection_matchers.dart (revision 0)
+++ lib/unittest/collection_matchers.dart (revision 0)
@@ -0,0 +1,187 @@
+// 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.
+
+/**
+ * Returns a matcher which matches collections in which all elements
+ * match the given [matcher].
+ */
+IMatcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher));
+
+class _EveryElement extends _CollectionMatcher {
+ Matcher _matcher;
+
+ _EveryElement(Matcher this._matcher);
+
+ bool matches(item) {
+ try {
+ return item.every((e) => _matcher.matches(e));
+ } catch (var e) {
+ return false;
+ }
+ }
+
+ IDescription describe(IDescription description) =>
+ description.add('every element ').addDescriptionOf(_matcher);
+}
+
+/**
+ * Returns a matcher which matches collections in which at least one
+ * element matches the given [matcher].
+ */
+IMatcher someElement(matcher) => new _SomeElement(wrapMatcher(matcher));
+
+class _SomeElement extends _CollectionMatcher {
+ Matcher _matcher;
+
+ _SomeElement(this._matcher);
+
+ bool matches(item) {
+ try {
+ return item.some( (e) => _matcher.matches(e) );
+ } catch (var e) {
+ return false;
+ }
+ }
+
+ IDescription describe(IDescription description) =>
+ description.add('some element ').addDescriptionOf(_matcher);
+}
+
+/**
+ * Returns a matcher which matches Iterables that have the same
+ * length and the same elements as [expected], and in the same order.
+ */
+IMatcher orderedEquals(Iterable expected) => new _OrderedEquals(expected);
+
+class _OrderedEquals extends Matcher {
+ Iterable _expected;
+
+ _OrderedEquals(this._expected);
+
+ String _test(item) {
+ if (item is !Iterable) {
+ return 'is not Iterable';
+ }
+ var expectedIterator = _expected.iterator();
+ var actualIterator = item.iterator();
+ var position = 0;
+ while (true) {
+ if (expectedIterator.hasNext()) {
+ if (actualIterator.hasNext()) {
+ if (expectedIterator.next() != actualIterator.next()) {
+ return 'mismatch at position ${position}';
+ } else {
+ ++position;
+ }
+ } else {
+ return 'shorter than expected';
+ }
+ } else if (actualIterator.hasNext()) {
+ return 'longer than expected';
+ } else {
+ return null;
+ }
+ }
+ }
+
+ bool matches(item) => (_test(item) == null);
+
+ IDescription describe(IDescription description) =>
+ description.add('equals ').addDescriptionOf(_expected).add(' ordered');
+
+ IDescription describeMismatch(item, IDescription mismatchDescription) =>
+ mismatchDescription.add(_test(item));
+}
+
+/**
+ * Returns a matcher which matches Iterables that have the same
+ * length and the same elements as [expected], but not necessarily in
+ * the same order. Note that this is O(n^2) so should only be used on
+ * small objects.
+ */
+IMatcher unorderedEquals(Iterable expected) =>
+ new _UnorderedEquals(expected);
+
+class _UnorderedEquals extends Matcher {
+ Iterable _expected;
+
+ _UnorderedEquals(Iterable this._expected);
+
+ String _test(item) {
+ if (item is !Iterable) {
+ return 'not iterable';
+ }
Bob Nystrom 2012/06/01 18:22:23 If you like, you can make this a single line: if
gram 2012/06/01 22:22:00 I think I prefer it split, especially as it has a
+ // Check the lengths are the same.
+ var expectedLength = 0;
+ if (_expected is Collection) {
+ Collection cast = _expected; // "_expected as Collection"
+ expectedLength = cast.length;
+ } else {
+ for (var element in _expected) {
+ ++expectedLength;
+ }
+ }
+ var actualLength = 0;
+ if (item is Collection) {
+ actualLength = item.length;
+ } else {
+ for (var element in item) {
+ ++actualLength;
+ }
+ }
+ if (expectedLength > actualLength) {
+ return 'has too few elements (${actualLength} < ${expectedLength})';
+ } else if (expectedLength < actualLength) {
+ return 'has too many elements (${actualLength} > ${expectedLength})';
+ }
+ var mask = 0;
+ var expectedPosition = 0;
+ for (var expectedElement in _expected) {
+ var actualPosition = 0;
+ var matched = false;
+ for (var actualElement in item) {
+ if ((mask & (1 << actualPosition)) == 0) { // not matched yet?
+ if (expectedElement == actualElement) {
+ matched = true;
+ mask |= (1 << actualPosition);
Bob Nystrom 2012/06/01 18:22:23 This may be the first Dart code I've seen that rel
gram 2012/06/01 22:22:00 I was concerned about that. In one respect I want
Bob Nystrom 2012/06/01 22:29:01 Maybe leave a TODO: use int when all Dart implemen
+ break;
+ }
+ }
+ ++actualPosition;
+ }
+ if (!matched) {
+ return 'has no match for element ${expectedElement} '
+ 'at position ${expectedPosition}';
+ }
+ ++expectedPosition;
+ }
+ return null;
+ }
+
+ bool matches(item) => (_test(item) == null);
+
+ IDescription describe(IDescription description) =>
+ description.add('equals ').addDescriptionOf(_expected).add(' unordered');
+
+ IDescription describeMismatch(item, IDescription mismatchDescription) =>
+ mismatchDescription.add(_test(item));
+}
+
+/**
+ * Collection matchers match against a collection. We add this intermediate
+ * class to give better mismatch error messages than the base Matcher class.
+ */
+
+/*abstract*/ class _CollectionMatcher extends Matcher {
Bob Nystrom 2012/06/01 18:22:23 I think Dart does actually allow abstract here (wh
gram 2012/06/01 22:22:00 frog barfs when generating docs.
Bob Nystrom 2012/06/01 22:29:01 Ah. Please leave a TODO then saying "uncomment thi
+ const _CollectionMatcher();
+ IDescription describeMismatch(item, IDescription mismatchDescription) {
+ if (item is !Collection) {
+ return mismatchDescription.
+ addDescriptionOf(item).
+ add(' not a collection');
+ } else {
+ return super.describeMismatch(item, mismatchDescription);
+ }
+ }
+}
« no previous file with comments | « no previous file | lib/unittest/core_matchers.dart » ('j') | lib/unittest/core_matchers.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698