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 var description = new StringDescription(); | 12 var description = new StringDescription(); |
13 description.add('Expected ${signature} ').addDescriptionOf(matcher). | 13 description.add('Expected ${signature} ').addDescriptionOf(matcher). |
14 add('\n but: '); | 14 add('\n but: '); |
15 matcher.describeMismatch(actual, description); | 15 matcher.describeMismatch(actual, description).add('.'); |
16 return description.toString(); | 16 return description.toString(); |
17 } | 17 } |
18 | 18 |
19 /** | 19 /** |
20 * The failure handler for the [expect()] calls that occur in [verify()] | 20 * The failure handler for the [expect()] calls that occur in [verify()] |
21 * methods in the mock objects. This calls the real failure handler used | 21 * methods in the mock objects. This calls the real failure handler used |
22 * by the unit test library after formatting the error message with | 22 * by the unit test library after formatting the error message with |
23 * the custom formatter. | 23 * the custom formatter. |
24 */ | 24 */ |
25 class _MockFailureHandler implements FailureHandler { | 25 class _MockFailureHandler implements FailureHandler { |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
149 | 149 |
150 /** | 150 /** |
151 * Given a [method] name and list of [arguments], return true | 151 * Given a [method] name and list of [arguments], return true |
152 * if it matches this [CallMatcher. | 152 * if it matches this [CallMatcher. |
153 */ | 153 */ |
154 bool matches(String method, List arguments) { | 154 bool matches(String method, List arguments) { |
155 if (!nameFilter.matches(method)) { | 155 if (!nameFilter.matches(method)) { |
156 return false; | 156 return false; |
157 } | 157 } |
158 if (arguments.length < argMatchers.length) { | 158 if (arguments.length < argMatchers.length) { |
159 throw new Exception("Less arguments than matchers for $method"); | 159 throw new Exception("Less arguments than matchers for $method."); |
160 } | 160 } |
161 for (var i = 0; i < argMatchers.length; i++) { | 161 for (var i = 0; i < argMatchers.length; i++) { |
162 if (!argMatchers[i].matches(arguments[i])) { | 162 if (!argMatchers[i].matches(arguments[i])) { |
163 return false; | 163 return false; |
164 } | 164 } |
165 } | 165 } |
166 return true; | 166 return true; |
167 } | 167 } |
168 } | 168 } |
169 | 169 |
(...skipping 558 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
728 /** The mock name. Needed if the log is shared; optional otherwise. */ | 728 /** The mock name. Needed if the log is shared; optional otherwise. */ |
729 final String name; | 729 final String name; |
730 | 730 |
731 /** The set of [behavior]s supported. */ | 731 /** The set of [behavior]s supported. */ |
732 Map<String,Behavior> behaviors; | 732 Map<String,Behavior> behaviors; |
733 | 733 |
734 /** The [log] of calls made. Only used if [name] is null. */ | 734 /** The [log] of calls made. Only used if [name] is null. */ |
735 LogEntryList log; | 735 LogEntryList log; |
736 | 736 |
737 /** How to handle unknown method calls - swallow or throw. */ | 737 /** How to handle unknown method calls - swallow or throw. */ |
738 final bool throwIfNoBehavior = false; | 738 final bool throwIfNoBehavior; |
739 | |
740 /** Whether to create an audit log or not. */ | |
741 final bool logging; | |
739 | 742 |
740 /** | 743 /** |
741 * Default constructor. Unknown method calls are allowed and logged, | 744 * Default constructor. Unknown method calls are allowed and logged, |
742 * the mock has no name, and has its own log. | 745 * the mock has no name, and has its own log. |
743 */ | 746 */ |
744 Mock() : throwIfNoBehavior = false, name = null { | 747 Mock() : throwIfNoBehavior = false, logging = true, name = null { |
745 log = new LogEntryList(); | 748 log = new LogEntryList(); |
746 behaviors = new Map<String,Behavior>(); | 749 behaviors = new Map<String,Behavior>(); |
747 } | 750 } |
748 | 751 |
749 /** | 752 /** |
750 * This constructor makes a mock that has a [name] and possibly uses | 753 * This constructor makes a mock that has a [name] and possibly uses |
751 * a shared [log]. If [throwIfNoBehavior] is true, any calls to methods | 754 * a shared [log]. If [throwIfNoBehavior] is true, any calls to methods |
752 * that have no defined behaviors will throw an exception; otherwise they | 755 * that have no defined behaviors will throw an exception; otherwise they |
753 * will be allowed and logged (but will not do anything). | 756 * will be allowed and logged (but will not do anything). If [logging] |
757 * is false, no logging will be done (whether or not a [log] is supplied). | |
754 */ | 758 */ |
755 Mock.custom([this.name, | 759 Mock.custom([this.name, |
756 this.log, | 760 this.log, |
757 this.throwIfNoBehavior = false]) { | 761 this.throwIfNoBehavior = false, |
758 if (log == null) { | 762 this.logging = true]) { |
763 if (!logging) { | |
764 log = null; | |
765 } else if (log == null) { | |
759 log = new LogEntryList(); | 766 log = new LogEntryList(); |
760 } | 767 } |
761 behaviors = new Map<String,Behavior>(); | 768 behaviors = new Map<String,Behavior>(); |
762 } | 769 } |
763 | 770 |
764 /** | 771 /** |
765 * [when] is used to create a new or extend an existing [Behavior]. | 772 * [when] is used to create a new or extend an existing [Behavior]. |
766 * A [CallMatcher] [filter] must be supplied, and the [Behavior]s for | 773 * A [CallMatcher] [filter] must be supplied, and the [Behavior]s for |
767 * that signature are returned (being created first if needed). | 774 * that signature are returned (being created first if needed). |
768 * | 775 * |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
809 // Note that for endlessly repeating values, we started the count at | 816 // Note that for endlessly repeating values, we started the count at |
810 // 0, so we get a potentially useful value here, which is the | 817 // 0, so we get a potentially useful value here, which is the |
811 // (negation of) the number of times we returned the value. | 818 // (negation of) the number of times we returned the value. |
812 if (--response.count == 0) { | 819 if (--response.count == 0) { |
813 actions.removeRange(0, 1); | 820 actions.removeRange(0, 1); |
814 } | 821 } |
815 // Do the response. | 822 // Do the response. |
816 _Action action = response.action; | 823 _Action action = response.action; |
817 var value = response.value; | 824 var value = response.value; |
818 if (action == _Action.RETURN) { | 825 if (action == _Action.RETURN) { |
819 log.add(new LogEntry(name, method, args, action, value)); | 826 if (log != null) { |
Siggi Cherem (dart-lang)
2012/07/11 22:46:04
why not continbue using the flag? ('if (logging)'
gram
2012/07/11 23:24:07
You're right - I originally didn't mean to make th
| |
827 log.add(new LogEntry(name, method, args, action, value)); | |
828 } | |
820 return value; | 829 return value; |
821 } else if (action == _Action.THROW) { | 830 } else if (action == _Action.THROW) { |
822 log.add(new LogEntry(name, method, args, action, value)); | 831 if (log != null) { |
832 log.add(new LogEntry(name, method, args, action, value)); | |
833 } | |
823 throw value; | 834 throw value; |
824 } else if (action == _Action.PROXY) { | 835 } else if (action == _Action.PROXY) { |
825 var rtn; | 836 var rtn; |
826 switch (args.length) { | 837 switch (args.length) { |
827 case 0: | 838 case 0: |
828 rtn = value(); | 839 rtn = value(); |
829 break; | 840 break; |
830 case 1: | 841 case 1: |
831 rtn = value(args[0]); | 842 rtn = value(args[0]); |
832 break; | 843 break; |
(...skipping 24 matching lines...) Expand all Loading... | |
857 case 9: | 868 case 9: |
858 rtn = value(args[0], args[1], args[2], args[3], | 869 rtn = value(args[0], args[1], args[2], args[3], |
859 args[4], args[5], args[6], args[7], args[8]); | 870 args[4], args[5], args[6], args[7], args[8]); |
860 break; | 871 break; |
861 case 9: | 872 case 9: |
862 rtn = value(args[0], args[1], args[2], args[3], | 873 rtn = value(args[0], args[1], args[2], args[3], |
863 args[4], args[5], args[6], args[7], args[8], args[9]); | 874 args[4], args[5], args[6], args[7], args[8], args[9]); |
864 break; | 875 break; |
865 default: | 876 default: |
866 throw new Exception( | 877 throw new Exception( |
867 "Cannot proxy calls with more than 10 parameters"); | 878 "Cannot proxy calls with more than 10 parameters."); |
868 } | 879 } |
869 log.add(new LogEntry(name, method, args, action, rtn)); | 880 if (log != null) { |
881 log.add(new LogEntry(name, method, args, action, rtn)); | |
882 } | |
870 return rtn; | 883 return rtn; |
871 } | 884 } |
872 } | 885 } |
873 } | 886 } |
874 if (matchedMethodName) { | 887 if (matchedMethodName) { |
875 // User did specify behavior for this method, but all the | 888 // User did specify behavior for this method, but all the |
876 // actions are exhausted. This is considered an error. | 889 // actions are exhausted. This is considered an error. |
877 throw new Exception('No more actions for method ' | 890 throw new Exception('No more actions for method ' |
878 '${_qualifiedName(name, method)}'); | 891 '${_qualifiedName(name, method)}.'); |
879 } else if (throwIfNoBehavior) { | 892 } else if (throwIfNoBehavior) { |
880 throw new Exception('No behavior specified for method ' | 893 throw new Exception('No behavior specified for method ' |
881 '${_qualifiedName(name, method)}'); | 894 '${_qualifiedName(name, method)}.'); |
882 } | 895 } |
883 // User hasn't specified behavior for this method; we don't throw | 896 // Otherwise user hasn't specified behavior for this method; we don't throw |
884 // so we can underspecify. | 897 // so we can underspecify. |
885 log.add(new LogEntry(name, method, args, _Action.IGNORE)); | 898 if (log != null) { |
899 log.add(new LogEntry(name, method, args, _Action.IGNORE)); | |
900 } | |
886 } | 901 } |
887 | 902 |
888 /** [verifyZeroInteractions] returns true if no calls were made */ | 903 /** [verifyZeroInteractions] returns true if no calls were made */ |
889 bool verifyZeroInteractions() => log.logs.length == 0; | 904 bool verifyZeroInteractions() { |
905 if (log == null) { | |
906 throw new Exception("Can't verify behavior when logging is disabled."); | |
907 } | |
908 return log.logs.length == 0; | |
909 } | |
890 | 910 |
891 /** | 911 /** |
892 * [getLogs] extracts all calls from the call log that match the | 912 * [getLogs] extracts all calls from the call log that match the |
893 * [logFilter] [CallMatcher], and returns the matching list of | 913 * [logFilter] [CallMatcher], and returns the matching list of |
894 * [LogEntry]s. If [destructive] is false (the default) the matching | 914 * [LogEntry]s. If [destructive] is false (the default) the matching |
895 * calls are left in the log, else they are removed. Removal allows | 915 * calls are left in the log, else they are removed. Removal allows |
896 * us to verify a set of interactions and then verify that there are | 916 * us to verify a set of interactions and then verify that there are |
897 * no other interactions left. [actionMatcher] can be used to further | 917 * no other interactions left. [actionMatcher] can be used to further |
898 * restrict the returned logs based on the action the mock performed. | 918 * restrict the returned logs based on the action the mock performed. |
899 * | 919 * |
900 * Typical usage: | 920 * Typical usage: |
901 * | 921 * |
902 * getLogs(callsTo(...)).verify(...); | 922 * getLogs(callsTo(...)).verify(...); |
903 */ | 923 */ |
904 LogEntryList getLogs([CallMatcher logFilter, | 924 LogEntryList getLogs([CallMatcher logFilter, |
905 Matcher actionMatcher, | 925 Matcher actionMatcher, |
906 bool destructive = false]) { | 926 bool destructive = false]) { |
907 return log.getMatches(name, logFilter, actionMatcher, destructive); | 927 if (log == null) { |
928 throw new Exception("Can't retrieve logs when logging is disabled."); | |
929 } else { | |
930 return log.getMatches(name, logFilter, actionMatcher, destructive); | |
931 } | |
908 } | 932 } |
909 } | 933 } |
OLD | NEW |