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 unittest; |
5 | 6 |
6 /** | 7 /** |
7 * Returns a matcher that matches empty strings, maps or collections. | 8 * Returns a matcher that matches empty strings, maps or collections. |
8 */ | 9 */ |
9 const Matcher isEmpty = const _Empty(); | 10 const Matcher isEmpty = const _Empty(); |
10 | 11 |
11 class _Empty extends BaseMatcher { | 12 class _Empty extends BaseMatcher { |
12 const _Empty(); | 13 const _Empty(); |
13 bool matches(item, MatchState matchState) { | 14 bool matches(item, MatchState matchState) { |
14 if (item is Map || item is Collection) { | 15 if (item is Map || item is Collection) { |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 * | 209 * |
209 * For example, to test whether 'bar' is an instance of type | 210 * For example, to test whether 'bar' is an instance of type |
210 * 'Foo', we would write: | 211 * 'Foo', we would write: |
211 * | 212 * |
212 * expect(bar, new isInstanceOf<Foo>()); | 213 * expect(bar, new isInstanceOf<Foo>()); |
213 * | 214 * |
214 * To get better error message, supply a name when creating the | 215 * To get better error message, supply a name when creating the |
215 * Type wrapper; e.g.: | 216 * Type wrapper; e.g.: |
216 * | 217 * |
217 * expect(bar, new isInstanceOf<Foo>('Foo')); | 218 * expect(bar, new isInstanceOf<Foo>('Foo')); |
| 219 * |
| 220 * Note that this does not currently work in dart2js; it will |
| 221 * match any type, and isNot(new isInstanceof<T>()) will always |
| 222 * fail. This is because dart2js currently ignores template type |
| 223 * parameters. |
218 */ | 224 */ |
219 class isInstanceOf<T> extends BaseMatcher { | 225 class isInstanceOf<T> extends BaseMatcher { |
220 final String _name; | 226 final String _name; |
221 const isInstanceOf([name = 'specified type']) : this._name = name; | 227 const isInstanceOf([name = 'specified type']) : this._name = name; |
222 bool matches(obj, MatchState matchState) => obj is T; | 228 bool matches(obj, MatchState matchState) => obj is T; |
223 // The description here is lame :-( | 229 // The description here is lame :-( |
224 Description describe(Description description) => | 230 Description describe(Description description) => |
225 description.add('an instance of ${_name}'); | 231 description.add('an instance of ${_name}'); |
226 } | 232 } |
227 | 233 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
273 | 279 |
274 const Throws([Matcher matcher]) : | 280 const Throws([Matcher matcher]) : |
275 this._matcher = matcher; | 281 this._matcher = matcher; |
276 | 282 |
277 bool matches(item, MatchState matchState) { | 283 bool matches(item, MatchState matchState) { |
278 if (item is Future) { | 284 if (item is Future) { |
279 // Queue up an asynchronous expectation that validates when the future | 285 // Queue up an asynchronous expectation that validates when the future |
280 // completes. | 286 // completes. |
281 item.onComplete(expectAsync1((future) { | 287 item.onComplete(expectAsync1((future) { |
282 if (future.hasValue) { | 288 if (future.hasValue) { |
283 expect(false, isTrue, | 289 expect(false, isTrue, reason: |
284 "Expected future to fail, but succeeded with '${future.value}'."); | 290 "Expected future to fail, but succeeded with '${future.value}'."); |
285 } else if (_matcher != null) { | 291 } else if (_matcher != null) { |
286 var reason; | 292 var reason; |
287 if (future.stackTrace != null) { | 293 if (future.stackTrace != null) { |
288 var stackTrace = future.stackTrace.toString(); | 294 var stackTrace = future.stackTrace.toString(); |
289 stackTrace = " ${stackTrace.replaceAll("\n", "\n ")}"; | 295 stackTrace = " ${stackTrace.replaceAll("\n", "\n ")}"; |
290 reason = "Actual exception trace:\n$stackTrace"; | 296 reason = "Actual exception trace:\n$stackTrace"; |
291 } | 297 } |
292 expect(future.exception, _matcher, reason); | 298 expect(future.exception, _matcher, reason: reason); |
293 } | 299 } |
294 })); | 300 })); |
295 | 301 |
296 // It hasn't failed yet. | 302 // It hasn't failed yet. |
297 return true; | 303 return true; |
298 } | 304 } |
299 | 305 |
300 try { | 306 try { |
301 item(); | 307 item(); |
302 return false; | 308 return false; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 * | 392 * |
387 * bool _isException(x) => x is Exception; | 393 * bool _isException(x) => x is Exception; |
388 * final Matcher isException = const _Predicate(_isException, "Exception"); | 394 * final Matcher isException = const _Predicate(_isException, "Exception"); |
389 * final Matcher throwsException = const _Throws(isException); | 395 * final Matcher throwsException = const _Throws(isException); |
390 * | 396 * |
391 * But currently using static functions in const expressions is not supported. | 397 * But currently using static functions in const expressions is not supported. |
392 * For now the only solution for all platforms seems to be separate classes | 398 * For now the only solution for all platforms seems to be separate classes |
393 * for each exception type. | 399 * for each exception type. |
394 */ | 400 */ |
395 | 401 |
396 abstract class ExceptionMatcher extends BaseMatcher { | 402 abstract class TypeMatcher extends BaseMatcher { |
397 final String _name; | 403 final String _name; |
398 const ExceptionMatcher(this._name); | 404 const TypeMatcher(this._name); |
399 Description describe(Description description) => | 405 Description describe(Description description) => |
400 description.add(_name); | 406 description.add(_name); |
401 } | 407 } |
402 | 408 |
403 /** A matcher for FormatExceptions. */ | 409 /** A matcher for FormatExceptions. */ |
404 const isFormatException = const _FormatException(); | 410 const isFormatException = const _FormatException(); |
405 | 411 |
406 /** A matcher for functions that throw FormatException */ | 412 /** A matcher for functions that throw FormatException. */ |
407 const Matcher throwsFormatException = | 413 const Matcher throwsFormatException = |
408 const Throws(isFormatException); | 414 const Throws(isFormatException); |
409 | 415 |
410 class _FormatException extends ExceptionMatcher { | 416 class _FormatException extends TypeMatcher { |
411 const _FormatException() : super("FormatException"); | 417 const _FormatException() : super("FormatException"); |
412 bool matches(item, MatchState matchState) => item is FormatException; | 418 bool matches(item, MatchState matchState) => item is FormatException; |
413 } | 419 } |
414 | 420 |
415 /** A matcher for Exceptions. */ | 421 /** A matcher for Exceptions. */ |
416 const isException = const _Exception(); | 422 const isException = const _Exception(); |
417 | 423 |
418 /** A matcher for functions that throw Exception */ | 424 /** A matcher for functions that throw Exception. */ |
419 const Matcher throwsException = const Throws(isException); | 425 const Matcher throwsException = const Throws(isException); |
420 | 426 |
421 class _Exception extends ExceptionMatcher { | 427 class _Exception extends TypeMatcher { |
422 const _Exception() : super("Exception"); | 428 const _Exception() : super("Exception"); |
423 bool matches(item, MatchState matchState) => item is Exception; | 429 bool matches(item, MatchState matchState) => item is Exception; |
424 } | 430 } |
425 | 431 |
426 /** A matcher for ArgumentErrors. */ | 432 /** A matcher for ArgumentErrors. */ |
427 const isArgumentError = const _ArgumentError(); | 433 const isArgumentError = const _ArgumentError(); |
428 | 434 |
429 /** A matcher for functions that throw ArgumentError */ | 435 /** A matcher for functions that throw ArgumentError. */ |
430 const Matcher throwsArgumentError = | 436 const Matcher throwsArgumentError = |
431 const Throws(isArgumentError); | 437 const Throws(isArgumentError); |
432 | 438 |
433 class _ArgumentError extends ExceptionMatcher { | 439 class _ArgumentError extends TypeMatcher { |
434 const _ArgumentError() : super("ArgumentError"); | 440 const _ArgumentError() : super("ArgumentError"); |
435 bool matches(item, MatchState matchState) => item is ArgumentError; | 441 bool matches(item, MatchState matchState) => item is ArgumentError; |
436 } | 442 } |
437 | 443 |
438 /** A matcher for IllegalJSRegExpExceptions. */ | 444 /** A matcher for IllegalJSRegExpExceptions. */ |
439 const isIllegalJSRegExpException = const _IllegalJSRegExpException(); | 445 const isIllegalJSRegExpException = const _IllegalJSRegExpException(); |
440 | 446 |
441 /** A matcher for functions that throw IllegalJSRegExpException */ | 447 /** A matcher for functions that throw IllegalJSRegExpException. */ |
442 const Matcher throwsIllegalJSRegExpException = | 448 const Matcher throwsIllegalJSRegExpException = |
443 const Throws(isIllegalJSRegExpException); | 449 const Throws(isIllegalJSRegExpException); |
444 | 450 |
445 class _IllegalJSRegExpException extends ExceptionMatcher { | 451 class _IllegalJSRegExpException extends TypeMatcher { |
446 const _IllegalJSRegExpException() : super("IllegalJSRegExpException"); | 452 const _IllegalJSRegExpException() : super("IllegalJSRegExpException"); |
447 bool matches(item, MatchState matchState) => item is IllegalJSRegExpException; | 453 bool matches(item, MatchState matchState) => item is IllegalJSRegExpException; |
448 } | 454 } |
449 | 455 |
450 /** A matcher for IndexOutOfRangeExceptions. */ | 456 /** A matcher for IndexOutOfRangeExceptions. */ |
451 const isIndexOutOfRangeException = const _IndexOutOfRangeException(); | 457 const isIndexOutOfRangeException = const _IndexOutOfRangeException(); |
452 | 458 |
453 /** A matcher for functions that throw IndexOutOfRangeException */ | 459 /** A matcher for functions that throw IndexOutOfRangeException. */ |
454 const Matcher throwsIndexOutOfRangeException = | 460 const Matcher throwsIndexOutOfRangeException = |
455 const Throws(isIndexOutOfRangeException); | 461 const Throws(isIndexOutOfRangeException); |
456 | 462 |
457 class _IndexOutOfRangeException extends ExceptionMatcher { | 463 class _IndexOutOfRangeException extends TypeMatcher { |
458 const _IndexOutOfRangeException() : super("IndexOutOfRangeException"); | 464 const _IndexOutOfRangeException() : super("IndexOutOfRangeException"); |
459 bool matches(item, MatchState matchState) => item is IndexOutOfRangeException; | 465 bool matches(item, MatchState matchState) => item is IndexOutOfRangeException; |
460 } | 466 } |
461 | 467 |
462 /** A matcher for NoSuchMethodErrors. */ | 468 /** A matcher for NoSuchMethodErrors. */ |
463 const isNoSuchMethodError = const _NoSuchMethodError(); | 469 const isNoSuchMethodError = const _NoSuchMethodError(); |
464 | 470 |
465 /** A matcher for functions that throw NoSuchMethodError */ | 471 /** A matcher for functions that throw NoSuchMethodError. */ |
466 const Matcher throwsNoSuchMethodError = | 472 const Matcher throwsNoSuchMethodError = |
467 const Throws(isNoSuchMethodError); | 473 const Throws(isNoSuchMethodError); |
468 | 474 |
469 class _NoSuchMethodError extends ExceptionMatcher { | 475 class _NoSuchMethodError extends TypeMatcher { |
470 const _NoSuchMethodError() : super("NoSuchMethodError"); | 476 const _NoSuchMethodError() : super("NoSuchMethodError"); |
471 bool matches(item, MatchState matchState) => item is NoSuchMethodError; | 477 bool matches(item, MatchState matchState) => item is NoSuchMethodError; |
472 } | 478 } |
473 | 479 |
474 /** A matcher for NotImplementedExceptions. */ | 480 /** A matcher for NotImplementedExceptions. */ |
475 const isNotImplementedException = const _NotImplementedException(); | 481 const isNotImplementedException = const _NotImplementedException(); |
476 | 482 |
477 /** A matcher for functions that throw Exception */ | 483 /** A matcher for functions that throw Exception. */ |
478 const Matcher throwsNotImplementedException = | 484 const Matcher throwsNotImplementedException = |
479 const Throws(isNotImplementedException); | 485 const Throws(isNotImplementedException); |
480 | 486 |
481 class _NotImplementedException extends ExceptionMatcher { | 487 class _NotImplementedException extends TypeMatcher { |
482 const _NotImplementedException() : super("NotImplementedException"); | 488 const _NotImplementedException() : super("NotImplementedException"); |
483 bool matches(item, MatchState matchState) => item is NotImplementedException; | 489 bool matches(item, MatchState matchState) => item is NotImplementedException; |
484 } | 490 } |
485 | 491 |
486 /** A matcher for NullPointerExceptions. */ | 492 /** A matcher for NullPointerExceptions. */ |
487 const isNullPointerException = const _NullPointerException(); | 493 const isNullPointerException = const _NullPointerException(); |
488 | 494 |
489 /** A matcher for functions that throw NotNullPointerException */ | 495 /** A matcher for functions that throw NotNullPointerException. */ |
490 const Matcher throwsNullPointerException = | 496 const Matcher throwsNullPointerException = |
491 const Throws(isNullPointerException); | 497 const Throws(isNullPointerException); |
492 | 498 |
493 class _NullPointerException extends ExceptionMatcher { | 499 class _NullPointerException extends TypeMatcher { |
494 const _NullPointerException() : super("NullPointerException"); | 500 const _NullPointerException() : super("NullPointerException"); |
495 bool matches(item, MatchState matchState) => item is NullPointerException; | 501 bool matches(item, MatchState matchState) => item is NullPointerException; |
496 } | 502 } |
497 | 503 |
498 /** A matcher for UnsupportedErrors. */ | 504 /** A matcher for UnsupportedError. */ |
499 const isUnsupportedError = const _UnsupportedError(); | 505 const isUnsupportedError = const _UnsupportedError(); |
500 | 506 |
501 /** A matcher for functions that throw UnsupportedError */ | 507 /** A matcher for functions that throw UnsupportedError. */ |
502 const Matcher throwsUnsupportedError = | 508 const Matcher throwsUnsupportedError = const Throws(isUnsupportedError); |
503 const Throws(isUnsupportedError); | |
504 | 509 |
505 class _UnsupportedError extends ExceptionMatcher { | 510 class _UnsupportedError extends TypeMatcher { |
506 const _UnsupportedError() : | 511 const _UnsupportedError() : |
507 super("UnsupportedError"); | 512 super("UnsupportedError"); |
508 bool matches(item, MatchState matchState) => | 513 bool matches(item, MatchState matchState) => item is UnsupportedError; |
509 item is UnsupportedError; | 514 } |
| 515 |
| 516 /** A matcher for Map types. */ |
| 517 const isMap = const _IsMap(); |
| 518 |
| 519 class _IsMap extends TypeMatcher { |
| 520 const _IsMap() : super("Map"); |
| 521 bool matches(item, MatchState matchState) => item is Map; |
| 522 } |
| 523 |
| 524 /** A matcher for List types. */ |
| 525 const isList = const _IsList(); |
| 526 |
| 527 class _IsList extends TypeMatcher { |
| 528 const _IsList() : super("List"); |
| 529 bool matches(item, MatchState matchState) => item is List; |
510 } | 530 } |
511 | 531 |
512 /** | 532 /** |
513 * Returns a matcher that matches if an object has a length property | 533 * Returns a matcher that matches if an object has a length property |
514 * that matches [matcher]. | 534 * that matches [matcher]. |
515 */ | 535 */ |
516 Matcher hasLength(matcher) => | 536 Matcher hasLength(matcher) => |
517 new _HasLength(wrapMatcher(matcher)); | 537 new _HasLength(wrapMatcher(matcher)); |
518 | 538 |
519 class _HasLength extends BaseMatcher { | 539 class _HasLength extends BaseMatcher { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 } | 623 } |
604 | 624 |
605 Description describe(Description description) => | 625 Description describe(Description description) => |
606 description.add('is in ').addDescriptionOf(_expected); | 626 description.add('is in ').addDescriptionOf(_expected); |
607 } | 627 } |
608 | 628 |
609 /** | 629 /** |
610 * Returns a matcher that uses an arbitrary function that returns | 630 * Returns a matcher that uses an arbitrary function that returns |
611 * true or false for the actual value. | 631 * true or false for the actual value. |
612 */ | 632 */ |
613 Matcher predicate(f, {description: 'satisfies function'}) => | 633 Matcher predicate(f, [description ='satisfies function']) => |
614 new _Predicate(f, description); | 634 new _Predicate(f, description); |
615 | 635 |
616 class _Predicate extends BaseMatcher { | 636 class _Predicate extends BaseMatcher { |
617 | 637 |
618 final _matcher; | 638 final _matcher; |
619 final String _description; | 639 final String _description; |
620 | 640 |
621 const _Predicate(this._matcher, this._description); | 641 const _Predicate(this._matcher, this._description); |
622 | 642 |
623 bool matches(item, MatchState matchState) => _matcher(item); | 643 bool matches(item, MatchState matchState) => _matcher(item); |
(...skipping 16 matching lines...) Expand all Loading... |
640 * class HasPrice extends FeatureMatcher { | 660 * class HasPrice extends FeatureMatcher { |
641 * const HasPrice(matcher) : | 661 * const HasPrice(matcher) : |
642 * super("Widget with price that is", "price", matcher); | 662 * super("Widget with price that is", "price", matcher); |
643 * featureValueOf(actual) => actual.price; | 663 * featureValueOf(actual) => actual.price; |
644 * } | 664 * } |
645 * | 665 * |
646 * and then use this for example like: | 666 * and then use this for example like: |
647 * | 667 * |
648 * expect(inventoryItem, new HasPrice(greaterThan(0))); | 668 * expect(inventoryItem, new HasPrice(greaterThan(0))); |
649 */ | 669 */ |
650 abstract class CustomMatcher extends BaseMatcher { | 670 class CustomMatcher extends BaseMatcher { |
651 final String _featureDescription; | 671 final String _featureDescription; |
652 final String _featureName; | 672 final String _featureName; |
653 final Matcher _matcher; | 673 final Matcher _matcher; |
654 | 674 |
655 const CustomMatcher(this._featureDescription, this._featureName, | 675 const CustomMatcher(this._featureDescription, this._featureName, |
656 this._matcher); | 676 this._matcher); |
657 | 677 |
658 /** Implement this to extract the interesting feature.*/ | 678 /** Override this to extract the interesting feature.*/ |
659 featureValueOf(actual); | 679 featureValueOf(actual) => actual; |
660 | 680 |
661 bool matches(item, MatchState matchState) { | 681 bool matches(item, MatchState matchState) { |
662 var f = featureValueOf(item); | 682 var f = featureValueOf(item); |
663 if (_matcher.matches(f, matchState)) return true; | 683 if (_matcher.matches(f, matchState)) return true; |
664 matchState.state = { 'innerState': matchState.state, 'feature': f }; | 684 matchState.state = { 'innerState': matchState.state, 'feature': f }; |
665 return false; | 685 return false; |
666 } | 686 } |
667 | 687 |
668 Description describe(Description description) => | 688 Description describe(Description description) => |
669 description.add(_featureDescription).add(' ').addDescriptionOf(_matcher); | 689 description.add(_featureDescription).add(' ').addDescriptionOf(_matcher); |
670 | 690 |
671 Description describeMismatch(item, Description mismatchDescription, | 691 Description describeMismatch(item, Description mismatchDescription, |
672 MatchState matchState, bool verbose) { | 692 MatchState matchState, bool verbose) { |
673 mismatchDescription.add(_featureName).add(' '); | 693 mismatchDescription.add(_featureName).add(' '); |
674 _matcher.describeMismatch(matchState.state['feature'], mismatchDescription, | 694 _matcher.describeMismatch(matchState.state['feature'], mismatchDescription, |
675 matchState.state['innerState'], verbose); | 695 matchState.state['innerState'], verbose); |
676 return mismatchDescription; | 696 return mismatchDescription; |
677 } | 697 } |
678 } | 698 } |
OLD | NEW |