minitest 5.11.3 → 5.25.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.
data/lib/minitest/mock.rb CHANGED
@@ -8,9 +8,9 @@ module Minitest # :nodoc:
8
8
  # All mock objects are an instance of Mock
9
9
 
10
10
  class Mock
11
- alias :__respond_to? :respond_to?
11
+ alias __respond_to? respond_to?
12
12
 
13
- overridden_methods = %w[
13
+ overridden_methods = %i[
14
14
  ===
15
15
  class
16
16
  inspect
@@ -23,18 +23,31 @@ module Minitest # :nodoc:
23
23
  to_s
24
24
  ]
25
25
 
26
+ overridden_methods << :singleton_method_added if defined?(::DEBUGGER__)
27
+
26
28
  instance_methods.each do |m|
27
- undef_method m unless overridden_methods.include?(m.to_s) || m =~ /^__/
29
+ undef_method m unless overridden_methods.include?(m) || m =~ /^__/
28
30
  end
29
31
 
30
32
  overridden_methods.map(&:to_sym).each do |method_id|
31
- define_method method_id do |*args, &b|
33
+ old_w, $-w = $-w, nil
34
+ define_method method_id do |*args, **kwargs, &b|
32
35
  if @expected_calls.key? method_id then
33
- method_missing(method_id, *args, &b)
36
+ if kwargs.empty? then # FIX: drop this after 2.7 dead
37
+ method_missing(method_id, *args, &b)
38
+ else
39
+ method_missing(method_id, *args, **kwargs, &b)
40
+ end
34
41
  else
35
- super(*args, &b)
42
+ if kwargs.empty? then # FIX: drop this after 2.7 dead
43
+ super(*args, &b)
44
+ else
45
+ super(*args, **kwargs, &b)
46
+ end
36
47
  end
37
48
  end
49
+ ensure
50
+ $-w = old_w
38
51
  end
39
52
 
40
53
  def initialize delegator = nil # :nodoc:
@@ -43,9 +56,11 @@ module Minitest # :nodoc:
43
56
  @actual_calls = Hash.new { |calls, name| calls[name] = [] }
44
57
  end
45
58
 
59
+ @@KW_WARNED = false # :nodoc:
60
+
46
61
  ##
47
- # Expect that method +name+ is called, optionally with +args+ or a
48
- # +blk+, and returns +retval+.
62
+ # Expect that method +name+ is called, optionally with +args+ (and
63
+ # +kwargs+ or a +blk+), and returns +retval+.
49
64
  #
50
65
  # @mock.expect(:meaning_of_life, 42)
51
66
  # @mock.meaning_of_life # => 42
@@ -78,15 +93,31 @@ module Minitest # :nodoc:
78
93
  # @mock.ordinal_increment # => raises MockExpectationError "No more expects available for :ordinal_increment"
79
94
  #
80
95
 
81
- def expect name, retval, args = [], &blk
96
+ def expect name, retval, args = [], **kwargs, &blk
82
97
  name = name.to_sym
83
98
 
84
- if block_given?
99
+ if blk then
85
100
  raise ArgumentError, "args ignored when block given" unless args.empty?
101
+ raise ArgumentError, "kwargs ignored when block given" unless kwargs.empty?
86
102
  @expected_calls[name] << { :retval => retval, :block => blk }
87
103
  else
88
104
  raise ArgumentError, "args must be an array" unless Array === args
89
- @expected_calls[name] << { :retval => retval, :args => args }
105
+
106
+ if ENV["MT_KWARGS_HAC\K"] && (Hash === args.last ||
107
+ Hash == args.last) then
108
+ if kwargs.empty? then
109
+ kwargs = args.pop
110
+ else
111
+ unless @@KW_WARNED then
112
+ from = caller(1..1).first
113
+ warn "Using MT_KWARGS_HAC\K yet passing kwargs. From #{from}"
114
+ @@KW_WARNED = true
115
+ end
116
+ end
117
+ end
118
+
119
+ @expected_calls[name] <<
120
+ { :retval => retval, :args => args, :kwargs => kwargs }
90
121
  end
91
122
  self
92
123
  end
@@ -94,7 +125,13 @@ module Minitest # :nodoc:
94
125
  def __call name, data # :nodoc:
95
126
  case data
96
127
  when Hash then
97
- "#{name}(#{data[:args].inspect[1..-2]}) => #{data[:retval].inspect}"
128
+ args = data[:args].inspect[1..-2]
129
+ kwargs = data[:kwargs]
130
+ if kwargs && !kwargs.empty? then
131
+ args << ", " unless args.empty?
132
+ args << kwargs.inspect[1..-2]
133
+ end
134
+ "#{name}(#{args}) => #{data[:retval].inspect}"
98
135
  else
99
136
  data.map { |d| __call name, d }.join ", "
100
137
  end
@@ -107,18 +144,22 @@ module Minitest # :nodoc:
107
144
 
108
145
  def verify
109
146
  @expected_calls.each do |name, expected|
110
- actual = @actual_calls.fetch(name, nil)
111
- raise MockExpectationError, "expected #{__call name, expected[0]}" unless actual
112
- raise MockExpectationError, "expected #{__call name, expected[actual.size]}, got [#{__call name, actual}]" if
147
+ actual = @actual_calls.fetch name, nil # defaults to []
148
+ raise MockExpectationError, "Expected #{__call name, expected[0]}" unless actual
149
+ raise MockExpectationError, "Expected #{__call name, expected[actual.size]}, got [#{__call name, actual}]" if
113
150
  actual.size < expected.size
114
151
  end
115
152
  true
116
153
  end
117
154
 
118
- def method_missing sym, *args, &block # :nodoc:
119
- unless @expected_calls.key?(sym) then
155
+ def method_missing sym, *args, **kwargs, &block # :nodoc:
156
+ unless @expected_calls.key? sym then
120
157
  if @delegator && @delegator.respond_to?(sym)
121
- return @delegator.public_send(sym, *args, &block)
158
+ if kwargs.empty? then # FIX: drop this after 2.7 dead
159
+ return @delegator.public_send(sym, *args, &block)
160
+ else
161
+ return @delegator.public_send(sym, *args, **kwargs, &block)
162
+ end
122
163
  else
123
164
  raise NoMethodError, "unmocked method %p, expected one of %p" %
124
165
  [sym, @expected_calls.keys.sort_by(&:to_s)]
@@ -129,41 +170,69 @@ module Minitest # :nodoc:
129
170
  expected_call = @expected_calls[sym][index]
130
171
 
131
172
  unless expected_call then
132
- raise MockExpectationError, "No more expects available for %p: %p" %
133
- [sym, args]
173
+ raise MockExpectationError, "No more expects available for %p: %p %p" %
174
+ [sym, args, kwargs]
134
175
  end
135
176
 
136
- expected_args, retval, val_block =
137
- expected_call.values_at(:args, :retval, :block)
177
+ expected_args, expected_kwargs, retval, val_block =
178
+ expected_call.values_at :args, :kwargs, :retval, :block
179
+
180
+ expected_kwargs = kwargs.to_h { |ak, av| [ak, Object] } if
181
+ Hash == expected_kwargs
138
182
 
139
183
  if val_block then
140
184
  # keep "verify" happy
141
185
  @actual_calls[sym] << expected_call
142
186
 
143
- raise MockExpectationError, "mocked method %p failed block w/ %p" %
144
- [sym, args] unless val_block.call(*args, &block)
187
+ raise MockExpectationError, "mocked method %p failed block w/ %p %p" %
188
+ [sym, args, kwargs] unless val_block.call(*args, **kwargs, &block)
145
189
 
146
190
  return retval
147
191
  end
148
192
 
149
193
  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]
