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

Side by Side Diff: pkg/unittest/lib/src/iterable_matchers.dart

Issue 210413002: pkg/unittest: using matcher and mock from packages (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: releasing v0.10.1 Created 6 years, 9 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 | « pkg/unittest/lib/src/interfaces.dart ('k') | pkg/unittest/lib/src/map_matchers.dart » ('j') | no next file with comments »
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 part of unittest.matcher;
6
7 /**
8 * Returns a matcher which matches [Iterable]s in which all elements
9 * match the given [matcher].
10 */
11 Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher));
12
13 class _EveryElement extends _IterableMatcher {
14 Matcher _matcher;
15
16 _EveryElement(Matcher this._matcher);
17
18 bool matches(item, Map matchState) {
19 if (item is! Iterable) {
20 return false;
21 }
22 var i = 0;
23 for (var element in item) {
24 if (!_matcher.matches(element, matchState)) {
25 addStateInfo(matchState, {'index': i, 'element': element});
26 return false;
27 }
28 ++i;
29 }
30 return true;
31 }
32
33 Description describe(Description description) =>
34 description.add('every element(').addDescriptionOf(_matcher).add(')');
35
36 Description describeMismatch(item, Description mismatchDescription,
37 Map matchState, bool verbose) {
38 if (matchState['index'] != null) {
39 var index = matchState['index'];
40 var element = matchState['element'];
41 mismatchDescription.add('has value ').addDescriptionOf(element).
42 add(' which ');
43 var subDescription = new StringDescription();
44 _matcher.describeMismatch(element, subDescription,
45 matchState['state'], verbose);
46 if (subDescription.length > 0) {
47 mismatchDescription.add(subDescription);
48 } else {
49 mismatchDescription.add("doesn't match ");
50 _matcher.describe(mismatchDescription);
51 }
52 mismatchDescription.add(' at index $index');
53 return mismatchDescription;
54 }
55 return super.describeMismatch(item, mismatchDescription,
56 matchState, verbose);
57 }
58 }
59
60 /**
61 * Returns a matcher which matches [Iterable]s in which at least one
62 * element matches the given [matcher].
63 */
64 Matcher anyElement(matcher) => new _AnyElement(wrapMatcher(matcher));
65
66 class _AnyElement extends _IterableMatcher {
67 Matcher _matcher;
68
69 _AnyElement(this._matcher);
70
71 bool matches(item, Map matchState) {
72 return item.any((e) => _matcher.matches(e, matchState));
73 }
74
75 Description describe(Description description) =>
76 description.add('some element ').addDescriptionOf(_matcher);
77 }
78
79 /**
80 * Returns a matcher which matches [Iterable]s that have the same
81 * length and the same elements as [expected], and in the same order.
82 * This is equivalent to equals but does not recurse.
83 */
84
85 Matcher orderedEquals(Iterable expected) => new _OrderedEquals(expected);
86
87 class _OrderedEquals extends Matcher {
88 final Iterable _expected;
89 Matcher _matcher;
90
91 _OrderedEquals(this._expected) {
92 _matcher = equals(_expected, 1);
93 }
94
95 bool matches(item, Map matchState) =>
96 (item is Iterable) && _matcher.matches(item, matchState);
97
98 Description describe(Description description) =>
99 description.add('equals ').addDescriptionOf(_expected).add(' ordered');
100
101 Description describeMismatch(item, Description mismatchDescription,
102 Map matchState, bool verbose) {
103 if (item is !Iterable) {
104 return mismatchDescription.add('is not an Iterable');
105 } else {
106 return _matcher.describeMismatch(item, mismatchDescription,
107 matchState, verbose);
108 }
109 }
110 }
111
112 /**
113 * Returns a matcher which matches [Iterable]s that have the same
114 * length and the same elements as [expected], but not necessarily in
115 * the same order. Note that this is O(n^2) so should only be used on
116 * small objects.
117 */
118 Matcher unorderedEquals(Iterable expected) => new _UnorderedEquals(expected);
119
120 class _UnorderedEquals extends _UnorderedMatches {
121 final List _expectedValues;
122
123 _UnorderedEquals(Iterable expected)
124 : super(expected.map(equals)),
125 _expectedValues = expected.toList();
126
127 Description describe(Description description) =>
128 description
129 .add('equals ')
130 .addDescriptionOf(_expectedValues)
131 .add(' unordered');
132 }
133
134 /**
135 * Iterable matchers match against [Iterable]s. We add this intermediate
136 * class to give better mismatch error messages than the base Matcher class.
137 */
138 abstract class _IterableMatcher extends Matcher {
139 const _IterableMatcher();
140 Description describeMismatch(item, Description mismatchDescription,
141 Map matchState, bool verbose) {
142 if (item is! Iterable) {
143 return mismatchDescription.
144 addDescriptionOf(item).
145 add(' not an Iterable');
146 } else {
147 return super.describeMismatch(item, mismatchDescription, matchState,
148 verbose);
149 }
150 }
151 }
152
153 /**
154 * Returns a matcher which matches [Iterable]s whose elements match the matchers
155 * in [expected], but not necessarily in the same order.
156 *
157 * Note that this is `O(n^2)` and so should only be used on small objects.
158 */
159 Matcher unorderedMatches(Iterable expected) => new _UnorderedMatches(expected);
160
161 class _UnorderedMatches extends Matcher {
162 final List<Matcher> _expected;
163
164 _UnorderedMatches(Iterable expected)
165 : _expected = expected.map(wrapMatcher).toList();
166
167 String _test(item) {
168 if (item is! Iterable) return 'not iterable';
169 item = item.toList();
170
171 // Check the lengths are the same.
172 if (_expected.length > item.length) {
173 return 'has too few elements (${item.length} < ${_expected.length})';
174 } else if (_expected.length < item.length) {
175 return 'has too many elements (${item.length} > ${_expected.length})';
176 }
177
178 var matched = new List<bool>.filled(item.length, false);
179 var expectedPosition = 0;
180 for (var expectedMatcher in _expected) {
181 var actualPosition = 0;
182 var gotMatch = false;
183 for (var actualElement in item) {
184 if (!matched[actualPosition]) {
185 if (expectedMatcher.matches(actualElement, {})) {
186 matched[actualPosition] = gotMatch = true;
187 break;
188 }
189 }
190 ++actualPosition;
191 }
192
193 if (!gotMatch) {
194 return new StringDescription()
195 .add('has no match for ')
196 .addDescriptionOf(expectedMatcher)
197 .add(' at index ${expectedPosition}')
198 .toString();
199 }
200
201 ++expectedPosition;
202 }
203 return null;
204 }
205
206 bool matches(item, Map mismatchState) => _test(item) == null;
207
208 Description describe(Description description) =>
209 description
210 .add('matches ')
211 .addAll('[', ', ', ']', _expected)
212 .add(' unordered');
213
214 Description describeMismatch(item, Description mismatchDescription,
215 Map matchState, bool verbose) =>
216 mismatchDescription.add(_test(item));
217 }
218
219 /**
220 * A pairwise matcher for iterable. You can pass an arbitrary [comparator]
221 * function that takes an expected and actual argument which will be applied
222 * to each pair in order. [description] should be a meaningful name for
223 * the comparator.
224 */
225 Matcher pairwiseCompare(Iterable expected, Function comparator,
226 String description) =>
227 new _PairwiseCompare(expected, comparator, description);
228
229 class _PairwiseCompare extends _IterableMatcher {
230 Iterable _expected;
231 Function _comparator;
232 String _description;
233
234 _PairwiseCompare(this._expected, this._comparator, this._description);
235
236 bool matches(item, Map matchState) {
237 if (item is! Iterable) return false;
238 if (item.length != _expected.length) return false;
239 var iterator = item.iterator;
240 var i = 0;
241 for (var e in _expected) {
242 iterator.moveNext();
243 if (!_comparator(e, iterator.current)) {
244 addStateInfo(matchState, {'index': i, 'expected': e,
245 'actual': iterator.current});
246 return false;
247 }
248 i++;
249 }
250 return true;
251 }
252
253 Description describe(Description description) =>
254 description.add('pairwise $_description ').addDescriptionOf(_expected);
255
256 Description describeMismatch(item, Description mismatchDescription,
257 Map matchState, bool verbose) {
258 if (item is !Iterable) {
259 return mismatchDescription.add('is not an Iterable');
260 } else if (item.length != _expected.length) {
261 return mismatchDescription.
262 add('has length ${item.length} instead of ${_expected.length}');
263 } else {
264 return mismatchDescription.
265 add('has ').
266 addDescriptionOf(matchState["actual"]).
267 add(' which is not $_description ').
268 addDescriptionOf(matchState["expected"]).
269 add(' at index ${matchState["index"]}');
270 }
271 }
272 }
273
OLDNEW
« no previous file with comments | « pkg/unittest/lib/src/interfaces.dart ('k') | pkg/unittest/lib/src/map_matchers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698