mocha 1.1.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +1 -0
- data/.rubocop.yml +53 -0
- data/.rubocop_todo.yml +27 -0
- data/.yardopts +1 -1
- data/CONTRIBUTING.md +4 -9
- data/COPYING.md +2 -2
- data/Gemfile +27 -0
- data/MIT-LICENSE.md +1 -1
- data/README.md +120 -30
- data/RELEASE.md +393 -1
- data/Rakefile +61 -50
- data/gemfiles/Gemfile.minitest.latest +1 -0
- data/gemfiles/Gemfile.test-unit.latest +1 -0
- data/lib/mocha/any_instance_method.rb +9 -74
- data/lib/mocha/api.rb +85 -69
- data/lib/mocha/argument_iterator.rb +4 -8
- data/lib/mocha/backtrace_filter.rb +3 -7
- data/lib/mocha/block_matcher.rb +31 -0
- data/lib/mocha/cardinality.rb +60 -49
- data/lib/mocha/central.rb +21 -12
- data/lib/mocha/change_state_side_effect.rb +0 -4
- data/lib/mocha/class_methods.rb +19 -20
- data/lib/mocha/configuration.rb +317 -52
- data/lib/mocha/debug.rb +2 -4
- data/lib/mocha/deprecation.rb +8 -11
- data/lib/mocha/detection/mini_test.rb +0 -2
- data/lib/mocha/detection/test_unit.rb +3 -5
- data/lib/mocha/error_with_filtered_backtrace.rb +13 -0
- data/lib/mocha/exception_raiser.rb +4 -6
- data/lib/mocha/expectation.rb +186 -95
- data/lib/mocha/expectation_error.rb +1 -1
- data/lib/mocha/expectation_error_factory.rb +0 -1
- data/lib/mocha/expectation_list.rb +7 -11
- data/lib/mocha/hooks.rb +1 -3
- data/lib/mocha/in_state_ordering_constraint.rb +0 -4
- data/lib/mocha/inspect.rb +30 -38
- data/lib/mocha/instance_method.rb +11 -8
- data/lib/mocha/integration/mini_test/adapter.rb +3 -5
- data/lib/mocha/integration/mini_test/exception_translation.rb +1 -1
- data/lib/mocha/integration/mini_test.rb +10 -31
- data/lib/mocha/integration/monkey_patcher.rb +8 -2
- data/lib/mocha/integration/test_unit/adapter.rb +8 -9
- data/lib/mocha/integration/test_unit.rb +10 -26
- data/lib/mocha/invocation.rb +73 -0
- data/lib/mocha/is_a.rb +0 -2
- data/lib/mocha/logger.rb +0 -4
- data/lib/mocha/macos_version.rb +5 -0
- data/lib/mocha/method_matcher.rb +1 -5
- data/lib/mocha/minitest.rb +6 -0
- data/lib/mocha/mock.rb +105 -57
- data/lib/mocha/mockery.rb +70 -98
- data/lib/mocha/names.rb +2 -12
- data/lib/mocha/not_initialized_error.rb +7 -0
- data/lib/mocha/object_methods.rb +25 -31
- data/lib/mocha/parameter_matchers/all_of.rb +2 -8
- data/lib/mocha/parameter_matchers/any_of.rb +2 -8
- data/lib/mocha/parameter_matchers/any_parameters.rb +3 -9
- data/lib/mocha/parameter_matchers/anything.rb +2 -8
- data/lib/mocha/parameter_matchers/base.rb +7 -13
- data/lib/mocha/parameter_matchers/equals.rb +1 -7
- data/lib/mocha/parameter_matchers/{query_string.rb → equivalent_uri.rb} +14 -15
- data/lib/mocha/parameter_matchers/has_entries.rb +2 -7
- data/lib/mocha/parameter_matchers/has_entry.rb +26 -21
- data/lib/mocha/parameter_matchers/has_key.rb +2 -7
- data/lib/mocha/parameter_matchers/has_keys.rb +53 -0
- data/lib/mocha/parameter_matchers/has_value.rb +2 -7
- data/lib/mocha/parameter_matchers/includes.rb +50 -8
- data/lib/mocha/parameter_matchers/instance_methods.rb +27 -0
- data/lib/mocha/parameter_matchers/instance_of.rb +0 -6
- data/lib/mocha/parameter_matchers/is_a.rb +2 -7
- data/lib/mocha/parameter_matchers/kind_of.rb +2 -6
- data/lib/mocha/parameter_matchers/not.rb +2 -7
- data/lib/mocha/parameter_matchers/optionally.rb +4 -10
- data/lib/mocha/parameter_matchers/positional_or_keyword_hash.rb +64 -0
- data/lib/mocha/parameter_matchers/regexp_matches.rb +0 -6
- data/lib/mocha/parameter_matchers/responds_with.rb +3 -8
- data/lib/mocha/parameter_matchers/yaml_equivalent.rb +2 -6
- data/lib/mocha/parameter_matchers.rb +3 -4
- data/lib/mocha/parameters_matcher.rb +8 -11
- data/lib/mocha/raised_exception.rb +11 -0
- data/lib/mocha/receivers.rb +10 -14
- data/lib/mocha/return_values.rb +4 -8
- data/lib/mocha/ruby_version.rb +3 -0
- data/lib/mocha/sequence.rb +4 -9
- data/lib/mocha/single_return_value.rb +2 -5
- data/lib/mocha/state_machine.rb +33 -46
- data/lib/mocha/stubbed_method.rb +88 -0
- data/lib/mocha/stubbing_error.rb +2 -13
- data/lib/mocha/test_unit.rb +5 -2
- data/lib/mocha/thrower.rb +4 -6
- data/lib/mocha/thrown_object.rb +12 -0
- data/lib/mocha/version.rb +1 -1
- data/lib/mocha/yield_parameters.rb +7 -17
- data/mocha.gemspec +16 -43
- metadata +38 -248
- data/bin/build-matrix +0 -71
- data/gemfiles/Gemfile.minitest.1.3.0 +0 -7
- data/gemfiles/Gemfile.minitest.1.4.0 +0 -7
- data/gemfiles/Gemfile.minitest.1.4.1 +0 -7
- data/gemfiles/Gemfile.minitest.1.4.2 +0 -7
- data/gemfiles/Gemfile.minitest.2.0.0 +0 -7
- data/gemfiles/Gemfile.minitest.2.0.1 +0 -7
- data/gemfiles/Gemfile.minitest.2.11.0 +0 -7
- data/gemfiles/Gemfile.minitest.2.11.2 +0 -7
- data/gemfiles/Gemfile.minitest.2.3.0 +0 -7
- data/gemfiles/Gemfile.test-unit.2.0.0 +0 -7
- data/gemfiles/Gemfile.test-unit.2.0.1 +0 -7
- data/gemfiles/Gemfile.test-unit.2.0.3 +0 -7
- data/init.rb +0 -3
- data/lib/mocha/class_method.rb +0 -127
- data/lib/mocha/integration/mini_test/nothing.rb +0 -19
- data/lib/mocha/integration/mini_test/version_13.rb +0 -51
- data/lib/mocha/integration/mini_test/version_140.rb +0 -51
- data/lib/mocha/integration/mini_test/version_141.rb +0 -62
- data/lib/mocha/integration/mini_test/version_142_to_172.rb +0 -62
- data/lib/mocha/integration/mini_test/version_200.rb +0 -63
- data/lib/mocha/integration/mini_test/version_201_to_222.rb +0 -63
- data/lib/mocha/integration/mini_test/version_2110_to_2111.rb +0 -67
- data/lib/mocha/integration/mini_test/version_2112_to_320.rb +0 -70
- data/lib/mocha/integration/mini_test/version_230_to_2101.rb +0 -65
- data/lib/mocha/integration/test_unit/gem_version_200.rb +0 -59
- data/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +0 -59
- data/lib/mocha/integration/test_unit/gem_version_203_to_220.rb +0 -59
- data/lib/mocha/integration/test_unit/gem_version_230_to_250.rb +0 -65
- data/lib/mocha/integration/test_unit/nothing.rb +0 -19
- data/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +0 -58
- data/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +0 -60
- data/lib/mocha/integration.rb +0 -14
- data/lib/mocha/mini_test.rb +0 -3
- data/lib/mocha/module_method.rb +0 -16
- data/lib/mocha/module_methods.rb +0 -14
- data/lib/mocha/multiple_yields.rb +0 -20
- data/lib/mocha/no_yields.rb +0 -11
- data/lib/mocha/parameter_matchers/object.rb +0 -17
- data/lib/mocha/pretty_parameters.rb +0 -28
- data/lib/mocha/setup.rb +0 -9
- data/lib/mocha/single_yield.rb +0 -18
- data/lib/mocha/standalone.rb +0 -4
- data/lib/mocha/unexpected_invocation.rb +0 -26
- data/lib/mocha_standalone.rb +0 -4
- data/test/acceptance/acceptance_test_helper.rb +0 -41
- data/test/acceptance/bug_18914_test.rb +0 -43
- data/test/acceptance/bug_21465_test.rb +0 -34
- data/test/acceptance/bug_21563_test.rb +0 -25
- data/test/acceptance/exception_rescue_test.rb +0 -55
- data/test/acceptance/expectations_on_multiple_methods_test.rb +0 -55
- data/test/acceptance/expected_invocation_count_test.rb +0 -232
- data/test/acceptance/failure_messages_test.rb +0 -64
- data/test/acceptance/issue_65_test.rb +0 -63
- data/test/acceptance/issue_70_test.rb +0 -55
- data/test/acceptance/mocha_example_test.rb +0 -98
- data/test/acceptance/mocha_test_result_test.rb +0 -84
- data/test/acceptance/mock_test.rb +0 -100
- data/test/acceptance/mock_with_initializer_block_test.rb +0 -51
- data/test/acceptance/mocked_methods_dispatch_test.rb +0 -78
- data/test/acceptance/multiple_expectations_failure_message_test.rb +0 -68
- data/test/acceptance/optional_parameters_test.rb +0 -70
- data/test/acceptance/parameter_matcher_test.rb +0 -337
- data/test/acceptance/partial_mocks_test.rb +0 -47
- data/test/acceptance/prepend_test.rb +0 -88
- data/test/acceptance/raise_exception_test.rb +0 -39
- data/test/acceptance/return_value_test.rb +0 -52
- data/test/acceptance/sequence_test.rb +0 -192
- data/test/acceptance/states_test.rb +0 -70
- data/test/acceptance/stub_any_instance_method_defined_on_superclass_test.rb +0 -34
- data/test/acceptance/stub_any_instance_method_test.rb +0 -238
- data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +0 -106
- data/test/acceptance/stub_class_method_defined_on_class_test.rb +0 -78
- data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -75
- data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +0 -112
- data/test/acceptance/stub_everything_test.rb +0 -56
- data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +0 -93
- data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -69
- data/test/acceptance/stub_instance_method_defined_on_class_test.rb +0 -69
- data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +0 -75
- data/test/acceptance/stub_instance_method_defined_on_module_test.rb +0 -75
- data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +0 -75
- data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -70
- data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -72
- data/test/acceptance/stub_module_method_test.rb +0 -163
- data/test/acceptance/stub_test.rb +0 -52
- data/test/acceptance/stubba_example_test.rb +0 -102
- data/test/acceptance/stubba_test_result_test.rb +0 -66
- data/test/acceptance/stubbing_error_backtrace_test.rb +0 -64
- data/test/acceptance/stubbing_frozen_object_test.rb +0 -88
- data/test/acceptance/stubbing_method_accepting_block_parameter_test.rb +0 -48
- data/test/acceptance/stubbing_method_unnecessarily_test.rb +0 -65
- data/test/acceptance/stubbing_nil_test.rb +0 -59
- data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +0 -130
- data/test/acceptance/stubbing_non_existent_class_method_test.rb +0 -157
- data/test/acceptance/stubbing_non_existent_instance_method_test.rb +0 -147
- data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +0 -130
- data/test/acceptance/stubbing_non_public_class_method_test.rb +0 -163
- data/test/acceptance/stubbing_non_public_instance_method_test.rb +0 -143
- data/test/acceptance/stubbing_on_non_mock_object_test.rb +0 -64
- data/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb +0 -35
- data/test/acceptance/throw_test.rb +0 -45
- data/test/acceptance/unexpected_invocation_test.rb +0 -25
- data/test/acceptance/unstubbing_test.rb +0 -168
- data/test/assertions.rb +0 -6
- data/test/deprecation_disabler.rb +0 -15
- data/test/execution_point.rb +0 -36
- data/test/integration/mini_test_test.rb +0 -8
- data/test/integration/shared_tests.rb +0 -174
- data/test/integration/test_unit_test.rb +0 -8
- data/test/method_definer.rb +0 -24
- data/test/mini_test_result.rb +0 -90
- data/test/minitest_result.rb +0 -49
- data/test/simple_counter.rb +0 -13
- data/test/test_helper.rb +0 -50
- data/test/test_runner.rb +0 -58
- data/test/test_unit_result.rb +0 -20
- data/test/unit/any_instance_method_test.rb +0 -132
- data/test/unit/array_inspect_test.rb +0 -16
- data/test/unit/backtrace_filter_test.rb +0 -19
- data/test/unit/cardinality_test.rb +0 -56
- data/test/unit/central_test.rb +0 -100
- data/test/unit/change_state_side_effect_test.rb +0 -41
- data/test/unit/class_method_test.rb +0 -223
- data/test/unit/class_methods_test.rb +0 -40
- data/test/unit/configuration_test.rb +0 -38
- data/test/unit/date_time_inspect_test.rb +0 -21
- data/test/unit/exception_raiser_test.rb +0 -42
- data/test/unit/expectation_list_test.rb +0 -82
- data/test/unit/expectation_test.rb +0 -497
- data/test/unit/hash_inspect_test.rb +0 -16
- data/test/unit/hooks_test.rb +0 -29
- data/test/unit/in_state_ordering_constraint_test.rb +0 -43
- data/test/unit/method_matcher_test.rb +0 -28
- data/test/unit/mock_test.rb +0 -341
- data/test/unit/mockery_test.rb +0 -151
- data/test/unit/module_methods_test.rb +0 -19
- data/test/unit/multiple_yields_test.rb +0 -18
- data/test/unit/no_yields_test.rb +0 -18
- data/test/unit/object_inspect_test.rb +0 -38
- data/test/unit/object_methods_test.rb +0 -46
- data/test/unit/parameter_matchers/all_of_test.rb +0 -26
- data/test/unit/parameter_matchers/any_of_test.rb +0 -26
- data/test/unit/parameter_matchers/anything_test.rb +0 -21
- data/test/unit/parameter_matchers/equals_test.rb +0 -25
- data/test/unit/parameter_matchers/has_entries_test.rb +0 -51
- data/test/unit/parameter_matchers/has_entry_test.rb +0 -129
- data/test/unit/parameter_matchers/has_key_test.rb +0 -55
- data/test/unit/parameter_matchers/has_value_test.rb +0 -57
- data/test/unit/parameter_matchers/includes_test.rb +0 -59
- data/test/unit/parameter_matchers/instance_of_test.rb +0 -25
- data/test/unit/parameter_matchers/is_a_test.rb +0 -25
- data/test/unit/parameter_matchers/kind_of_test.rb +0 -25
- data/test/unit/parameter_matchers/not_test.rb +0 -26
- data/test/unit/parameter_matchers/regexp_matches_test.rb +0 -46
- data/test/unit/parameter_matchers/responds_with_test.rb +0 -32
- data/test/unit/parameter_matchers/stub_matcher.rb +0 -27
- data/test/unit/parameter_matchers/yaml_equivalent_test.rb +0 -25
- data/test/unit/parameters_matcher_test.rb +0 -121
- data/test/unit/receivers_test.rb +0 -66
- data/test/unit/return_values_test.rb +0 -63
- data/test/unit/sequence_test.rb +0 -104
- data/test/unit/single_return_value_test.rb +0 -14
- data/test/unit/single_yield_test.rb +0 -18
- data/test/unit/state_machine_test.rb +0 -98
- data/test/unit/string_inspect_test.rb +0 -11
- data/test/unit/thrower_test.rb +0 -20
- data/test/unit/yield_parameters_test.rb +0 -93
- data/yard-templates/default/layout/html/google_analytics.erb +0 -11
- data/yard-templates/default/layout/html/setup.rb +0 -6
data/lib/mocha/mock.rb
CHANGED
@@ -1,20 +1,26 @@
|
|
1
|
-
require '
|
1
|
+
require 'ruby2_keywords'
|
2
2
|
require 'mocha/expectation'
|
3
3
|
require 'mocha/expectation_list'
|
4
|
+
require 'mocha/invocation'
|
4
5
|
require 'mocha/names'
|
5
6
|
require 'mocha/receivers'
|
6
7
|
require 'mocha/method_matcher'
|
7
8
|
require 'mocha/parameters_matcher'
|
8
|
-
require 'mocha/unexpected_invocation'
|
9
9
|
require 'mocha/argument_iterator'
|
10
10
|
require 'mocha/expectation_error_factory'
|
11
11
|
|
12
12
|
module Mocha
|
13
|
-
|
14
13
|
# Traditional mock object.
|
15
14
|
#
|
16
|
-
#
|
17
|
-
# methods on {Expectation}.
|
15
|
+
# {expects} and {stubs} return an {Expectation} which can be further modified
|
16
|
+
# by methods on {Expectation}.
|
17
|
+
#
|
18
|
+
# {responds_like} and {responds_like_instance_of} both return a {Mock}, and
|
19
|
+
# can therefore, be chained to the original creation methods in {API}.
|
20
|
+
# They force the mock to indicate what it is supposed to be mocking, thus
|
21
|
+
# making it a safer verifying mock. They check that the underlying +responder+
|
22
|
+
# will actually respond to the methods being stubbed, throwing a
|
23
|
+
# +NoMethodError+ upon invocation otherwise.
|
18
24
|
#
|
19
25
|
# Stubs and expectations are basically the same thing. A stub is just an
|
20
26
|
# expectation of zero or more invocations. The {#stubs} method is syntactic
|
@@ -67,15 +73,14 @@ module Mocha
|
|
67
73
|
# different mock objects, use the {Expectation#in_sequence} method to
|
68
74
|
# explicitly define a total or partial ordering of invocations.
|
69
75
|
class Mock
|
70
|
-
|
71
76
|
# Adds an expectation that the specified method must be called exactly once with any parameters.
|
72
77
|
#
|
73
|
-
# @
|
74
|
-
# @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {#expects} were called multiple times.
|
78
|
+
# @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
|
75
79
|
#
|
76
80
|
# @overload def expects(method_name)
|
81
|
+
# @param [Symbol,String] method_name name of expected method
|
77
82
|
# @overload def expects(expected_methods_vs_return_values)
|
78
|
-
#
|
83
|
+
# @param [Hash] expected_methods_vs_return_values expected method name symbols as keys and corresponding return values as values - these expectations are setup as if {#expects} were called multiple times.
|
79
84
|
#
|
80
85
|
# @example Expected method invoked once so no error raised
|
81
86
|
# object = mock()
|
@@ -103,24 +108,26 @@ module Mocha
|
|
103
108
|
# object.expects(:expected_method_one).returns(:result_one)
|
104
109
|
# object.expects(:expected_method_two).returns(:result_two)
|
105
110
|
def expects(method_name_or_hash, backtrace = nil)
|
111
|
+
expectation = nil
|
106
112
|
iterator = ArgumentIterator.new(method_name_or_hash)
|
107
|
-
iterator.each
|
113
|
+
iterator.each do |*args|
|
108
114
|
method_name = args.shift
|
109
115
|
ensure_method_not_already_defined(method_name)
|
110
116
|
expectation = Expectation.new(self, method_name, backtrace)
|
111
|
-
expectation.returns(args.shift)
|
117
|
+
expectation.returns(args.shift) unless args.empty?
|
112
118
|
@expectations.add(expectation)
|
113
|
-
|
119
|
+
end
|
120
|
+
expectation
|
114
121
|
end
|
115
122
|
|
116
123
|
# Adds an expectation that the specified method may be called any number of times with any parameters.
|
117
124
|
#
|
118
|
-
# @
|
119
|
-
# @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {#stubs} were called multiple times.
|
125
|
+
# @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
|
120
126
|
#
|
121
127
|
# @overload def stubs(method_name)
|
128
|
+
# @param [Symbol,String] method_name name of stubbed method
|
122
129
|
# @overload def stubs(stubbed_methods_vs_return_values)
|
123
|
-
#
|
130
|
+
# @param [Hash] stubbed_methods_vs_return_values stubbed method name symbols as keys and corresponding return values as values - these stubbed methods are setup as if {#stubs} were called multiple times.
|
124
131
|
#
|
125
132
|
# @example No error raised however many times stubbed method is invoked
|
126
133
|
# object = mock()
|
@@ -139,36 +146,48 @@ module Mocha
|
|
139
146
|
# object.stubs(:stubbed_method_one).returns(:result_one)
|
140
147
|
# object.stubs(:stubbed_method_two).returns(:result_two)
|
141
148
|
def stubs(method_name_or_hash, backtrace = nil)
|
149
|
+
expectation = nil
|
142
150
|
iterator = ArgumentIterator.new(method_name_or_hash)
|
143
|
-
iterator.each
|
151
|
+
iterator.each do |*args|
|
144
152
|
method_name = args.shift
|
145
153
|
ensure_method_not_already_defined(method_name)
|
146
154
|
expectation = Expectation.new(self, method_name, backtrace)
|
147
155
|
expectation.at_least(0)
|
148
|
-
expectation.returns(args.shift)
|
156
|
+
expectation.returns(args.shift) unless args.empty?
|
149
157
|
@expectations.add(expectation)
|
150
|
-
|
158
|
+
end
|
159
|
+
expectation
|
151
160
|
end
|
152
161
|
|
153
|
-
# Removes the specified stubbed
|
162
|
+
# Removes the specified stubbed methods (added by calls to {#expects} or {#stubs}) and all expectations associated with them.
|
154
163
|
#
|
155
|
-
# @param [Symbol]
|
164
|
+
# @param [Array<Symbol>] method_names names of methods to unstub.
|
156
165
|
#
|
157
166
|
# @example Invoking an unstubbed method causes error to be raised
|
158
|
-
# object = mock('mock')
|
167
|
+
# object = mock('mock')
|
159
168
|
# object.stubs(:stubbed_method).returns(:result_one)
|
160
169
|
# object.stubbed_method # => :result_one
|
161
170
|
# object.unstub(:stubbed_method)
|
162
171
|
# object.stubbed_method # => unexpected invocation: #<Mock:mock>.stubbed_method()
|
163
|
-
|
164
|
-
|
172
|
+
#
|
173
|
+
# @example Unstubbing multiple methods.
|
174
|
+
# multiplier.unstub(:double, :triple)
|
175
|
+
#
|
176
|
+
# # exactly equivalent to
|
177
|
+
#
|
178
|
+
# multiplier.unstub(:double)
|
179
|
+
# multiplier.unstub(:triple)
|
180
|
+
def unstub(*method_names)
|
181
|
+
method_names.each do |method_name|
|
182
|
+
@expectations.remove_all_matching_method(method_name)
|
183
|
+
end
|
165
184
|
end
|
166
185
|
|
167
|
-
# Constrains the {Mock} instance so that it can only expect or stub methods to which +responder+ responds. The constraint is only applied at method invocation time.
|
186
|
+
# Constrains the {Mock} instance so that it can only expect or stub methods to which +responder+ responds publicly. The constraint is only applied at method invocation time.
|
168
187
|
#
|
169
|
-
# A +NoMethodError+ will be raised if the +responder+ does not +#respond_to?+
|
188
|
+
# A +NoMethodError+ will be raised if the +responder+ does not publicly +#respond_to?+ the invoked method (even if the method has been expected or stubbed).
|
170
189
|
#
|
171
|
-
# The {Mock} instance will delegate its +#respond_to?+ method to the +responder+.
|
190
|
+
# The {Mock} instance will delegate its +#respond_to?+ method to the +responder+. However, the +include_all+ parameter is not passed through, so only public methods on the +responder+ will be considered.
|
172
191
|
#
|
173
192
|
# Note that the methods on +responder+ are never actually invoked.
|
174
193
|
#
|
@@ -218,11 +237,11 @@ module Mocha
|
|
218
237
|
self
|
219
238
|
end
|
220
239
|
|
221
|
-
# Constrains the {Mock} instance so that it can only expect or stub methods to which an instance of the +responder_class+ responds. The constraint is only applied at method invocation time. Note that the responder instance is instantiated using +Class#allocate+.
|
240
|
+
# Constrains the {Mock} instance so that it can only expect or stub methods to which an instance of the +responder_class+ responds publicly. The constraint is only applied at method invocation time. Note that the responder instance is instantiated using +Class#allocate+.
|
222
241
|
#
|
223
|
-
# A +NoMethodError+ will be raised if the responder instance does not +#respond_to?+
|
242
|
+
# A +NoMethodError+ will be raised if the responder instance does not publicly +#respond_to?+ the invoked method (even if the method has been expected or stubbed).
|
224
243
|
#
|
225
|
-
# The {Mock} instance will delegate its +#respond_to?+ method to the responder instance.
|
244
|
+
# The {Mock} instance will delegate its +#respond_to?+ method to the responder instance. However, the +include_all+ parameter is not passed through, so only public methods on the +responder+ will be considered.
|
226
245
|
#
|
227
246
|
# Note that the methods on the responder instance are never actually invoked.
|
228
247
|
#
|
@@ -251,7 +270,7 @@ module Mocha
|
|
251
270
|
end
|
252
271
|
|
253
272
|
# @private
|
254
|
-
def initialize(mockery, name = nil, receiver = nil
|
273
|
+
def initialize(mockery, name = nil, receiver = nil)
|
255
274
|
@mockery = mockery
|
256
275
|
@name = name || DefaultName.new(self)
|
257
276
|
@receiver = receiver || DefaultReceiver.new(self)
|
@@ -259,7 +278,7 @@ module Mocha
|
|
259
278
|
@everything_stubbed = false
|
260
279
|
@responder = nil
|
261
280
|
@unexpected_invocation = nil
|
262
|
-
|
281
|
+
@expired = false
|
263
282
|
end
|
264
283
|
|
265
284
|
# @private
|
@@ -269,6 +288,8 @@ module Mocha
|
|
269
288
|
|
270
289
|
alias_method :__stubs__, :stubs
|
271
290
|
|
291
|
+
alias_method :__singleton_class__, :singleton_class
|
292
|
+
|
272
293
|
alias_method :quacks_like, :responds_like
|
273
294
|
alias_method :quacks_like_instance_of, :responds_like_instance_of
|
274
295
|
|
@@ -288,35 +309,29 @@ module Mocha
|
|
288
309
|
end
|
289
310
|
|
290
311
|
# @private
|
312
|
+
# rubocop:disable Style/MethodMissingSuper
|
291
313
|
def method_missing(symbol, *arguments, &block)
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
end
|
307
|
-
raise ExpectationErrorFactory.build(message, caller)
|
308
|
-
end
|
314
|
+
handle_method_call(symbol, arguments, block)
|
315
|
+
end
|
316
|
+
ruby2_keywords(:method_missing)
|
317
|
+
# rubocop:enable Style/MethodMissingSuper
|
318
|
+
|
319
|
+
# @private
|
320
|
+
def handle_method_call(symbol, arguments, block)
|
321
|
+
check_expiry
|
322
|
+
check_responder_responds_to(symbol)
|
323
|
+
invocation = Invocation.new(self, symbol, arguments, block)
|
324
|
+
if (matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(invocation))
|
325
|
+
matching_expectation_allowing_invocation.invoke(invocation)
|
326
|
+
elsif (matching_expectation = all_expectations.match(invocation)) || (!matching_expectation && !@everything_stubbed)
|
327
|
+
raise_unexpected_invocation_error(invocation, matching_expectation)
|
309
328
|
end
|
310
329
|
end
|
311
330
|
|
312
331
|
# @private
|
313
|
-
def
|
314
|
-
if @responder
|
315
|
-
|
316
|
-
@responder.respond_to?(symbol, include_private)
|
317
|
-
else
|
318
|
-
@responder.respond_to?(symbol)
|
319
|
-
end
|
332
|
+
def respond_to_missing?(symbol, _include_all)
|
333
|
+
if @responder
|
334
|
+
@responder.respond_to?(symbol)
|
320
335
|
else
|
321
336
|
@everything_stubbed || all_expectations.matches_method?(symbol)
|
322
337
|
end
|
@@ -327,6 +342,11 @@ module Mocha
|
|
327
342
|
@expectations.verified?(assertion_counter)
|
328
343
|
end
|
329
344
|
|
345
|
+
# @private
|
346
|
+
def __expire__
|
347
|
+
@expired = true
|
348
|
+
end
|
349
|
+
|
330
350
|
# @private
|
331
351
|
def mocha_inspect
|
332
352
|
@name.mocha_inspect
|
@@ -339,7 +359,7 @@ module Mocha
|
|
339
359
|
|
340
360
|
# @private
|
341
361
|
def ensure_method_not_already_defined(method_name)
|
342
|
-
|
362
|
+
__singleton_class__.send(:undef_method, method_name) if __singleton_class__.method_defined?(method_name) || __singleton_class__.private_method_defined?(method_name)
|
343
363
|
end
|
344
364
|
|
345
365
|
# @private
|
@@ -347,6 +367,34 @@ module Mocha
|
|
347
367
|
@expectations.any?
|
348
368
|
end
|
349
369
|
|
350
|
-
|
370
|
+
private
|
371
|
+
|
372
|
+
def raise_unexpected_invocation_error(invocation, matching_expectation)
|
373
|
+
if @unexpected_invocation.nil?
|
374
|
+
@unexpected_invocation = invocation
|
375
|
+
matching_expectation.invoke(invocation) if matching_expectation
|
376
|
+
message = "#{@unexpected_invocation.call_description}\n#{@mockery.mocha_inspect}"
|
377
|
+
else
|
378
|
+
message = @unexpected_invocation.short_call_description
|
379
|
+
end
|
380
|
+
raise ExpectationErrorFactory.build("unexpected invocation: #{message}", caller)
|
381
|
+
end
|
382
|
+
|
383
|
+
def check_responder_responds_to(symbol)
|
384
|
+
if @responder && !@responder.respond_to?(symbol) # rubocop:disable Style/GuardClause
|
385
|
+
raise NoMethodError, "undefined method `#{symbol}' for #{mocha_inspect} which responds like #{@responder.mocha_inspect}"
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
def check_expiry
|
390
|
+
return unless @expired
|
351
391
|
|
392
|
+
sentences = [
|
393
|
+
"#{mocha_inspect} was instantiated in one test but it is receiving invocations within another test.",
|
394
|
+
'This can lead to unintended interactions between tests and hence unexpected test failures.',
|
395
|
+
'Ensure that every test correctly cleans up any state that it introduces.'
|
396
|
+
]
|
397
|
+
raise StubbingError.new(sentences.join(' '), caller)
|
398
|
+
end
|
399
|
+
end
|
352
400
|
end
|
data/lib/mocha/mockery.rb
CHANGED
@@ -6,16 +6,42 @@ require 'mocha/state_machine'
|
|
6
6
|
require 'mocha/logger'
|
7
7
|
require 'mocha/configuration'
|
8
8
|
require 'mocha/stubbing_error'
|
9
|
+
require 'mocha/not_initialized_error'
|
9
10
|
require 'mocha/expectation_error_factory'
|
10
11
|
|
11
12
|
module Mocha
|
12
|
-
|
13
13
|
class Mockery
|
14
|
+
class Null < self
|
15
|
+
def add_mock(*)
|
16
|
+
raise_not_initialized_error
|
17
|
+
end
|
14
18
|
|
15
|
-
|
19
|
+
def add_state_machine(*)
|
20
|
+
raise_not_initialized_error
|
21
|
+
end
|
22
|
+
|
23
|
+
def stubba
|
24
|
+
Central::Null.new(&method(:raise_not_initialized_error))
|
25
|
+
end
|
16
26
|
|
27
|
+
private
|
28
|
+
|
29
|
+
def raise_not_initialized_error
|
30
|
+
message = 'Mocha methods cannot be used outside the context of a test'
|
31
|
+
raise NotInitializedError.new(message, caller)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class << self
|
17
36
|
def instance
|
18
|
-
@
|
37
|
+
@instances.last || Null.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def setup
|
41
|
+
@instances ||= []
|
42
|
+
mockery = new
|
43
|
+
mockery.logger = instance.logger unless @instances.empty?
|
44
|
+
@instances.push(mockery)
|
19
45
|
end
|
20
46
|
|
21
47
|
def verify(*args)
|
@@ -24,28 +50,25 @@ module Mocha
|
|
24
50
|
|
25
51
|
def teardown
|
26
52
|
instance.teardown
|
53
|
+
ensure
|
54
|
+
@instances.pop
|
27
55
|
end
|
28
|
-
|
29
|
-
def reset_instance
|
30
|
-
@instance = nil
|
31
|
-
end
|
32
|
-
|
33
56
|
end
|
34
57
|
|
35
|
-
def named_mock(name
|
36
|
-
add_mock(Mock.new(self, Name.new(name)
|
58
|
+
def named_mock(name)
|
59
|
+
add_mock(Mock.new(self, Name.new(name)))
|
37
60
|
end
|
38
61
|
|
39
|
-
def unnamed_mock
|
40
|
-
add_mock(Mock.new(self
|
62
|
+
def unnamed_mock
|
63
|
+
add_mock(Mock.new(self))
|
41
64
|
end
|
42
65
|
|
43
|
-
def mock_impersonating(object
|
44
|
-
add_mock(Mock.new(self, ImpersonatingName.new(object), ObjectReceiver.new(object)
|
66
|
+
def mock_impersonating(object)
|
67
|
+
add_mock(Mock.new(self, ImpersonatingName.new(object), ObjectReceiver.new(object)))
|
45
68
|
end
|
46
69
|
|
47
|
-
def mock_impersonating_any_instance_of(klass
|
48
|
-
add_mock(Mock.new(self, ImpersonatingAnyInstanceName.new(klass), AnyInstanceReceiver.new(klass)
|
70
|
+
def mock_impersonating_any_instance_of(klass)
|
71
|
+
add_mock(Mock.new(self, ImpersonatingAnyInstanceName.new(klass), AnyInstanceReceiver.new(klass)))
|
49
72
|
end
|
50
73
|
|
51
74
|
def new_state_machine(name)
|
@@ -55,24 +78,22 @@ module Mocha
|
|
55
78
|
def verify(assertion_counter = nil)
|
56
79
|
unless mocks.all? { |mock| mock.__verified__?(assertion_counter) }
|
57
80
|
message = "not all expectations were satisfied\n#{mocha_inspect}"
|
58
|
-
if unsatisfied_expectations.empty?
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
81
|
+
backtrace = if unsatisfied_expectations.empty?
|
82
|
+
caller
|
83
|
+
else
|
84
|
+
unsatisfied_expectations[0].backtrace
|
85
|
+
end
|
63
86
|
raise ExpectationErrorFactory.build(message, backtrace)
|
64
87
|
end
|
65
|
-
expectations.each do |
|
66
|
-
|
67
|
-
|
68
|
-
on_stubbing_method_unnecessarily(e)
|
69
|
-
end
|
70
|
-
end
|
88
|
+
expectations.reject(&:used?).each do |expectation|
|
89
|
+
signature_proc = lambda { expectation.method_signature }
|
90
|
+
check(:stubbing_method_unnecessarily, 'method unnecessarily', signature_proc, expectation.backtrace)
|
71
91
|
end
|
72
92
|
end
|
73
93
|
|
74
94
|
def teardown
|
75
95
|
stubba.unstub_all
|
96
|
+
mocks.each(&:__expire__)
|
76
97
|
reset
|
77
98
|
end
|
78
99
|
|
@@ -89,78 +110,23 @@ module Mocha
|
|
89
110
|
end
|
90
111
|
|
91
112
|
def mocha_inspect
|
92
|
-
message =
|
93
|
-
message << "unsatisfied expectations:\n- #{unsatisfied_expectations.map
|
94
|
-
message << "satisfied expectations:\n- #{satisfied_expectations.map
|
95
|
-
message << "states:\n- #{state_machines.map
|
113
|
+
message = ''
|
114
|
+
message << "unsatisfied expectations:\n- #{unsatisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if unsatisfied_expectations.any?
|
115
|
+
message << "satisfied expectations:\n- #{satisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if satisfied_expectations.any?
|
116
|
+
message << "states:\n- #{state_machines.map(&:mocha_inspect).join("\n- ")}\n" if state_machines.any?
|
96
117
|
message
|
97
118
|
end
|
98
119
|
|
99
120
|
def on_stubbing(object, method)
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
on_stubbing_non_existent_method(object, method)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
unless Mocha::Configuration.allow?(:stubbing_non_public_method)
|
107
|
-
if object.method_exists?(method, include_public_methods = false)
|
108
|
-
on_stubbing_non_public_method(object, method)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
unless Mocha::Configuration.allow?(:stubbing_method_on_nil)
|
112
|
-
if object.nil?
|
113
|
-
on_stubbing_method_on_nil(object, method)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
unless Mocha::Configuration.allow?(:stubbing_method_on_non_mock_object)
|
117
|
-
on_stubbing_method_on_non_mock_object(object, method)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def on_stubbing_non_existent_method(object, method)
|
122
|
-
if Mocha::Configuration.prevent?(:stubbing_non_existent_method)
|
123
|
-
raise StubbingError.new("stubbing non-existent method: #{object.mocha_inspect}.#{method}", caller)
|
121
|
+
signature_proc = lambda { "#{object.mocha_inspect}.#{method}" }
|
122
|
+
check(:stubbing_non_existent_method, 'non-existent method', signature_proc) do
|
123
|
+
!(object.stubba_class.__method_exists__?(method, true) || object.respond_to?(method))
|
124
124
|
end
|
125
|
-
|
126
|
-
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def on_stubbing_non_public_method(object, method)
|
131
|
-
if Mocha::Configuration.prevent?(:stubbing_non_public_method)
|
132
|
-
raise StubbingError.new("stubbing non-public method: #{object.mocha_inspect}.#{method}", caller)
|
133
|
-
end
|
134
|
-
if Mocha::Configuration.warn_when?(:stubbing_non_public_method)
|
135
|
-
logger.warn "stubbing non-public method: #{object.mocha_inspect}.#{method}"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def on_stubbing_method_on_nil(object, method)
|
140
|
-
if Mocha::Configuration.prevent?(:stubbing_method_on_nil)
|
141
|
-
raise StubbingError.new("stubbing method on nil: #{object.mocha_inspect}.#{method}", caller)
|
142
|
-
end
|
143
|
-
if Mocha::Configuration.warn_when?(:stubbing_method_on_nil)
|
144
|
-
logger.warn "stubbing method on nil: #{object.mocha_inspect}.#{method}"
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def on_stubbing_method_on_non_mock_object(object, method)
|
149
|
-
if Mocha::Configuration.prevent?(:stubbing_method_on_non_mock_object)
|
150
|
-
raise StubbingError.new("stubbing method on non-mock object: #{object.mocha_inspect}.#{method}", caller)
|
151
|
-
end
|
152
|
-
if Mocha::Configuration.warn_when?(:stubbing_method_on_non_mock_object)
|
153
|
-
logger.warn "stubbing method on non-mock object: #{object.mocha_inspect}.#{method}"
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
def on_stubbing_method_unnecessarily(expectation)
|
158
|
-
if Mocha::Configuration.prevent?(:stubbing_method_unnecessarily)
|
159
|
-
raise StubbingError.new("stubbing method unnecessarily: #{expectation.method_signature}", expectation.backtrace)
|
160
|
-
end
|
161
|
-
if Mocha::Configuration.warn_when?(:stubbing_method_unnecessarily)
|
162
|
-
logger.warn "stubbing method unnecessarily: #{expectation.method_signature}"
|
125
|
+
check(:stubbing_non_public_method, 'non-public method', signature_proc) do
|
126
|
+
object.stubba_class.__method_exists__?(method, false)
|
163
127
|
end
|
128
|
+
check(:stubbing_method_on_nil, 'method on nil', signature_proc) { object.nil? }
|
129
|
+
check(:stubbing_method_on_non_mock_object, 'method on non-mock object', signature_proc)
|
164
130
|
end
|
165
131
|
|
166
132
|
attr_writer :logger
|
@@ -169,19 +135,27 @@ module Mocha
|
|
169
135
|
@logger ||= Logger.new($stderr)
|
170
136
|
end
|
171
137
|
|
172
|
-
|
173
138
|
private
|
174
139
|
|
140
|
+
def check(action, description, signature_proc, backtrace = caller)
|
141
|
+
treatment = Mocha.configuration.send(action)
|
142
|
+
return if (treatment == :allow) || (block_given? && !yield)
|
143
|
+
method_signature = signature_proc.call
|
144
|
+
message = "stubbing #{description}: #{method_signature}"
|
145
|
+
raise StubbingError.new(message, backtrace) if treatment == :prevent
|
146
|
+
logger.warn(message) if treatment == :warn
|
147
|
+
end
|
148
|
+
|
175
149
|
def expectations
|
176
150
|
mocks.map { |mock| mock.__expectations__.to_a }.flatten
|
177
151
|
end
|
178
152
|
|
179
153
|
def unsatisfied_expectations
|
180
|
-
expectations.reject
|
154
|
+
expectations.reject(&:verified?)
|
181
155
|
end
|
182
156
|
|
183
157
|
def satisfied_expectations
|
184
|
-
expectations.select
|
158
|
+
expectations.select(&:verified?)
|
185
159
|
end
|
186
160
|
|
187
161
|
def add_mock(mock)
|
@@ -199,7 +173,5 @@ module Mocha
|
|
199
173
|
@mocks = nil
|
200
174
|
@state_machines = nil
|
201
175
|
end
|
202
|
-
|
203
176
|
end
|
204
|
-
|
205
177
|
end
|
data/lib/mocha/names.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Mocha
|
2
|
-
|
3
2
|
class ImpersonatingName
|
4
|
-
|
5
3
|
def initialize(object)
|
6
4
|
@object = object
|
7
5
|
end
|
@@ -9,11 +7,9 @@ module Mocha
|
|
9
7
|
def mocha_inspect
|
10
8
|
@object.mocha_inspect
|
11
9
|
end
|
12
|
-
|
13
10
|
end
|
14
11
|
|
15
12
|
class ImpersonatingAnyInstanceName
|
16
|
-
|
17
13
|
def initialize(klass)
|
18
14
|
@klass = klass
|
19
15
|
end
|
@@ -21,23 +17,19 @@ module Mocha
|
|
21
17
|
def mocha_inspect
|
22
18
|
"#<AnyInstance:#{@klass.mocha_inspect}>"
|
23
19
|
end
|
24
|
-
|
25
20
|
end
|
26
21
|
|
27
22
|
class Name
|
28
|
-
|
29
23
|
def initialize(name)
|
30
|
-
@name = name
|
24
|
+
@name = name.to_s
|
31
25
|
end
|
32
26
|
|
33
27
|
def mocha_inspect
|
34
28
|
"#<Mock:#{@name}>"
|
35
29
|
end
|
36
|
-
|
37
30
|
end
|
38
31
|
|
39
32
|
class DefaultName
|
40
|
-
|
41
33
|
def initialize(mock)
|
42
34
|
@mock = mock
|
43
35
|
end
|
@@ -45,9 +37,7 @@ module Mocha
|
|
45
37
|
def mocha_inspect
|
46
38
|
address = @mock.__id__ * 2
|
47
39
|
address += 0x100000000 if address < 0
|
48
|
-
"#<Mock:0x#{'
|
40
|
+
"#<Mock:0x#{format('%<address>x', address: address)}>"
|
49
41
|
end
|
50
|
-
|
51
42
|
end
|
52
|
-
|
53
43
|
end
|