mocha 1.1.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +1 -0
- data/.rubocop.yml +61 -0
- data/.rubocop_todo.yml +27 -0
- data/.yardopts +1 -0
- data/CONTRIBUTING.md +4 -9
- data/README.md +114 -28
- data/RELEASE.md +248 -1
- data/Rakefile +53 -35
- data/gemfiles/Gemfile.test-unit.latest +5 -1
- data/init.rb +1 -3
- data/lib/mocha/any_instance_method.rb +12 -72
- data/lib/mocha/api.rb +121 -56
- data/lib/mocha/argument_iterator.rb +4 -8
- data/lib/mocha/backtrace_filter.rb +1 -5
- 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 +361 -18
- data/lib/mocha/debug.rb +3 -2
- 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 +125 -89
- 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 +15 -8
- data/lib/mocha/integration/mini_test/adapter.rb +2 -4
- data/lib/mocha/integration/mini_test/exception_translation.rb +1 -1
- data/lib/mocha/integration/mini_test/nothing.rb +4 -4
- data/lib/mocha/integration/mini_test/version_13.rb +4 -1
- data/lib/mocha/integration/mini_test/version_140.rb +4 -1
- data/lib/mocha/integration/mini_test/version_141.rb +4 -1
- data/lib/mocha/integration/mini_test/version_142_to_172.rb +4 -1
- data/lib/mocha/integration/mini_test/version_200.rb +4 -1
- data/lib/mocha/integration/mini_test/version_201_to_222.rb +4 -1
- data/lib/mocha/integration/mini_test/version_2110_to_2111.rb +4 -1
- data/lib/mocha/integration/mini_test/version_2112_to_320.rb +4 -1
- data/lib/mocha/integration/mini_test/version_230_to_2101.rb +4 -1
- data/lib/mocha/integration/mini_test.rb +7 -0
- data/lib/mocha/integration/monkey_patcher.rb +8 -2
- data/lib/mocha/integration/test_unit/adapter.rb +5 -6
- data/lib/mocha/integration/test_unit/gem_version_200.rb +5 -2
- data/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +5 -2
- data/lib/mocha/integration/test_unit/gem_version_203_to_220.rb +5 -2
- data/lib/mocha/integration/test_unit/gem_version_230_to_250.rb +5 -2
- data/lib/mocha/integration/test_unit/nothing.rb +4 -4
- data/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +4 -1
- data/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +4 -1
- data/lib/mocha/integration/test_unit.rb +7 -0
- data/lib/mocha/integration.rb +2 -5
- data/lib/mocha/invocation.rb +77 -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 +8 -0
- data/lib/mocha/mock.rb +94 -46
- data/lib/mocha/mockery.rb +72 -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 +6 -12
- data/lib/mocha/parameter_matchers/equals.rb +1 -7
- data/lib/mocha/parameter_matchers/{query_string.rb → equivalent_uri.rb} +15 -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 +18 -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/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 +6 -9
- 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 +4 -0
- data/lib/mocha/sequence.rb +4 -9
- data/lib/mocha/setup.rb +5 -0
- data/lib/mocha/single_return_value.rb +2 -5
- data/lib/mocha/singleton_class.rb +9 -0
- data/lib/mocha/state_machine.rb +33 -46
- data/lib/mocha/stubbed_method.rb +125 -0
- data/lib/mocha/stubbing_error.rb +2 -13
- data/lib/mocha/test_unit.rb +7 -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/lib/mocha.rb +8 -0
- data/mocha.gemspec +42 -40
- data/yard-templates/default/layout/html/google_analytics.erb +6 -9
- data/yard-templates/default/layout/html/setup.rb +2 -3
- metadata +45 -191
- 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/lib/mocha/class_method.rb +0 -127
- 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/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
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'mocha/parameters_matcher'
|
2
|
+
require 'mocha/raised_exception'
|
3
|
+
require 'mocha/return_values'
|
4
|
+
require 'mocha/thrown_object'
|
5
|
+
require 'mocha/yield_parameters'
|
6
|
+
require 'mocha/configuration'
|
7
|
+
require 'mocha/deprecation'
|
8
|
+
|
9
|
+
module Mocha
|
10
|
+
class Invocation
|
11
|
+
attr_reader :method_name, :block
|
12
|
+
|
13
|
+
def initialize(mock, method_name, *arguments, &block)
|
14
|
+
@mock = mock
|
15
|
+
@method_name = method_name
|
16
|
+
@arguments = arguments
|
17
|
+
@block = block
|
18
|
+
@yields = []
|
19
|
+
@result = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def call(yield_parameters = YieldParameters.new, return_values = ReturnValues.new)
|
23
|
+
yield_parameters.next_invocation.each do |yield_args|
|
24
|
+
@yields << ParametersMatcher.new(yield_args)
|
25
|
+
if @block
|
26
|
+
@block.call(*yield_args)
|
27
|
+
else
|
28
|
+
raise LocalJumpError unless Mocha.configuration.reinstate_undocumented_behaviour_from_v1_9?
|
29
|
+
yield_args_description = ParametersMatcher.new(yield_args).mocha_inspect
|
30
|
+
Deprecation.warning(
|
31
|
+
"Stubbed method was instructed to yield #{yield_args_description}, but no block was given by invocation: #{call_description}.",
|
32
|
+
' This will raise a LocalJumpError in the future.',
|
33
|
+
' Use Expectation#with_block_given to constrain this expectation to match invocations supplying a block.',
|
34
|
+
' And, if necessary, add another expectation to match invocations not supplying a block.'
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
return_values.next(self)
|
39
|
+
end
|
40
|
+
|
41
|
+
def returned(value)
|
42
|
+
@result = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def raised(exception)
|
46
|
+
@result = RaisedException.new(exception)
|
47
|
+
end
|
48
|
+
|
49
|
+
def threw(tag, value)
|
50
|
+
@result = ThrownObject.new(tag, value)
|
51
|
+
end
|
52
|
+
|
53
|
+
def arguments
|
54
|
+
@arguments.dup
|
55
|
+
end
|
56
|
+
|
57
|
+
def call_description
|
58
|
+
description = "#{@mock.mocha_inspect}.#{@method_name}#{ParametersMatcher.new(@arguments).mocha_inspect}"
|
59
|
+
description << ' { ... }' unless @block.nil?
|
60
|
+
description
|
61
|
+
end
|
62
|
+
|
63
|
+
def short_call_description
|
64
|
+
"#{@method_name}(#{@arguments.join(', ')})"
|
65
|
+
end
|
66
|
+
|
67
|
+
def result_description
|
68
|
+
desc = "# => #{@result.mocha_inspect}"
|
69
|
+
desc << " after yielding #{@yields.map(&:mocha_inspect).join(', then ')}" if @yields.any?
|
70
|
+
desc
|
71
|
+
end
|
72
|
+
|
73
|
+
def full_description
|
74
|
+
"\n - #{call_description} #{result_description}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/mocha/is_a.rb
CHANGED
data/lib/mocha/logger.rb
CHANGED
data/lib/mocha/method_matcher.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
module Mocha
|
2
|
-
|
3
2
|
class MethodMatcher
|
4
|
-
|
5
3
|
attr_reader :expected_method_name
|
6
4
|
|
7
5
|
def initialize(expected_method_name)
|
@@ -13,9 +11,7 @@ module Mocha
|
|
13
11
|
end
|
14
12
|
|
15
13
|
def mocha_inspect
|
16
|
-
|
14
|
+
@expected_method_name.to_s
|
17
15
|
end
|
18
|
-
|
19
16
|
end
|
20
|
-
|
21
17
|
end
|
data/lib/mocha/mock.rb
CHANGED
@@ -1,20 +1,27 @@
|
|
1
|
-
require '
|
1
|
+
require 'mocha/singleton_class'
|
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
|
+
require 'mocha/ruby_version'
|
11
12
|
|
12
13
|
module Mocha
|
13
|
-
|
14
14
|
# Traditional mock object.
|
15
15
|
#
|
16
|
-
#
|
17
|
-
# methods on {Expectation}.
|
16
|
+
# {expects} and {stubs} return an {Expectation} which can be further modified
|
17
|
+
# by methods on {Expectation}.
|
18
|
+
#
|
19
|
+
# {responds_like} and {responds_like_instance_of} both return a {Mock}, and
|
20
|
+
# can therefore, be chained to the original creation methods in {API}.
|
21
|
+
# They force the mock to indicate what it is supposed to be mocking, thus
|
22
|
+
# making it a safer verifying mock. They check that the underlying +responder+
|
23
|
+
# will actually respond to the methods being stubbed, throwing a
|
24
|
+
# +NoMethodError+ upon invocation otherwise.
|
18
25
|
#
|
19
26
|
# Stubs and expectations are basically the same thing. A stub is just an
|
20
27
|
# expectation of zero or more invocations. The {#stubs} method is syntactic
|
@@ -67,15 +74,14 @@ module Mocha
|
|
67
74
|
# different mock objects, use the {Expectation#in_sequence} method to
|
68
75
|
# explicitly define a total or partial ordering of invocations.
|
69
76
|
class Mock
|
70
|
-
|
71
77
|
# Adds an expectation that the specified method must be called exactly once with any parameters.
|
72
78
|
#
|
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.
|
79
|
+
# @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
|
75
80
|
#
|
76
81
|
# @overload def expects(method_name)
|
82
|
+
# @param [Symbol,String] method_name name of expected method
|
77
83
|
# @overload def expects(expected_methods_vs_return_values)
|
78
|
-
#
|
84
|
+
# @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
85
|
#
|
80
86
|
# @example Expected method invoked once so no error raised
|
81
87
|
# object = mock()
|
@@ -104,23 +110,23 @@ module Mocha
|
|
104
110
|
# object.expects(:expected_method_two).returns(:result_two)
|
105
111
|
def expects(method_name_or_hash, backtrace = 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
|
114
120
|
end
|
115
121
|
|
116
122
|
# Adds an expectation that the specified method may be called any number of times with any parameters.
|
117
123
|
#
|
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.
|
124
|
+
# @return [Expectation] last-built expectation which can be further modified by methods on {Expectation}.
|
120
125
|
#
|
121
126
|
# @overload def stubs(method_name)
|
127
|
+
# @param [Symbol,String] method_name name of stubbed method
|
122
128
|
# @overload def stubs(stubbed_methods_vs_return_values)
|
123
|
-
#
|
129
|
+
# @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
130
|
#
|
125
131
|
# @example No error raised however many times stubbed method is invoked
|
126
132
|
# object = mock()
|
@@ -140,19 +146,19 @@ module Mocha
|
|
140
146
|
# object.stubs(:stubbed_method_two).returns(:result_two)
|
141
147
|
def stubs(method_name_or_hash, backtrace = nil)
|
142
148
|
iterator = ArgumentIterator.new(method_name_or_hash)
|
143
|
-
iterator.each
|
149
|
+
iterator.each do |*args|
|
144
150
|
method_name = args.shift
|
145
151
|
ensure_method_not_already_defined(method_name)
|
146
152
|
expectation = Expectation.new(self, method_name, backtrace)
|
147
153
|
expectation.at_least(0)
|
148
|
-
expectation.returns(args.shift)
|
154
|
+
expectation.returns(args.shift) unless args.empty?
|
149
155
|
@expectations.add(expectation)
|
150
|
-
|
156
|
+
end
|
151
157
|
end
|
152
158
|
|
153
|
-
# Removes the specified stubbed
|
159
|
+
# Removes the specified stubbed methods (added by calls to {#expects} or {#stubs}) and all expectations associated with them.
|
154
160
|
#
|
155
|
-
# @param [Symbol]
|
161
|
+
# @param [Array<Symbol>] method_names names of methods to unstub.
|
156
162
|
#
|
157
163
|
# @example Invoking an unstubbed method causes error to be raised
|
158
164
|
# object = mock('mock') do
|
@@ -160,8 +166,18 @@ module Mocha
|
|
160
166
|
# object.stubbed_method # => :result_one
|
161
167
|
# object.unstub(:stubbed_method)
|
162
168
|
# object.stubbed_method # => unexpected invocation: #<Mock:mock>.stubbed_method()
|
163
|
-
|
164
|
-
|
169
|
+
#
|
170
|
+
# @example Unstubbing multiple methods.
|
171
|
+
# multiplier.unstub(:double, :triple)
|
172
|
+
#
|
173
|
+
# # exactly equivalent to
|
174
|
+
#
|
175
|
+
# multiplier.unstub(:double)
|
176
|
+
# multiplier.unstub(:triple)
|
177
|
+
def unstub(*method_names)
|
178
|
+
method_names.each do |method_name|
|
179
|
+
@expectations.remove_all_matching_method(method_name)
|
180
|
+
end
|
165
181
|
end
|
166
182
|
|
167
183
|
# 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.
|
@@ -251,7 +267,7 @@ module Mocha
|
|
251
267
|
end
|
252
268
|
|
253
269
|
# @private
|
254
|
-
def initialize(mockery, name = nil, receiver = nil
|
270
|
+
def initialize(mockery, name = nil, receiver = nil)
|
255
271
|
@mockery = mockery
|
256
272
|
@name = name || DefaultName.new(self)
|
257
273
|
@receiver = receiver || DefaultReceiver.new(self)
|
@@ -259,7 +275,7 @@ module Mocha
|
|
259
275
|
@everything_stubbed = false
|
260
276
|
@responder = nil
|
261
277
|
@unexpected_invocation = nil
|
262
|
-
|
278
|
+
@expired = false
|
263
279
|
end
|
264
280
|
|
265
281
|
# @private
|
@@ -269,6 +285,8 @@ module Mocha
|
|
269
285
|
|
270
286
|
alias_method :__stubs__, :stubs
|
271
287
|
|
288
|
+
alias_method :__singleton_class__, :singleton_class
|
289
|
+
|
272
290
|
alias_method :quacks_like, :responds_like
|
273
291
|
alias_method :quacks_like_instance_of, :responds_like_instance_of
|
274
292
|
|
@@ -288,30 +306,20 @@ module Mocha
|
|
288
306
|
end
|
289
307
|
|
290
308
|
# @private
|
291
|
-
def method_missing(symbol, *arguments, &block)
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
if matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(
|
296
|
-
matching_expectation_allowing_invocation.invoke(
|
297
|
-
|
298
|
-
|
299
|
-
if @unexpected_invocation.nil?
|
300
|
-
@unexpected_invocation = UnexpectedInvocation.new(self, symbol, *arguments)
|
301
|
-
matching_expectation.invoke(&block) if matching_expectation
|
302
|
-
message = @unexpected_invocation.full_description
|
303
|
-
message << @mockery.mocha_inspect
|
304
|
-
else
|
305
|
-
message = @unexpected_invocation.short_description
|
306
|
-
end
|
307
|
-
raise ExpectationErrorFactory.build(message, caller)
|
308
|
-
end
|
309
|
+
def method_missing(symbol, *arguments, &block) # rubocop:disable Style/MethodMissingSuper
|
310
|
+
check_expiry
|
311
|
+
check_responder_responds_to(symbol)
|
312
|
+
invocation = Invocation.new(self, symbol, *arguments, &block)
|
313
|
+
if (matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(invocation))
|
314
|
+
matching_expectation_allowing_invocation.invoke(invocation)
|
315
|
+
elsif (matching_expectation = all_expectations.match(invocation)) || (!matching_expectation && !@everything_stubbed)
|
316
|
+
raise_unexpected_invocation_error(invocation, matching_expectation)
|
309
317
|
end
|
310
318
|
end
|
311
319
|
|
312
320
|
# @private
|
313
|
-
def
|
314
|
-
if @responder
|
321
|
+
def respond_to_missing?(symbol, include_private = false)
|
322
|
+
if @responder
|
315
323
|
if @responder.method(:respond_to?).arity > 1
|
316
324
|
@responder.respond_to?(symbol, include_private)
|
317
325
|
else
|
@@ -322,11 +330,23 @@ module Mocha
|
|
322
330
|
end
|
323
331
|
end
|
324
332
|
|
333
|
+
if PRE_RUBY_V19
|
334
|
+
# @private
|
335
|
+
def respond_to?(symbol, include_private = false)
|
336
|
+
respond_to_missing?(symbol, include_private)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
325
340
|
# @private
|
326
341
|
def __verified__?(assertion_counter = nil)
|
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
|
351
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
|
+
if @expired # rubocop:disable Style/GuardClause
|
391
|
+
Deprecation.warning(
|
392
|
+
"#{mocha_inspect} was instantiated in one test but it is receiving invocations within another test.",
|
393
|
+
' This can lead to unintended interactions between tests and hence unexpected test failures.',
|
394
|
+
' Ensure that every test correctly cleans up any state that it introduces.',
|
395
|
+
' A Mocha::StubbingError will be raised in this scenario in the future.'
|
396
|
+
)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
352
400
|
end
|
data/lib/mocha/mockery.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'mocha/ruby_version'
|
1
2
|
require 'mocha/central'
|
2
3
|
require 'mocha/mock'
|
3
4
|
require 'mocha/names'
|
@@ -6,16 +7,42 @@ require 'mocha/state_machine'
|
|
6
7
|
require 'mocha/logger'
|
7
8
|
require 'mocha/configuration'
|
8
9
|
require 'mocha/stubbing_error'
|
10
|
+
require 'mocha/not_initialized_error'
|
9
11
|
require 'mocha/expectation_error_factory'
|
10
12
|
|
11
13
|
module Mocha
|
12
|
-
|
13
14
|
class Mockery
|
15
|
+
class Null < self
|
16
|
+
def add_mock(*)
|
17
|
+
raise_not_initialized_error
|
18
|
+
end
|
14
19
|
|
15
|
-
|
20
|
+
def add_state_machine(*)
|
21
|
+
raise_not_initialized_error
|
22
|
+
end
|
23
|
+
|
24
|
+
def stubba
|
25
|
+
Central::Null.new(&method(:raise_not_initialized_error))
|
26
|
+
end
|
16
27
|
|
28
|
+
private
|
29
|
+
|
30
|
+
def raise_not_initialized_error
|
31
|
+
message = 'Mocha methods cannot be used outside the context of a test'
|
32
|
+
raise NotInitializedError.new(message, caller)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class << self
|
17
37
|
def instance
|
18
|
-
@
|
38
|
+
@instances.last || Null.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def setup
|
42
|
+
@instances ||= []
|
43
|
+
mockery = new
|
44
|
+
mockery.logger = instance.logger unless @instances.empty?
|
45
|
+
@instances.push(mockery)
|
19
46
|
end
|
20
47
|
|
21
48
|
def verify(*args)
|
@@ -24,28 +51,25 @@ module Mocha
|
|
24
51
|
|
25
52
|
def teardown
|
26
53
|
instance.teardown
|
54
|
+
ensure
|
55
|
+
@instances.pop
|
27
56
|
end
|
28
|
-
|
29
|
-
def reset_instance
|
30
|
-
@instance = nil
|
31
|
-
end
|
32
|
-
|
33
57
|
end
|
34
58
|
|
35
|
-
def named_mock(name
|
36
|
-
add_mock(Mock.new(self, Name.new(name)
|
59
|
+
def named_mock(name)
|
60
|
+
add_mock(Mock.new(self, Name.new(name)))
|
37
61
|
end
|
38
62
|
|
39
|
-
def unnamed_mock
|
40
|
-
add_mock(Mock.new(self
|
63
|
+
def unnamed_mock
|
64
|
+
add_mock(Mock.new(self))
|
41
65
|
end
|
42
66
|
|
43
|
-
def mock_impersonating(object
|
44
|
-
add_mock(Mock.new(self, ImpersonatingName.new(object), ObjectReceiver.new(object)
|
67
|
+
def mock_impersonating(object)
|
68
|
+
add_mock(Mock.new(self, ImpersonatingName.new(object), ObjectReceiver.new(object)))
|
45
69
|
end
|
46
70
|
|
47
|
-
def mock_impersonating_any_instance_of(klass
|
48
|
-
add_mock(Mock.new(self, ImpersonatingAnyInstanceName.new(klass), AnyInstanceReceiver.new(klass)
|
71
|
+
def mock_impersonating_any_instance_of(klass)
|
72
|
+
add_mock(Mock.new(self, ImpersonatingAnyInstanceName.new(klass), AnyInstanceReceiver.new(klass)))
|
49
73
|
end
|
50
74
|
|
51
75
|
def new_state_machine(name)
|
@@ -55,24 +79,22 @@ module Mocha
|
|
55
79
|
def verify(assertion_counter = nil)
|
56
80
|
unless mocks.all? { |mock| mock.__verified__?(assertion_counter) }
|
57
81
|
message = "not all expectations were satisfied\n#{mocha_inspect}"
|
58
|
-
if unsatisfied_expectations.empty?
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
82
|
+
backtrace = if unsatisfied_expectations.empty?
|
83
|
+
caller
|
84
|
+
else
|
85
|
+
unsatisfied_expectations[0].backtrace
|
86
|
+
end
|
63
87
|
raise ExpectationErrorFactory.build(message, backtrace)
|
64
88
|
end
|
65
|
-
expectations.each do |
|
66
|
-
|
67
|
-
|
68
|
-
on_stubbing_method_unnecessarily(e)
|
69
|
-
end
|
70
|
-
end
|
89
|
+
expectations.reject(&:used?).each do |expectation|
|
90
|
+
signature_proc = lambda { expectation.method_signature }
|
91
|
+
check(:stubbing_method_unnecessarily, 'method unnecessarily', signature_proc, expectation.backtrace)
|
71
92
|
end
|
72
93
|
end
|
73
94
|
|
74
95
|
def teardown
|
75
96
|
stubba.unstub_all
|
97
|
+
mocks.each(&:__expire__)
|
76
98
|
reset
|
77
99
|
end
|
78
100
|
|
@@ -89,78 +111,24 @@ module Mocha
|
|
89
111
|
end
|
90
112
|
|
91
113
|
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
|
114
|
+
message = ''
|
115
|
+
message << "unsatisfied expectations:\n- #{unsatisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if unsatisfied_expectations.any?
|
116
|
+
message << "satisfied expectations:\n- #{satisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if satisfied_expectations.any?
|
117
|
+
message << "states:\n- #{state_machines.map(&:mocha_inspect).join("\n- ")}\n" if state_machines.any?
|
96
118
|
message
|
97
119
|
end
|
98
120
|
|
99
121
|
def on_stubbing(object, method)
|
100
|
-
method =
|
101
|
-
|
102
|
-
|
103
|
-
|
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)
|
122
|
+
method = PRE_RUBY_V19 ? method.to_s : method.to_sym
|
123
|
+
signature_proc = lambda { "#{object.mocha_inspect}.#{method}" }
|
124
|
+
check(:stubbing_non_existent_method, 'non-existent method', signature_proc) do
|
125
|
+
!(object.stubba_class.__method_exists__?(method, true) || object.respond_to?(method.to_sym))
|
124
126
|
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}"
|
127
|
+
check(:stubbing_non_public_method, 'non-public method', signature_proc) do
|
128
|
+
object.stubba_class.__method_exists__?(method, false)
|
163
129
|
end
|
130
|
+
check(:stubbing_method_on_nil, 'method on nil', signature_proc) { object.nil? }
|
131
|
+
check(:stubbing_method_on_non_mock_object, 'method on non-mock object', signature_proc)
|
164
132
|
end
|
165
133
|
|
166
134
|
attr_writer :logger
|
@@ -169,19 +137,27 @@ module Mocha
|
|
169
137
|
@logger ||= Logger.new($stderr)
|
170
138
|
end
|
171
139
|
|
172
|
-
|
173
140
|
private
|
174
141
|
|
142
|
+
def check(action, description, signature_proc, backtrace = caller)
|
143
|
+
treatment = Mocha.configuration.send(action)
|
144
|
+
return if (treatment == :allow) || (block_given? && !yield)
|
145
|
+
method_signature = signature_proc.call
|
146
|
+
message = "stubbing #{description}: #{method_signature}"
|
147
|
+
raise StubbingError.new(message, backtrace) if treatment == :prevent
|
148
|
+
logger.warn(message) if treatment == :warn
|
149
|
+
end
|
150
|
+
|
175
151
|
def expectations
|
176
152
|
mocks.map { |mock| mock.__expectations__.to_a }.flatten
|
177
153
|
end
|
178
154
|
|
179
155
|
def unsatisfied_expectations
|
180
|
-
expectations.reject
|
156
|
+
expectations.reject(&:verified?)
|
181
157
|
end
|
182
158
|
|
183
159
|
def satisfied_expectations
|
184
|
-
expectations.select
|
160
|
+
expectations.select(&:verified?)
|
185
161
|
end
|
186
162
|
|
187
163
|
def add_mock(mock)
|
@@ -199,7 +175,5 @@ module Mocha
|
|
199
175
|
@mocks = nil
|
200
176
|
@state_machines = nil
|
201
177
|
end
|
202
|
-
|
203
178
|
end
|
204
|
-
|
205
179
|
end
|