| 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 /** | 5 /** |
| 6 * The error formatter for mocking is a bit different from the default one | 6 * The error formatter for mocking is a bit different from the default one |
| 7 * for unit testing; instead of the third argument being a 'reason' | 7 * for unit testing; instead of the third argument being a 'reason' |
| 8 * it is instead a [signature] describing the method signature filter | 8 * it is instead a [signature] describing the method signature filter |
| 9 * that was used to select the logs that were verified. | 9 * that was used to select the logs that were verified. |
| 10 */ | 10 */ |
| 11 String _mockingErrorFormatter(actual, Matcher matcher, String signature) { | 11 String _mockingErrorFormatter(actual, Matcher matcher, String signature, |
| 12 MatchState matchState, bool verbose) { |
| 12 var description = new StringDescription(); | 13 var description = new StringDescription(); |
| 13 description.add('Expected ${signature} ').addDescriptionOf(matcher). | 14 description.add('Expected ${signature} ').addDescriptionOf(matcher). |
| 14 add('\n but: '); | 15 add('\n but: '); |
| 15 matcher.describeMismatch(actual, description).add('.'); | 16 matcher.describeMismatch(actual, description, matchState, verbose).add('.'); |
| 16 return description.toString(); | 17 return description.toString(); |
| 17 } | 18 } |
| 18 | 19 |
| 19 /** | 20 /** |
| 20 * The failure handler for the [expect()] calls that occur in [verify()] | 21 * The failure handler for the [expect()] calls that occur in [verify()] |
| 21 * methods in the mock objects. This calls the real failure handler used | 22 * methods in the mock objects. This calls the real failure handler used |
| 22 * by the unit test library after formatting the error message with | 23 * by the unit test library after formatting the error message with |
| 23 * the custom formatter. | 24 * the custom formatter. |
| 24 */ | 25 */ |
| 25 class _MockFailureHandler implements FailureHandler { | 26 class _MockFailureHandler implements FailureHandler { |
| 26 FailureHandler proxy; | 27 FailureHandler proxy; |
| 27 _MockFailureHandler(this.proxy); | 28 _MockFailureHandler(this.proxy); |
| 28 void fail(String reason) { | 29 void fail(String reason) { |
| 29 proxy.fail(reason); | 30 proxy.fail(reason); |
| 30 } | 31 } |
| 31 void failMatch(actual, Matcher matcher, String reason) { | 32 void failMatch(actual, Matcher matcher, String reason, |
| 32 proxy.fail(_mockingErrorFormatter(actual, matcher, reason)); | 33 MatchState matchState, bool verbose) { |
| 34 proxy.fail(_mockingErrorFormatter(actual, matcher, reason, |
| 35 matchState, verbose)); |
| 33 } | 36 } |
| 34 } | 37 } |
| 35 | 38 |
| 36 _MockFailureHandler _mockFailureHandler = null; | 39 _MockFailureHandler _mockFailureHandler = null; |
| 37 | 40 |
| 38 /** | 41 /** |
| 39 * [_noArg] is a sentinel value representing no argument. | 42 * [_noArg] is a sentinel value representing no argument. |
| 40 */ | 43 */ |
| 41 final _noArg = const _Sentinel(); | 44 final _noArg = const _Sentinel(); |
| 42 | 45 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 150 } | 153 } |
| 151 d.add(')'); | 154 d.add(')'); |
| 152 return d.toString(); | 155 return d.toString(); |
| 153 } | 156 } |
| 154 | 157 |
| 155 /** | 158 /** |
| 156 * Given a [method] name and list of [arguments], return true | 159 * Given a [method] name and list of [arguments], return true |
| 157 * if it matches this [CallMatcher. | 160 * if it matches this [CallMatcher. |
| 158 */ | 161 */ |
| 159 bool matches(String method, List arguments) { | 162 bool matches(String method, List arguments) { |
| 160 if (!nameFilter.matches(method)) { | 163 var matchState = new MatchState(); |
| 164 if (!nameFilter.matches(method, matchState)) { |
| 161 return false; | 165 return false; |
| 162 } | 166 } |
| 163 if (arguments.length < argMatchers.length) { | 167 if (arguments.length < argMatchers.length) { |
| 164 throw new Exception("Less arguments than matchers for $method."); | 168 throw new Exception("Less arguments than matchers for $method."); |
| 165 } | 169 } |
| 166 for (var i = 0; i < argMatchers.length; i++) { | 170 for (var i = 0; i < argMatchers.length; i++) { |
| 167 if (!argMatchers[i].matches(arguments[i])) { | 171 if (!argMatchers[i].matches(arguments[i], matchState)) { |
| 168 return false; | 172 return false; |
| 169 } | 173 } |
| 170 } | 174 } |
| 171 return true; | 175 return true; |
| 172 } | 176 } |
| 173 } | 177 } |
| 174 | 178 |
| 175 /** | 179 /** |
| 176 * Returns a [CallMatcher] for the specified signature. [method] can be | 180 * Returns a [CallMatcher] for the specified signature. [method] can be |
| 177 * null to match anything, or a literal [String], a predicate [Function], | 181 * null to match anything, or a literal [String], a predicate [Function], |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 d.add('${time.hour}:${_pad2(time.minute)}:' | 306 d.add('${time.hour}:${_pad2(time.minute)}:' |
| 303 '${_pad2(time.second)}.${time.millisecond}> '); | 307 '${_pad2(time.second)}.${time.millisecond}> '); |
| 304 } else { | 308 } else { |
| 305 // Show relative time. | 309 // Show relative time. |
| 306 int delta = time.millisecondsSinceEpoch - baseTime.millisecondsSinceEpoch; | 310 int delta = time.millisecondsSinceEpoch - baseTime.millisecondsSinceEpoch; |
| 307 int secs = delta ~/ 1000; | 311 int secs = delta ~/ 1000; |
| 308 int msecs = delta % 1000; | 312 int msecs = delta % 1000; |
| 309 d.add('$secs.$msecs> '); | 313 d.add('$secs.$msecs> '); |
| 310 } | 314 } |
| 311 d.add('${_qualifiedName(mockName, methodName)}('); | 315 d.add('${_qualifiedName(mockName, methodName)}('); |
| 312 for (var i = 0; i < args.length; i++) { | 316 if (args != null) { |
| 313 if (i != 0) d.add(', '); | 317 for (var i = 0; i < args.length; i++) { |
| 314 d.addDescriptionOf(args[i]); | 318 if (i != 0) d.add(', '); |
| 319 d.addDescriptionOf(args[i]); |
| 320 } |
| 315 } | 321 } |
| 316 d.add(') ${action == Action.THROW ? "threw" : "returned"} '); | 322 d.add(') ${action == Action.THROW ? "threw" : "returned"} '); |
| 317 d.addDescriptionOf(value); | 323 d.addDescriptionOf(value); |
| 318 return d.toString(); | 324 return d.toString(); |
| 319 } | 325 } |
| 320 } | 326 } |
| 321 | 327 |
| 322 /** Utility function for optionally qualified method names */ | 328 /** Utility function for optionally qualified method names */ |
| 323 String _qualifiedName(owner, String method) { | 329 String _qualifiedName(owner, String method) { |
| 324 if (owner == null || owner === anything) { | 330 if (owner == null || owner === anything) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 385 Matcher actionMatcher, | 391 Matcher actionMatcher, |
| 386 bool destructive = false]) { | 392 bool destructive = false]) { |
| 387 if (mockNameFilter == null) { | 393 if (mockNameFilter == null) { |
| 388 mockNameFilter = anything; | 394 mockNameFilter = anything; |
| 389 } else { | 395 } else { |
| 390 mockNameFilter = wrapMatcher(mockNameFilter); | 396 mockNameFilter = wrapMatcher(mockNameFilter); |
| 391 } | 397 } |
| 392 Function entryFilter = _makePredicate(logFilter); | 398 Function entryFilter = _makePredicate(logFilter); |
| 393 String filterName = _qualifiedName(mockNameFilter, logFilter.toString()); | 399 String filterName = _qualifiedName(mockNameFilter, logFilter.toString()); |
| 394 LogEntryList rtn = new LogEntryList(filterName); | 400 LogEntryList rtn = new LogEntryList(filterName); |
| 401 MatchState matchState = new MatchState(); |
| 395 for (var i = 0; i < logs.length; i++) { | 402 for (var i = 0; i < logs.length; i++) { |
| 396 LogEntry entry = logs[i]; | 403 LogEntry entry = logs[i]; |
| 397 if (mockNameFilter.matches(entry.mockName) && entryFilter(entry)) { | 404 if (mockNameFilter.matches(entry.mockName, matchState) && |
| 398 if (actionMatcher == null || actionMatcher.matches(entry)) { | 405 entryFilter(entry)) { |
| 406 if (actionMatcher == null || |
| 407 actionMatcher.matches(entry, matchState)) { |
| 399 rtn.add(entry); | 408 rtn.add(entry); |
| 400 if (destructive) { | 409 if (destructive) { |
| 401 logs.removeRange(i--, 1); | 410 logs.removeRange(i--, 1); |
| 402 } | 411 } |
| 403 } | 412 } |
| 404 } | 413 } |
| 405 } | 414 } |
| 406 return rtn; | 415 return rtn; |
| 407 } | 416 } |
| 408 | 417 |
| (...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 // we get our first key match). | 696 // we get our first key match). |
| 688 List scratch = null; | 697 List scratch = null; |
| 689 int remainingCount = 0; | 698 int remainingCount = 0; |
| 690 if (isPreceding) { | 699 if (isPreceding) { |
| 691 scratch = new List(); | 700 scratch = new List(); |
| 692 remainingCount = logs.length; | 701 remainingCount = logs.length; |
| 693 } | 702 } |
| 694 | 703 |
| 695 var keyIterator = keys.logs.iterator(); | 704 var keyIterator = keys.logs.iterator(); |
| 696 LogEntry keyEntry = keyIterator.next(); | 705 LogEntry keyEntry = keyIterator.next(); |
| 706 MatchState matchState = new MatchState(); |
| 697 | 707 |
| 698 for (LogEntry logEntry in logs) { | 708 for (LogEntry logEntry in logs) { |
| 699 // If we have a log entry match, copy the saved matches from the | 709 // If we have a log entry match, copy the saved matches from the |
| 700 // scratch buffer into the return list, as well as the matching entry, | 710 // scratch buffer into the return list, as well as the matching entry, |
| 701 // if appropriate, and reset the scratch buffer. Continue processing | 711 // if appropriate, and reset the scratch buffer. Continue processing |
| 702 // from the next key entry. | 712 // from the next key entry. |
| 703 if (keyEntry == logEntry) { | 713 if (keyEntry == logEntry) { |
| 704 if (scratch != null) { | 714 if (scratch != null) { |
| 705 int numToCopy = scratch.length; | 715 int numToCopy = scratch.length; |
| 706 if (distance > 0 && distance < numToCopy) { | 716 if (distance > 0 && distance < numToCopy) { |
| 707 numToCopy = distance; | 717 numToCopy = distance; |
| 708 } | 718 } |
| 709 for (var i = scratch.length - numToCopy; i < scratch.length; i++) { | 719 for (var i = scratch.length - numToCopy; i < scratch.length; i++) { |
| 710 rtn.logs.add(scratch[i]); | 720 rtn.logs.add(scratch[i]); |
| 711 } | 721 } |
| 712 scratch.clear(); | 722 scratch.clear(); |
| 713 } else { | 723 } else { |
| 714 remainingCount = distance > 0 ? distance : logs.length; | 724 remainingCount = distance > 0 ? distance : logs.length; |
| 715 } | 725 } |
| 716 if (includeKeys) { | 726 if (includeKeys) { |
| 717 rtn.logs.add(keyEntry); | 727 rtn.logs.add(keyEntry); |
| 718 } | 728 } |
| 719 if (keyIterator.hasNext()) { | 729 if (keyIterator.hasNext()) { |
| 720 keyEntry = keyIterator.next(); | 730 keyEntry = keyIterator.next(); |
| 721 } else if (isPreceding) { // We're done. | 731 } else if (isPreceding) { // We're done. |
| 722 break; | 732 break; |
| 723 } | 733 } |
| 724 } else if (remainingCount > 0 && | 734 } else if (remainingCount > 0 && |
| 725 mockNameFilter.matches(logEntry.mockName) && | 735 mockNameFilter.matches(logEntry.mockName, matchState) && |
| 726 logFilter(logEntry)) { | 736 logFilter(logEntry)) { |
| 727 if (scratch != null) { | 737 if (scratch != null) { |
| 728 scratch.add(logEntry); | 738 scratch.add(logEntry); |
| 729 } else { | 739 } else { |
| 730 rtn.logs.add(logEntry); | 740 rtn.logs.add(logEntry); |
| 731 --remainingCount; | 741 --remainingCount; |
| 732 } | 742 } |
| 733 } | 743 } |
| 734 } | 744 } |
| 735 return rtn; | 745 return rtn; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 791 | 801 |
| 792 /** | 802 /** |
| 793 * [_TimesMatcher]s are used to make assertions about the number of | 803 * [_TimesMatcher]s are used to make assertions about the number of |
| 794 * times a method was called. | 804 * times a method was called. |
| 795 */ | 805 */ |
| 796 class _TimesMatcher extends BaseMatcher { | 806 class _TimesMatcher extends BaseMatcher { |
| 797 final int min, max; | 807 final int min, max; |
| 798 | 808 |
| 799 const _TimesMatcher(this.min, [this.max = -1]); | 809 const _TimesMatcher(this.min, [this.max = -1]); |
| 800 | 810 |
| 801 bool matches(logList) => logList.length >= min && | 811 bool matches(logList, MatchState matchState) => logList.length >= min && |
| 802 (max < 0 || logList.length <= max); | 812 (max < 0 || logList.length <= max); |
| 803 | 813 |
| 804 Description describe(Description description) { | 814 Description describe(Description description) { |
| 805 description.add(' to be called '); | 815 description.add('to be called '); |
| 806 if (max < 0) { | 816 if (max < 0) { |
| 807 description.add('at least $min'); | 817 description.add('at least $min'); |
| 808 } else if (max == min) { | 818 } else if (max == min) { |
| 809 description.add('$max'); | 819 description.add('$max'); |
| 810 } else if (min == 0) { | 820 } else if (min == 0) { |
| 811 description.add('at most $max'); | 821 description.add('at most $max'); |
| 812 } else { | 822 } else { |
| 813 description.add('between $min and $max'); | 823 description.add('between $min and $max'); |
| 814 } | 824 } |
| 815 return description.add(' times'); | 825 return description.add(' times'); |
| 816 } | 826 } |
| 817 | 827 |
| 818 Description describeMismatch(logList, Description mismatchDescription) => | 828 Description describeMismatch(logList, Description mismatchDescription, |
| 829 MatchState matchState, bool verbose) => |
| 819 mismatchDescription.add('was called ${logList.length} times'); | 830 mismatchDescription.add('was called ${logList.length} times'); |
| 820 } | 831 } |
| 821 | 832 |
| 822 /** [happenedExactly] matches an exact number of calls. */ | 833 /** [happenedExactly] matches an exact number of calls. */ |
| 823 Matcher happenedExactly(count) { | 834 Matcher happenedExactly(count) { |
| 824 return new _TimesMatcher(count, count); | 835 return new _TimesMatcher(count, count); |
| 825 } | 836 } |
| 826 | 837 |
| 827 /** [happenedAtLeast] matches a minimum number of calls. */ | 838 /** [happenedAtLeast] matches a minimum number of calls. */ |
| 828 Matcher happenedAtLeast(count) { | 839 Matcher happenedAtLeast(count) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 849 /** | 860 /** |
| 850 * [_ResultMatcher]s are used to make assertions about the results | 861 * [_ResultMatcher]s are used to make assertions about the results |
| 851 * of method calls. These can be used as optional parameters to [getLogs]. | 862 * of method calls. These can be used as optional parameters to [getLogs]. |
| 852 */ | 863 */ |
| 853 class _ResultMatcher extends BaseMatcher { | 864 class _ResultMatcher extends BaseMatcher { |
| 854 final Action action; | 865 final Action action; |
| 855 final Matcher value; | 866 final Matcher value; |
| 856 | 867 |
| 857 const _ResultMatcher(this.action, this.value); | 868 const _ResultMatcher(this.action, this.value); |
| 858 | 869 |
| 859 bool matches(item) { | 870 bool matches(item, MatchState matchState) { |
| 860 if (item is! LogEntry) { | 871 if (item is! LogEntry) { |
| 861 return false; | 872 return false; |
| 862 } | 873 } |
| 863 // normalize the action; _PROXY is like _RETURN. | 874 // normalize the action; _PROXY is like _RETURN. |
| 864 Action eaction = item.action; | 875 Action eaction = item.action; |
| 865 if (eaction == Action.PROXY) { | 876 if (eaction == Action.PROXY) { |
| 866 eaction = Action.RETURN; | 877 eaction = Action.RETURN; |
| 867 } | 878 } |
| 868 return (eaction == action && value.matches(item.value)); | 879 return (eaction == action && value.matches(item.value, matchState)); |
| 869 } | 880 } |
| 870 | 881 |
| 871 Description describe(Description description) { | 882 Description describe(Description description) { |
| 872 description.add(' to '); | 883 description.add(' to '); |
| 873 if (action == Action.RETURN || action == Action.PROXY) | 884 if (action == Action.RETURN || action == Action.PROXY) |
| 874 description.add('return '); | 885 description.add('return '); |
| 875 else | 886 else |
| 876 description.add('throw '); | 887 description.add('throw '); |
| 877 return description.addDescriptionOf(value); | 888 return description.addDescriptionOf(value); |
| 878 } | 889 } |
| 879 | 890 |
| 880 Description describeMismatch(item, Description mismatchDescription) { | 891 Description describeMismatch(item, Description mismatchDescription, |
| 892 MatchState matchState, bool verbose) { |
| 881 if (item.action == Action.RETURN || item.action == Action.PROXY) { | 893 if (item.action == Action.RETURN || item.action == Action.PROXY) { |
| 882 mismatchDescription.add('returned '); | 894 mismatchDescription.add('returned '); |
| 883 } else { | 895 } else { |
| 884 mismatchDescription.add('threw '); | 896 mismatchDescription.add('threw '); |
| 885 } | 897 } |
| 886 mismatchDescription.add(item.value); | 898 mismatchDescription.add(item.value); |
| 887 return mismatchDescription; | 899 return mismatchDescription; |
| 888 } | 900 } |
| 889 } | 901 } |
| 890 | 902 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 928 * We could make this class use _ResultMatcher but it doesn't buy that | 940 * We could make this class use _ResultMatcher but it doesn't buy that |
| 929 * match and adds some perf hit, so there is some duplication here. | 941 * match and adds some perf hit, so there is some duplication here. |
| 930 */ | 942 */ |
| 931 class _ResultSetMatcher extends BaseMatcher { | 943 class _ResultSetMatcher extends BaseMatcher { |
| 932 final Action action; | 944 final Action action; |
| 933 final Matcher value; | 945 final Matcher value; |
| 934 final _Frequency frequency; // ALL, SOME, or NONE. | 946 final _Frequency frequency; // ALL, SOME, or NONE. |
| 935 | 947 |
| 936 const _ResultSetMatcher(this.action, this.value, this.frequency); | 948 const _ResultSetMatcher(this.action, this.value, this.frequency); |
| 937 | 949 |
| 938 bool matches(logList) { | 950 bool matches(logList, MatchState matchState) { |
| 939 for (LogEntry entry in logList) { | 951 for (LogEntry entry in logList) { |
| 940 // normalize the action; PROXY is like RETURN. | 952 // normalize the action; PROXY is like RETURN. |
| 941 Action eaction = entry.action; | 953 Action eaction = entry.action; |
| 942 if (eaction == Action.PROXY) { | 954 if (eaction == Action.PROXY) { |
| 943 eaction = Action.RETURN; | 955 eaction = Action.RETURN; |
| 944 } | 956 } |
| 945 if (eaction == action && value.matches(entry.value)) { | 957 if (eaction == action && value.matches(entry.value, matchState)) { |
| 946 if (frequency == _Frequency.NONE) { | 958 if (frequency == _Frequency.NONE) { |
| 959 matchState.state = { |
| 960 'state' : matchState.state, |
| 961 'entry' : entry |
| 962 }; |
| 947 return false; | 963 return false; |
| 948 } else if (frequency == _Frequency.SOME) { | 964 } else if (frequency == _Frequency.SOME) { |
| 949 return true; | 965 return true; |
| 950 } | 966 } |
| 951 } else { | 967 } else { |
| 952 // Mismatch. | 968 // Mismatch. |
| 953 if (frequency == _Frequency.ALL) { // We need just one mismatch to fail. | 969 if (frequency == _Frequency.ALL) { // We need just one mismatch to fail. |
| 970 matchState.state = { |
| 971 'state' : matchState.state, |
| 972 'entry' : entry |
| 973 }; |
| 954 return false; | 974 return false; |
| 955 } | 975 } |
| 956 } | 976 } |
| 957 } | 977 } |
| 958 // If we get here, then if count is _ALL we got all matches and | 978 // If we get here, then if count is _ALL we got all matches and |
| 959 // this is success; otherwise we got all mismatched which is | 979 // this is success; otherwise we got all mismatched which is |
| 960 // success for count == _NONE and failure for count == _SOME. | 980 // success for count == _NONE and failure for count == _SOME. |
| 961 return (frequency != _Frequency.SOME); | 981 return (frequency != _Frequency.SOME); |
| 962 } | 982 } |
| 963 | 983 |
| 964 Description describe(Description description) { | 984 Description describe(Description description) { |
| 965 description.add(' to '); | 985 description.add(' to '); |
| 966 description.add(frequency == _Frequency.ALL ? 'alway ' : | 986 description.add(frequency == _Frequency.ALL ? 'alway ' : |
| 967 (frequency == _Frequency.NONE ? 'never ' : 'sometimes ')); | 987 (frequency == _Frequency.NONE ? 'never ' : 'sometimes ')); |
| 968 if (action == Action.RETURN || action == Action.PROXY) | 988 if (action == Action.RETURN || action == Action.PROXY) |
| 969 description.add('return '); | 989 description.add('return '); |
| 970 else | 990 else |
| 971 description.add('throw '); | 991 description.add('throw '); |
| 972 return description.addDescriptionOf(value); | 992 return description.addDescriptionOf(value); |
| 973 } | 993 } |
| 974 | 994 |
| 975 Description describeMismatch(logList, Description mismatchDescription) { | 995 Description describeMismatch(logList, Description mismatchDescription, |
| 996 MatchState matchState, bool verbose) { |
| 976 if (frequency != _Frequency.SOME) { | 997 if (frequency != _Frequency.SOME) { |
| 977 for (LogEntry entry in logList) { | 998 LogEntry entry = matchState.state['entry']; |
| 978 if (entry.action != action || !value.matches(entry.value)) { | 999 if (entry.action == Action.RETURN || entry.action == Action.PROXY) { |
| 979 if (entry.action == Action.RETURN || entry.action == Action.PROXY) | 1000 mismatchDescription.add('returned '); |
| 980 mismatchDescription.add('returned '); | 1001 } else { |
| 981 else | 1002 mismatchDescription.add('threw '); |
| 982 mismatchDescription.add('threw '); | |
| 983 mismatchDescription.add(entry.value); | |
| 984 mismatchDescription.add(' at least once'); | |
| 985 break; | |
| 986 } | |
| 987 } | 1003 } |
| 1004 mismatchDescription.add(entry.value); |
| 1005 mismatchDescription.add(' that '); |
| 1006 value.describeMismatch(entry.value, mismatchDescription, |
| 1007 matchState.state['state'], verbose); |
| 1008 mismatchDescription.add(' at least once'); |
| 988 } else { | 1009 } else { |
| 989 mismatchDescription.add('never did'); | 1010 mismatchDescription.add('never did'); |
| 990 } | 1011 } |
| 991 return mismatchDescription; | 1012 return mismatchDescription; |
| 992 } | 1013 } |
| 993 } | 1014 } |
| 994 | 1015 |
| 995 /** | 1016 /** |
| 996 *[alwaysReturned] asserts that all matching calls to a method returned | 1017 *[alwaysReturned] asserts that all matching calls to a method returned |
| 997 * a value that matched [value]. | 1018 * a value that matched [value]. |
| (...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1191 * of [Behavior]s, and find the first match that still has return | 1212 * of [Behavior]s, and find the first match that still has return |
| 1192 * values available, and then do the action specified by that | 1213 * values available, and then do the action specified by that |
| 1193 * return value. If we find no [Behavior] to apply an exception is | 1214 * return value. If we find no [Behavior] to apply an exception is |
| 1194 * thrown. | 1215 * thrown. |
| 1195 */ | 1216 */ |
| 1196 noSuchMethod(String method, List args) { | 1217 noSuchMethod(String method, List args) { |
| 1197 if (method.startsWith('get:')) { | 1218 if (method.startsWith('get:')) { |
| 1198 method = 'get ${method.substring(4)}'; | 1219 method = 'get ${method.substring(4)}'; |
| 1199 } | 1220 } |
| 1200 bool matchedMethodName = false; | 1221 bool matchedMethodName = false; |
| 1222 MatchState matchState = new MatchState(); |
| 1201 for (String k in _behaviors.getKeys()) { | 1223 for (String k in _behaviors.getKeys()) { |
| 1202 Behavior b = _behaviors[k]; | 1224 Behavior b = _behaviors[k]; |
| 1203 if (b.matcher.nameFilter.matches(method)) { | 1225 if (b.matcher.nameFilter.matches(method, matchState)) { |
| 1204 matchedMethodName = true; | 1226 matchedMethodName = true; |
| 1205 } | 1227 } |
| 1206 if (b.matches(method, args)) { | 1228 if (b.matches(method, args)) { |
| 1207 List actions = b.actions; | 1229 List actions = b.actions; |
| 1208 if (actions == null || actions.length == 0) { | 1230 if (actions == null || actions.length == 0) { |
| 1209 continue; // No return values left in this Behavior. | 1231 continue; // No return values left in this Behavior. |
| 1210 } | 1232 } |
| 1211 // Get the first response. | 1233 // Get the first response. |
| 1212 Responder response = actions[0]; | 1234 Responder response = actions[0]; |
| 1213 // If it is exhausted, remove it from the list. | 1235 // If it is exhausted, remove it from the list. |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1348 arg3 = _noArg, | 1370 arg3 = _noArg, |
| 1349 arg4 = _noArg, | 1371 arg4 = _noArg, |
| 1350 arg5 = _noArg, | 1372 arg5 = _noArg, |
| 1351 arg6 = _noArg, | 1373 arg6 = _noArg, |
| 1352 arg7 = _noArg, | 1374 arg7 = _noArg, |
| 1353 arg8 = _noArg, | 1375 arg8 = _noArg, |
| 1354 arg9 = _noArg]) => | 1376 arg9 = _noArg]) => |
| 1355 getLogs(callsTo(method, arg0, arg1, arg2, arg3, arg4, | 1377 getLogs(callsTo(method, arg0, arg1, arg2, arg3, arg4, |
| 1356 arg5, arg6, arg7, arg8, arg9)); | 1378 arg5, arg6, arg7, arg8, arg9)); |
| 1357 } | 1379 } |
| OLD | NEW |