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,200 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
# Given a class `TheClass`, `TheClass.any_instance` returns a `Recorder`,
|
|
5
|
+
# which records stubs and message expectations for later playback on
|
|
6
|
+
# instances of `TheClass`.
|
|
7
|
+
#
|
|
8
|
+
# Further constraints are stored in instances of [Chain](Chain).
|
|
9
|
+
#
|
|
10
|
+
# @see AnyInstance
|
|
11
|
+
# @see Chain
|
|
12
|
+
class Recorder
|
|
13
|
+
# @private
|
|
14
|
+
attr_reader :message_chains, :stubs, :klass
|
|
15
|
+
|
|
16
|
+
def initialize(klass)
|
|
17
|
+
@message_chains = MessageChains.new
|
|
18
|
+
@stubs = Hash.new { |hash,key| hash[key] = [] }
|
|
19
|
+
@observed_methods = []
|
|
20
|
+
@played_methods = {}
|
|
21
|
+
@klass = klass
|
|
22
|
+
@expectation_set = false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Initializes the recording a stub to be played back against any
|
|
26
|
+
# instance of this object that invokes the submitted method.
|
|
27
|
+
#
|
|
28
|
+
# @see Methods#stub
|
|
29
|
+
def stub(method_name_or_method_map, &block)
|
|
30
|
+
if Hash === method_name_or_method_map
|
|
31
|
+
method_name_or_method_map.each do |method_name, return_value|
|
|
32
|
+
stub(method_name).and_return(return_value)
|
|
33
|
+
end
|
|
34
|
+
else
|
|
35
|
+
observe!(method_name_or_method_map)
|
|
36
|
+
message_chains.add(method_name_or_method_map, StubChain.new(self, method_name_or_method_map, &block))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Initializes the recording a stub chain to be played back against any
|
|
41
|
+
# instance of this object that invokes the method matching the first
|
|
42
|
+
# argument.
|
|
43
|
+
#
|
|
44
|
+
# @see Methods#stub_chain
|
|
45
|
+
def stub_chain(*method_names_and_optional_return_values, &block)
|
|
46
|
+
normalize_chain(*method_names_and_optional_return_values) do |method_name, args|
|
|
47
|
+
observe!(method_name)
|
|
48
|
+
message_chains.add(method_name, StubChainChain.new(self, *args, &block))
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Initializes the recording a message expectation to be played back
|
|
53
|
+
# against any instance of this object that invokes the submitted
|
|
54
|
+
# method.
|
|
55
|
+
#
|
|
56
|
+
# @see Methods#should_receive
|
|
57
|
+
def should_receive(method_name, &block)
|
|
58
|
+
@expectation_set = true
|
|
59
|
+
observe!(method_name)
|
|
60
|
+
message_chains.add(method_name, PositiveExpectationChain.new(self, method_name, &block))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def should_not_receive(method_name, &block)
|
|
64
|
+
should_receive(method_name, &block).never
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Removes any previously recorded stubs, stub_chains or message
|
|
68
|
+
# expectations that use `method_name`.
|
|
69
|
+
#
|
|
70
|
+
# @see Methods#unstub
|
|
71
|
+
def unstub(method_name)
|
|
72
|
+
unless @observed_methods.include?(method_name.to_sym)
|
|
73
|
+
raise RSpec::Mocks::MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed"
|
|
74
|
+
end
|
|
75
|
+
message_chains.remove_stub_chains_for!(method_name)
|
|
76
|
+
::RSpec::Mocks.proxies_of(@klass).each do |proxy|
|
|
77
|
+
stubs[method_name].each { |stub| proxy.remove_single_stub(method_name, stub) }
|
|
78
|
+
end
|
|
79
|
+
stubs[method_name].clear
|
|
80
|
+
stop_observing!(method_name) unless message_chains.has_expectation?(method_name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @api private
|
|
84
|
+
#
|
|
85
|
+
# Used internally to verify that message expectations have been
|
|
86
|
+
# fulfilled.
|
|
87
|
+
def verify
|
|
88
|
+
if @expectation_set && !message_chains.all_expectations_fulfilled?
|
|
89
|
+
raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{message_chains.unfulfilled_expectations.sort.join(', ')}"
|
|
90
|
+
end
|
|
91
|
+
ensure
|
|
92
|
+
stop_all_observation!
|
|
93
|
+
::RSpec::Mocks.space.remove_any_instance_recorder_for(@klass)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# @private
|
|
97
|
+
def stop_all_observation!
|
|
98
|
+
@observed_methods.each {|method_name| restore_method!(method_name)}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @private
|
|
102
|
+
def playback!(instance, method_name)
|
|
103
|
+
RSpec::Mocks.space.ensure_registered(instance)
|
|
104
|
+
message_chains.playback!(instance, method_name)
|
|
105
|
+
@played_methods[method_name] = instance
|
|
106
|
+
received_expected_message!(method_name) if message_chains.has_expectation?(method_name)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# @private
|
|
110
|
+
def instance_that_received(method_name)
|
|
111
|
+
@played_methods[method_name]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def build_alias_method_name(method_name)
|
|
115
|
+
"__#{method_name}_without_any_instance__"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def already_observing?(method_name)
|
|
119
|
+
@observed_methods.include?(method_name)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def normalize_chain(*args)
|
|
125
|
+
args.shift.to_s.split('.').map {|s| s.to_sym}.reverse.each {|a| args.unshift a}
|
|
126
|
+
yield args.first, args
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def received_expected_message!(method_name)
|
|
130
|
+
message_chains.received_expected_message!(method_name)
|
|
131
|
+
restore_method!(method_name)
|
|
132
|
+
mark_invoked!(method_name)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def restore_method!(method_name)
|
|
136
|
+
if public_protected_or_private_method_defined?(build_alias_method_name(method_name))
|
|
137
|
+
restore_original_method!(method_name)
|
|
138
|
+
else
|
|
139
|
+
remove_dummy_method!(method_name)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def restore_original_method!(method_name)
|
|
144
|
+
alias_method_name = build_alias_method_name(method_name)
|
|
145
|
+
@klass.class_exec do
|
|
146
|
+
remove_method method_name
|
|
147
|
+
alias_method method_name, alias_method_name
|
|
148
|
+
remove_method alias_method_name
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def remove_dummy_method!(method_name)
|
|
153
|
+
@klass.class_exec do
|
|
154
|
+
remove_method method_name
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def backup_method!(method_name)
|
|
159
|
+
alias_method_name = build_alias_method_name(method_name)
|
|
160
|
+
@klass.class_exec do
|
|
161
|
+
alias_method alias_method_name, method_name
|
|
162
|
+
end if public_protected_or_private_method_defined?(method_name)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def public_protected_or_private_method_defined?(method_name)
|
|
166
|
+
@klass.method_defined?(method_name) || @klass.private_method_defined?(method_name)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def stop_observing!(method_name)
|
|
170
|
+
restore_method!(method_name)
|
|
171
|
+
@observed_methods.delete(method_name)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def observe!(method_name)
|
|
175
|
+
if RSpec::Mocks.configuration.verify_partial_doubles?
|
|
176
|
+
raise MockExpectationError unless @klass.method_defined?(method_name)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
stop_observing!(method_name) if already_observing?(method_name)
|
|
180
|
+
@observed_methods << method_name
|
|
181
|
+
backup_method!(method_name)
|
|
182
|
+
@klass.__send__(:define_method, method_name) do |*args, &blk|
|
|
183
|
+
klass = ::RSpec::Mocks.method_handle_for(self, method_name).owner
|
|
184
|
+
::RSpec::Mocks.any_instance_recorder_for(klass).playback!(self, method_name)
|
|
185
|
+
self.__send__(method_name, *args, &blk)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def mark_invoked!(method_name)
|
|
190
|
+
backup_method!(method_name)
|
|
191
|
+
@klass.__send__(:define_method, method_name) do |*args, &blk|
|
|
192
|
+
klass = ::RSpec::Mocks.method_handle_for(self, method_name).owner
|
|
193
|
+
invoked_instance = ::RSpec::Mocks.any_instance_recorder_for(klass).instance_that_received(method_name)
|
|
194
|
+
raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by #{self.inspect} but has already been received by #{invoked_instance}"
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
# @private
|
|
5
|
+
class StubChain < Chain
|
|
6
|
+
|
|
7
|
+
# @private
|
|
8
|
+
def expectation_fulfilled?
|
|
9
|
+
true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def create_message_expectation_on(instance)
|
|
15
|
+
proxy = ::RSpec::Mocks.proxy_for(instance)
|
|
16
|
+
expected_from = IGNORED_BACKTRACE_LINE
|
|
17
|
+
stub = proxy.add_stub(expected_from, *@expectation_args, &@expectation_block)
|
|
18
|
+
@recorder.stubs[stub.message] << stub
|
|
19
|
+
|
|
20
|
+
if RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
|
|
21
|
+
stub.and_yield_receiver_to_implementation
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
stub
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def invocation_order
|
|
28
|
+
@invocation_order ||= {
|
|
29
|
+
:with => [nil],
|
|
30
|
+
:and_return => [:with, nil],
|
|
31
|
+
:and_raise => [:with, nil],
|
|
32
|
+
:and_yield => [:with, nil],
|
|
33
|
+
:and_call_original => [:with, nil]
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def verify_invocation_order(rspec_method_name, *args, &block)
|
|
38
|
+
unless invocation_order[rspec_method_name].include?(last_message)
|
|
39
|
+
raise(NoMethodError, "Undefined method #{rspec_method_name}")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
module AnyInstance
|
|
4
|
+
# @private
|
|
5
|
+
class StubChainChain < StubChain
|
|
6
|
+
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def create_message_expectation_on(instance)
|
|
10
|
+
::RSpec::Mocks::StubChain.stub_chain_on(instance, *@expectation_args, &@expectation_block)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def invocation_order
|
|
14
|
+
@invocation_order ||= {
|
|
15
|
+
:and_return => [nil],
|
|
16
|
+
:and_raise => [nil],
|
|
17
|
+
:and_yield => [nil]
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'rspec/mocks/argument_matchers'
|
|
2
|
+
|
|
3
|
+
module RSpec
|
|
4
|
+
module Mocks
|
|
5
|
+
# Wrapper for matching arguments against a list of expected values. Used by
|
|
6
|
+
# the `with` method on a `MessageExpectation`:
|
|
7
|
+
#
|
|
8
|
+
# object.should_receive(:message).with(:a, 'b', 3)
|
|
9
|
+
# object.message(:a, 'b', 3)
|
|
10
|
+
#
|
|
11
|
+
# Values passed to `with` can be literal values or argument matchers that
|
|
12
|
+
# match against the real objects .e.g.
|
|
13
|
+
#
|
|
14
|
+
# object.should_receive(:message).with(hash_including(:a => 'b'))
|
|
15
|
+
#
|
|
16
|
+
# Can also be used directly to match the contents of any `Array`. This
|
|
17
|
+
# enables 3rd party mocking libs to take advantage of rspec's argument
|
|
18
|
+
# matching without using the rest of rspec-mocks.
|
|
19
|
+
#
|
|
20
|
+
# require 'rspec/mocks/argument_list_matcher'
|
|
21
|
+
# include RSpec::Mocks::ArgumentMatchers
|
|
22
|
+
#
|
|
23
|
+
# arg_list_matcher = RSpec::Mocks::ArgumentListMatcher.new(123, hash_including(:a => 'b'))
|
|
24
|
+
# arg_list_matcher.args_match?(123, :a => 'b')
|
|
25
|
+
#
|
|
26
|
+
# This class is immutable.
|
|
27
|
+
#
|
|
28
|
+
# @see ArgumentMatchers
|
|
29
|
+
class ArgumentListMatcher
|
|
30
|
+
# @private
|
|
31
|
+
attr_reader :expected_args
|
|
32
|
+
|
|
33
|
+
# @api public
|
|
34
|
+
# @param [Array] *expected_args a list of expected literals and/or argument matchers
|
|
35
|
+
# @param [Block] block a block with arity matching the expected
|
|
36
|
+
#
|
|
37
|
+
# Initializes an `ArgumentListMatcher` with a collection of literal
|
|
38
|
+
# values and/or argument matchers, or a block that handles the evaluation
|
|
39
|
+
# for you.
|
|
40
|
+
#
|
|
41
|
+
# @see ArgumentMatchers
|
|
42
|
+
# @see #args_match?
|
|
43
|
+
def initialize(*expected_args, &block)
|
|
44
|
+
@expected_args = expected_args
|
|
45
|
+
@block = expected_args.empty? ? block : nil
|
|
46
|
+
@match_any_args = false
|
|
47
|
+
@matchers = nil
|
|
48
|
+
|
|
49
|
+
case expected_args.first
|
|
50
|
+
when ArgumentMatchers::AnyArgsMatcher
|
|
51
|
+
@match_any_args = true
|
|
52
|
+
when ArgumentMatchers::NoArgsMatcher
|
|
53
|
+
@matchers = []
|
|
54
|
+
else
|
|
55
|
+
@matchers = expected_args.collect {|arg| matcher_for(arg)}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @api public
|
|
60
|
+
# @param [Array] *args
|
|
61
|
+
#
|
|
62
|
+
# Matches each element in the `expected_args` against the element in the same
|
|
63
|
+
# position of the arguments passed to `new`.
|
|
64
|
+
#
|
|
65
|
+
# @see #initialize
|
|
66
|
+
def args_match?(*args)
|
|
67
|
+
match_any_args? || block_passes?(*args) || matchers_match?(*args)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def matcher_for(arg)
|
|
73
|
+
return ArgumentMatchers::MatcherMatcher.new(arg) if is_matcher?(arg)
|
|
74
|
+
return ArgumentMatchers::RegexpMatcher.new(arg) if Regexp === arg
|
|
75
|
+
return ArgumentMatchers::EqualityProxy.new(arg)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def is_matcher?(object)
|
|
79
|
+
return false if object.respond_to?(:i_respond_to_everything_so_im_not_really_a_matcher)
|
|
80
|
+
|
|
81
|
+
[:failure_message_for_should, :failure_message].any? do |msg|
|
|
82
|
+
object.respond_to?(msg)
|
|
83
|
+
end && object.respond_to?(:matches?)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def block_passes?(*args)
|
|
87
|
+
@block.call(*args) if @block
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def matchers_match?(*args)
|
|
91
|
+
@matchers == args
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def match_any_args?
|
|
95
|
+
@match_any_args
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Value that will match all argument lists.
|
|
99
|
+
#
|
|
100
|
+
# @private
|
|
101
|
+
MATCH_ALL = new(ArgumentMatchers::AnyArgsMatcher.new)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
module RSpec
|
|
2
|
+
module Mocks
|
|
3
|
+
|
|
4
|
+
# ArgumentMatchers are placeholders that you can include in message
|
|
5
|
+
# expectations to match arguments against a broader check than simple
|
|
6
|
+
# equality.
|
|
7
|
+
#
|
|
8
|
+
# With the exception of `any_args` and `no_args`, they all match against
|
|
9
|
+
# the arg in same position in the argument list.
|
|
10
|
+
#
|
|
11
|
+
# @see ArgumentListMatcher
|
|
12
|
+
module ArgumentMatchers
|
|
13
|
+
|
|
14
|
+
class AnyArgsMatcher
|
|
15
|
+
def description
|
|
16
|
+
"any args"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class AnyArgMatcher
|
|
21
|
+
def initialize(ignore)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def ==(other)
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class NoArgsMatcher
|
|
30
|
+
def description
|
|
31
|
+
"no args"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class RegexpMatcher
|
|
36
|
+
def initialize(regexp)
|
|
37
|
+
@regexp = regexp
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def ==(value)
|
|
41
|
+
Regexp === value ? value == @regexp : value =~ @regexp
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class BooleanMatcher
|
|
46
|
+
def initialize(ignore)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def ==(value)
|
|
50
|
+
[true,false].include?(value)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
class HashIncludingMatcher
|
|
55
|
+
def initialize(expected)
|
|
56
|
+
@expected = expected
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def ==(actual)
|
|
60
|
+
@expected.all? {|k,v| actual.has_key?(k) && v == actual[k]}
|
|
61
|
+
rescue NoMethodError
|
|
62
|
+
false
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def description
|
|
66
|
+
"hash_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
class HashExcludingMatcher
|
|
71
|
+
def initialize(expected)
|
|
72
|
+
@expected = expected
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def ==(actual)
|
|
76
|
+
@expected.none? {|k,v| actual.has_key?(k) && v == actual[k]}
|
|
77
|
+
rescue NoMethodError
|
|
78
|
+
false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def description
|
|
82
|
+
"hash_not_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class ArrayIncludingMatcher
|
|
87
|
+
def initialize(expected)
|
|
88
|
+
@expected = expected
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def ==(actual)
|
|
92
|
+
Set.new(actual).superset?(Set.new(@expected))
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def description
|
|
96
|
+
"array_including(#{@expected.join(",")})"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class DuckTypeMatcher
|
|
101
|
+
def initialize(*methods_to_respond_to)
|
|
102
|
+
@methods_to_respond_to = methods_to_respond_to
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def ==(value)
|
|
106
|
+
@methods_to_respond_to.all? {|message| value.respond_to?(message)}
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
class MatcherMatcher
|
|
111
|
+
def initialize(matcher)
|
|
112
|
+
@matcher = matcher
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def ==(value)
|
|
116
|
+
@matcher.matches?(value)
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class EqualityProxy
|
|
121
|
+
def initialize(given)
|
|
122
|
+
@given = given
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def ==(expected)
|
|
126
|
+
@given == expected
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class InstanceOf
|
|
131
|
+
def initialize(klass)
|
|
132
|
+
@klass = klass
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def ==(actual)
|
|
136
|
+
actual.instance_of?(@klass)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
class KindOf
|
|
141
|
+
def initialize(klass)
|
|
142
|
+
@klass = klass
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def ==(actual)
|
|
146
|
+
actual.kind_of?(@klass)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Matches any args at all. Supports a more explicit variation of
|
|
151
|
+
# `object.should_receive(:message)`
|
|
152
|
+
#
|
|
153
|
+
# @example
|
|
154
|
+
#
|
|
155
|
+
# object.should_receive(:message).with(any_args)
|
|
156
|
+
def any_args
|
|
157
|
+
AnyArgsMatcher.new
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Matches any argument at all.
|
|
161
|
+
#
|
|
162
|
+
# @example
|
|
163
|
+
#
|
|
164
|
+
# object.should_receive(:message).with(anything)
|
|
165
|
+
def anything
|
|
166
|
+
AnyArgMatcher.new(nil)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Matches no arguments.
|
|
170
|
+
#
|
|
171
|
+
# @example
|
|
172
|
+
#
|
|
173
|
+
# object.should_receive(:message).with(no_args)
|
|
174
|
+
def no_args
|
|
175
|
+
NoArgsMatcher.new
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# Matches if the actual argument responds to the specified messages.
|
|
179
|
+
#
|
|
180
|
+
# @example
|
|
181
|
+
#
|
|
182
|
+
# object.should_receive(:message).with(duck_type(:hello))
|
|
183
|
+
# object.should_receive(:message).with(duck_type(:hello, :goodbye))
|
|
184
|
+
def duck_type(*args)
|
|
185
|
+
DuckTypeMatcher.new(*args)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Matches a boolean value.
|
|
189
|
+
#
|
|
190
|
+
# @example
|
|
191
|
+
#
|
|
192
|
+
# object.should_receive(:message).with(boolean())
|
|
193
|
+
def boolean
|
|
194
|
+
BooleanMatcher.new(nil)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Matches a hash that includes the specified key(s) or key/value pairs.
|
|
198
|
+
# Ignores any additional keys.
|
|
199
|
+
#
|
|
200
|
+
# @example
|
|
201
|
+
#
|
|
202
|
+
# object.should_receive(:message).with(hash_including(:key => val))
|
|
203
|
+
# object.should_receive(:message).with(hash_including(:key))
|
|
204
|
+
# object.should_receive(:message).with(hash_including(:key, :key2 => val2))
|
|
205
|
+
def hash_including(*args)
|
|
206
|
+
HashIncludingMatcher.new(anythingize_lonely_keys(*args))
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Matches an array that includes the specified items at least once.
|
|
210
|
+
# Ignores duplicates and additional values
|
|
211
|
+
#
|
|
212
|
+
# @example
|
|
213
|
+
#
|
|
214
|
+
# object.should_receive(:message).with(array_including(1,2,3))
|
|
215
|
+
# object.should_receive(:message).with(array_including([1,2,3]))
|
|
216
|
+
def array_including(*args)
|
|
217
|
+
actually_an_array = Array === args.first && args.count == 1 ? args.first : args
|
|
218
|
+
ArrayIncludingMatcher.new(actually_an_array)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Matches a hash that doesn't include the specified key(s) or key/value.
|
|
222
|
+
#
|
|
223
|
+
# @example
|
|
224
|
+
#
|
|
225
|
+
# object.should_receive(:message).with(hash_excluding(:key => val))
|
|
226
|
+
# object.should_receive(:message).with(hash_excluding(:key))
|
|
227
|
+
# object.should_receive(:message).with(hash_excluding(:key, :key2 => :val2))
|
|
228
|
+
def hash_excluding(*args)
|
|
229
|
+
HashExcludingMatcher.new(anythingize_lonely_keys(*args))
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
alias_method :hash_not_including, :hash_excluding
|
|
233
|
+
|
|
234
|
+
# Matches if `arg.instance_of?(klass)`
|
|
235
|
+
#
|
|
236
|
+
# @example
|
|
237
|
+
#
|
|
238
|
+
# object.should_receive(:message).with(instance_of(Thing))
|
|
239
|
+
def instance_of(klass)
|
|
240
|
+
InstanceOf.new(klass)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
alias_method :an_instance_of, :instance_of
|
|
244
|
+
|
|
245
|
+
# Matches if `arg.kind_of?(klass)`
|
|
246
|
+
# @example
|
|
247
|
+
#
|
|
248
|
+
# object.should_receive(:message).with(kind_of(Thing))
|
|
249
|
+
def kind_of(klass)
|
|
250
|
+
KindOf.new(klass)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
alias_method :a_kind_of, :kind_of
|
|
254
|
+
|
|
255
|
+
private
|
|
256
|
+
|
|
257
|
+
def anythingize_lonely_keys(*args)
|
|
258
|
+
hash = args.last.class == Hash ? args.delete_at(-1) : {}
|
|
259
|
+
args.each { | arg | hash[arg] = anything }
|
|
260
|
+
hash
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|