Chromium Code Reviews| Index: lib/unittest/collection_matchers.dart |
| =================================================================== |
| --- lib/unittest/collection_matchers.dart (revision 0) |
| +++ lib/unittest/collection_matchers.dart (revision 0) |
| @@ -0,0 +1,157 @@ |
| +// 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]. |
| + */ |
| +Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher)); |
| + |
| +class _EveryElement extends _CollectionMatcher { |
| + Matcher _matcher; |
| + |
| + _EveryElement(Matcher this._matcher); |
| + |
| + bool matches(item) { |
| + return item.every((e) => _matcher.matches(e)); |
| + } |
| + |
| + Description describe(Description description) => |
| + description.add('every element ').addDescriptionOf(_matcher); |
| +} |
| + |
| +/** |
| + * Returns a matcher which matches collections in which at least one |
| + * element matches the given [matcher]. |
| + */ |
| +Matcher someElement(matcher) => new _SomeElement(wrapMatcher(matcher)); |
| + |
| +class _SomeElement extends _CollectionMatcher { |
| + Matcher _matcher; |
| + |
| + _SomeElement(this._matcher); |
| + |
| + bool matches(item) { |
| + return item.some( (e) => _matcher.matches(e) ); |
| + } |
| + |
| + Description describe(Description description) => |
| + description.add('some element ').addDescriptionOf(_matcher); |
| +} |
| + |
| +/** |
| + * Returns a matcher which matches Iterables that have the same |
|
Siggi Cherem (dart-lang)
2012/06/06 00:26:08
dart-doc style: Iterables => [Iterable]s
(here and
gram
2012/06/06 16:23:56
Done.
|
| + * length and the same elements as [expected], and in the same order. |
| + */ |
| +Matcher orderedEquals(Iterable expected) => new _OrderedEquals(expected); |
| + |
| +class _OrderedEquals extends BaseMatcher { |
| + Iterable _expected; |
| + |
| + _OrderedEquals(this._expected); |
| + |
| + String _test(item) { |
| + return _compareIterables(_expected, item, |
| + (expected, actual, location) => expected == actual? null : location); |
| + } |
| + |
| + bool matches(item) => (_test(item) == null); |
| + |
| + Description describe(Description description) => |
| + description.add('equals ').addDescriptionOf(_expected).add(' ordered'); |
| + |
| + Description describeMismatch(item, Description 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. |
| + */ |
| +Matcher unorderedEquals(Iterable expected) => |
| + new _UnorderedEquals(expected); |
| + |
| +class _UnorderedEquals extends BaseMatcher { |
| + Iterable _expected; |
| + |
| + _UnorderedEquals(Iterable this._expected); |
| + |
| + String _test(item) { |
| + if (item is !Iterable) { |
| + return 'not iterable'; |
| + } |
| + // 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})'; |
| + } |
| + List<bool> matched = new List<bool>(actualLength); |
| + var expectedPosition = 0; |
| + for (var expectedElement in _expected) { |
| + var actualPosition = 0; |
| + var gotMatch = false; |
| + for (var actualElement in item) { |
| + if (!matched[actualPosition]) { |
| + if (expectedElement == actualElement) { |
| + matched[actualPosition] = gotMatch = true; |
| + break; |
| + } |
| + } |
| + ++actualPosition; |
| + } |
| + if (!gotMatch) { |
| + return 'has no match for element ${expectedElement} ' |
| + 'at position ${expectedPosition}'; |
| + } |
| + ++expectedPosition; |
| + } |
| + return null; |
| + } |
| + |
| + bool matches(item) => (_test(item) == null); |
| + |
| + Description describe(Description description) => |
| + description.add('equals ').addDescriptionOf(_expected).add(' unordered'); |
| + |
| + Description describeMismatch(item, Description 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 BaseMatcher { |
| + const _CollectionMatcher(); |
| + Description describeMismatch(item, Description mismatchDescription) { |
| + if (item is !Collection) { |
| + return mismatchDescription. |
| + addDescriptionOf(item). |
| + add(' not a collection'); |
| + } else { |
| + return super.describeMismatch(item, mismatchDescription); |
| + } |
| + } |
| +} |