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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.gitmodules +15 -0
- data/.travis.yml +13 -0
- data/.yardopts +5 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile +8 -0
- data/README.md +147 -0
- data/Rakefile +26 -0
- data/config.ru +10 -0
- data/example/Gemfile +4 -0
- data/example/README.md +13 -0
- data/example/Rakefile +8 -0
- data/example/opal/user.rb +11 -0
- data/example/spec/user_spec.rb +15 -0
- data/lib/opal-rspec.rb +2 -0
- data/lib/opal/rspec.rb +20 -0
- data/lib/opal/rspec/rake_task.rb +63 -0
- data/lib/opal/rspec/version.rb +5 -0
- data/opal-rspec.gemspec +21 -0
- data/opal/opal-rspec.rb +1 -0
- data/opal/opal/rspec.rb +25 -0
- data/opal/opal/rspec/async.rb +289 -0
- data/opal/opal/rspec/browser_formatter.rb +188 -0
- data/opal/opal/rspec/fixes.rb +116 -0
- data/opal/opal/rspec/requires.rb +45 -0
- data/opal/opal/rspec/runner.rb +69 -0
- data/opal/opal/rspec/sprockets_runner.rb.erb +11 -0
- data/opal/opal/rspec/text_formatter.rb +74 -0
- data/spec/async_spec.rb +38 -0
- data/spec/example_spec.rb +163 -0
- data/spec/matchers_spec.rb +201 -0
- data/spec/mock_spec.rb +63 -0
- data/spec/named_subject_spec.rb +11 -0
- data/spec/should_syntax_spec.rb +17 -0
- data/vendor/spec_runner.js +50 -0
- data/vendor_lib/rspec-expectations.rb +1 -0
- data/vendor_lib/rspec.rb +3 -0
- data/vendor_lib/rspec/autorun.rb +2 -0
- data/vendor_lib/rspec/core.rb +203 -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.rb +54 -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/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.rb +146 -0
- data/vendor_lib/rspec/core/shared_example_group/collection.rb +27 -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/expectations.rb +75 -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.rb +1 -0
- data/vendor_lib/rspec/expectations/extensions/object.rb +29 -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/matchers.rb +633 -0
- data/vendor_lib/rspec/matchers/built_in.rb +39 -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/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/mocks.rb +100 -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/support.rb +6 -0
- data/vendor_lib/rspec/support/caller_filter.rb +56 -0
- data/vendor_lib/rspec/support/spec.rb +14 -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/version.rb +7 -0
- data/vendor_lib/rspec/support/warnings.rb +41 -0
- data/vendor_lib/rspec/version.rb +5 -0
- 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
|