rspec-mocks 2.11.3 → 3.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +1 -1
  5. data/Changelog.md +989 -21
  6. data/{License.txt → LICENSE.md} +5 -3
  7. data/README.md +260 -73
  8. data/lib/rspec/mocks/any_instance/chain.rb +58 -24
  9. data/lib/rspec/mocks/any_instance/error_generator.rb +31 -0
  10. data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +31 -0
  11. data/lib/rspec/mocks/any_instance/expectation_chain.rb +23 -30
  12. data/lib/rspec/mocks/any_instance/message_chains.rb +38 -15
  13. data/lib/rspec/mocks/any_instance/proxy.rb +116 -0
  14. data/lib/rspec/mocks/any_instance/recorder.rb +155 -59
  15. data/lib/rspec/mocks/any_instance/stub_chain.rb +33 -19
  16. data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +10 -12
  17. data/lib/rspec/mocks/any_instance.rb +11 -81
  18. data/lib/rspec/mocks/argument_list_matcher.rb +59 -37
  19. data/lib/rspec/mocks/argument_matchers.rb +233 -149
  20. data/lib/rspec/mocks/configuration.rb +212 -0
  21. data/lib/rspec/mocks/error_generator.rb +304 -49
  22. data/lib/rspec/mocks/example_methods.rb +361 -22
  23. data/lib/rspec/mocks/instance_method_stasher.rb +146 -0
  24. data/lib/rspec/mocks/marshal_extension.rb +41 -0
  25. data/lib/rspec/mocks/matchers/expectation_customization.rb +20 -0
  26. data/lib/rspec/mocks/matchers/have_received.rb +134 -0
  27. data/lib/rspec/mocks/matchers/receive.rb +133 -0
  28. data/lib/rspec/mocks/matchers/receive_message_chain.rb +82 -0
  29. data/lib/rspec/mocks/matchers/receive_messages.rb +77 -0
  30. data/lib/rspec/mocks/message_chain.rb +87 -0
  31. data/lib/rspec/mocks/message_expectation.rb +648 -314
  32. data/lib/rspec/mocks/method_double.rb +185 -58
  33. data/lib/rspec/mocks/method_reference.rb +202 -0
  34. data/lib/rspec/mocks/minitest_integration.rb +68 -0
  35. data/lib/rspec/mocks/mutate_const.rb +339 -0
  36. data/lib/rspec/mocks/object_reference.rb +149 -0
  37. data/lib/rspec/mocks/order_group.rb +48 -7
  38. data/lib/rspec/mocks/proxy.rb +405 -74
  39. data/lib/rspec/mocks/space.rb +219 -15
  40. data/lib/rspec/mocks/standalone.rb +2 -2
  41. data/lib/rspec/mocks/syntax.rb +325 -0
  42. data/lib/rspec/mocks/targets.rb +124 -0
  43. data/lib/rspec/mocks/test_double.rb +125 -57
  44. data/lib/rspec/mocks/verifying_double.rb +121 -0
  45. data/lib/rspec/mocks/verifying_message_expectation.rb +54 -0
  46. data/lib/rspec/mocks/verifying_proxy.rb +220 -0
  47. data/lib/rspec/mocks/version.rb +3 -1
  48. data/lib/rspec/mocks.rb +121 -27
  49. data.tar.gz.sig +0 -0
  50. metadata +178 -253
  51. metadata.gz.sig +3 -0
  52. data/features/README.md +0 -67
  53. data/features/Scope.md +0 -17
  54. data/features/Upgrade.md +0 -22
  55. data/features/argument_matchers/README.md +0 -27
  56. data/features/argument_matchers/explicit.feature +0 -60
  57. data/features/argument_matchers/general_matchers.feature +0 -85
  58. data/features/argument_matchers/type_matchers.feature +0 -27
  59. data/features/message_expectations/README.md +0 -69
  60. data/features/message_expectations/any_instance.feature +0 -21
  61. data/features/message_expectations/block_local_expectations.feature.pending +0 -55
  62. data/features/message_expectations/expect_message.feature +0 -94
  63. data/features/message_expectations/receive_counts.feature +0 -209
  64. data/features/message_expectations/warn_when_expectation_is_set_on_nil.feature +0 -50
  65. data/features/method_stubs/README.md +0 -47
  66. data/features/method_stubs/any_instance.feature +0 -133
  67. data/features/method_stubs/as_null_object.feature +0 -35
  68. data/features/method_stubs/simple_return_value.feature +0 -64
  69. data/features/method_stubs/stub_chain.feature +0 -51
  70. data/features/method_stubs/stub_implementation.feature +0 -26
  71. data/features/method_stubs/to_ary.feature +0 -47
  72. data/features/outside_rspec/configuration.feature +0 -82
  73. data/features/outside_rspec/standalone.feature +0 -32
  74. data/features/step_definitions/additional_cli_steps.rb +0 -4
  75. data/features/stubbing_constants/README.md +0 -62
  76. data/features/stubbing_constants/stub_defined_constant.feature +0 -79
  77. data/features/stubbing_constants/stub_undefined_constant.feature +0 -50
  78. data/features/support/env.rb +0 -6
  79. data/lib/rspec/mocks/errors.rb +0 -12
  80. data/lib/rspec/mocks/extensions/instance_exec.rb +0 -34
  81. data/lib/rspec/mocks/extensions/marshal.rb +0 -23
  82. data/lib/rspec/mocks/extensions/psych.rb +0 -23
  83. data/lib/rspec/mocks/framework.rb +0 -21
  84. data/lib/rspec/mocks/methods.rb +0 -155
  85. data/lib/rspec/mocks/mock.rb +0 -7
  86. data/lib/rspec/mocks/serialization.rb +0 -34
  87. data/lib/rspec/mocks/stashed_instance_method.rb +0 -60
  88. data/lib/rspec/mocks/stub_const.rb +0 -332
  89. data/lib/spec/mocks.rb +0 -2
  90. data/spec/rspec/mocks/and_yield_spec.rb +0 -114
  91. data/spec/rspec/mocks/any_instance/message_chains_spec.rb +0 -40
  92. data/spec/rspec/mocks/any_instance_spec.rb +0 -877
  93. data/spec/rspec/mocks/any_number_of_times_spec.rb +0 -30
  94. data/spec/rspec/mocks/argument_expectation_spec.rb +0 -34
  95. data/spec/rspec/mocks/at_least_spec.rb +0 -142
  96. data/spec/rspec/mocks/at_most_spec.rb +0 -90
  97. data/spec/rspec/mocks/block_return_value_spec.rb +0 -53
  98. data/spec/rspec/mocks/bug_report_10260_spec.rb +0 -8
  99. data/spec/rspec/mocks/bug_report_10263_spec.rb +0 -25
  100. data/spec/rspec/mocks/bug_report_11545_spec.rb +0 -32
  101. data/spec/rspec/mocks/bug_report_496_spec.rb +0 -17
  102. data/spec/rspec/mocks/bug_report_600_spec.rb +0 -22
  103. data/spec/rspec/mocks/bug_report_7611_spec.rb +0 -16
  104. data/spec/rspec/mocks/bug_report_8165_spec.rb +0 -31
  105. data/spec/rspec/mocks/bug_report_830_spec.rb +0 -21
  106. data/spec/rspec/mocks/bug_report_957_spec.rb +0 -22
  107. data/spec/rspec/mocks/double_spec.rb +0 -12
  108. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +0 -95
  109. data/spec/rspec/mocks/hash_excluding_matcher_spec.rb +0 -67
  110. data/spec/rspec/mocks/hash_including_matcher_spec.rb +0 -90
  111. data/spec/rspec/mocks/mock_ordering_spec.rb +0 -103
  112. data/spec/rspec/mocks/mock_space_spec.rb +0 -58
  113. data/spec/rspec/mocks/mock_spec.rb +0 -730
  114. data/spec/rspec/mocks/multiple_return_value_spec.rb +0 -119
  115. data/spec/rspec/mocks/nil_expectation_warning_spec.rb +0 -62
  116. data/spec/rspec/mocks/null_object_mock_spec.rb +0 -106
  117. data/spec/rspec/mocks/once_counts_spec.rb +0 -52
  118. data/spec/rspec/mocks/options_hash_spec.rb +0 -35
  119. data/spec/rspec/mocks/partial_mock_spec.rb +0 -171
  120. data/spec/rspec/mocks/partial_mock_using_mocks_directly_spec.rb +0 -95
  121. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +0 -142
  122. data/spec/rspec/mocks/precise_counts_spec.rb +0 -68
  123. data/spec/rspec/mocks/record_messages_spec.rb +0 -26
  124. data/spec/rspec/mocks/serialization_spec.rb +0 -111
  125. data/spec/rspec/mocks/stash_spec.rb +0 -27
  126. data/spec/rspec/mocks/stashed_instance_method_spec.rb +0 -53
  127. data/spec/rspec/mocks/stub_chain_spec.rb +0 -154
  128. data/spec/rspec/mocks/stub_const_spec.rb +0 -334
  129. data/spec/rspec/mocks/stub_implementation_spec.rb +0 -81
  130. data/spec/rspec/mocks/stub_spec.rb +0 -247
  131. data/spec/rspec/mocks/stubbed_message_expectations_spec.rb +0 -47
  132. data/spec/rspec/mocks/test_double_spec.rb +0 -57
  133. data/spec/rspec/mocks/to_ary_spec.rb +0 -40
  134. data/spec/rspec/mocks/twice_counts_spec.rb +0 -66
  135. data/spec/rspec/mocks_spec.rb +0 -51
  136. data/spec/spec_helper.rb +0 -21
