| 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 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 'with key <${key}> ${location}', depth+1); | 166 'with key <${key}> ${location}', depth+1); |
| 167 if (reason != null) { | 167 if (reason != null) { |
| 168 break; | 168 break; |
| 169 } | 169 } |
| 170 } | 170 } |
| 171 } | 171 } |
| 172 } | 172 } |
| 173 } | 173 } |
| 174 } else { | 174 } else { |
| 175 reason = new StringDescription(); | 175 reason = new StringDescription(); |
| 176 var eType = typeName(expected); | |
| 177 var aType = typeName(actual); | |
| 178 var includeTypes = eType != aType; | |
| 179 // If we have recursed, show the expected value too; if not, | 176 // If we have recursed, show the expected value too; if not, |
| 180 // expect() will show it for us. | 177 // expect() will show it for us. |
| 181 if (depth > 0) { | 178 if (depth > 0) { |
| 182 reason.add('expected '); | 179 reason.add('expected '); |
| 183 if (includeTypes) { | |
| 184 reason.add(eType).add(':'); | |
| 185 } | |
| 186 reason.addDescriptionOf(expected).add(' but '); | 180 reason.addDescriptionOf(expected).add(' but '); |
| 187 } | 181 } |
| 188 reason.add('was '); | 182 reason.add('was '); |
| 189 if (includeTypes) { | |
| 190 reason.add(aType).add(':'); | |
| 191 } | |
| 192 reason.addDescriptionOf(actual); | 183 reason.addDescriptionOf(actual); |
| 193 if (includeTypes && depth == 0) { | |
| 194 reason.add(' (not type ').add(eType).add(')'); | |
| 195 } | |
| 196 } | 184 } |
| 197 } | 185 } |
| 198 if (reason != null && location.length > 0) { | 186 if (reason != null && location.length > 0) { |
| 199 reason.add(' ').add(location); | 187 reason.add(' ').add(location); |
| 200 } | 188 } |
| 201 return reason; | 189 return reason; |
| 202 } | 190 } |
| 203 | 191 |
| 204 String typeName(x) { | |
| 205 // dart2js blows up on some objects (e.g. window.navigator). | |
| 206 // So we play safe here. | |
| 207 try { | |
| 208 if (x == null) return "null"; | |
| 209 return x.runtimeType.toString(); | |
| 210 } catch (e) { | |
| 211 return "Unknown"; | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 String _match(expected, actual) { | 192 String _match(expected, actual) { |
| 216 Description reason = _recursiveMatch(expected, actual, '', 0); | 193 Description reason = _recursiveMatch(expected, actual, '', 0); |
| 217 return reason == null ? null : reason.toString(); | 194 return reason == null ? null : reason.toString(); |
| 218 } | 195 } |
| 219 | 196 |
| 220 // TODO(gram) - see if we can make use of matchState here to avoid | 197 // TODO(gram) - see if we can make use of matchState here to avoid |
| 221 // recursing again in describeMismatch. | 198 // recursing again in describeMismatch. |
| 222 bool matches(item, MatchState matchState) => _match(_expected, item) == null; | 199 bool matches(item, MatchState matchState) => _match(_expected, item) == null; |
| 223 | 200 |
| 224 Description describe(Description description) => | 201 Description describe(Description description) => |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 576 bool matches(item, MatchState matchState) { | 553 bool matches(item, MatchState matchState) { |
| 577 return _matcher.matches(item.length, matchState); | 554 return _matcher.matches(item.length, matchState); |
| 578 } | 555 } |
| 579 | 556 |
| 580 Description describe(Description description) => | 557 Description describe(Description description) => |
| 581 description.add('an object with length of '). | 558 description.add('an object with length of '). |
| 582 addDescriptionOf(_matcher); | 559 addDescriptionOf(_matcher); |
| 583 | 560 |
| 584 Description describeMismatch(item, Description mismatchDescription, | 561 Description describeMismatch(item, Description mismatchDescription, |
| 585 MatchState matchState, bool verbose) { | 562 MatchState matchState, bool verbose) { |
| 586 super.describeMismatch(item, mismatchDescription, matchState, verbose); | |
| 587 try { | 563 try { |
| 588 // We want to generate a different description if there is no length | 564 // We want to generate a different description if there is no length |
| 589 // property. This is harmless code that will throw if no length property | 565 // property. This is harmless code that will throw if no length property |
| 590 // but subtle enough that an optimizer shouldn't strip it out. | 566 // but subtle enough that an optimizer shouldn't strip it out. |
| 591 if (item.length * item.length >= 0) { | 567 if (item.length * item.length >= 0) { |
| 592 return mismatchDescription.add(' with length of '). | 568 return mismatchDescription.add('had length of '). |
| 593 addDescriptionOf(item.length); | 569 addDescriptionOf(item.length); |
| 594 } | 570 } |
| 595 } catch (e) { | 571 } catch (e) { |
| 596 return mismatchDescription.add(' has no length property'); | 572 return mismatchDescription.add('had no length property'); |
| 597 } | 573 } |
| 598 } | 574 } |
| 599 } | 575 } |
| 600 | 576 |
| 601 /** | 577 /** |
| 602 * Returns a matcher that matches if the match argument contains | 578 * Returns a matcher that matches if the match argument contains |
| 603 * the expected value. For [String]s this means substring matching; | 579 * the expected value. For [String]s this means substring matching; |
| 604 * for [Map]s it means the map has the key, and for [Iterable]s | 580 * for [Map]s it means the map has the key, and for [Iterable]s |
| 605 * (including [Iterable]s) it means the iterable has a matching | 581 * (including [Iterable]s) it means the iterable has a matching |
| 606 * element. In the case of iterables, [expected] can itself be a | 582 * element. In the case of iterables, [expected] can itself be a |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 725 description.add(_featureDescription).add(' ').addDescriptionOf(_matcher); | 701 description.add(_featureDescription).add(' ').addDescriptionOf(_matcher); |
| 726 | 702 |
| 727 Description describeMismatch(item, Description mismatchDescription, | 703 Description describeMismatch(item, Description mismatchDescription, |
| 728 MatchState matchState, bool verbose) { | 704 MatchState matchState, bool verbose) { |
| 729 mismatchDescription.add(_featureName).add(' '); | 705 mismatchDescription.add(_featureName).add(' '); |
| 730 _matcher.describeMismatch(matchState.state['feature'], mismatchDescription, | 706 _matcher.describeMismatch(matchState.state['feature'], mismatchDescription, |
| 731 matchState.state['innerState'], verbose); | 707 matchState.state['innerState'], verbose); |
| 732 return mismatchDescription; | 708 return mismatchDescription; |
| 733 } | 709 } |
| 734 } | 710 } |
| OLD | NEW |