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

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

Issue 112583003: Add an [unorderedMatches] matcher to unittest. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years 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 | pkg/unittest/pubspec.yaml » ('j') | pkg/unittest/pubspec.yaml » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of unittest.matcher; 5 part of unittest.matcher;
6 6
7 /** 7 /**
8 * Returns a matcher which matches [Iterable]s in which all elements 8 * Returns a matcher which matches [Iterable]s in which all elements
9 * match the given [matcher]. 9 * match the given [matcher].
10 */ 10 */
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 Description describeMismatch(item, Description mismatchDescription, 101 Description describeMismatch(item, Description mismatchDescription,
102 Map matchState, bool verbose) { 102 Map matchState, bool verbose) {
103 if (item is !Iterable) { 103 if (item is !Iterable) {
104 return mismatchDescription.add('is not an Iterable'); 104 return mismatchDescription.add('is not an Iterable');
105 } else { 105 } else {
106 return _matcher.describeMismatch(item, mismatchDescription, 106 return _matcher.describeMismatch(item, mismatchDescription,
107 matchState, verbose); 107 matchState, verbose);
108 } 108 }
109 } 109 }
110 } 110 }
111
111 /** 112 /**
112 * Returns a matcher which matches [Iterable]s that have the same 113 * Returns a matcher which matches [Iterable]s that have the same
113 * length and the same elements as [expected], but not necessarily in 114 * length and the same elements as [expected], but not necessarily in
114 * the same order. Note that this is O(n^2) so should only be used on 115 * the same order. Note that this is O(n^2) so should only be used on
115 * small objects. 116 * small objects.
116 */ 117 */
117 Matcher unorderedEquals(Iterable expected) => 118 Matcher unorderedEquals(Iterable expected) =>
118 new _UnorderedEquals(expected); 119 new _UnorderedEquals(expected);
119 120
120 class _UnorderedEquals extends Matcher { 121 class _UnorderedEquals extends Matcher {
121 Iterable _expected; 122 Iterable _expected;
122 123
123 _UnorderedEquals(Iterable this._expected); 124 _UnorderedEquals(Iterable this._expected);
124 125
125 String _test(item) { 126 String _test(item) {
126 if (item is !Iterable) { 127 if (item is !Iterable) {
127 return 'not iterable'; 128 return 'not iterable';
128 } 129 }
129 // Check the lengths are the same. 130 // Check the lengths are the same.
130 var expectedLength = _expected.length; 131 var expectedLength = _expected.length;
131 var actualLength = item.length; 132 var actualLength = item.length;
132 if (expectedLength > actualLength) { 133 if (expectedLength > actualLength) {
133 return 'has too few elements (${actualLength} < ${expectedLength})'; 134 return 'has too few elements (${actualLength} < ${expectedLength})';
134 } else if (expectedLength < actualLength) { 135 } else if (expectedLength < actualLength) {
135 return 'has too many elements (${actualLength} > ${expectedLength})'; 136 return 'has too many elements (${actualLength} > ${expectedLength})';
136 } 137 }
137 List<bool> matched = new List<bool>(actualLength); 138 List<bool> matched = new List<bool>(actualLength);
Siggi Cherem (dart-lang) 2013/12/17 00:32:03 might be worth adjusting this too (use the filled
138 for (var i = 0; i < actualLength; i++) { 139 for (var i = 0; i < actualLength; i++) {
139 matched[i] = false; 140 matched[i] = false;
140 } 141 }
141 var expectedPosition = 0; 142 var expectedPosition = 0;
142 for (var expectedElement in _expected) { 143 for (var expectedElement in _expected) {
143 var actualPosition = 0; 144 var actualPosition = 0;
144 var gotMatch = false; 145 var gotMatch = false;
145 for (var actualElement in item) { 146 for (var actualElement in item) {
146 if (!matched[actualPosition]) { 147 if (!matched[actualPosition]) {
147 if (expectedElement == actualElement) { 148 if (expectedElement == actualElement) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 addDescriptionOf(item). 187 addDescriptionOf(item).
187 add(' not an Iterable'); 188 add(' not an Iterable');
188 } else { 189 } else {
189 return super.describeMismatch(item, mismatchDescription, matchState, 190 return super.describeMismatch(item, mismatchDescription, matchState,
190 verbose); 191 verbose);
191 } 192 }
192 } 193 }
193 } 194 }
194 195
195 /** 196 /**
197 * Returns a matcher which matches [Iterable]s whose elements match the matchers
198 * in [expected], but not necessarily in the same order.
199 *
200 * Note that this is `O(n^2)` and so should only be used on small objects.
201 */
202 Matcher unorderedMatches(Iterable expected) =>
203 new _UnorderedMatches(expected);
204
205 class _UnorderedMatches extends Matcher {
Siggi Cherem (dart-lang) 2013/12/17 00:32:03 seems like there is a lot of code in common here a
nweiz 2013/12/17 03:33:47 I intentionally avoided going too deep on modifyin
Siggi Cherem (dart-lang) 2013/12/17 18:48:45 I think it is worth the effort for the matchers li
206 final List<Matcher> _expected;
207
208 _UnorderedMatches(Iterable expected)
209 : _expected = expected.map(wrapMatcher).toList();
210
211 String _test(item) {
212 if (item is !Iterable) return 'not iterable';
213 item = item.toList();
214
215 // Check the lengths are the same.
216 if (_expected.length > item.length) {
217 return 'has too few elements (${item.length} < ${_expected.length})';
218 } else if (_expected.length < item.length) {
219 return 'has too many elements (${item.length} > ${_expected.length})';
220 }
221
222 var matched = new List<bool>.filled(item.length, false);
223 var expectedPosition = 0;
224 for (var expectedMatcher in _expected) {
225 var actualPosition = 0;
226 var gotMatch = false;
227 for (var actualElement in item) {
228 if (!matched[actualPosition]) {
229 if (expectedMatcher.matches(actualElement, {})) {
230 matched[actualPosition] = gotMatch = true;
231 break;
232 }
233 }
234 ++actualPosition;
235 }
236
237 if (!gotMatch) {
238 return new StringDescription()
239 .add('has no match for ')
240 .addDescriptionOf(expectedMatcher)
241 .add(' at index ${expectedPosition}')
242 .toString();
243 }
244
245 ++expectedPosition;
246 }
247 return null;
248 }
249
250 bool matches(item, Map mismatchState) => _test(item) == null;
251
252 Description describe(Description description) =>
253 description
254 .add('matches ')
255 .addAll('[', ', ', ']', _expected)
256 .add(' unordered');
257
258 Description describeMismatch(item, Description mismatchDescription,
259 Map matchState, bool verbose) =>
260 mismatchDescription.add(_test(item));
261 }
262
263 /**
196 * A pairwise matcher for iterable. You can pass an arbitrary [comparator] 264 * A pairwise matcher for iterable. You can pass an arbitrary [comparator]
197 * function that takes an expected and actual argument which will be applied 265 * function that takes an expected and actual argument which will be applied
198 * to each pair in order. [description] should be a meaningful name for 266 * to each pair in order. [description] should be a meaningful name for
199 * the comparator. 267 * the comparator.
200 */ 268 */
201 Matcher pairwiseCompare(Iterable expected, Function comparator, 269 Matcher pairwiseCompare(Iterable expected, Function comparator,
202 String description) => 270 String description) =>
203 new _PairwiseCompare(expected, comparator, description); 271 new _PairwiseCompare(expected, comparator, description);
204 272
205 class _PairwiseCompare extends _IterableMatcher { 273 class _PairwiseCompare extends _IterableMatcher {
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 return mismatchDescription. 308 return mismatchDescription.
241 add('has '). 309 add('has ').
242 addDescriptionOf(matchState["actual"]). 310 addDescriptionOf(matchState["actual"]).
243 add(' which is not $_description '). 311 add(' which is not $_description ').
244 addDescriptionOf(matchState["expected"]). 312 addDescriptionOf(matchState["expected"]).
245 add(' at index ${matchState["index"]}'); 313 add(' at index ${matchState["index"]}');
246 } 314 }
247 } 315 }
248 } 316 }
249 317
OLDNEW
« no previous file with comments | « no previous file | pkg/unittest/pubspec.yaml » ('j') | pkg/unittest/pubspec.yaml » ('J')

Powered by Google App Engine
This is Rietveld 408576698