Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(985)

Side by Side Diff: pkg/unittest/lib/src/core_matchers.dart

Issue 18442002: Add missing newline after Actual value in fail message. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/unittest/lib/src/basematcher.dart ('k') | pkg/unittest/lib/src/expect.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 */
11 const Matcher isEmpty = const _Empty(); 11 const Matcher isEmpty = const _Empty();
12 12
13 class _Empty extends BaseMatcher { 13 class _Empty extends Matcher {
14 const _Empty(); 14 const _Empty();
15 bool matches(item, Map matchState) { 15 bool matches(item, Map matchState) {
16 if (item is Map || item is Iterable) { 16 if (item is Map || item is Iterable) {
17 return item.isEmpty; 17 return item.isEmpty;
18 } else if (item is String) { 18 } else if (item is String) {
19 return item.length == 0; 19 return item.length == 0;
20 } else { 20 } else {
21 return false; 21 return false;
22 } 22 }
23 } 23 }
24 Description describe(Description description) => 24 Description describe(Description description) =>
25 description.add('empty'); 25 description.add('empty');
26 } 26 }
27 27
28 /** A matcher that matches any null value. */ 28 /** A matcher that matches any null value. */
29 const Matcher isNull = const _IsNull(); 29 const Matcher isNull = const _IsNull();
30 30
31 /** A matcher that matches any non-null value. */ 31 /** A matcher that matches any non-null value. */
32 const Matcher isNotNull = const _IsNotNull(); 32 const Matcher isNotNull = const _IsNotNull();
33 33
34 class _IsNull extends BaseMatcher { 34 class _IsNull extends Matcher {
35 const _IsNull(); 35 const _IsNull();
36 bool matches(item, Map matchState) => item == null; 36 bool matches(item, Map matchState) => item == null;
37 Description describe(Description description) => 37 Description describe(Description description) =>
38 description.add('null'); 38 description.add('null');
39 } 39 }
40 40
41 class _IsNotNull extends BaseMatcher { 41 class _IsNotNull extends Matcher {
42 const _IsNotNull(); 42 const _IsNotNull();
43 bool matches(item, Map matchState) => item != null; 43 bool matches(item, Map matchState) => item != null;
44 Description describe(Description description) => 44 Description describe(Description description) =>
45 description.add('not null'); 45 description.add('not null');
46 } 46 }
47 47
48 /** A matcher that matches the Boolean value true. */ 48 /** A matcher that matches the Boolean value true. */
49 const Matcher isTrue = const _IsTrue(); 49 const Matcher isTrue = const _IsTrue();
50 50
51 /** A matcher that matches anything except the Boolean value true. */ 51 /** A matcher that matches anything except the Boolean value true. */
52 const Matcher isFalse = const _IsFalse(); 52 const Matcher isFalse = const _IsFalse();
53 53
54 class _IsTrue extends BaseMatcher { 54 class _IsTrue extends Matcher {
55 const _IsTrue(); 55 const _IsTrue();
56 bool matches(item, Map matchState) => item == true; 56 bool matches(item, Map matchState) => item == true;
57 Description describe(Description description) => 57 Description describe(Description description) =>
58 description.add('true'); 58 description.add('true');
59 } 59 }
60 60
61 class _IsFalse extends BaseMatcher { 61 class _IsFalse extends Matcher {
62 const _IsFalse(); 62 const _IsFalse();
63 bool matches(item, Map matchState) => item == false; 63 bool matches(item, Map matchState) => item == false;
64 Description describe(Description description) => 64 Description describe(Description description) =>
65 description.add('false'); 65 description.add('false');
66 } 66 }
67 67
68 /** 68 /**
69 * Returns a matches that matches if the value is the same instance 69 * Returns a matches that matches if the value is the same instance
70 * as [object] (`===`). 70 * as [object] (`===`).
71 */ 71 */
72 Matcher same(expected) => new _IsSameAs(expected); 72 Matcher same(expected) => new _IsSameAs(expected);
73 73
74 class _IsSameAs extends BaseMatcher { 74 class _IsSameAs extends Matcher {
75 final _expected; 75 final _expected;
76 const _IsSameAs(this._expected); 76 const _IsSameAs(this._expected);
77 bool matches(item, Map matchState) => identical(item, _expected); 77 bool matches(item, Map matchState) => identical(item, _expected);
78 // If all types were hashable we could show a hash here. 78 // If all types were hashable we could show a hash here.
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 expected is String 89 expected is String
90 ? new _StringEqualsMatcher(expected) 90 ? new _StringEqualsMatcher(expected)
91 : new _DeepMatcher(expected, limit); 91 : new _DeepMatcher(expected, limit);
92 92
93 class _DeepMatcher extends BaseMatcher { 93 class _DeepMatcher extends Matcher {
94 final _expected; 94 final _expected;
95 final int _limit; 95 final int _limit;
96 var count; 96 var count;
97 97
98 _DeepMatcher(this._expected, [limit = 1000]) : this._limit = limit; 98 _DeepMatcher(this._expected, [limit = 1000]) : this._limit = limit;
99 99
100 // Returns a pair (reason, location) 100 // Returns a pair (reason, location)
101 List _compareIterables(expected, actual, matcher, depth, location) { 101 List _compareIterables(expected, actual, matcher, depth, location) {
102 if (actual is !Iterable) { 102 if (actual is !Iterable) {
103 return ['is not Iterable', location]; 103 return ['is not Iterable', location];
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
227 if (reason.length == 0 && mismatchDescription.length > 0) { 227 if (reason.length == 0 && mismatchDescription.length > 0) {
228 mismatchDescription.add('is ').addDescriptionOf(item); 228 mismatchDescription.add('is ').addDescriptionOf(item);
229 } else { 229 } else {
230 mismatchDescription.add(reason); 230 mismatchDescription.add(reason);
231 } 231 }
232 return mismatchDescription; 232 return mismatchDescription;
233 } 233 }
234 } 234 }
235 235
236 /** A special equality matcher for strings. */ 236 /** A special equality matcher for strings. */
237 class _StringEqualsMatcher extends BaseMatcher { 237 class _StringEqualsMatcher extends Matcher {
238 final String _value; 238 final String _value;
239 239
240 _StringEqualsMatcher(this._value); 240 _StringEqualsMatcher(this._value);
241 241
242 bool get showActualValue => true; 242 bool get showActualValue => true;
243 243
244 bool matches(item, Map matchState) => _value == item; 244 bool matches(item, Map matchState) => _value == item;
245 245
246 Description describe(Description description) => 246 Description describe(Description description) =>
247 description.addDescriptionOf(_value); 247 description.addDescriptionOf(_value);
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 } else { 307 } else {
308 buff.write(s.substring(start, start + 10)); 308 buff.write(s.substring(start, start + 10));
309 buff.write(' ...'); 309 buff.write(' ...');
310 } 310 }
311 } 311 }
312 } 312 }
313 313
314 /** A matcher that matches any value. */ 314 /** A matcher that matches any value. */
315 const Matcher anything = const _IsAnything(); 315 const Matcher anything = const _IsAnything();
316 316
317 class _IsAnything extends BaseMatcher { 317 class _IsAnything extends Matcher {
318 const _IsAnything(); 318 const _IsAnything();
319 bool matches(item, Map matchState) => true; 319 bool matches(item, Map matchState) => true;
320 Description describe(Description description) => 320 Description describe(Description description) =>
321 description.add('anything'); 321 description.add('anything');
322 } 322 }
323 323
324 /** 324 /**
325 * Returns a matcher that matches if an object is an instance 325 * Returns a matcher that matches if an object is an instance
326 * of [type] (or a subtype). 326 * of [type] (or a subtype).
327 * 327 *
328 * As types are not first class objects in Dart we can only 328 * As types are not first class objects in Dart we can only
329 * approximate this test by using a generic wrapper class. 329 * approximate this test by using a generic wrapper class.
330 * 330 *
331 * For example, to test whether 'bar' is an instance of type 331 * For example, to test whether 'bar' is an instance of type
332 * 'Foo', we would write: 332 * 'Foo', we would write:
333 * 333 *
334 * expect(bar, new isInstanceOf<Foo>()); 334 * expect(bar, new isInstanceOf<Foo>());
335 * 335 *
336 * To get better error message, supply a name when creating the 336 * To get better error message, supply a name when creating the
337 * Type wrapper; e.g.: 337 * Type wrapper; e.g.:
338 * 338 *
339 * expect(bar, new isInstanceOf<Foo>('Foo')); 339 * expect(bar, new isInstanceOf<Foo>('Foo'));
340 * 340 *
341 * Note that this does not currently work in dart2js; it will 341 * Note that this does not currently work in dart2js; it will
342 * match any type, and isNot(new isInstanceof<T>()) will always 342 * match any type, and isNot(new isInstanceof<T>()) will always
343 * fail. This is because dart2js currently ignores template type 343 * fail. This is because dart2js currently ignores template type
344 * parameters. 344 * parameters.
345 */ 345 */
346 class isInstanceOf<T> extends BaseMatcher { 346 class isInstanceOf<T> extends Matcher {
347 final String _name; 347 final String _name;
348 const isInstanceOf([name = 'specified type']) : this._name = name; 348 const isInstanceOf([name = 'specified type']) : this._name = name;
349 bool matches(obj, Map matchState) => obj is T; 349 bool matches(obj, Map matchState) => obj is T;
350 // The description here is lame :-( 350 // The description here is lame :-(
351 Description describe(Description description) => 351 Description describe(Description description) =>
352 description.add('an instance of ${_name}'); 352 description.add('an instance of ${_name}');
353 } 353 }
354 354
355 /** 355 /**
356 * This can be used to match two kinds of objects: 356 * This can be used to match two kinds of objects:
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
388 388
389 /** 389 /**
390 * A matcher that matches a function call against no exception. 390 * A matcher that matches a function call against no exception.
391 * The function will be called once. Any exceptions will be silently swallowed. 391 * The function will be called once. Any exceptions will be silently swallowed.
392 * The value passed to expect() should be a reference to the function. 392 * The value passed to expect() should be a reference to the function.
393 * Note that the function cannot take arguments; to handle this 393 * Note that the function cannot take arguments; to handle this
394 * a wrapper will have to be created. 394 * a wrapper will have to be created.
395 */ 395 */
396 const Matcher returnsNormally = const _ReturnsNormally(); 396 const Matcher returnsNormally = const _ReturnsNormally();
397 397
398 class Throws extends BaseMatcher { 398 class Throws extends Matcher {
399 final Matcher _matcher; 399 final Matcher _matcher;
400 400
401 const Throws([Matcher matcher]) : 401 const Throws([Matcher matcher]) :
402 this._matcher = matcher; 402 this._matcher = matcher;
403 403
404 bool matches(item, Map matchState) { 404 bool matches(item, Map matchState) {
405 if (item is! Function && item is! Future) return false; 405 if (item is! Function && item is! Future) return false;
406 if (item is Future) { 406 if (item is Future) {
407 var done = wrapAsync((fn) => fn()); 407 var done = wrapAsync((fn) => fn());
408 408
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 mismatchDescription. add('threw '). 459 mismatchDescription. add('threw ').
460 addDescriptionOf(matchState['exception']); 460 addDescriptionOf(matchState['exception']);
461 if (verbose) { 461 if (verbose) {
462 mismatchDescription.add(' at ').add(matchState['stack'].toString()); 462 mismatchDescription.add(' at ').add(matchState['stack'].toString());
463 } 463 }
464 return mismatchDescription; 464 return mismatchDescription;
465 } 465 }
466 } 466 }
467 } 467 }
468 468
469 class _ReturnsNormally extends BaseMatcher { 469 class _ReturnsNormally extends Matcher {
470 const _ReturnsNormally(); 470 const _ReturnsNormally();
471 471
472 bool matches(f, Map matchState) { 472 bool matches(f, Map matchState) {
473 try { 473 try {
474 f(); 474 f();
475 return true; 475 return true;
476 } catch (e, s) { 476 } catch (e, s) {
477 addStateInfo(matchState, {'exception': e, 'stack': s}); 477 addStateInfo(matchState, {'exception': e, 'stack': s});
478 return false; 478 return false;
479 } 479 }
(...skipping 27 matching lines...) Expand all
507 * 507 *
508 * bool _isException(x) => x is Exception; 508 * bool _isException(x) => x is Exception;
509 * final Matcher isException = const _Predicate(_isException, "Exception"); 509 * final Matcher isException = const _Predicate(_isException, "Exception");
510 * final Matcher throwsException = const _Throws(isException); 510 * final Matcher throwsException = const _Throws(isException);
511 * 511 *
512 * But currently using static functions in const expressions is not supported. 512 * But currently using static functions in const expressions is not supported.
513 * For now the only solution for all platforms seems to be separate classes 513 * For now the only solution for all platforms seems to be separate classes
514 * for each exception type. 514 * for each exception type.
515 */ 515 */
516 516
517 abstract class TypeMatcher extends BaseMatcher { 517 abstract class TypeMatcher extends Matcher {
518 final String _name; 518 final String _name;
519 const TypeMatcher(this._name); 519 const TypeMatcher(this._name);
520 Description describe(Description description) => 520 Description describe(Description description) =>
521 description.add(_name); 521 description.add(_name);
522 } 522 }
523 523
524 /** A matcher for FormatExceptions. */ 524 /** A matcher for FormatExceptions. */
525 const isFormatException = const _FormatException(); 525 const isFormatException = const _FormatException();
526 526
527 /** A matcher for functions that throw FormatException. */ 527 /** A matcher for functions that throw FormatException. */
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
633 bool matches(item, Map matchState) => item is List; 633 bool matches(item, Map matchState) => item is List;
634 } 634 }
635 635
636 /** 636 /**
637 * Returns a matcher that matches if an object has a length property 637 * Returns a matcher that matches if an object has a length property
638 * that matches [matcher]. 638 * that matches [matcher].
639 */ 639 */
640 Matcher hasLength(matcher) => 640 Matcher hasLength(matcher) =>
641 new _HasLength(wrapMatcher(matcher)); 641 new _HasLength(wrapMatcher(matcher));
642 642
643 class _HasLength extends BaseMatcher { 643 class _HasLength extends Matcher {
644 final Matcher _matcher; 644 final Matcher _matcher;
645 const _HasLength([Matcher matcher = null]) : this._matcher = matcher; 645 const _HasLength([Matcher matcher = null]) : this._matcher = matcher;
646 646
647 bool matches(item, Map matchState) { 647 bool matches(item, Map matchState) {
648 try { 648 try {
649 // This is harmless code that will throw if no length property 649 // This is harmless code that will throw if no length property
650 // but subtle enough that an optimizer shouldn't strip it out. 650 // but subtle enough that an optimizer shouldn't strip it out.
651 if (item.length * item.length >= 0) { 651 if (item.length * item.length >= 0) {
652 return _matcher.matches(item.length, matchState); 652 return _matcher.matches(item.length, matchState);
653 } 653 }
(...skipping 24 matching lines...) Expand all
678 /** 678 /**
679 * Returns a matcher that matches if the match argument contains 679 * Returns a matcher that matches if the match argument contains
680 * the expected value. For [String]s this means substring matching; 680 * the expected value. For [String]s this means substring matching;
681 * for [Map]s it means the map has the key, and for [Iterable]s 681 * for [Map]s it means the map has the key, and for [Iterable]s
682 * (including [Iterable]s) it means the iterable has a matching 682 * (including [Iterable]s) it means the iterable has a matching
683 * element. In the case of iterables, [expected] can itself be a 683 * element. In the case of iterables, [expected] can itself be a
684 * matcher. 684 * matcher.
685 */ 685 */
686 Matcher contains(expected) => new _Contains(expected); 686 Matcher contains(expected) => new _Contains(expected);
687 687
688 class _Contains extends BaseMatcher { 688 class _Contains extends Matcher {
689 689
690 final _expected; 690 final _expected;
691 691
692 const _Contains(this._expected); 692 const _Contains(this._expected);
693 693
694 bool matches(item, Map matchState) { 694 bool matches(item, Map matchState) {
695 if (item is String) { 695 if (item is String) {
696 return item.indexOf(_expected) >= 0; 696 return item.indexOf(_expected) >= 0;
697 } else if (item is Iterable) { 697 } else if (item is Iterable) {
698 if (_expected is Matcher) { 698 if (_expected is Matcher) {
(...skipping 20 matching lines...) Expand all
719 } 719 }
720 } 720 }
721 } 721 }
722 722
723 /** 723 /**
724 * Returns a matcher that matches if the match argument is in 724 * Returns a matcher that matches if the match argument is in
725 * the expected value. This is the converse of [contains]. 725 * the expected value. This is the converse of [contains].
726 */ 726 */
727 Matcher isIn(expected) => new _In(expected); 727 Matcher isIn(expected) => new _In(expected);
728 728
729 class _In extends BaseMatcher { 729 class _In extends Matcher {
730 730
731 final _expected; 731 final _expected;
732 732
733 const _In(this._expected); 733 const _In(this._expected);
734 734
735 bool matches(item, Map matchState) { 735 bool matches(item, Map matchState) {
736 if (_expected is String) { 736 if (_expected is String) {
737 return _expected.indexOf(item) >= 0; 737 return _expected.indexOf(item) >= 0;
738 } else if (_expected is Iterable) { 738 } else if (_expected is Iterable) {
739 return _expected.any((e) => e == item); 739 return _expected.any((e) => e == item);
740 } else if (_expected is Map) { 740 } else if (_expected is Map) {
741 return _expected.containsKey(item); 741 return _expected.containsKey(item);
742 } 742 }
743 return false; 743 return false;
744 } 744 }
745 745
746 Description describe(Description description) => 746 Description describe(Description description) =>
747 description.add('is in ').addDescriptionOf(_expected); 747 description.add('is in ').addDescriptionOf(_expected);
748 } 748 }
749 749
750 /** 750 /**
751 * Returns a matcher that uses an arbitrary function that returns 751 * Returns a matcher that uses an arbitrary function that returns
752 * true or false for the actual value. For example: 752 * true or false for the actual value. For example:
753 * 753 *
754 * expect(v, predicate((x) => ((x % 2) == 0), "is even")) 754 * expect(v, predicate((x) => ((x % 2) == 0), "is even"))
755 */ 755 */
756 Matcher predicate(Function f, [description ='satisfies function']) => 756 Matcher predicate(Function f, [description ='satisfies function']) =>
757 new _Predicate(f, description); 757 new _Predicate(f, description);
758 758
759 class _Predicate extends BaseMatcher { 759 class _Predicate extends Matcher {
760 760
761 final Function _matcher; 761 final Function _matcher;
762 final String _description; 762 final String _description;
763 763
764 const _Predicate(this._matcher, this._description); 764 const _Predicate(this._matcher, this._description);
765 765
766 bool matches(item, Map matchState) => _matcher(item); 766 bool matches(item, Map matchState) => _matcher(item);
767 767
768 Description describe(Description description) => 768 Description describe(Description description) =>
769 description.add(_description); 769 description.add(_description);
770 } 770 }
771 771
772 /** 772 /**
773 * A useful utility class for implementing other matchers through inheritance. 773 * A useful utility class for implementing other matchers through inheritance.
774 * Derived classes should call the base constructor with a feature name and 774 * Derived classes should call the base constructor with a feature name and
775 * description, and an instance matcher, and should implement the 775 * description, and an instance matcher, and should implement the
776 * [featureValueOf] abstract method. 776 * [featureValueOf] abstract method.
777 * 777 *
778 * The feature description will typically describe the item and the feature, 778 * The feature description will typically describe the item and the feature,
779 * while the feature name will just name the feature. For example, we may 779 * while the feature name will just name the feature. For example, we may
780 * have a Widget class where each Widget has a price; we could make a 780 * have a Widget class where each Widget has a price; we could make a
781 * FeatureMatcher that can make assertions about prices with: 781 * FeatureMatcher that can make assertions about prices with:
782 * 782 *
783 * class HasPrice extends FeatureMatcher { 783 * class HasPrice extends CustomMatcher {
784 * const HasPrice(matcher) : 784 * const HasPrice(matcher) :
785 * super("Widget with price that is", "price", matcher); 785 * super("Widget with price that is", "price", matcher);
786 * featureValueOf(actual) => actual.price; 786 * featureValueOf(actual) => actual.price;
787 * } 787 * }
788 * 788 *
789 * and then use this for example like: 789 * and then use this for example like:
790 * 790 *
791 * expect(inventoryItem, new HasPrice(greaterThan(0))); 791 * expect(inventoryItem, new HasPrice(greaterThan(0)));
792 */ 792 */
793 class CustomMatcher extends BaseMatcher { 793 class CustomMatcher extends Matcher {
794 final String _featureDescription; 794 final String _featureDescription;
795 final String _featureName; 795 final String _featureName;
796 final Matcher _matcher; 796 final Matcher _matcher;
797 797
798 CustomMatcher(this._featureDescription, this._featureName, matcher) 798 CustomMatcher(this._featureDescription, this._featureName, matcher)
799 : this._matcher = wrapMatcher(matcher); 799 : this._matcher = wrapMatcher(matcher);
800 800
801 /** Override this to extract the interesting feature.*/ 801 /** Override this to extract the interesting feature.*/
802 featureValueOf(actual) => actual; 802 featureValueOf(actual) => actual;
803 803
(...skipping 14 matching lines...) Expand all
818 var innerDescription = new StringDescription(); 818 var innerDescription = new StringDescription();
819 _matcher.describeMismatch(matchState['feature'], innerDescription, 819 _matcher.describeMismatch(matchState['feature'], innerDescription,
820 matchState['state'], verbose); 820 matchState['state'], verbose);
821 if (innerDescription.length > 0) { 821 if (innerDescription.length > 0) {
822 mismatchDescription.add(' which ').add(innerDescription.toString()); 822 mismatchDescription.add(' which ').add(innerDescription.toString());
823 } 823 }
824 return mismatchDescription; 824 return mismatchDescription;
825 } 825 }
826 } 826 }
827 827
OLDNEW
« no previous file with comments | « pkg/unittest/lib/src/basematcher.dart ('k') | pkg/unittest/lib/src/expect.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698