mocha 1.14.0 → 2.0.0.alpha

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/Gemfile +3 -5
  4. data/README.md +1 -1
  5. data/RELEASE.md +52 -0
  6. data/Rakefile +19 -20
  7. data/gemfiles/Gemfile.test-unit.latest +1 -5
  8. data/lib/mocha/any_instance_method.rb +0 -5
  9. data/lib/mocha/api.rb +29 -78
  10. data/lib/mocha/class_methods.rb +2 -2
  11. data/lib/mocha/configuration.rb +30 -108
  12. data/lib/mocha/expectation.rb +55 -7
  13. data/lib/mocha/inspect.rb +2 -2
  14. data/lib/mocha/instance_method.rb +0 -4
  15. data/lib/mocha/integration/mini_test.rb +10 -38
  16. data/lib/mocha/integration/test_unit/adapter.rb +1 -1
  17. data/lib/mocha/integration/test_unit.rb +10 -33
  18. data/lib/mocha/invocation.rb +12 -16
  19. data/lib/mocha/minitest.rb +2 -4
  20. data/lib/mocha/mock.rb +22 -26
  21. data/lib/mocha/mockery.rb +1 -3
  22. data/lib/mocha/parameter_matchers/equivalent_uri.rb +0 -1
  23. data/lib/mocha/parameter_matchers/instance_methods.rb +9 -0
  24. data/lib/mocha/parameter_matchers/positional_or_keyword_hash.rb +56 -0
  25. data/lib/mocha/parameters_matcher.rb +0 -1
  26. data/lib/mocha/ruby_version.rb +1 -2
  27. data/lib/mocha/stubbed_method.rb +5 -42
  28. data/lib/mocha/test_unit.rb +2 -4
  29. data/lib/mocha/version.rb +1 -1
  30. data/lib/mocha.rb +0 -8
  31. data/mocha.gemspec +1 -1
  32. metadata +7 -27
  33. data/init.rb +0 -1
  34. data/lib/mocha/integration/mini_test/nothing.rb +0 -19
  35. data/lib/mocha/integration/mini_test/version_13.rb +0 -54
  36. data/lib/mocha/integration/mini_test/version_140.rb +0 -54
  37. data/lib/mocha/integration/mini_test/version_141.rb +0 -65
  38. data/lib/mocha/integration/mini_test/version_142_to_172.rb +0 -65
  39. data/lib/mocha/integration/mini_test/version_200.rb +0 -66
  40. data/lib/mocha/integration/mini_test/version_201_to_222.rb +0 -66
  41. data/lib/mocha/integration/mini_test/version_2110_to_2111.rb +0 -70
  42. data/lib/mocha/integration/mini_test/version_2112_to_320.rb +0 -73
  43. data/lib/mocha/integration/mini_test/version_230_to_2101.rb +0 -68
  44. data/lib/mocha/integration/test_unit/gem_version_200.rb +0 -62
  45. data/lib/mocha/integration/test_unit/gem_version_201_to_202.rb +0 -62
  46. data/lib/mocha/integration/test_unit/gem_version_203_to_220.rb +0 -62
  47. data/lib/mocha/integration/test_unit/gem_version_230_to_250.rb +0 -68
  48. data/lib/mocha/integration/test_unit/nothing.rb +0 -19
  49. data/lib/mocha/integration/test_unit/ruby_version_185_and_below.rb +0 -61
  50. data/lib/mocha/integration/test_unit/ruby_version_186_and_above.rb +0 -63
  51. data/lib/mocha/integration.rb +0 -11
  52. data/lib/mocha/setup.rb +0 -14
  53. data/lib/mocha/singleton_class.rb +0 -9
@@ -1,3 +1,4 @@
1
+ require 'ruby2_keywords'
1
2
  require 'mocha/method_matcher'
2
3
  require 'mocha/parameters_matcher'
3
4
  require 'mocha/expectation_error'
@@ -187,17 +188,26 @@ module Mocha
187
188
  at_most(1)
188
189
  end
189
190
 
190
- # Modifies expectation so that the expected method must be called with +expected_parameters+.
191
+ # Modifies expectation so that the expected method must be called with +expected_parameters_or_matchers+.
191
192
  #
