| 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 import 'core_matchers.dart'; | 5 import 'core_matchers.dart'; |
| 6 import 'description.dart'; | 6 import 'description.dart'; |
| 7 import 'interfaces.dart'; | 7 import 'interfaces.dart'; |
| 8 import 'util.dart'; | 8 import 'util.dart'; |
| 9 | 9 |
| 10 /// Returns a matcher which matches [Iterable]s in which all elements | 10 /// Returns a matcher which matches [Iterable]s in which all elements |
| 11 /// match the given [matcher]. | 11 /// match the given [matcher]. |
| 12 Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher)); | 12 Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher)); |
| 13 | 13 |
| 14 class _EveryElement extends _IterableMatcher { | 14 class _EveryElement extends _IterableMatcher { |
| 15 final Matcher _matcher; | 15 final Matcher _matcher; |
| 16 | 16 |
| 17 _EveryElement(Matcher this._matcher); | 17 _EveryElement(this._matcher); |
| 18 | 18 |
| 19 bool matches(item, Map matchState) { | 19 bool matches(item, Map matchState) { |
| 20 if (item is! Iterable) { | 20 if (item is! Iterable) { |
| 21 return false; | 21 return false; |
| 22 } | 22 } |
| 23 var i = 0; | 23 var i = 0; |
| 24 for (var element in item) { | 24 for (var element in item) { |
| 25 if (!_matcher.matches(element, matchState)) { | 25 if (!_matcher.matches(element, matchState)) { |
| 26 addStateInfo(matchState, {'index': i, 'element': element}); | 26 addStateInfo(matchState, {'index': i, 'element': element}); |
| 27 return false; | 27 return false; |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 /// Note that this is `O(n^2)` and so should only be used on small objects. | 148 /// Note that this is `O(n^2)` and so should only be used on small objects. |
| 149 Matcher unorderedMatches(Iterable expected) => new _UnorderedMatches(expected); | 149 Matcher unorderedMatches(Iterable expected) => new _UnorderedMatches(expected); |
| 150 | 150 |
| 151 class _UnorderedMatches extends Matcher { | 151 class _UnorderedMatches extends Matcher { |
| 152 final List<Matcher> _expected; | 152 final List<Matcher> _expected; |
| 153 | 153 |
| 154 _UnorderedMatches(Iterable expected) | 154 _UnorderedMatches(Iterable expected) |
| 155 : _expected = expected.map(wrapMatcher).toList(); | 155 : _expected = expected.map(wrapMatcher).toList(); |
| 156 | 156 |
| 157 String _test(item) { | 157 String _test(item) { |
| 158 if (item is! Iterable) return 'not iterable'; | 158 if (item is Iterable) { |
| 159 item = item.toList(); | 159 var list = item.toList(); |
| 160 | 160 |
| 161 // Check the lengths are the same. | 161 // Check the lengths are the same. |
| 162 if (_expected.length > item.length) { | 162 if (_expected.length > list.length) { |
| 163 return 'has too few elements (${item.length} < ${_expected.length})'; | 163 return 'has too few elements (${list.length} < ${_expected.length})'; |
| 164 } else if (_expected.length < item.length) { | 164 } else if (_expected.length < list.length) { |
| 165 return 'has too many elements (${item.length} > ${_expected.length})'; | 165 return 'has too many elements (${list.length} > ${_expected.length})'; |
| 166 } | |
| 167 | |
| 168 var matched = new List<bool>.filled(item.length, false); | |
| 169 var expectedPosition = 0; | |
| 170 for (var expectedMatcher in _expected) { | |
| 171 var actualPosition = 0; | |
| 172 var gotMatch = false; | |
| 173 for (var actualElement in item) { | |
| 174 if (!matched[actualPosition]) { | |
| 175 if (expectedMatcher.matches(actualElement, {})) { | |
| 176 matched[actualPosition] = gotMatch = true; | |
| 177 break; | |
| 178 } | |
| 179 } | |
| 180 ++actualPosition; | |
| 181 } | 166 } |
| 182 | 167 |
| 183 if (!gotMatch) { | 168 var matched = new List<bool>.filled(list.length, false); |
| 184 return new StringDescription() | 169 var expectedPosition = 0; |
| 185 .add('has no match for ') | 170 for (var expectedMatcher in _expected) { |
| 186 .addDescriptionOf(expectedMatcher) | 171 var actualPosition = 0; |
| 187 .add(' at index ${expectedPosition}') | 172 var gotMatch = false; |
| 188 .toString(); | 173 for (var actualElement in list) { |
| 174 if (!matched[actualPosition]) { |
| 175 if (expectedMatcher.matches(actualElement, {})) { |
| 176 matched[actualPosition] = gotMatch = true; |
| 177 break; |
| 178 } |
| 179 } |
| 180 ++actualPosition; |
| 181 } |
| 182 |
| 183 if (!gotMatch) { |
| 184 return new StringDescription() |
| 185 .add('has no match for ') |
| 186 .addDescriptionOf(expectedMatcher) |
| 187 .add(' at index $expectedPosition') |
| 188 .toString(); |
| 189 } |
| 190 |
| 191 ++expectedPosition; |
| 189 } | 192 } |
| 190 | 193 return null; |
| 191 ++expectedPosition; | 194 } else { |
| 195 return 'not iterable'; |
| 192 } | 196 } |
| 193 return null; | |
| 194 } | 197 } |
| 195 | 198 |
| 196 bool matches(item, Map mismatchState) => _test(item) == null; | 199 bool matches(item, Map mismatchState) => _test(item) == null; |
| 197 | 200 |
| 198 Description describe(Description description) => description | 201 Description describe(Description description) => description |
| 199 .add('matches ') | 202 .add('matches ') |
| 200 .addAll('[', ', ', ']', _expected) | 203 .addAll('[', ', ', ']', _expected) |
| 201 .add(' unordered'); | 204 .add(' unordered'); |
| 202 | 205 |
| 203 Description describeMismatch(item, Description mismatchDescription, | 206 Description describeMismatch(item, Description mismatchDescription, |
| 204 Map matchState, bool verbose) => | 207 Map matchState, bool verbose) => |
| 205 mismatchDescription.add(_test(item)); | 208 mismatchDescription.add(_test(item)); |
| 206 } | 209 } |
| 207 | 210 |
| 208 /// A pairwise matcher for [Iterable]s. | 211 /// A pairwise matcher for [Iterable]s. |
| 209 /// | 212 /// |
| 210 /// The [comparator] function, taking an expected and an actual argument, and | 213 /// The [comparator] function, taking an expected and an actual argument, and |
| 211 /// returning whether they match, will be applied to each pair in order. | 214 /// returning whether they match, will be applied to each pair in order. |
| 212 /// [description] should be a meaningful name for the comparator. | 215 /// [description] should be a meaningful name for the comparator. |
| 213 Matcher pairwiseCompare( | 216 Matcher pairwiseCompare<S, T>( |
| 214 Iterable expected, bool comparator(a, b), String description) => | 217 Iterable<S> expected, bool comparator(S a, T b), String description) => |
| 215 new _PairwiseCompare(expected, comparator, description); | 218 new _PairwiseCompare(expected, comparator, description); |
| 216 | 219 |
| 217 typedef bool _Comparator(a, b); | 220 typedef bool _Comparator<S, T>(S a, T b); |
| 218 | 221 |
| 219 class _PairwiseCompare extends _IterableMatcher { | 222 class _PairwiseCompare<S, T> extends _IterableMatcher { |
| 220 final Iterable _expected; | 223 final Iterable<S> _expected; |
| 221 final _Comparator _comparator; | 224 final _Comparator<S, T> _comparator; |
| 222 final String _description; | 225 final String _description; |
| 223 | 226 |
| 224 _PairwiseCompare(this._expected, this._comparator, this._description); | 227 _PairwiseCompare(this._expected, this._comparator, this._description); |
| 225 | 228 |
| 226 bool matches(item, Map matchState) { | 229 bool matches(item, Map matchState) { |
| 227 if (item is! Iterable) return false; | 230 if (item is Iterable) { |
| 228 if (item.length != _expected.length) return false; | 231 if (item.length != _expected.length) return false; |
| 229 var iterator = item.iterator; | 232 var iterator = item.iterator; |
| 230 var i = 0; | 233 var i = 0; |
| 231 for (var e in _expected) { | 234 for (var e in _expected) { |
| 232 iterator.moveNext(); | 235 iterator.moveNext(); |
| 233 if (!_comparator(e, iterator.current)) { | 236 if (!_comparator(e, iterator.current)) { |
| 234 addStateInfo(matchState, | 237 addStateInfo(matchState, |
| 235 {'index': i, 'expected': e, 'actual': iterator.current}); | 238 {'index': i, 'expected': e, 'actual': iterator.current}); |
| 236 return false; | 239 return false; |
| 240 } |
| 241 i++; |
| 237 } | 242 } |
| 238 i++; | 243 return true; |
| 244 } else { |
| 245 return false; |
| 239 } | 246 } |
| 240 return true; | |
| 241 } | 247 } |
| 242 | 248 |
| 243 Description describe(Description description) => | 249 Description describe(Description description) => |
| 244 description.add('pairwise $_description ').addDescriptionOf(_expected); | 250 description.add('pairwise $_description ').addDescriptionOf(_expected); |
| 245 | 251 |
| 246 Description describeMismatch( | 252 Description describeMismatch( |
| 247 item, Description mismatchDescription, Map matchState, bool verbose) { | 253 item, Description mismatchDescription, Map matchState, bool verbose) { |
| 248 if (item is! Iterable) { | 254 if (item is! Iterable) { |
| 249 return mismatchDescription.add('is not an Iterable'); | 255 return mismatchDescription.add('is not an Iterable'); |
| 250 } else if (item.length != _expected.length) { | 256 } else if (item.length != _expected.length) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 Description describe(Description description) => description | 303 Description describe(Description description) => description |
| 298 .add('contains in order(') | 304 .add('contains in order(') |
| 299 .addDescriptionOf(_expected) | 305 .addDescriptionOf(_expected) |
| 300 .add(')'); | 306 .add(')'); |
| 301 | 307 |
| 302 @override | 308 @override |
| 303 Description describeMismatch(item, Description mismatchDescription, | 309 Description describeMismatch(item, Description mismatchDescription, |
| 304 Map matchState, bool verbose) => | 310 Map matchState, bool verbose) => |
| 305 mismatchDescription.add(_test(item, matchState)); | 311 mismatchDescription.add(_test(item, matchState)); |
| 306 } | 312 } |
| OLD | NEW |