194
+ raise ArgumentError, "mocked method %p expects %d arguments, got %p" %
195
+ [sym, expected_args.size, args]
196
+ end
197
+
198
+ if expected_kwargs.size != kwargs.size then
199
+ raise ArgumentError, "mocked method %p expects %d keyword arguments, got %p" %
200
+ [sym, expected_kwargs.size, kwargs]
152
201
  end
153
202
 
154
- zipped_args = expected_args.zip(args)
203
+ zipped_args = expected_args.zip args
155
204
  fully_matched = zipped_args.all? { |mod, a|
156
205
  mod === a or mod == a
157
206
  }
158
207
 
159
208
  unless fully_matched then
160
- raise MockExpectationError, "mocked method %p called with unexpected arguments %p" %
161
- [sym, args]
209
+ fmt = "mocked method %p called with unexpected arguments %p"
210
+ raise MockExpectationError, fmt % [sym, args]
211
+ end
212
+
213
+ unless expected_kwargs.keys.sort == kwargs.keys.sort then
214
+ fmt = "mocked method %p called with unexpected keywords %p vs %p"
215
+ raise MockExpectationError, fmt % [sym, expected_kwargs.keys, kwargs.keys]
216
+ end
217
+
218
+ zipped_kwargs = expected_kwargs.to_h { |ek, ev|
219
+ av = kwargs[ek]
220
+ [ek, [ev, av]]
221
+ }
222
+
223
+ fully_matched = zipped_kwargs.all? { |ek, (ev, av)|
224
+ ev === av or ev == av
225
+ }
226
+
227
+ unless fully_matched then
228
+ fmt = "mocked method %p called with unexpected keyword arguments %p vs %p"
229
+ raise MockExpectationError, fmt % [sym, expected_kwargs, kwargs]
162
230
  end
