minitest 5.15.0 → 5.17.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: 0d7d16c7decb91ba01a888704bd527d1e5569454b444fe1b4e41a8a3a7db7406
4
- data.tar.gz: 1ee0d2823a94b63b8cd019198fe2ca20a5c3d9d7bf4918148bdfa543fb65945d
3
+ metadata.gz: 76379897c6c77174044638d17a95f50b1b2fddbfde053759d864d8b9b419984b
4
+ data.tar.gz: 7cdedb3e76825894a5577f2c639c541402e1955b1166221530e2937b6c605b81
5
5
  SHA512:
6
- metadata.gz: 933a300969aa30dc8f254952dd17f9975cb1f3aad9c10c96260394d088b76900273773374b5ed72731356f2b7f1cfeb131583ae943322250a60401e554e11f45
7
- data.tar.gz: 24a356e1d3c06e28d03860b4dca92d17b88979ebad6316fe97298207c58b29b0ae207657d0044a43ede1bf9a27ac43ca8c779e24fc9ca5ed4c920beca2eaf143
6
+ metadata.gz: 5bc0b4b036c2e07d3db6ace79c1d0e51d2aa5cac74a26174ec822f1f987882bffc0165650c86f168ee38b31e9f07d825730b20a1f13b704fc395a9a88a4d9060
7
+ data.tar.gz: e9bdf26bc5a327b72b7a1dbdf701f6cef70561b634a258f932c511f26e7f2886597a05cc4a964749ef16e32529ab6a0cb6d11601f2954c3830444d34c3fcb23b
checksums.yaml.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,66 @@
1
+ === 5.17.0 / 2022-12-31
2
+
3
+ * 1 minor enhancement:
4
+
5
+ * Refactor setup hooks into a SETUP_METHODS constant. (MSP-Greg)
6
+
7
+ * 3 bug fixes:
8
+
9
+ * Fix kwargs for Mock calls to delegator. (blowmage)
10
+ * Fix kwargs for expectations. (bobmazanec, blowmage)
11
+ * Remove check for .b method. (tenderlove)
12
+
13
+ === 5.16.3 / 2022-08-17
14
+
15
+ * 2 bug fixes:
16
+
17
+ * Fixed exception sanitization by removing TypeError restriction on rescue.
18
+ * Use A instead of deprecated TESTOPTS in rake test:slow. (davidstosik)
19
+
20
+ === 5.16.2 / 2022-07-03
21
+
22
+ * 4 bug fixes:
23
+
24
+ * Added MT_KWARGS_HACK kludge for stub to deal with ruby 2.7 kwargs nastiness. (tsugimoto)
25
+ * In #expect, pop Hash class from args if $MT_KWARGS_HACK. (casperisfine)
26
+ * In above scenario, set expected kwargs (as Objects) based on actual kwargs.
27
+ * Nuke ivars if exception fails to marshal twice (eg better_errors). (irphilli)
28
+
29
+ === 5.16.1 / 2022-06-20
30
+
31
+ * 2 bug fixes:
32
+
33
+ * Apparently adding real kwarg support to mocks/stubs broke some code. Fixed.
34
+ * Use `MT_KWARGS_HACK=1` to activate the kludgy kwargs support w/ caveats.
35
+ * Clarified some doco wrt the block on #stub.
36
+
37
+ === 5.16.0 / 2022-06-14
38
+
39
+ * 2 major enhancements:
40
+
41
+ * Added Minitest::TestTask.
42
+ * Dropping ruby 2.2 - 2.5. 2.6 is DTM soon too.
43
+
44
+ * 11 minor enhancements:
45
+
46
+ * Added --show-skips option to show skips at end of run but not require --verbose. (MSP-Greg)
47
+ * Added Minitest.seed, the random seed used by the run.
48
+ * Calling `srand Minitest.seed` before all shuffles to ensure determinism.
49
+ * Extended #stub to handle kwargs for both block and call args. (SampsonCrowley)
50
+ * Extended Mock#__call to display kwargs.
51
+ * Extended Mock#expect to record kwargs.
52
+ * Extended Mock#method_missing to take kwargs & compare them against expected.
53
+ * Mock#method_missing displays better errors on arity mismatch.
54
+ * Removed minor optimization removing empty suites before run.
55
+ * Simplified test randomization (test order will change even with fixed seed).
56
+ * assert_match now returns the MatchData on success. (Nakilon)
57
+
58
+ * 3 bug fixes:
59
+
60
+ * (Re)Fixed marshalling of exceptions, neutering them in 2 passes.
61
+ * Fixed more problems with rdoc.
62
+ * Had to patch up mock and stub to deal with <=2.7 kwargs oddities
63
+
1
64
  === 5.15.0 / 2021-12-14
2
65
 
3
66
  * 1 major enhancement:
data/Manifest.txt CHANGED
@@ -17,6 +17,7 @@ lib/minitest/pride.rb
17
17
  lib/minitest/pride_plugin.rb
18
18
  lib/minitest/spec.rb
19
19
  lib/minitest/test.rb
20
+ lib/minitest/test_task.rb
20
21
  lib/minitest/unit.rb
21
22
  test/minitest/metametameta.rb
22
23
  test/minitest/test_minitest_assertions.rb
@@ -25,3 +26,4 @@ test/minitest/test_minitest_mock.rb
25
26
  test/minitest/test_minitest_reporter.rb
26
27
  test/minitest/test_minitest_spec.rb
27
28
  test/minitest/test_minitest_test.rb
29
+ test/minitest/test_minitest_test_task.rb
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  home :: https://github.com/seattlerb/minitest
4
4
  bugs :: https://github.com/seattlerb/minitest/issues
5
- rdoc :: http://docs.seattlerb.org/minitest
5
+ rdoc :: https://docs.seattlerb.org/minitest
6
6
  vim :: https://github.com/sunaku/vim-ruby-minitest
7
7
  emacs:: https://github.com/arthurnn/minitest-emacs
8
8
 
@@ -70,6 +70,7 @@ extract-method refactorings still apply.
70
70
  * minitest/mock - a simple and clean mock/stub system.
71
71
  * minitest/benchmark - an awesome way to assert your algorithm's performance.
72
72
  * minitest/pride - show your pride in testing!
73
+ * minitest/test_task - a full-featured and clean rake task generator.
73
74
  * Incredibly small and fast runner, but no bells and whistles.
74
75
  * Written by squishy human beings. Software can never be perfect. We will all eventually die.
75
76
 
@@ -186,7 +187,7 @@ Output is tab-delimited to make it easy to paste into a spreadsheet.
186
187
  === Mocks
187
188
 
188
189
  Mocks and stubs defined using terminology by Fowler & Meszaros at
189
- http://www.martinfowler.com/bliki/TestDouble.html:
190
+ https://www.martinfowler.com/bliki/TestDouble.html:
190
191
 
191
192
  "Mocks are pre-programmed with expectations which form a specification
192
193
  of the calls they are expected to receive. They can throw an exception
@@ -237,7 +238,7 @@ an example of asserting that code inside a thread is run:
237
238
  === Stubs
238
239
 
239
240
  Mocks and stubs are defined using terminology by Fowler & Meszaros at
240
- http://www.martinfowler.com/bliki/TestDouble.html:
241
+ https://www.martinfowler.com/bliki/TestDouble.html:
241
242
 
242
243
  "Stubs provide canned answers to calls made during the test".
243
244
 
@@ -264,9 +265,8 @@ new non-existing method:
264
265
 
265
266
  === Running Your Tests
266
267
 
267
- Ideally, you'll use a rake task to run your tests, either piecemeal or
268
- all at once. Both rake and rails ship with rake tasks for running your
269
- tests. BUT! You don't have to:
268
+ Ideally, you'll use a rake task to run your tests (see below), either
269
+ piecemeal or all at once. BUT! You don't have to:
270
270
 
