mocha 1.4.0 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +58 -0
- data/.rubocop_todo.yml +50 -0
- data/README.md +12 -71
- data/RELEASE.md +19 -0
- data/Rakefile +35 -28
- data/bin/build-matrix +17 -18
- data/lib/mocha/any_instance_method.rb +19 -25
- data/lib/mocha/api.rb +1 -5
- data/lib/mocha/argument_iterator.rb +4 -8
- data/lib/mocha/backtrace_filter.rb +1 -5
- data/lib/mocha/cardinality.rb +20 -27
- data/lib/mocha/central.rb +21 -12
- data/lib/mocha/change_state_side_effect.rb +0 -4
- data/lib/mocha/class_method.rb +31 -37
- data/lib/mocha/class_methods.rb +11 -15
- data/lib/mocha/configuration.rb +69 -10
- data/lib/mocha/debug.rb +3 -2
- data/lib/mocha/deprecation.rb +4 -11
- data/lib/mocha/detection/mini_test.rb +0 -2
- data/lib/mocha/detection/test_unit.rb +4 -4
- data/lib/mocha/error_with_filtered_backtrace.rb +13 -0
- data/lib/mocha/exception_raiser.rb +2 -5
- data/lib/mocha/expectation.rb +15 -18
- data/lib/mocha/expectation_error.rb +2 -0
- data/lib/mocha/expectation_error_factory.rb +0 -1
- data/lib/mocha/expectation_list.rb +2 -6
- data/lib/mocha/hooks.rb +1 -3
- data/lib/mocha/in_state_ordering_constraint.rb +0 -4
- data/lib/mocha/inspect.rb +3 -5
- data/lib/mocha/instance_method.rb +0 -2
- 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/monkey_patcher.rb +5 -7
- 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.rb +3 -4
- data/lib/mocha/is_a.rb +0 -2
- data/lib/mocha/logger.rb +0 -4
- data/lib/mocha/method_matcher.rb +1 -5
- data/lib/mocha/minitest.rb +1 -1
- data/lib/mocha/mock.rb +25 -30
- data/lib/mocha/mockery.rb +62 -43
- data/lib/mocha/module_method.rb +0 -10
- data/lib/mocha/module_methods.rb +0 -4
- data/lib/mocha/multiple_yields.rb +0 -5
- data/lib/mocha/names.rb +1 -11
- data/lib/mocha/no_yields.rb +1 -7
- data/lib/mocha/not_initialized_error.rb +7 -0
- data/lib/mocha/object_methods.rb +16 -16
- data/lib/mocha/parameter_matchers/all_of.rb +1 -7
- data/lib/mocha/parameter_matchers/any_of.rb +1 -7
- 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 +0 -6
- data/lib/mocha/parameter_matchers/equivalent_uri.rb +6 -6
- data/lib/mocha/parameter_matchers/has_entries.rb +2 -6
- data/lib/mocha/parameter_matchers/has_entry.rb +8 -11
- data/lib/mocha/parameter_matchers/has_key.rb +2 -6
- data/lib/mocha/parameter_matchers/has_value.rb +2 -6
- data/lib/mocha/parameter_matchers/includes.rb +2 -6
- data/lib/mocha/parameter_matchers/instance_of.rb +0 -6
- data/lib/mocha/parameter_matchers/is_a.rb +2 -6
- data/lib/mocha/parameter_matchers/kind_of.rb +2 -6
- data/lib/mocha/parameter_matchers/not.rb +2 -6
- data/lib/mocha/parameter_matchers/object.rb +0 -2
- 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 +0 -2
- data/lib/mocha/parameters_matcher.rb +6 -9
- data/lib/mocha/pretty_parameters.rb +0 -4
- data/lib/mocha/receivers.rb +10 -14
- data/lib/mocha/return_values.rb +3 -7
- data/lib/mocha/sequence.rb +4 -9
- data/lib/mocha/single_return_value.rb +0 -4
- data/lib/mocha/single_yield.rb +0 -5
- data/lib/mocha/state_machine.rb +6 -10
- data/lib/mocha/stubbing_error.rb +2 -13
- data/lib/mocha/test_unit.rb +1 -1
- data/lib/mocha/thrower.rb +2 -5
- data/lib/mocha/unexpected_invocation.rb +3 -5
- data/lib/mocha/version.rb +1 -1
- data/lib/mocha/yield_parameters.rb +3 -7
- data/mocha.gemspec +34 -58
- data/test/acceptance/acceptance_test_helper.rb +0 -6
- data/test/acceptance/bug_18914_test.rb +7 -12
- data/test/acceptance/bug_21465_test.rb +0 -2
- data/test/acceptance/bug_21563_test.rb +0 -2
- data/test/acceptance/exception_rescue_test.rb +7 -8
- data/test/acceptance/expectations_on_multiple_methods_test.rb +2 -1
- data/test/acceptance/expected_invocation_count_test.rb +27 -29
- data/test/acceptance/failure_messages_test.rb +3 -5
- data/test/acceptance/issue_272_test.rb +0 -1
- data/test/acceptance/issue_65_test.rb +15 -13
- data/test/acceptance/issue_70_test.rb +0 -1
- data/test/acceptance/mocha_example_test.rb +5 -6
- data/test/acceptance/mocha_test_result_test.rb +7 -7
- data/test/acceptance/mock_test.rb +2 -4
- data/test/acceptance/mock_with_initializer_block_test.rb +0 -2
- data/test/acceptance/mocked_methods_dispatch_test.rb +0 -2
- data/test/acceptance/multiple_expectations_failure_message_test.rb +16 -17
- data/test/acceptance/optional_parameters_test.rb +0 -2
- data/test/acceptance/parameter_matcher_test.rb +2 -3
- data/test/acceptance/partial_mocks_test.rb +4 -6
- data/test/acceptance/prepend_test.rb +14 -16
- data/test/acceptance/prevent_use_of_mocha_outside_test_test.rb +77 -0
- data/test/acceptance/raise_exception_test.rb +2 -4
- data/test/acceptance/return_value_test.rb +0 -2
- data/test/acceptance/sequence_test.rb +9 -11
- data/test/acceptance/states_test.rb +6 -4
- data/test/acceptance/stub_any_instance_method_defined_on_superclass_test.rb +33 -2
- data/test/acceptance/stub_any_instance_method_test.rb +19 -17
- data/test/acceptance/stub_class_method_defined_on_active_record_association_proxy_test.rb +8 -8
- data/test/acceptance/stub_class_method_defined_on_class_test.rb +2 -1
- data/test/acceptance/stub_class_method_defined_on_module_test.rb +0 -1
- data/test/acceptance/stub_class_method_defined_on_superclass_test.rb +34 -1
- data/test/acceptance/stub_everything_test.rb +1 -3
- data/test/acceptance/stub_instance_method_defined_on_active_record_association_proxy_test.rb +6 -7
- data/test/acceptance/stub_instance_method_defined_on_class_and_aliased_test.rb +0 -1
- data/test/acceptance/stub_instance_method_defined_on_class_test.rb +0 -1
- data/test/acceptance/stub_instance_method_defined_on_kernel_module_test.rb +63 -1
- data/test/acceptance/stub_instance_method_defined_on_module_test.rb +0 -1
- data/test/acceptance/stub_instance_method_defined_on_object_class_test.rb +2 -1
- data/test/acceptance/stub_instance_method_defined_on_singleton_class_test.rb +0 -2
- data/test/acceptance/stub_instance_method_defined_on_superclass_test.rb +0 -1
- data/test/acceptance/stub_module_method_test.rb +13 -13
- data/test/acceptance/stub_test.rb +1 -3
- data/test/acceptance/stubba_example_test.rb +6 -14
- data/test/acceptance/stubba_test_result_test.rb +5 -8
- data/test/acceptance/stubbing_error_backtrace_test.rb +2 -2
- data/test/acceptance/stubbing_frozen_object_test.rb +2 -1
- data/test/acceptance/stubbing_method_accepting_block_parameter_test.rb +12 -7
- data/test/acceptance/stubbing_method_unnecessarily_test.rb +0 -2
- data/test/acceptance/stubbing_nil_test.rb +4 -5
- data/test/acceptance/stubbing_non_existent_any_instance_method_test.rb +1 -3
- data/test/acceptance/stubbing_non_existent_class_method_test.rb +3 -3
- data/test/acceptance/stubbing_non_existent_instance_method_test.rb +1 -3
- data/test/acceptance/stubbing_non_public_any_instance_method_test.rb +0 -2
- data/test/acceptance/stubbing_non_public_class_method_test.rb +3 -3
- data/test/acceptance/stubbing_non_public_instance_method_test.rb +1 -3
- data/test/acceptance/stubbing_on_non_mock_object_test.rb +4 -10
- data/test/acceptance/stubbing_same_class_method_on_parent_and_child_classes_test.rb +3 -4
- data/test/acceptance/throw_test.rb +0 -2
- data/test/acceptance/unexpected_invocation_test.rb +2 -3
- data/test/acceptance/unstubbing_test.rb +41 -14
- data/test/deprecation_disabler.rb +0 -1
- data/test/execution_point.rb +2 -4
- data/test/integration/mini_test_test.rb +2 -2
- data/test/integration/shared_tests.rb +24 -22
- data/test/integration/test_unit_test.rb +2 -2
- data/test/method_definer.rb +1 -3
- data/test/mini_test_result.rb +17 -11
- data/test/minitest_result.rb +0 -1
- data/test/simple_counter.rb +0 -2
- data/test/test_helper.rb +13 -5
- data/test/test_runner.rb +2 -4
- data/test/test_unit_result.rb +4 -2
- data/test/unit/any_instance_method_test.rb +31 -17
- data/test/unit/array_inspect_test.rb +2 -4
- data/test/unit/backtrace_filter_test.rb +3 -5
- data/test/unit/cardinality_test.rb +0 -2
- data/test/unit/central_test.rb +26 -27
- data/test/unit/change_state_side_effect_test.rb +0 -4
- data/test/unit/class_method_test.rb +59 -34
- data/test/unit/class_methods_test.rb +34 -5
- data/test/unit/configuration_test.rb +1 -2
- data/test/unit/date_time_inspect_test.rb +1 -3
- data/test/unit/exception_raiser_test.rb +0 -2
- data/test/unit/expectation_list_test.rb +0 -2
- data/test/unit/expectation_test.rb +41 -46
- data/test/unit/hash_inspect_test.rb +3 -5
- data/test/unit/hooks_test.rb +14 -8
- data/test/unit/in_state_ordering_constraint_test.rb +0 -4
- data/test/unit/method_matcher_test.rb +1 -3
- data/test/unit/mock_test.rb +35 -22
- data/test/unit/mockery_test.rb +45 -28
- data/test/unit/module_methods_test.rb +0 -2
- data/test/unit/multiple_yields_test.rb +0 -2
- data/test/unit/no_yields_test.rb +0 -2
- data/test/unit/object_inspect_test.rb +16 -7
- data/test/unit/object_methods_test.rb +22 -6
- data/test/unit/parameter_matchers/all_of_test.rb +0 -2
- data/test/unit/parameter_matchers/any_of_test.rb +0 -2
- data/test/unit/parameter_matchers/anything_test.rb +2 -4
- data/test/unit/parameter_matchers/equals_test.rb +1 -3
- data/test/unit/parameter_matchers/equivalent_uri_test.rb +0 -1
- data/test/unit/parameter_matchers/has_entries_test.rb +2 -2
- data/test/unit/parameter_matchers/has_entry_test.rb +13 -14
- data/test/unit/parameter_matchers/has_key_test.rb +0 -1
- data/test/unit/parameter_matchers/has_value_test.rb +0 -2
- data/test/unit/parameter_matchers/includes_test.rb +8 -9
- data/test/unit/parameter_matchers/instance_of_test.rb +1 -3
- data/test/unit/parameter_matchers/is_a_test.rb +1 -3
- data/test/unit/parameter_matchers/kind_of_test.rb +1 -3
- data/test/unit/parameter_matchers/not_test.rb +0 -2
- data/test/unit/parameter_matchers/regexp_matches_test.rb +1 -2
- data/test/unit/parameter_matchers/responds_with_test.rb +9 -3
- data/test/unit/parameter_matchers/stub_matcher.rb +0 -4
- data/test/unit/parameter_matchers/yaml_equivalent_test.rb +1 -3
- data/test/unit/parameters_matcher_test.rb +2 -4
- data/test/unit/receivers_test.rb +35 -5
- data/test/unit/return_values_test.rb +3 -5
- data/test/unit/sequence_test.rb +1 -5
- data/test/unit/single_return_value_test.rb +0 -2
- data/test/unit/single_yield_test.rb +0 -2
- data/test/unit/state_machine_test.rb +1 -3
- data/test/unit/string_inspect_test.rb +2 -4
- data/test/unit/thrower_test.rb +0 -2
- data/test/unit/yield_parameters_test.rb +0 -2
- data/yard-templates/default/layout/html/setup.rb +2 -3
- metadata +25 -6
data/lib/mocha/cardinality.rb
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
module Mocha
|
2
|
-
|
3
2
|
class Cardinality
|
4
|
-
|
5
3
|
INFINITY = 1 / 0.0
|
6
4
|
|
7
5
|
class << self
|
8
|
-
|
9
6
|
def exactly(count)
|
10
7
|
new(count, count)
|
11
8
|
end
|
@@ -20,15 +17,15 @@ module Mocha
|
|
20
17
|
|
21
18
|
def times(range_or_count)
|
22
19
|
case range_or_count
|
23
|
-
|
24
|
-
|
20
|
+
when Range then new(range_or_count.first, range_or_count.last)
|
21
|
+
else new(range_or_count, range_or_count)
|
25
22
|
end
|
26
23
|
end
|
27
|
-
|
28
24
|
end
|
29
25
|
|
30
26
|
def initialize(required, maximum)
|
31
|
-
@required
|
27
|
+
@required = required
|
28
|
+
@maximum = maximum
|
32
29
|
end
|
33
30
|
|
34
31
|
def invocations_allowed?(invocation_count)
|
@@ -48,28 +45,26 @@ module Mocha
|
|
48
45
|
end
|
49
46
|
|
50
47
|
def allowed_any_number_of_times?
|
51
|
-
required
|
48
|
+
required.zero? && infinite?(maximum)
|
52
49
|
end
|
53
50
|
|
54
51
|
def used?(invocation_count)
|
55
|
-
(invocation_count > 0) ||
|
52
|
+
(invocation_count > 0) || maximum.zero?
|
56
53
|
end
|
57
54
|
|
58
55
|
def mocha_inspect
|
59
56
|
if allowed_any_number_of_times?
|
60
|
-
|
57
|
+
'allowed any number of times'
|
58
|
+
elsif required.zero? && maximum.zero?
|
59
|
+
'expected never'
|
60
|
+
elsif required == maximum
|
61
|
+
"expected exactly #{times(required)}"
|
62
|
+
elsif infinite?(maximum)
|
63
|
+
"expected at least #{times(required)}"
|
64
|
+
elsif required.zero?
|
65
|
+
"expected at most #{times(maximum)}"
|
61
66
|
else
|
62
|
-
|
63
|
-
"expected never"
|
64
|
-
elsif required == maximum
|
65
|
-
"expected exactly #{times(required)}"
|
66
|
-
elsif infinite?(maximum)
|
67
|
-
"expected at least #{times(required)}"
|
68
|
-
elsif required == 0
|
69
|
-
"expected at most #{times(maximum)}"
|
70
|
-
else
|
71
|
-
"expected between #{required} and #{times(maximum)}"
|
72
|
-
end
|
67
|
+
"expected between #{required} and #{times(maximum)}"
|
73
68
|
end
|
74
69
|
end
|
75
70
|
|
@@ -79,17 +74,15 @@ module Mocha
|
|
79
74
|
|
80
75
|
def times(number)
|
81
76
|
case number
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
77
|
+
when 0 then 'no times'
|
78
|
+
when 1 then 'once'
|
79
|
+
when 2 then 'twice'
|
80
|
+
else "#{number} times"
|
86
81
|
end
|
87
82
|
end
|
88
83
|
|
89
84
|
def infinite?(number)
|
90
85
|
number.respond_to?(:infinite?) && number.infinite?
|
91
86
|
end
|
92
|
-
|
93
87
|
end
|
94
|
-
|
95
88
|
end
|
data/lib/mocha/central.rb
CHANGED
@@ -1,6 +1,19 @@
|
|
1
1
|
module Mocha
|
2
|
-
|
3
2
|
class Central
|
3
|
+
class Null < self
|
4
|
+
def initialize(&block)
|
5
|
+
super
|
6
|
+
@raise_not_initialized_error = block
|
7
|
+
end
|
8
|
+
|
9
|
+
def stub(*)
|
10
|
+
@raise_not_initialized_error.call
|
11
|
+
end
|
12
|
+
|
13
|
+
def unstub(*)
|
14
|
+
@raise_not_initialized_error.call
|
15
|
+
end
|
16
|
+
end
|
4
17
|
|
5
18
|
attr_accessor :stubba_methods
|
6
19
|
|
@@ -9,25 +22,21 @@ module Mocha
|
|
9
22
|
end
|
10
23
|
|
11
24
|
def stub(method)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
25
|
+
return if stubba_methods.detect { |m| m.matches?(method) }
|
26
|
+
method.stub
|
27
|
+
stubba_methods.push(method)
|
16
28
|
end
|
17
29
|
|
18
30
|
def unstub(method)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
31
|
+
return unless (existing = stubba_methods.detect { |m| m.matches?(method) })
|
32
|
+
existing.unstub
|
33
|
+
stubba_methods.delete(existing)
|
23
34
|
end
|
24
35
|
|
25
36
|
def unstub_all
|
26
|
-
while stubba_methods.any?
|
37
|
+
while stubba_methods.any?
|
27
38
|
unstub(stubba_methods.first)
|
28
39
|
end
|
29
40
|
end
|
30
|
-
|
31
41
|
end
|
32
|
-
|
33
42
|
end
|
data/lib/mocha/class_method.rb
CHANGED
@@ -2,16 +2,15 @@ require 'mocha/ruby_version'
|
|
2
2
|
require 'metaclass'
|
3
3
|
|
4
4
|
module Mocha
|
5
|
-
|
6
5
|
class ClassMethod
|
7
|
-
|
8
6
|
PrependedModule = Class.new(Module)
|
9
7
|
|
10
8
|
attr_reader :stubbee, :method
|
11
9
|
|
12
10
|
def initialize(stubbee, method)
|
13
11
|
@stubbee = stubbee
|
14
|
-
@original_method
|
12
|
+
@original_method = nil
|
13
|
+
@original_visibility = nil
|
15
14
|
@method = PRE_RUBY_V19 ? method.to_s : method.to_sym
|
16
15
|
end
|
17
16
|
|
@@ -24,9 +23,8 @@ module Mocha
|
|
24
23
|
remove_new_method
|
25
24
|
restore_original_method
|
26
25
|
mock.unstub(method.to_sym)
|
27
|
-
|
28
|
-
|
29
|
-
end
|
26
|
+
return if mock.any_expectations?
|
27
|
+
reset_mocha
|
30
28
|
end
|
31
29
|
|
32
30
|
def mock
|
@@ -38,21 +36,22 @@ module Mocha
|
|
38
36
|
end
|
39
37
|
|
40
38
|
def hide_original_method
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
39
|
+
return unless (@original_visibility = method_visibility(method))
|
40
|
+
begin
|
41
|
+
if RUBY_V2_PLUS
|
42
|
+
@definition_target = PrependedModule.new
|
43
|
+
stubbee.__metaclass__.__send__ :prepend, @definition_target
|
44
|
+
else
|
45
|
+
@original_method = stubbee._method(method)
|
46
|
+
if @original_method && @original_method.owner == stubbee.__metaclass__
|
47
|
+
stubbee.__metaclass__.send(:remove_method, method)
|
51
48
|
end
|
52
|
-
rescue NameError
|
53
|
-
# deal with nasties like ActiveRecord::Associations::AssociationProxy
|
54
49
|
end
|
50
|
+
# rubocop:disable Lint/HandleExceptions
|
51
|
+
rescue NameError
|
52
|
+
# deal with nasties like ActiveRecord::Associations::AssociationProxy
|
55
53
|
end
|
54
|
+
# rubocop:enable Lint/HandleExceptions
|
56
55
|
end
|
57
56
|
|
58
57
|
def define_new_method
|
@@ -61,9 +60,8 @@ module Mocha
|
|
61
60
|
mocha.method_missing(:#{method}, *args, &block)
|
62
61
|
end
|
63
62
|
CODE
|
64
|
-
|
65
|
-
|
66
|
-
end
|
63
|
+
return unless @original_visibility
|
64
|
+
Module.instance_method(@original_visibility).bind(definition_target).call(method)
|
67
65
|
end
|
68
66
|
|
69
67
|
def remove_new_method
|
@@ -71,26 +69,24 @@ module Mocha
|
|
71
69
|
end
|
72
70
|
|
73
71
|
def restore_original_method
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
end
|
81
|
-
else
|
82
|
-
stubbee.__metaclass__.send(:define_method, method, @original_method)
|
72
|
+
return if RUBY_V2_PLUS
|
73
|
+
if @original_method && @original_method.owner == stubbee.__metaclass__
|
74
|
+
if PRE_RUBY_V19
|
75
|
+
original_method = @original_method
|
76
|
+
stubbee.__metaclass__.send(:define_method, method) do |*args, &block|
|
77
|
+
original_method.call(*args, &block)
|
83
78
|
end
|
84
|
-
|
85
|
-
|
86
|
-
Module.instance_method(@original_visibility).bind(stubbee.__metaclass__).call(method)
|
79
|
+
else
|
80
|
+
stubbee.__metaclass__.send(:define_method, method, @original_method)
|
87
81
|
end
|
88
82
|
end
|
83
|
+
return unless @original_visibility
|
84
|
+
Module.instance_method(@original_visibility).bind(stubbee.__metaclass__).call(method)
|
89
85
|
end
|
90
86
|
|
91
87
|
def matches?(other)
|
92
|
-
return false unless
|
93
|
-
(stubbee.object_id == other.stubbee.object_id)
|
88
|
+
return false unless other.class == self.class
|
89
|
+
(stubbee.object_id == other.stubbee.object_id) && (method == other.method)
|
94
90
|
end
|
95
91
|
|
96
92
|
alias_method :==, :eql?
|
@@ -113,7 +109,5 @@ module Mocha
|
|
113
109
|
def definition_target
|
114
110
|
@definition_target ||= stubbee.__metaclass__
|
115
111
|
end
|
116
|
-
|
117
112
|
end
|
118
|
-
|
119
113
|
end
|
data/lib/mocha/class_methods.rb
CHANGED
@@ -3,10 +3,8 @@ require 'mocha/class_method'
|
|
3
3
|
require 'mocha/any_instance_method'
|
4
4
|
|
5
5
|
module Mocha
|
6
|
-
|
7
6
|
# Methods added to all classes to allow mocking and stubbing on real (i.e. non-mock) objects.
|
8
7
|
module ClassMethods
|
9
|
-
|
10
8
|
# @private
|
11
9
|
def stubba_method
|
12
10
|
Mocha::ClassMethod
|
@@ -14,33 +12,33 @@ module Mocha
|
|
14
12
|
|
15
13
|
# @private
|
16
14
|
class AnyInstance
|
17
|
-
|
18
15
|
def initialize(klass)
|
19
16
|
@stubba_object = klass
|
20
17
|
end
|
21
18
|
|
22
|
-
def mocha
|
23
|
-
|
19
|
+
def mocha(instantiate = true)
|
20
|
+
if instantiate
|
21
|
+
@mocha ||= Mocha::Mockery.instance.mock_impersonating_any_instance_of(@stubba_object)
|
22
|
+
else
|
23
|
+
defined?(@mocha) ? @mocha : nil
|
24
|
+
end
|
24
25
|
end
|
25
26
|
|
26
27
|
def stubba_method
|
27
28
|
Mocha::AnyInstanceMethod
|
28
29
|
end
|
29
30
|
|
30
|
-
|
31
|
-
@stubba_object
|
32
|
-
end
|
31
|
+
attr_reader :stubba_object
|
33
32
|
|
34
33
|
def method_exists?(method, include_public_methods = true)
|
35
34
|
if include_public_methods
|
36
|
-
return true if @stubba_object.public_instance_methods(
|
35
|
+
return true if @stubba_object.public_instance_methods(true).include?(method)
|
37
36
|
return true if @stubba_object.allocate.respond_to?(method.to_sym)
|
38
37
|
end
|
39
|
-
return true if @stubba_object.protected_instance_methods(
|
40
|
-
return true if @stubba_object.private_instance_methods(
|
41
|
-
|
38
|
+
return true if @stubba_object.protected_instance_methods(true).include?(method)
|
39
|
+
return true if @stubba_object.private_instance_methods(true).include?(method)
|
40
|
+
false
|
42
41
|
end
|
43
|
-
|
44
42
|
end
|
45
43
|
|
46
44
|
# @return [Mock] a mock object which will detect calls to any instance of this class.
|
@@ -58,7 +56,5 @@ module Mocha
|
|
58
56
|
end
|
59
57
|
@any_instance ||= AnyInstance.new(self)
|
60
58
|
end
|
61
|
-
|
62
59
|
end
|
63
|
-
|
64
60
|
end
|
data/lib/mocha/configuration.rb
CHANGED
@@ -1,18 +1,80 @@
|
|
1
1
|
module Mocha
|
2
|
-
|
3
|
-
#
|
2
|
+
# This class allows you to determine what should happen under certain circumstances. In each scenario, Mocha can be configured to {.allow do nothing}, {.warn_when display a warning message}, or {.prevent raise an exception}. The relevant scenario is identified using one of the following symbols:
|
3
|
+
#
|
4
|
+
# * +:stubbing_method_unnecessarily+ This is useful for identifying unused stubs. Unused stubs are often accidentally introduced when code is {http://martinfowler.com/bliki/DefinitionOfRefactoring.html refactored}. Allowed by default.
|
5
|
+
# * +:stubbing_non_existent_method+ - This is useful if you want to ensure that methods you're mocking really exist. A common criticism of unit tests with mock objects is that such a test may (incorrectly) pass when an equivalent non-mocking test would (correctly) fail. While you should always have some integration tests, particularly for critical business functionality, this Mocha configuration setting should catch scenarios when mocked methods and real methods have become misaligned. Allowed by default.
|
6
|
+
# * +:stubbing_non_public_method+ - Many people think that it's good practice only to mock public methods. This is one way to prevent your tests being too tightly coupled to the internal implementation of a class. Such tests tend to be very brittle and not much use when refactoring. Allowed by default.
|
7
|
+
# * +:stubbing_method_on_non_mock_object+ - If you like the idea of {http://www.jmock.org/oopsla2004.pdf mocking roles not objects} and {http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html you don't like stubbing concrete classes}, this is the setting for you. However, while this restriction makes a lot of sense in Java with its {http://java.sun.com/docs/books/tutorial/java/concepts/interface.html explicit interfaces}, it may be moot in Ruby where roles are probably best represented as Modules. Allowed by default.
|
8
|
+
# * +:stubbing_method_on_nil+ - This is usually done accidentally, but there might be rare cases where it is intended. Prevented by default.
|
9
|
+
#
|
10
|
+
# @example Preventing unnecessary stubbing of a method
|
11
|
+
# Mocha::Configuration.prevent(:stubbing_method_unnecessarily)
|
12
|
+
#
|
13
|
+
# example = mock('example')
|
14
|
+
# example.stubs(:unused_stub)
|
15
|
+
# # => Mocha::StubbingError: stubbing method unnecessarily:
|
16
|
+
# # => #<Mock:example>.unused_stub(any_parameters)
|
17
|
+
#
|
18
|
+
# @example Preventing stubbing of a method on a non-mock object
|
19
|
+
# Mocha::Configuration.prevent(:stubbing_method_on_non_mock_object)
|
20
|
+
#
|
21
|
+
# class Example
|
22
|
+
# def example_method; end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# example = Example.new
|
26
|
+
# example.stubs(:example_method)
|
27
|
+
# # => Mocha::StubbingError: stubbing method on non-mock object:
|
28
|
+
# # => #<Example:0x593620>.example_method
|
29
|
+
#
|
30
|
+
# @example Preventing stubbing of a non-existent method
|
31
|
+
#
|
32
|
+
# Mocha::Configuration.prevent(:stubbing_non_existent_method)
|
33
|
+
#
|
34
|
+
# class Example
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# example = Example.new
|
38
|
+
# example.stubs(:method_that_doesnt_exist)
|
39
|
+
# # => Mocha::StubbingError: stubbing non-existent method:
|
40
|
+
# # => #<Example:0x593760>.method_that_doesnt_exist
|
41
|
+
#
|
42
|
+
# @example Preventing stubbing of a non-public method
|
43
|
+
# Mocha::Configuration.prevent(:stubbing_non_public_method)
|
44
|
+
#
|
45
|
+
# class Example
|
46
|
+
# def internal_method; end
|
47
|
+
# private :internal_method
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# example = Example.new
|
51
|
+
# example.stubs(:internal_method)
|
52
|
+
# # => Mocha::StubbingError: stubbing non-public method:
|
53
|
+
# # => #<Example:0x593530>.internal_method
|
54
|
+
#
|
55
|
+
# Typically the configuration would be set globally in a +test_helper.rb+ or +spec_helper.rb+ file. However, it can also be temporarily overridden locally using the block syntax of the relevant method. In the latter case, the original configuration settings are restored when the block is exited.
|
56
|
+
#
|
57
|
+
# @example Temporarily allowing stubbing of a non-existent method
|
58
|
+
# Mocha::Configuration.prevent(:stubbing_non_public_method)
|
59
|
+
#
|
60
|
+
# class Example
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# Mocha::Configuration.allow(:stubbing_non_existent_method) do
|
64
|
+
# example = Example.new
|
65
|
+
# example.stubs(:method_that_doesnt_exist)
|
66
|
+
# # => no exception raised
|
67
|
+
# end
|
4
68
|
class Configuration
|
5
|
-
|
6
69
|
DEFAULTS = {
|
7
70
|
:stubbing_method_unnecessarily => :allow,
|
8
71
|
:stubbing_method_on_non_mock_object => :allow,
|
9
72
|
:stubbing_non_existent_method => :allow,
|
10
73
|
:stubbing_non_public_method => :allow,
|
11
|
-
:stubbing_method_on_nil => :prevent
|
12
|
-
}
|
74
|
+
:stubbing_method_on_nil => :prevent
|
75
|
+
}.freeze
|
13
76
|
|
14
77
|
class << self
|
15
|
-
|
16
78
|
# Allow the specified +action+.
|
17
79
|
#
|
18
80
|
# @param [Symbol] action one of +:stubbing_method_unnecessarily+, +:stubbing_method_on_non_mock_object+, +:stubbing_non_existent_method+, +:stubbing_non_public_method+, +:stubbing_method_on_nil+.
|
@@ -74,16 +136,13 @@ module Mocha
|
|
74
136
|
end
|
75
137
|
|
76
138
|
# @private
|
77
|
-
def temporarily_change_config(action, new_value
|
139
|
+
def temporarily_change_config(action, new_value)
|
78
140
|
original_value = configuration[action]
|
79
141
|
configuration[action] = new_value
|
80
142
|
yield
|
81
143
|
ensure
|
82
144
|
configuration[action] = original_value
|
83
145
|
end
|
84
|
-
|
85
146
|
end
|
86
|
-
|
87
147
|
end
|
88
|
-
|
89
148
|
end
|
data/lib/mocha/debug.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module Mocha
|
2
2
|
module Debug
|
3
3
|
OPTIONS = (ENV['MOCHA_OPTIONS'] || '').split(',').inject({}) do |hash, key|
|
4
|
-
hash[key] = true
|
4
|
+
hash[key] = true
|
5
|
+
hash
|
5
6
|
end.freeze
|
6
7
|
|
7
8
|
def self.puts(message)
|
8
|
-
|
9
|
+
warn(message) if OPTIONS['debug']
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
data/lib/mocha/deprecation.rb
CHANGED
@@ -1,27 +1,20 @@
|
|
1
1
|
require 'mocha/backtrace_filter'
|
2
2
|
|
3
3
|
module Mocha
|
4
|
-
|
5
4
|
class Deprecation
|
6
|
-
|
7
5
|
class << self
|
8
|
-
|
9
6
|
attr_accessor :mode, :messages
|
10
7
|
|
11
8
|
def warning(message)
|
12
9
|
@messages << message
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
10
|
+
return if mode == :disabled
|
11
|
+
filter = BacktraceFilter.new
|
12
|
+
location = filter.filtered(caller)[0]
|
13
|
+
warn "Mocha deprecation warning at #{location}: #{message}"
|
18
14
|
end
|
19
|
-
|
20
15
|
end
|
21
16
|
|
22
17
|
self.mode = :enabled
|
23
18
|
self.messages = []
|
24
|
-
|
25
19
|
end
|
26
|
-
|
27
20
|
end
|
@@ -3,11 +3,9 @@ module Mocha
|
|
3
3
|
module TestUnit
|
4
4
|
def self.testcase
|
5
5
|
if defined?(::Test::Unit::TestCase) &&
|
6
|
-
|
7
|
-
|
6
|
+
!(defined?(::MiniTest::Unit::TestCase) && (::Test::Unit::TestCase < ::MiniTest::Unit::TestCase)) &&
|
7
|
+
!(defined?(::MiniTest::Spec) && (::Test::Unit::TestCase < ::MiniTest::Spec))
|
8
8
|
::Test::Unit::TestCase
|
9
|
-
else
|
10
|
-
nil
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
@@ -16,8 +14,10 @@ module Mocha
|
|
16
14
|
if testcase
|
17
15
|
begin
|
18
16
|
require 'test/unit/version'
|
17
|
+
# rubocop:disable Lint/HandleExceptions
|
19
18
|
rescue LoadError
|
20
19
|
end
|
20
|
+
# rubocop:enable Lint/HandleExceptions
|
21
21
|
if defined?(::Test::Unit::VERSION)
|
22
22
|
version = ::Test::Unit::VERSION
|
23
23
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'mocha/backtrace_filter'
|
2
|
+
|
3
|
+
module Mocha
|
4
|
+
# @private
|
5
|
+
class ErrorWithFilteredBacktrace < StandardError
|
6
|
+
# @private
|
7
|
+
def initialize(message = nil, backtrace = [])
|
8
|
+
super(message)
|
9
|
+
filter = BacktraceFilter.new
|
10
|
+
set_backtrace(filter.filtered(backtrace))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
module Mocha
|
2
|
-
|
3
2
|
class ExceptionRaiser
|
4
|
-
|
5
3
|
def initialize(exception, message)
|
6
|
-
@exception
|
4
|
+
@exception = exception
|
5
|
+
@message = message
|
7
6
|
end
|
8
7
|
|
9
8
|
def evaluate
|
@@ -11,7 +10,5 @@ module Mocha
|
|
11
10
|
raise @exception, @message if @message
|
12
11
|
raise @exception
|
13
12
|
end
|
14
|
-
|
15
13
|
end
|
16
|
-
|
17
14
|
end
|
data/lib/mocha/expectation.rb
CHANGED
@@ -11,10 +11,8 @@ require 'mocha/change_state_side_effect'
|
|
11
11
|
require 'mocha/cardinality'
|
12
12
|
|
13
13
|
module Mocha
|
14
|
-
|
15
14
|
# Methods on expectations returned from {Mock#expects}, {Mock#stubs}, {ObjectMethods#expects} and {ObjectMethods#stubs}.
|
16
15
|
class Expectation
|
17
|
-
|
18
16
|
# Modifies expectation so that the number of calls to the expected method must be within a specific +range+.
|
19
17
|
#
|
20
18
|
# @param [Range,Integer] range specifies the allowable range in the number of expected invocations.
|
@@ -184,7 +182,7 @@ module Mocha
|
|
184
182
|
# object = mock()
|
185
183
|
# object.expects(:expected_method).at_most_once
|
186
184
|
# 2.times { object.expected_method } # => unexpected invocation
|
187
|
-
def at_most_once
|
185
|
+
def at_most_once
|
188
186
|
at_most(1)
|
189
187
|
self
|
190
188
|
end
|
@@ -506,7 +504,8 @@ module Mocha
|
|
506
504
|
@parameters_matcher = ParametersMatcher.new
|
507
505
|
@ordering_constraints = []
|
508
506
|
@side_effects = []
|
509
|
-
@cardinality
|
507
|
+
@cardinality = Cardinality.exactly(1)
|
508
|
+
@invocation_count = 0
|
510
509
|
@return_values = ReturnValues.new
|
511
510
|
@yield_parameters = YieldParameters.new
|
512
511
|
@backtrace = backtrace || caller
|
@@ -529,12 +528,12 @@ module Mocha
|
|
529
528
|
|
530
529
|
# @private
|
531
530
|
def perform_side_effects
|
532
|
-
@side_effects.each
|
531
|
+
@side_effects.each(&:perform)
|
533
532
|
end
|
534
533
|
|
535
534
|
# @private
|
536
535
|
def in_correct_order?
|
537
|
-
@ordering_constraints.all?
|
536
|
+
@ordering_constraints.all?(&:allows_invocation_now?)
|
538
537
|
end
|
539
538
|
|
540
539
|
# @private
|
@@ -560,8 +559,8 @@ module Mocha
|
|
560
559
|
# @private
|
561
560
|
def invoke
|
562
561
|
@invocation_count += 1
|
563
|
-
perform_side_effects
|
564
|
-
if block_given?
|
562
|
+
perform_side_effects
|
563
|
+
if block_given?
|
565
564
|
@yield_parameters.next_invocation.each do |yield_parameters|
|
566
565
|
yield(*yield_parameters)
|
567
566
|
end
|
@@ -584,21 +583,21 @@ module Mocha
|
|
584
583
|
def inspect
|
585
584
|
address = __id__ * 2
|
586
585
|
address += 0x100000000 if address < 0
|
587
|
-
"#<Expectation:0x#{'%x'
|
586
|
+
"#<Expectation:0x#{format('%x', address)} #{mocha_inspect} >"
|
588
587
|
end
|
589
588
|
|
590
589
|
# @private
|
591
590
|
def mocha_inspect
|
592
591
|
message = "#{@cardinality.mocha_inspect}, "
|
593
592
|
message << case @invocation_count
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
message <<
|
593
|
+
when 0 then 'not yet invoked'
|
594
|
+
when 1 then 'invoked once'
|
595
|
+
when 2 then 'invoked twice'
|
596
|
+
else "invoked #{@invocation_count} times"
|
597
|
+
end
|
598
|
+
message << ': '
|
600
599
|
message << method_signature
|
601
|
-
message << "; #{@ordering_constraints.map
|
600
|
+
message << "; #{@ordering_constraints.map(&:mocha_inspect).join('; ')}" unless @ordering_constraints.empty?
|
602
601
|
message
|
603
602
|
end
|
604
603
|
|
@@ -606,7 +605,5 @@ module Mocha
|
|
606
605
|
def method_signature
|
607
606
|
"#{@mock.mocha_inspect}.#{@method_matcher.mocha_inspect}#{@parameters_matcher.mocha_inspect}"
|
608
607
|
end
|
609
|
-
|
610
608
|
end
|
611
|
-
|
612
609
|
end
|
@@ -4,5 +4,7 @@ module Mocha
|
|
4
4
|
# Authors of test libraries may use +Mocha::ExpectationErrorFactory+ to have Mocha raise a different exception.
|
5
5
|
#
|
6
6
|
# @see Mocha::ExpectationErrorFactory
|
7
|
+
# rubocop:disable Lint/InheritException
|
7
8
|
class ExpectationError < Exception; end
|
9
|
+
# rubocop:enable Lint/InheritException
|
8
10
|
end
|