163
231
 
164
232
  @actual_calls[sym] << {
165
233
  :retval => retval,
166
- :args => zipped_args.map! { |mod, a| mod === a ? mod : a },
234
+ :args => zipped_args.map { |e, a| e === a ? e : a },
235
+ :kwargs => zipped_kwargs.to_h { |k, (e, a)| [k, e === a ? e : a] },
167
236
  }
168
237
 
169
238
  retval
@@ -172,20 +241,35 @@ module Minitest # :nodoc:
172
241
  def respond_to? sym, include_private = false # :nodoc:
173
242
  return true if @expected_calls.key? sym.to_sym
174
243
  return true if @delegator && @delegator.respond_to?(sym, include_private)
175
- __respond_to?(sym, include_private)
244
+ __respond_to? sym, include_private
176
245
  end
177
246
  end
178
247
  end
179
248
 
180
249
  module Minitest::Assertions
181
250
  ##
182
- # Assert that the mock verifies correctly.
251
+ # Assert that the mock verifies correctly and fail if not.
183
252
 
184
- def assert_mock mock
253
+ def assert_mock mock, msg = nil
185
254
  assert mock.verify
255
+ rescue MockExpectationError => e
256
+ msg = message(msg) { e.message }
257
+ flunk msg
186
258
  end
187
259
  end
188
260
 
261
+ module Minitest::Expectations
262
+ ##
263
+ # See Minitest::Assertions#assert_mock.
264
+ #
265
+ # _(collection).must_verify
266
+ #
267
+ # :method: must_verify
268
+
269
+ infect_an_assertion :assert_mock, :must_verify, :unary if
270
+ defined?(infect_an_assertion)
271
+ end
272
+
189
273
  ##
190
274
  # Object extensions for Minitest::Mock.
191
275
 
@@ -207,31 +291,54 @@ class Object
207
291
  # assert obj_under_test.stale?
208
292
  # end
209
293
  # end
210
- #
294
+ #--
295
+ # NOTE: keyword args in callables are NOT checked for correctness
296
+ # against the existing method. Too many edge cases to be worth it.
211
297
 
212
- def stub name, val_or_callable, *block_args
298
+ def stub name, val_or_callable, *block_args, **block_kwargs, &block
213
299
  new_name = "__minitest_stub__#{name}"
214
300
 
215
301
  metaclass = class << self; self; end
