opal-rspec-cj 0.4.4

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 (176) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +15 -0
  4. data/.travis.yml +13 -0
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +25 -0
  7. data/Gemfile +8 -0
  8. data/README.md +147 -0
  9. data/Rakefile +26 -0
  10. data/config.ru +10 -0
  11. data/example/Gemfile +4 -0
  12. data/example/README.md +13 -0
  13. data/example/Rakefile +8 -0
  14. data/example/opal/user.rb +11 -0
  15. data/example/spec/user_spec.rb +15 -0
  16. data/lib/opal-rspec.rb +2 -0
  17. data/lib/opal/rspec.rb +20 -0
  18. data/lib/opal/rspec/rake_task.rb +63 -0
  19. data/lib/opal/rspec/version.rb +5 -0
  20. data/opal-rspec.gemspec +21 -0
  21. data/opal/opal-rspec.rb +1 -0
  22. data/opal/opal/rspec.rb +25 -0
  23. data/opal/opal/rspec/async.rb +289 -0
  24. data/opal/opal/rspec/browser_formatter.rb +188 -0
  25. data/opal/opal/rspec/fixes.rb +116 -0
  26. data/opal/opal/rspec/requires.rb +45 -0
  27. data/opal/opal/rspec/runner.rb +69 -0
  28. data/opal/opal/rspec/sprockets_runner.rb.erb +11 -0
  29. data/opal/opal/rspec/text_formatter.rb +74 -0
  30. data/spec/async_spec.rb +38 -0
  31. data/spec/example_spec.rb +163 -0
  32. data/spec/matchers_spec.rb +201 -0
  33. data/spec/mock_spec.rb +63 -0
  34. data/spec/named_subject_spec.rb +11 -0
  35. data/spec/should_syntax_spec.rb +17 -0
  36. data/vendor/spec_runner.js +50 -0
  37. data/vendor_lib/rspec-expectations.rb +1 -0
  38. data/vendor_lib/rspec.rb +3 -0
  39. data/vendor_lib/rspec/autorun.rb +2 -0
  40. data/vendor_lib/rspec/core.rb +203 -0
  41. data/vendor_lib/rspec/core/backport_random.rb +302 -0
  42. data/vendor_lib/rspec/core/backtrace_formatter.rb +65 -0
  43. data/vendor_lib/rspec/core/command_line.rb +36 -0
  44. data/vendor_lib/rspec/core/configuration.rb +1129 -0
  45. data/vendor_lib/rspec/core/configuration_options.rb +143 -0
  46. data/vendor_lib/rspec/core/drb_command_line.rb +26 -0
  47. data/vendor_lib/rspec/core/drb_options.rb +87 -0
  48. data/vendor_lib/rspec/core/dsl.rb +26 -0
  49. data/vendor_lib/rspec/core/example.rb +312 -0
  50. data/vendor_lib/rspec/core/example_group.rb +540 -0
  51. data/vendor_lib/rspec/core/filter_manager.rb +224 -0
  52. data/vendor_lib/rspec/core/flat_map.rb +17 -0
  53. data/vendor_lib/rspec/core/formatters.rb +54 -0
  54. data/vendor_lib/rspec/core/formatters/base_formatter.rb +291 -0
  55. data/vendor_lib/rspec/core/formatters/base_text_formatter.rb +307 -0
  56. data/vendor_lib/rspec/core/formatters/deprecation_formatter.rb +193 -0
  57. data/vendor_lib/rspec/core/formatters/documentation_formatter.rb +67 -0
  58. data/vendor_lib/rspec/core/formatters/helpers.rb +82 -0
  59. data/vendor_lib/rspec/core/formatters/html_formatter.rb +155 -0
  60. data/vendor_lib/rspec/core/formatters/html_printer.rb +408 -0
  61. data/vendor_lib/rspec/core/formatters/json_formatter.rb +99 -0
  62. data/vendor_lib/rspec/core/formatters/progress_formatter.rb +32 -0
  63. data/vendor_lib/rspec/core/formatters/snippet_extractor.rb +101 -0
  64. data/vendor_lib/rspec/core/hooks.rb +535 -0
  65. data/vendor_lib/rspec/core/memoized_helpers.rb +431 -0
  66. data/vendor_lib/rspec/core/metadata.rb +313 -0
  67. data/vendor_lib/rspec/core/mocking/with_absolutely_nothing.rb +11 -0
  68. data/vendor_lib/rspec/core/mocking/with_flexmock.rb +27 -0
  69. data/vendor_lib/rspec/core/mocking/with_mocha.rb +52 -0
  70. data/vendor_lib/rspec/core/mocking/with_rr.rb +27 -0
  71. data/vendor_lib/rspec/core/mocking/with_rspec.rb +27 -0
  72. data/vendor_lib/rspec/core/option_parser.rb +234 -0
  73. data/vendor_lib/rspec/core/ordering.rb +154 -0
  74. data/vendor_lib/rspec/core/pending.rb +110 -0
  75. data/vendor_lib/rspec/core/project_initializer.rb +88 -0
  76. data/vendor_lib/rspec/core/rake_task.rb +128 -0
  77. data/vendor_lib/rspec/core/reporter.rb +132 -0
  78. data/vendor_lib/rspec/core/ruby_project.rb +44 -0
  79. data/vendor_lib/rspec/core/runner.rb +97 -0
  80. data/vendor_lib/rspec/core/shared_context.rb +53 -0
  81. data/vendor_lib/rspec/core/shared_example_group.rb +146 -0
  82. data/vendor_lib/rspec/core/shared_example_group/collection.rb +27 -0
  83. data/vendor_lib/rspec/core/version.rb +7 -0
  84. data/vendor_lib/rspec/core/warnings.rb +22 -0
  85. data/vendor_lib/rspec/core/world.rb +131 -0
  86. data/vendor_lib/rspec/expectations.rb +75 -0
  87. data/vendor_lib/rspec/expectations/differ.rb +154 -0
  88. data/vendor_lib/rspec/expectations/errors.rb +9 -0
  89. data/vendor_lib/rspec/expectations/expectation_target.rb +87 -0
  90. data/vendor_lib/rspec/expectations/extensions.rb +1 -0
  91. data/vendor_lib/rspec/expectations/extensions/object.rb +29 -0
  92. data/vendor_lib/rspec/expectations/fail_with.rb +79 -0
  93. data/vendor_lib/rspec/expectations/handler.rb +68 -0
  94. data/vendor_lib/rspec/expectations/syntax.rb +182 -0
  95. data/vendor_lib/rspec/expectations/version.rb +8 -0
  96. data/vendor_lib/rspec/matchers.rb +633 -0
  97. data/vendor_lib/rspec/matchers/built_in.rb +39 -0
  98. data/vendor_lib/rspec/matchers/built_in/base_matcher.rb +68 -0
  99. data/vendor_lib/rspec/matchers/built_in/be.rb +213 -0
  100. data/vendor_lib/rspec/matchers/built_in/be_instance_of.rb +15 -0
  101. data/vendor_lib/rspec/matchers/built_in/be_kind_of.rb +11 -0
  102. data/vendor_lib/rspec/matchers/built_in/be_within.rb +55 -0
  103. data/vendor_lib/rspec/matchers/built_in/change.rb +141 -0
  104. data/vendor_lib/rspec/matchers/built_in/cover.rb +21 -0
  105. data/vendor_lib/rspec/matchers/built_in/eq.rb +22 -0
  106. data/vendor_lib/rspec/matchers/built_in/eql.rb +23 -0
  107. data/vendor_lib/rspec/matchers/built_in/equal.rb +48 -0
  108. data/vendor_lib/rspec/matchers/built_in/exist.rb +26 -0
  109. data/vendor_lib/rspec/matchers/built_in/has.rb +48 -0
  110. data/vendor_lib/rspec/matchers/built_in/include.rb +61 -0
  111. data/vendor_lib/rspec/matchers/built_in/match.rb +17 -0
  112. data/vendor_lib/rspec/matchers/built_in/match_array.rb +51 -0
  113. data/vendor_lib/rspec/matchers/built_in/raise_error.rb +154 -0
  114. data/vendor_lib/rspec/matchers/built_in/respond_to.rb +74 -0
  115. data/vendor_lib/rspec/matchers/built_in/satisfy.rb +30 -0
  116. data/vendor_lib/rspec/matchers/built_in/start_and_end_with.rb +48 -0
  117. data/vendor_lib/rspec/matchers/built_in/throw_symbol.rb +94 -0
  118. data/vendor_lib/rspec/matchers/built_in/yield.rb +297 -0
  119. data/vendor_lib/rspec/matchers/compatibility.rb +14 -0
  120. data/vendor_lib/rspec/matchers/configuration.rb +113 -0
  121. data/vendor_lib/rspec/matchers/dsl.rb +23 -0
  122. data/vendor_lib/rspec/matchers/generated_descriptions.rb +35 -0
  123. data/vendor_lib/rspec/matchers/matcher.rb +301 -0
  124. data/vendor_lib/rspec/matchers/method_missing.rb +12 -0
  125. data/vendor_lib/rspec/matchers/operator_matcher.rb +99 -0
  126. data/vendor_lib/rspec/matchers/pretty.rb +70 -0
  127. data/vendor_lib/rspec/matchers/test_unit_integration.rb +11 -0
  128. data/vendor_lib/rspec/mocks.rb +100 -0
  129. data/vendor_lib/rspec/mocks/any_instance/chain.rb +92 -0
  130. data/vendor_lib/rspec/mocks/any_instance/expectation_chain.rb +47 -0
  131. data/vendor_lib/rspec/mocks/any_instance/message_chains.rb +75 -0
  132. data/vendor_lib/rspec/mocks/any_instance/recorder.rb +200 -0
  133. data/vendor_lib/rspec/mocks/any_instance/stub_chain.rb +45 -0
  134. data/vendor_lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
  135. data/vendor_lib/rspec/mocks/argument_list_matcher.rb +104 -0
  136. data/vendor_lib/rspec/mocks/argument_matchers.rb +264 -0
  137. data/vendor_lib/rspec/mocks/arity_calculator.rb +66 -0
  138. data/vendor_lib/rspec/mocks/configuration.rb +111 -0
  139. data/vendor_lib/rspec/mocks/error_generator.rb +203 -0
  140. data/vendor_lib/rspec/mocks/errors.rb +12 -0
  141. data/vendor_lib/rspec/mocks/example_methods.rb +201 -0
  142. data/vendor_lib/rspec/mocks/extensions/marshal.rb +17 -0
  143. data/vendor_lib/rspec/mocks/framework.rb +36 -0
  144. data/vendor_lib/rspec/mocks/instance_method_stasher.rb +112 -0
  145. data/vendor_lib/rspec/mocks/matchers/have_received.rb +99 -0
  146. data/vendor_lib/rspec/mocks/matchers/receive.rb +112 -0
  147. data/vendor_lib/rspec/mocks/matchers/receive_messages.rb +72 -0
  148. data/vendor_lib/rspec/mocks/message_expectation.rb +643 -0
  149. data/vendor_lib/rspec/mocks/method_double.rb +209 -0
  150. data/vendor_lib/rspec/mocks/method_reference.rb +95 -0
  151. data/vendor_lib/rspec/mocks/mock.rb +7 -0
  152. data/vendor_lib/rspec/mocks/mutate_const.rb +406 -0
  153. data/vendor_lib/rspec/mocks/object_reference.rb +90 -0
  154. data/vendor_lib/rspec/mocks/order_group.rb +82 -0
  155. data/vendor_lib/rspec/mocks/proxy.rb +269 -0
  156. data/vendor_lib/rspec/mocks/proxy_for_nil.rb +37 -0
  157. data/vendor_lib/rspec/mocks/space.rb +95 -0
  158. data/vendor_lib/rspec/mocks/standalone.rb +3 -0
  159. data/vendor_lib/rspec/mocks/stub_chain.rb +51 -0
  160. data/vendor_lib/rspec/mocks/syntax.rb +374 -0
  161. data/vendor_lib/rspec/mocks/targets.rb +90 -0
  162. data/vendor_lib/rspec/mocks/test_double.rb +109 -0
  163. data/vendor_lib/rspec/mocks/verifying_double.rb +77 -0
  164. data/vendor_lib/rspec/mocks/verifying_message_expecation.rb +60 -0
  165. data/vendor_lib/rspec/mocks/verifying_proxy.rb +151 -0
  166. data/vendor_lib/rspec/mocks/version.rb +7 -0
  167. data/vendor_lib/rspec/support.rb +6 -0
  168. data/vendor_lib/rspec/support/caller_filter.rb +56 -0
  169. data/vendor_lib/rspec/support/spec.rb +14 -0
  170. data/vendor_lib/rspec/support/spec/deprecation_helpers.rb +29 -0
  171. data/vendor_lib/rspec/support/spec/in_sub_process.rb +40 -0
  172. data/vendor_lib/rspec/support/spec/stderr_splitter.rb +50 -0
  173. data/vendor_lib/rspec/support/version.rb +7 -0
  174. data/vendor_lib/rspec/support/warnings.rb +41 -0
  175. data/vendor_lib/rspec/version.rb +5 -0
  176. metadata +268 -0
