Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |