minitest 5.10.3 → 5.18.0
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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/History.rdoc +267 -4
- data/Manifest.txt +3 -0
- data/README.rdoc +123 -22
- data/Rakefile +5 -16
- data/lib/hoe/minitest.rb +0 -4
- data/lib/minitest/assertions.rb +197 -32
- data/lib/minitest/benchmark.rb +39 -8
- data/lib/minitest/expectations.rb +72 -35
- data/lib/minitest/mock.rb +118 -34
- data/lib/minitest/parallel.rb +1 -1
- data/lib/minitest/pride_plugin.rb +1 -1
- data/lib/minitest/spec.rb +27 -9
- data/lib/minitest/test.rb +38 -66
- data/lib/minitest/test_task.rb +305 -0
- data/lib/minitest/unit.rb +5 -8
- data/lib/minitest.rb +271 -52
- data/test/minitest/metametameta.rb +44 -9
- data/test/minitest/test_minitest_assertions.rb +1701 -0
- data/test/minitest/test_minitest_benchmark.rb +2 -2
- data/test/minitest/test_minitest_mock.rb +648 -14
- data/test/minitest/test_minitest_reporter.rb +46 -21
- data/test/minitest/test_minitest_spec.rb +317 -156
- data/test/minitest/test_minitest_test.rb +308 -1146
- data/test/minitest/test_minitest_test_task.rb +46 -0
- data.tar.gz.sig +1 -2
- metadata +36 -24
- metadata.gz.sig +0 -0
data/lib/hoe/minitest.rb
CHANGED
data/lib/minitest/assertions.rb
CHANGED
@@ -27,20 +27,18 @@ module Minitest
|
|
27
27
|
# figure out what diff to use.
|
28
28
|
|
29
29
|
def self.diff
|
30
|
+
return @diff if defined? @diff
|
31
|
+
|
30
32
|
@diff = if (RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ &&
|
31
33
|
system("diff.exe", __FILE__, __FILE__)) then
|
32
34
|
"diff.exe -u"
|
33
|
-
elsif Minitest::Test.maglev? then
|
34
|
-
"diff -u"
|
35
35
|
elsif system("gdiff", __FILE__, __FILE__)
|
36
36
|
"gdiff -u" # solaris and kin suck
|
37
37
|
elsif system("diff", __FILE__, __FILE__)
|
38
38
|
"diff -u"
|
39
39
|
else
|
40
40
|
nil
|
41
|
-
end
|
42
|
-
|
43
|
-
@diff
|
41
|
+
end
|
44
42
|
end
|
45
43
|
|
46
44
|
##
|
@@ -55,22 +53,16 @@ module Minitest
|
|
55
53
|
# diff command or if it doesn't make sense to diff the output
|
56
54
|
# (single line, short output), then it simply returns a basic
|
57
55
|
# comparison between the two.
|
56
|
+
#
|
57
|
+
# See +things_to_diff+ for more info.
|
58
58
|
|
59
59
|
def diff exp, act
|
60
|
-
expect = mu_pp_for_diff exp
|
61
|
-
butwas = mu_pp_for_diff act
|
62
60
|
result = nil
|
63
61
|
|
64
|
-
|
65
|
-
(expect.include?("\n") ||
|
66
|
-
butwas.include?("\n") ||
|
67
|
-
expect.size > 30 ||
|
68
|
-
butwas.size > 30 ||
|
69
|
-
expect == butwas) &&
|
70
|
-
Minitest::Assertions.diff
|
62
|
+
expect, butwas = things_to_diff(exp, act)
|
71
63
|
|
72
64
|
return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" unless
|
73
|
-
|
65
|
+
expect
|
74
66
|
|
75
67
|
Tempfile.open("expect") do |a|
|
76
68
|
a.puts expect
|
@@ -99,10 +91,40 @@ module Minitest
|
|
99
91
|
result
|
100
92
|
end
|
101
93
|
|
94
|
+
##
|
95
|
+
# Returns things to diff [expect, butwas], or [nil, nil] if nothing to diff.
|
96
|
+
#
|
97
|
+
# Criterion:
|
98
|
+
#
|
99
|
+
# 1. Strings include newlines or escaped newlines, but not both.
|
100
|
+
# 2. or: String lengths are > 30 characters.
|
101
|
+
# 3. or: Strings are equal to each other (but maybe different encodings?).
|
102
|
+
# 4. and: we found a diff executable.
|
103
|
+
|
104
|
+
def things_to_diff exp, act
|
105
|
+
expect = mu_pp_for_diff exp
|
106
|
+
butwas = mu_pp_for_diff act
|
107
|
+
|
108
|
+
e1, e2 = expect.include?("\n"), expect.include?("\\n")
|
109
|
+
b1, b2 = butwas.include?("\n"), butwas.include?("\\n")
|
110
|
+
|
111
|
+
need_to_diff =
|
112
|
+
(e1 ^ e2 ||
|
113
|
+
b1 ^ b2 ||
|
114
|
+
expect.size > 30 ||
|
115
|
+
butwas.size > 30 ||
|
116
|
+
expect == butwas) &&
|
117
|
+
Minitest::Assertions.diff
|
118
|
+
|
119
|
+
need_to_diff && [expect, butwas]
|
120
|
+
end
|
121
|
+
|
102
122
|
##
|
103
123
|
# This returns a human-readable version of +obj+. By default
|
104
|
-
# #inspect is called. You can override this to use #
|
124
|
+
# #inspect is called. You can override this to use #pretty_inspect
|
105
125
|
# if you want.
|
126
|
+
#
|
127
|
+
# See Minitest::Test.make_my_diffs_pretty!
|
106
128
|
|
107
129
|
def mu_pp obj
|
108
130
|
s = obj.inspect
|
@@ -110,8 +132,11 @@ module Minitest
|
|
110
132
|
if defined? Encoding then
|
111
133
|
s = s.encode Encoding.default_external
|
112
134
|
|
113
|
-
if String === obj && obj.encoding != Encoding.default_external
|
114
|
-
|
135
|
+
if String === obj && (obj.encoding != Encoding.default_external ||
|
136
|
+
!obj.valid_encoding?) then
|
137
|
+
enc = "# encoding: #{obj.encoding}"
|
138
|
+
val = "# valid: #{obj.valid_encoding?}"
|
139
|
+
s = "#{enc}\n#{val}\n#{s}"
|
115
140
|
end
|
116
141
|
end
|
117
142
|
|
@@ -119,13 +144,32 @@ module Minitest
|
|
119
144
|
end
|
120
145
|
|
121
146
|
##
|
122
|
-
# This returns a diff-able human-readable version of +obj+.
|
123
|
-
# differs from the regular mu_pp because it expands escaped
|
124
|
-
# newlines and makes hex-values
|
147
|
+
# This returns a diff-able more human-readable version of +obj+.
|
148
|
+
# This differs from the regular mu_pp because it expands escaped
|
149
|
+
# newlines and makes hex-values (like object_ids) generic. This
|
125
150
|
# uses mu_pp to do the first pass and then cleans it up.
|
126
151
|
|
127
152
|
def mu_pp_for_diff obj
|
128
|
-
mu_pp
|
153
|
+
str = mu_pp obj
|
154
|
+
|
155
|
+
# both '\n' & '\\n' (_after_ mu_pp (aka inspect))
|
156
|
+
single = !!str.match(/(?<!\\|^)\\n/)
|
157
|
+
double = !!str.match(/(?<=\\|^)\\n/)
|
158
|
+
|
159
|
+
process =
|
160
|
+
if single ^ double then
|
161
|
+
if single then
|
162
|
+
lambda { |s| s == "\\n" ? "\n" : s } # unescape
|
163
|
+
else
|
164
|
+
lambda { |s| s == "\\\\n" ? "\\n\n" : s } # unescape a bit, add nls
|
165
|
+
end
|
166
|
+
else
|
167
|
+
:itself # leave it alone
|
168
|
+
end
|
169
|
+
|
170
|
+
str.
|
171
|
+
gsub(/\\?\\n/, &process).
|
172
|
+
gsub(/:0x[a-fA-F0-9]{4,}/m, ":0xXXXXXX") # anonymize hex values
|
129
173
|
end
|
130
174
|
|
131
175
|
##
|
@@ -173,7 +217,7 @@ module Minitest
|
|
173
217
|
msg = message(msg, E) { diff exp, act }
|
174
218
|
result = assert exp == act, msg
|
175
219
|
|
176
|
-
if
|
220
|
+
if nil == exp then
|
177
221
|
if Minitest::VERSION =~ /^6/ then
|
178
222
|
refute_nil exp, "Use assert_nil if expecting nil."
|
179
223
|
else
|
@@ -205,8 +249,8 @@ module Minitest
|
|
205
249
|
# For comparing Floats. Fails unless +exp+ and +act+ have a relative
|
206
250
|
# error less than +epsilon+.
|
207
251
|
|
208
|
-
def assert_in_epsilon
|
209
|
-
assert_in_delta
|
252
|
+
def assert_in_epsilon exp, act, epsilon = 0.001, msg = nil
|
253
|
+
assert_in_delta exp, act, [exp.abs, act.abs].min * epsilon, msg
|
210
254
|
end
|
211
255
|
|
212
256
|
##
|
@@ -249,6 +293,8 @@ module Minitest
|
|
249
293
|
assert_respond_to matcher, :"=~"
|
250
294
|
matcher = Regexp.new Regexp.escape matcher if String === matcher
|
251
295
|
assert matcher =~ obj, msg
|
296
|
+
|
297
|
+
Regexp.last_match
|
252
298
|
end
|
253
299
|
|
254
300
|
##
|
@@ -283,6 +329,9 @@ module Minitest
|
|
283
329
|
# See also: #assert_silent
|
284
330
|
|
285
331
|
def assert_output stdout = nil, stderr = nil
|
332
|
+
flunk "assert_output requires a block to capture output." unless
|
333
|
+
block_given?
|
334
|
+
|
286
335
|
out, err = capture_io do
|
287
336
|
yield
|
288
337
|
end
|
@@ -294,6 +343,44 @@ module Minitest
|
|
294
343
|
x = send out_msg, stdout, out, "In stdout" if out_msg
|
295
344
|
|
296
345
|
(!stdout || x) && (!stderr || y)
|
346
|
+
rescue Assertion
|
347
|
+
raise
|
348
|
+
rescue => e
|
349
|
+
raise UnexpectedError, e
|
350
|
+
end
|
351
|
+
|
352
|
+
##
|
353
|
+
# Fails unless +path+ exists.
|
354
|
+
|
355
|
+
def assert_path_exists path, msg = nil
|
356
|
+
msg = message(msg) { "Expected path '#{path}' to exist" }
|
357
|
+
assert File.exist?(path), msg
|
358
|
+
end
|
359
|
+
|
360
|
+
##
|
361
|
+
# For testing with pattern matching (only supported with Ruby 3.0 and later)
|
362
|
+
#
|
363
|
+
# # pass
|
364
|
+
# assert_pattern { [1,2,3] => [Integer, Integer, Integer] }
|
365
|
+
#
|
366
|
+
# # fail "length mismatch (given 3, expected 1)"
|
367
|
+
# assert_pattern { [1,2,3] => [Integer] }
|
368
|
+
#
|
369
|
+
# The bare <tt>=></tt> pattern will raise a NoMatchingPatternError on failure, which would
|
370
|
+
# normally be counted as a test error. This assertion rescues NoMatchingPatternError and
|
371
|
+
# generates a test failure. Any other exception will be raised as normal and generate a test
|
372
|
+
# error.
|
373
|
+
|
374
|
+
def assert_pattern
|
375
|
+
raise NotImplementedError, "only available in Ruby 3.0+" unless RUBY_VERSION >= "3.0"
|
376
|
+
flunk "assert_pattern requires a block to capture errors." unless block_given?
|
377
|
+
|
378
|
+
begin # TODO: remove after ruby 2.6 dropped
|
379
|
+
yield
|
380
|
+
pass
|
381
|
+
rescue NoMatchingPatternError => e
|
382
|
+
flunk e.message
|
383
|
+
end
|
297
384
|
end
|
298
385
|
|
299
386
|
##
|
@@ -316,9 +403,26 @@ module Minitest
|
|
316
403
|
#
|
317
404
|
# +exp+ takes an optional message on the end to help explain
|
318
405
|
# failures and defaults to StandardError if no exception class is
|
319
|
-
# passed.
|
406
|
+
# passed. Eg:
|
407
|
+
#
|
408
|
+
# assert_raises(CustomError) { method_with_custom_error }
|
409
|
+
#
|
410
|
+
# With custom error message:
|
411
|
+
#
|
412
|
+
# assert_raises(CustomError, 'This should have raised CustomError') { method_with_custom_error }
|
413
|
+
#
|
414
|
+
# Using the returned object:
|
415
|
+
#
|
416
|
+
# error = assert_raises(CustomError) do
|
417
|
+
# raise CustomError, 'This is really bad'
|
418
|
+
# end
|
419
|
+
#
|
420
|
+
# assert_equal 'This is really bad', error.message
|
320
421
|
|
321
422
|
def assert_raises *exp
|
423
|
+
flunk "assert_raises requires a block to capture errors." unless
|
424
|
+
block_given?
|
425
|
+
|
322
426
|
msg = "#{exp.pop}.\n" if String === exp.last
|
323
427
|
exp << StandardError if exp.empty?
|
324
428
|
|
@@ -327,7 +431,7 @@ module Minitest
|
|
327
431
|
rescue *exp => e
|
328
432
|
pass # count assertion
|
329
433
|
return e
|
330
|
-
rescue Minitest::Skip
|
434
|
+
rescue Minitest::Assertion # incl Skip & UnexpectedError
|
331
435
|
# don't count assertion
|
332
436
|
raise
|
333
437
|
rescue SignalException, SystemExit
|
@@ -397,7 +501,7 @@ module Minitest
|
|
397
501
|
def assert_throws sym, msg = nil
|
398
502
|
default = "Expected #{mu_pp(sym)} to have been thrown"
|
399
503
|
caught = true
|
400
|
-
catch(sym) do
|
504
|
+
value = catch(sym) do
|
401
505
|
begin
|
402
506
|
yield
|
403
507
|
rescue ThreadError => e # wtf?!? 1.8 + threads == suck
|
@@ -413,6 +517,11 @@ module Minitest
|
|
413
517
|
end
|
414
518
|
|
415
519
|
assert caught, message(msg) { default }
|
520
|
+
value
|
521
|
+
rescue Assertion
|
522
|
+
raise
|
523
|
+
rescue => e
|
524
|
+
raise UnexpectedError, e
|
416
525
|
end
|
417
526
|
|
418
527
|
##
|
@@ -481,10 +590,13 @@ module Minitest
|
|
481
590
|
|
482
591
|
return captured_stdout.read, captured_stderr.read
|
483
592
|
ensure
|
484
|
-
captured_stdout.unlink
|
485
|
-
captured_stderr.unlink
|
486
593
|
$stdout.reopen orig_stdout
|
487
594
|
$stderr.reopen orig_stderr
|
595
|
+
|
596
|
+
orig_stdout.close
|
597
|
+
orig_stderr.close
|
598
|
+
captured_stdout.close!
|
599
|
+
captured_stderr.close!
|
488
600
|
end
|
489
601
|
end
|
490
602
|
end
|
@@ -504,7 +616,16 @@ module Minitest
|
|
504
616
|
end
|
505
617
|
|
506
618
|
##
|
507
|
-
# Fails
|
619
|
+
# Fails after a given date (in the local time zone). This allows
|
620
|
+
# you to put time-bombs in your tests if you need to keep
|
621
|
+
# something around until a later date lest you forget about it.
|
622
|
+
|
623
|
+
def fail_after y,m,d,msg
|
624
|
+
flunk msg if Time.now > Time.local(y, m, d)
|
625
|
+
end
|
626
|
+
|
627
|
+
##
|
628
|
+
# Fails with +msg+.
|
508
629
|
|
509
630
|
def flunk msg = nil
|
510
631
|
msg ||= "Epic Fail!"
|
@@ -534,7 +655,7 @@ module Minitest
|
|
534
655
|
|
535
656
|
def refute test, msg = nil
|
536
657
|
msg ||= message { "Expected #{mu_pp(test)} to not be truthy" }
|
537
|
-
|
658
|
+
assert !test, msg
|
538
659
|
end
|
539
660
|
|
540
661
|
##
|
@@ -626,6 +747,30 @@ module Minitest
|
|
626
747
|
refute obj.nil?, msg
|
627
748
|
end
|
628
749
|
|
750
|
+
##
|
751
|
+
# For testing with pattern matching (only supported with Ruby 3.0 and later)
|
752
|
+
#
|
753
|
+
# # pass
|
754
|
+
# refute_pattern { [1,2,3] => [String] }
|
755
|
+
#
|
756
|
+
# # fail "NoMatchingPatternError expected, but nothing was raised."
|
757
|
+
# refute_pattern { [1,2,3] => [Integer, Integer, Integer] }
|
758
|
+
#
|
759
|
+
# This assertion expects a NoMatchingPatternError exception, and will fail if none is raised. Any
|
760
|
+
# other exceptions will be raised as normal and generate a test error.
|
761
|
+
|
762
|
+
def refute_pattern
|
763
|
+
raise NotImplementedError, "only available in Ruby 3.0+" unless RUBY_VERSION >= "3.0"
|
764
|
+
flunk "refute_pattern requires a block to capture errors." unless block_given?
|
765
|
+
|
766
|
+
begin
|
767
|
+
yield
|
768
|
+
flunk("NoMatchingPatternError expected, but nothing was raised.")
|
769
|
+
rescue NoMatchingPatternError
|
770
|
+
pass
|
771
|
+
end
|
772
|
+
end
|
773
|
+
|
629
774
|
##
|
630
775
|
# Fails if +o1+ is not +op+ +o2+. Eg:
|
631
776
|
#
|
@@ -638,6 +783,14 @@ module Minitest
|
|
638
783
|
refute o1.__send__(op, o2), msg
|
639
784
|
end
|
640
785
|
|
786
|
+
##
|
787
|
+
# Fails if +path+ exists.
|
788
|
+
|
789
|
+
def refute_path_exists path, msg = nil
|
790
|
+
msg = message(msg) { "Expected path '#{path}' to not exist" }
|
791
|
+
refute File.exist?(path), msg
|
792
|
+
end
|
793
|
+
|
641
794
|
##
|
642
795
|
# For testing with predicates.
|
643
796
|
#
|
@@ -683,6 +836,18 @@ module Minitest
|
|
683
836
|
raise Minitest::Skip, msg, bt
|
684
837
|
end
|
685
838
|
|
839
|
+
##
|
840
|
+
# Skips the current run until a given date (in the local time
|
841
|
+
# zone). This allows you to put some fixes on hold until a later
|
842
|
+
# date, but still holds you accountable and prevents you from
|
843
|
+
# forgetting it.
|
844
|
+
|
845
|
+
def skip_until y,m,d,msg
|
846
|
+
skip msg if Time.now < Time.local(y, m, d)
|
847
|
+
where = caller.first.rpartition(':in').reject(&:empty?).first
|
848
|
+
warn "Stale skip_until %p at %s" % [msg, where]
|
849
|
+
end
|
850
|
+
|
686
851
|
##
|
687
852
|
# Was this testcase skipped? Meant for #teardown.
|
688
853
|
|
data/lib/minitest/benchmark.rb
CHANGED
@@ -109,8 +109,8 @@ module Minitest
|
|
109
109
|
# is applied against the slope itself. As such, you probably want
|
110
110
|
# to tighten it from the default.
|
111
111
|
#
|
112
|
-
# See
|
113
|
-
# more details.
|
112
|
+
# See https://www.graphpad.com/guides/prism/8/curve-fitting/reg_intepretingnonlinr2.htm
|
113
|
+
# for more details.
|
114
114
|
#
|
115
115
|
# Fit is calculated by #fit_linear.
|
116
116
|
#
|
@@ -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:
|
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:
|
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:
|
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:
|
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:
|
301
|
+
# See: https://mathworld.wolfram.com/LeastSquaresFittingPowerLaw.html
|
302
302
|
|
303
303
|
def fit_power xs, ys
|
304
304
|
n = xs.size
|
@@ -318,7 +318,7 @@ module Minitest
|
|
318
318
|
# Enumerates over +enum+ mapping +block+ if given, returning the
|
319
319
|
# sum of the result. Eg:
|
320
320
|
#
|
321
|
-
# sigma([1, 2, 3]) # => 1 + 2 + 3 =>
|
321
|
+
# sigma([1, 2, 3]) # => 1 + 2 + 3 => 6
|
322
322
|
# sigma([1, 2, 3]) { |n| n ** 2 } # => 1 + 4 + 9 => 14
|
323
323
|
|
324
324
|
def sigma enum, &block
|
@@ -418,6 +418,37 @@ module Minitest
|
|
418
418
|
assert_performance_exponential threshold, &work
|
419
419
|
end
|
420
420
|
end
|
421
|
+
|
422
|
+
|
423
|
+
##
|
424
|
+
# Create a benchmark that verifies that the performance is logarithmic.
|
425
|
+
#
|
426
|
+
# describe "my class Bench" do
|
427
|
+
# bench_performance_logarithmic "algorithm" do |n|
|
428
|
+
# @obj.algorithm(n)
|
429
|
+
# end
|
430
|
+
# end
|
431
|
+
|
432
|
+
def self.bench_performance_logarithmic name, threshold = 0.99, &work
|
433
|
+
bench name do
|
434
|
+
assert_performance_logarithmic threshold, &work
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
##
|
439
|
+
# Create a benchmark that verifies that the performance is power.
|
440
|
+
#
|
441
|
+
# describe "my class Bench" do
|
442
|
+
# bench_performance_power "algorithm" do |n|
|
443
|
+
# @obj.algorithm(n)
|
444
|
+
# end
|
445
|
+
# end
|
446
|
+
|
447
|
+
def self.bench_performance_power name, threshold = 0.99, &work
|
448
|
+
bench name do
|
449
|
+
assert_performance_power threshold, &work
|
450
|
+
end
|
451
|
+
end
|
421
452
|
end
|
422
453
|
|
423
454
|
Minitest::Spec.register_spec_type(/Bench(mark)?$/, Minitest::BenchSpec)
|