216
302
 
217
303
  if respond_to? name and not methods.map(&:to_s).include? name.to_s then
218
- metaclass.send :define_method, name do |*args|
219
- super(*args)
304
+ metaclass.send :define_method, name do |*args, **kwargs|
305
+ super(*args, **kwargs)
220
306
  end
221
307
  end
222
308
 
223
309
  metaclass.send :alias_method, new_name, name
224
310
 
225
- metaclass.send :define_method, name do |*args, &blk|
226
- if val_or_callable.respond_to? :call then
227
- val_or_callable.call(*args, &blk)
228
- else
229
- blk.call(*block_args) if blk
230
- val_or_callable
311
+ if ENV["MT_KWARGS_HAC\K"] then
312
+ metaclass.send :define_method, name do |*args, &blk|
313
+ if val_or_callable.respond_to? :call then
314
+ val_or_callable.call(*args, &blk)
315
+ else
316
+ blk.call(*block_args, **block_kwargs) if blk
317
+ val_or_callable
318
+ end
319
+ end
320
+ else
321
+ metaclass.send :define_method, name do |*args, **kwargs, &blk|
322
+ if val_or_callable.respond_to? :call then
323
+ if kwargs.empty? then # FIX: drop this after 2.7 dead
324
+ val_or_callable.call(*args, &blk)
325
+ else
326
+ val_or_callable.call(*args, **kwargs, &blk)
327
+ end
328
+ else
329
+ if blk then
330
+ if block_kwargs.empty? then # FIX: drop this after 2.7 dead
331
+ blk.call(*block_args)
332
+ else
333
+ blk.call(*block_args, **block_kwargs)
334
+ end
335
+ end
336
+ val_or_callable
337
+ end
231
338
  end
232
339
  end
233
340
 
234
- yield self
341
+ block[self]
235
342
  ensure
236
343
  metaclass.send :undef_method, name
237
344
  metaclass.send :alias_method, name, new_name
@@ -1,5 +1,5 @@
1
1
  module Minitest
2
- module Parallel #:nodoc:
2
+ module Parallel # :nodoc:
3
3
 
4
4
  ##
5
5
  # The engine used to run multiple tests in parallel.
@@ -16,7 +16,7 @@ module Minitest
16
16
 
17
17
  def initialize size
18
18
  @size = size
19
- @queue = Queue.new
19
+ @queue = Thread::Queue.new
20
20
  @pool = nil
21
21
  end
22
22
 
@@ -24,10 +24,10 @@ module Minitest
24
24
  # Start the executor
25
25
 
26
26
  def start