@@ -3,35 +3,49 @@ module RSpec
3
3
  module AnyInstance
4
4
  # @private
5
5
  class StubChain < Chain
6
-
7
- # @private
8
- def initialize(*args, &block)
9
- record(:stub, *args, &block)
10
- end
11
-
12
6
  # @private
13
7
  def expectation_fulfilled?
14
8
  true
15
9
  end
16
10
 
17
- private
11
+ private
12
+
13
+ def create_message_expectation_on(instance)
14
+ proxy = ::RSpec::Mocks.space.proxy_for(instance)
15
+ method_name, opts = @expectation_args
16
+ opts = (opts || {}).merge(:expected_form => IGNORED_BACKTRACE_LINE)
17
+
18
+ stub = proxy.add_stub(method_name, opts, &@expectation_block)
19
+ @recorder.stubs[stub.message] << stub
20
+
21
+ if RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
22
+ stub.and_yield_receiver_to_implementation
23
+ end
24
+
25
+ stub
26
+ end
27
+
28
+ InvocationOrder =
29
+ {
30
+ :and_return => [:with, nil],
31
+ :and_raise => [:with, nil],
32
+ :and_yield => [:with, :and_yield, nil],
33
+ :and_throw => [:with, nil],
34
+ :and_call_original => [:with, nil],
35
+ :and_wrap_original => [:with, nil]
36
+ }.freeze
37
+
38
+ EmptyInvocationOrder = {}.freeze
18
39
 