192
- # May be used with parameter matchers in {ParameterMatchers}.
193
+ # May be used with Ruby literals or variables for exact matching or with parameter matchers for less-specific matching, e.g. {ParameterMatchers#includes}, {ParameterMatchers#has_key}, etc. See {ParameterMatchers} for a list of all available parameter matchers.
193
194
  #
194
- # @param [*Array] expected_parameters parameters expected.
195
+ # Positional arguments were separated from keyword arguments in Ruby v3 (see {https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0 this article}). In relation to this a new configuration option ({Configuration#strict_keyword_argument_matching=}) is available in Ruby >= 2.7.
196
+ #
197
+ # When {Configuration#strict_keyword_argument_matching=} is set to +false+ (which is currently the default), a positional +Hash+ and a set of keyword arguments passed to {#with} are treated the same for the purposes of parameter matching. However, a deprecation warning will be displayed if a positional +Hash+ matches a set of keyword arguments or vice versa. This is because {Configuration#strict_keyword_argument_matching=} will default to +true+ in the future.
198
+ #
199
+ # When {Configuration#strict_keyword_argument_matching=} is set to +true+, an actual positional +Hash+ will not match an expected set of keyword arguments; and vice versa, an actual set of keyword arguments will not match an expected positional +Hash+, i.e. the parameter matching is stricter.
200
+ #
201
+ # @see ParameterMatchers
202
+ # @see Configuration#strict_keyword_argument_matching=
203
+ #
204
+ # @param [*Array<Object,ParameterMatchers::Base>] expected_parameters_or_matchers expected parameter values or parameter matchers.
195
205
  # @yield optional block specifying custom matching.
196
- # @yieldparam [*Array] actual_parameters parameters with which expected method was invoked.
206
+ # @yieldparam [*Array<Object>] actual_parameters parameters with which expected method was invoked.
197
207
  # @yieldreturn [Boolean] +true+ if +actual_parameters+ are acceptable.
198
208
  # @return [Expectation] the same expectation, thereby allowing invocations of other {Expectation} methods to be chained.
199
209
  #
200
- # @example Expected method must be called with expected parameters.
210
+ # @example Expected method must be called with exact parameter values.
201
211
  # object = mock()
202
212
  # object.expects(:expected_method).with(:param1, :param2)
203
213
  # object.expected_method(:param1, :param2)
@@ -208,6 +218,43 @@ module Mocha
208
218
  # object.expected_method(:param3)
209
219
  # # => verify fails
210
220
  #
221
+ # @example Expected method must be called with parameters matching parameter matchers.
222
+ # object = mock()
223
+ # object.expects(:expected_method).with(includes('string2'), anything)
224
+ # object.expected_method(['string1', 'string2'], 'any-old-value')
225
+ # # => verify succeeds
226
+ #
227
+ # object = mock()
228
+ # object.expects(:expected_method).with(includes('string2'), anything)
229
+ # object.expected_method(['string1'], 'any-old-value')
230
+ # # => verify fails
231
+ #
232
+ # @example Loose keyword argument matching (default)
233
+ #
234
+ # class Example
235
+ # def foo(a, bar:); end
236
+ # end
237
+ #
238
+ # example = Example.new
239
+ # example.expects(:foo).with('a', bar: 'b')
240
+ # example.foo('a', { bar: 'b' })
241
+ # # This passes the test, but would result in an ArgumentError in practice
242
+ #
243
+ # @example Strict keyword argument matching
244
+ #
245
+ # Mocha.configure do |c|
246
+ # c.strict_keyword_argument_matching = true
247
+ # end
248
+ #
249
+ # class Example
250
+ # def foo(a, bar:); end
251
+ # end
252
+ #
253
+ # example = Example.new
254
+ # example.expects(:foo).with('a', bar: 'b')
255
+ # example.foo('a', { bar: 'b' })
256
+ # # This now fails as expected
257
+ #
211
258
  # @example Expected method must be called with a value divisible by 4.
212
259
  # object = mock()
213
260
  # object.expects(:expected_method).with() { |value| value % 4 == 0 }
@@ -218,10 +265,11 @@ module Mocha
218
265
  # object.expects(:expected_method).with() { |value| value % 4 == 0 }
219
266
  # object.expected_method(17)
220
267
  # # => verify fails
221
- def with(*expected_parameters, &matching_block)
222
- @parameters_matcher = ParametersMatcher.new(expected_parameters, &matching_block)
268
+ def with(*expected_parameters_or_matchers, &matching_block)
269
+ @parameters_matcher = ParametersMatcher.new(expected_parameters_or_matchers, &matching_block)
223
270
  self
224
271
  end
272
+ ruby2_keywords(:with)
225
273
 
226
274
  # Modifies expectation so that the expected method must be called with a block.
227
275
  #
data/lib/mocha/inspect.rb CHANGED
@@ -18,9 +18,9 @@ module Mocha
18
18
  end
19
19
 
20
20
  module HashMethods
21
- def mocha_inspect(wrapped = true)
21
+ def mocha_inspect
22
22
  unwrapped = collect { |key, value| "#{key.mocha_inspect} => #{value.mocha_inspect}" }.join(', ')
23
- wrapped ? "{#{unwrapped}}" : unwrapped
23
+ Hash.ruby2_keywords_hash?(self) ? unwrapped : "{#{unwrapped}}"
24
24
  end
25
25
  end
26
26
 
@@ -8,10 +8,6 @@ module Mocha
8
8
  stubbee
9
9
  end
10
10
 
11
- def method_body(method)
12
- PRE_RUBY_V19 ? proc { |*args, &block| method.call(*args, &block) } : method
13
- end
14
-
15
11
  def stubbee_method(method_name)
16
12
  stubbee._method(method_name)
17
13
  end
@@ -1,54 +1,26 @@
1
1
  require 'mocha/debug'
2
-
3
2
  require 'mocha/detection/mini_test'
4
-
5
- require 'mocha/integration/mini_test/nothing'
6
- require 'mocha/integration/mini_test/version_13'
7
- require 'mocha/integration/mini_test/version_140'
8
- require 'mocha/integration/mini_test/version_141'
9
- require 'mocha/integration/mini_test/version_142_to_172'
10
- require 'mocha/integration/mini_test/version_200'
11
- require 'mocha/integration/mini_test/version_201_to_222'
12
- require 'mocha/integration/mini_test/version_230_to_2101'
13
- require 'mocha/integration/mini_test/version_2110_to_2111'
14
- require 'mocha/integration/mini_test/version_2112_to_320'
15
3
  require 'mocha/integration/mini_test/adapter'
16
4
 
17
- require 'mocha/deprecation'
18
-
19
5
  module Mocha
20
6
  module Integration
21
7
  module MiniTest
22
8
  def self.activate
23
- return false unless Detection::MiniTest.testcase
24
- mini_test_version = Gem::Version.new(Detection::MiniTest.version)
9
+ target = Detection::MiniTest.testcase
10
+ return false unless target
25
11
 
12
+ mini_test_version = Gem::Version.new(Detection::MiniTest.version)
26
13
  Debug.puts "Detected MiniTest version: #{mini_test_version}"
27
14
 
28
- integration_module = [
29
- MiniTest::Adapter,
30
- MiniTest::Version2112To320,
31
- MiniTest::Version2110To2111,
32
- MiniTest::Version230To2101,
33
- MiniTest::Version201To222,
34
- MiniTest::Version200,
35
- MiniTest::Version142To172,
36
- MiniTest::Version141,
37
- MiniTest::Version140,
38
- MiniTest::Version13,
39
- MiniTest::Nothing
40
- ].detect { |m| m.applicable_to?(mini_test_version) }
15
+ unless MiniTest::Adapter.applicable_to?(mini_test_version)
16
+ raise 'Versions of minitest earlier than v3.3.0 are not supported.'
17
+ end
41
18
 
42
- target = Detection::MiniTest.testcase
43
- unless target < integration_module
44
- unless integration_module == MiniTest::Adapter
45
- Deprecation.warning(
46
- 'Versions of minitest earlier than v3.3.0 will not be supported in future versions of Mocha.'
47
- )
48
- end
49
- Debug.puts "Applying #{integration_module.description}"
50
- target.send(:include, integration_module)
19
+ unless target < MiniTest::Adapter
20
+ Debug.puts "Applying #{MiniTest::Adapter.description}"
21
+ target.send(:include, MiniTest::Adapter)
51
22
  end
23
+
52
24
  true
53
25
  end
54
26
  end
@@ -12,7 +12,7 @@ module Mocha
12
12
  include Mocha::API
13
13
 
14
14
  # @private
15
- def self.applicable_to?(test_unit_version, _ruby_version = nil)
15
+ def self.applicable_to?(test_unit_version)
16
16
  Gem::Requirement.new('>= 2.5.1').satisfied_by?(test_unit_version)
17
17
  end
18
18
 
@@ -1,49 +1,26 @@
1
1
  require 'mocha/debug'
2
-
3
2
  require 'mocha/detection/test_unit'
4
-
5
- require 'mocha/integration/test_unit/nothing'
6
- require 'mocha/integration/test_unit/ruby_version_185_and_below'
7
- require 'mocha/integration/test_unit/ruby_version_186_and_above'
8
- require 'mocha/integration/test_unit/gem_version_200'
9
- require 'mocha/integration/test_unit/gem_version_201_to_202'
10
- require 'mocha/integration/test_unit/gem_version_203_to_220'
11
- require 'mocha/integration/test_unit/gem_version_230_to_250'
12
3
  require 'mocha/integration/test_unit/adapter'
13
4
 
14
- require 'mocha/deprecation'
15
-
16
5
  module Mocha
17
6
  module Integration
18
7
  module TestUnit
19
8
  def self.activate
20
- return false unless Detection::TestUnit.testcase
21
- test_unit_version = Gem::Version.new(Detection::TestUnit.version)
22
- ruby_version = Gem::Version.new(RUBY_VERSION.dup)
9
+ target = Detection::TestUnit.testcase
10
+ return false unless target
23
11
 
24
- Debug.puts "Detected Ruby version: #{ruby_version}"
12
+ test_unit_version = Gem::Version.new(Detection::TestUnit.version)
25
13
  Debug.puts "Detected Test::Unit version: #{test_unit_version}"
26
14
 
27
- integration_module = [
28
- TestUnit::Adapter,
29
- TestUnit::GemVersion230To250,
30
- TestUnit::GemVersion203To220,
31
- TestUnit::GemVersion201To202,
32
- TestUnit::GemVersion200,
33
- TestUnit::RubyVersion186AndAbove,
34
- TestUnit::RubyVersion185AndBelow,
35
- TestUnit::Nothing
36
- ].detect { |m| m.applicable_to?(test_unit_version, ruby_version) }
15
+ unless TestUnit::Adapter.applicable_to?(test_unit_version)
16
+ raise 'Versions of test-unit earlier than v2.5.1 are not supported.'
17
+ end
37
18
 
38
- unless ::Test::Unit::TestCase < integration_module
39
- unless integration_module == TestUnit::Adapter
40
- Deprecation.warning(
41
- 'Versions of test-unit earlier than v2.5.1 will not be supported in future versions of Mocha.'
42
- )
43
- end
44
- Debug.puts "Applying #{integration_module.description}"
45
- ::Test::Unit::TestCase.send(:include, integration_module)
19
+ unless target < TestUnit::Adapter
20
+ Debug.puts "Applying #{TestUnit::Adapter.description}"
21
+ target.send(:include, TestUnit::Adapter)
46
22
  end
23
+
47
24
  true
48
25
  end
49
26
  end
@@ -3,14 +3,12 @@ require 'mocha/raised_exception'
3
3
  require 'mocha/return_values'
4
4
  require 'mocha/thrown_object'
5
5
  require 'mocha/yield_parameters'
6
- require 'mocha/configuration'
7
- require 'mocha/deprecation'
8
6
 
9
7
  module Mocha
10
8
  class Invocation
11
9
  attr_reader :method_name, :block
12
10
 
13
- def initialize(mock, method_name, *arguments, &block)
11
+ def initialize(mock, method_name, arguments = [], block = nil)
14
12
  @mock = mock
15
13
  @method_name = method_name
16
14
  @arguments = arguments
@@ -22,18 +20,8 @@ module Mocha
22
20
  def call(yield_parameters = YieldParameters.new, return_values = ReturnValues.new)
23
21
  yield_parameters.next_invocation.each do |yield_args|
24
22
  @yields << ParametersMatcher.new(yield_args)
25
- if @block
26
- @block.call(*yield_args)
27
- else
28
- raise LocalJumpError unless Mocha.configuration.reinstate_undocumented_behaviour_from_v1_9?
29
- yield_args_description = ParametersMatcher.new(yield_args).mocha_inspect
30
- Deprecation.warning(
31
- "Stubbed method was instructed to yield #{yield_args_description}, but no block was given by invocation: #{call_description}.",
32
- ' This will raise a LocalJumpError in the future.',
33
- ' Use Expectation#with_block_given to constrain this expectation to match invocations supplying a block.',
34
- ' And, if necessary, add another expectation to match invocations not supplying a block.'
35
- )
36
- end
23
+ raise LocalJumpError unless @block
24
+ @block.call(*yield_args)
37
25
  end
38
26
  return_values.next(self)
39
27
  end
@@ -55,7 +43,7 @@ module Mocha
55
43
  end
56
44
 
57
45
  def call_description
58
- description = "#{@mock.mocha_inspect}.#{@method_name}#{ParametersMatcher.new(@arguments).mocha_inspect}"
46
+ description = "#{@mock.mocha_inspect}.#{@method_name}#{argument_description}"
59
47
  description << ' { ... }' unless @block.nil?
60
48
  description
61
49
  end
@@ -73,5 +61,13 @@ module Mocha
73
61
  def full_description
74
62
  "\n - #{call_description} #{result_description}"
75
63
  end
64
+
65
+ private
66
+
67
+ def argument_description
68
+ signature = arguments.mocha_inspect
69
+ signature = signature.gsub(/^\[|\]$/, '')
70
+ "(#{signature})"
71
+ end
76
72
  end
77
73
  end
@@ -1,8 +1,6 @@
1
+ require 'mocha/ruby_version'
1
2
  require 'mocha/integration/mini_test'
2
- require 'mocha/deprecation'
3
3
 
4
4
  unless Mocha::Integration::MiniTest.activate
5
- Mocha::Deprecation.warning(
6
- "MiniTest must be loaded *before* `require 'mocha/minitest'`."
7
- )
5
+ raise "MiniTest must be loaded *before* `require 'mocha/minitest'`."
8
6
  end
data/lib/mocha/mock.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'mocha/singleton_class'
1
+ require 'ruby2_keywords'
2
2
  require 'mocha/expectation'
3
3
  require 'mocha/expectation_list'
4
4
  require 'mocha/invocation'
@@ -8,7 +8,6 @@ require 'mocha/method_matcher'
8
8
  require 'mocha/parameters_matcher'
9
9
  require 'mocha/argument_iterator'
10
10
  require 'mocha/expectation_error_factory'
11
- require 'mocha/ruby_version'
12
11
 
13
12
  module Mocha
14
13
  # Traditional mock object.
@@ -165,7 +164,7 @@ module Mocha
165
164
  # @param [Array<Symbol>] method_names names of methods to unstub.
166
165
  #
167
166
  # @example Invoking an unstubbed method causes error to be raised
168
- # object = mock('mock') do
167
+ # object = mock('mock')
169
168
  # object.stubs(:stubbed_method).returns(:result_one)
170
169
  # object.stubbed_method # => :result_one
171
170
  # object.unstub(:stubbed_method)
@@ -310,10 +309,18 @@ module Mocha
310
309
  end
311
310
 
312
311
  # @private
313
- def method_missing(symbol, *arguments, &block) # rubocop:disable Style/MethodMissingSuper
312
+ # rubocop:disable Style/MethodMissingSuper
313
+ def method_missing(symbol, *arguments, &block)
314
+ handle_method_call(symbol, arguments, block)
315
+ end
316
+ ruby2_keywords(:method_missing)
317
+ # rubocop:enable Style/MethodMissingSuper
318
+
319
+ # @private
320
+ def handle_method_call(symbol, arguments, block)
314
321
  check_expiry
