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

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

Issue 438473002: pkg/matcher: refactored code around data-structure vs execution-based matchers (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 4 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/matcher/lib/matcher.dart ('k') | pkg/matcher/lib/src/error_matchers.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 library matcher.core_matchers; 5 library matcher.core_matchers;
6 6
7 import 'dart:async';
8
9 import 'description.dart'; 7 import 'description.dart';
10 import 'expect.dart';
11 import 'interfaces.dart'; 8 import 'interfaces.dart';
9 import 'util.dart';
12 10
13 /// Returns a matcher that matches empty strings, maps or iterables 11 /// Returns a matcher that matches empty strings, maps or iterables
14 /// (including collections). 12 /// (including collections).
15 const Matcher isEmpty = const _Empty(); 13 const Matcher isEmpty = const _Empty();
16 14
17 class _Empty extends Matcher { 15 class _Empty extends Matcher {
18 const _Empty(); 16 const _Empty();
19 bool matches(item, Map matchState) { 17 bool matches(item, Map matchState) {
20 if (item is Map || item is Iterable) { 18 if (item is Map || item is Iterable) {
21 return item.isEmpty; 19 return item.isEmpty;
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 /// parameters. 381 /// parameters.
384 class isInstanceOf<T> extends Matcher { 382 class isInstanceOf<T> extends Matcher {
385 final String _name; 383 final String _name;
386 const isInstanceOf([name = 'specified type']) : this._name = name; 384 const isInstanceOf([name = 'specified type']) : this._name = name;
387 bool matches(obj, Map matchState) => obj is T; 385 bool matches(obj, Map matchState) => obj is T;
388 // The description here is lame :-( 386 // The description here is lame :-(
389 Description describe(Description description) => 387 Description describe(Description description) =>
390 description.add('an instance of ${_name}'); 388 description.add('an instance of ${_name}');
391 } 389 }
392 390
393 /// This can be used to match two kinds of objects:
394 ///
395 /// * A [Function] that throws an exception when called. The function cannot
396 /// take any arguments. If you want to test that a function expecting
397 /// arguments throws, wrap it in another zero-argument function that calls
398 /// the one you want to test.
399 ///
400 /// * A [Future] that completes with an exception. Note that this creates an
401 /// asynchronous expectation. The call to `expect()` that includes this will
402 /// return immediately and execution will continue. Later, when the future
403 /// completes, the actual expectation will run.
404 const Matcher throws = const Throws();
405
406 /// This can be used to match two kinds of objects:
407 ///
408 /// * A [Function] that throws an exception when called. The function cannot
409 /// take any arguments. If you want to test that a function expecting
410 /// arguments throws, wrap it in another zero-argument function that calls
411 /// the one you want to test.
412 ///
413 /// * A [Future] that completes with an exception. Note that this creates an
414 /// asynchronous expectation. The call to `expect()` that includes this will
415 /// return immediately and execution will continue. Later, when the future
416 /// completes, the actual expectation will run.
417 ///
418 /// In both cases, when an exception is thrown, this will test that the exceptio n
419 /// object matches [matcher]. If [matcher] is not an instance of [Matcher], it
420 /// will implicitly be treated as `equals(matcher)`.
421 Matcher throwsA(matcher) => new Throws(wrapMatcher(matcher));
422
423 /// A matcher that matches a function call against no exception. 391 /// A matcher that matches a function call against no exception.
424 /// The function will be called once. Any exceptions will be silently swallowed. 392 /// The function will be called once. Any exceptions will be silently swallowed.
425 /// The value passed to expect() should be a reference to the function. 393 /// The value passed to expect() should be a reference to the function.
426 /// Note that the function cannot take arguments; to handle this 394 /// Note that the function cannot take arguments; to handle this
427 /// a wrapper will have to be created. 395 /// a wrapper will have to be created.
428 const Matcher returnsNormally = const _ReturnsNormally(); 396 const Matcher returnsNormally = const _ReturnsNormally();
429 397
430 class Throws extends Matcher {
431 final Matcher _matcher;
432
433 const Throws([Matcher matcher]) : this._matcher = matcher;
434
435 bool matches(item, Map matchState) {
436 if (item is! Function && item is! Future) return false;
437 if (item is Future) {
438 var done = wrapAsync((fn) => fn());
439
440 // Queue up an asynchronous expectation that validates when the future
441 // completes.
442 item.then((value) {
443 done(() {
444 fail("Expected future to fail, but succeeded with '$value'.");
445 });
446 }, onError: (error, trace) {
447 done(() {
448 if (_matcher == null) return;
449 var reason;
450 if (trace != null) {
451 var stackTrace = trace.toString();
452 stackTrace = " ${stackTrace.replaceAll("\n", "\n ")}";
453 reason = "Actual exception trace:\n$stackTrace";
454 }
455 expect(error, _matcher, reason: reason);
456 });
457 });
458 // It hasn't failed yet.
459 return true;
460 }
461
462 try {
463 item();
464 return false;
465 } catch (e, s) {
466 if (_matcher == null || _matcher.matches(e, matchState)) {
467 return true;
468 } else {
469 addStateInfo(matchState, {'exception': e, 'stack': s});
470 return false;
471 }
472 }
473 }
474
475 Description describe(Description description) {
476 if (_matcher == null) {
477 return description.add("throws");
478 } else {
479 return description.add('throws ').addDescriptionOf(_matcher);
480 }
481 }
482
483 Description describeMismatch(item, Description mismatchDescription,
484 Map matchState,
485 bool verbose) {
486 if (item is! Function && item is! Future) {
487 return mismatchDescription.add('is not a Function or Future');
488 } else if (_matcher == null || matchState['exception'] == null) {
489 return mismatchDescription.add('did not throw');
490 } else {
491 mismatchDescription. add('threw ').
492 addDescriptionOf(matchState['exception']);
493 if (verbose) {
494 mismatchDescription.add(' at ').add(matchState['stack'].toString());
495 }
496 return mismatchDescription;
497 }
498 }
499 }
500
501 class _ReturnsNormally extends Matcher { 398 class _ReturnsNormally extends Matcher {
502 const _ReturnsNormally(); 399 const _ReturnsNormally();
503 400
504 bool matches(f, Map matchState) { 401 bool matches(f, Map matchState) {
505 try { 402 try {
506 f(); 403 f();
507 return true; 404 return true;
508 } catch (e, s) { 405 } catch (e, s) {
509 addStateInfo(matchState, {'exception': e, 'stack': s}); 406 addStateInfo(matchState, {'exception': e, 'stack': s});
510 return false; 407 return false;
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after
738 addDescriptionOf(matchState['feature']); 635 addDescriptionOf(matchState['feature']);
739 var innerDescription = new StringDescription(); 636 var innerDescription = new StringDescription();
740 _matcher.describeMismatch(matchState['feature'], innerDescription, 637 _matcher.describeMismatch(matchState['feature'], innerDescription,
741 matchState['state'], verbose); 638 matchState['state'], verbose);
742 if (innerDescription.length > 0) { 639 if (innerDescription.length > 0) {
743 mismatchDescription.add(' which ').add(innerDescription.toString()); 640 mismatchDescription.add(' which ').add(innerDescription.toString());
744 } 641 }
745 return mismatchDescription; 642 return mismatchDescription;
746 } 643 }
747 } 644 }
OLDNEW
« no previous file with comments | « pkg/matcher/lib/matcher.dart ('k') | pkg/matcher/lib/src/error_matchers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698