19
40
  def invocation_order
20
- @invocation_order ||= {
21
- :stub => [nil],
22
- :with => [:stub],
23
- :and_return => [:with, :stub],
24
- :and_raise => [:with, :stub],
25
- :and_yield => [:with, :stub]
26
- }
41
+ InvocationOrder
27
42
  end
28
43
 
29
- def verify_invocation_order(rspec_method_name, *args, &block)
30
- unless invocation_order[rspec_method_name].include?(last_message)
31
- raise(NoMethodError, "Undefined method #{rspec_method_name}")
32
- end
44
+ def verify_invocation_order(rspec_method_name, *_args, &_block)
45
+ return if invocation_order.fetch(rspec_method_name, [nil]).include?(last_message)
46
+ raise NoMethodError, "Undefined method #{rspec_method_name}"
33
47
  end
34
48
  end
35
49
  end
36
50
  end
37
- end
51
+ end
@@ -3,23 +3,21 @@ module RSpec
3
3
  module AnyInstance
4
4
  # @private
5
5
  class StubChainChain < StubChain
6
-
7
- # @private
8
- def initialize(*args, &block)
9
- record(:stub_chain, *args, &block)
6
+ def initialize(*args)
7
+ super
8
+ @expectation_fulfilled = false
10
9
  end
