minitest 5.20.0 → 5.22.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 667a803a272949e7b05440f91a56155ea3977a5b9d364542801889c5a2fe0ff0
4
- data.tar.gz: 862bf0ff3d24eea4bbe6c7f435ceef19aaa97748f6a87ec3fa51dc218ca79298
3
+ metadata.gz: 4e826dd27ec8fd1c38cb81a0323e2f16463119c10a4f15838c32d539a8ff2940
4
+ data.tar.gz: f6d5799c7399ceafdd07825931b705d66503828c2269df50d60241a012495982
5
5
  SHA512:
6
- metadata.gz: 2284c84ae5f98a3454e9a95417e609ca1a8ef9af8ee8b1fad8f2aca2632fde6a309e266ef1d399d9a7d47337cdcba696500a1b36f1fa7d952615eb390a89e329
7
- data.tar.gz: a76204f74c2caf693a4302065815b871863ae655372d25fc4d41e416b0d4935704c1e1068457b5cda934312e3915ae8a27595ca962c98e544dd45b54cac2aef7
6
+ metadata.gz: f4483bded8417061d3552c03c4a13422e280c7c71ecb3e37e346c29d0b910205794bb5e84ff5c3ccfb0daf27f399ac3cf669f1d508608338c1ac6029efe32549
7
+ data.tar.gz: 891b15d02dee4a0bf11d76963f887db4daca5840653aa7d89eaa47a6356fd14737bb25f613af5e7695c54ead3382c328837618b1ffd6fbee1fa4d7f4a7625c67
checksums.yaml.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,53 @@
1
+ === 5.22.1 / 2024-02-06
2
+
3
+ * 1 bug fix:
4
+
5
+ * Don't exit non-zero if no tests ran and no filter (aka, the test file is empty).
6
+ (I'm starting to think the exit 1 thing for @tenderlove was a mistake...)
7
+
8
+ === 5.22.0 / 2024-02-05
9
+
10
+ * 1 minor enhancement:
11
+
12
+ * Added "did you mean" output if your --name filter matches nothing. (tenderlove)
13
+
14
+ * 2 bug fixes:
15
+
16
+ * Big cleanup of test filtering. Much prettier / more functional.
17
+ * Fix situation where Assertion#location can't find the location. (pftg)
18
+
19
+ === 5.21.2 / 2024-01-17
20
+
21
+ * 1 bug fix:
22
+
23
+ * Fixed bug in Minitest::Compress#compress formatting w/ nested patterns. Now recurses properly.
24
+
25
+ === 5.21.1 / 2024-01-11
26
+
27
+ * 1 bug fix:
28
+
29
+ * Rails' default backtrace filter can't currently work with caller_locations, so reverting back to caller.
30
+
31
+ === 5.21.0 / 2024-01-11
32
+
33
+ * 10 minor enhancements:
34
+
35
+ * Add include_all kw arg to assert_respond_to and refute_respond_to.
36
+ * Added --quiet flag to skip ProgressReporter (prints the dots). Minor speedup.
37
+ * Added Minitest::Compress#compress and added it to UnexpectedError.
38
+ * Added ability to initialize BacktraceFilter w/ custom regexp.
39
+ * Filter failure backtraces using backtrace_filter before calculating location. (thomasmarshall)
40
+ * Make BacktraceFilter#filter compatible with locations (still compares strings).
41
+ * Optimized Assertion#location ~30%.
42
+ * Output relative paths for all failures/errors/backtraces.
43
+ * Refactored location information in assertions, now using locations.
44
+ * Removed thread and mutex_m dependencies. (hsbt, eregon)
45
+
46
+ * 2 bug fixes:
47
+
48
+ * Drop undocumented bt arg in #skip. Dunno why that ever happened, prolly for testing?
49
+ * Fix mock to work with ruby debugger enabled. (keithlayne)
50
+
1
51
  === 5.20.0 / 2023-09-06
2
52
 
3
53
  * 1 minor enhancement:
@@ -9,7 +59,7 @@
9
59
  * 2 minor enhancements:
10
60
 
11
61
  * Add metadata lazy accessor to Runnable / Result. (matteeyah)
12
- * Only load minitest/unit (aka ancient MiniTest compatibility layer) if ENV["MT_COMPAT"]
62
+ * Only load minitest/unit (aka ancient MiniTest compatibility layer) if \ENV[\"MT_COMPAT\"]
13
63
 
14
64
  * 1 bug fix:
15
65
 
@@ -20,7 +70,7 @@
20
70
  * 3 bug fixes:
21
71
 
22
72
  * Avoid extra string allocations when filtering tests. (tenderlove)
23
- * Only mention deprecated ENV['N'] if it is an integer string.
73
+ * Only mention deprecated \ENV[\'N\'] if it is an integer string.
24
74
  * Push up test_order to Minitest::Runnable to fix minitest/hell. (koic)
25
75
 
26
76
  === 5.18.0 / 2023-03-04
@@ -214,7 +264,7 @@
214
264
 
215
265
  * 3 bug fixes:
216
266
 
217
- * Check `option[:filter]` klass before match. Fixes 2.6 warning. (y-yagi)
267
+ * Check \option[:filter] klass before match. Fixes 2.6 warning. (y-yagi)
218
268
  * Fixed Assertions#diff from recalculating if set to nil
219
269
  * Fixed spec section of readme to not use deprecated global expectations. (CheezItMan)
220
270
 
data/Manifest.txt CHANGED
@@ -9,6 +9,7 @@ lib/minitest.rb
9
9
  lib/minitest/assertions.rb
10
10
  lib/minitest/autorun.rb
11
11
  lib/minitest/benchmark.rb
12
+ lib/minitest/compress.rb
12
13
  lib/minitest/expectations.rb
13
14
  lib/minitest/hell.rb
14
15
  lib/minitest/mock.rb
data/README.rdoc CHANGED
@@ -3,6 +3,7 @@
3
3
  home :: https://github.com/minitest/minitest
4
4
  bugs :: https://github.com/minitest/minitest/issues
5
5
  rdoc :: https://docs.seattlerb.org/minitest
6
+ clog :: https://github.com/minitest/minitest/blob/master/History.rdoc
6
7
  vim :: https://github.com/sunaku/vim-ruby-minitest
7
8
  emacs:: https://github.com/arthurnn/minitest-emacs
8
9
 
@@ -198,6 +198,11 @@ module Minitest
198
198
  assert obj.empty?, msg
199
199
  end
200
200
 
201
+ def _where # :nodoc:
202
+ where = Minitest.filter_backtrace(caller).first
203
+ where = where.split(/:in /, 2).first # clean up noise
204
+ end
205
+
201
206
  E = "" # :nodoc:
202
207
 
203
208
  ##
@@ -221,10 +226,7 @@ module Minitest
221
226
  if Minitest::VERSION =~ /^6/ then
222
227
  refute_nil exp, "Use assert_nil if expecting nil."
223
228
  else
224
- where = Minitest.filter_backtrace(caller).first
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."
229
+ warn "DEPRECATED: Use assert_nil if expecting nil from #{_where}. This will fail in Minitest 6."
228
230
  end
229
231
  end
230
232
 
@@ -449,12 +451,13 @@ module Minitest
449
451
 
450
452
  ##
451
453
  # Fails unless +obj+ responds to +meth+.
454
+ # include_all defaults to false to match Object#respond_to?
452
455
 
453
- def assert_respond_to obj, meth, msg = nil
456
+ def assert_respond_to obj, meth, msg = nil, include_all: false
454
457
  msg = message(msg) {
455
458
  "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}"
456
459
  }
457
- assert obj.respond_to?(meth), msg
460
+ assert obj.respond_to?(meth, include_all), msg
458
461
  end
459
462
 
460
463
  ##
@@ -474,9 +477,7 @@ module Minitest
474
477
  # Fails unless the call returns a true value
475
478
 
476
479
  def assert_send send_ary, m = nil
477
- where = Minitest.filter_backtrace(caller).first
478
- where = where.split(/:in /, 2).first # clean up noise
479
- warn "DEPRECATED: assert_send. From #{where}"
480
+ warn "DEPRECATED: assert_send. From #{_where}"
480
481
 
481
482
  recv, msg, *args = send_ary
482
483
  m = message(m) {
@@ -807,11 +808,12 @@ module Minitest
807
808
 
808
809
  ##
809
810
  # Fails if +obj+ responds to the message +meth+.
811
+ # include_all defaults to false to match Object#respond_to?
810
812
 
811
- def refute_respond_to obj, meth, msg = nil
813
+ def refute_respond_to obj, meth, msg = nil, include_all: false
812
814
  msg = message(msg) { "Expected #{mu_pp(obj)} to not respond to #{meth}" }
813
815
 
814
- refute obj.respond_to?(meth), msg
816
+ refute obj.respond_to?(meth, include_all), msg
815
817
  end
816
818
 
817
819
  ##
@@ -830,10 +832,10 @@ module Minitest
830
832
  # gets listed at the end of the run but doesn't cause a failure
831
833
  # exit code.
832
834
 
833
- def skip msg = nil, bt = caller
835
+ def skip msg = nil, _ignored = nil
834
836
  msg ||= "Skipped, no message given"
835
837
  @skip = true
836
- raise Minitest::Skip, msg, bt
838
+ raise Minitest::Skip, msg
837
839
  end
838
840
 
839
841
  ##
@@ -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 = ->(ary, n, off) { # each_slice_with_offset
15
+ if off.zero? then
16
+ ary.each_slice n
17
+ else
18
+ # [ ...off... [...n...] [...n...] ... ]
19
+ front, back = ary.take(off), ary.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, ary| ### sort by max dist + min offset
33
+ d = ary.each_cons(2).sum { |a, b| b-a }
34
+ [-d, ary.first]
35
+ } # b: [1 3 5] c: [2 4 6]
36
+
37
+ ranges = order
38
+ .map { |k, ary| # [[1..2 3..4] [2..3 4..5]]
39
+ ary
40
+ .each_cons(2)
41
+ .map { |a, b| a..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
data/lib/minitest/mock.rb CHANGED
@@ -10,7 +10,7 @@ module Minitest # :nodoc:
10
10
  class Mock
11
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,8 +23,10 @@ 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|
@@ -288,7 +288,6 @@ end
288
288
 
289
289
  class Integer # :nodoc:
290
290
  def threads_do(jobs) # :nodoc:
291
- require "thread"
292
291
  q = Work.new jobs
293
292
 
294
293
  self.times.map {
data/lib/minitest.rb CHANGED
@@ -1,15 +1,15 @@
1
1
  require "optparse"
2
- require "thread"
3
- require "mutex_m"
4
- require "minitest/parallel"
5
2
  require "stringio"
6
3
  require "etc"
7
4
 
5
+ require_relative "minitest/parallel"
6
+ require_relative "minitest/compress"
7
+
8
8
  ##
9
9
  # :include: README.rdoc
10
10
 
11
11
  module Minitest
12
- VERSION = "5.20.0" # :nodoc:
12
+ VERSION = "5.22.1" # :nodoc:
13
13
 
14
14
  @@installed_at_exit ||= false
15
15
  @@after_run = []
@@ -134,7 +134,7 @@ module Minitest
134
134
  # Minitest.run(args)
135
135
  # Minitest.__run(reporter, options)
136
136
  # Runnable.runnables.each
137
- # runnable.run(reporter, options)
137
+ # runnable_klass.run(reporter, options)
138
138
  # self.runnable_methods.each
139
139
  # self.run_one_method(self, runnable_method, reporter)
140
140
  # Minitest.run_one_method(klass, runnable_method)
@@ -150,7 +150,7 @@ module Minitest
150
150
 
151
151
  reporter = CompositeReporter.new
152
152
  reporter << SummaryReporter.new(options[:io], options)
153
- reporter << ProgressReporter.new(options[:io], options)
153
+ reporter << ProgressReporter.new(options[:io], options) unless options[:quiet]
154
154
 
155
155
  self.reporter = reporter # this makes it available to plugins
156
156
  self.init_plugins options
@@ -164,11 +164,34 @@ module Minitest
164
164
  warn "Interrupted. Exiting..."
165
165
  end
166
166
  self.parallel_executor.shutdown
167
+
168
+ # might have been removed/replaced during init_plugins:
169
+ summary = reporter.reporters.grep(SummaryReporter).first
170
+ return empty_run! options if summary && summary.count == 0
171
+
167
172
  reporter.report
168
173
 
169
174
  reporter.passed?
170
175
  end
171
176
 
177
+ def self.empty_run! options # :nodoc:
178
+ filter = options[:filter]
179
+ return true unless filter # no filter, but nothing ran == success
180
+
181
+ warn "Nothing ran for filter: %s" % [filter]
182
+
183
+ require "did_you_mean" # soft dependency, punt if it doesn't load
184
+
185
+ ms = Runnable.runnables.flat_map(&:runnable_methods)
186
+ cs = DidYouMean::SpellChecker.new(dictionary: ms).correct filter
187
+
188
+ warn DidYouMean::Formatter.message_for cs unless cs.empty?
189
+ rescue LoadError
190
+ # do nothing
191
+ ensure
192
+ return false
193
+ end
194
+
172
195
  ##
173
196
  # Internal run method. Responsible for telling all Runnable
174
197
  # sub-classes to run.
@@ -212,6 +235,10 @@ module Minitest
212
235
  options[:verbose] = true
213
236
  end
214
237
 
238
+ opts.on "-q", "--quiet", "Quiet. Show no progress processing files." do
239
+ options[:quiet] = true
240
+ end
241
+
215
242
  opts.on "--show-skips", "Show skipped at the end of run." do
216
243
  options[:show_skips] = true
217
244
  end
@@ -334,25 +361,15 @@ module Minitest
334
361
  # reporter to record.
335
362
 
336
363
  def self.run reporter, options = {}
337
- filtered_methods = if options[:filter]
338
- filter = options[:filter]
339
- filter = Regexp.new $1 if filter.is_a?(String) && filter =~ %r%/(.*)/%
340
-
341
- self.runnable_methods.find_all { |m|
342
- filter === m || filter === "#{self}##{m}"
343
- }
344
- else
345
- self.runnable_methods
346
- end
364
+ pos = options[:filter]
365
+ neg = options[:exclude]
347
366
 
348
- if options[:exclude]
349
- exclude = options[:exclude]
350
- exclude = Regexp.new $1 if exclude =~ %r%/(.*)/%
367
+ pos = Regexp.new $1 if pos.is_a?(String) && pos =~ %r%/(.*)/%
368
+ neg = Regexp.new $1 if neg.is_a?(String) && neg =~ %r%/(.*)/%
351
369
 
352
- filtered_methods.delete_if { |m|
353
- exclude === m || exclude === "#{self}##{m}"
354
- }
355
- end
370
+ filtered_methods = self.runnable_methods
371
+ .select { |m| !pos || pos === m || pos === "#{self}##{m}" }
372
+ .reject { |m| neg && (neg === m || neg === "#{self}##{m}") }
356
373
 
357
374
  return if filtered_methods.empty?
358
375
 
@@ -525,12 +542,14 @@ module Minitest
525
542
  not self.failure
526
543
  end
527
544
 
545
+ BASE_DIR = "#{Dir.pwd}/" # :nodoc:
546
+
528
547
  ##
529
548
  # The location identifier of this test. Depends on a method
530
549
  # existing called class_name.
531
550
 
532
551
  def location
533
- loc = " [#{self.failure.location}]" unless passed? or error?
552
+ loc = " [#{self.failure.location.delete_prefix BASE_DIR}]" unless passed? or error?
534
553
  "#{self.class_name}##{self.name}#{loc}"
535
554
  end
536
555
 
@@ -619,7 +638,10 @@ module Minitest
619
638
  # you want. Go nuts.
620
639
 
621
640
  class AbstractReporter
622
- include Mutex_m
641
+
642
+ def initialize # :nodoc:
643
+ @mutex = Mutex.new
644
+ end
623
645
 
624
646
  ##
625
647
  # Starts reporting on the run.
@@ -655,6 +677,10 @@ module Minitest
655
677
  def passed?
656
678
  true
657
679
  end
680
+
681
+ def synchronize(&block) # :nodoc:
682
+ @mutex.synchronize(&block)
683
+ end
658
684
  end
659
685
 
660
686
  class Reporter < AbstractReporter # :nodoc:
@@ -828,7 +854,7 @@ module Minitest
828
854
  io.puts "# Running:"
829
855
  io.puts
830
856
 
831
- self.sync = io.respond_to? :"sync=" # stupid emacs
857
+ self.sync = io.respond_to? :"sync="
832
858
  self.old_sync, io.sync = io.sync, true if self.sync
833
859
  end
834
860
 
@@ -936,6 +962,8 @@ module Minitest
936
962
  # Represents run failures.
937
963
 
938
964
  class Assertion < Exception
965
+ RE = /in .(?:assert|refute|flunk|pass|fail|raise|must|wont)/ # :nodoc:
966
+
939
967
  def error # :nodoc:
940
968
  self
941
969
  end
@@ -944,12 +972,11 @@ module Minitest
944
972
  # Where was this run before an assertion was raised?
945
973
 
946
974
  def location
947
- last_before_assertion = ""
948
- self.backtrace.reverse_each do |s|
949
- break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
950
- last_before_assertion = s
951
- end
952
- last_before_assertion.sub(/:in .*$/, "")
975
+ bt = Minitest.filter_backtrace self.backtrace
976
+ idx = bt.rindex { |s| s.match? RE } || -1 # fall back to first item
977
+ loc = bt[idx+1] || bt.last || "unknown:-1"
978
+
979
+ loc.sub(/:in .*$/, "")
953
980
  end
954
981
 
955
982
  def result_code # :nodoc:
@@ -974,11 +1001,21 @@ module Minitest
974
1001
  # Assertion wrapping an unexpected error that was raised during a run.
975
1002
 
976
1003
  class UnexpectedError < Assertion
1004
+ include Minitest::Compress
1005
+
977
1006
  # TODO: figure out how to use `cause` instead
978
1007
  attr_accessor :error # :nodoc:
979
1008
 
980
1009
  def initialize error # :nodoc:
981
1010
  super "Unexpected exception"
1011
+
1012
+ if SystemStackError === error then
1013
+ bt = error.backtrace
1014
+ new_bt = compress bt
1015
+ error = error.exception "#{bt.size} -> #{new_bt.size}"
1016
+ error.set_backtrace new_bt
1017
+ end
1018
+
982
1019
  self.error = error
983
1020
  end
984
1021
 
@@ -986,8 +1023,11 @@ module Minitest
986
1023
  self.error.backtrace
987
1024
  end
988
1025
 
1026
+ BASE_RE = %r%#{Dir.pwd}/% # :nodoc:
1027
+
989
1028
  def message # :nodoc:
990
- bt = Minitest.filter_backtrace(self.backtrace).join "\n "
1029
+ bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
1030
+ .gsub(BASE_RE, "")
991
1031
  "#{self.error.class}: #{self.error.message}\n #{bt}"
992
1032
  end
993
1033
 
@@ -1071,6 +1111,12 @@ module Minitest
1071
1111
 
1072
1112
  MT_RE = %r%lib/minitest% #:nodoc:
1073
1113
 
1114
+ attr_accessor :regexp
1115
+
1116
+ def initialize regexp = MT_RE
1117
+ self.regexp = regexp
1118
+ end
1119
+
1074
1120
  ##
1075
1121
  # Filter +bt+ to something useful. Returns the whole thing if
1076
1122
  # $DEBUG (ruby) or $MT_DEBUG (env).
@@ -1080,9 +1126,9 @@ module Minitest
1080
1126
 
1081
1127
  return bt.dup if $DEBUG || ENV["MT_DEBUG"]
1082
1128
 
1083
- new_bt = bt.take_while { |line| line !~ MT_RE }
1084
- new_bt = bt.select { |line| line !~ MT_RE } if new_bt.empty?
1085
- new_bt = bt.dup if new_bt.empty?
1129
+ new_bt = bt.take_while { |line| line.to_s !~ regexp }
1130
+ new_bt = bt.select { |line| line.to_s !~ regexp } if new_bt.empty?
1131
+ new_bt = bt.dup if new_bt.empty?
1086
1132
 
1087
1133
  new_bt
1088
1134
  end
@@ -8,16 +8,17 @@ class Minitest::Test
8
8
  end
9
9
 
10
10
  def with_empty_backtrace_filter
11
- original = Minitest.backtrace_filter
12
-
13
- obj = Minitest::BacktraceFilter.new
14
- def obj.filter _bt
15
- []
11
+ with_backtrace_filter Minitest::BacktraceFilter.new %r%.% do
12
+ yield
16
13
  end
14
+ end
15
+
16
+ def with_backtrace_filter filter
17
+ original = Minitest.backtrace_filter
17
18
 
18
19
  Minitest::Test.io_lock.synchronize do # try not to trounce in parallel
19
20
  begin
20
- Minitest.backtrace_filter = obj
21
+ Minitest.backtrace_filter = filter
21
22
  yield
22
23
  ensure
23
24
  Minitest.backtrace_filter = original
@@ -105,15 +106,17 @@ class MetaMetaMetaTestCase < Minitest::Test
105
106
  output.gsub!(/0x[A-Fa-f0-9]+/, "0xXXX")
106
107
  output.gsub!(/ +$/, "")
107
108
 
109
+ file = ->(s) { s.start_with?("/") ? "FULLFILE" : "FILE" }
110
+
108
111
  if windows? then
109
112
  output.gsub!(/\[(?:[A-Za-z]:)?[^\]:]+:\d+\]/, "[FILE:LINE]")
110
113
  output.gsub!(/^(\s+)(?:[A-Za-z]:)?[^:]+:\d+:in/, '\1FILE:LINE:in')
111
114
  else
112
- output.gsub!(/\[[^\]:]+:\d+\]/, "[FILE:LINE]")
113
- output.gsub!(/^(\s+)[^:]+:\d+:in/, '\1FILE:LINE:in')
115
+ output.gsub!(/\[([^\]:]+):\d+\]/) { "[#{file[$1]}:LINE]" }
116
+ output.gsub!(/^(\s+)([^:]+):\d+:in/) { "#{$1}#{file[$2]}:LINE:in" }
114
117
  end
115
118
 
116
- output.gsub!(/( at )[^:]+:\d+/, '\1[FILE:LINE]')
119
+ output.gsub!(/( at )[^:]+:\d+/) { "#{$1}[#{file[$2]}:LINE]" } # eval?
117
120
 
118
121
  output
119
122
  end
@@ -936,6 +936,16 @@ class TestMinitestAssertions < Minitest::Test
936
936
  end
937
937
  end
938
938
 
939
+ def test_assert_respond_to__include_all
940
+ @tc.assert_respond_to @tc, :exit, include_all: true
941
+ end
942
+
943
+ def test_assert_respond_to__include_all_triggered
944
+ assert_triggered(/Expected .+::DummyTest. to respond to #exit\?/) do
945
+ @tc.assert_respond_to @tc, :exit?, include_all: true
946
+ end
947
+ end
948
+
939
949
  def test_assert_same
940
950
  @assertion_count = 3
941
951
 
@@ -1153,18 +1163,14 @@ class TestMinitestAssertions < Minitest::Test
1153
1163
  def test_class_asserts_match_refutes
1154
1164
  @assertion_count = 0
1155
1165
 
1156
- methods = Minitest::Assertions.public_instance_methods
1157
- methods.map!(&:to_s) if Symbol === methods.first
1166
+ methods = Minitest::Assertions.public_instance_methods.map(&:to_s)
1158
1167
 
1159
1168
  # These don't have corresponding refutes _on purpose_. They're
1160
1169
  # useless and will never be added, so don't bother.
1161
1170
  ignores = %w[assert_output assert_raises assert_send
1162
1171
  assert_silent assert_throws assert_mock]
1163
1172
 
1164
- # These are test/unit methods. I'm not actually sure why they're still here
1165
- ignores += %w[assert_no_match assert_not_equal assert_not_nil
1166
- assert_not_same assert_nothing_raised
1167
- assert_nothing_thrown assert_raise]
1173
+ ignores += %w[assert_allocations] # for minitest-gcstats
1168
1174
 
1169
1175
  asserts = methods.grep(/^assert/).sort - ignores
1170
1176
  refutes = methods.grep(/^refute/).sort - ignores
@@ -1444,6 +1450,16 @@ class TestMinitestAssertions < Minitest::Test
1444
1450
  end
1445
1451
  end
1446
1452
 
1453
+ def test_refute_respond_to__include_all
1454
+ @tc.refute_respond_to "blah", :missing, include_all: true
1455
+ end
1456
+
1457
+ def test_refute_respond_to__include_all_triggered
1458
+ assert_triggered(/Expected .*DummyTest.* to not respond to exit./) do
1459
+ @tc.refute_respond_to @tc, :exit, include_all: true
1460
+ end
1461
+ end
1462
+
1447
1463
  def test_refute_same
1448
1464
  @tc.refute_same 1, 2
1449
1465
  end
@@ -48,6 +48,25 @@ class TestMinitestReporter < MetaMetaMetaTestCase
48
48
  @et
49
49
  end
50
50
 
51
+ def system_stack_error_test
52
+ unless defined? @sse then
53
+
54
+ ex = SystemStackError.new
55
+
56
+ pre = ("a".."c").to_a
57
+ mid = ("aa".."ad").to_a * 67
58
+ post = ("d".."f").to_a
59
+ ary = pre + mid + post
60
+
61
+ ex.set_backtrace ary
62
+
63
+ @sse = Minitest::Test.new(:woot)
64
+ @sse.failures << Minitest::UnexpectedError.new(ex)
65
+ @sse = Minitest::Result.from @sse
66
+ end
67
+ @sse
68
+ end
69
+
51
70
  def fail_test
52
71
  unless defined? @ft then
53
72
  @ft = Minitest::Test.new(:woot)
@@ -314,6 +333,42 @@ class TestMinitestReporter < MetaMetaMetaTestCase
314
333
  assert_equal exp, normalize_output(io.string)
315
334
  end
316
335
 
336
+ def test_report_error__sse
337
+ r.start
338
+ r.record system_stack_error_test
339
+ r.report
340
+
341
+ exp = clean <<-EOM
342
+ Run options:
343
+
344
+ # Running:
345
+
346
+ E
347
+
348
+ Finished in 0.00
349
+
350
+ 1) Error:
351
+ Minitest::Test#woot:
352
+ SystemStackError: 274 -> 12
353
+ a
354
+ b
355
+ c
356
+ +->> 67 cycles of 4 lines:
357
+ | aa
358
+ | ab
359
+ | ac
360
+ | ad
361
+ +-<<
362
+ d
363
+ e
364
+ f
365
+
366
+ 1 runs, 0 assertions, 0 failures, 1 errors, 0 skips
367
+ EOM
368
+
369
+ assert_equal exp, normalize_output(io.string)
370
+ end
371
+
317
372
  def test_report_skipped
318
373
  r.start
319
374
  r.record skip_test
@@ -338,4 +393,48 @@ class TestMinitestReporter < MetaMetaMetaTestCase
338
393
 
339
394
  assert_equal exp, normalize_output(io.string)
340
395
  end
396
+
397
+ def test_report_failure_uses_backtrace_filter
398
+ filter = Minitest::BacktraceFilter.new
399
+ def filter.filter _bt
400
+ ["foo.rb:123:in `foo'"]
401
+ end
402
+
403
+ with_backtrace_filter filter do
404
+ r.start
405
+ r.record fail_test
406
+ r.report
407
+ end
408
+
409
+ exp = "Minitest::Test#woot [foo.rb:123]"
410
+
411
+ assert_includes io.string, exp
412
+ end
413
+
414
+ def test_report_failure_uses_backtrace_filter_complex_sorbet
415
+ backtrace = <<~EOBT
416
+ /Users/user/.gem/ruby/3.2.2/gems/minitest-5.20.0/lib/minitest/assertions.rb:183:in `assert'
417
+ example_test.rb:9:in `assert_false'
418
+ /Users/user/.gem/ruby/3.2.2/gems/sorbet-runtime-0.5.11068/lib/types/private/methods/call_validation.rb:256:in `bind_call'
419
+ /Users/user/.gem/ruby/3.2.2/gems/sorbet-runtime-0.5.11068/lib/types/private/methods/call_validation.rb:256:in `validate_call'
420
+ /Users/user/.gem/ruby/3.2.2/gems/sorbet-runtime-0.5.11068/lib/types/private/methods/_methods.rb:275:in `block in _on_method_added'
421
+ example_test.rb:25:in `test_something'
422
+ /Users/user/.gem/ruby/3.2.2/gems/minitest-5.20.0/lib/minitest/test.rb:94:in `block (3 levels) in run'
423
+ /Users/user/.gem/ruby/3.2.2/gems/minitest-5.20.0/lib/minitest/test.rb:191:in `capture_exceptions'
424
+ /Users/user/.gem/ruby/3.2.2/gems/minitest-5.20.0/lib/minitest/test.rb:89:in `block (2 levels) in run'
425
+ ... so many lines ...
426
+ EOBT
427
+
428
+ filter = Minitest::BacktraceFilter.new %r%lib/minitest|gems/sorbet%
429
+
430
+ with_backtrace_filter filter do
431
+ begin
432
+ assert_equal 1, 2
433
+ rescue Minitest::Assertion => e
434
+ e.set_backtrace backtrace.lines.map(&:chomp)
435
+
436
+ assert_match "example_test.rb:25", e.location
437
+ end
438
+ end
439
+ end
341
440
  end
@@ -1280,3 +1280,96 @@ class TestMinitestUnitRecording < MetaMetaMetaTestCase
1280
1280
  end
1281
1281
  end
1282
1282
  end
1283
+
1284
+ class TestUnexpectedError < Minitest::Test
1285
+ def assert_compress exp, input
1286
+ e = Minitest::UnexpectedError.new RuntimeError.new
1287
+
1288
+ exp = exp.lines.map(&:chomp) if String === exp
1289
+ act = e.compress input
1290
+
1291
+ assert_equal exp, act
1292
+ end
1293
+
1294
+ ACT1 = %w[ a b c b c b c b c d ]
1295
+
1296
+ def test_normal
1297
+ assert_compress <<~EXP, %w[ a b c b c b c b c d ]
1298
+ a
1299
+ +->> 4 cycles of 2 lines:
1300
+ | b
1301
+ | c
1302
+ +-<<
1303
+ d
1304
+ EXP
1305
+ end
1306
+
1307
+ def test_normal2
1308
+ assert_compress <<~EXP, %w[ a b c b c b c b c ]
1309
+ a
1310
+ +->> 4 cycles of 2 lines:
1311
+ | b
1312
+ | c
1313
+ +-<<
1314
+ EXP
1315
+ end
1316
+
1317
+ def test_longer_c_than_b
1318
+ # the extra c in the front makes the overall length longer sorting it first
1319
+ assert_compress <<~EXP, %w[ c a b c b c b c b c b d ]
1320
+ c
1321
+ a
1322
+ b
1323
+ +->> 4 cycles of 2 lines:
1324
+ | c
1325
+ | b
1326
+ +-<<
1327
+ d
1328
+ EXP
1329
+ end
1330
+
1331
+ def test_1_line_cycles
1332
+ assert_compress <<~EXP, %w[ c a b c b c b c b c b b b d ]
1333
+ c
1334
+ a
1335
+ +->> 4 cycles of 2 lines:
1336
+ | b
1337
+ | c
1338
+ +-<<
1339
+ +->> 3 cycles of 1 lines:
1340
+ | b
1341
+ +-<<
1342
+ d
1343
+ EXP
1344
+ end
1345
+
1346
+ def test_sanity3
1347
+ pre = ("aa".."am").to_a
1348
+ mid = ("a".."z").to_a * 67
1349
+ post = ("aa".."am").to_a
1350
+ ary = pre + mid + post
1351
+
1352
+ exp = pre +
1353
+ [" +->> 67 cycles of 26 lines:"] +
1354
+ ("a".."z").map { |s| " | #{s}" } +
1355
+ [" +-<<"] +
1356
+ post
1357
+
1358
+ assert_compress exp, ary
1359
+ end
1360
+
1361
+ def test_absurd_patterns
1362
+ assert_compress <<~EXP, %w[ a b c b c a b c b c a b c ]
1363
+ +->> 2 cycles of 5 lines:
1364
+ | a
1365
+ | +->> 2 cycles of 2 lines:
1366
+ | | b
1367
+ | | c
1368
+ | +-<<
1369
+ +-<<
1370
+ a
1371
+ b
1372
+ c
1373
+ EXP
1374
+ end
1375
+ end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.20.0
4
+ version: 5.22.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Davis
@@ -10,9 +10,9 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDPjCCAiagAwIBAgIBBzANBgkqhkiG9w0BAQsFADBFMRMwEQYDVQQDDApyeWFu
13
+ MIIDPjCCAiagAwIBAgIBCDANBgkqhkiG9w0BAQsFADBFMRMwEQYDVQQDDApyeWFu
14
14
  ZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB
15
- GRYDY29tMB4XDTIzMDEwMTA3NTExN1oXDTI0MDEwMTA3NTExN1owRTETMBEGA1UE
15
+ GRYDY29tMB4XDTI0MDEwMjIxMjEyM1oXDTI1MDEwMTIxMjEyM1owRTETMBEGA1UE
16
16
  AwwKcnlhbmQtcnVieTEZMBcGCgmSJomT8ixkARkWCXplbnNwaWRlcjETMBEGCgmS
17
17
  JomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALda
18
18
  b9DCgK+627gPJkB6XfjZ1itoOQvpqH1EXScSaba9/S2VF22VYQbXU1xQXL/WzCkx
@@ -22,14 +22,14 @@ cert_chain:
22
22
  qhtV7HJxNKuPj/JFH0D2cswvzznE/a5FOYO68g+YCuFi5L8wZuuM8zzdwjrWHqSV
23
23
  gBEfoTEGr7Zii72cx+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
24
24
  HQYDVR0OBBYEFEfFe9md/r/tj/Wmwpy+MI8d9k/hMA0GCSqGSIb3DQEBCwUAA4IB
25
- AQAkg3y+PBnBAPWdxxITm5sPHqdWQgSyCpRA20o4LTuWr8BWhSXBkfQNa7cY6fOn
26
- xyM34VPzBFbExv6XOGDfOMFBVaYTHuN9peC/5/umL7kLl+nflXzL2QA7K6LYj5Bg
27
- sM574Onr0dZDM6Vn69bzQ7rBIFDfK/OhlPzqKZad4nsdcsVH8ODCiT+ATMIZyz5K
28
- WCnNtqlyiWXI8tdTpahDgcUwfcN/oN7v4K8iU5IbLJX6HQ5DKgmKjfb6XyMth16k
29
- ROfWo9Uyp8ba/j9eVG14KkYRaLydAY1MNQk2yd3R5CGfeOpD1kttxjoypoUJ2dOG
30
- nsNBRuQJ1UfiCG97a6DNm+Fr
25
+ AQCygvpmncmkiSs9r/Kceo4bBPDszhTv6iBi4LwMReqnFrpNLMOWJw7xi8x+3eL2
26
+ XS09ZPNOt2zm70KmFouBMgOysnDY4k2dE8uF6B8JbZOO8QfalW+CoNBliefOTcn2
27
+ bg5IOP7UoGM5lC174/cbDJrJnRG9bzig5FAP0mvsgA8zgTRXQzIUAZEo92D5K7p4
28
+ B4/O998ho6BSOgYBI9Yk1ttdCtti6Y+8N9+fZESsjtWMykA+WXWeGUScHqiU+gH8
29
+ S7043fq9EbQdBr2AXdj92+CDwuTfHI6/Hj5FVBDULufrJaan4xUgL70Hvc6pTTeW
30
+ deKfBjgVAq7EYHu1AczzlUly
31
31
  -----END CERTIFICATE-----
32
- date: 2023-09-06 00:00:00.000000000 Z
32
+ date: 2024-02-07 00:00:00.000000000 Z
33
33
  dependencies:
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: rdoc
@@ -57,14 +57,14 @@ dependencies:
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '4.0'
60
+ version: '4.2'
61
61
  type: :development
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '4.0'
67
+ version: '4.2'
68
68
  description: |-
69
69
  minitest provides a complete suite of testing facilities supporting
70
70
  TDD, BDD, mocking, and benchmarking.
@@ -139,6 +139,7 @@ files:
139
139
  - lib/minitest/assertions.rb
140
140
  - lib/minitest/autorun.rb
141
141
  - lib/minitest/benchmark.rb
142
+ - lib/minitest/compress.rb
142
143
  - lib/minitest/expectations.rb
143
144
  - lib/minitest/hell.rb
144
145
  - lib/minitest/mock.rb
@@ -163,6 +164,7 @@ licenses:
163
164
  metadata:
164
165
  homepage_uri: https://github.com/minitest/minitest
165
166
  bug_tracker_uri: https://github.com/minitest/minitest/issues
167
+ changelog_uri: https://github.com/minitest/minitest/blob/master/History.rdoc
166
168
  post_install_message:
167
169
  rdoc_options:
168
170
  - "--main"
@@ -183,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
185
  - !ruby/object:Gem::Version
184
186
  version: '0'
185
187
  requirements: []
186
- rubygems_version: 3.4.10
188
+ rubygems_version: 3.5.3
187
189
  signing_key:
188
190
  specification_version: 4
189
191
  summary: minitest provides a complete suite of testing facilities supporting TDD,
metadata.gz.sig CHANGED
Binary file