271
271
  % ruby -Ilib:test test/minitest/test_minitest_test.rb
272
272
  Run options: --seed 37685
@@ -294,18 +294,45 @@ provided via plugins. To see them, simply run with +--help+:
294
294
  -p, --pride Pride. Show your testing pride!
295
295
  -a, --autotest Connect to autotest server.
296
296
 
297
+ === Rake Tasks
298
+
297
299
  You can set up a rake task to run all your tests by adding this to your Rakefile:
298
300
 
299
- require "rake/testtask"
301
+ require "minitest/test_task"
302
+
303
+ Minitest::TestTask.create # named test, sensible defaults
300
304
 
301
- Rake::TestTask.new(:test) do |t|
305
+ # or more explicitly:
306
+
307
+ Minitest::TestTask.create(:test) do |t|
302
308
  t.libs << "test"
303
309
  t.libs << "lib"
304
- t.test_files = FileList["test/**/test_*.rb"]
310
+ t.warning = false
311
+ t.test_globs = ["test/**/*_test.rb"]
305
312
  end
306
313
 
307
314
  task :default => :test
308
315
 
316
+ Each of these will generate 4 tasks:
317
+
318
+ rake test :: Run the test suite.
319
+ rake test:cmd :: Print out the test command.
320
+ rake test:isolated :: Show which test files fail when run separately.
321
+ rake test:slow :: Show bottom 25 tests sorted by time.
322
+
323
+ === Rake Task Variables
324
+
325
+ There are a bunch of variables you can supply to rake to modify the run.
326
+
327
+ MT_LIB_EXTRAS :: Extra libs to dynamically override/inject for custom runs.
328
+ N :: -n: Tests to run (string or /regexp/).
329
+ X :: -x: Tests to exclude (string or /regexp/).
330
+ A :: Any extra arguments. Honors shell quoting.
331
+ MT_CPU :: How many threads to use for parallel test runs
332
+ SEED :: -s --seed Sets random seed.
333
+ TESTOPTS :: Deprecated, same as A
334
+ FILTER :: Deprecated, same as A
335
+
309
336
  == Writing Extensions
310
337
 
311
338
  To define a plugin, add a file named minitest/XXX_plugin.rb to your
@@ -380,37 +407,34 @@ Using our example above, here is how we might implement MyCI:
380
407
 
381
408
  Minitest is a dependency of rails, which until fairly recently had an
382
409
  overzealous backwards compatibility policy. As such, I'm stuck
383
- supporting versions of ruby that are long past EOL. Once rails 5.2 is
384
- dropped (hopefully April 2021), I get to drop a bunch of versions of
385
- ruby that I have to currently test against.
410
+ supporting versions of ruby that are long past EOL. Hopefully I'll be
411
+ able to support only current versions of ruby sometime in the near
412
+ future.
386
413
 
387
- (As of 2021-01-31)
414
+ (As of 2022-11-29)
388
415
 
389
416
  Current versions of rails: (https://endoflife.date/rails)
390
417
 
391
- | rails | min ruby | rec ruby | minitest | status |
392
- |-------+----------+----------+----------+----------|
393
- | 7.0 | >= 2.7 | 3.0 | >= 5.1 | Future |
394
- | 6.1 | >= 2.5 | 3.0 | >= 5.1 | Current |
395
- | 6.0 | >= 2.5 | 2.6 | >= 5.1 | Security |
396
- | 5.2 | >= 2.2.2 | 2.5 | ~> 5.1 | Security | EOL @railsconf 2021?
418
+ | rails | min ruby | rec ruby | minitest | status | EOL Date |
419
+ |-------+----------+----------+----------+----------+------------|
420
+ | 7.0 | >= 2.7 | 3.1 | >= 5.1 | Current | 2025-06-01?|
421
+ | 6.1 | >= 2.5 | 3.0 | >= 5.1 | Maint | 2024-06-01?|
422
+ | 6.0 | >= 2.5 | 2.6 | >= 5.1 | Security | 2023-06-01 |
423
+ | 5.2 | >= 2.2.2 | 2.5 | ~> 5.1 | EOL | 2022-06-01 |
397
424
 
398
425
  Current versions of ruby: (https://endoflife.date/ruby)
399
426
 
400
427
  | ruby | Status | EOL Date |
401
428
  |------+---------+------------|
402
- | 3.0 | Current | 2024-03-31 |
403
- | 2.7 | Maint | 2023-03-31 |
404
- | 2.6 | Maint* | 2022-03-31 |
429
+ | 3.1 | Current | 2025-12-25 |
430
+ | 3.0 | Maint | 2024-03-31 |
431
+ | 2.7 | Maint* | 2023-03-31 |
432
+ | 2.6 | EOL | 2022-03-31 |
405
433
  | 2.5 | EOL | 2021-03-31 |
406
- | 2.4 | EOL | 2020-03-31 |
407
- | 2.3 | EOL | 2019-03-31 |
408
- | 2.2 | EOL | 2018-03-31 |
409
434
 
410
435
  See also:
411
436
 
412
437
  * https://www.fastruby.io/blog/ruby/rails/versions/compatibility-table.html
413
- * https://jamesjeffersconsulting.com/ruby-rails-version-matrix/
414
438
 
415
439
  === How to test SimpleDelegates?
416
440
 
@@ -614,6 +638,7 @@ minitest-capistrano :: Assertions and expectations for testing
614
638
  Capistrano recipes.
615
639
  minitest-capybara :: Capybara matchers support for minitest unit and
616
640
  spec.
641
+ minitest-cc :: It provides minimal information about code coverage.
617
642
  minitest-chef-handler :: Run Minitest suites as Chef report handlers
618
643
  minitest-ci :: CI reporter plugin for Minitest.
619
644
  minitest-context :: Defines contexts for code reuse in Minitest
@@ -712,7 +737,7 @@ minitest-stub-const :: Stub constants for the duration of a block.
712
737
  minitest-tags :: Add tags for minitest.
713
738
  minitest-unordered :: Adds a new assertion to minitest for checking the
714
739
  contents of a collection, ignoring element order.
715
- minitest-vcr :: Automatic cassette managment with Minitest::Spec
740
+ minitest-vcr :: Automatic cassette management with Minitest::Spec
716
741
  and VCR.
717
742
  minitest_log :: Adds structured logging, data explication, and verdicts.
718
743
  minitest_owrapper :: Get tests results as a TestResult object.
@@ -726,6 +751,9 @@ rematch :: Declutter your test files from large hardcoded da
726
751
  and update them automatically when your code changes.
727
752
  rspec2minitest :: Easily translate any RSpec matchers to Minitest
728
753
  assertions and expectations.
754
+ stubberry :: Multiple stubbing 'berries', sweet and useful
755
+ stub helpers and assertions. ( stub_must,
756
+ assert_method_called, stubbing ORM objects by id )
729
757
 
730
758
  == Unknown Extensions:
731
759
 
@@ -751,7 +779,7 @@ Authors... Please send me a pull request with a description of your minitest ext
751
779
 
752
780
  == Minitest related goods
753
781
 
754
- * minitest/pride fabric: http://www.spoonflower.com/fabric/3928730-again-by-katie_allen
782
+ * minitest/pride fabric: https://www.spoonflower.com/fabric/3928730-again-by-katie_allen
755
783
 
756
784
  == REQUIREMENTS:
757
785
 
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ Hoe.spec "minitest" do
11
11
 
12
12
  license "MIT"
13
13
 
14
- require_ruby_version [">= 2.2", "< 4.0"]
14
+ require_ruby_version [">= 2.6", "< 4.0"]
15
15
  end
16
16
 
17
17
  desc "Find missing expectations"
@@ -293,6 +293,8 @@ module Minitest
293
293
  assert_respond_to matcher, :"=~"
294
294
  matcher = Regexp.new Regexp.escape matcher if String === matcher
295
295
  assert matcher =~ obj, msg
296
+
297
+ Regexp.last_match
296
298
  end
297
299
 
298
300
  ##
@@ -217,7 +217,7 @@ module Minitest
217
217
  ##
218
218
  # Takes an array of x/y pairs and calculates the general R^2 value.
219
219
  #
220
- # See: http://en.wikipedia.org/wiki/Coefficient_of_determination
220
+ # See: https://en.wikipedia.org/wiki/Coefficient_of_determination
221
221
 
222
222
  def fit_error xys
223
223
  y_bar = sigma(xys) { |_, y| y } / xys.size.to_f
@@ -232,7 +232,7 @@ module Minitest
232
232
  #
233
233
  # Takes x and y values and returns [a, b, r^2].
234
234
  #
235
- # See: http://mathworld.wolfram.com/LeastSquaresFittingExponential.html
235
+ # See: https://mathworld.wolfram.com/LeastSquaresFittingExponential.html
236
236
 
237
237
  def fit_exponential xs, ys
238
238
  n = xs.size
@@ -254,7 +254,7 @@ module Minitest
254
254
  #
255
255
  # Takes x and y values and returns [a, b, r^2].
256
256
  #
257
- # See: http://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html
257
+ # See: https://mathworld.wolfram.com/LeastSquaresFittingLogarithmic.html
258
258
 
259
259
  def fit_logarithmic xs, ys
260
260
  n = xs.size
@@ -276,7 +276,7 @@ module Minitest
276
276
  #
277
277
  # Takes x and y values and returns [a, b, r^2].
278
278
  #
279
- # See: http://mathworld.wolfram.com/LeastSquaresFitting.html
279
+ # See: https://mathworld.wolfram.com/LeastSquaresFitting.html
280
280
 
281
281
  def fit_linear xs, ys
282
282
  n = xs.size
@@ -298,7 +298,7 @@ module Minitest
298
298
  #
299
299
  # Takes x and y values and returns [a, b, r^2].
300
300
  #
301
- # See: http://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html
301
+ # See: https://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html
302
302
 
303
303
  def fit_power xs, ys
304
304
  n = xs.size
data/lib/minitest/mock.rb CHANGED
@@ -28,11 +28,19 @@ module Minitest # :nodoc:
28
28
  end
29
29
 
30
30
  overridden_methods.map(&:to_sym).each do |method_id|
31
- define_method method_id do |*args, &b|
31
+ define_method method_id do |*args, **kwargs, &b|
32
32
  if @expected_calls.key? method_id then
33
- method_missing(method_id, *args, &b)
33
+ if kwargs.empty? then # FIX: drop this after 2.7 dead
34
+ method_missing(method_id, *args, &b)
35
+ else
36
+ method_missing(method_id, *args, **kwargs, &b)
37
+ end
34
38
  else
35
- super(*args, &b)
39
+ if kwargs.empty? then # FIX: drop this after 2.7 dead
40
+ super(*args, &b)
41
+ else
42
+ super(*args, **kwargs, &b)
43
+ end
36
44
  end
37
45
  end
38
46
  end
@@ -43,9 +51,11 @@ module Minitest # :nodoc:
43
51
  @actual_calls = Hash.new { |calls, name| calls[name] = [] }
44
52
  end
45
53
 
54
+ @@KW_WARNED = false # :nodoc:
55
+
46
56
  ##
47
- # Expect that method +name+ is called, optionally with +args+ or a
48
- # +blk+, and returns +retval+.
57
+ # Expect that method +name+ is called, optionally with +args+ (and
58
+ # +kwargs+ or a +blk+, and returns +retval+.
49
59
  #
50
60
  # @mock.expect(:meaning_of_life, 42)
51
61
  # @mock.meaning_of_life # => 42
@@ -78,15 +88,31 @@ module Minitest # :nodoc:
78
88
  # @mock.ordinal_increment # => raises MockExpectationError "No more expects available for :ordinal_increment"
79
89
  #
80
90
 
81
- def expect name, retval, args = [], &blk
91
+ def expect name, retval, args = [], **kwargs, &blk
82
92
  name = name.to_sym
83
93
 
84
94
  if block_given?
85
95
  raise ArgumentError, "args ignored when block given" unless args.empty?
96
+ raise ArgumentError, "kwargs ignored when block given" unless kwargs.empty?
86
97
  @expected_calls[name] << { :retval => retval, :block => blk }
87
98
  else
88
99
  raise ArgumentError, "args must be an array" unless Array === args
89
- @expected_calls[name] << { :retval => retval, :args => args }
100
+
101
+ if ENV["MT_KWARGS_HAC\K"] && (Hash === args.last ||
102
+ Hash == args.last) then
103
+ if kwargs.empty? then
104
+ kwargs = args.pop
105
+ else
106
+ unless @@KW_WARNED then
107
+ from = caller.first
108
+ warn "Using MT_KWARGS_HAC\K yet passing kwargs. From #{from}"
109
+ @@KW_WARNED = true
110
+ end
111
+ end
112
+ end
113
+
114
+ @expected_calls[name] <<
115
+ { :retval => retval, :args => args, :kwargs => kwargs }
90
116
  end
91
117
  self
92
118
  end
@@ -94,7 +120,13 @@ module Minitest # :nodoc:
94
120
  def __call name, data # :nodoc:
95
121
  case data
96
122
  when Hash then
97
- "#{name}(#{data[:args].inspect[1..-2]}) => #{data[:retval].inspect}"
123
+ args = data[:args].inspect[1..-2]
124
+ kwargs = data[:kwargs]
125
+ if kwargs && !kwargs.empty? then
126
+ args << ", " unless args.empty?
127
+ args << kwargs.inspect[1..-2]
128
+ end
129
+ "#{name}(#{args}) => #{data[:retval].inspect}"
98
130
  else
99
131
  data.map { |d| __call name, d }.join ", "
100
132
  end
@@ -115,10 +147,14 @@ module Minitest # :nodoc:
115
147
  true
116
148
  end
117
149
 
118
- def method_missing sym, *args, &block # :nodoc:
150
+ def method_missing sym, *args, **kwargs, &block # :nodoc:
119
151
  unless @expected_calls.key?(sym) then
120
152
  if @delegator && @delegator.respond_to?(sym)
121
- return @delegator.public_send(sym, *args, &block)
153
+ if kwargs.empty? then # FIX: drop this after 2.7 dead
154
+ return @delegator.public_send(sym, *args, &block)
155
+ else
156
+ return @delegator.public_send(sym, *args, **kwargs, &block)
157
+ end
122
158
  else
123
159
  raise NoMethodError, "unmocked method %p, expected one of %p" %
124
160
  [sym, @expected_calls.keys.sort_by(&:to_s)]
@@ -129,26 +165,34 @@ module Minitest # :nodoc:
129
165
  expected_call = @expected_calls[sym][index]
130
166
 
131
167
  unless expected_call then
132
- raise MockExpectationError, "No more expects available for %p: %p" %
133
- [sym, args]
168
+ raise MockExpectationError, "No more expects available for %p: %p %p" %
169
+ [sym, args, kwargs]
134
170
  end
135
171
 
136
- expected_args, retval, val_block =
137
- expected_call.values_at(:args, :retval, :block)
172
+ expected_args, expected_kwargs, retval, val_block =
173
+ expected_call.values_at(:args, :kwargs, :retval, :block)
174
+
175
+ expected_kwargs = kwargs.map { |ak, av| [ak, Object] }.to_h if
176
+ Hash == expected_kwargs
138
177
 
139
178
  if val_block then
140
179
  # keep "verify" happy
141
180
  @actual_calls[sym] << expected_call
142
181
 
143
- raise MockExpectationError, "mocked method %p failed block w/ %p" %
144
- [sym, args] unless val_block.call(*args, &block)
182
+ raise MockExpectationError, "mocked method %p failed block w/ %p %p" %
183
+ [sym, args, kwargs] unless val_block.call(*args, **kwargs, &block)
145
184
 
146
185
  return retval
147
186
  end
148
187
 
149
188
  if expected_args.size != args.size then
150
- raise ArgumentError, "mocked method %p expects %d arguments, got %d" %
151
- [sym, expected_args.size, args.size]
189
+ raise ArgumentError, "mocked method %p expects %d arguments, got %p" %
190
+ [sym, expected_args.size, args]
191
+ end
192
+
193
+ if expected_kwargs.size != kwargs.size then
194
+ raise ArgumentError, "mocked method %p expects %d keyword arguments, got %p" %
195
+ [sym, expected_kwargs.size, kwargs]
152
196
  end
153
197
 
154
198
  zipped_args = expected_args.zip(args)
@@ -157,13 +201,33 @@ module Minitest # :nodoc:
157
201
  }
158
202
 
159
203
  unless fully_matched then
160
- raise MockExpectationError, "mocked method %p called with unexpected arguments %p" %
161
- [sym, args]
204
+ fmt = "mocked method %p called with unexpected arguments %p"
205
+ raise MockExpectationError, fmt % [sym, args]
206
+ end
207
+
208
+ unless expected_kwargs.keys.sort == kwargs.keys.sort then
209
+ fmt = "mocked method %p called with unexpected keywords %p vs %p"
210
+ raise MockExpectationError, fmt % [sym, expected_kwargs.keys, kwargs.keys]
211
+ end
212
+
213
+ zipped_kwargs = expected_kwargs.map { |ek, ev|
214
+ av = kwargs[ek]
215
+ [ek, [ev, av]]
216
+ }.to_h
217
+
218
+ fully_matched = zipped_kwargs.all? { |ek, (ev, av)|
219
+ ev === av or ev == av
220
+ }
221
+
222
+ unless fully_matched then
223
+ fmt = "mocked method %p called with unexpected keyword arguments %p vs %p"
224
+ raise MockExpectationError, fmt % [sym, expected_kwargs, kwargs]
162
225
  end
163
226
 
164
227
  @actual_calls[sym] << {
165
228
  :retval => retval,
166
- :args => zipped_args.map! { |mod, a| mod === a ? mod : a },
229
+ :args => zipped_args.map { |e, a| e === a ? e : a },
230
+ :kwargs => zipped_kwargs.map { |k, (e, a)| [k, e === a ? e : a] }.to_h,
167
231
  }
168
232
 
169
233
  retval
@@ -211,31 +275,50 @@ class Object
211
275
  # NOTE: keyword args in callables are NOT checked for correctness
212
276
  # against the existing method. Too many edge cases to be worth it.
213
277
 
214
- def stub name, val_or_callable, *block_args
278
+ def stub name, val_or_callable, *block_args, **block_kwargs, &block
215
279
  new_name = "__minitest_stub__#{name}"
216
280
 
217
281
  metaclass = class << self; self; end
218
282
 
219
283
  if respond_to? name and not methods.map(&:to_s).include? name.to_s then
220
- metaclass.send :define_method, name do |*args|
221
- super(*args)
284
+ metaclass.send :define_method, name do |*args, **kwargs|
285
+ super(*args, **kwargs)
222
286
  end
223
287
  end
224
288
 
225
289
  metaclass.send :alias_method, new_name, name
226
290
 
227
- metaclass.send :define_method, name do |*args, &blk|
228
- if val_or_callable.respond_to? :call then
229
- val_or_callable.call(*args, &blk)
230
- else
231
- blk.call(*block_args) if blk
232
- val_or_callable
291
+ if ENV["MT_KWARGS_HAC\K"] then
292
+ metaclass.send :define_method, name do |*args, &blk|
293
+ if val_or_callable.respond_to? :call then
294
+ val_or_callable.call(*args, &blk)
295
+ else
296
+ blk.call(*block_args, **block_kwargs) if blk
297
+ val_or_callable
298
+ end
299
+ end
300
+ else
301
+ metaclass.send :define_method, name do |*args, **kwargs, &blk|
302
+ if val_or_callable.respond_to? :call then
303
+ if kwargs.empty? then # FIX: drop this after 2.7 dead
304
+ val_or_callable.call(*args, &blk)
305
+ else
306
+ val_or_callable.call(*args, **kwargs, &blk)
307
+ end
308
+ else
309
+ if blk then
310
+ if block_kwargs.empty? then # FIX: drop this after 2.7 dead
311
+ blk.call(*block_args)
312
+ else
313
+ blk.call(*block_args, **block_kwargs)
314
+ end
315
+ end
316
+ val_or_callable
317
+ end
233
318
  end
234
319
  end
235
320
 
236
- metaclass.send(:ruby2_keywords, name) if metaclass.respond_to?(:ruby2_keywords, true)
237
-
238
- yield self
321
+ block[self]
239
322
  ensure
240
323
  metaclass.send :undef_method, name
241
324
  metaclass.send :alias_method, name, new_name
@@ -48,7 +48,7 @@ module Minitest
48
48
  def initialize io # :nodoc:
49
49
  @io = io
50
50
  # stolen from /System/Library/Perl/5.10.0/Term/ANSIColor.pm
51
- # also reference http://en.wikipedia.org/wiki/ANSI_escape_code
51
+ # also reference https://en.wikipedia.org/wiki/ANSI_escape_code
52
52
  @colors ||= (31..36).to_a
53
53
  @size = @colors.size
54
54
  @index = 0
data/lib/minitest/spec.rb CHANGED
@@ -6,6 +6,10 @@ class Module # :nodoc:
6
6
  dont_flip = false if block
7
7
  target_obj = block ? '_{obj.method}' : '_(obj)'
8
8
 
9
+ # https://eregon.me/blog/2021/02/13/correct-delegation-in-ruby-2-27-3.html
10
+ # Drop this when we can drop ruby 2.6 (aka after rails 6.1 EOL, ~2024-06)
11
+ kw_extra = "ruby2_keywords %p" % [new_name] if respond_to?(:ruby2_keywords, true)
12
+
9
13
  # warn "%-22p -> %p %p" % [meth, new_name, dont_flip]
10
14
  self.class_eval <<-EOM, __FILE__, __LINE__ + 1
11
15
  def #{new_name} *args
@@ -14,6 +18,7 @@ class Module # :nodoc:
14
18
  Kernel.warn "DEPRECATED: global use of #{new_name} from #\{where}. Use #{target_obj}.#{new_name} instead. This will fail in Minitest 6."
15
19
  Minitest::Expectation.new(self, Minitest::Spec.current).#{new_name}(*args)
16
20
  end
21
+ #{kw_extra}
17
22
  EOM
18
23
 
19
24
  Minitest::Expectation.class_eval <<-EOM, __FILE__, __LINE__ + 1
@@ -28,6 +33,7 @@ class Module # :nodoc:
28
33
  ctx.#{meth}(args.first, target, *args[1..-1])
29
34
  end
30
35
  end
36
+ #{kw_extra}
31
37
  EOM
32
38
  end
33
39
  end
@@ -66,7 +72,7 @@ module Kernel
66
72
  #
67
73
  # For some suggestions on how to improve your specs, try:
68
74
  #
69
- # http://betterspecs.org
75
+ # https://betterspecs.org
70
76
  #
71
77
  # but do note that several items there are debatable or specific to
72
78
  # rspec.