315
322
  check_responder_responds_to(symbol)
316
- invocation = Invocation.new(self, symbol, *arguments, &block)
323
+ invocation = Invocation.new(self, symbol, arguments, block)
317
324
  if (matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(invocation))
318
325
  matching_expectation_allowing_invocation.invoke(invocation)
319
326
  elsif (matching_expectation = all_expectations.match(invocation)) || (!matching_expectation && !@everything_stubbed)
@@ -322,25 +329,14 @@ module Mocha
322
329
  end
323
330
 
324
331
  # @private
325
- def respond_to_missing?(symbol, include_private = false)
332
+ def respond_to_missing?(symbol, include_all)
326
333
  if @responder
327
- if @responder.method(:respond_to?).arity > 1
328
- @responder.respond_to?(symbol, include_private)
329
- else
330
- @responder.respond_to?(symbol)
331
- end
334
+ @responder.respond_to?(symbol, include_all)
332
335
  else
333
336
  @everything_stubbed || all_expectations.matches_method?(symbol)
334
337
  end
335
338
  end
336
339
 
337
- if PRE_RUBY_V19
338
- # @private
339
- def respond_to?(symbol, include_private = false)
340
- respond_to_missing?(symbol, include_private)
341
- end
342
- end
343
-
344
340
  # @private
345
341
  def __verified__?(assertion_counter = nil)
346
342
  @expectations.verified?(assertion_counter)
@@ -391,14 +387,14 @@ module Mocha
391
387
  end
392
388
 
393
389
  def check_expiry
394
- if @expired # rubocop:disable Style/GuardClause
395
- Deprecation.warning(
396
- "#{mocha_inspect} was instantiated in one test but it is receiving invocations within another test.",
397
- ' This can lead to unintended interactions between tests and hence unexpected test failures.',
398
- ' Ensure that every test correctly cleans up any state that it introduces.',
399
- ' A Mocha::StubbingError will be raised in this scenario in the future.'
400
- )
401
- end
390
+ return unless @expired
391
+
392
+ sentences = [
393
+ "#{mocha_inspect} was instantiated in one test but it is receiving invocations within another test.",
394
+ 'This can lead to unintended interactions between tests and hence unexpected test failures.',
395
+ 'Ensure that every test correctly cleans up any state that it introduces.'
396
+ ]
397
+ raise StubbingError.new(sentences.join(' '), caller)
402
398
  end
403
399
  end
404
400
  end
data/lib/mocha/mockery.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'mocha/ruby_version'
2
1
  require 'mocha/central'
3
2
  require 'mocha/mock'
4
3
  require 'mocha/names'
@@ -119,10 +118,9 @@ module Mocha
119
118
  end
120
119
 
121
120
  def on_stubbing(object, method)
122
- method = PRE_RUBY_V19 ? method.to_s : method.to_sym
123
121
  signature_proc = lambda { "#{object.mocha_inspect}.#{method}" }
124
122
  check(:stubbing_non_existent_method, 'non-existent method', signature_proc) do
125
- !(object.stubba_class.__method_exists__?(method, true) || object.respond_to?(method.to_sym))
123
+ !(object.stubba_class.__method_exists__?(method, true) || object.respond_to?(method))
126
124
  end
127
125
  check(:stubbing_non_public_method, 'non-public method', signature_proc) do
128
126
  object.stubba_class.__method_exists__?(method, false)
@@ -1,4 +1,3 @@
1
- require 'mocha/deprecation'
2
1
  require 'mocha/parameter_matchers/base'
3
2
  require 'uri'
4
3
  require 'cgi'
@@ -1,4 +1,5 @@
1
1
  require 'mocha/parameter_matchers/equals'
2
+ require 'mocha/parameter_matchers/positional_or_keyword_hash'
2
3
 
3
4
  module Mocha
4
5
  module ParameterMatchers
@@ -16,3 +17,11 @@ end
16
17
  class Object
17
18
  include Mocha::ParameterMatchers::InstanceMethods
