minitest 5.20.0 → 5.22.2

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: 24c5445e518a9b867eabce480e1d5c176c93fc6806eaed987200961e56443ec0
4
+ data.tar.gz: 2b1c37793c825e1b437d30a899411a2d71e924ab250c23d348f71ca1dbd68df2
5
5
  SHA512:
6
- metadata.gz: 2284c84ae5f98a3454e9a95417e609ca1a8ef9af8ee8b1fad8f2aca2632fde6a309e266ef1d399d9a7d47337cdcba696500a1b36f1fa7d952615eb390a89e329
7
- data.tar.gz: a76204f74c2caf693a4302065815b871863ae655372d25fc4d41e416b0d4935704c1e1068457b5cda934312e3915ae8a27595ca962c98e544dd45b54cac2aef7
6
+ metadata.gz: bc52b553200c232e0493953439fd935ee6cac3e46c45e121c81c2bc0046a5afd44caf8df980273fd46bf9ac81d38f1349f3a76a9ce9f59afff0e0e2316ea1a45
7
+ data.tar.gz: f98fcfb53d73e1d134d16b376aba3d78ef90d27024c18c48a5e0b153cc55225afc38c2c166e92d9282ffab713654843f82c9fa8a20332a16cc7308c9e1e4a140
checksums.yaml.gz.sig CHANGED
Binary file
data/History.rdoc CHANGED
@@ -1,3 +1,60 @@
1
+ === 5.22.2 / 2024-02-07
2
+
3
+ * 1 bug fix:
4
+
5
+ * Third time's a charm? Remember: 'ensure' is almost always the
6
+ wrong way to go (for results... it's great for cleaning up).
7
+
8
+ === 5.22.1 / 2024-02-06
9
+
10
+ * 1 bug fix:
11
+
12
+ * Don't exit non-zero if no tests ran and no filter (aka, the test file is empty).
13
+ (I'm starting to think the exit 1 thing for @tenderlove was a mistake...)
14
+
15
+ === 5.22.0 / 2024-02-05
16
+
17
+ * 1 minor enhancement:
18
+
19
+ * Added "did you mean" output if your --name filter matches nothing. (tenderlove)
20
+
21
+ * 2 bug fixes:
22
+
23
+ * Big cleanup of test filtering. Much prettier / more functional.
24
+ * Fix situation where Assertion#location can't find the location. (pftg)
25
+
26
+ === 5.21.2 / 2024-01-17
27
+
28
+ * 1 bug fix:
29
+
30
+ * Fixed bug in Minitest::Compress#compress formatting w/ nested patterns. Now recurses properly.
31
+
32
+ === 5.21.1 / 2024-01-11
33
+
34
+ * 1 bug fix:
35
+
36
+ * Rails' default backtrace filter can't currently work with caller_locations, so reverting back to caller.
37
+
38
+ === 5.21.0 / 2024-01-11
39
+
40
+ * 10 minor enhancements:
41
+
42
+ * Add include_all kw arg to assert_respond_to and refute_respond_to.
43
+ * Added --quiet flag to skip ProgressReporter (prints the dots). Minor speedup.
44
+ * Added Minitest::Compress#compress and added it to UnexpectedError.
45
+ * Added ability to initialize BacktraceFilter w/ custom regexp.
46
+ * Filter failure backtraces using backtrace_filter before calculating location. (thomasmarshall)
47
+ * Make BacktraceFilter#filter compatible with locations (still compares strings).
48
+ * Optimized Assertion#location ~30%.
49
+ * Output relative paths for all failures/errors/backtraces.
50
+ * Refactored location information in assertions, now using locations.
51
+ * Removed thread and mutex_m dependencies. (hsbt, eregon)
52
+
53
+ * 2 bug fixes:
54
+
55
+ * Drop undocumented bt arg in #skip. Dunno why that ever happened, prolly for testing?
56
+ * Fix mock to work with ruby debugger enabled. (keithlayne)
57
+
1
58
  === 5.20.0 / 2023-09-06
2
59
 
3
60
  * 1 minor enhancement:
@@ -9,7 +66,7 @@
9
66
  * 2 minor enhancements:
10
67
 
11
68
  * Add metadata lazy accessor to Runnable / Result. (matteeyah)
12
- * Only load minitest/unit (aka ancient MiniTest compatibility layer) if ENV["MT_COMPAT"]
69
+ * Only load minitest/unit (aka ancient MiniTest compatibility layer) if \ENV[\"MT_COMPAT\"]
13
70
 
14
71
  * 1 bug fix:
15
72
 
@@ -20,7 +77,7 @@
20
77
  * 3 bug fixes:
21
78
 
22
79
  * Avoid extra string allocations when filtering tests. (tenderlove)
23
- * Only mention deprecated ENV['N'] if it is an integer string.
80
+ * Only mention deprecated \ENV[\'N\'] if it is an integer string.
24
81
  * Push up test_order to Minitest::Runnable to fix minitest/hell. (koic)
25
82
 
26
83
  === 5.18.0 / 2023-03-04
@@ -214,7 +271,7 @@
214
271
 
215
272
  * 3 bug fixes:
216
273
 
217
- * Check `option[:filter]` klass before match. Fixes 2.6 warning. (y-yagi)
274
+ * Check \option[:filter] klass before match. Fixes 2.6 warning. (y-yagi)
218
275
  * Fixed Assertions#diff from recalculating if set to nil
219
276
  * Fixed spec section of readme to not use deprecated global expectations. (CheezItMan)
220
277
 
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.2" # :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,32 @@ 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
+ end
192
+
172
193
  ##
173
194
  # Internal run method. Responsible for telling all Runnable
174
195
  # sub-classes to run.
@@ -212,6 +233,10 @@ module Minitest
212
233
  options[:verbose] = true
213
234
  end
214
235
 
236
+ opts.on "-q", "--quiet", "Quiet. Show no progress processing files." do
237
+ options[:quiet] = true
238
+ end
239
+
215
240
  opts.on "--show-skips", "Show skipped at the end of run." do
216
241
  options[:show_skips] = true
217
242
  end
@@ -334,25 +359,15 @@ module Minitest
334
359
  # reporter to record.
335
360
 
336
361
  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
362
+ pos = options[:filter]
363
+ neg = options[:exclude]
347
364
 
348
- if options[:exclude]
349
- exclude = options[:exclude]
350
- exclude = Regexp.new $1 if exclude =~ %r%/(.*)/%
365
+ pos = Regexp.new $1 if pos.is_a?(String) && pos =~ %r%/(.*)/%
366
+ neg = Regexp.new $1 if neg.is_a?(String) && neg =~ %r%/(.*)/%
351
367
 
352
- filtered_methods.delete_if { |m|
353
- exclude === m || exclude === "#{self}##{m}"
354
- }
355
- end
368
+ filtered_methods = self.runnable_methods
369
+ .select { |m| !pos || pos === m || pos === "#{self}##{m}" }
370
+ .reject { |m| neg && (neg === m || neg === "#{self}##{m}") }
356
371
 
357
372
  return if filtered_methods.empty?
358
373
 
@@ -525,12 +540,14 @@ module Minitest
525
540
  not self.failure
526
541
  end
527
542
 
543
+ BASE_DIR = "#{Dir.pwd}/" # :nodoc:
544
+
528
545
  ##
529
546
  # The location identifier of this test. Depends on a method
530
547
  # existing called class_name.
531
548
 
532
549
  def location
533
- loc = " [#{self.failure.location}]" unless passed? or error?
550
+ loc = " [#{self.failure.location.delete_prefix BASE_DIR}]" unless passed? or error?
534
551
  "#{self.class_name}##{self.name}#{loc}"
535
552
  end
536
553
 
@@ -619,7 +636,10 @@ module Minitest
619
636
  # you want. Go nuts.
620
637
 
621
638
  class AbstractReporter
622
- include Mutex_m
639
+
640
+ def initialize # :nodoc:
641
+ @mutex = Mutex.new
642
+ end
623
643
 
624
644
  ##
625
645
  # Starts reporting on the run.
@@ -655,6 +675,10 @@ module Minitest
655
675
  def passed?
656
676
  true
657
677
  end
678
+
679
+ def synchronize(&block) # :nodoc:
680
+ @mutex.synchronize(&block)
681
+ end
658
682
  end
659
683
 
660
684
  class Reporter < AbstractReporter # :nodoc:
@@ -828,7 +852,7 @@ module Minitest
828
852
  io.puts "# Running:"
829
853
  io.puts
830
854
 
831
- self.sync = io.respond_to? :"sync=" # stupid emacs
855
+ self.sync = io.respond_to? :"sync="
832
856
  self.old_sync, io.sync = io.sync, true if self.sync
833
857
  end
834
858
 
@@ -936,6 +960,8 @@ module Minitest
936
960
  # Represents run failures.
937
961
 
938
962
  class Assertion < Exception
963
+ RE = /in .(?:assert|refute|flunk|pass|fail|raise|must|wont)/ # :nodoc:
964
+
939
965
  def error # :nodoc:
940
966
  self
941
967
  end
@@ -944,12 +970,11 @@ module Minitest
944
970
  # Where was this run before an assertion was raised?
945
971
 
946
972
  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 .*$/, "")
973
+ bt = Minitest.filter_backtrace self.backtrace
974
+ idx = bt.rindex { |s| s.match? RE } || -1 # fall back to first item
975
+ loc = bt[idx+1] || bt.last || "unknown:-1"
976
+
977
+ loc.sub(/:in .*$/, "")
953
978
  end
954
979
 
955
980
  def result_code # :nodoc:
@@ -974,11 +999,21 @@ module Minitest
974
999
  # Assertion wrapping an unexpected error that was raised during a run.
975
1000
 
976
1001
  class UnexpectedError < Assertion
1002
+ include Minitest::Compress
1003
+
977
1004
  # TODO: figure out how to use `cause` instead
978
1005
  attr_accessor :error # :nodoc:
979
1006
 
980
1007
  def initialize error # :nodoc:
981
1008
  super "Unexpected exception"
1009
+
1010
+ if SystemStackError === error then
1011
+ bt = error.backtrace
1012
+ new_bt = compress bt
1013
+ error = error.exception "#{bt.size} -> #{new_bt.size}"
1014
+ error.set_backtrace new_bt
1015
+ end
1016
+
982
1017
  self.error = error
983
1018
  end
984
1019
 
@@ -986,8 +1021,11 @@ module Minitest
986
1021
  self.error.backtrace
987
1022
  end
988
1023
 
1024
+ BASE_RE = %r%#{Dir.pwd}/% # :nodoc:
1025
+
989
1026
  def message # :nodoc:
990
- bt = Minitest.filter_backtrace(self.backtrace).join "\n "
1027
+ bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
1028
+ .gsub(BASE_RE, "")
991
1029
  "#{self.error.class}: #{self.error.message}\n #{bt}"
992
1030
  end
993
1031
 
@@ -1071,6 +1109,12 @@ module Minitest
1071
1109
 
1072
1110
  MT_RE = %r%lib/minitest% #:nodoc:
1073
1111
 
1112
+ attr_accessor :regexp
1113
+
1114
+ def initialize regexp = MT_RE
1115
+ self.regexp = regexp
1116
+ end
1117
+
1074
1118
  ##
1075
1119
  # Filter +bt+ to something useful. Returns the whole thing if
1076
1120
  # $DEBUG (ruby) or $MT_DEBUG (env).
@@ -1080,9 +1124,9 @@ module Minitest
1080
1124
 
1081
1125
  return bt.dup if $DEBUG || ENV["MT_DEBUG"]
1082
1126
 
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?
1127
+ new_bt = bt.take_while { |line| line.to_s !~ regexp }
1128
+ new_bt = bt.select { |line| line.to_s !~ regexp } if new_bt.empty?
1129
+ new_bt = bt.dup if new_bt.empty?
1086
1130
 
1087
1131
  new_bt
1088
1132
  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
@@ -1,4 +1,2 @@
1
- ^�bG�@�����Ąw��nr��:@�
2
- ���Q���%�`d[MS7#�N�Ǟ,sVn=5��ݕ��0+E$��0���KKn80br�
3
- �ʜ�}�� ���m�O��i
4
- ��=
1
+ �TO���J���0�MN�i�W^�<~-C������Vi{�,{���V��=蝠�
2
+ JV�������j-G81o��iB���T���\��
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.2
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