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

Side by Side 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, 6 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | lib/unittest/core_matchers.dart » ('j') | lib/unittest/core_matchers.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 /**
6 * Returns a matcher which matches collections in which all elements
7 * match the given [matcher].
8 */
9 IMatcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher));
10
11 class _EveryElement extends _CollectionMatcher {
12 Matcher _matcher;
13
14 _EveryElement(Matcher this._matcher);
15
16 bool matches(item) {
17 try {
18 return item.every((e) => _matcher.matches(e));
19 } catch (var e) {
20 return false;
21 }
22 }
23
24 IDescription describe(IDescription description) =>
25 description.add('every element ').addDescriptionOf(_matcher);
26 }
27
28 /**
29 * Returns a matcher which matches collections in which at least one
30 * element matches the given [matcher].
31 */
32 IMatcher someElement(matcher) => new _SomeElement(wrapMatcher(matcher));
33
34 class _SomeElement extends _CollectionMatcher {
35 Matcher _matcher;
36
37 _SomeElement(this._matcher);
38
39 bool matches(item) {
40 try {
41 return item.some( (e) => _matcher.matches(e) );
42 } catch (var e) {
43 return false;
44 }
45 }
46
47 IDescription describe(IDescription description) =>
48 description.add('some element ').addDescriptionOf(_matcher);
49 }
50
51 /**
52 * Returns a matcher which matches Iterables that have the same
53 * length and the same elements as [expected], and in the same order.
54 */
55 IMatcher orderedEquals(Iterable expected) => new _OrderedEquals(expected);
56
57 class _OrderedEquals extends Matcher {
58 Iterable _expected;
59
60 _OrderedEquals(this._expected);
61
62 String _test(item) {
63 if (item is !Iterable) {
64 return 'is not Iterable';
65 }
66 var expectedIterator = _expected.iterator();
67 var actualIterator = item.iterator();
68 var position = 0;
69 while (true) {
70 if (expectedIterator.hasNext()) {
71 if (actualIterator.hasNext()) {
72 if (expectedIterator.next() != actualIterator.next()) {
73 return 'mismatch at position ${position}';
74 } else {
75 ++position;
76 }
77 } else {
78 return 'shorter than expected';
79 }
80 } else if (actualIterator.hasNext()) {
81 return 'longer than expected';
82 } else {
83 return null;
84 }
85 }
86 }
87
88 bool matches(item) => (_test(item) == null);
89
90 IDescription describe(IDescription description) =>
91 description.add('equals ').addDescriptionOf(_expected).add(' ordered');
92
93 IDescription describeMismatch(item, IDescription mismatchDescription) =>
94 mismatchDescription.add(_test(item));
95 }
96
97 /**
98 * Returns a matcher which matches Iterables that have the same
99 * length and the same elements as [expected], but not necessarily in
100 * the same order. Note that this is O(n^2) so should only be used on
101 * small objects.
102 */
103 IMatcher unorderedEquals(Iterable expected) =>
104 new _UnorderedEquals(expected);
105
106 class _UnorderedEquals extends Matcher {
107 Iterable _expected;
108
109 _UnorderedEquals(Iterable this._expected);
110
111 String _test(item) {
112 if (item is !Iterable) {
113 return 'not iterable';
114 }
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
115 // Check the lengths are the same.
116 var expectedLength = 0;
117 if (_expected is Collection) {
118 Collection cast = _expected; // "_expected as Collection"
119 expectedLength = cast.length;
120 } else {
121 for (var element in _expected) {
122 ++expectedLength;
123 }
124 }
125 var actualLength = 0;
126 if (item is Collection) {
127 actualLength = item.length;
128 } else {
129 for (var element in item) {
130 ++actualLength;
131 }
132 }
133 if (expectedLength > actualLength) {
134 return 'has too few elements (${actualLength} < ${expectedLength})';
135 } else if (expectedLength < actualLength) {
136 return 'has too many elements (${actualLength} > ${expectedLength})';
137 }
138 var mask = 0;
139 var expectedPosition = 0;
140 for (var expectedElement in _expected) {
141 var actualPosition = 0;
142 var matched = false;
143 for (var actualElement in item) {
144 if ((mask & (1 << actualPosition)) == 0) { // not matched yet?
145 if (expectedElement == actualElement) {
146 matched = true;
147 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
148 break;
149 }
150 }
151 ++actualPosition;
152 }
153 if (!matched) {
154 return 'has no match for element ${expectedElement} '
155 'at position ${expectedPosition}';
156 }
157 ++expectedPosition;
158 }
159 return null;
160 }
161
162 bool matches(item) => (_test(item) == null);
163
164 IDescription describe(IDescription description) =>
165 description.add('equals ').addDescriptionOf(_expected).add(' unordered');
166
167 IDescription describeMismatch(item, IDescription mismatchDescription) =>
168 mismatchDescription.add(_test(item));
169 }
170
171 /**
172 * Collection matchers match against a collection. We add this intermediate
173 * class to give better mismatch error messages than the base Matcher class.
174 */
175
176 /*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
177 const _CollectionMatcher();
178 IDescription describeMismatch(item, IDescription mismatchDescription) {
179 if (item is !Collection) {
180 return mismatchDescription.
181 addDescriptionOf(item).
182 add(' not a collection');
183 } else {
184 return super.describeMismatch(item, mismatchDescription);
185 }
186 }
187 }
OLDNEW
« 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