18
19
  end
20
+
21
+ # @private
22
+ class Hash
23
+ # @private
24
+ def to_matcher
25
+ Mocha::ParameterMatchers::PositionalOrKeywordHash.new(self)
26
+ end
27
+ end
@@ -0,0 +1,56 @@
1
+ require 'mocha/configuration'
2
+ require 'mocha/deprecation'
3
+ require 'mocha/parameter_matchers/base'
4
+
5
+ module Mocha
6
+ module ParameterMatchers
7
+ # @private
8
+ class PositionalOrKeywordHash < Base
9
+ def initialize(value)
10
+ @value = value
11
+ end
12
+
13
+ def matches?(available_parameters)
14
+ parameter, is_last_parameter = extract_parameter(available_parameters)
15
+ return false unless parameter == @value
16
+
17
+ if is_last_parameter && !same_type_of_hash?(parameter, @value)
18
+ return false if Mocha.configuration.strict_keyword_argument_matching?
19
+
20
+ deprecation_warning(parameter, @value) if Mocha::RUBY_V27_PLUS
21
+ end
22
+
23
+ true
24
+ end
25
+
26
+ def mocha_inspect
27
+ @value.mocha_inspect
28
+ end
29
+
30
+ private
31
+
32
+ def extract_parameter(available_parameters)
33
+ [available_parameters.shift, available_parameters.empty?]
34
+ end
35
+
36
+ def same_type_of_hash?(actual, expected)
37
+ ruby2_keywords_hash?(actual) == ruby2_keywords_hash?(expected)
38
+ end
39
+
40
+ def deprecation_warning(actual, expected)
41
+ details = "Expected #{hash_type(expected)} (#{expected.mocha_inspect}), but received #{hash_type(actual)} (#{actual.mocha_inspect})."
42
+ sentence1 = 'These will stop matching when strict keyword argument matching is enabled.'
43
+ sentence2 = 'See the documentation for Mocha::Configuration#strict_keyword_argument_matching=.'
44
+ Deprecation.warning([details, sentence1, sentence2].join(' '))
45
+ end
46
+
47
+ def hash_type(hash)
48
+ ruby2_keywords_hash?(hash) ? 'keyword arguments' : 'positional hash'
49
+ end
50
+
51
+ def ruby2_keywords_hash?(hash)
52
+ hash.is_a?(Hash) && ::Hash.ruby2_keywords_hash?(hash)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -23,7 +23,6 @@ module Mocha
23
23
  def mocha_inspect
24
24
  signature = matchers.mocha_inspect
25
25
  signature = signature.gsub(/^\[|\]$/, '')
26
- signature = signature.gsub(/^\{|\}$/, '') if matchers.length == 1
27
26
  "(#{signature})"
28
27
  end
29
28
 
@@ -1,4 +1,3 @@
1
1
  module Mocha
2
- PRE_RUBY_V19 = Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('1.9')
3
- RUBY_V2_PLUS = Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2')
2
+ RUBY_V27_PLUS = Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.7')
4
3
  end
@@ -1,5 +1,5 @@
1
+ require 'ruby2_keywords'
1
2
  require 'mocha/ruby_version'
2
- require 'mocha/singleton_class'
3
3
 
4
4
  module Mocha
5
5
  class StubbedMethod
@@ -11,7 +11,7 @@ module Mocha
11
11
  @stubbee = stubbee
12
12
  @original_method = nil
13
13
  @original_visibility = nil
14
- @method_name = PRE_RUBY_V19 ? method_name.to_s : method_name.to_sym
14
+ @method_name = method_name.to_sym
15
15
  end
16
16
 
17
17
  def stub
@@ -21,7 +21,6 @@ module Mocha
21
21
 
22
22
  def unstub
23
23
  remove_new_method
24
- restore_original_method
25
24
  mock.unstub(method_name.to_sym)
26
25
  return if mock.any_expectations?
27
26
  reset_mocha
@@ -38,28 +37,16 @@ module Mocha
38
37
  def hide_original_method
39
38
  return unless original_method_owner.__method_exists__?(method_name)
40
39
  store_original_method_visibility