11
10
 
12
- private
11
+ private
12
+
13
+ def create_message_expectation_on(instance)
14
+ ::RSpec::Mocks::StubChain.stub_chain_on(instance, *@expectation_args, &@expectation_block)
15
+ end
13
16
 
14
17
  def invocation_order
15
- @invocation_order ||= {
16
- :stub_chain => [nil],
17
- :and_return => [:stub_chain],
18
- :and_raise => [:stub_chain],
19
- :and_yield => [:stub_chain]
20
- }
18
+ EmptyInvocationOrder
21
19
  end
22
20
  end
23
21
  end
24
22
  end
25
- end
23
+ end
@@ -1,81 +1,11 @@
1
- require 'rspec/mocks/any_instance/chain'
2
- require 'rspec/mocks/any_instance/stub_chain'
3
- require 'rspec/mocks/any_instance/stub_chain_chain'
4
- require 'rspec/mocks/any_instance/expectation_chain'
5
- require 'rspec/mocks/any_instance/message_chains'
6
- require 'rspec/mocks/any_instance/recorder'
7
-
8
- module RSpec
9
- module Mocks
10
- module AnyInstance
11
- # Used to set stubs and message expectations on any instance of a given
12
- # class. Returns a [Recorder](Recorder), which records messages like
13
- # `stub` and `should_receive` for later playback on instances of the
14
- # class.
15
- #
16
- # @example
17
- #
18
- # Car.any_instance.should_receive(:go)
19
- # race = Race.new
20
- # race.cars << Car.new
21
- # race.go # assuming this delegates to all of its cars
22
- # # this example would pass
23
- #
24
- # Account.any_instance.stub(:balance) { Money.new(:USD, 25) }
25
- # Account.new.balance # => Money.new(:USD, 25))
26
- #
27
- # @return [Recorder]
28
- def any_instance
29
- RSpec::Mocks::space.add(self)
30
- modify_dup_to_remove_mock_proxy_when_invoked
31
- __recorder
32
- end
33
-
34
- # @private
35
- def rspec_verify
36
- __recorder.verify
37
- super
38
- ensure
39
- __recorder.stop_all_observation!
40
- restore_dup
41
- @__recorder = nil
42
- end
43
-
44
- # @private
45
- def rspec_reset
46
- restore_dup
47
- __mock_proxy.reset
48
- end
49
-
50
- # @private
51
- def __recorder
52
- @__recorder ||= AnyInstance::Recorder.new(self)
53
- end
54
-
55
- private
56
- def modify_dup_to_remove_mock_proxy_when_invoked
57
- if self.method_defined?(:dup) and !self.method_defined?(:__rspec_original_dup)
58
- self.class_eval do
59
- def __rspec_dup
60
- __remove_mock_proxy
61
- __rspec_original_dup
62
- end
63
-
64
- alias_method :__rspec_original_dup, :dup
65
- alias_method :dup, :__rspec_dup
66
- end
67
- end
68
- end
69
-
70
- def restore_dup
71
- if self.method_defined?(:__rspec_original_dup)
72
- self.class_eval do
73
- alias_method :dup, :__rspec_original_dup
74
- remove_method :__rspec_original_dup
75
- remove_method :__rspec_dup
76
- end
77
- end
78
- end
79
- end
80
- end
81
- end
1
+ %w[
2
+ any_instance/chain
3
+ any_instance/error_generator
4
+ any_instance/stub_chain
5
+ any_instance/stub_chain_chain
6
+ any_instance/expect_chain_chain
7
+ any_instance/expectation_chain
8
+ any_instance/message_chains
9
+ any_instance/recorder
10
+ any_instance/proxy
11
+ ].each { |f| RSpec::Support.require_rspec_mocks(f) }
@@ -1,17 +1,21 @@
1
+ # We intentionally do not use the `RSpec::Support.require...` methods
2
+ # here so that this file can be loaded individually, as documented
3
+ # below.
1
4
  require 'rspec/mocks/argument_matchers'