@@ -0,0 +1,643 @@
1
+ module RSpec
2
+ module Mocks
3
+
4
+ # A message expectation that only allows concrete return values to be set
5
+ # for a message. While this same effect can be achieved using a standard
6
+ # MessageExpecation, this version is much faster and so can be used as an
7
+ # optimization.
8
+ class SimpleMessageExpectation
9
+
10
+ def initialize(message, response, error_generator, backtrace_line = nil)
11
+ @message, @response, @error_generator, @backtrace_line = message, response, error_generator, backtrace_line
12
+ @received = false
13
+ end
14
+
15
+ def invoke(*_)
16
+ @received = true
17
+ @response
18
+ end
19
+
20
+ def matches?(message, *_)
21
+ @message == message
22
+ end
23
+
24
+ def called_max_times?
25
+ false
26
+ end
27
+
28
+ def verify_messages_received
29
+ InsertOntoBacktrace.line(@backtrace_line) do
30
+ unless @received
31
+ @error_generator.raise_expectation_error(@message, 1, ArgumentListMatcher::MATCH_ALL, 0, nil)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ class MessageExpectation
38
+ # @private
39
+ attr_accessor :error_generator, :implementation
40
+ attr_reader :message
41
+ attr_reader :orig_object
42
+ attr_writer :expected_received_count, :expected_from, :argument_list_matcher
43
+ protected :expected_received_count=, :expected_from=, :error_generator, :error_generator=, :implementation=
44
+
45
+ # @private
46
+ def initialize(error_generator, expectation_ordering, expected_from, method_double,
47
+ expected_received_count=1, opts={}, &implementation_block)
48
+ @error_generator = error_generator
49
+ @error_generator.opts = opts
50
+ @expected_from = expected_from
51
+ @method_double = method_double
52
+ @orig_object = @method_double.object
53
+ @message = @method_double.method_name
54
+ @actual_received_count = 0
55
+ @expected_received_count = expected_received_count
56
+ @argument_list_matcher = ArgumentListMatcher::MATCH_ALL
57
+ @order_group = expectation_ordering
58
+ @order_group.register(self)
59
+ @ordered = false
60
+ @at_least = @at_most = @exactly = nil
61
+ @args_to_yield = []
62
+ @failed_fast = nil
63
+ @eval_context = nil
64
+ @yield_receiver_to_implementation_block = false
65
+
66
+ @implementation = Implementation.new
67
+ self.inner_implementation_action = implementation_block
68
+ end
69
+
70
+ # @private
71
+
72
+ # @private
73
+ def expected_args
74
+ @argument_list_matcher.expected_args
75
+ end
76
+
77
+ # @overload and_return(value)
78
+ # @overload and_return(first_value, second_value)
79
+ # @overload and_return(&block)
80
+ #
81
+ # Tells the object to return a value when it receives the message. Given
82
+ # more than one value, the first value is returned the first time the
83
+ # message is received, the second value is returned the next time, etc,
84
+ # etc.
85
+ #
86
+ # If the message is received more times than there are values, the last
87
+ # value is received for every subsequent call.
88
+ #
89
+ # The block format is still supported, but is unofficially deprecated in
90
+ # favor of just passing a block to the stub method.
91
+ #
92
+ # @example
93
+ #
94
+ # counter.stub(:count).and_return(1)
95
+ # counter.count # => 1
96
+ # counter.count # => 1
97
+ #
98
+ # counter.stub(:count).and_return(1,2,3)
99
+ # counter.count # => 1
100
+ # counter.count # => 2
101
+ # counter.count # => 3
102
+ # counter.count # => 3
103
+ # counter.count # => 3
104
+ # # etc
105
+ #
106
+ # # Supported, but ...
107
+ # counter.stub(:count).and_return { 1 }
108
+ # counter.count # => 1
109
+ #
110
+ # # ... this is prefered
111
+ # counter.stub(:count) { 1 }
112
+ # counter.count # => 1
113
+ def and_return(*values, &implementation)
114
+ if negative?
115
+ raise "`and_return` is not supported with negative message expectations"
116
+ else
117
+ @expected_received_count = [@expected_received_count, values.size].max unless ignoring_args? || (@expected_received_count == 0 and @at_least)
118
+
119
+ if implementation
120
+ # TODO: deprecate `and_return { value }`
121
+ self.inner_implementation_action = implementation
122
+ else
123
+ self.terminal_implementation_action = AndReturnImplementation.new(values)
124
+ end
125
+
126
+ nil
127
+ end
128
+ end
129
+
130
+ def and_yield_receiver_to_implementation
131
+ @yield_receiver_to_implementation_block = true
132
+ self
133
+ end
134
+
135
+ def yield_receiver_to_implementation_block?
136
+ @yield_receiver_to_implementation_block
137
+ end
138
+
139
+ # Tells the object to delegate to the original unmodified method
140
+ # when it receives the message.
141
+ #
142
+ # @note This is only available on partial mock objects.
143
+ #
144
+ # @example
145
+ #
146
+ # counter.should_receive(:increment).and_call_original
147
+ # original_count = counter.count
148
+ # counter.increment
149
+ # expect(counter.count).to eq(original_count + 1)
150
+ def and_call_original
151
+ if RSpec::Mocks::TestDouble === @method_double.object
152
+ @error_generator.raise_only_valid_on_a_partial_mock(:and_call_original)
153
+ else
154
+ if implementation.inner_action
155
+ RSpec.warning("You're overriding a previous implementation for this stub")
156
+ end
157
+ @implementation = AndCallOriginalImplementation.new(@method_double.original_method)
158
+ @yield_receiver_to_implementation_block = false
159
+ end
160
+ end
161
+
162
+ # @overload and_raise
163
+ # @overload and_raise(ExceptionClass)
164
+ # @overload and_raise(ExceptionClass, message)
165
+ # @overload and_raise(exception_instance)
166
+ #
167
+ # Tells the object to raise an exception when the message is received.
168
+ #
169
+ # @note
170
+ #
171
+ # When you pass an exception class, the MessageExpectation will raise
172
+ # an instance of it, creating it with `exception` and passing `message`
173
+ # if specified. If the exception class initializer requires more than
174
+ # one parameters, you must pass in an instance and not the class,
175
+ # otherwise this method will raise an ArgumentError exception.
176
+ #
177
+ # @example
178
+ #
179
+ # car.stub(:go).and_raise
180
+ # car.stub(:go).and_raise(OutOfGas)
181
+ # car.stub(:go).and_raise(OutOfGas, "At least 2 oz of gas needed to drive")
182
+ # car.stub(:go).and_raise(OutOfGas.new(2, :oz))
183
+ def and_raise(exception = RuntimeError, message = nil)
184
+ if exception.respond_to?(:exception)
185
+ exception = message ? exception.exception(message) : exception.exception
186
+ end
187
+
188
+ self.terminal_implementation_action = Proc.new { raise exception }
189
+ nil
190
+ end
191
+
192
+ # @overload and_throw(symbol)
193
+ # @overload and_throw(symbol, object)
194
+ #
195
+ # Tells the object to throw a symbol (with the object if that form is
196
+ # used) when the message is received.
197
+ #
198
+ # @example
199
+ #
200
+ # car.stub(:go).and_throw(:out_of_gas)
201
+ # car.stub(:go).and_throw(:out_of_gas, :level => 0.1)
202
+ def and_throw(*args)
203
+ self.terminal_implementation_action = Proc.new { throw(*args) }
204
+ nil
205
+ end
206
+
207
+ # Tells the object to yield one or more args to a block when the message
208
+ # is received.
209
+ #
210
+ # @example
211
+ #
212
+ # stream.stub(:open).and_yield(StringIO.new)
213
+ def and_yield(*args, &block)
214
+ yield @eval_context = Object.new if block
215
+ @args_to_yield << args
216
+ self.initial_implementation_action = AndYieldImplementation.new(@args_to_yield, @eval_context, @error_generator)
217
+ self
218
+ end
219
+
220
+ # @private
221
+ def matches?(message, *args)
222
+ @message == message && @argument_list_matcher.args_match?(*args)
223
+ end
224
+
225
+ # @private
226
+ def invoke(parent_stub, *args, &block)
227
+ if yield_receiver_to_implementation_block?
228
+ args.unshift(orig_object)
229
+ end
230
+
231
+ if negative? || ((@exactly || @at_most) && (@actual_received_count == @expected_received_count))
232
+ @actual_received_count += 1
233
+ @failed_fast = true
234
+ #args are the args we actually received, @argument_list_matcher is the
235
+ #list of args we were expecting
236
+ @error_generator.raise_expectation_error(@message, @expected_received_count, @argument_list_matcher, @actual_received_count, expectation_count_type, *args)
237
+ end
238
+
239
+ @order_group.handle_order_constraint self
240
+
241
+ begin
242
+ if implementation.present?
243
+ implementation.call(*args, &block)
244
+ elsif parent_stub
245
+ parent_stub.invoke(nil, *args, &block)
246
+ end
247
+ ensure
248
+ @actual_received_count += 1
249
+ end
250
+ end
251
+
252
+ # @private
253
+ def negative?
254
+ @expected_received_count == 0 && !@at_least
255
+ end
256
+
257
+ # @private
258
+ def called_max_times?
259
+ @expected_received_count != :any &&
260
+ !@at_least &&
261
+ @expected_received_count > 0 &&
262
+ @actual_received_count >= @expected_received_count
263
+ end
264
+
265
+ # @private
266
+ def matches_name_but_not_args(message, *args)
267
+ @message == message and not @argument_list_matcher.args_match?(*args)
268
+ end
269
+
270
+ # @private
271
+ def verify_messages_received
272
+ InsertOntoBacktrace.line(@expected_from) do
273
+ generate_error unless expected_messages_received? || failed_fast?
274
+ end
275
+ end
276
+
277
+ # @private
278
+ def expected_messages_received?
279
+ ignoring_args? || matches_exact_count? || matches_at_least_count? || matches_at_most_count?
280
+ end
281
+
282
+ def ensure_expected_ordering_received!
283
+ @order_group.verify_invocation_order(self) if @ordered
284
+ true
285
+ end
286
+
287
+ # @private
288
+ def ignoring_args?
289
+ @expected_received_count == :any
290
+ end
291
+
292
+ # @private
293
+ def matches_at_least_count?
294
+ @at_least && @actual_received_count >= @expected_received_count
295
+ end
296
+
297
+ # @private
298
+ def matches_at_most_count?
299
+ @at_most && @actual_received_count <= @expected_received_count
300
+ end
301
+
302
+ # @private
303
+ def matches_exact_count?
304
+ @expected_received_count == @actual_received_count
305
+ end
306
+
307
+ # @private
308
+ def similar_messages
309
+ @similar_messages ||= []
310
+ end
311
+
312
+ # @private
313
+ def advise(*args)
314
+ similar_messages << args
315
+ end
316
+
317
+ # @private
318
+ def generate_error
319
+ if similar_messages.empty?
320
+ @error_generator.raise_expectation_error(@message, @expected_received_count, @argument_list_matcher, @actual_received_count, expectation_count_type, *expected_args)
321
+ else
322
+ @error_generator.raise_similar_message_args_error(self, *@similar_messages)
323
+ end
324
+ end
325
+
326
+ def expectation_count_type
327
+ return :at_least if @at_least
328
+ return :at_most if @at_most
329
+ return nil
330
+ end
331
+
332
+ # @private
333
+ def description
334
+ @error_generator.describe_expectation(@message, @expected_received_count, @actual_received_count, *expected_args)
335
+ end
336
+
337
+ def raise_out_of_order_error
338
+ @error_generator.raise_out_of_order_error @message
339
+ end
340
+
341
+ # Constrains a stub or message expectation to invocations with specific
342
+ # arguments.
343
+ #
344
+ # With a stub, if the message might be received with other args as well,
345
+ # you should stub a default value first, and then stub or mock the same
346
+ # message using `with` to constrain to specific arguments.
347
+ #
348
+ # A message expectation will fail if the message is received with different
349
+ # arguments.
350
+ #
351
+ # @example
352
+ #
353
+ # cart.stub(:add) { :failure }
354
+ # cart.stub(:add).with(Book.new(:isbn => 1934356379)) { :success }
355
+ # cart.add(Book.new(:isbn => 1234567890))
356
+ # # => :failure
357
+ # cart.add(Book.new(:isbn => 1934356379))
358
+ # # => :success
359
+ #
360
+ # cart.should_receive(:add).with(Book.new(:isbn => 1934356379)) { :success }
361
+ # cart.add(Book.new(:isbn => 1234567890))
362
+ # # => failed expectation
363
+ # cart.add(Book.new(:isbn => 1934356379))
364
+ # # => passes
365
+ def with(*args, &block)
366
+ if args.empty?
367
+ raise ArgumentError,
368
+ "`with` must have at least one argument. Use `no_args` matcher to set the expectation of receiving no arguments."
369
+ end
370
+
371
+ self.inner_implementation_action = block
372
+ @argument_list_matcher = ArgumentListMatcher.new(*args)
373
+ self
374
+ end
375
+
376
+ # Constrain a message expectation to be received a specific number of
377
+ # times.
378
+ #
379
+ # @example
380
+ #
381
+ # dealer.should_receive(:deal_card).exactly(10).times
382
+ def exactly(n, &block)
383
+ self.inner_implementation_action = block
384
+ set_expected_received_count :exactly, n
385
+ self
386
+ end
387
+
388
+ # Constrain a message expectation to be received at least a specific
389
+ # number of times.
390
+ #
391
+ # @example
392
+ #
393
+ # dealer.should_receive(:deal_card).at_least(9).times
394
+ def at_least(n, &block)
395
+ set_expected_received_count :at_least, n
396
+
397
+ if n == 0
398
+ raise "at_least(0) has been removed, use allow(...).to receive(:message) instead"
399
+ end
400
+
401
+ self.inner_implementation_action = block
402
+
403
+ self
404
+ end
405
+
406
+ # Constrain a message expectation to be received at most a specific
407
+ # number of times.
408
+ #
409
+ # @example
410
+ #
411
+ # dealer.should_receive(:deal_card).at_most(10).times
412
+ def at_most(n, &block)
413
+ self.inner_implementation_action = block
414
+ set_expected_received_count :at_most, n
415
+ self
416
+ end
417
+
418
+ # Syntactic sugar for `exactly`, `at_least` and `at_most`
419
+ #
420
+ # @example
421
+ #
422
+ # dealer.should_receive(:deal_card).exactly(10).times
423
+ # dealer.should_receive(:deal_card).at_least(10).times
424
+ # dealer.should_receive(:deal_card).at_most(10).times
425
+ def times(&block)
426
+ self.inner_implementation_action = block
427
+ self
428
+ end
429
+
430
+ # Expect a message not to be received at all.
431
+ #
432
+ # @example
433
+ #
434
+ # car.should_receive(:stop).never
435
+ def never
436
+ ErrorGenerator.raise_double_negation_error("expect(obj)") if negative?
437
+ @expected_received_count = 0
438
+ self
439
+ end
440
+
441
+ # Expect a message to be received exactly one time.
442
+ #
443
+ # @example
444
+ #
445
+ # car.should_receive(:go).once
446
+ def once(&block)
447
+ self.inner_implementation_action = block
448
+ set_expected_received_count :exactly, 1
449
+ self
450
+ end
451
+
452
+ # Expect a message to be received exactly two times.
453
+ #
454
+ # @example
455
+ #
456
+ # car.should_receive(:go).twice
457
+ def twice(&block)
458
+ self.inner_implementation_action = block
459
+ set_expected_received_count :exactly, 2
460
+ self
461
+ end
462
+
463
+ # Expect messages to be received in a specific order.
464
+ #
465
+ # @example
466
+ #
467
+ # api.should_receive(:prepare).ordered
468
+ # api.should_receive(:run).ordered
469
+ # api.should_receive(:finish).ordered
470
+ def ordered(&block)
471
+ self.inner_implementation_action = block
472
+ @ordered = true
473
+ self
474
+ end
475
+
476
+ # @private
477
+ def ordered?
478
+ @ordered
479
+ end
480
+
481
+ # @private
482
+ def negative_expectation_for?(message)
483
+ @message == message && negative?
484
+ end
485
+
486
+ # @private
487
+ def actual_received_count_matters?
488
+ @at_least || @at_most || @exactly
489
+ end
490
+
491
+ # @private
492
+ def increase_actual_received_count!
493
+ @actual_received_count += 1
494
+ end
495
+
496
+ private
497
+
498
+ def failed_fast?
499
+ @failed_fast
500
+ end
501
+
502
+ def set_expected_received_count(relativity, n)
503
+ @at_least = (relativity == :at_least)
504
+ @at_most = (relativity == :at_most)
505
+ @exactly = (relativity == :exactly)
506
+ @expected_received_count = case n
507
+ when Numeric then n
508
+ when :once then 1
509
+ when :twice then 2
510
+ end
511
+ end
512
+
513
+ def initial_implementation_action=(action)
514
+ implementation.initial_action = action
515
+ end
516
+
517
+ def inner_implementation_action=(action)
518
+ RSpec.warning("You're overriding a previous implementation for this stub") if implementation.inner_action
519
+ implementation.inner_action = action if action
520
+ end
521
+
522
+ def terminal_implementation_action=(action)
523
+ implementation.terminal_action = action
524
+ end
525
+ end
526
+
527
+ # Handles the implementation of an `and_yield` declaration.
528
+ # @private
529
+ class AndYieldImplementation
530
+ def initialize(args_to_yield, eval_context, error_generator)
531
+ @args_to_yield = args_to_yield
532
+ @eval_context = eval_context
533
+ @error_generator = error_generator
534
+ end
535
+
536
+ def call(*args_to_ignore, &block)
537
+ return if @args_to_yield.empty? && @eval_context.nil?
538
+
539
+ @error_generator.raise_missing_block_error @args_to_yield unless block
540
+ value = nil
541
+ @args_to_yield.each do |args|
542
+ if block.arity > -1 && args.length != block.arity
543
+ @error_generator.raise_wrong_arity_error args, block.arity
544
+ end
545
+ value = @eval_context ? @eval_context.instance_exec(*args, &block) : block.call(*args)
546
+ end
547
+ value
548
+ end
549
+ end
550
+
551
+ # Handles the implementation of an `and_return` implementation.
552
+ # @private
553
+ class AndReturnImplementation
554
+ def initialize(values_to_return)
555
+ @values_to_return = values_to_return
556
+ end
557
+
558
+ def call(*args_to_ignore, &block)
559
+ if @values_to_return.size > 1
560
+ @values_to_return.shift
561
+ else
562
+ @values_to_return.first
563
+ end
564
+ end
565
+ end
566
+
567
+ # Represents a configured implementation. Takes into account
568
+ # any number of sub-implementations.
569
+ # @private
570
+ class Implementation
571
+ attr_accessor :initial_action, :inner_action, :terminal_action
572
+
573
+ def call(*args, &block)
574
+ actions.map do |action|
575
+ action.call(*args, &block)
576
+ end.last
577
+ end
578
+
579
+ def present?
580
+ actions.any?
581
+ end
582
+
583
+ private
584
+
585
+ def actions
586
+ [initial_action, inner_action, terminal_action].compact
587
+ end
588
+ end
589
+
590
+ # Represents an `and_call_original` implementation.
591
+ # @private
592
+ class AndCallOriginalImplementation
593
+ def initialize(method)
594
+ @method = method
595
+ end
596
+
597
+ CannotModifyFurtherError = Class.new(StandardError)
598
+
599
+ def initial_action=(value)
600
+ raise cannot_modify_further_error
601
+ end
602
+
603
+ def inner_action=(value)
604
+ raise cannot_modify_further_error
605
+ end
606
+
607
+ def terminal_action=(value)
608
+ raise cannot_modify_further_error
609
+ end
610
+
611
+ def present?
612
+ true
613
+ end
614
+
615
+ def inner_action
616
+ true
617
+ end
618
+
619
+ def call(*args, &block)
620
+ @method.call(*args, &block)
621
+ end
622
+
623
+ private
624
+
625
+ def cannot_modify_further_error
626
+ CannotModifyFurtherError.new "This method has already been configured " +
627
+ "to call the original implementation, and cannot be modified further."
628
+ end
629
+ end
630
+
631
+ # Insert original locations into stacktraces
632
+ # @api private
633
+ class InsertOntoBacktrace
634
+ def self.line(location)
635
+ yield
636
+ rescue RSpec::Mocks::MockExpectationError => error
637
+ error.backtrace.insert(0, location)
638
+ Kernel::raise error
639
+ end
640
+ end
641
+
642
+ end
643
+ end