opal-rspec 0.4.0.beta3 → 0.4.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -1
- data/.gitmodules +15 -0
- data/.travis.yml +12 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +3 -1
- data/Gemfile +6 -7
- data/README.md +2 -0
- data/Rakefile +12 -50
- data/lib/opal/rspec/version.rb +1 -1
- data/lib/opal/rspec.rb +14 -0
- data/opal/opal/rspec/async.rb +146 -11
- data/opal/opal/rspec/fixes.rb +18 -8
- data/opal/opal/rspec/requires.rb +45 -0
- data/opal/opal/rspec.rb +1 -24
- data/opal-rspec.gemspec +1 -1
- data/spec/async_spec.rb +4 -5
- data/spec/matchers_spec.rb +20 -0
- data/spec/named_subject_spec.rb +11 -0
- data/spec/should_syntax_spec.rb +17 -0
- data/vendor_lib/rspec/autorun.rb +2 -0
- data/vendor_lib/rspec/core/backport_random.rb +302 -0
- data/vendor_lib/rspec/core/backtrace_formatter.rb +65 -0
- data/vendor_lib/rspec/core/command_line.rb +36 -0
- data/vendor_lib/rspec/core/configuration.rb +1129 -0
- data/vendor_lib/rspec/core/configuration_options.rb +143 -0
- data/vendor_lib/rspec/core/drb_command_line.rb +26 -0
- data/vendor_lib/rspec/core/drb_options.rb +87 -0
- data/vendor_lib/rspec/core/dsl.rb +26 -0
- data/vendor_lib/rspec/core/example.rb +312 -0
- data/vendor_lib/rspec/core/example_group.rb +540 -0
- data/vendor_lib/rspec/core/filter_manager.rb +224 -0
- data/vendor_lib/rspec/core/flat_map.rb +17 -0
- data/vendor_lib/rspec/core/formatters/base_formatter.rb +291 -0
- data/vendor_lib/rspec/core/formatters/base_text_formatter.rb +307 -0
- data/vendor_lib/rspec/core/formatters/deprecation_formatter.rb +193 -0
- data/vendor_lib/rspec/core/formatters/documentation_formatter.rb +67 -0
- data/vendor_lib/rspec/core/formatters/helpers.rb +82 -0
- data/vendor_lib/rspec/core/formatters/html_formatter.rb +155 -0
- data/vendor_lib/rspec/core/formatters/html_printer.rb +408 -0
- data/vendor_lib/rspec/core/formatters/json_formatter.rb +99 -0
- data/vendor_lib/rspec/core/formatters/progress_formatter.rb +32 -0
- data/vendor_lib/rspec/core/formatters/snippet_extractor.rb +101 -0
- data/vendor_lib/rspec/core/formatters.rb +54 -0
- data/vendor_lib/rspec/core/hooks.rb +535 -0
- data/vendor_lib/rspec/core/memoized_helpers.rb +431 -0
- data/vendor_lib/rspec/core/metadata.rb +313 -0
- data/vendor_lib/rspec/core/mocking/with_absolutely_nothing.rb +11 -0
- data/vendor_lib/rspec/core/mocking/with_flexmock.rb +27 -0
- data/vendor_lib/rspec/core/mocking/with_mocha.rb +52 -0
- data/vendor_lib/rspec/core/mocking/with_rr.rb +27 -0
- data/vendor_lib/rspec/core/mocking/with_rspec.rb +27 -0
- data/vendor_lib/rspec/core/option_parser.rb +234 -0
- data/vendor_lib/rspec/core/ordering.rb +154 -0
- data/vendor_lib/rspec/core/pending.rb +110 -0
- data/vendor_lib/rspec/core/project_initializer.rb +88 -0
- data/vendor_lib/rspec/core/rake_task.rb +128 -0
- data/vendor_lib/rspec/core/reporter.rb +132 -0
- data/vendor_lib/rspec/core/ruby_project.rb +44 -0
- data/vendor_lib/rspec/core/runner.rb +97 -0
- data/vendor_lib/rspec/core/shared_context.rb +53 -0
- data/vendor_lib/rspec/core/shared_example_group/collection.rb +27 -0
- data/vendor_lib/rspec/core/shared_example_group.rb +146 -0
- data/vendor_lib/rspec/core/version.rb +7 -0
- data/vendor_lib/rspec/core/warnings.rb +22 -0
- data/vendor_lib/rspec/core/world.rb +131 -0
- data/vendor_lib/rspec/core.rb +203 -0
- data/vendor_lib/rspec/expectations/differ.rb +154 -0
- data/vendor_lib/rspec/expectations/errors.rb +9 -0
- data/vendor_lib/rspec/expectations/expectation_target.rb +87 -0
- data/vendor_lib/rspec/expectations/extensions/object.rb +29 -0
- data/vendor_lib/rspec/expectations/extensions.rb +1 -0
- data/vendor_lib/rspec/expectations/fail_with.rb +79 -0
- data/vendor_lib/rspec/expectations/handler.rb +68 -0
- data/vendor_lib/rspec/expectations/syntax.rb +182 -0
- data/vendor_lib/rspec/expectations/version.rb +8 -0
- data/vendor_lib/rspec/expectations.rb +75 -0
- data/vendor_lib/rspec/matchers/built_in/base_matcher.rb +68 -0
- data/vendor_lib/rspec/matchers/built_in/be.rb +213 -0
- data/vendor_lib/rspec/matchers/built_in/be_instance_of.rb +15 -0
- data/vendor_lib/rspec/matchers/built_in/be_kind_of.rb +11 -0
- data/vendor_lib/rspec/matchers/built_in/be_within.rb +55 -0
- data/vendor_lib/rspec/matchers/built_in/change.rb +141 -0
- data/vendor_lib/rspec/matchers/built_in/cover.rb +21 -0
- data/vendor_lib/rspec/matchers/built_in/eq.rb +22 -0
- data/vendor_lib/rspec/matchers/built_in/eql.rb +23 -0
- data/vendor_lib/rspec/matchers/built_in/equal.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/exist.rb +26 -0
- data/vendor_lib/rspec/matchers/built_in/has.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/include.rb +61 -0
- data/vendor_lib/rspec/matchers/built_in/match.rb +17 -0
- data/vendor_lib/rspec/matchers/built_in/match_array.rb +51 -0
- data/vendor_lib/rspec/matchers/built_in/raise_error.rb +154 -0
- data/vendor_lib/rspec/matchers/built_in/respond_to.rb +74 -0
- data/vendor_lib/rspec/matchers/built_in/satisfy.rb +30 -0
- data/vendor_lib/rspec/matchers/built_in/start_and_end_with.rb +48 -0
- data/vendor_lib/rspec/matchers/built_in/throw_symbol.rb +94 -0
- data/vendor_lib/rspec/matchers/built_in/yield.rb +297 -0
- data/vendor_lib/rspec/matchers/built_in.rb +39 -0
- data/vendor_lib/rspec/matchers/compatibility.rb +14 -0
- data/vendor_lib/rspec/matchers/configuration.rb +113 -0
- data/vendor_lib/rspec/matchers/dsl.rb +23 -0
- data/vendor_lib/rspec/matchers/generated_descriptions.rb +35 -0
- data/vendor_lib/rspec/matchers/matcher.rb +301 -0
- data/vendor_lib/rspec/matchers/method_missing.rb +12 -0
- data/vendor_lib/rspec/matchers/operator_matcher.rb +99 -0
- data/vendor_lib/rspec/matchers/pretty.rb +70 -0
- data/vendor_lib/rspec/matchers/test_unit_integration.rb +11 -0
- data/vendor_lib/rspec/matchers.rb +633 -0
- data/vendor_lib/rspec/mocks/any_instance/chain.rb +92 -0
- data/vendor_lib/rspec/mocks/any_instance/expectation_chain.rb +47 -0
- data/vendor_lib/rspec/mocks/any_instance/message_chains.rb +75 -0
- data/vendor_lib/rspec/mocks/any_instance/recorder.rb +200 -0
- data/vendor_lib/rspec/mocks/any_instance/stub_chain.rb +45 -0
- data/vendor_lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
- data/vendor_lib/rspec/mocks/argument_list_matcher.rb +104 -0
- data/vendor_lib/rspec/mocks/argument_matchers.rb +264 -0
- data/vendor_lib/rspec/mocks/arity_calculator.rb +66 -0
- data/vendor_lib/rspec/mocks/configuration.rb +111 -0
- data/vendor_lib/rspec/mocks/error_generator.rb +203 -0
- data/vendor_lib/rspec/mocks/errors.rb +12 -0
- data/vendor_lib/rspec/mocks/example_methods.rb +201 -0
- data/vendor_lib/rspec/mocks/extensions/marshal.rb +17 -0
- data/vendor_lib/rspec/mocks/framework.rb +36 -0
- data/vendor_lib/rspec/mocks/instance_method_stasher.rb +112 -0
- data/vendor_lib/rspec/mocks/matchers/have_received.rb +99 -0
- data/vendor_lib/rspec/mocks/matchers/receive.rb +112 -0
- data/vendor_lib/rspec/mocks/matchers/receive_messages.rb +72 -0
- data/vendor_lib/rspec/mocks/message_expectation.rb +643 -0
- data/vendor_lib/rspec/mocks/method_double.rb +209 -0
- data/vendor_lib/rspec/mocks/method_reference.rb +95 -0
- data/vendor_lib/rspec/mocks/mock.rb +7 -0
- data/vendor_lib/rspec/mocks/mutate_const.rb +406 -0
- data/vendor_lib/rspec/mocks/object_reference.rb +90 -0
- data/vendor_lib/rspec/mocks/order_group.rb +82 -0
- data/vendor_lib/rspec/mocks/proxy.rb +269 -0
- data/vendor_lib/rspec/mocks/proxy_for_nil.rb +37 -0
- data/vendor_lib/rspec/mocks/space.rb +95 -0
- data/vendor_lib/rspec/mocks/standalone.rb +3 -0
- data/vendor_lib/rspec/mocks/stub_chain.rb +51 -0
- data/vendor_lib/rspec/mocks/syntax.rb +374 -0
- data/vendor_lib/rspec/mocks/targets.rb +90 -0
- data/vendor_lib/rspec/mocks/test_double.rb +109 -0
- data/vendor_lib/rspec/mocks/verifying_double.rb +77 -0
- data/vendor_lib/rspec/mocks/verifying_message_expecation.rb +60 -0
- data/vendor_lib/rspec/mocks/verifying_proxy.rb +151 -0
- data/vendor_lib/rspec/mocks/version.rb +7 -0
- data/vendor_lib/rspec/mocks.rb +100 -0
- data/vendor_lib/rspec/support/caller_filter.rb +56 -0
- data/vendor_lib/rspec/support/spec/deprecation_helpers.rb +29 -0
- data/vendor_lib/rspec/support/spec/in_sub_process.rb +40 -0
- data/vendor_lib/rspec/support/spec/stderr_splitter.rb +50 -0
- data/vendor_lib/rspec/support/spec.rb +14 -0
- data/vendor_lib/rspec/support/version.rb +7 -0
- data/vendor_lib/rspec/support/warnings.rb +41 -0
- data/vendor_lib/rspec/support.rb +6 -0
- data/vendor_lib/rspec/version.rb +5 -0
- data/vendor_lib/rspec-expectations.rb +1 -0
- data/vendor_lib/rspec.rb +3 -0
- metadata +163 -4
- data/opal/opal/rspec/rspec.js +0 -20384
@@ -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
|