opal-rspec-cj 0.4.4

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