| 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 |