27
- @pool = size.times.map {
28
- Thread.new(@queue) do |queue|
27
+ @pool = Array.new(size) {
28
+ Thread.new @queue do |queue|
29
29
  Thread.current.abort_on_exception = true
30
- while (job = queue.pop)
30
+ while job = queue.pop do
31
31
  klass, method, reporter = job
32
32
  reporter.synchronize { reporter.prerecord klass, method }
33
33
  result = Minitest.run_one_method klass, method
@@ -8,13 +8,13 @@ module Minitest
8
8
  end
9
9
 
10
10
  def self.plugin_pride_init options # :nodoc:
11
- if PrideIO.pride? then
12
- klass = ENV["TERM"] =~ /^xterm|-256color$/ ? PrideLOL : PrideIO
13
- io = klass.new options[:io]
11
+ return unless PrideIO.pride?
14
12
 
15
- self.reporter.reporters.grep(Minitest::Reporter).each do |rep|
16
- rep.io = io if rep.io.tty?
17
- end
13
+ klass = ENV["TERM"] =~ /^xterm|-(?:256color|direct)$/ ? PrideLOL : PrideIO
14
+ io = klass.new options[:io]
15
+
16
+ self.reporter.reporters.grep(Minitest::Reporter).each do |rep|
17
+ rep.io = io if rep.io.tty?
18
18
  end
19
19
  end
20
20
 
@@ -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
@@ -59,12 +59,10 @@ module Minitest
59
59
 
60
60
  def print o
61
61
  case o
62
- when "." then
62
+ when ".", "S" then
63
63
  io.print pride o
64
64
  when "E", "F" then
65
65
  io.print "#{ESC}41m#{ESC}37m#{o}#{NND}"
66
- when "S" then
67
- io.print pride o
68
66
  else
69
67
  io.print o
70
68
  end
@@ -72,11 +70,9 @@ module Minitest
72
70
 
73
71
  def puts *o # :nodoc:
74
72
  o.map! { |s|
75
- s.to_s.sub(/Finished/) {
73
+ s.to_s.sub("Finished") {
76
74
  @index = 0
77
- "Fabulous run".split(//).map { |c|
78
- pride(c)
79
- }.join
75
+ "Fabulous run".chars.map { |c| pride(c) }.join
80
76
  }
81
77
  }
82
78
 
@@ -113,19 +109,16 @@ module Minitest
113
109
  #
114
110
  # plot (3*sin(x)+3), (3*sin(x+2*pi/3)+3), (3*sin(x+4*pi/3)+3)
115
111
 
116
- # 6 has wide pretty gradients. 3 == lolcat, about half the width
117
- @colors = (0...(6 * 7)).map { |n|
118
- n *= 1.0 / 6
112
+ @colors = Array.new(6 * 7) { |n|
113
+ n *= 1.0 / 3
119
114
  r = (3 * Math.sin(n ) + 3).to_i
120
- g = (3 * Math.sin(n + 2 * PI_3) + 3).to_i
121
- b = (3 * Math.sin(n + 4 * PI_3) + 3).to_i
122
-
123
- # Then we take rgb and encode them in a single number using base 6.
124
- # For some mysterious reason, we add 16... to clear the bottom 4 bits?
125
- # Yes... they're ugly.
115
+ g = (3 * Math.sin(n + 4 * PI_3) + 3).to_i
116
+ b = (3 * Math.sin(n + 2 * PI_3) + 3).to_i
126
117
 
118
+ # Then we take rgb and encode them in a single number using
119
+ # base 6, shifted by 16 for the base 16 ansi colors.
127
120
  36 * r + 6 * g + b + 16
128
- }
121
+ }.rotate(4) # puts "red" first
129
122
 
130
123
  super
131
124
  end
data/lib/minitest/spec.rb CHANGED
@@ -4,16 +4,26 @@ class Module # :nodoc:
4
4
  def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:
5
5
  block = dont_flip == :block
6
6
  dont_flip = false if block
7
+ target_obj = block ? "_{obj.method}" : "_(obj)"
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
7
12
 
8
13
  # warn "%-22p -> %p %p" % [meth, new_name, dont_flip]
9
14
  self.class_eval <<-EOM, __FILE__, __LINE__ + 1
10
15
  def #{new_name} *args
16
+ where = Minitest.filter_backtrace(caller).first
17
+ where = where.split(/:in /, 2).first # clean up noise
18
+ Kernel.warn "DEPRECATED: global use of #{new_name} from #\{where}. Use #{target_obj}.#{new_name} instead. This will fail in Minitest 6."
11
19
  Minitest::Expectation.new(self, Minitest::Spec.current).#{new_name}(*args)
12
20
  end
21
+ #{kw_extra}
13
22
  EOM
14
23
 
15
24
  Minitest::Expectation.class_eval <<-EOM, __FILE__, __LINE__ + 1
16
25
  def #{new_name} *args
26
+ raise "Calling ##{new_name} outside of test." unless ctx
17
27
  case
18
28
  when #{!!dont_flip} then
19
29
  ctx.#{meth}(target, *args)
@@ -23,6 +33,7 @@ class Module # :nodoc:
23
33
  ctx.#{meth}(args.first, target, *args[1..-1])
24
34
  end
25
35
  end
36
+ #{kw_extra}
26
37
  EOM
27
38
  end
28
39
  end
@@ -61,7 +72,7 @@ module Kernel
61
72
  #
62
73
  # For some suggestions on how to improve your specs, try:
63
74
  #
64
- # http://betterspecs.org
75
+ # https://betterspecs.org
65
76
  #
66
77
  # but do note that several items there are debatable or specific to
67
78
  # rspec.
@@ -70,14 +81,15 @@ module Kernel
70
81
 
71
82
  def describe desc, *additional_desc, &block # :doc:
72
83
  stack = Minitest::Spec.describe_stack
73
- name = [stack.last, desc, *additional_desc].compact.join("::")
74
- sclas = stack.last || if Class === self && kind_of?(Minitest::Spec::DSL) then
75
- self
76
- else
77
- Minitest::Spec.spec_type desc, *additional_desc
78
- end
84
+ is_spec_class = Class === self && kind_of?(Minitest::Spec::DSL)
85
+ name = [stack.last, desc, *additional_desc]
86
+ name.prepend self if stack.empty? && is_spec_class
87
+ sclas =
88
+ stack.last \
89
+ || (is_spec_class && self) \
90
+ || Minitest::Spec.spec_type(desc, *additional_desc)
79
91
 
80
- cls = sclas.create name, desc
92
+ cls = sclas.create name.compact.join("::"), desc
81
93
 
82
94
  stack.push cls
83
95
  cls.class_eval(&block)
@@ -238,7 +250,7 @@ class Minitest::Spec < Minitest::Test
238
250
  pre, post = "let '#{name}' cannot ", ". Please use another name."
239
251
  methods = Minitest::Spec.instance_methods.map(&:to_s) - %w[subject]
240
252
  raise ArgumentError, "#{pre}begin with 'test'#{post}" if
241
- name =~ /\Atest/
253
+ name.start_with? "test"
242
254
  raise ArgumentError, "#{pre}override a method in Minitest::Spec#{post}" if
243
255
  methods.include? name
244
256
 
@@ -257,7 +269,7 @@ class Minitest::Spec < Minitest::Test
257
269
  end
258
270
 
259
271
  def create name, desc # :nodoc:
260
- cls = Class.new(self) do
272
+ cls = Class.new self do
261
273
  @name = name
262
274
  @desc = desc
263
275
 
@@ -278,28 +290,35 @@ class Minitest::Spec < Minitest::Test
278
290
  end
279
291
 
280
292
  attr_reader :desc # :nodoc:
281
- alias :specify :it
293
+ alias specify it
282
294
 
283
295
  ##
284
296
  # Rdoc... why are you so dumb?
285
297
 
286
298
  module InstanceMethods
287
299
  ##
288
- # Returns a value monad that has all of Expectations methods
289
- # available to it.
300
+ # Takes a value or a block and returns a value monad that has
301
+ # all of Expectations methods available to it.
290
302
  #
291
- # Also aliased to #value and #expect for your aesthetic pleasure:
303
+ # _(1 + 1).must_equal 2
292
304
  #
293
- # _(1 + 1).must_equal 2
294
- # value(1 + 1).must_equal 2
295
- # expect(1 + 1).must_equal 2
305
+ # And for blocks:
306
+ #
307
+ # _ { 1 + "1" }.must_raise TypeError
296
308
  #
297
309
  # This method of expectation-based testing is preferable to
298
310
  # straight-expectation methods (on Object) because it stores its
299
311
  # test context, bypassing our hacky use of thread-local variables.
300
312
  #
301
- # At some point, the methods on Object will be deprecated and then
302
- # removed.
313
+ # NOTE: At some point, the methods on Object will be deprecated
314
+ # and then removed.
315
+ #
316
+ # It is also aliased to #value and #expect for your aesthetic
317
+ # pleasure:
318
+ #
319
+ # _(1 + 1).must_equal 2
320
+ # value(1 + 1).must_equal 2
321
+ # expect(1 + 1).must_equal 2
303
322
 
304
323
  def _ value = nil, &block
305
324
  Minitest::Expectation.new block || value, self