| 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 matcher; | 5 part of 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 */ |
| 11 Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher)); | 11 Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher)); |
| 12 | 12 |
| 13 class _EveryElement extends _IterableMatcher { | 13 class _EveryElement extends _IterableMatcher { |
| 14 Matcher _matcher; | 14 Matcher _matcher; |
| 15 | 15 |
| 16 _EveryElement(Matcher this._matcher); | 16 _EveryElement(Matcher this._matcher); |
| 17 | 17 |
| 18 bool matches(item, MatchState matchState) { | 18 bool matches(item, Map matchState) { |
| 19 if (item is! Iterable) { | 19 if (item is! Iterable) { |
| 20 return false; | 20 return false; |
| 21 } | 21 } |
| 22 var i = 0; | 22 var i = 0; |
| 23 for (var element in item) { | 23 for (var element in item) { |
| 24 if (!_matcher.matches(element, matchState)) { | 24 if (!_matcher.matches(element, matchState)) { |
| 25 matchState.state = { | 25 addStateInfo(matchState, {'index': i, 'element': element}); |
| 26 'index': i, | |
| 27 'element': element, | |
| 28 'state': matchState.state | |
| 29 }; | |
| 30 return false; | 26 return false; |
| 31 } | 27 } |
| 32 ++i; | 28 ++i; |
| 33 } | 29 } |
| 34 return true; | 30 return true; |
| 35 } | 31 } |
| 36 | 32 |
| 37 Description describe(Description description) => | 33 Description describe(Description description) => |
| 38 description.add('every element ').addDescriptionOf(_matcher); | 34 description.add('every element(').addDescriptionOf(_matcher).add(')'); |
| 39 | 35 |
| 40 Description describeMismatch(item, Description mismatchDescription, | 36 Description describeMismatch(item, Description mismatchDescription, |
| 41 MatchState matchState, bool verbose) { | 37 Map matchState, bool verbose) { |
| 42 if (matchState.state != null) { | 38 if (matchState['index'] != null) { |
| 43 var index = matchState.state['index']; | 39 var index = matchState['index']; |
| 44 var element = matchState.state['element']; | 40 var element = matchState['element']; |
| 45 mismatchDescription.add('position $index '); | 41 mismatchDescription.add('has value ').addDescriptionOf(element). |
| 46 return _matcher.describeMismatch(element, mismatchDescription, | 42 add(' which '); |
| 47 matchState.state['state'], verbose); | 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; |
| 48 } | 54 } |
| 49 return super.describeMismatch(item, mismatchDescription, | 55 return super.describeMismatch(item, mismatchDescription, |
| 50 matchState, verbose); | 56 matchState, verbose); |
| 51 } | 57 } |
| 52 } | 58 } |
| 53 | 59 |
| 54 /** | 60 /** |
| 55 * Returns a matcher which matches [Iterable]s in which at least one | 61 * Returns a matcher which matches [Iterable]s in which at least one |
| 56 * element matches the given [matcher]. | 62 * element matches the given [matcher]. |
| 57 */ | 63 */ |
| 58 Matcher someElement(matcher) => new _SomeElement(wrapMatcher(matcher)); | 64 Matcher someElement(matcher) => new _SomeElement(wrapMatcher(matcher)); |
| 59 | 65 |
| 60 class _SomeElement extends _IterableMatcher { | 66 class _SomeElement extends _IterableMatcher { |
| 61 Matcher _matcher; | 67 Matcher _matcher; |
| 62 | 68 |
| 63 _SomeElement(this._matcher); | 69 _SomeElement(this._matcher); |
| 64 | 70 |
| 65 bool matches(item, MatchState matchState) { | 71 bool matches(item, Map matchState) { |
| 66 return item.any((e) => _matcher.matches(e, matchState)); | 72 return item.any((e) => _matcher.matches(e, matchState)); |
| 67 } | 73 } |
| 68 | 74 |
| 69 Description describe(Description description) => | 75 Description describe(Description description) => |
| 70 description.add('some element ').addDescriptionOf(_matcher); | 76 description.add('some element ').addDescriptionOf(_matcher); |
| 71 } | 77 } |
| 72 | 78 |
| 73 /** | 79 /** |
| 74 * Returns a matcher which matches [Iterable]s that have the same | 80 * Returns a matcher which matches [Iterable]s that have the same |
| 75 * length and the same elements as [expected], and in the same order. | 81 * length and the same elements as [expected], and in the same order. |
| 76 * This is equivalent to equals but does not recurse. | 82 * This is equivalent to equals but does not recurse. |
| 77 */ | 83 */ |
| 78 | 84 |
| 79 Matcher orderedEquals(Iterable expected) => new _OrderedEquals(expected); | 85 Matcher orderedEquals(Iterable expected) => new _OrderedEquals(expected); |
| 80 | 86 |
| 81 class _OrderedEquals extends BaseMatcher { | 87 class _OrderedEquals extends BaseMatcher { |
| 82 final Iterable _expected; | 88 final Iterable _expected; |
| 83 Matcher _matcher; | 89 Matcher _matcher; |
| 84 | 90 |
| 85 _OrderedEquals(this._expected) { | 91 _OrderedEquals(this._expected) { |
| 86 _matcher = equals(_expected, 1); | 92 _matcher = equals(_expected, 1); |
| 87 } | 93 } |
| 88 | 94 |
| 89 bool matches(item, MatchState matchState) => | 95 bool matches(item, Map matchState) => |
| 90 (item is Iterable) && _matcher.matches(item, matchState); | 96 (item is Iterable) && _matcher.matches(item, matchState); |
| 91 | 97 |
| 92 Description describe(Description description) => | 98 Description describe(Description description) => |
| 93 description.add('equals ').addDescriptionOf(_expected).add(' ordered'); | 99 description.add('equals ').addDescriptionOf(_expected).add(' ordered'); |
| 94 | 100 |
| 95 Description describeMismatch(item, Description mismatchDescription, | 101 Description describeMismatch(item, Description mismatchDescription, |
| 96 MatchState matchState, bool verbose) { | 102 Map matchState, bool verbose) { |
| 97 if (item is !Iterable) { | 103 if (item is !Iterable) { |
| 98 return mismatchDescription.add('not an Iterable'); | 104 return mismatchDescription.add('is not an Iterable'); |
| 99 } else { | 105 } else { |
| 100 return _matcher.describeMismatch(item, mismatchDescription, | 106 return _matcher.describeMismatch(item, mismatchDescription, |
| 101 matchState, verbose); | 107 matchState, verbose); |
| 102 } | 108 } |
| 103 } | 109 } |
| 104 } | 110 } |
| 105 /** | 111 /** |
| 106 * Returns a matcher which matches [Iterable]s that have the same | 112 * Returns a matcher which matches [Iterable]s that have the same |
| 107 * length and the same elements as [expected], but not necessarily in | 113 * length and the same elements as [expected], but not necessarily in |
| 108 * the same order. Note that this is O(n^2) so should only be used on | 114 * the same order. Note that this is O(n^2) so should only be used on |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 matched[actualPosition] = gotMatch = true; | 148 matched[actualPosition] = gotMatch = true; |
| 143 break; | 149 break; |
| 144 } | 150 } |
| 145 } | 151 } |
| 146 ++actualPosition; | 152 ++actualPosition; |
| 147 } | 153 } |
| 148 if (!gotMatch) { | 154 if (!gotMatch) { |
| 149 Description reason = new StringDescription(); | 155 Description reason = new StringDescription(); |
| 150 reason.add('has no match for element '). | 156 reason.add('has no match for element '). |
| 151 addDescriptionOf(expectedElement). | 157 addDescriptionOf(expectedElement). |
| 152 add(' at position ${expectedPosition}'); | 158 add(' at index ${expectedPosition}'); |
| 153 return reason.toString(); | 159 return reason.toString(); |
| 154 } | 160 } |
| 155 ++expectedPosition; | 161 ++expectedPosition; |
| 156 } | 162 } |
| 157 return null; | 163 return null; |
| 158 } | 164 } |
| 159 | 165 |
| 160 bool matches(item, MatchState mismatchState) => (_test(item) == null); | 166 bool matches(item, Map mismatchState) => (_test(item) == null); |
| 161 | 167 |
| 162 Description describe(Description description) => | 168 Description describe(Description description) => |
| 163 description.add('equals ').addDescriptionOf(_expected).add(' unordered'); | 169 description.add('equals ').addDescriptionOf(_expected).add(' unordered'); |
| 164 | 170 |
| 165 Description describeMismatch(item, Description mismatchDescription, | 171 Description describeMismatch(item, Description mismatchDescription, |
| 166 MatchState matchState, bool verbose) => | 172 Map matchState, bool verbose) => |
| 167 mismatchDescription.add(_test(item)); | 173 mismatchDescription.add(_test(item)); |
| 168 } | 174 } |
| 169 | 175 |
| 170 /** | 176 /** |
| 171 * Iterable matchers match against [Iterable]s. We add this intermediate | 177 * Iterable matchers match against [Iterable]s. We add this intermediate |
| 172 * class to give better mismatch error messages than the base Matcher class. | 178 * class to give better mismatch error messages than the base Matcher class. |
| 173 */ | 179 */ |
| 174 abstract class _IterableMatcher extends BaseMatcher { | 180 abstract class _IterableMatcher extends BaseMatcher { |
| 175 const _IterableMatcher(); | 181 const _IterableMatcher(); |
| 176 Description describeMismatch(item, Description mismatchDescription, | 182 Description describeMismatch(item, Description mismatchDescription, |
| 177 MatchState matchState, bool verbose) { | 183 Map matchState, bool verbose) { |
| 178 if (item is! Iterable) { | 184 if (item is! Iterable) { |
| 179 return mismatchDescription. | 185 return mismatchDescription. |
| 180 addDescriptionOf(item). | 186 addDescriptionOf(item). |
| 181 add(' not an Iterable'); | 187 add(' not an Iterable'); |
| 182 } else { | 188 } else { |
| 183 return super.describeMismatch(item, mismatchDescription, matchState, | 189 return super.describeMismatch(item, mismatchDescription, matchState, |
| 184 verbose); | 190 verbose); |
| 185 } | 191 } |
| 186 } | 192 } |
| 187 } | 193 } |
| 188 | 194 |
| 189 /** | 195 /** |
| 190 * A pairwise matcher for iterable. You can pass an arbitrary [comparator] | 196 * A pairwise matcher for iterable. You can pass an arbitrary [comparator] |
| 191 * function that takes an expected and actual argument which will be applied | 197 * function that takes an expected and actual argument which will be applied |
| 192 * to each pair in order. [description] should be a meaningful name for | 198 * to each pair in order. [description] should be a meaningful name for |
| 193 * the comparator. | 199 * the comparator. |
| 194 */ | 200 */ |
| 195 Matcher pairwiseCompare(Iterable expected, Function comparator, | 201 Matcher pairwiseCompare(Iterable expected, Function comparator, |
| 196 String description) => | 202 String description) => |
| 197 new _PairwiseCompare(expected, comparator, description); | 203 new _PairwiseCompare(expected, comparator, description); |
| 198 | 204 |
| 199 class _PairwiseCompare extends _IterableMatcher { | 205 class _PairwiseCompare extends _IterableMatcher { |
| 200 Iterable _expected; | 206 Iterable _expected; |
| 201 Function _comparator; | 207 Function _comparator; |
| 202 String _description; | 208 String _description; |
| 203 | 209 |
| 204 _PairwiseCompare(this._expected, this._comparator, this._description); | 210 _PairwiseCompare(this._expected, this._comparator, this._description); |
| 205 | 211 |
| 206 bool matches(item, MatchState matchState) { | 212 bool matches(item, Map matchState) { |
| 207 if (item is! Iterable) return false; | 213 if (item is! Iterable) return false; |
| 208 if (item.length != _expected.length) return false; | 214 if (item.length != _expected.length) return false; |
| 209 var iterator = item.iterator; | 215 var iterator = item.iterator; |
| 210 var i = 0; | 216 var i = 0; |
| 211 for (var e in _expected) { | 217 for (var e in _expected) { |
| 212 iterator.moveNext(); | 218 iterator.moveNext(); |
| 213 if (!_comparator(e, iterator.current)) { | 219 if (!_comparator(e, iterator.current)) { |
| 214 matchState.state = { | 220 addStateInfo(matchState, {'index': i, 'expected': e, |
| 215 'index': i, | 221 'actual': iterator.current}); |
| 216 'expected': e, | |
| 217 'actual' : iterator.current, | |
| 218 'state': matchState.state | |
| 219 }; | |
| 220 return false; | 222 return false; |
| 221 } | 223 } |
| 222 i++; | 224 i++; |
| 223 } | 225 } |
| 224 return true; | 226 return true; |
| 225 } | 227 } |
| 226 | 228 |
| 227 Description describe(Description description) => | 229 Description describe(Description description) => |
| 228 description.add('pairwise $_description ').addDescriptionOf(_expected); | 230 description.add('pairwise $_description ').addDescriptionOf(_expected); |
| 229 | 231 |
| 230 Description describeMismatch(item, Description mismatchDescription, | 232 Description describeMismatch(item, Description mismatchDescription, |
| 231 MatchState matchState, bool verbose) { | 233 Map matchState, bool verbose) { |
| 232 if (item is !Iterable) { | 234 if (item is !Iterable) { |
| 233 return mismatchDescription.add('not an Iterable'); | 235 return mismatchDescription.add('is not an Iterable'); |
| 234 } else if (item.length != _expected.length) { | 236 } else if (item.length != _expected.length) { |
| 235 return mismatchDescription. | 237 return mismatchDescription. |
| 236 add('length was ${item.length} instead of ${_expected.length}'); | 238 add('has length ${item.length} instead of ${_expected.length}'); |
| 237 } else { | 239 } else { |
| 238 return mismatchDescription. | 240 return mismatchDescription. |
| 239 addDescriptionOf(matchState.state["actual"]). | 241 add('has '). |
| 240 add(' not $_description '). | 242 addDescriptionOf(matchState["actual"]). |
| 241 addDescriptionOf(matchState.state["expected"]). | 243 add(' which is not $_description '). |
| 242 add(' at position ${matchState.state["index"]}'); | 244 addDescriptionOf(matchState["expected"]). |
| 245 add(' at index ${matchState["index"]}'); |
| 243 } | 246 } |
| 244 } | 247 } |
| 245 } | 248 } |
| 246 | 249 |
| OLD | NEW |