rspec-mocks 3.0.0.beta1 → 3.0.0.beta2

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.
Files changed (114) hide show
  1. data.tar.gz.sig +1 -1
  2. data/Changelog.md +95 -3
  3. data/README.md +27 -13
  4. data/features/README.md +15 -7
  5. data/features/argument_matchers/README.md +5 -5
  6. data/features/argument_matchers/explicit.feature +6 -6
  7. data/features/argument_matchers/general_matchers.feature +4 -4
  8. data/features/argument_matchers/type_matchers.feature +2 -2
  9. data/features/message_expectations/README.md +29 -27
  10. data/features/message_expectations/call_original.feature +0 -1
  11. data/features/message_expectations/message_chains_using_expect.feature +49 -0
  12. data/features/method_stubs/README.md +2 -1
  13. data/features/method_stubs/{any_instance.feature → allow_any_instance_of.feature} +12 -12
  14. data/features/method_stubs/{stub_chain.feature → receive_message_chain.feature} +3 -3
  15. data/features/method_stubs/to_ary.feature +1 -1
  16. data/features/mutating_constants/stub_defined_constant.feature +0 -1
  17. data/features/outside_rspec/standalone.feature +1 -1
  18. data/features/spies/spy_pure_mock_method.feature +1 -1
  19. data/features/test_frameworks/test_unit.feature +21 -10
  20. data/features/verifying_doubles/README.md +17 -0
  21. data/features/verifying_doubles/class_doubles.feature +1 -16
  22. data/features/verifying_doubles/dynamic_classes.feature +0 -1
  23. data/features/verifying_doubles/{introduction.feature → instance_doubles.feature} +41 -23
  24. data/features/verifying_doubles/partial_doubles.feature +2 -2
  25. data/lib/rspec/mocks.rb +69 -82
  26. data/lib/rspec/mocks/any_instance/expect_chain_chain.rb +35 -0
  27. data/lib/rspec/mocks/any_instance/expectation_chain.rb +1 -2
  28. data/lib/rspec/mocks/any_instance/recorder.rb +52 -18
  29. data/lib/rspec/mocks/any_instance/stub_chain.rb +1 -1
  30. data/lib/rspec/mocks/any_instance/stub_chain_chain.rb +4 -0
  31. data/lib/rspec/mocks/argument_list_matcher.rb +10 -44
  32. data/lib/rspec/mocks/argument_matchers.rb +132 -163
  33. data/lib/rspec/mocks/configuration.rb +28 -4
  34. data/lib/rspec/mocks/error_generator.rb +46 -13
  35. data/lib/rspec/mocks/example_methods.rb +13 -12
  36. data/lib/rspec/mocks/extensions/marshal.rb +1 -1
  37. data/lib/rspec/mocks/framework.rb +3 -4
  38. data/lib/rspec/mocks/instance_method_stasher.rb +2 -3
  39. data/lib/rspec/mocks/matchers/have_received.rb +8 -6
  40. data/lib/rspec/mocks/matchers/receive.rb +28 -20
  41. data/lib/rspec/mocks/matchers/receive_message_chain.rb +65 -0
  42. data/lib/rspec/mocks/matchers/receive_messages.rb +3 -2
  43. data/lib/rspec/mocks/message_chain.rb +91 -0
  44. data/lib/rspec/mocks/message_expectation.rb +86 -80
  45. data/lib/rspec/mocks/method_double.rb +2 -11
  46. data/lib/rspec/mocks/method_reference.rb +82 -23
  47. data/lib/rspec/mocks/method_signature_verifier.rb +207 -0
  48. data/lib/rspec/mocks/mutate_const.rb +34 -50
  49. data/lib/rspec/mocks/object_reference.rb +0 -1
  50. data/lib/rspec/mocks/proxy.rb +70 -13
  51. data/lib/rspec/mocks/ruby_features.rb +24 -0
  52. data/lib/rspec/mocks/space.rb +105 -31
  53. data/lib/rspec/mocks/standalone.rb +2 -2
  54. data/lib/rspec/mocks/syntax.rb +43 -8
  55. data/lib/rspec/mocks/targets.rb +16 -7
  56. data/lib/rspec/mocks/test_double.rb +41 -15
  57. data/lib/rspec/mocks/verifying_double.rb +51 -4
  58. data/lib/rspec/mocks/verifying_message_expecation.rb +12 -12
  59. data/lib/rspec/mocks/verifying_proxy.rb +32 -19
  60. data/lib/rspec/mocks/version.rb +1 -1
  61. data/spec/rspec/mocks/and_call_original_spec.rb +28 -7
  62. data/spec/rspec/mocks/and_return_spec.rb +23 -0
  63. data/spec/rspec/mocks/and_yield_spec.rb +1 -2
  64. data/spec/rspec/mocks/any_instance_spec.rb +33 -17
  65. data/spec/rspec/mocks/array_including_matcher_spec.rb +6 -6
  66. data/spec/rspec/mocks/before_all_spec.rb +132 -0
  67. data/spec/rspec/mocks/block_return_value_spec.rb +12 -1
  68. data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +9 -11
  69. data/spec/rspec/mocks/configuration_spec.rb +14 -1
  70. data/spec/rspec/mocks/double_spec.rb +867 -24
  71. data/spec/rspec/mocks/example_methods_spec.rb +13 -0
  72. data/spec/rspec/mocks/extensions/marshal_spec.rb +17 -17
  73. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +29 -1
  74. data/spec/rspec/mocks/hash_excluding_matcher_spec.rb +12 -12
  75. data/spec/rspec/mocks/hash_including_matcher_spec.rb +21 -17
  76. data/spec/rspec/mocks/instance_method_stasher_spec.rb +2 -3
  77. data/spec/rspec/mocks/matchers/have_received_spec.rb +7 -0
  78. data/spec/rspec/mocks/matchers/receive_message_chain_spec.rb +198 -0
  79. data/spec/rspec/mocks/matchers/receive_messages_spec.rb +2 -2
  80. data/spec/rspec/mocks/matchers/receive_spec.rb +19 -6
  81. data/spec/rspec/mocks/method_signature_verifier_spec.rb +272 -0
  82. data/spec/rspec/mocks/methods_spec.rb +0 -1
  83. data/spec/rspec/mocks/multiple_return_value_spec.rb +2 -2
  84. data/spec/rspec/mocks/mutate_const_spec.rb +24 -1
  85. data/spec/rspec/mocks/nil_expectation_warning_spec.rb +6 -22
  86. data/spec/rspec/mocks/null_object_mock_spec.rb +13 -7
  87. data/spec/rspec/mocks/options_hash_spec.rb +3 -3
  88. data/spec/rspec/mocks/{partial_mock_spec.rb → partial_double_spec.rb} +5 -2
  89. data/spec/rspec/mocks/{partial_mock_using_mocks_directly_spec.rb → partial_double_using_mocks_directly_spec.rb} +1 -1
  90. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +18 -0
  91. data/spec/rspec/mocks/serialization_spec.rb +1 -0
  92. data/spec/rspec/mocks/space_spec.rb +218 -7
  93. data/spec/rspec/mocks/stub_chain_spec.rb +6 -0
  94. data/spec/rspec/mocks/stub_spec.rb +0 -6
  95. data/spec/rspec/mocks/syntax_spec.rb +19 -0
  96. data/spec/rspec/mocks/test_double_spec.rb +0 -1
  97. data/spec/rspec/mocks/verifying_double_spec.rb +281 -18
  98. data/spec/rspec/mocks/verifying_message_expecation_spec.rb +7 -6
  99. data/spec/rspec/mocks_spec.rb +168 -42
  100. data/spec/spec_helper.rb +34 -22
  101. metadata +94 -63
  102. metadata.gz.sig +0 -0
  103. checksums.yaml +0 -15
  104. checksums.yaml.gz.sig +0 -2
  105. data/features/outside_rspec/configuration.feature +0 -60
  106. data/lib/rspec/mocks/arity_calculator.rb +0 -66
  107. data/lib/rspec/mocks/errors.rb +0 -12
  108. data/lib/rspec/mocks/mock.rb +0 -7
  109. data/lib/rspec/mocks/proxy_for_nil.rb +0 -37
  110. data/lib/rspec/mocks/stub_chain.rb +0 -51
  111. data/spec/rspec/mocks/argument_expectation_spec.rb +0 -32
  112. data/spec/rspec/mocks/arity_calculator_spec.rb +0 -95
  113. data/spec/rspec/mocks/mock_space_spec.rb +0 -113
  114. data/spec/rspec/mocks/mock_spec.rb +0 -788