5
+ require 'rspec/support/fuzzy_matcher'
2
6
 
3
7
  module RSpec
4
8
  module Mocks
5
9
  # Wrapper for matching arguments against a list of expected values. Used by
6
10
  # the `with` method on a `MessageExpectation`:
7
11
  #
8
- # object.should_receive(:message).with(:a, 'b', 3)
12
+ # expect(object).to receive(:message).with(:a, 'b', 3)
9
13
  # object.message(:a, 'b', 3)
10
14
  #
11
15
  # Values passed to `with` can be literal values or argument matchers that
12
16
  # match against the real objects .e.g.
13
17
  #
14
- # object.should_receive(:message).with(hash_including(:a => 'b'))
18
+ # expect(object).to receive(:message).with(hash_including(:a => 'b'))
15
19
  #
16
20
  # Can also be used directly to match the contents of any `Array`. This
17
21
  # enables 3rd party mocking libs to take advantage of rspec's argument
@@ -23,71 +27,89 @@ module RSpec
23
27
  # arg_list_matcher = RSpec::Mocks::ArgumentListMatcher.new(123, hash_including(:a => 'b'))
24
28
  # arg_list_matcher.args_match?(123, :a => 'b')
25
29
  #
30
+ # This class is immutable.
31
+ #
26
32
  # @see ArgumentMatchers
27
33
  class ArgumentListMatcher
28
34
  # @private
29
35
  attr_reader :expected_args
30
36
 
31
37
  # @api public
32
- # @param [Array] *expected_args a list of expected literals and/or argument matchers
33
- # @param [Block] block a block with arity matching the expected
38
+ # @param [Array] expected_args a list of expected literals and/or argument matchers
34
39
  #
35
40
  # Initializes an `ArgumentListMatcher` with a collection of literal
36
- # values and/or argument matchers, or a block that handles the evaluation
37
- # for you.
41
+ # values and/or argument matchers.
38
42
  #
39
43
  # @see ArgumentMatchers
40
44
  # @see #args_match?
41
- def initialize(*expected_args, &block)
45
+ def initialize(*expected_args)
42
46
  @expected_args = expected_args
43
- @block = expected_args.empty? ? block : nil
44
- @match_any_args = false
45
- @matchers = nil
46
-
47
- case expected_args.first
48
- when ArgumentMatchers::AnyArgsMatcher
49
- @match_any_args = true
50
- when ArgumentMatchers::NoArgsMatcher
51
- @matchers = []
52
- else
53
- @matchers = expected_args.collect {|arg| matcher_for(arg)}
54
- end
47
+ ensure_expected_args_valid!
55
48
  end
49
+ ruby2_keywords :initialize if respond_to?(:ruby2_keywords, true)
56
50
 
57
51
  # @api public
58
- # @param [Array] *args
52
+ # @param [Array] actual_args
59
53
  #
