opal-rspec-cj 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +15 -0
  4. data/.travis.yml +13 -0
  5. data/.yardopts +5 -0
  6. data/CHANGELOG.md +25 -0
  7. data/Gemfile +8 -0
  8. data/README.md +147 -0
  9. data/Rakefile +26 -0
  10. data/config.ru +10 -0
  11. data/example/Gemfile +4 -0
  12. data/example/README.md +13 -0
  13. data/example/Rakefile +8 -0
  14. data/example/opal/user.rb +11 -0
  15. data/example/spec/user_spec.rb +15 -0
  16. data/lib/opal-rspec.rb +2 -0
  17. data/lib/opal/rspec.rb +20 -0
  18. data/lib/opal/rspec/rake_task.rb +63 -0
  19. data/lib/opal/rspec/version.rb +5 -0
  20. data/opal-rspec.gemspec +21 -0
  21. data/opal/opal-rspec.rb +1 -0
  22. data/opal/opal/rspec.rb +25 -0
  23. data/opal/opal/rspec/async.rb +289 -0
  24. data/opal/opal/rspec/browser_formatter.rb +188 -0
  25. data/opal/opal/rspec/fixes.rb +116 -0
  26. data/opal/opal/rspec/requires.rb +45 -0
  27. data/opal/opal/rspec/runner.rb +69 -0
  28. data/opal/opal/rspec/sprockets_runner.rb.erb +11 -0
  29. data/opal/opal/rspec/text_formatter.rb +74 -0
  30. data/spec/async_spec.rb +38 -0
  31. data/spec/example_spec.rb +163 -0
  32. data/spec/matchers_spec.rb +201 -0
  33. data/spec/mock_spec.rb +63 -0
  34. data/spec/named_subject_spec.rb +11 -0
  35. data/spec/should_syntax_spec.rb +17 -0
  36. data/vendor/spec_runner.js +50 -0
  37. data/vendor_lib/rspec-expectations.rb +1 -0
  38. data/vendor_lib/rspec.rb +3 -0
  39. data/vendor_lib/rspec/autorun.rb +2 -0
  40. data/vendor_lib/rspec/core.rb +203 -0
  41. data/vendor_lib/rspec/core/backport_random.rb +302 -0
  42. data/vendor_lib/rspec/core/backtrace_formatter.rb +65 -0
  43. data/vendor_lib/rspec/core/command_line.rb +36 -0
  44. data/vendor_lib/rspec/core/configuration.rb +1129 -0
  45. data/vendor_lib/rspec/core/configuration_options.rb +143 -0
  46. data/vendor_lib/rspec/core/drb_command_line.rb +26 -0
  47. data/vendor_lib/rspec/core/drb_options.rb +87 -0
  48. data/vendor_lib/rspec/core/dsl.rb +26 -0
  49. data/vendor_lib/rspec/core/example.rb +312 -0
  50. data/vendor_lib/rspec/core/example_group.rb +540 -0
  51. data/vendor_lib/rspec/core/filter_manager.rb +224 -0
  52. data/vendor_lib/rspec/core/flat_map.rb +17 -0
  53. data/vendor_lib/rspec/core/formatters.rb +54 -0
  54. data/vendor_lib/rspec/core/formatters/base_formatter.rb +291 -0
  55. data/vendor_lib/rspec/core/formatters/base_text_formatter.rb +307 -0
  56. data/vendor_lib/rspec/core/formatters/deprecation_formatter.rb +193 -0
  57. data/vendor_lib/rspec/core/formatters/documentation_formatter.rb +67 -0
  58. data/vendor_lib/rspec/core/formatters/helpers.rb +82 -0
  59. data/vendor_lib/rspec/core/formatters/html_formatter.rb +155 -0
  60. data/vendor_lib/rspec/core/formatters/html_printer.rb +408 -0
  61. data/vendor_lib/rspec/core/formatters/json_formatter.rb +99 -0
  62. data/vendor_lib/rspec/core/formatters/progress_formatter.rb +32 -0
  63. data/vendor_lib/rspec/core/formatters/snippet_extractor.rb +101 -0
  64. data/vendor_lib/rspec/core/hooks.rb +535 -0
  65. data/vendor_lib/rspec/core/memoized_helpers.rb +431 -0
  66. data/vendor_lib/rspec/core/metadata.rb +313 -0
  67. data/vendor_lib/rspec/core/mocking/with_absolutely_nothing.rb +11 -0
  68. data/vendor_lib/rspec/core/mocking/with_flexmock.rb +27 -0
  69. data/vendor_lib/rspec/core/mocking/with_mocha.rb +52 -0
  70. data/vendor_lib/rspec/core/mocking/with_rr.rb +27 -0
  71. data/vendor_lib/rspec/core/mocking/with_rspec.rb +27 -0
  72. data/vendor_lib/rspec/core/option_parser.rb +234 -0
  73. data/vendor_lib/rspec/core/ordering.rb +154 -0
  74. data/vendor_lib/rspec/core/pending.rb +110 -0
  75. data/vendor_lib/rspec/core/project_initializer.rb +88 -0
  76. data/vendor_lib/rspec/core/rake_task.rb +128 -0
  77. data/vendor_lib/rspec/core/reporter.rb +132 -0
  78. data/vendor_lib/rspec/core/ruby_project.rb +44 -0
  79. data/vendor_lib/rspec/core/runner.rb +97 -0
  80. data/vendor_lib/rspec/core/shared_context.rb +53 -0
  81. data/vendor_lib/rspec/core/shared_example_group.rb +146 -0
  82. data/vendor_lib/rspec/core/shared_example_group/collection.rb +27 -0
  83. data/vendor_lib/rspec/core/version.rb +7 -0
  84. data/vendor_lib/rspec/core/warnings.rb +22 -0
  85. data/vendor_lib/rspec/core/world.rb +131 -0
  86. data/vendor_lib/rspec/expectations.rb +75 -0
  87. data/vendor_lib/rspec/expectations/differ.rb +154 -0
  88. data/vendor_lib/rspec/expectations/errors.rb +9 -0
  89. data/vendor_lib/rspec/expectations/expectation_target.rb +87 -0
  90. data/vendor_lib/rspec/expectations/extensions.rb +1 -0
  91. data/vendor_lib/rspec/expectations/extensions/object.rb +29 -0
  92. data/vendor_lib/rspec/expectations/fail_with.rb +79 -0
  93. data/vendor_lib/rspec/expectations/handler.rb +68 -0
  94. data/vendor_lib/rspec/expectations/syntax.rb +182 -0
  95. data/vendor_lib/rspec/expectations/version.rb +8 -0
  96. data/vendor_lib/rspec/matchers.rb +633 -0
  97. data/vendor_lib/rspec/matchers/built_in.rb +39 -0
  98. data/vendor_lib/rspec/matchers/built_in/base_matcher.rb +68 -0
  99. data/vendor_lib/rspec/matchers/built_in/be.rb +213 -0
  100. data/vendor_lib/rspec/matchers/built_in/be_instance_of.rb +15 -0
  101. data/vendor_lib/rspec/matchers/built_in/be_kind_of.rb +11 -0
  102. data/vendor_lib/rspec/matchers/built_in/be_within.rb +55 -0
  103. data/vendor_lib/rspec/matchers/built_in/change.rb +141 -0
  104. data/vendor_lib/rspec/matchers/built_in/cover.rb +21 -0
  105. data/vendor_lib/rspec/matchers/built_in/eq.rb +22 -0
  106. data/vendor_lib/rspec/matchers/built_in/eql.rb +23 -0
  107. data/vendor_lib/rspec/matchers/built_in/equal.rb +48 -0
  108. data/vendor_lib/rspec/matchers/built_in/exist.rb +26 -0
  109. data/vendor_lib/rspec/matchers/built_in/has.rb +48 -0
  110. data/vendor_lib/rspec/matchers/built_in/include.rb +61 -0
  111. data/vendor_lib/rspec/matchers/built_in/match.rb +17 -0
  112. data/vendor_lib/rspec/matchers/built_in/match_array.rb +51 -0
  113. data/vendor_lib/rspec/matchers/built_in/raise_error.rb +154 -0
  114. data/vendor_lib/rspec/matchers/built_in/respond_to.rb +74 -0
  115. data/vendor_lib/rspec/matchers/built_in/satisfy.rb +30 -0
  116. data/vendor_lib/rspec/matchers/built_in/start_and_end_with.rb +48 -0
  117. data/vendor_lib/rspec/matchers/built_in/throw_symbol.rb +94 -0
  118. data/vendor_lib/rspec/matchers/built_in/yield.rb +297 -0
  119. data/vendor_lib/rspec/matchers/compatibility.rb +14 -0
  120. data/vendor_lib/rspec/matchers/configuration.rb +113 -0
  121. data/vendor_lib/rspec/matchers/dsl.rb +23 -0
  122. data/vendor_lib/rspec/matchers/generated_descriptions.rb +35 -0
  123. data/vendor_lib/rspec/matchers/matcher.rb +301 -0
  124. data/vendor_lib/rspec/matchers/method_missing.rb +12 -0
  125. data/vendor_lib/rspec/matchers/operator_matcher.rb +99 -0
  126. data/vendor_lib/rspec/matchers/pretty.rb +70 -0
  127. data/vendor_lib/rspec/matchers/test_unit_integration.rb +11 -0
  128. data/vendor_lib/rspec/mocks.rb +100 -0
  129. data/vendor_lib/rspec/mocks/any_instance/chain.rb +92 -0
  130. data/vendor_lib/rspec/mocks/any_instance/expectation_chain.rb +47 -0
  131. data/vendor_lib/rspec/mocks/any_instance/message_chains.rb +75 -0
  132. data/vendor_lib/rspec/mocks/any_instance/recorder.rb +200 -0
  133. data/vendor_lib/rspec/mocks/any_instance/stub_chain.rb +45 -0
  134. data/vendor_lib/rspec/mocks/any_instance/stub_chain_chain.rb +23 -0
  135. data/vendor_lib/rspec/mocks/argument_list_matcher.rb +104 -0
  136. data/vendor_lib/rspec/mocks/argument_matchers.rb +264 -0
  137. data/vendor_lib/rspec/mocks/arity_calculator.rb +66 -0
  138. data/vendor_lib/rspec/mocks/configuration.rb +111 -0
  139. data/vendor_lib/rspec/mocks/error_generator.rb +203 -0
  140. data/vendor_lib/rspec/mocks/errors.rb +12 -0
  141. data/vendor_lib/rspec/mocks/example_methods.rb +201 -0
  142. data/vendor_lib/rspec/mocks/extensions/marshal.rb +17 -0
  143. data/vendor_lib/rspec/mocks/framework.rb +36 -0
  144. data/vendor_lib/rspec/mocks/instance_method_stasher.rb +112 -0
  145. data/vendor_lib/rspec/mocks/matchers/have_received.rb +99 -0
  146. data/vendor_lib/rspec/mocks/matchers/receive.rb +112 -0
  147. data/vendor_lib/rspec/mocks/matchers/receive_messages.rb +72 -0
  148. data/vendor_lib/rspec/mocks/message_expectation.rb +643 -0
  149. data/vendor_lib/rspec/mocks/method_double.rb +209 -0
  150. data/vendor_lib/rspec/mocks/method_reference.rb +95 -0
  151. data/vendor_lib/rspec/mocks/mock.rb +7 -0
  152. data/vendor_lib/rspec/mocks/mutate_const.rb +406 -0
  153. data/vendor_lib/rspec/mocks/object_reference.rb +90 -0
  154. data/vendor_lib/rspec/mocks/order_group.rb +82 -0
  155. data/vendor_lib/rspec/mocks/proxy.rb +269 -0
  156. data/vendor_lib/rspec/mocks/proxy_for_nil.rb +37 -0
  157. data/vendor_lib/rspec/mocks/space.rb +95 -0
  158. data/vendor_lib/rspec/mocks/standalone.rb +3 -0
  159. data/vendor_lib/rspec/mocks/stub_chain.rb +51 -0
  160. data/vendor_lib/rspec/mocks/syntax.rb +374 -0
  161. data/vendor_lib/rspec/mocks/targets.rb +90 -0
  162. data/vendor_lib/rspec/mocks/test_double.rb +109 -0
  163. data/vendor_lib/rspec/mocks/verifying_double.rb +77 -0
  164. data/vendor_lib/rspec/mocks/verifying_message_expecation.rb +60 -0
  165. data/vendor_lib/rspec/mocks/verifying_proxy.rb +151 -0
  166. data/vendor_lib/rspec/mocks/version.rb +7 -0
  167. data/vendor_lib/rspec/support.rb +6 -0
  168. data/vendor_lib/rspec/support/caller_filter.rb +56 -0
  169. data/vendor_lib/rspec/support/spec.rb +14 -0
  170. data/vendor_lib/rspec/support/spec/deprecation_helpers.rb +29 -0
  171. data/vendor_lib/rspec/support/spec/in_sub_process.rb +40 -0
  172. data/vendor_lib/rspec/support/spec/stderr_splitter.rb +50 -0
  173. data/vendor_lib/rspec/support/version.rb +7 -0
  174. data/vendor_lib/rspec/support/warnings.rb +41 -0
  175. data/vendor_lib/rspec/version.rb +5 -0
  176. metadata +268 -0
@@ -0,0 +1,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