@@ -0,0 +1,35 @@
1
+ module RSpec
2
+ module Mocks
3
+ module AnyInstance
4
+ # @private
5
+ class ExpectChainChain < StubChain
6
+ def initialize(*args)
7
+ super
8
+ @expectation_fulfilled = false
9
+ end
10
+
11
+ def expectation_fulfilled?
12
+ @expectation_fulfilled
13
+ end
14
+
15
+ def playback!(instance)
16
+ super.tap { @expectation_fulfilled = true }
17
+ end
18
+
19
+ private
20
+
21
+ def create_message_expectation_on(instance)
22
+ ::RSpec::Mocks::ExpectChain.expect_chain_on(instance, *@expectation_args, &@expectation_block)
23
+ end
24
+
25
+ def invocation_order
26
+ @invocation_order ||= {
27
+ :and_return => [nil],
28
+ :and_raise => [nil],
29
+ :and_yield => [nil]
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -23,7 +23,7 @@ module RSpec
23
23
  private
24
24
 
25
25
  def create_message_expectation_on(instance)
26
- proxy = ::RSpec::Mocks.proxy_for(instance)
26
+ proxy = ::RSpec::Mocks.space.proxy_for(instance)
27
27
  expected_from = IGNORED_BACKTRACE_LINE
28
28
  me = proxy.add_message_expectation(expected_from, *@expectation_args, &@expectation_block)
29
29
  if RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
@@ -44,4 +44,3 @@ module RSpec
44
44
  end
45
45
  end
46
46
  end
47
-
@@ -49,6 +49,15 @@ module RSpec
49
49
  end
50
50
  end
51
51
 
52
+ # @api private
53
+ def expect_chain(*method_names_and_optional_return_values, &block)
54
+ @expectation_set = true
55
+ normalize_chain(*method_names_and_optional_return_values) do |method_name, args|
56
+ observe!(method_name)
57
+ message_chains.add(method_name, ExpectChainChain.new(self, *args, &block))
58
+ end
59
+ end
60
+
52
61
  # Initializes the recording a message expectation to be played back
53
62
  # against any instance of this object that invokes the submitted
54
63
  # method.
@@ -73,7 +82,7 @@ module RSpec
73
82
  raise RSpec::Mocks::MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed"
74
83
  end
75
84
  message_chains.remove_stub_chains_for!(method_name)
76
- ::RSpec::Mocks.proxies_of(@klass).each do |proxy|
85
+ ::RSpec::Mocks.space.proxies_of(@klass).each do |proxy|
77
86
  stubs[method_name].each { |stub| proxy.remove_single_stub(method_name, stub) }
78
87
  end
79
88
  stubs[method_name].clear
@@ -116,10 +125,38 @@ module RSpec
116
125
  end
117
126
 
118
127
  def already_observing?(method_name)
119
- @observed_methods.include?(method_name)
128
+ @observed_methods.include?(method_name) || super_class_observing?(method_name)
129
+ end
130
+
131
+ protected
132
+
133
+ def stop_observing!(method_name)
134
+ restore_method!(method_name)
135
+ @observed_methods.delete(method_name)
136
+ super_class_observers_for(method_name).each do |ancestor|
137
+ ::RSpec::Mocks.space.
138
+ any_instance_recorder_for(ancestor).stop_observing!(method_name)
139
+ end
120
140
  end
121
141
 
122
- private
142
+ private
143
+
144
+ def ancestor_is_an_observer?(method_name)
145
+ lambda do |ancestor|
146
+ unless ancestor == @klass
147
+ ::RSpec::Mocks.space.
148
+ any_instance_recorder_for(ancestor).already_observing?(method_name)
149
+ end
150
+ end
151
+ end
152
+
153
+ def super_class_observers_for(method_name)
154
+ @klass.ancestors.select(&ancestor_is_an_observer?(method_name))
155
+ end
156
+
157
+ def super_class_observing?(method_name)
158
+ @klass.ancestors.any?(&ancestor_is_an_observer?(method_name))
159
+ end
123
160
 
124
161
  def normalize_chain(*args)
125
162
  args.shift.to_s.split('.').map {|s| s.to_sym}.reverse.each {|a| args.unshift a}
@@ -141,11 +178,13 @@ module RSpec
141
178
  end
142
179
 
143
180
  def restore_original_method!(method_name)
144
- alias_method_name = build_alias_method_name(method_name)
145
- @klass.class_exec do
146
- remove_method method_name
147
- alias_method method_name, alias_method_name
148
- remove_method alias_method_name
181
+ if @klass.instance_method(method_name).owner == @klass
182
+ alias_method_name = build_alias_method_name(method_name)
183
+ @klass.class_exec do
184
+ remove_method method_name
185
+ alias_method method_name, alias_method_name
186
+ remove_method alias_method_name
187
+ end
149
188
  end
150
189
  end
151
190
 
@@ -163,12 +202,7 @@ module RSpec
163
202
  end
164
203
 
165
204
  def public_protected_or_private_method_defined?(method_name)
166
- @klass.method_defined?(method_name) || @klass.private_method_defined?(method_name)
167
- end
168
-
169
- def stop_observing!(method_name)
170
- restore_method!(method_name)
171
- @observed_methods.delete(method_name)
205
+ MethodReference.method_defined_at_any_visibility?(@klass, method_name)
172
206
  end
173
207
 
174
208
  def observe!(method_name)
@@ -180,8 +214,8 @@ module RSpec
180
214
  @observed_methods << method_name
181
215
  backup_method!(method_name)
182
216
  @klass.__send__(:define_method, method_name) do |*args, &blk|
183
- klass = ::RSpec::Mocks.method_handle_for(self, method_name).owner
184
- ::RSpec::Mocks.any_instance_recorder_for(klass).playback!(self, method_name)
217
+ klass = ::RSpec::Support.method_handle_for(self, method_name).owner
218
+ ::RSpec::Mocks.space.any_instance_recorder_for(klass).playback!(self, method_name)
185
219
  self.__send__(method_name, *args, &blk)
186
220
  end
187
221
  end
@@ -189,8 +223,8 @@ module RSpec
189
223
  def mark_invoked!(method_name)
190
224
  backup_method!(method_name)
191
225
  @klass.__send__(:define_method, method_name) do |*args, &blk|
192
- klass = ::RSpec::Mocks.method_handle_for(self, method_name).owner
193
- invoked_instance = ::RSpec::Mocks.any_instance_recorder_for(klass).instance_that_received(method_name)
226
+ klass = ::RSpec::Support.method_handle_for(self, method_name).owner
227
+ invoked_instance = ::RSpec::Mocks.space.any_instance_recorder_for(klass).instance_that_received(method_name)
194
228
  raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by #{self.inspect} but has already been received by #{invoked_instance}"
195
229
  end
196
230
  end
@@ -12,7 +12,7 @@ module RSpec
12
12
  private
13
13
 
14
14
  def create_message_expectation_on(instance)
15
- proxy = ::RSpec::Mocks.proxy_for(instance)
15
+ proxy = ::RSpec::Mocks.space.proxy_for(instance)
16
16
  expected_from = IGNORED_BACKTRACE_LINE
17
17
  stub = proxy.add_stub(expected_from, *@expectation_args, &@expectation_block)
18
18
  @recorder.stubs[stub.message] << stub
@@ -3,6 +3,10 @@ module RSpec
3
3
  module AnyInstance
4
4
  # @private
5
5
  class StubChainChain < StubChain
6
+ def initialize(*args)
7
+ super
8
+ @expectation_fulfilled = false
9
+ end
6
10
 
7
11
  private
8
12
 
@@ -1,17 +1,18 @@
1
1
  require 'rspec/mocks/argument_matchers'
2
+ require 'rspec/support/fuzzy_matcher'
2
3
 
3
4
  module RSpec
4
5
  module Mocks
5
6
  # Wrapper for matching arguments against a list of expected values. Used by
6
7
  # the `with` method on a `MessageExpectation`:
7
8
  #
8
- # object.should_receive(:message).with(:a, 'b', 3)
9
+ # expect(object).to receive(:message).with(:a, 'b', 3)
9
10
  # object.message(:a, 'b', 3)
10
11
  #
11
12
  # Values passed to `with` can be literal values or argument matchers that
12
13
  # match against the real objects .e.g.
13
14
  #
14
- # object.should_receive(:message).with(hash_including(:a => 'b'))
15
+ # expect(object).to receive(:message).with(hash_including(:a => 'b'))
15
16
  #
16
17
  # Can also be used directly to match the contents of any `Array`. This
17
18
  # enables 3rd party mocking libs to take advantage of rspec's argument
@@ -35,24 +36,17 @@ module RSpec
35
36
  # @param [Block] block a block with arity matching the expected
36
37
  #
37
38
  # Initializes an `ArgumentListMatcher` with a collection of literal
38
- # values and/or argument matchers, or a block that handles the evaluation
39
- # for you.
39
+ # values and/or argument matchers.
40
40
  #
41
41
  # @see ArgumentMatchers
42
42
  # @see #args_match?
43
- def initialize(*expected_args, &block)
43
+ def initialize(*expected_args)
44
44
  @expected_args = expected_args
45
- @block = expected_args.empty? ? block : nil
46
- @match_any_args = false
47
- @matchers = nil
48
45
 
49
- case expected_args.first
50
- when ArgumentMatchers::AnyArgsMatcher
51
- @match_any_args = true
52
- when ArgumentMatchers::NoArgsMatcher
53
- @matchers = []
54
- else
55
- @matchers = expected_args.collect {|arg| matcher_for(arg)}
46
+ @matchers = case expected_args.first
47
+ when ArgumentMatchers::AnyArgsMatcher then Array
48
+ when ArgumentMatchers::NoArgsMatcher then []
49
+ else expected_args
56
50
  end
57
51
  end
58
52
 
@@ -64,35 +58,7 @@ module RSpec
64
58
  #
65
59
  # @see #initialize
66
60
  def args_match?(*args)
67
- match_any_args? || block_passes?(*args) || matchers_match?(*args)
68
- end
69
-
70
- private
71
-
72
- def matcher_for(arg)
73
- return ArgumentMatchers::MatcherMatcher.new(arg) if is_matcher?(arg)
74
- return ArgumentMatchers::RegexpMatcher.new(arg) if Regexp === arg
75
- return ArgumentMatchers::EqualityProxy.new(arg)
76
- end
77
-
78
- def is_matcher?(object)
79
- return false if object.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
80
-
81
- [:failure_message_for_should, :failure_message].any? do |msg|
82
- object.respond_to?(msg)
83
- end && object.respond_to?(:matches?)
84
- end
85
-
86
- def block_passes?(*args)
87
- @block.call(*args) if @block
88
- end
89
-
90
- def matchers_match?(*args)
91
- @matchers == args
92
- end
93
-
94
- def match_any_args?
95
- @match_any_args
61
+ Support::FuzzyMatcher.values_match?(@matchers, args)
96
62
  end
97
63
 
98
64
  # Value that will match all argument lists.
@@ -10,149 +10,12 @@ module RSpec
10
10
  #
11
11
  # @see ArgumentListMatcher
12
12
  module ArgumentMatchers
13
-
14
- class AnyArgsMatcher
15
- def description
16
- "any args"
17
- end
18
- end
19
-
20
- class AnyArgMatcher
21
- def initialize(ignore)
22
- end
23
-
24
- def ==(other)
25
- true
26
- end
27
- end
28
-
29
- class NoArgsMatcher
30
- def description
31
- "no args"
32
- end
33
- end
34
-
35
- class RegexpMatcher
36
- def initialize(regexp)
37
- @regexp = regexp
38
- end
39
-
40
- def ==(value)
41
- Regexp === value ? value == @regexp : value =~ @regexp
42
- end
43
- end
44
-
45
- class BooleanMatcher
46
- def initialize(ignore)
47
- end
48
-
49
- def ==(value)
50
- [true,false].include?(value)
51
- end
52
- end
53
-
54
- class HashIncludingMatcher
55
- def initialize(expected)
56
- @expected = expected
57
- end
58
-
59
- def ==(actual)
60
- @expected.all? {|k,v| actual.has_key?(k) && v == actual[k]}
61
- rescue NoMethodError
62
- false
63
- end
64
-
65
- def description
66
- "hash_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
67
- end
68
- end
69
-
70
- class HashExcludingMatcher
71
- def initialize(expected)
72
- @expected = expected
73
- end
74
-
75
- def ==(actual)
76
- @expected.none? {|k,v| actual.has_key?(k) && v == actual[k]}
77
- rescue NoMethodError
78
- false
79
- end
80
-
81
- def description
82
- "hash_not_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
83
- end
84
- end
85
-
86
- class ArrayIncludingMatcher
87
- def initialize(expected)
88
- @expected = expected
89
- end
90
-
91
- def ==(actual)
92
- Set.new(actual).superset?(Set.new(@expected))
93
- end
94
-
95
- def description
96
- "array_including(#{@expected.join(",")})"
97
- end
98
- end
99
-
100
- class DuckTypeMatcher
101
- def initialize(*methods_to_respond_to)
102
- @methods_to_respond_to = methods_to_respond_to
103
- end
104
-
105
- def ==(value)
106
- @methods_to_respond_to.all? {|message| value.respond_to?(message)}
107
- end
108
- end
109
-
110
- class MatcherMatcher
111
- def initialize(matcher)
112
- @matcher = matcher
113
- end
114
-
115
- def ==(value)
116
- @matcher.matches?(value)
117
- end
118
- end
119
-
120
- class EqualityProxy
121
- def initialize(given)
122
- @given = given
123
- end
124
-
125
- def ==(expected)
126
- @given == expected
127
- end
128
- end
129
-
130
- class InstanceOf
131
- def initialize(klass)
132
- @klass = klass
133
- end
134
-
135
- def ==(actual)
136
- actual.instance_of?(@klass)
137
- end
138
- end
139
-
140
- class KindOf
141
- def initialize(klass)
142
- @klass = klass
143
- end
144
-
145
- def ==(actual)
146
- actual.kind_of?(@klass)
147
- end
148
- end
149
-
150
13
  # Matches any args at all. Supports a more explicit variation of
151
- # `object.should_receive(:message)`
14
+ # `expect(object).to receive(:message)`
152
15
  #
153
16
  # @example
154
17
  #
155
- # object.should_receive(:message).with(any_args)
18
+ # expect(object).to receive(:message).with(any_args)
156
19
  def any_args
157
20
  AnyArgsMatcher.new
158
21
  end
@@ -161,16 +24,16 @@ module RSpec
161
24
  #
162
25
  # @example
163
26
  #
164
- # object.should_receive(:message).with(anything)
27
+ # expect(object).to receive(:message).with(anything)
165
28
  def anything
166
- AnyArgMatcher.new(nil)
29
+ AnyArgMatcher.new
167
30
  end
168
31
 
169
32
  # Matches no arguments.
170
33
  #
171
34
  # @example
172
35
  #
173
- # object.should_receive(:message).with(no_args)
36
+ # expect(object).to receive(:message).with(no_args)
174
37
  def no_args
175
38
  NoArgsMatcher.new
176
39
  end
@@ -179,8 +42,8 @@ module RSpec
179
42
  #
180
43
  # @example
181
44
  #
182
- # object.should_receive(:message).with(duck_type(:hello))
183
- # object.should_receive(:message).with(duck_type(:hello, :goodbye))
45
+ # expect(object).to receive(:message).with(duck_type(:hello))
46
+ # expect(object).to receive(:message).with(duck_type(:hello, :goodbye))
184
47
  def duck_type(*args)
185
48
  DuckTypeMatcher.new(*args)
186
49
  end
@@ -189,9 +52,9 @@ module RSpec
189
52
  #
190
53
  # @example
191
54
  #
192
- # object.should_receive(:message).with(boolean())
55
+ # expect(object).to receive(:message).with(boolean())
193
56
  def boolean
194
- BooleanMatcher.new(nil)
57
+ BooleanMatcher.new
195
58
  end
196
59
 
197
60
  # Matches a hash that includes the specified key(s) or key/value pairs.
@@ -199,11 +62,11 @@ module RSpec
199
62
  #
200
63
  # @example
201
64
  #
202
- # object.should_receive(:message).with(hash_including(:key => val))
203
- # object.should_receive(:message).with(hash_including(:key))
204
- # object.should_receive(:message).with(hash_including(:key, :key2 => val2))
65
+ # expect(object).to receive(:message).with(hash_including(:key => val))
66
+ # expect(object).to receive(:message).with(hash_including(:key))
67
+ # expect(object).to receive(:message).with(hash_including(:key, :key2 => val2))
205
68
  def hash_including(*args)
206
- HashIncludingMatcher.new(anythingize_lonely_keys(*args))
69
+ HashIncludingMatcher.new(ArgumentMatchers.anythingize_lonely_keys(*args))
207
70
  end
208
71
 
209
72
  # Matches an array that includes the specified items at least once.
@@ -211,8 +74,8 @@ module RSpec
211
74
  #
212
75
  # @example
213
76
  #
214
- # object.should_receive(:message).with(array_including(1,2,3))
215
- # object.should_receive(:message).with(array_including([1,2,3]))
77
+ # expect(object).to receive(:message).with(array_including(1,2,3))
78
+ # expect(object).to receive(:message).with(array_including([1,2,3]))
216
79
  def array_including(*args)
217
80
  actually_an_array = Array === args.first && args.count == 1 ? args.first : args
218
81
  ArrayIncludingMatcher.new(actually_an_array)
@@ -222,11 +85,11 @@ module RSpec
222
85
  #
223
86
  # @example
224
87
  #
225
- # object.should_receive(:message).with(hash_excluding(:key => val))
226
- # object.should_receive(:message).with(hash_excluding(:key))
227
- # object.should_receive(:message).with(hash_excluding(:key, :key2 => :val2))
88
+ # expect(object).to receive(:message).with(hash_excluding(:key => val))
89
+ # expect(object).to receive(:message).with(hash_excluding(:key))
90
+ # expect(object).to receive(:message).with(hash_excluding(:key, :key2 => :val2))
228
91
  def hash_excluding(*args)
229
- HashExcludingMatcher.new(anythingize_lonely_keys(*args))
92
+ HashExcludingMatcher.new(ArgumentMatchers.anythingize_lonely_keys(*args))
230
93
  end
231
94
 
232
95
  alias_method :hash_not_including, :hash_excluding
@@ -235,7 +98,7 @@ module RSpec
235
98
  #
236
99
  # @example
237
100
  #
238
- # object.should_receive(:message).with(instance_of(Thing))
101
+ # expect(object).to receive(:message).with(instance_of(Thing))
239
102
  def instance_of(klass)
240
103
  InstanceOf.new(klass)
241
104
  end
@@ -245,20 +108,126 @@ module RSpec
245
108
  # Matches if `arg.kind_of?(klass)`
246
109
  # @example
247
110
  #
248
- # object.should_receive(:message).with(kind_of(Thing))
111
+ # expect(object).to receive(:message).with(kind_of(Thing))
249
112
  def kind_of(klass)
250
- KindOf.new(klass)
113
+ klass
251
114
  end
252
115
 
253
116
  alias_method :a_kind_of, :kind_of
254
117
 
255
- private
256
-
257
- def anythingize_lonely_keys(*args)
118
+ # @api private
119
+ def self.anythingize_lonely_keys(*args)
258
120
  hash = args.last.class == Hash ? args.delete_at(-1) : {}
259
- args.each { | arg | hash[arg] = anything }
121
+ args.each { | arg | hash[arg] = AnyArgMatcher.new }
260
122
  hash
261
123
  end
124
+
125
+ # @api private
126
+ class AnyArgsMatcher
127
+ def description
128
+ "any args"
129
+ end
130
+ end
131
+
132
+ # @api private
133
+ class AnyArgMatcher
134
+ def ===(other)
135
+ true
136
+ end
137
+ end
138
+
139
+ # @api private
140
+ class NoArgsMatcher
141
+ def description
142
+ "no args"
143
+ end
144
+ end
145
+
146
+ # @api private
147
+ class BooleanMatcher
148
+ def ===(value)
149
+ true == value || false == value
150
+ end
151
+ end
152
+
153
+ # @api private
154
+ class BaseHashMatcher
155
+ def initialize(expected)
156
+ @expected = expected
157
+ end
158
+
159
+ def ===(predicate, actual)
160
+ @expected.__send__(predicate) do |k, v|
161
+ actual.has_key?(k) && Support::FuzzyMatcher.values_match?(v, actual[k])
162
+ end
163
+ rescue NoMethodError
164
+ false
165
+ end
166
+
167
+ def description(name)
168
+ "#{name}(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
169
+ end
170
+ end
171
+
172
+ # @api private
173
+ class HashIncludingMatcher < BaseHashMatcher
174
+ def ===(actual)
175
+ super(:all?, actual)
176
+ end
177
+
178
+ def description
179
+ super("hash_including")
180
+ end
181
+ end
182
+
183
+ # @api private
184
+ class HashExcludingMatcher < BaseHashMatcher
185
+ def ===(actual)
186
+ super(:none?, actual)
187
+ end
188
+
189
+ def description
190
+ super("hash_not_including")
191
+ end
192
+ end
193
+
194
+ # @api private
195
+ class ArrayIncludingMatcher
196
+ def initialize(expected)
197
+ @expected = expected
198
+ end
199
+
200
+ def ===(actual)
201
+ Set.new(actual).superset?(Set.new(@expected))
202
+ end
203
+
204
+ def description
205
+ "array_including(#{@expected.join(",")})"
206
+ end
207
+ end
208
+
209
+ # @api private
210
+ class DuckTypeMatcher
211
+ def initialize(*methods_to_respond_to)
212
+ @methods_to_respond_to = methods_to_respond_to
213
+ end
214
+
215
+ def ===(value)
216
+ @methods_to_respond_to.all? {|message| value.respond_to?(message)}
217
+ end
218
+ end
219
+
220
+ # @api private
221
+ class InstanceOf
222
+ def initialize(klass)
223
+ @klass = klass
224
+ end
225
+
226
+ def ===(actual)
227
+ actual.instance_of?(@klass)
228
+ end
229
+ end
230
+
262
231
  end
263
232
  end
264
233
  end