| 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 that matches empty strings, maps or iterables | 8 * Returns a matcher that matches empty strings, maps or iterables |
| 9 * (including collections). | 9 * (including collections). |
| 10 */ | 10 */ |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 Description describe(Description description) => | 79 Description describe(Description description) => |
| 80 description.add('same instance as ').addDescriptionOf(_expected); | 80 description.add('same instance as ').addDescriptionOf(_expected); |
| 81 } | 81 } |
| 82 | 82 |
| 83 /** | 83 /** |
| 84 * Returns a matcher that does a deep recursive match. This only works | 84 * Returns a matcher that does a deep recursive match. This only works |
| 85 * with scalars, Maps and Iterables. To handle cyclic structures a | 85 * with scalars, Maps and Iterables. To handle cyclic structures a |
| 86 * recursion depth [limit] can be provided. The default limit is 100. | 86 * recursion depth [limit] can be provided. The default limit is 100. |
| 87 */ | 87 */ |
| 88 Matcher equals(expected, [limit=100]) => | 88 Matcher equals(expected, [limit=100]) => |
| 89 new _DeepMatcher(expected, limit); | 89 expected is String |
| 90 ? new _StringEqualsMatcher(expected) |
| 91 : new _DeepMatcher(expected, limit); |
| 90 | 92 |
| 91 class _DeepMatcher extends BaseMatcher { | 93 class _DeepMatcher extends BaseMatcher { |
| 92 final _expected; | 94 final _expected; |
| 93 final int _limit; | 95 final int _limit; |
| 94 var count; | 96 var count; |
| 95 | 97 |
| 96 _DeepMatcher(this._expected, [limit = 1000]) : this._limit = limit; | 98 _DeepMatcher(this._expected, [limit = 1000]) : this._limit = limit; |
| 97 | 99 |
| 98 String _compareIterables(expected, actual, matcher, depth) { | 100 String _compareIterables(expected, actual, matcher, depth) { |
| 99 if (actual is !Iterable) { | 101 if (actual is !Iterable) { |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 bool matches(item, MatchState matchState) => _match(_expected, item) == null; | 201 bool matches(item, MatchState matchState) => _match(_expected, item) == null; |
| 200 | 202 |
| 201 Description describe(Description description) => | 203 Description describe(Description description) => |
| 202 description.addDescriptionOf(_expected); | 204 description.addDescriptionOf(_expected); |
| 203 | 205 |
| 204 Description describeMismatch(item, Description mismatchDescription, | 206 Description describeMismatch(item, Description mismatchDescription, |
| 205 MatchState matchState, bool verbose) => | 207 MatchState matchState, bool verbose) => |
| 206 mismatchDescription.add(_match(_expected, item)); | 208 mismatchDescription.add(_match(_expected, item)); |
| 207 } | 209 } |
| 208 | 210 |
| 211 /** A special equality matcher for strings. */ |
| 212 class _StringEqualsMatcher extends BaseMatcher { |
| 213 final String _value; |
| 214 |
| 215 _StringEqualsMatcher(this._value); |
| 216 |
| 217 bool get showActualValue => true; |
| 218 |
| 219 bool matches(item, MatchState mismatchState) => _value == item; |
| 220 |
| 221 Description describe(Description description) => |
| 222 description.addDescriptionOf(_value); |
| 223 |
| 224 Description describeMismatch(item, Description mismatchDescription, |
| 225 MatchState matchState, bool verbose) { |
| 226 if (item is! String) { |
| 227 return mismatchDescription.addDescriptionOf(item).add(' not a string'); |
| 228 } else { |
| 229 var buff = new StringBuffer(); |
| 230 buff.write('Strings are not equal.'); |
| 231 var escapedItem = _escape(item); |
| 232 var escapedValue = _escape(_value); |
| 233 int minLength = escapedItem.length < escapedValue.length ? |
| 234 escapedItem.length : escapedValue.length; |
| 235 int start; |
| 236 for (start = 0; start < minLength; start++) { |
| 237 if (escapedValue.codeUnitAt(start) != escapedItem.codeUnitAt(start)) { |
| 238 break; |
| 239 } |
| 240 } |
| 241 if (start == minLength) { |
| 242 if (escapedValue.length < escapedItem.length) { |
| 243 buff.write(' Both strings start the same, but the given value also' |
| 244 ' has the following trailing characters: '); |
| 245 _writeTrailing(buff, escapedItem, escapedValue.length); |
| 246 } else { |
| 247 buff.write(' Both strings start the same, but the given value is' |
| 248 ' missing the following trailing characters: '); |
| 249 _writeTrailing(buff, escapedValue, escapedItem.length); |
| 250 } |
| 251 } else { |
| 252 buff.write('\nExpected: '); |
| 253 _writeLeading(buff, escapedValue, start); |
| 254 _writeTrailing(buff, escapedValue, start); |
| 255 buff.write('\n Actual: '); |
| 256 _writeLeading(buff, escapedItem, start); |
| 257 _writeTrailing(buff, escapedItem, start); |
| 258 buff.write('\n '); |
| 259 for (int i = (start > 10 ? 14 : start); i > 0; i--) buff.write(' '); |
| 260 buff.write('^\n Differ at position $start'); |
| 261 } |
| 262 |
| 263 return mismatchDescription.replace(buff.toString()); |
| 264 } |
| 265 } |
| 266 |
| 267 static String _escape(String s) => |
| 268 s.replaceAll('\n', '\\n').replaceAll('\r', '\\r').replaceAll('\t', '\\t'); |
| 269 |
| 270 static String _writeLeading(StringBuffer buff, String s, int start) { |
| 271 if (start > 10) { |
| 272 buff.write('... '); |
| 273 buff.write(s.substring(start - 10, start)); |
| 274 } else { |
| 275 buff.write(s.substring(0, start)); |
| 276 } |
| 277 } |
| 278 |
| 279 static String _writeTrailing(StringBuffer buff, String s, int start) { |
| 280 if (start + 10 > s.length) { |
| 281 buff.write(s.substring(start)); |
| 282 } else { |
| 283 buff.write(s.substring(start, start + 10)); |
| 284 buff.write(' ...'); |
| 285 } |
| 286 } |
| 287 } |
| 288 |
| 209 /** A matcher that matches any value. */ | 289 /** A matcher that matches any value. */ |
| 210 const Matcher anything = const _IsAnything(); | 290 const Matcher anything = const _IsAnything(); |
| 211 | 291 |
| 212 class _IsAnything extends BaseMatcher { | 292 class _IsAnything extends BaseMatcher { |
| 213 const _IsAnything(); | 293 const _IsAnything(); |
| 214 bool matches(item, MatchState matchState) => true; | 294 bool matches(item, MatchState matchState) => true; |
| 215 Description describe(Description description) => | 295 Description describe(Description description) => |
| 216 description.add('anything'); | 296 description.add('anything'); |
| 217 } | 297 } |
| 218 | 298 |
| (...skipping 482 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 701 description.add(_featureDescription).add(' ').addDescriptionOf(_matcher); | 781 description.add(_featureDescription).add(' ').addDescriptionOf(_matcher); |
| 702 | 782 |
| 703 Description describeMismatch(item, Description mismatchDescription, | 783 Description describeMismatch(item, Description mismatchDescription, |
| 704 MatchState matchState, bool verbose) { | 784 MatchState matchState, bool verbose) { |
| 705 mismatchDescription.add(_featureName).add(' '); | 785 mismatchDescription.add(_featureName).add(' '); |
| 706 _matcher.describeMismatch(matchState.state['feature'], mismatchDescription, | 786 _matcher.describeMismatch(matchState.state['feature'], mismatchDescription, |
| 707 matchState.state['innerState'], verbose); | 787 matchState.state['innerState'], verbose); |
| 708 return mismatchDescription; | 788 return mismatchDescription; |
| 709 } | 789 } |
| 710 } | 790 } |
| OLD | NEW |