41
- if use_prepended_module_for_stub_method?
42
- use_prepended_module_for_stub_method
43
- else
44
- begin
45
- store_original_method
46
- # rubocop:disable Lint/HandleExceptions
47
- rescue NameError
48
- # deal with nasties like ActiveRecord::Associations::AssociationProxy
49
- end
50
- # rubocop:enable Lint/HandleExceptions
51
- if stub_method_overwrites_original_method?
52
- remove_original_method_from_stubbee
53
- end
54
- end
40
+ use_prepended_module_for_stub_method
55
41
  end
56
42
 
57
43
  def define_new_method
58
44
  self_in_scope = self
59
45
  method_name_in_scope = method_name
60
46
  stub_method_owner.send(:define_method, method_name) do |*args, &block|
61
- self_in_scope.mock.method_missing(method_name_in_scope, *args, &block)
47
+ self_in_scope.mock.handle_method_call(method_name_in_scope, args, block)
62
48
  end
49
+ stub_method_owner.send(:ruby2_keywords, method_name)
63
50
  retain_original_visibility(stub_method_owner)
64
51
  end
65
52
 
@@ -67,18 +54,6 @@ module Mocha
67
54
  stub_method_owner.send(:remove_method, method_name)
68
55
  end
69
56
 
70
- def store_original_method
71
- @original_method = stubbee_method(method_name)
72
- end
73
-
74
- def restore_original_method
75
- return if use_prepended_module_for_stub_method?
76
- if stub_method_overwrites_original_method?
77
- original_method_owner.send(:define_method, method_name, method_body(@original_method))
78
- end
79
- retain_original_visibility(original_method_owner)
80
- end
81
-
82
57
  def matches?(other)
83
58
  return false unless other.class == self.class
84
59
  (stubbee.object_id == other.stubbee.object_id) && (method_name == other.method_name)
@@ -101,18 +76,6 @@ module Mocha
101
76
  @original_visibility = original_method_owner.__method_visibility__(method_name)
102
77
  end
103
78
 
104
- def stub_method_overwrites_original_method?
105
- @original_method && @original_method.owner == original_method_owner
106
- end
107
-
108
- def remove_original_method_from_stubbee
109
- original_method_owner.send(:remove_method, method_name)
110
- end
111
-
112
- def use_prepended_module_for_stub_method?
113
- RUBY_V2_PLUS
114
- end
115
-
116
79
  def use_prepended_module_for_stub_method
117
80
  @stub_method_owner = PrependedModule.new
118
81
  original_method_owner.__send__ :prepend, @stub_method_owner
@@ -1,8 +1,6 @@
1
+ require 'mocha/ruby_version'
1
2
  require 'mocha/integration/test_unit'
2
- require 'mocha/deprecation'
3
3
 
4
4
  unless Mocha::Integration::TestUnit.activate
5
- Mocha::Deprecation.warning(
6
- "Test::Unit must be loaded *before* `require 'mocha/test_unit'`."
7
- )
5
+ raise "Test::Unit must be loaded *before* `require 'mocha/test_unit'`."
8
6
  end
data/lib/mocha/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mocha
2
- VERSION = '1.14.0'.freeze
2
+ VERSION = '2.0.0.alpha'.freeze
3
3
  end
data/lib/mocha.rb CHANGED
@@ -1,9 +1 @@
1
1
  require 'mocha/version'
2
- require 'mocha/ruby_version'
3
- require 'mocha/deprecation'
4
-
5
- if Mocha::PRE_RUBY_V19
6
- Mocha::Deprecation.warning(
7
- 'Versions of Ruby earlier than v1.9 will not be supported in future versions of Mocha.'
8
- )
9
- end
data/mocha.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.name = 'mocha'
7
7
  s.version = Mocha::VERSION
8
8
  s.licenses = ['MIT', 'BSD-2-Clause']
9
- s.required_ruby_version = '>= 1.8.7'
9
+ s.required_ruby_version = '>= 2.0'
10
10
 
11
11
  s.authors = ['James Mead']
12
12
  s.description = 'Mocking and stubbing library with JMock/SchMock syntax, which allows mocking and stubbing of methods on real (non-mock) classes.'