mocha 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4bd89c61177f213648b496bffa016c3546d6461da8552429560ff3f9804df4f
4
- data.tar.gz: df6603b30f57ea57f6ba3383fc80df02ce0d94b246c35dd97b3eed80e689e717
3
+ metadata.gz: a37edfad5feabba14a5fe1b5c1d9d7a7f367f412c73a464dc2d20404ad42fea0
4
+ data.tar.gz: de9748735df4300f10a724b1eb6309f5262138ac3bc85bb0adbe6a9e64d09ec5
5
5
  SHA512:
6
- metadata.gz: d3cb27ce0f13c163fb82a9ac9d3464ea3e0a2478a091033e1cb518a27db4dc4dad7ef16445a31cb363a31622b445413b132c7ffef29cc4b5c84183a7e951ec4d
7
- data.tar.gz: ee6377fe60777af55832a284086920a4e1eff54824440f5ab4e9aa03c89e232034f0b0ec89abf5627de60c97d4f6405093144f37ec96217b31ba41ea125fd79b
6
+ metadata.gz: b2b4635c867e2670144fe93b7b9f2822429fb3f9df7ad7242fb5242832cd775c392eb624dc45706fd5c4d55802a921381ce801bf1ccc3050c9ef912eb9641d07
7
+ data.tar.gz: 56a349f9e87ab72e3e1a34d006c02bfef4afdffdc22991c9b1cd450f65d644203fdbc73a7559990eca6dea7a25dbc3765364c02ad86560b5968f7cb75a72e3ec
data/.rubocop.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
3
  AllCops:
4
- TargetRubyVersion: 2.2 # closest to required_ruby_version of '>= 2.0'
4
+ TargetRubyVersion: 2.2 # closest to required_ruby_version of '>= 2.1'
5
5
 
6
6
  # Even the reference in the documentation suggests that you should prefer
7
7
  # `alias_method` vs `alias`, so I don't understand why that isn't the default.
data/.yardopts CHANGED
@@ -16,7 +16,7 @@ lib/mocha/expectation_error.rb
16
16
  lib/mocha/stubbing_error.rb
17
17
  lib/mocha/unexpected_invocation.rb
18
18
  lib/mocha/integration/test_unit/adapter.rb
19
- lib/mocha/integration/mini_test/adapter.rb
19
+ lib/mocha/integration/minitest/adapter.rb
20
20
  -
21
21
  RELEASE.md