60
54
  # Matches each element in the `expected_args` against the element in the same
61
55
  # position of the arguments passed to `new`.
62
56
  #
63
57
  # @see #initialize
64
- def args_match?(*args)
65
- match_any_args? || block_passes?(*args) || matchers_match?(*args)
66
- end
58
+ def args_match?(*actual_args)
59
+ expected_args = resolve_expected_args_based_on(actual_args)
67
60
 
68
- private
61
+ return false if expected_args.size != actual_args.size
69
62
 
70
- def matcher_for(arg)
71
- return ArgumentMatchers::MatcherMatcher.new(arg) if is_matcher?(arg)
72
- return ArgumentMatchers::RegexpMatcher.new(arg) if arg.is_a?(Regexp)
73
- return ArgumentMatchers::EqualityProxy.new(arg)
74
- end
63
+ if RUBY_VERSION >= "3"
64
+ # if both arguments end with Hashes, and if one is a keyword hash and the other is not, they don't match
65
+ if Hash === expected_args.last && Hash === actual_args.last
66
+ if !Hash.ruby2_keywords_hash?(actual_args.last) && Hash.ruby2_keywords_hash?(expected_args.last)
67
+ return false
68
+ end
69
+ end
70
+ end
75
71
 
76
- def is_matcher?(obj)
77
- !obj.null_object? & obj.respond_to?(:matches?) & [:failure_message_for_should, :failure_message].any? { |m| obj.respond_to?(m) }
72
+ Support::FuzzyMatcher.values_match?(expected_args, actual_args)
78
73
  end
74
+ ruby2_keywords :args_match? if respond_to?(:ruby2_keywords, true)
75
+
76
+ # @private
77
+ # Resolves abstract arg placeholders like `no_args` and `any_args` into
78
+ # a more concrete arg list based on the provided `actual_args`.
79
+ def resolve_expected_args_based_on(actual_args)
80
+ return [] if [ArgumentMatchers::NoArgsMatcher::INSTANCE] == expected_args
79
81
 
80
- def block_passes?(*args)
81
- @block.call(*args) if @block
82
+ any_args_index = expected_args.index { |a| ArgumentMatchers::AnyArgsMatcher::INSTANCE == a }
83
+ return expected_args unless any_args_index
84
+
85
+ replace_any_args_with_splat_of_anything(any_args_index, actual_args.count)
82
86
  end
83
87
 
84
- def matchers_match?(*args)
85
- @matchers == args
88
+ private
89
+
90
+ def replace_any_args_with_splat_of_anything(before_count, actual_args_count)
91
+ any_args_count = actual_args_count - expected_args.count + 1
92
+ after_count = expected_args.count - before_count - 1
93
+
94
+ any_args = 1.upto(any_args_count).map { ArgumentMatchers::AnyArgMatcher::INSTANCE }
95
+ expected_args.first(before_count) + any_args + expected_args.last(after_count)
86
96
  end
87
97
 
88
- def match_any_args?
89
- @match_any_args
98
+ def ensure_expected_args_valid!
99
+ if expected_args.count { |a| ArgumentMatchers::AnyArgsMatcher::INSTANCE == a } > 1
100
+ raise ArgumentError, "`any_args` can only be passed to " \
101
+ "`with` once but you have passed it multiple times."
102
+ elsif expected_args.count > 1 && expected_args.any? { |a| ArgumentMatchers::NoArgsMatcher::INSTANCE == a }
103
+ raise ArgumentError, "`no_args` can only be passed as a " \
104
+ "singleton argument to `with` (i.e. `with(no_args)`), " \
105
+ "but you have passed additional arguments."
106
+ end
90
107
  end
108
+
109
+ # Value that will match all argument lists.
110
+ #
111
+ # @private
112
+ MATCH_ALL = new(ArgumentMatchers::AnyArgsMatcher::INSTANCE)
91
113
  end
92
114
  end
93
115
  end