minitest 5.20.0 → 5.25.1
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/History.rdoc +130 -3
- data/Manifest.txt +3 -0
- data/README.rdoc +16 -13
- data/Rakefile +6 -0
- data/lib/hoe/minitest.rb +2 -1
- data/lib/minitest/assertions.rb +77 -80
- 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/manual_plugins.rb +16 -0
- data/lib/minitest/mock.rb +17 -15
- data/lib/minitest/parallel.rb +5 -5
- data/lib/minitest/pride_plugin.rb +16 -23
- data/lib/minitest/spec.rb +5 -5
- data/lib/minitest/test.rb +14 -25
- data/lib/minitest/test_task.rb +17 -12
- data/lib/minitest.rb +257 -144
- data/test/minitest/metametameta.rb +32 -18
- data/test/minitest/test_minitest_assertions.rb +159 -140
- data/test/minitest/test_minitest_benchmark.rb +1 -1
- data/test/minitest/test_minitest_mock.rb +80 -75
- data/test/minitest/test_minitest_reporter.rb +111 -16
- data/test/minitest/test_minitest_spec.rb +54 -55
- data/test/minitest/test_minitest_test.rb +191 -117
- data/test/minitest/test_minitest_test_task.rb +18 -7
- data.tar.gz.sig +0 -0
- metadata +17 -13
- 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
|
|
@@ -393,7 +389,7 @@ module Minitest
|
|
393
389
|
# str.must_be :empty?
|
394
390
|
|
395
391
|
def assert_predicate o1, op, msg = nil
|
396
|
-
msg = message(msg) { "Expected #{mu_pp
|
392
|
+
msg = message(msg) { "Expected #{mu_pp o1} to be #{op}" }
|
397
393
|
assert o1.__send__(op), msg
|
398
394
|
end
|
399
395
|
|
@@ -438,23 +434,24 @@ module Minitest
|
|
438
434
|
raise
|
439
435
|
rescue Exception => e
|
440
436
|
flunk proc {
|
441
|
-
exception_details(e, "#{msg}#{mu_pp
|
437
|
+
exception_details(e, "#{msg}#{mu_pp exp} exception expected, not")
|
442
438
|
}
|
443
439
|
end
|
444
440
|
|
445
441
|
exp = exp.first if exp.size == 1
|
446
442
|
|
447
|
-
flunk "#{msg}#{mu_pp
|
443
|
+
flunk "#{msg}#{mu_pp exp} expected but nothing was raised."
|
448
444
|
end
|
449
445
|
|
450
446
|
##
|
451
447
|
# Fails unless +obj+ responds to +meth+.
|
448
|
+
# include_all defaults to false to match Object#respond_to?
|
452
449
|
|
453
|
-
def assert_respond_to obj, meth, msg = nil
|
450
|
+
def assert_respond_to obj, meth, msg = nil, include_all: false
|
454
451
|
msg = message(msg) {
|
455
|
-
"Expected #{mu_pp
|
452
|
+
"Expected #{mu_pp obj} (#{obj.class}) to respond to ##{meth}"
|
456
453
|
}
|
457
|
-
assert obj.respond_to?(meth), msg
|
454
|
+
assert obj.respond_to?(meth, include_all), msg
|
458
455
|
end
|
459
456
|
|
460
457
|
##
|
@@ -474,13 +471,12 @@ module Minitest
|
|
474
471
|
# Fails unless the call returns a true value
|
475
472
|
|
476
473
|
def assert_send send_ary, m = nil
|
477
|
-
|
478
|
-
where = where.split(/:in /, 2).first # clean up noise
|
479
|
-
warn "DEPRECATED: assert_send. From #{where}"
|
474
|
+
warn "DEPRECATED: assert_send. From #{_where}"
|
480
475
|
|
481
476
|
recv, msg, *args = send_ary
|
482
477
|
m = message(m) {
|
483
|
-
"Expected #{mu_pp
|
478
|
+
"Expected #{mu_pp recv}.#{msg}(*#{mu_pp args}) to return true"
|
479
|
+
}
|
484
480
|
assert recv.__send__(msg, *args), m
|
485
481
|
end
|
486
482
|
|
@@ -499,15 +495,15 @@ module Minitest
|
|
499
495
|
# Fails unless the block throws +sym+
|
500
496
|
|
501
497
|
def assert_throws sym, msg = nil
|
502
|
-
default = "Expected #{mu_pp
|
498
|
+
default = "Expected #{mu_pp sym} to have been thrown"
|
503
499
|
caught = true
|
504
|
-
value = catch
|
500
|
+
value = catch sym do
|
505
501
|
begin
|
506
502
|
yield
|
507
503
|
rescue ThreadError => e # wtf?!? 1.8 + threads == suck
|
508
|
-
default += ", not
|
504
|
+
default += ", not :#{e.message[/uncaught throw \`(\w+?)\'/, 1]}"
|
509
505
|
rescue ArgumentError => e # 1.9 exception
|
510
|
-
raise e unless e.message.include?
|
506
|
+
raise e unless e.message.include? "uncaught throw"
|
511
507
|
default += ", not #{e.message.split(/ /).last}"
|
512
508
|
rescue NameError => e # 1.8 exception
|
513
509
|
raise e unless e.name == sym
|
@@ -606,12 +602,12 @@ module Minitest
|
|
606
602
|
|
607
603
|
def exception_details e, msg
|
608
604
|
[
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
605
|
+
msg,
|
606
|
+
"Class: <#{e.class}>",
|
607
|
+
"Message: <#{e.message.inspect}>",
|
608
|
+
"---Backtrace---",
|
609
|
+
Minitest.filter_backtrace(e.backtrace),
|
610
|
+
"---------------",
|
615
611
|
].join "\n"
|
616
612
|
end
|
617
613
|
|
@@ -620,7 +616,7 @@ module Minitest
|
|
620
616
|
# you to put time-bombs in your tests if you need to keep
|
621
617
|
# something around until a later date lest you forget about it.
|
622
618
|
|
623
|
-
def fail_after y,m,d,msg
|
619
|
+
def fail_after y, m, d, msg
|
624
620
|
flunk msg if Time.now > Time.local(y, m, d)
|
625
621
|
end
|
626
622
|
|
@@ -654,7 +650,7 @@ module Minitest
|
|
654
650
|
# Fails if +test+ is truthy.
|
655
651
|
|
656
652
|
def refute test, msg = nil
|
657
|
-
msg ||= message { "Expected #{mu_pp
|
653
|
+
msg ||= message { "Expected #{mu_pp test} to not be truthy" }
|
658
654
|
assert !test, msg
|
659
655
|
end
|
660
656
|
|
@@ -662,7 +658,7 @@ module Minitest
|
|
662
658
|
# Fails if +obj+ is empty.
|
663
659
|
|
664
660
|
def refute_empty obj, msg = nil
|
665
|
-
msg = message(msg) { "Expected #{mu_pp
|
661
|
+
msg = message(msg) { "Expected #{mu_pp obj} to not be empty" }
|
666
662
|
assert_respond_to obj, :empty?
|
667
663
|
refute obj.empty?, msg
|
668
664
|
end
|
@@ -674,7 +670,7 @@ module Minitest
|
|
674
670
|
|
675
671
|
def refute_equal exp, act, msg = nil
|
676
672
|
msg = message(msg) {
|
677
|
-
"Expected #{mu_pp
|
673
|
+
"Expected #{mu_pp act} to not be equal to #{mu_pp exp}"
|
678
674
|
}
|
679
675
|
refute exp == act, msg
|
680
676
|
end
|
@@ -705,7 +701,7 @@ module Minitest
|
|
705
701
|
|
706
702
|
def refute_includes collection, obj, msg = nil
|
707
703
|
msg = message(msg) {
|
708
|
-
"Expected #{mu_pp
|
704
|
+
"Expected #{mu_pp collection} to not include #{mu_pp obj}"
|
709
705
|
}
|
710
706
|
assert_respond_to collection, :include?
|
711
707
|
refute collection.include?(obj), msg
|
@@ -716,7 +712,7 @@ module Minitest
|
|
716
712
|
|
717
713
|
def refute_instance_of cls, obj, msg = nil
|
718
714
|
msg = message(msg) {
|
719
|
-
"Expected #{mu_pp
|
715
|
+
"Expected #{mu_pp obj} to not be an instance of #{cls}"
|
720
716
|
}
|
721
717
|
refute obj.instance_of?(cls), msg
|
722
718
|
end
|
@@ -725,7 +721,7 @@ module Minitest
|
|
725
721
|
# Fails if +obj+ is a kind of +cls+.
|
726
722
|
|
727
723
|
def refute_kind_of cls, obj, msg = nil
|
728
|
-
msg = message(msg) { "Expected #{mu_pp
|
724
|
+
msg = message(msg) { "Expected #{mu_pp obj} to not be a kind of #{cls}" }
|
729
725
|
refute obj.kind_of?(cls), msg
|
730
726
|
end
|
731
727
|
|
@@ -734,7 +730,7 @@ module Minitest
|
|
734
730
|
|
735
731
|
def refute_match matcher, obj, msg = nil
|
736
732
|
msg = message(msg) { "Expected #{mu_pp matcher} to not match #{mu_pp obj}" }
|
737
|
-
assert_respond_to matcher,
|
733
|
+
assert_respond_to matcher, :=~
|
738
734
|
matcher = Regexp.new Regexp.escape matcher if String === matcher
|
739
735
|
refute matcher =~ obj, msg
|
740
736
|
end
|
@@ -743,7 +739,7 @@ module Minitest
|
|
743
739
|
# Fails if +obj+ is nil.
|
744
740
|
|
745
741
|
def refute_nil obj, msg = nil
|
746
|
-
msg = message(msg) { "Expected #{mu_pp
|
742
|
+
msg = message(msg) { "Expected #{mu_pp obj} to not be nil" }
|
747
743
|
refute obj.nil?, msg
|
748
744
|
end
|
749
745
|
|
@@ -765,7 +761,7 @@ module Minitest
|
|
765
761
|
|
766
762
|
begin
|
767
763
|
yield
|
768
|
-
flunk
|
764
|
+
flunk "NoMatchingPatternError expected, but nothing was raised."
|
769
765
|
rescue NoMatchingPatternError
|
770
766
|
pass
|
771
767
|
end
|
@@ -779,7 +775,7 @@ module Minitest
|
|
779
775
|
|
780
776
|
def refute_operator o1, op, o2 = UNDEFINED, msg = nil
|
781
777
|
return refute_predicate o1, op, msg if UNDEFINED == o2
|
782
|
-
msg = message(msg) { "Expected #{mu_pp
|
778
|
+
msg = message(msg) { "Expected #{mu_pp o1} to not be #{op} #{mu_pp o2}" }
|
783
779
|
refute o1.__send__(op, o2), msg
|
784
780
|
end
|
785
781
|
|
@@ -801,17 +797,18 @@ module Minitest
|
|
801
797
|
# str.wont_be :empty?
|
802
798
|
|
803
799
|
def refute_predicate o1, op, msg = nil
|
804
|
-
msg = message(msg) { "Expected #{mu_pp
|
800
|
+
msg = message(msg) { "Expected #{mu_pp o1} to not be #{op}" }
|
805
801
|
refute o1.__send__(op), msg
|
806
802
|
end
|
807
803
|
|
808
804
|
##
|
809
805
|
# Fails if +obj+ responds to the message +meth+.
|
806
|
+
# include_all defaults to false to match Object#respond_to?
|
810
807
|
|
811
|
-
def refute_respond_to obj, meth, msg = nil
|
812
|
-
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}" }
|
813
810
|
|
814
|
-
refute obj.respond_to?(meth), msg
|
811
|
+
refute obj.respond_to?(meth, include_all), msg
|
815
812
|
end
|
816
813
|
|
817
814
|
##
|
@@ -830,10 +827,10 @@ module Minitest
|
|
830
827
|
# gets listed at the end of the run but doesn't cause a failure
|
831
828
|
# exit code.
|
832
829
|
|
833
|
-
def skip msg = nil,
|
830
|
+
def skip msg = nil, _ignored = nil
|
834
831
|
msg ||= "Skipped, no message given"
|
835
832
|
@skip = true
|
836
|
-
raise Minitest::Skip, msg
|
833
|
+
raise Minitest::Skip, msg
|
837
834
|
end
|
838
835
|
|
839
836
|
##
|
@@ -842,9 +839,9 @@ module Minitest
|
|
842
839
|
# date, but still holds you accountable and prevents you from
|
843
840
|
# forgetting it.
|
844
841
|
|
845
|
-
def skip_until y,m,d,msg
|
842
|
+
def skip_until y, m, d, msg
|
846
843
|
skip msg if Time.now < Time.local(y, m, d)
|
847
|
-
where = caller.first.rpartition(
|
844
|
+
where = caller(1..1).first.rpartition(":in").reject(&:empty?).first
|
848
845
|
warn "Stale skip_until %p at %s" % [msg, where]
|
849
846
|
end
|
850
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
|