22
22
  COPYING.md
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  * A Ruby library for [mocking](http://xunitpatterns.com/Mock%20Object.html) and [stubbing](http://xunitpatterns.com/Test%20Stub.html) - but deliberately not (yet) [faking](http://xunitpatterns.com/Fake%20Object.html) or [spying](http://xunitpatterns.com/Test%20Spy.html).
6
6
  * A unified, simple and readable syntax for both full & partial mocking.
7
- * Built-in support for MiniTest and Test::Unit.
7
+ * Built-in support for Minitest and Test::Unit.
8
8
  * Supported by many other test frameworks.
9
9
 
10
10
  ### Intended Usage
@@ -18,7 +18,7 @@ Install the latest version of the gem with the following command...
18
18
 
19
19
  $ gem install mocha
20
20
 
21
- Note: If you are intending to use Mocha with Test::Unit or MiniTest, you should only setup Mocha *after* loading the relevant test library...
21
+ Note: If you are intending to use Mocha with Test::Unit or Minitest, you should only setup Mocha *after* loading the relevant test library...
22
22
 
23
23
  ##### Test::Unit
24
24
 
@@ -29,12 +29,12 @@ require 'test/unit'
29
29
  require 'mocha/test_unit'
30
30
  ```
31
31
 
32
- ##### MiniTest
32
+ ##### Minitest
33
33
 
34
34
  ```ruby
35
35
  require 'rubygems'
36
36
  gem 'mocha'
37
- require 'minitest/unit'
37
+ require 'minitest/autorun'
38
38
  require 'mocha/minitest'
39
39
  ```
40
40
 
@@ -53,14 +53,14 @@ require 'test/unit'
53
53
  require 'mocha/test_unit'
54
54
  ```
55
55
 
56
- ##### MiniTest
56
+ ##### Minitest
57
57
 
58
58
  ```ruby
59
59
  # Gemfile
60
60
  gem 'mocha'
61
61
 
62
62
  # Elsewhere after Bundler has loaded gems e.g. after `require 'bundler/setup'`
63
- require 'minitest/unit'
63
+ require 'minitest/autorun'
64
64
  require 'mocha/minitest'
65
65
  ```
66
66
 
@@ -103,9 +103,9 @@ end
103
103
 
104
104
  If you're loading Mocha using Bundler within a Rails application, you should setup Mocha manually e.g. at the bottom of your `test_helper.rb`.
105
105
 
106
- ##### MiniTest
106
+ ##### Minitest
107
107
 
108
- Note that since Rails v4 (at least), `ActiveSupport::TestCase` has inherited from `Minitest::Test` or its earlier equivalents. Thus unless you are *explicitly* using Test::Unit, you are likely to be using MiniTest.
108
+ Note that since Rails v4 (at least), `ActiveSupport::TestCase` has inherited from `Minitest::Test` or its earlier equivalents. Thus unless you are *explicitly* using Test::Unit, you are likely to be using Minitest.
109
109
 
110
110
  ```ruby
111
111
  # Gemfile in Rails app
@@ -151,7 +151,7 @@ class MiscExampleTest < Test::Unit::TestCase
151
151
  end
152
152
 
153
153
  def test_stubbing_instance_methods_on_real_objects
154
- prices = [stub(:pence => 1000), stub(:pence => 2000)]
154
+ prices = [stub(pence: 1000), stub(pence: 2000)]
155
155
  product = Product.new
156
156
  product.stubs(:prices).returns(prices)
157
157
  assert_equal [1000, 2000], product.prices.collect {|p| p.pence}
@@ -170,7 +170,7 @@ class MiscExampleTest < Test::Unit::TestCase
170
170
  end
171
171
 
172
172
  def test_shortcuts
173
- object = stub(:method1 => :result1, :method2 => :result2)
173
+ object = stub(method1: :result1, method2: :result2)
174
174
  assert_equal :result1, object.method1
175
175
  assert_equal :result2, object.method2
176
176
  end
data/RELEASE.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Release Notes
2
2
 
3
+ ## 2.2.0
4
+
5
+ ### External changes
6
+
7
+ * Support multiple methods in `responds_with` matcher (f086b7e4, #578) - thanks to @vlad-pisanov for the suggestion
8
+ * Add block syntax for sequences (93fdffd, #61)
9
+ * Improve sequence failure message (0800c6ff, #60)
10
+ * Drop support for Ruby v2.0 (85848fb0, #642)
11
+ * Include the original test name in expired stub error messages (ca3ff8eb, #641, #642) - thanks to @casperisfine
12
+
13
+ * Avoid rubocop directive ending up in YARD docs (2a9ee81a)
14
+ * Update docs to fix those for `Mock#method_missing` (cee0bad6)
15
+ * Reinstate missing CNAME for GitHub Pages site (da67bb0d)
16
+ * Use Ruby v1.9 Hash syntax in docs (6de20726, #625)
17
+ * Add missing YARD tag for API#sequence name param (343c5979)
18
+ * Add missing YARD tag for API#states name param (f798df83)
19
+
20
+ ### Internal changes
21
+
22
+ * Tidy up Minitest vs MiniTest references (#626, #614, #615) - thanks to @zenspider & @Maimer for their help
23
+ * Add Ruby v3.3 to CI build matrix (ce31b544)
24
+
3
25
  ## 2.1.0
4
26
 
5
27
  ### External changes
data/Rakefile CHANGED
@@ -42,10 +42,10 @@ namespace 'test' do # rubocop:disable Metrics/BlockLength
42
42
  end
43
43
 
44
44
  namespace 'integration' do
45
- desc 'Run MiniTest integration tests (intended to be run in its own process)'
45
+ desc 'Run Minitest integration tests (intended to be run in its own process)'
46
46
  Rake::TestTask.new('minitest') do |t|
47
47
  t.libs << 'test'
48
- t.test_files = FileList['test/integration/mini_test_test.rb']
48
+ t.test_files = FileList['test/integration/minitest_test.rb']
49
49
  t.verbose = true
50
50
  t.warning = true
51
51
  end
@@ -93,18 +93,18 @@ end
93
93
  # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
94
94
  def benchmark_test_case(klass, iterations)
95
95
  require 'benchmark'
96
- require 'mocha/detection/mini_test'
96
+ require 'mocha/detection/minitest'
97
97
 
98
- if defined?(MiniTest)
99
- minitest_version = Gem::Version.new(Mocha::Detection::MiniTest.version)
98
+ if defined?(Minitest)
99
+ minitest_version = Gem::Version.new(Mocha::Detection::Minitest.version)
100
100
  if Gem::Requirement.new('>= 5.0.0').satisfied_by?(minitest_version)
101
101
  Minitest.seed = 1
102
- result = Benchmark.realtime { iterations.times { |_i| klass.run(MiniTest::CompositeReporter.new) } }
103
- MiniTest::Runnable.runnables.delete(klass)
102
+ result = Benchmark.realtime { iterations.times { |_i| klass.run(Minitest::CompositeReporter.new) } }
103
+ Minitest::Runnable.runnables.delete(klass)
104
104
  result
105
105
  else
106
- MiniTest::Unit.output = StringIO.new
107
- Benchmark.realtime { iterations.times { |_i| MiniTest::Unit.new.run([klass]) } }
106
+ Minitest::Unit.output = StringIO.new
107
+ Benchmark.realtime { iterations.times { |_i| Minitest::Unit.new.run([klass]) } }
108
108
  end
109
109
  else
110
110
  load 'test/unit/ui/console/testrunner.rb' unless defined?(Test::Unit::UI::Console::TestRunner)
data/lib/mocha/api.rb CHANGED
@@ -7,7 +7,7 @@ require 'mocha/object_methods'
7
7
  require 'mocha/class_methods'
8
8
 
9
9
  module Mocha
10
- # Methods added to +Test::Unit::TestCase+, +MiniTest::Unit::TestCase+ or equivalent.
10
+ # Methods added to +Test::Unit::TestCase+, +Minitest::Unit::TestCase+ or equivalent.
11
11
  # The mock creation methods are {#mock}, {#stub} and {#stub_everything}, all of which return a #{Mock}
12
12
  # which can be further modified by {Mock#responds_like} and {Mock#responds_like_instance_of} methods,
13
13
  # both of which return a {Mock}, too, and can therefore, be chained to the original creation methods.
@@ -60,7 +60,7 @@ module Mocha
60
60
  #
61
61
  # @example Using expected_methods_vs_return_values Hash to setup expectations.
62
62
  # def test_motor_starts_and_stops
63
- # motor = mock('motor', :start => true, :stop => true)
63
+ # motor = mock('motor', start: true, stop: true)
64
64
  # assert motor.start
65
65
  # assert motor.stop
66
66
  # # an error will be raised unless both Motor#start and Motor#stop have been called
@@ -88,7 +88,7 @@ module Mocha
88
88
  #
89
89
  # @example Using stubbed_methods_vs_return_values Hash to setup stubbed methods.
90
90
  # def test_motor_starts_and_stops
91
- # motor = stub('motor', :start => true, :stop => true)
91
+ # motor = stub('motor', start: true, stop: true)
92
92
  # assert motor.start
93
93
  # assert motor.stop
94
94
  # # an error will not be raised even if either Motor#start or Motor#stop has not been called
@@ -115,7 +115,7 @@ module Mocha
115
115
  #
116
116
  # @example Ignore invocations of irrelevant methods.
117
117
  # def test_motor_stops
118
- # motor = stub_everything('motor', :stop => true)
118
+ # motor = stub_everything('motor', stop: true)
119
119
  # assert_nil motor.irrelevant_method_1 # => no error raised
120
120
  # assert_nil motor.irrelevant_method_2 # => no error raised
121
121
  # assert motor.stop
@@ -131,8 +131,11 @@ module Mocha
131
131
 
132
132
  # Builds a new sequence which can be used to constrain the order in which expectations can occur.
133
133
  #
134
- # Specify that an expected invocation must occur within a named {Sequence} by using {Expectation#in_sequence}.
134
+ # Specify that an expected invocation must occur within a named {Sequence} by calling {Expectation#in_sequence}
135
+ # on each expectation or by passing a block within which all expectations should be constrained by the {Sequence}.
135
136
  #
137
+ # @param [String] name name of sequence
138
+ # @yield optional block within which expectations should be constrained by the sequence
136
139
  # @return [Sequence] a new sequence
137
140
  #
138
141
  # @see Expectation#in_sequence
@@ -156,8 +159,23 @@ module Mocha
156
159
  #
157
160
  # task_one.execute
158
161
  # task_two.execute
162
+ #
163
+ # @example Ensure methods on egg are invoked in the correct order using a block.
164
+ # egg = mock('egg')
165
+ # sequence('breakfast') do
166
+ # egg.expects(:crack)
167
+ # egg.expects(:fry)
168
+ # egg.expects(:eat)
169
+ # end
159
170
  def sequence(name)
160
- Sequence.new(name)
171
+ Sequence.new(name).tap do |seq|
172
+ Mockery.instance.sequences.push(seq)
173
+ begin
174
+ yield if block_given?
175
+ ensure
176
+ Mockery.instance.sequences.pop
177
+ end
178
+ end
161
179
  end
162
180
 
163
181
  # Builds a new state machine which can be used to constrain the order in which expectations can occur.
@@ -170,6 +188,7 @@ module Mocha
170
188
  #
171
189
  # A test can contain multiple state machines.
172
190
  #
191
+ # @param [String] name name of state machine
173
192
  # @return [StateMachine] a new state machine
174
193
  #
175
194
  # @see Expectation#then
@@ -1,17 +1,17 @@
1
1
  module Mocha
2
2
  module Detection
3
- module MiniTest
3
+ module Minitest
4
4
  def self.testcase
5
5
  if defined?(::Minitest::Test)
6
6
  ::Minitest::Test
7
- elsif defined?(::MiniTest::Unit::TestCase)
8
- ::MiniTest::Unit::TestCase
7
+ elsif defined?(::Minitest::Unit::TestCase)
8
+ ::Minitest::Unit::TestCase
9
9
  end
10
10
  end
11
11
 
12
12
  def self.version
13
- if defined?(::MiniTest::Unit::VERSION)
14
- ::MiniTest::Unit::VERSION
13
+ if defined?(::Minitest::Unit::VERSION)
14
+ ::Minitest::Unit::VERSION
15
15
  elsif defined?(::Minitest::VERSION)
16
16
  ::Minitest::VERSION
17
17
  else
@@ -3,8 +3,8 @@ module Mocha
3
3
  module TestUnit
4
4
  def self.testcase
5
5
  if defined?(::Test::Unit::TestCase) &&
6
- !(defined?(::MiniTest::Unit::TestCase) && (::Test::Unit::TestCase < ::MiniTest::Unit::TestCase)) &&
7
- !(defined?(::MiniTest::Spec) && (::Test::Unit::TestCase < ::MiniTest::Spec))
6
+ !(defined?(::Minitest::Unit::TestCase) && (::Test::Unit::TestCase < ::Minitest::Unit::TestCase)) &&
7
+ !(defined?(::Minitest::Spec) && (::Test::Unit::TestCase < ::Minitest::Spec))
8
8
  ::Test::Unit::TestCase
9
9
  end
10
10
  end
@@ -632,14 +632,20 @@ module Mocha
632
632
  @ordering_constraints.all?(&:allows_invocation_now?)
633
633
  end
634
634
 
635
+ # @private
636
+ def ordering_constraints_not_allowing_invocation_now
637
+ @ordering_constraints.reject(&:allows_invocation_now?)
638
+ end
639
+
635
640
  # @private
636
641
  def matches_method?(method_name)
637
642
  @method_matcher.match?(method_name)
638
643
  end
639
644
 
640
645
  # @private
641
- def match?(invocation)
642
- @method_matcher.match?(invocation.method_name) && @parameters_matcher.match?(invocation.arguments) && @block_matcher.match?(invocation.block) && in_correct_order?
646
+ def match?(invocation, ignoring_order: false)
647
+ order_independent_match = @method_matcher.match?(invocation.method_name) && @parameters_matcher.match?(invocation.arguments) && @block_matcher.match?(invocation.block)
648
+ ignoring_order ? order_independent_match : order_independent_match && in_correct_order?
643
649
  end
644
650
 
645
651
  # @private
@@ -6,9 +6,9 @@ module Mocha
6
6
  #
7
7
  # This class should only be used by authors of test libraries and not by typical "users" of Mocha.
8
8
  #
9
- # For example, it is used by +Mocha::Integration::MiniTest::Adapter+ in order to have Mocha raise a +MiniTest::Assertion+ which can then be sensibly handled by +MiniTest::Unit::TestCase+.
9
+ # For example, it is used by +Mocha::Integration::Minitest::Adapter+ in order to have Mocha raise a +Minitest::Assertion+ which can then be sensibly handled by +Minitest::Unit::TestCase+.
10
10
  #
11
- # @see Mocha::Integration::MiniTest::Adapter
11
+ # @see Mocha::Integration::Minitest::Adapter
12
12
  class ExpectationErrorFactory
13
13
  class << self
14
14
  # @!attribute exception_class
@@ -17,7 +17,11 @@ module Mocha
17
17
  @expectations.any? { |expectation| expectation.matches_method?(method_name) }
18
18
  end
19
19
 
20
- def match(invocation)
20
+ def match(invocation, ignoring_order: false)
21
+ matching_expectations(invocation, ignoring_order: ignoring_order).first
22
+ end
23
+
24
+ def match_but_out_of_order(invocation)
21
25
  matching_expectations(invocation).first
22
26
  end
23
27
 
@@ -51,8 +55,8 @@ module Mocha
51
55
 
52
56
  private
53
57
 
54
- def matching_expectations(invocation)
55
- @expectations.select { |e| e.match?(invocation) }
58
+ def matching_expectations(invocation, ignoring_order: false)
59
+ @expectations.select { |e| e.match?(invocation, ignoring_order: ignoring_order) }
56
60
  end
57
61
  end
58
62
  end
data/lib/mocha/hooks.rb CHANGED
@@ -7,12 +7,12 @@ module Mocha
7
7
  #
8
8
  # This module is provided as part of the +Mocha::API+ module and is therefore part of the public API, but should only be used by authors of test libraries and not by typical "users" of Mocha.
9
9
  #
10
- # Integration with Test::Unit and MiniTest are provided as part of Mocha, because they are (or were once) part of the Ruby standard library. Integration with other test libraries is not provided as *part* of Mocha, but is supported by means of the methods in this module.
10
+ # Integration with Test::Unit and Minitest are provided as part of Mocha, because they are (or were once) part of the Ruby standard library. Integration with other test libraries is not provided as *part* of Mocha, but is supported by means of the methods in this module.
11
11
  #
12
12
  # See the code in the +Adapter+ modules for examples of how to use the methods in this module. +Mocha::ExpectationErrorFactory+ may be used if you want +Mocha+ to raise a different type of exception.
13
13
  #
14
14
  # @see Mocha::Integration::TestUnit::Adapter
15
- # @see Mocha::Integration::MiniTest::Adapter
15
+ # @see Mocha::Integration::Minitest::Adapter
16
16
  # @see Mocha::ExpectationErrorFactory
17
17
  # @see Mocha::API
18
18
  module Hooks
@@ -35,8 +35,14 @@ module Mocha
35
35
  # Resets Mocha after a test (only for use by authors of test libraries).
36
36
  #
37
37
  # This method should be called after each individual test has finished (including after any "teardown" code).
38
- def mocha_teardown
39
- Mockery.teardown
38
+ def mocha_teardown(origin = mocha_test_name)
39
+ Mockery.teardown(origin)
40
+ end
41
+
42
+ # Returns a string representing the unit test name, to be included in some Mocha
43
+ # to help track down potential bugs.
44
+ def mocha_test_name
45
+ nil
40
46
  end
41
47
  end
42
48
  end
@@ -4,21 +4,21 @@ require 'mocha/expectation_error_factory'
4
4
 
5
5
  module Mocha
6
6
  module Integration
7
- module MiniTest
8
- # Integrates Mocha into recent versions of MiniTest.
7
+ module Minitest
8
+ # Integrates Mocha into recent versions of Minitest.
9
9
  #
10
10
  # See the source code for an example of how to integrate Mocha into a test library.
11
11
  module Adapter
12
12
  include Mocha::API
13
13
 
14
14
  # @private
15
- def self.applicable_to?(mini_test_version)
16
- Gem::Requirement.new('>= 3.3.0').satisfied_by?(mini_test_version)
15
+ def self.applicable_to?(minitest_version)
16
+ Gem::Requirement.new('>= 3.3.0').satisfied_by?(minitest_version)
17
17
  end
18
18
 
19
19
  # @private
20
20
  def self.description
21
- 'adapter for MiniTest gem >= v3.3.0'
21
+ 'adapter for Minitest gem >= v3.3.0'
22
22
  end
23
23
 
24
24
  # @private
@@ -46,6 +46,21 @@ module Mocha
46
46
  super
47
47
  mocha_teardown
48
48
  end
49
+
50
+ # @private
51
+ def mocha_test_name
52
+ if respond_to?(:name)
53
+ test_name = name
54
+ elsif respond_to?(:__name__) # Older minitest
55
+ test_name = __name__
56
+ end
57
+
58
+ if test_name
59
+ "#{self.class.name}##{test_name}"
60
+ else
61
+ self.class.name
62
+ end
63
+ end
49
64
  end
50
65
  end
51
66
  end
@@ -2,10 +2,10 @@ require 'mocha/expectation_error'
2
2
 
3
3
  module Mocha
4
4
  module Integration
5
- module MiniTest
5
+ module Minitest
6
6
  def self.translate(exception)
7
7
  return exception unless exception.is_a?(::Mocha::ExpectationError)
8
- translated_exception = ::MiniTest::Assertion.new(exception.message)
8
+ translated_exception = ::Minitest::Assertion.new(exception.message)
9
9
  translated_exception.set_backtrace(exception.backtrace)
10
10
  translated_exception
11
11
  end
@@ -0,0 +1,28 @@
1
+ require 'mocha/debug'
2
+ require 'mocha/detection/minitest'
3
+ require 'mocha/integration/minitest/adapter'
4
+
5
+ module Mocha
6
+ module Integration
7
+ module Minitest
8
+ def self.activate
9
+ target = Detection::Minitest.testcase
10
+ return false unless target
11
+
12
+ minitest_version = Gem::Version.new(Detection::Minitest.version)
13
+ Debug.puts "Detected Minitest version: #{minitest_version}"
14
+
15
+ unless Minitest::Adapter.applicable_to?(minitest_version)
16
+ raise 'Versions of minitest earlier than v3.3.0 are not supported.'
17
+ end
18
+
19
+ unless target < Minitest::Adapter
20
+ Debug.puts "Applying #{Minitest::Adapter.description}"
21
+ target.send(:include, Minitest::Adapter)
22
+ end
23
+
24
+ true
25
+ end
26
+ end
27
+ end
28
+ end
@@ -37,6 +37,11 @@ module Mocha
37
37
 
38
38
  private
39
39
 
40
+ # @private
41
+ def mocha_test_name
42
+ name
43
+ end
44
+
40
45
  # @private
41
46
  def handle_mocha_expectation_error(exception)
42
47
  return false unless exception.is_a?(Mocha::ExpectationError)
@@ -1,6 +1,6 @@
1
1
  require 'mocha/ruby_version'
2
- require 'mocha/integration/mini_test'
2
+ require 'mocha/integration/minitest'
3
3
 
4
- unless Mocha::Integration::MiniTest.activate
5
- raise "MiniTest must be loaded *before* `require 'mocha/minitest'`."
4
+ unless Mocha::Integration::Minitest.activate
5
+ raise "Minitest must be loaded *before* `require 'mocha/minitest'`."
6
6
  end
data/lib/mocha/mock.rb CHANGED
@@ -100,7 +100,7 @@ module Mocha
100
100
  #
101
101
  # @example Setup multiple expectations using +expected_methods_vs_return_values+.
102
102
  # object = mock()
103
- # object.expects(:expected_method_one => :result_one, :expected_method_two => :result_two)
103
+ # object.expects(expected_method_one: :result_one, expected_method_two: :result_two)
104
104
  #
105
105
  # # is exactly equivalent to
106
106
  #
@@ -114,6 +114,7 @@ module Mocha
114
114
  method_name = args.shift
115
115
  ensure_method_not_already_defined(method_name)
116
116
  expectation = Expectation.new(self, method_name, backtrace)
117
+ expectation.in_sequence(@mockery.sequences.last) if @mockery.sequences.any?
117
118
  expectation.returns(args.shift) unless args.empty?
118
119
  @expectations.add(expectation)
119
120
  end
@@ -138,7 +139,7 @@ module Mocha
138
139
  #
139
140
  # @example Setup multiple expectations using +stubbed_methods_vs_return_values+.
140
141
  # object = mock()
141
- # object.stubs(:stubbed_method_one => :result_one, :stubbed_method_two => :result_two)
142
+ # object.stubs(stubbed_method_one: :result_one, stubbed_method_two: :result_two)
142
143
  #
143
144
  # # is exactly equivalent to
144
145
  #
@@ -153,6 +154,7 @@ module Mocha
153
154
  ensure_method_not_already_defined(method_name)
154
155
  expectation = Expectation.new(self, method_name, backtrace)
155
156
  expectation.at_least(0)
157
+ expectation.in_sequence(@mockery.sequences.last) if @mockery.sequences.any?
156
158
  expectation.returns(args.shift) unless args.empty?
157
159
  @expectations.add(expectation)
158
160
  end
@@ -309,12 +311,10 @@ module Mocha
309
311
  end
310
312
 
311
313
  # @private
312
- # rubocop:disable Style/MethodMissingSuper
313
- def method_missing(symbol, *arguments, &block)
314
+ def method_missing(symbol, *arguments, &block) # rubocop:disable Style/MethodMissingSuper
314
315
  handle_method_call(symbol, arguments, block)
315
316
  end
316
317
  ruby2_keywords(:method_missing)
317
- # rubocop:enable Style/MethodMissingSuper
318
318
 
319
319
  # @private
320
320
  def handle_method_call(symbol, arguments, block)
@@ -323,7 +323,7 @@ module Mocha
323
323
  invocation = Invocation.new(self, symbol, arguments, block)
324
324
  if (matching_expectation_allowing_invocation = all_expectations.match_allowing_invocation(invocation))
325
325
  matching_expectation_allowing_invocation.invoke(invocation)
326
- elsif (matching_expectation = all_expectations.match(invocation)) || (!matching_expectation && !@everything_stubbed)
326
+ elsif (matching_expectation = all_expectations.match(invocation, ignoring_order: true)) || (!matching_expectation && !@everything_stubbed)
327
327
  raise_unexpected_invocation_error(invocation, matching_expectation)
328
328
  end
329
329
  end
@@ -343,8 +343,8 @@ module Mocha
343
343
  end
344
344
 
345
345
  # @private
346
- def __expire__
347
- @expired = true
346
+ def __expire__(origin)
347
+ @expired = origin || true
348
348
  end
349
349
 
350
350
  # @private
@@ -373,7 +373,11 @@ module Mocha
373
373
  if @unexpected_invocation.nil?
374
374
  @unexpected_invocation = invocation
375
375
  matching_expectation.invoke(invocation) if matching_expectation
376
- message = "#{@unexpected_invocation.call_description}\n#{@mockery.mocha_inspect}"
376
+ call_description = @unexpected_invocation.call_description
377
+ if matching_expectation && !matching_expectation.in_correct_order?
378
+ call_description += ' invoked out of order'
379
+ end
380
+ message = "#{call_description}\n#{@mockery.mocha_inspect}"
377
381
  else
378
382
  message = @unexpected_invocation.short_call_description
379
383
  end
@@ -389,8 +393,10 @@ module Mocha
389
393
  def check_expiry
390
394
  return unless @expired
391
395
 
396
+ origin = @expired == true ? 'one test' : @expired
397
+
392
398
  sentences = [
393
- "#{mocha_inspect} was instantiated in one test but it is receiving invocations within another test.",
399
+ "#{mocha_inspect} was instantiated in #{origin} but it is receiving invocations within another test.",
394
400
  'This can lead to unintended interactions between tests and hence unexpected test failures.',
395
401
  'Ensure that every test correctly cleans up any state that it introduces.'
396
402
  ]
data/lib/mocha/mockery.rb CHANGED
@@ -48,8 +48,8 @@ module Mocha
48
48
  instance.verify(*args)
49
49
  end
50
50
 
51
- def teardown
52
- instance.teardown
51
+ def teardown(origin = nil)
52
+ instance.teardown(origin)
53
53
  ensure
54
54
  @instances.pop
55
55
  end
@@ -91,9 +91,9 @@ module Mocha
91
91
  end
92
92
  end
93
93
 
94
- def teardown
94
+ def teardown(origin = nil)
95
95
  stubba.unstub_all
96
- mocks.each(&:__expire__)
96
+ mocks.each { |m| m.__expire__(origin) }
97
97
  reset
98
98
  end
99
99
 
@@ -109,6 +109,10 @@ module Mocha
109
109
  @state_machines ||= []
110
110
  end
111
111
 
112
+ def sequences
113
+ @sequences ||= []
114
+ end
115
+
112
116
  def mocha_inspect
113
117
  message = ''
114
118
  message << "unsatisfied expectations:\n- #{unsatisfied_expectations.map(&:mocha_inspect).join("\n- ")}\n" if unsatisfied_expectations.any?
@@ -59,7 +59,7 @@ module Mocha
59
59
  #
60
60
  # @example Setting up multiple expectations on a non-mock object.
61
61
  # product = Product.new
62
- # product.expects(:valid? => true, :save => true)
62
+ # product.expects(valid?: true, save: true)
63
63
  #
64
64
  # # exactly equivalent to
65
65
  #
@@ -108,7 +108,7 @@ module Mocha
108
108
  #
109
109
  # @example Setting up multiple stubbed methods on a non-mock object.
110
110
  # product = Product.new
111
- # product.stubs(:valid? => true, :save => true)
111
+ # product.stubs(valid?: true, save: true)
112
112
  #
113
113
  # # exactly equivalent to
114
114
  #
@@ -21,12 +21,12 @@ module Mocha
21
21
  # @example Alternative ways to combine matchers with a logical AND.
22
22
  # object = mock()
23
23
  # object.expects(:run).with(all_of(has_key(:foo), has_key(:bar)))
24
- # object.run(:foo => 'foovalue', :bar => 'barvalue')
24
+ # object.run(foo: 'foovalue', bar: 'barvalue')
25
25
  #
26
26
  # # is exactly equivalent to
27
27
  #
28
28
  # object.expects(:run).with(has_key(:foo) & has_key(:bar))
29
- # object.run(:foo => 'foovalue', :bar => 'barvalue)
29
+ # object.run(foo: 'foovalue', bar: 'barvalue)
30
30
  def &(other)
31
31
  AllOf.new(self, other)
32
32
  end
@@ -45,12 +45,12 @@ module Mocha
45
45
  # @example Alternative ways to combine matchers with a logical OR.
46
46
  # object = mock()
47
47
  # object.expects(:run).with(any_of(has_key(:foo), has_key(:bar)))
48
- # object.run(:foo => 'foovalue')
48
+ # object.run(foo: 'foovalue')
49
49
  #
50
50
  # # is exactly equivalent to
51
51
  #
52
52
  # object.expects(:run).with(has_key(:foo) | has_key(:bar))
53
- # object.run(:foo => 'foovalue')
53
+ # object.run(foo: 'foovalue')
54
54
  #
55
55
  # @example Using an explicit {Equals} matcher in combination with {#|}.
56
56
  # object.expects(:run).with(equals(1) | equals(2))
@@ -24,7 +24,7 @@ module Mocha
24
24
  # @example Actual parameter includes item which matches nested matcher.
25
25
  # object = mock()
26
26
  # object.expects(:method_1).with(includes(has_key(:key)))
27
- # object.method_1(['foo', 'bar', {:key => 'baz'}])
27
+ # object.method_1(['foo', 'bar', {key: 'baz'}])
28
28
  # # no error raised
29
29
  #
30
30
  # @example Actual parameter does not include item matching nested matcher.
@@ -44,11 +44,11 @@ module Mocha
44
44
  # @example Actual parameter is a Hash including the given key.
45
45
  # object = mock()
46
46
  # object.expects(:method_1).with(includes(:bar))
47
- # object.method_1({:foo => 1, :bar => 2})
47
+ # object.method_1({foo: 1, bar: 2})
48
48
  # # no error raised
49
49
  #
50
50
  # @example Actual parameter is a Hash without the given key.
51
- # object.method_1({:foo => 1, :baz => 2})
51
+ # object.method_1({foo: 1, baz: 2})
52
52
  # # error raised, because hash does not include key 'bar'
53
53
  #
54
54
  # @example Actual parameter is a Hash with a key matching the given matcher.
@@ -1,12 +1,18 @@
1
1
  require 'mocha/parameter_matchers/base'
2
+ require 'mocha/parameter_matchers/all_of'
2
3
  require 'yaml'
3
4
 
4
5
  module Mocha
5
6
  module ParameterMatchers
6
- # Matches any object that responds to +message+ with +result+. To put it another way, it tests the quack, not the duck.
7
+ # @overload def responds_with(message, result)
8
+ # Matches any object that responds to +message+ with +result+. To put it another way, it tests the quack, not the duck.
9
+ # @param [Symbol] message method to invoke.
10
+ # @param [Object] result expected result of sending +message+.
11
+ # @overload def responds_with(messages_vs_results)
12
+ # Matches any object that responds to all the messages with the corresponding results as specified by +messages_vs_results+.
13
+ # @param [Hash<Symbol,Object>] messages_vs_results +Hash+ of messages vs results.
14
+ # @raise [ArgumentError] if +messages_vs_results+ does not contain at least one entry.
7
15
  #
8
- # @param [Symbol] message method to invoke.
9
- # @param [Object] result expected result of sending +message+.
10
16
  # @return [RespondsWith] parameter matcher.
11
17
  #
12
18
  # @see Expectation#with
@@ -22,8 +28,29 @@ module Mocha
22
28
  # object.expects(:method_1).with(responds_with(:upcase, "BAR"))
23
29
  # object.method_1("foo")
24
30
  # # error raised, because "foo".upcase != "BAR"
25
- def responds_with(message, result)
26
- RespondsWith.new(message, result)
31
+ #
32
+ # @example Actual parameter responds with "FOO" when :upcase is invoked and "oof" when :reverse is invoked.
33
+ # object = mock()
34
+ # object.expects(:method_1).with(responds_with(upcase: "FOO", reverse: "oof"))
35
+ # object.method_1("foo")
36
+ # # no error raised, because "foo".upcase == "FOO" and "foo".reverse == "oof"
37
+ def responds_with(*options)
38
+ case options.length
39
+ when 0
40
+ raise ArgumentError, 'No arguments. Expecting at least one.'
41
+ when 1
42
+ option = options.first
43
+ raise ArgumentError, 'Argument is not a Hash.' unless option.is_a?(Hash)
44
+ raise ArgumentError, 'Argument has no entries.' if option.empty?
45
+
46
+ matchers = option.map { |message, result| RespondsWith.new(message, result) }
47
+ AllOf.new(*matchers)
48
+ when 2
49
+ message, result = options
50
+ RespondsWith.new(message, result)
51
+ else
52
+ raise ArgumentError, 'Too many arguments; use either a single argument (must be a Hash) or two arguments (a message and a result).'
53
+ end
27
54
  end
28
55
 
29
56
  # Parameter matcher which matches if actual parameter returns expected result when specified method is invoked.
data/lib/mocha/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Mocha
2
- VERSION = '2.1.0'.freeze
2
+ VERSION = '2.2.0'.freeze
3
3
  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 = '>= 2.0'
9
+ s.required_ruby_version = '>= 2.1'
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.'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mocha
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Mead
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-27 00:00:00.000000000 Z
11
+ date: 2024-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby2_keywords
@@ -58,7 +58,7 @@ files:
58
58
  - lib/mocha/configuration.rb
59
59
  - lib/mocha/debug.rb
60
60
  - lib/mocha/deprecation.rb
61
- - lib/mocha/detection/mini_test.rb
61
+ - lib/mocha/detection/minitest.rb
62
62
  - lib/mocha/detection/test_unit.rb
63
63
  - lib/mocha/error_with_filtered_backtrace.rb
64
64
  - lib/mocha/exception_raiser.rb
@@ -71,9 +71,9 @@ files:
71
71
  - lib/mocha/inspect.rb
72
72
  - lib/mocha/instance_method.rb
73
73
  - lib/mocha/integration/assertion_counter.rb
74
- - lib/mocha/integration/mini_test.rb
75
- - lib/mocha/integration/mini_test/adapter.rb
76
- - lib/mocha/integration/mini_test/exception_translation.rb
74
+ - lib/mocha/integration/minitest.rb
75
+ - lib/mocha/integration/minitest/adapter.rb
76
+ - lib/mocha/integration/minitest/exception_translation.rb
77
77
  - lib/mocha/integration/monkey_patcher.rb
78
78
  - lib/mocha/integration/test_unit.rb
79
79
  - lib/mocha/integration/test_unit/adapter.rb
@@ -141,7 +141,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - ">="
143
143
  - !ruby/object:Gem::Version
144
- version: '2.0'
144
+ version: '2.1'
145
145
  required_rubygems_version: !ruby/object:Gem::Requirement
146
146
  requirements:
147
147
  - - ">="
@@ -1,28 +0,0 @@
1
- require 'mocha/debug'
2
- require 'mocha/detection/mini_test'
3
- require 'mocha/integration/mini_test/adapter'
4
-
5
- module Mocha
6
- module Integration
7
- module MiniTest
8
- def self.activate
9
- target = Detection::MiniTest.testcase
10
- return false unless target
11
-
12
- mini_test_version = Gem::Version.new(Detection::MiniTest.version)
13
- Debug.puts "Detected MiniTest version: #{mini_test_version}"
14
-
15
- unless MiniTest::Adapter.applicable_to?(mini_test_version)
16
- raise 'Versions of minitest earlier than v3.3.0 are not supported.'
17
- end
18
-
19
- unless target < MiniTest::Adapter
20
- Debug.puts "Applying #{MiniTest::Adapter.description}"
21
- target.send(:include, MiniTest::Adapter)
22
- end
23
-
24
- true
25
- end
26
- end
27
- end
28
- end