rspec-mocks 3.0.0.beta1 → 3.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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