minitest 5.16.3 → 5.25.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/History.rdoc +176 -1
- data/Manifest.txt +3 -0
- data/README.rdoc +26 -25
- data/Rakefile +7 -0
- data/lib/hoe/minitest.rb +2 -1
- data/lib/minitest/assertions.rb +126 -79
- data/lib/minitest/autorun.rb +0 -7
- data/lib/minitest/benchmark.rb +6 -9
- data/lib/minitest/compress.rb +94 -0
- data/lib/minitest/error_on_warning.rb +11 -0
- data/lib/minitest/expectations.rb +18 -0
- data/lib/minitest/manual_plugins.rb +16 -0
- data/lib/minitest/mock.rb +23 -17
- data/lib/minitest/parallel.rb +5 -5
- data/lib/minitest/pride_plugin.rb +16 -23
- data/lib/minitest/spec.rb +10 -4
- data/lib/minitest/test.rb +22 -37
- data/lib/minitest/test_task.rb +24 -22
- data/lib/minitest.rb +296 -148
- data/test/minitest/metametameta.rb +32 -18
- data/test/minitest/test_minitest_assertions.rb +269 -140
- data/test/minitest/test_minitest_benchmark.rb +1 -1
- data/test/minitest/test_minitest_mock.rb +89 -77
- data/test/minitest/test_minitest_reporter.rb +139 -15
- data/test/minitest/test_minitest_spec.rb +130 -55
- data/test/minitest/test_minitest_test.rb +200 -116
- data/test/minitest/test_minitest_test_task.rb +18 -7
- data.tar.gz.sig +0 -0
- metadata +20 -16
- metadata.gz.sig +0 -0
data/lib/minitest/assertions.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
require "rbconfig"
|
4
2
|
require "tempfile"
|
5
3
|
require "stringio"
|
@@ -29,12 +27,12 @@ module Minitest
|
|
29
27
|
def self.diff
|
30
28
|
return @diff if defined? @diff
|
31
29
|
|
32
|
-
@diff = if (RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
|
33
|
-
system
|
30
|
+
@diff = if (RbConfig::CONFIG["host_os"] =~ /mswin|mingw/ and
|
31
|
+
system "diff.exe", __FILE__, __FILE__) then
|
34
32
|
"diff.exe -u"
|
35
|
-
elsif system
|
33
|
+
elsif system "gdiff", __FILE__, __FILE__ then
|
36
34
|
"gdiff -u" # solaris and kin suck
|
37
|
-
elsif system
|
35
|
+
elsif system "diff", __FILE__, __FILE__ then
|
38
36
|
"diff -u"
|
39
37
|
else
|
40
38
|
nil
|
@@ -59,16 +57,16 @@ module Minitest
|
|
59
57
|
def diff exp, act
|
60
58
|
result = nil
|
61
59
|
|
62
|
-
expect, butwas = things_to_diff
|
60
|
+
expect, butwas = things_to_diff exp, act
|
63
61
|
|
64
62
|
return "Expected: #{mu_pp exp}\n Actual: #{mu_pp act}" unless
|
65
63
|
expect
|
66
64
|
|
67
|
-
Tempfile.open
|
65
|
+
Tempfile.open "expect" do |a|
|
68
66
|
a.puts expect
|
69
67
|
a.flush
|
70
68
|
|
71
|
-
Tempfile.open
|
69
|
+
Tempfile.open "butwas" do |b|
|
72
70
|
b.puts butwas
|
73
71
|
b.flush
|
74
72
|
|
@@ -79,10 +77,10 @@ module Minitest
|
|
79
77
|
if result.empty? then
|
80
78
|
klass = exp.class
|
81
79
|
result = [
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
80
|
+
"No visible difference in the #{klass}#inspect output.\n",
|
81
|
+
"You should look at the implementation of #== on ",
|
82
|
+
"#{klass} or its members.\n",
|
83
|
+
expect,
|
86
84
|
].join
|
87
85
|
end
|
88
86
|
end
|
@@ -127,20 +125,15 @@ module Minitest
|
|
127
125
|
# See Minitest::Test.make_my_diffs_pretty!
|
128
126
|
|
129
127
|
def mu_pp obj
|
130
|
-
s = obj.inspect
|
128
|
+
s = obj.inspect.encode Encoding.default_external
|
131
129
|
|
132
|
-
|
133
|
-
|
130
|
+
return s unless String === obj &&
|
131
|
+
(obj.encoding != Encoding.default_external || !obj.valid_encoding?)
|
134
132
|
|
135
|
-
|
136
|
-
|
137
|
-
enc = "# encoding: #{obj.encoding}"
|
138
|
-
val = "# valid: #{obj.valid_encoding?}"
|
139
|
-
s = "#{enc}\n#{val}\n#{s}"
|
140
|
-
end
|
141
|
-
end
|
133
|
+
enc = "# encoding: #{obj.encoding}"
|
134
|
+
val = "# valid: #{obj.valid_encoding?}"
|
142
135
|
|
143
|
-
s
|
136
|
+
[enc, val, s].join "\n"
|
144
137
|
end
|
145
138
|
|
146
139
|
##
|
@@ -153,8 +146,8 @@ module Minitest
|
|
153
146
|
str = mu_pp obj
|
154
147
|
|
155
148
|
# both '\n' & '\\n' (_after_ mu_pp (aka inspect))
|
156
|
-
single =
|
157
|
-
double =
|
149
|
+
single = str.match?(/(?<!\\|^)\\n/)
|
150
|
+
double = str.match?(/(?<=\\|^)\\n/)
|
158
151
|
|
159
152
|
process =
|
160
153
|
if single ^ double then
|
@@ -167,9 +160,9 @@ module Minitest
|
|
167
160
|
:itself # leave it alone
|
168
161
|
end
|
169
162
|
|
170
|
-
str
|
171
|
-
gsub(/\\?\\n/, &process)
|
172
|
-
gsub(/:0x[a-fA-F0-9]{4,}/m, ":0xXXXXXX") # anonymize hex values
|
163
|
+
str
|
164
|
+
.gsub(/\\?\\n/, &process)
|
165
|
+
.gsub(/:0x[a-fA-F0-9]{4,}/m, ":0xXXXXXX") # anonymize hex values
|
173
166
|
end
|
174
167
|
|
175
168
|
##
|
@@ -193,11 +186,16 @@ module Minitest
|
|
193
186
|
# Fails unless +obj+ is empty.
|
194
187
|
|
195
188
|
def assert_empty obj, msg = nil
|
196
|
-
msg = message(msg) { "Expected #{mu_pp
|
189
|
+
msg = message(msg) { "Expected #{mu_pp obj} to be empty" }
|
197
190
|
assert_respond_to obj, :empty?
|
198
191
|
assert obj.empty?, msg
|
199
192
|
end
|
200
193
|
|
194
|
+
def _where # :nodoc:
|
195
|
+
Minitest.filter_backtrace(caller).first
|
196
|
+
.split(":in ", 2).first # clean up noise
|
197
|
+
end
|
198
|
+
|
201
199
|
E = "" # :nodoc:
|
202
200
|
|
203
201
|
##
|
@@ -218,13 +216,10 @@ module Minitest
|
|
218
216
|
result = assert exp == act, msg
|
219
217
|
|
220
218
|
if nil == exp then
|
221
|
-
if Minitest::VERSION
|
219
|
+
if Minitest::VERSION >= "6" then
|
222
220
|
refute_nil exp, "Use assert_nil if expecting nil."
|
223
221
|
else
|
224
|
-
|
225
|
-
where = where.split(/:in /, 2).first # clean up noise
|
226
|
-
|
227
|
-
warn "DEPRECATED: Use assert_nil if expecting nil from #{where}. This will fail in Minitest 6."
|
222
|
+
warn "DEPRECATED: Use assert_nil if expecting nil from #{_where}. This will fail in Minitest 6."
|
228
223
|
end
|
229
224
|
end
|
230
225
|
|
@@ -258,7 +253,7 @@ module Minitest
|
|
258
253
|
|
259
254
|
def assert_includes collection, obj, msg = nil
|
260
255
|
msg = message(msg) {
|
261
|
-
"Expected #{mu_pp
|
256
|
+
"Expected #{mu_pp collection} to include #{mu_pp obj}"
|
262
257
|
}
|
263
258
|
assert_respond_to collection, :include?
|
264
259
|
assert collection.include?(obj), msg
|
@@ -269,7 +264,7 @@ module Minitest
|
|
269
264
|
|
270
265
|
def assert_instance_of cls, obj, msg = nil
|
271
266
|
msg = message(msg) {
|
272
|
-
"Expected #{mu_pp
|
267
|
+
"Expected #{mu_pp obj} to be an instance of #{cls}, not #{obj.class}"
|
273
268
|
}
|
274
269
|
|
275
270
|
assert obj.instance_of?(cls), msg
|
@@ -280,7 +275,8 @@ module Minitest
|
|
280
275
|
|
281
276
|
def assert_kind_of cls, obj, msg = nil
|
282
277
|
msg = message(msg) {
|
283
|
-
"Expected #{mu_pp
|
278
|
+
"Expected #{mu_pp obj} to be a kind of #{cls}, not #{obj.class}"
|
279
|
+
}
|
284
280
|
|
285
281
|
assert obj.kind_of?(cls), msg
|
286
282
|
end
|
@@ -290,7 +286,7 @@ module Minitest
|
|
290
286
|
|
291
287
|
def assert_match matcher, obj, msg = nil
|
292
288
|
msg = message(msg) { "Expected #{mu_pp matcher} to match #{mu_pp obj}" }
|
293
|
-
assert_respond_to matcher,
|
289
|
+
assert_respond_to matcher, :=~
|
294
290
|
matcher = Regexp.new Regexp.escape matcher if String === matcher
|
295
291
|
assert matcher =~ obj, msg
|
296
292
|
|
@@ -301,7 +297,7 @@ module Minitest
|
|
301
297
|
# Fails unless +obj+ is nil
|
302
298
|
|
303
299
|
def assert_nil obj, msg = nil
|
304
|
-
msg = message(msg) { "Expected #{mu_pp
|
300
|
+
msg = message(msg) { "Expected #{mu_pp obj} to be nil" }
|
305
301
|
assert obj.nil?, msg
|
306
302
|
end
|
307
303
|
|
@@ -312,7 +308,7 @@ module Minitest
|
|
312
308
|
|
313
309
|
def assert_operator o1, op, o2 = UNDEFINED, msg = nil
|
314
310
|
return assert_predicate o1, op, msg if UNDEFINED == o2
|
315
|
-
msg = message(msg) { "Expected #{mu_pp
|
311
|
+
msg = message(msg) { "Expected #{mu_pp o1} to be #{op} #{mu_pp o2}" }
|
316
312
|
assert o1.__send__(op, o2), msg
|
317
313
|
end
|
318
314
|
|
@@ -357,6 +353,32 @@ module Minitest
|
|
357
353
|
assert File.exist?(path), msg
|
358
354
|
end
|
359
355
|
|
356
|
+
##
|
357
|
+
# For testing with pattern matching (only supported with Ruby 3.0 and later)
|
358
|
+
#
|
359
|
+
# # pass
|
360
|
+
# assert_pattern { [1,2,3] => [Integer, Integer, Integer] }
|
361
|
+
#
|
362
|
+
# # fail "length mismatch (given 3, expected 1)"
|
363
|
+
# assert_pattern { [1,2,3] => [Integer] }
|
364
|
+
#
|
365
|
+
# The bare <tt>=></tt> pattern will raise a NoMatchingPatternError on failure, which would
|
366
|
+
# normally be counted as a test error. This assertion rescues NoMatchingPatternError and
|
367
|
+
# generates a test failure. Any other exception will be raised as normal and generate a test
|
368
|
+
# error.
|
369
|
+
|
370
|
+
def assert_pattern
|
371
|
+
raise NotImplementedError, "only available in Ruby 3.0+" unless RUBY_VERSION >= "3.0"
|
372
|
+
flunk "assert_pattern requires a block to capture errors." unless block_given?
|
373
|
+
|
374
|
+
begin # TODO: remove after ruby 2.6 dropped
|
375
|
+
yield
|
376
|
+
pass
|
377
|
+
rescue NoMatchingPatternError => e
|
378
|
+
flunk e.message
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
360
382
|
##
|
361
383
|
# For testing with predicates. Eg:
|
362
384
|
#
|
@@ -367,7 +389,7 @@ module Minitest
|
|
367
389
|
# str.must_be :empty?
|
368
390
|
|
369
391
|
def assert_predicate o1, op, msg = nil
|
370
|
-
msg = message(msg) { "Expected #{mu_pp
|
392
|
+
msg = message(msg) { "Expected #{mu_pp o1} to be #{op}" }
|
371
393
|
assert o1.__send__(op), msg
|
372
394
|
end
|
373
395
|
|
@@ -412,23 +434,24 @@ module Minitest
|
|
412
434
|
raise
|
413
435
|
rescue Exception => e
|
414
436
|
flunk proc {
|
415
|
-
exception_details(e, "#{msg}#{mu_pp
|
437
|
+
exception_details(e, "#{msg}#{mu_pp exp} exception expected, not")
|
416
438
|
}
|
417
439
|
end
|
418
440
|
|
419
441
|
exp = exp.first if exp.size == 1
|
420
442
|
|
421
|
-
flunk "#{msg}#{mu_pp
|
443
|
+
flunk "#{msg}#{mu_pp exp} expected but nothing was raised."
|
422
444
|
end
|
423
445
|
|
424
446
|
##
|
425
447
|
# Fails unless +obj+ responds to +meth+.
|
448
|
+
# include_all defaults to false to match Object#respond_to?
|
426
449
|
|
427
|
-
def assert_respond_to obj, meth, msg = nil
|
450
|
+
def assert_respond_to obj, meth, msg = nil, include_all: false
|
428
451
|
msg = message(msg) {
|
429
|
-
"Expected #{mu_pp
|
452
|
+
"Expected #{mu_pp obj} (#{obj.class}) to respond to ##{meth}"
|
430
453
|
}
|
431
|
-
assert obj.respond_to?(meth), msg
|
454
|
+
assert obj.respond_to?(meth, include_all), msg
|
432
455
|
end
|
433
456
|
|
434
457
|
##
|
@@ -448,13 +471,12 @@ module Minitest
|
|
448
471
|
# Fails unless the call returns a true value
|
449
472
|
|
450
473
|
def assert_send send_ary, m = nil
|
451
|
-
|
452
|
-
where = where.split(/:in /, 2).first # clean up noise
|
453
|
-
warn "DEPRECATED: assert_send. From #{where}"
|
474
|
+
warn "DEPRECATED: assert_send. From #{_where}"
|
454
475
|
|
455
476
|
recv, msg, *args = send_ary
|
456
477
|
m = message(m) {
|
457
|
-
"Expected #{mu_pp
|
478
|
+
"Expected #{mu_pp recv}.#{msg}(*#{mu_pp args}) to return true"
|
479
|
+
}
|
458
480
|
assert recv.__send__(msg, *args), m
|
459
481
|
end
|
460
482
|
|
@@ -473,15 +495,15 @@ module Minitest
|
|
473
495
|
# Fails unless the block throws +sym+
|
474
496
|
|
475
497
|
def assert_throws sym, msg = nil
|
476
|
-
default = "Expected #{mu_pp
|
498
|
+
default = "Expected #{mu_pp sym} to have been thrown"
|
477
499
|
caught = true
|
478
|
-
value = catch
|
500
|
+
value = catch sym do
|
479
501
|
begin
|
480
502
|
yield
|
481
503
|
rescue ThreadError => e # wtf?!? 1.8 + threads == suck
|
482
|
-
default += ", not
|
504
|
+
default += ", not :#{e.message[/uncaught throw \`(\w+?)\'/, 1]}"
|
483
505
|
rescue ArgumentError => e # 1.9 exception
|
484
|
-
raise e unless e.message.include?
|
506
|
+
raise e unless e.message.include? "uncaught throw"
|
485
507
|
default += ", not #{e.message.split(/ /).last}"
|
486
508
|
rescue NameError => e # 1.8 exception
|
487
509
|
raise e unless e.name == sym
|
@@ -580,12 +602,12 @@ module Minitest
|
|
580
602
|
|
581
603
|
def exception_details e, msg
|
582
604
|
[
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
605
|
+
msg,
|
606
|
+
"Class: <#{e.class}>",
|
607
|
+
"Message: <#{e.message.inspect}>",
|
608
|
+
"---Backtrace---",
|
609
|
+
Minitest.filter_backtrace(e.backtrace),
|
610
|
+
"---------------",
|
589
611
|
].join "\n"
|
590
612
|
end
|
591
613
|
|
@@ -594,7 +616,7 @@ module Minitest
|
|
594
616
|
# you to put time-bombs in your tests if you need to keep
|
595
617
|
# something around until a later date lest you forget about it.
|
596
618
|
|
597
|
-
def fail_after y,m,d,msg
|
619
|
+
def fail_after y, m, d, msg
|
598
620
|
flunk msg if Time.now > Time.local(y, m, d)
|
599
621
|
end
|
600
622
|
|
@@ -628,7 +650,7 @@ module Minitest
|
|
628
650
|
# Fails if +test+ is truthy.
|
629
651
|
|
630
652
|
def refute test, msg = nil
|
631
|
-
msg ||= message { "Expected #{mu_pp
|
653
|
+
msg ||= message { "Expected #{mu_pp test} to not be truthy" }
|
632
654
|
assert !test, msg
|
633
655
|
end
|
634
656
|
|
@@ -636,7 +658,7 @@ module Minitest
|
|
636
658
|
# Fails if +obj+ is empty.
|
637
659
|
|
638
660
|
def refute_empty obj, msg = nil
|
639
|
-
msg = message(msg) { "Expected #{mu_pp
|
661
|
+
msg = message(msg) { "Expected #{mu_pp obj} to not be empty" }
|
640
662
|
assert_respond_to obj, :empty?
|
641
663
|
refute obj.empty?, msg
|
642
664
|
end
|
@@ -648,7 +670,7 @@ module Minitest
|
|
648
670
|
|
649
671
|
def refute_equal exp, act, msg = nil
|
650
672
|
msg = message(msg) {
|
651
|
-
"Expected #{mu_pp
|
673
|
+
"Expected #{mu_pp act} to not be equal to #{mu_pp exp}"
|
652
674
|
}
|
653
675
|
refute exp == act, msg
|
654
676
|
end
|
@@ -679,7 +701,7 @@ module Minitest
|
|
679
701
|
|
680
702
|
def refute_includes collection, obj, msg = nil
|
681
703
|
msg = message(msg) {
|
682
|
-
"Expected #{mu_pp
|
704
|
+
"Expected #{mu_pp collection} to not include #{mu_pp obj}"
|
683
705
|
}
|
684
706
|
assert_respond_to collection, :include?
|
685
707
|
refute collection.include?(obj), msg
|
@@ -690,7 +712,7 @@ module Minitest
|
|
690
712
|
|
691
713
|
def refute_instance_of cls, obj, msg = nil
|
692
714
|
msg = message(msg) {
|
693
|
-
"Expected #{mu_pp
|
715
|
+
"Expected #{mu_pp obj} to not be an instance of #{cls}"
|
694
716
|
}
|
695
717
|
refute obj.instance_of?(cls), msg
|
696
718
|
end
|
@@ -699,7 +721,7 @@ module Minitest
|
|
699
721
|
# Fails if +obj+ is a kind of +cls+.
|
700
722
|
|
701
723
|
def refute_kind_of cls, obj, msg = nil
|
702
|
-
msg = message(msg) { "Expected #{mu_pp
|
724
|
+
msg = message(msg) { "Expected #{mu_pp obj} to not be a kind of #{cls}" }
|
703
725
|
refute obj.kind_of?(cls), msg
|
704
726
|
end
|
705
727
|
|
@@ -708,7 +730,7 @@ module Minitest
|
|
708
730
|
|
709
731
|
def refute_match matcher, obj, msg = nil
|
710
732
|
msg = message(msg) { "Expected #{mu_pp matcher} to not match #{mu_pp obj}" }
|
711
|
-
assert_respond_to matcher,
|
733
|
+
assert_respond_to matcher, :=~
|
712
734
|
matcher = Regexp.new Regexp.escape matcher if String === matcher
|
713
735
|
refute matcher =~ obj, msg
|
714
736
|
end
|
@@ -717,10 +739,34 @@ module Minitest
|
|
717
739
|
# Fails if +obj+ is nil.
|
718
740
|
|
719
741
|
def refute_nil obj, msg = nil
|
720
|
-
msg = message(msg) { "Expected #{mu_pp
|
742
|
+
msg = message(msg) { "Expected #{mu_pp obj} to not be nil" }
|
721
743
|
refute obj.nil?, msg
|
722
744
|
end
|
723
745
|
|
746
|
+
##
|
747
|
+
# For testing with pattern matching (only supported with Ruby 3.0 and later)
|
748
|
+
#
|
749
|
+
# # pass
|
750
|
+
# refute_pattern { [1,2,3] => [String] }
|
751
|
+
#
|
752
|
+
# # fail "NoMatchingPatternError expected, but nothing was raised."
|
753
|
+
# refute_pattern { [1,2,3] => [Integer, Integer, Integer] }
|
754
|
+
#
|
755
|
+
# This assertion expects a NoMatchingPatternError exception, and will fail if none is raised. Any
|
756
|
+
# other exceptions will be raised as normal and generate a test error.
|
757
|
+
|
758
|
+
def refute_pattern
|
759
|
+
raise NotImplementedError, "only available in Ruby 3.0+" unless RUBY_VERSION >= "3.0"
|
760
|
+
flunk "refute_pattern requires a block to capture errors." unless block_given?
|
761
|
+
|
762
|
+
begin
|
763
|
+
yield
|
764
|
+
flunk "NoMatchingPatternError expected, but nothing was raised."
|
765
|
+
rescue NoMatchingPatternError
|
766
|
+
pass
|
767
|
+
end
|
768
|
+
end
|
769
|
+
|
724
770
|
##
|
725
771
|
# Fails if +o1+ is not +op+ +o2+. Eg:
|
726
772
|
#
|
@@ -729,7 +775,7 @@ module Minitest
|
|
729
775
|
|
730
776
|
def refute_operator o1, op, o2 = UNDEFINED, msg = nil
|
731
777
|
return refute_predicate o1, op, msg if UNDEFINED == o2
|
732
|
-
msg = message(msg) { "Expected #{mu_pp
|
778
|
+
msg = message(msg) { "Expected #{mu_pp o1} to not be #{op} #{mu_pp o2}" }
|
733
779
|
refute o1.__send__(op, o2), msg
|
734
780
|
end
|
735
781
|
|
@@ -751,17 +797,18 @@ module Minitest
|
|
751
797
|
# str.wont_be :empty?
|
752
798
|
|
753
799
|
def refute_predicate o1, op, msg = nil
|
754
|
-
msg = message(msg) { "Expected #{mu_pp
|
800
|
+
msg = message(msg) { "Expected #{mu_pp o1} to not be #{op}" }
|
755
801
|
refute o1.__send__(op), msg
|
756
802
|
end
|
757
803
|
|
758
804
|
##
|
759
805
|
# Fails if +obj+ responds to the message +meth+.
|
806
|
+
# include_all defaults to false to match Object#respond_to?
|
760
807
|
|
761
|
-
def refute_respond_to obj, meth, msg = nil
|
762
|
-
msg = message(msg) { "Expected #{mu_pp
|
808
|
+
def refute_respond_to obj, meth, msg = nil, include_all: false
|
809
|
+
msg = message(msg) { "Expected #{mu_pp obj} to not respond to #{meth}" }
|
763
810
|
|
764
|
-
refute obj.respond_to?(meth), msg
|
811
|
+
refute obj.respond_to?(meth, include_all), msg
|
765
812
|
end
|
766
813
|
|
767
814
|
##
|
@@ -780,10 +827,10 @@ module Minitest
|
|
780
827
|
# gets listed at the end of the run but doesn't cause a failure
|
781
828
|
# exit code.
|
782
829
|
|
783
|
-
def skip msg = nil,
|
830
|
+
def skip msg = nil, _ignored = nil
|
784
831
|
msg ||= "Skipped, no message given"
|
785
832
|
@skip = true
|
786
|
-
raise Minitest::Skip, msg
|
833
|
+
raise Minitest::Skip, msg
|
787
834
|
end
|
788
835
|
|
789
836
|
##
|
@@ -792,9 +839,9 @@ module Minitest
|
|
792
839
|
# date, but still holds you accountable and prevents you from
|
793
840
|
# forgetting it.
|
794
841
|
|
795
|
-
def skip_until y,m,d,msg
|
842
|
+
def skip_until y, m, d, msg
|
796
843
|
skip msg if Time.now < Time.local(y, m, d)
|
797
|
-
where = caller.first.rpartition(
|
844
|
+
where = caller(1..1).first.rpartition(":in").reject(&:empty?).first
|
798
845
|
warn "Stale skip_until %p at %s" % [msg, where]
|
799
846
|
end
|
800
847
|
|
data/lib/minitest/autorun.rb
CHANGED
data/lib/minitest/benchmark.rb
CHANGED
@@ -47,8 +47,6 @@ module Minitest
|
|
47
47
|
|
48
48
|
def self.bench_linear min, max, step = 10
|
49
49
|
(min..max).step(step).to_a
|
50
|
-
rescue LocalJumpError # 1.8.6
|
51
|
-
r = []; (min..max).step(step) { |n| r << n }; r
|
52
50
|
end
|
53
51
|
|
54
52
|
##
|
@@ -83,7 +81,7 @@ module Minitest
|
|
83
81
|
def assert_performance validation, &work
|
84
82
|
range = self.class.bench_range
|
85
83
|
|
86
|
-
io.print
|
84
|
+
io.print self.name
|
87
85
|
|
88
86
|
times = []
|
89
87
|
|
@@ -236,7 +234,7 @@ module Minitest
|
|
236
234
|
|
237
235
|
def fit_exponential xs, ys
|
238
236
|
n = xs.size
|
239
|
-
xys = xs.zip
|
237
|
+
xys = xs.zip ys
|
240
238
|
sxlny = sigma(xys) { |x, y| x * Math.log(y) }
|
241
239
|
slny = sigma(xys) { |_, y| Math.log(y) }
|
242
240
|
sx2 = sigma(xys) { |x, _| x * x }
|
@@ -258,7 +256,7 @@ module Minitest
|
|
258
256
|
|
259
257
|
def fit_logarithmic xs, ys
|
260
258
|
n = xs.size
|
261
|
-
xys = xs.zip
|
259
|
+
xys = xs.zip ys
|
262
260
|
slnx2 = sigma(xys) { |x, _| Math.log(x) ** 2 }
|
263
261
|
slnx = sigma(xys) { |x, _| Math.log(x) }
|
264
262
|
sylnx = sigma(xys) { |x, y| y * Math.log(x) }
|
@@ -280,7 +278,7 @@ module Minitest
|
|
280
278
|
|
281
279
|
def fit_linear xs, ys
|
282
280
|
n = xs.size
|
283
|
-
xys = xs.zip
|
281
|
+
xys = xs.zip ys
|
284
282
|
sx = sigma xs
|
285
283
|
sy = sigma ys
|
286
284
|
sx2 = sigma(xs) { |x| x ** 2 }
|
@@ -302,7 +300,7 @@ module Minitest
|
|
302
300
|
|
303
301
|
def fit_power xs, ys
|
304
302
|
n = xs.size
|
305
|
-
xys = xs.zip
|
303
|
+
xys = xs.zip ys
|
306
304
|
slnxlny = sigma(xys) { |x, y| Math.log(x) * Math.log(y) }
|
307
305
|
slnx = sigma(xs) { |x | Math.log(x) }
|
308
306
|
slny = sigma(ys) { | y| Math.log(y) }
|
@@ -323,7 +321,7 @@ module Minitest
|
|
323
321
|
|
324
322
|
def sigma enum, &block
|
325
323
|
enum = enum.map(&block) if block
|
326
|
-
enum.
|
324
|
+
enum.sum
|
327
325
|
end
|
328
326
|
|
329
327
|
##
|
@@ -419,7 +417,6 @@ module Minitest
|
|
419
417
|
end
|
420
418
|
end
|
421
419
|
|
422
|
-
|
423
420
|
##
|
424
421
|
# Create a benchmark that verifies that the performance is logarithmic.
|
425
422
|
#
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Minitest
|
2
|
+
##
|
3
|
+
# Compresses backtraces.
|
4
|
+
|
5
|
+
module Compress
|
6
|
+
|
7
|
+
##
|
8
|
+
# Takes a backtrace (array of strings) and compresses repeating
|
9
|
+
# cycles in it to make it more readable.
|
10
|
+
|
11
|
+
def compress orig
|
12
|
+
ary = orig
|
13
|
+
|
14
|
+
eswo = ->(a, n, off) { # each_slice_with_offset
|
15
|
+
if off.zero? then
|
16
|
+
a.each_slice n
|
17
|
+
else
|
18
|
+
# [ ...off... [...n...] [...n...] ... ]
|
19
|
+
front, back = a.take(off), a.drop(off)
|
20
|
+
[front].chain back.each_slice n
|
21
|
+
end
|
22
|
+
}
|
23
|
+
|
24
|
+
3.times do # maybe don't use loop do here?
|
25
|
+
index = ary # [ a b c b c b c d ]
|
26
|
+
.size
|
27
|
+
.times # 0...size
|
28
|
+
.group_by { |i| ary[i] } # { a: [0] b: [1 3 5], c: [2 4 6], d: [7] }
|
29
|
+
|
30
|
+
order = index
|
31
|
+
.reject { |k, v| v.size == 1 } # { b: [1 3 5], c: [2 4 6] }
|
32
|
+
.sort_by { |k, a1| ### sort by max dist + min offset
|
33
|
+
d = a1.each_cons(2).sum { |a2, b| b-a2 }
|
34
|
+
[-d, a1.first]
|
35
|
+
} # b: [1 3 5] c: [2 4 6]
|
36
|
+
|
37
|
+
ranges = order
|
38
|
+
.map { |k, a1| # [[1..2 3..4] [2..3 4..5]]
|
39
|
+
a1
|
40
|
+
.each_cons(2)
|
41
|
+
.map { |a2, b| a2..b-1 }
|
42
|
+
}
|
43
|
+
|
44
|
+
big_ranges = ranges
|
45
|
+
.flat_map { |a| # [1..2 3..4 2..3 4..5]
|
46
|
+
a.sort_by { |r| [-r.size, r.first] }.first 5
|
47
|
+
}
|
48
|
+
.first(100)
|
49
|
+
|
50
|
+
culprits = big_ranges
|
51
|
+
.map { |r|
|
52
|
+
eswo[ary, r.size, r.begin] # [o1 s1 s1 s2 s2]
|
53
|
+
.chunk_while { |a, b| a == b } # [[o1] [s1 s1] [s2 s2]]
|
54
|
+
.map { |a| [a.size, a.first] } # [[1 o1] [2 s1] [2 s2]]
|
55
|
+
}
|
56
|
+
.select { |chunks|
|
57
|
+
chunks.any? { |a| a.first > 1 } # compressed anything?
|
58
|
+
}
|
59
|
+
|
60
|
+
min = culprits
|
61
|
+
.min_by { |a| a.flatten.size } # most compressed
|
62
|
+
|
63
|
+
break unless min
|
64
|
+
|
65
|
+
ary = min.flat_map { |(n, lines)|
|
66
|
+
if n > 1 then
|
67
|
+
[[n, compress(lines)]] # [o1 [2 s1] [2 s2]]
|
68
|
+
else
|
69
|
+
lines
|
70
|
+
end
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
format = ->(lines) {
|
75
|
+
lines.flat_map { |line|
|
76
|
+
case line
|
77
|
+
when Array then
|
78
|
+
n, lines = line
|
79
|
+
lines = format[lines]
|
80
|
+
[
|
81
|
+
" +->> #{n} cycles of #{lines.size} lines:",
|
82
|
+
*lines.map { |s| " | #{s}" },
|
83
|
+
" +-<<",
|
84
|
+
]
|
85
|
+
else
|
86
|
+
line
|
87
|
+
end
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
format[ary]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|