minitest 5.16.3 → 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.
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.16.3" # :nodoc:
12
+ VERSION = "5.25.1" # :nodoc:
13
13
 
14
14
  @@installed_at_exit ||= false
15
15
  @@after_run = []
@@ -32,7 +32,7 @@ module Minitest
32
32
 
33
33
  cattr_accessor :parallel_executor
34
34
 
35
- warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"]
35
+ warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"] && ENV["N"].to_i > 0
36
36
  n_threads = (ENV["MT_CPU"] || ENV["N"] || Etc.nprocessors).to_i
37
37
 
38
38
  self.parallel_executor = Parallel::Executor.new n_threads
@@ -60,13 +60,15 @@ module Minitest
60
60
  cattr_accessor :info_signal
61
61
  self.info_signal = "INFO"
62
62
 
63
+ cattr_accessor :allow_fork
64
+ self.allow_fork = false
65
+
63
66
  ##
64
67
  # Registers Minitest to run at process exit
65
68
 
66
69
  def self.autorun
67
- if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
68
- Warning[:deprecated] = true
69
- end
70
+ Warning[:deprecated] = true if
71
+ Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
70
72
 
71
73
  at_exit {
72
74
  next if $! and not ($!.kind_of? SystemExit and $!.success?)
@@ -75,7 +77,7 @@ module Minitest
75
77
 
76
78
  pid = Process.pid
77
79
  at_exit {
78
- next if Process.pid != pid
80
+ next if !Minitest.allow_fork && Process.pid != pid
79
81
  @@after_run.reverse_each(&:call)
80
82
  exit exit_code || false
81
83
  }
@@ -95,20 +97,19 @@ module Minitest
95
97
  @@after_run << block
96
98
  end
97
99
 
98
- def self.init_plugins options # :nodoc:
99
- self.extensions.each do |name|
100
- msg = "plugin_#{name}_init"
101
- send msg, options if self.respond_to? msg
102
- end
100
+ ##
101
+ # Register a plugin to be used. Does NOT require / load it.
102
+
103
+ def self.register_plugin name_or_mod
104
+ self.extensions << name_or_mod
105
+ nil
103
106
  end
104
107
 
105
108
  def self.load_plugins # :nodoc:
106
- return unless self.extensions.empty?
109
+ return unless defined? Gem
107
110
 
108
111
  seen = {}
109
112
 
110
- require "rubygems" unless defined? Gem
111
-
112
113
  Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
113
114
  name = File.basename plugin_path, "_plugin.rb"
114
115
 
@@ -120,72 +121,27 @@ module Minitest
120
121
  end
121
122
  end
122
123
 
123
- ##
124
- # This is the top-level run method. Everything starts from here. It
125
- # tells each Runnable sub-class to run, and each of those are
126
- # responsible for doing whatever they do.
127
- #
128
- # The overall structure of a run looks like this:
129
- #
130
- # Minitest.autorun
131
- # Minitest.run(args)
132
- # Minitest.__run(reporter, options)
133
- # Runnable.runnables.each
134
- # runnable.run(reporter, options)
135
- # self.runnable_methods.each
136
- # self.run_one_method(self, runnable_method, reporter)
137
- # Minitest.run_one_method(klass, runnable_method)
138
- # klass.new(runnable_method).run
139
-
140
- def self.run args = []
141
- self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
142
-
143
- options = process_args args
144
-
145
- Minitest.seed = options[:seed]
146
- srand Minitest.seed
147
-
148
- reporter = CompositeReporter.new
149
- reporter << SummaryReporter.new(options[:io], options)
150
- reporter << ProgressReporter.new(options[:io], options)
151
-
152
- self.reporter = reporter # this makes it available to plugins
153
- self.init_plugins options
154
- self.reporter = nil # runnables shouldn't depend on the reporter, ever
155
-
156
- self.parallel_executor.start if parallel_executor.respond_to?(:start)
157
- reporter.start
158
- begin
159
- __run reporter, options
160
- rescue Interrupt
161
- warn "Interrupted. Exiting..."
124
+ def self.init_plugins options # :nodoc:
125
+ self.extensions.each do |mod_or_meth|
126
+ case mod_or_meth
127
+ when Symbol, String then
128
+ name = mod_or_meth
129
+ msg = "plugin_#{name}_init"
130
+ next unless self.respond_to? msg
131
+ send msg, options
132
+ when Module then
133
+ recv = mod_or_meth
134
+ next unless recv.respond_to? :minitest_plugin_init
135
+ recv.minitest_plugin_init options
136
+ else
137
+ raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
138
+ end
162
139
  end
163
- self.parallel_executor.shutdown
164
- reporter.report
165
-
166
- reporter.passed?
167
- end
168
-
169
- ##
170
- # Internal run method. Responsible for telling all Runnable
171
- # sub-classes to run.
172
-
173
- def self.__run reporter, options
174
- suites = Runnable.runnables.shuffle
175
- parallel, serial = suites.partition { |s| s.test_order == :parallel }
176
-
177
- # If we run the parallel tests before the serial tests, the parallel tests
178
- # could run in parallel with the serial tests. This would be bad because
179
- # the serial tests won't lock around Reporter#record. Run the serial tests
180
- # first, so that after they complete, the parallel tests will lock when
181
- # recording results.
182
- serial.map { |suite| suite.run reporter, options } +
183
- parallel.map { |suite| suite.run reporter, options }
184
140
  end
185
141
 
186
142
  def self.process_args args = [] # :nodoc:
187
143
  options = {
188
- :io => $stdout,
144
+ :io => $stdout,
189
145
  }
190
146
  orig_args = args.dup
191
147
 
@@ -209,6 +165,10 @@ module Minitest
209
165
  options[:verbose] = true
210
166
  end
211
167
 
168
+ opts.on "-q", "--quiet", "Quiet. Show no progress processing files." do
169
+ options[:quiet] = true
170
+ end
171
+
212
172
  opts.on "--show-skips", "Show skipped at the end of run." do
213
173
  options[:show_skips] = true
214
174
  end
@@ -225,13 +185,37 @@ module Minitest
225
185
  options[:skip] = s.chars.to_a
226
186
  end
227
187
 
188
+ ruby27plus = ::Warning.respond_to? :[]=
189
+
190
+ opts.on "-W[error]", String, "Turn Ruby warnings into errors" do |s|
191
+ options[:Werror] = true
192
+ case s
193
+ when "error", "all", nil then
194
+ require "minitest/error_on_warning"
195
+ $VERBOSE = true
196
+ ::Warning[:deprecated] = true if ruby27plus
197
+ else
198
+ ::Warning[s.to_sym] = true if ruby27plus # check validity of category
199
+ end
200
+ end
201
+
228
202
  unless extensions.empty?
229
203
  opts.separator ""
230
- opts.separator "Known extensions: #{extensions.join(", ")}"
231
-
232
- extensions.each do |meth|
233
- msg = "plugin_#{meth}_options"
234
- send msg, opts, options if self.respond_to?(msg)
204
+ opts.separator "Known extensions: #{extensions.join ", "}"
205
+
206
+ extensions.each do |mod_or_meth|
207
+ case mod_or_meth
208
+ when Symbol, String then
209
+ meth = mod_or_meth
210
+ msg = "plugin_#{meth}_options"
211
+ send msg, opts, options if respond_to? msg
212
+ when Module
213
+ recv = mod_or_meth
214
+ next unless recv.respond_to? :minitest_plugin_options
215
+ recv.minitest_plugin_options opts, options
216
+ else
217
+ raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
218
+ end
235
219
  end
236
220
  end
237
221
 
@@ -255,12 +239,99 @@ module Minitest
255
239
  end
256
240
 
257
241
  options[:args] = orig_args.map { |s|
258
- s =~ /[\s|&<>$()]/ ? s.inspect : s
242
+ s.match?(/[\s|&<>$()]/) ? s.inspect : s
259
243
  }.join " "
260
244
 
261
245
  options
262
246
  end
263
247
 
248
+ ##
249
+ # This is the top-level run method. Everything starts from here. It
250
+ # tells each Runnable sub-class to run, and each of those are
251
+ # responsible for doing whatever they do.
252
+ #
253
+ # The overall structure of a run looks like this:
254
+ #
255
+ # Minitest.autorun
256
+ # Minitest.run(args)
257
+ # Minitest.load_plugins
258
+ # Minitest.process_args
259
+ # Minitest.init_plugins
260
+ # Minitest.__run(reporter, options)
261
+ # Runnable.runnables.each
262
+ # runnable_klass.run(reporter, options)
263
+ # self.runnable_methods.each
264
+ # self.run_one_method(self, runnable_method, reporter)
265
+ # Minitest.run_one_method(klass, runnable_method)
266
+ # klass.new(runnable_method).run
267
+
268
+ def self.run args = []
269
+ self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
270
+
271
+ options = process_args args
272
+
273
+ Minitest.seed = options[:seed]
274
+ srand Minitest.seed
275
+
276
+ reporter = CompositeReporter.new
277
+ reporter << SummaryReporter.new(options[:io], options)
278
+ reporter << ProgressReporter.new(options[:io], options) unless options[:quiet]
279
+
280
+ self.reporter = reporter # this makes it available to plugins
281
+ self.init_plugins options
282
+ self.reporter = nil # runnables shouldn't depend on the reporter, ever
283
+
284
+ self.parallel_executor.start if parallel_executor.respond_to? :start
285
+ reporter.start
286
+ begin
287
+ __run reporter, options
288
+ rescue Interrupt
289
+ warn "Interrupted. Exiting..."
290
+ end
291
+ self.parallel_executor.shutdown
292
+
293
+ # might have been removed/replaced during init_plugins:
294
+ summary = reporter.reporters.grep(SummaryReporter).first
295
+
296
+ reporter.report
297
+
298
+ return empty_run! options if summary && summary.count == 0
299
+ reporter.passed?
300
+ end
301
+
302
+ def self.empty_run! options # :nodoc:
303
+ filter = options[:filter]
304
+ return true unless filter # no filter, but nothing ran == success
305
+
306
+ warn "Nothing ran for filter: %s" % [filter]
307
+
308
+ require "did_you_mean" # soft dependency, punt if it doesn't load
309
+
310
+ ms = Runnable.runnables.flat_map(&:runnable_methods)
311
+ cs = DidYouMean::SpellChecker.new(dictionary: ms).correct filter
312
+
313
+ warn DidYouMean::Formatter.message_for cs unless cs.empty?
314
+ rescue LoadError
315
+ # do nothing
316
+ end
317
+
318
+ ##
319
+ # Internal run method. Responsible for telling all Runnable
320
+ # sub-classes to run.
321
+
322
+ def self.__run reporter, options
323
+ suites = Runnable.runnables.shuffle
324
+ parallel, serial = suites.partition { |s| s.test_order == :parallel }
325
+
326
+ # If we run the parallel tests before the serial tests, the parallel tests
327
+ # could run in parallel with the serial tests. This would be bad because
328
+ # the serial tests won't lock around Reporter#record. Run the serial tests
329
+ # first, so that after they complete, the parallel tests will lock when
330
+ # recording results.
331
+ serial.map { |suite| suite.run reporter, options } +
332
+ parallel.map { |suite| suite.run reporter, options }
333
+ end
334
+
264
335
  def self.filter_backtrace bt # :nodoc:
265
336
  result = backtrace_filter.filter bt
266
337
  result = bt.dup if result.empty?
@@ -331,24 +402,34 @@ module Minitest
331
402
  # reporter to record.
332
403
 
333
404
  def self.run reporter, options = {}
334
- filter = options[:filter] || "/./"
335
- filter = Regexp.new $1 if filter.is_a?(String) && filter =~ %r%/(.*)/%
336
-
337
- filtered_methods = self.runnable_methods.find_all { |m|
338
- filter === m || filter === "#{self}##{m}"
339
- }
405
+ pos = options[:filter]
406
+ neg = options[:exclude]
340
407
 
341
- exclude = options[:exclude]
342
- exclude = Regexp.new $1 if exclude =~ %r%/(.*)/%
408
+ pos = Regexp.new $1 if pos.kind_of?(String) && pos =~ %r%/(.*)/%
409
+ neg = Regexp.new $1 if neg.kind_of?(String) && neg =~ %r%/(.*)/%
343
410
 
344
- filtered_methods.delete_if { |m|
345
- exclude === m || exclude === "#{self}##{m}"
346
- }
411
+ filtered_methods = self.runnable_methods
412
+ .select { |m| !pos || pos === m || pos === "#{self}##{m}" }
413
+ .reject { |m| neg && (neg === m || neg === "#{self}##{m}") }
347
414
 
348
415
  return if filtered_methods.empty?
349
416
 
417
+ t0 = name = nil
418
+
419
+ @_info_handler = lambda do
420
+ unless reporter.passed? then
421
+ warn "Current results:"
422
+ warn reporter.reporters.grep(SummaryReporter).first
423
+ end
424
+
425
+ warn "Current: %s#%s %.2fs" % [self, name, Minitest.clock_time - t0]
426
+ end
427
+
350
428
  with_info_handler reporter do
351
429
  filtered_methods.each do |method_name|
430
+ name = method_name
431
+ t0 = Minitest.clock_time
432
+
352
433
  run_one_method self, method_name, reporter
353
434
  end
354
435
  end
@@ -365,17 +446,16 @@ module Minitest
365
446
  reporter.record Minitest.run_one_method(klass, method_name)
366
447
  end
367
448
 
368
- def self.with_info_handler reporter, &block # :nodoc:
369
- handler = lambda do
370
- unless reporter.passed? then
371
- warn "Current results:"
372
- warn ""
373
- warn reporter.reporters.first
374
- warn ""
375
- end
376
- end
449
+ ##
450
+ # Defines the order to run tests (:random by default). Override
451
+ # this or use a convenience method to change it for your tests.
377
452
 
378
- on_signal ::Minitest.info_signal, handler, &block
453
+ def self.test_order
454
+ :random
455
+ end
456
+
457
+ def self.with_info_handler reporter, &block # :nodoc:
458
+ on_signal ::Minitest.info_signal, @_info_handler, &block
379
459
  end
380
460
 
381
461
  SIGNALS = Signal.list # :nodoc:
@@ -413,7 +493,7 @@ module Minitest
413
493
  def marshal_dump # :nodoc:
414
494
  unless @@marshal_dump_warned then
415
495
  warn ["Minitest::Runnable#marshal_dump is deprecated.",
416
- "You might be violating internals. From", caller.first].join " "
496
+ "You might be violating internals. From", caller(1..1).first].join " "
417
497
  @@marshal_dump_warned = true
418
498
  end
419
499
 
@@ -432,6 +512,31 @@ module Minitest
432
512
  self.name = name
433
513
  self.failures = []
434
514
  self.assertions = 0
515
+ # lazy initializer for metadata
516
+ end
517
+
518
+ ##
519
+ # Metadata you attach to the test results that get sent to the reporter.
520
+ #
521
+ # Lazily initializes to a hash, to keep memory down.
522
+ #
523
+ # NOTE: this data *must* be plain (read: marshal-able) data!
524
+ # Hashes! Arrays! Strings!
525
+
526
+ def metadata
527
+ @metadata ||= {}
528
+ end
529
+
530
+ ##
531
+ # Sets metadata, mainly used for +Result.from+.
532
+
533
+ attr_writer :metadata
534
+
535
+ ##
536
+ # Returns true if metadata exists.
537
+
538
+ def metadata?
539
+ defined? @metadata
435
540
  end
436
541
 
437
542
  ##
@@ -483,12 +588,14 @@ module Minitest
483
588
  not self.failure
484
589
  end
485
590
 
591
+ BASE_DIR = "#{Dir.pwd}/" # :nodoc:
592
+
486
593
  ##
487
594
  # The location identifier of this test. Depends on a method
488
595
  # existing called class_name.
489
596
 
490
597
  def location
491
- loc = " [#{self.failure.location}]" unless passed? or error?
598
+ loc = " [#{self.failure.location.delete_prefix BASE_DIR}]" unless passed? or error?
492
599
  "#{self.class_name}##{self.name}#{loc}"
493
600
  end
494
601
 
@@ -514,7 +621,7 @@ module Minitest
514
621
  # Did this run error?
515
622
 
516
623
  def error?
517
- self.failures.any? { |f| UnexpectedError === f }
624
+ self.failures.any? UnexpectedError
518
625
  end
519
626
  end
520
627
 
@@ -552,6 +659,7 @@ module Minitest
552
659
  r.assertions = o.assertions
553
660
  r.failures = o.failures.dup
554
661
  r.time = o.time
662
+ r.metadata = o.metadata if o.metadata?
555
663
 
556
664
  r.source_location = o.method(o.name).source_location rescue ["unknown", -1]
557
665
 
@@ -576,7 +684,10 @@ module Minitest
576
684
  # you want. Go nuts.
577
685
 
578
686
  class AbstractReporter
579
- include Mutex_m
687
+
688
+ def initialize # :nodoc:
689
+ @mutex = Mutex.new
690
+ end
580
691
 
581
692
  ##
582
693
  # Starts reporting on the run.
@@ -612,6 +723,10 @@ module Minitest
612
723
  def passed?
613
724
  true
614
725
  end
726
+
727
+ def synchronize &block # :nodoc:
728
+ @mutex.synchronize(&block)
729
+ end
615
730
  end
616
731
 
617
732
  class Reporter < AbstractReporter # :nodoc:
@@ -641,11 +756,11 @@ module Minitest
641
756
  # own.
642
757
 
643
758
  class ProgressReporter < Reporter
644
- def prerecord klass, name #:nodoc:
645
- if options[:verbose] then
646
- io.print "%s#%s = " % [klass.name, name]
647
- io.flush
648
- end
759
+ def prerecord klass, name # :nodoc:
760
+ return unless options[:verbose]
761
+
762
+ io.print "%s#%s = " % [klass.name, name]
763
+ io.flush
649
764
  end
650
765
 
651
766
  def record result # :nodoc:
@@ -715,6 +830,11 @@ module Minitest
715
830
 
716
831
  attr_accessor :errors
717
832
 
833
+ ##
834
+ # Total number of tests that warned.
835
+
836
+ attr_accessor :warnings
837
+
718
838
  ##
719
839
  # Total number of tests that where skipped.
720
840
 
@@ -730,6 +850,7 @@ module Minitest
730
850
  self.total_time = nil
731
851
  self.failures = nil
732
852
  self.errors = nil
853
+ self.warnings = nil
733
854
  self.skips = nil
734
855
  end
735
856
 
@@ -758,6 +879,7 @@ module Minitest
758
879
  self.total_time = Minitest.clock_time - start_time
759
880
  self.failures = aggregate[Assertion].size
760
881
  self.errors = aggregate[UnexpectedError].size
882
+ self.warnings = aggregate[UnexpectedWarning].size
761
883
  self.skips = aggregate[Skip].size
762
884
  end
763
885
  end
@@ -772,10 +894,8 @@ module Minitest
772
894
  # own.
773
895
 
774
896
  class SummaryReporter < StatisticsReporter
775
- # :stopdoc:
776
- attr_accessor :sync
777
- attr_accessor :old_sync
778
- # :startdoc:
897
+ attr_accessor :sync # :nodoc:
898
+ attr_accessor :old_sync # :nodoc:
779
899
 
780
900
  def start # :nodoc:
781
901
  super
@@ -785,7 +905,7 @@ module Minitest
785
905
  io.puts "# Running:"
786
906
  io.puts
787
907
 
788
- self.sync = io.respond_to? :"sync=" # stupid emacs
908
+ self.sync = io.respond_to? :"sync="
789
909
  self.old_sync, io.sync = io.sync, true if self.sync
790
910
  end
791
911
 
@@ -823,26 +943,22 @@ module Minitest
823
943
  end
824
944
 
825
945
  def to_s # :nodoc:
826
- aggregated_results(StringIO.new(binary_string)).string
946
+ aggregated_results(StringIO.new("".b)).string
827
947
  end
828
948
 
829
949
  def summary # :nodoc:
830
- extra = ""
950
+ extra = []
951
+
952
+ extra << ", %d warnings" % [warnings] if options[:Werror]
831
953
 
832
- extra = "\n\nYou have skipped tests. Run with --verbose for details." if
954
+ extra << "\n\nYou have skipped tests. Run with --verbose for details." if
833
955
  results.any?(&:skipped?) unless
834
- options[:verbose] or options[:show_skips] or ENV["MT_NO_SKIP_MSG"]
956
+ options[:verbose] or
957
+ options[:show_skips] or
958
+ ENV["MT_NO_SKIP_MSG"]
835
959
 
836
960
  "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
837
- [count, assertions, failures, errors, skips, extra]
838
- end
839
-
840
- private
841
-
842
- if '<3'.respond_to? :b
843
- def binary_string; ''.b; end
844
- else
845
- def binary_string; ''.force_encoding(Encoding::ASCII_8BIT); end
961
+ [count, assertions, failures, errors, skips, extra.join]
846
962
  end
847
963
  end
848
964
 
@@ -901,6 +1017,8 @@ module Minitest
901
1017
  # Represents run failures.
902
1018
 
903
1019
  class Assertion < Exception
1020
+ RE = /in [`'](?:[^']+[#.])?(?:assert|refute|flunk|pass|fail|raise|must|wont)/ # :nodoc:
1021
+
904
1022
  def error # :nodoc:
905
1023
  self
906
1024
  end
@@ -909,12 +1027,11 @@ module Minitest
909
1027
  # Where was this run before an assertion was raised?
910
1028
 
911
1029
  def location
912
- last_before_assertion = ""
913
- self.backtrace.reverse_each do |s|
914
- break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
915
- last_before_assertion = s
916
- end
917
- last_before_assertion.sub(/:in .*$/, "")
1030
+ bt = Minitest.filter_backtrace self.backtrace
1031
+ idx = bt.rindex { |s| s.match? RE } || -1 # fall back to first item
1032
+ loc = bt[idx+1] || bt.last || "unknown:-1"
1033
+
1034
+ loc.sub(/:in .*$/, "")
918
1035
  end
919
1036
 
920
1037
  def result_code # :nodoc:
@@ -939,11 +1056,21 @@ module Minitest
939
1056
  # Assertion wrapping an unexpected error that was raised during a run.
940
1057
 
941
1058
  class UnexpectedError < Assertion
1059
+ include Minitest::Compress
1060
+
942
1061
  # TODO: figure out how to use `cause` instead
943
1062
  attr_accessor :error # :nodoc:
944
1063
 
945
1064
  def initialize error # :nodoc:
946
1065
  super "Unexpected exception"
1066
+
1067
+ if SystemStackError === error then
1068
+ bt = error.backtrace
1069
+ new_bt = compress bt
1070
+ error = error.exception "#{bt.size} -> #{new_bt.size}"
1071
+ error.set_backtrace new_bt
1072
+ end
1073
+
947
1074
  self.error = error
948
1075
  end
949
1076
 
@@ -951,8 +1078,11 @@ module Minitest
951
1078
  self.error.backtrace
952
1079
  end
953
1080
 
1081
+ BASE_RE = %r%#{Dir.pwd}/% # :nodoc:
1082
+
954
1083
  def message # :nodoc:
955
- bt = Minitest.filter_backtrace(self.backtrace).join "\n "
1084
+ bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
1085
+ .gsub(BASE_RE, "")
956
1086
  "#{self.error.class}: #{self.error.message}\n #{bt}"
957
1087
  end
958
1088
 
@@ -961,6 +1091,15 @@ module Minitest
961
1091
  end
962
1092
  end
963
1093
 
1094
+ ##
1095
+ # Assertion raised on warning when running in -Werror mode.
1096
+
1097
+ class UnexpectedWarning < Assertion
1098
+ def result_label # :nodoc:
1099
+ "Warning"
1100
+ end
1101
+ end
1102
+
964
1103
  ##
965
1104
  # Provides a simple set of guards that you can use in your tests
966
1105
  # to skip execution if it is not applicable. These methods are
@@ -990,7 +1129,7 @@ module Minitest
990
1129
 
991
1130
  def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
992
1131
  where = Minitest.filter_backtrace(caller).first
993
- where = where.split(/:in /, 2).first # clean up noise
1132
+ where = where.split(":in ", 2).first # clean up noise
994
1133
  warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
995
1134
  "maglev" == platform
996
1135
  end
@@ -999,14 +1138,14 @@ module Minitest
999
1138
  # Is this running on mri?
1000
1139
 
1001
1140
  def mri? platform = RUBY_DESCRIPTION
1002
- /^ruby/ =~ platform
1141
+ platform.start_with? "ruby"
1003
1142
  end
1004
1143
 
1005
1144
  ##
1006
1145
  # Is this running on macOS?
1007
1146
 
1008
1147
  def osx? platform = RUBY_PLATFORM
1009
- /darwin/ =~ platform
1148
+ platform.include? "darwin"
1010
1149
  end
1011
1150
 
1012
1151
  ##
@@ -1014,7 +1153,7 @@ module Minitest
1014
1153
 
1015
1154
  def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1016
1155
  where = Minitest.filter_backtrace(caller).first
1017
- where = where.split(/:in /, 2).first # clean up noise
1156
+ where = where.split(":in ", 2).first # clean up noise
1018
1157
  warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
1019
1158
  "rbx" == platform
1020
1159
  end
@@ -1023,7 +1162,7 @@ module Minitest
1023
1162
  # Is this running on windows?
1024
1163
 
1025
1164
  def windows? platform = RUBY_PLATFORM
1026
- /mswin|mingw/ =~ platform
1165
+ /mswin|mingw/.match? platform
1027
1166
  end
1028
1167
  end
1029
1168
 
@@ -1034,7 +1173,16 @@ module Minitest
1034
1173
 
1035
1174
  class BacktraceFilter
1036
1175
 
1037
- MT_RE = %r%lib/minitest% #:nodoc:
1176
+ MT_RE = %r%lib/minitest|internal:warning% # :nodoc:
1177
+
1178
+ ##
1179
+ # The regular expression to use to filter backtraces. Defaults to +MT_RE+.
1180
+
1181
+ attr_accessor :regexp
1182
+
1183
+ def initialize regexp = MT_RE # :nodoc:
1184
+ self.regexp = regexp
1185
+ end
1038
1186
 
1039
1187
  ##
1040
1188
  # Filter +bt+ to something useful. Returns the whole thing if
@@ -1045,9 +1193,9 @@ module Minitest
1045
1193
 
1046
1194
  return bt.dup if $DEBUG || ENV["MT_DEBUG"]
1047
1195
 
1048
- new_bt = bt.take_while { |line| line !~ MT_RE }
1049
- new_bt = bt.select { |line| line !~ MT_RE } if new_bt.empty?
1050
- new_bt = bt.dup if new_bt.empty?
1196
+ new_bt = bt.take_while { |line| !regexp.match? line.to_s }
1197
+ new_bt = bt.select { |line| !regexp.match? line.to_s } if new_bt.empty?
1198
+ new_bt = bt.dup if new_bt.empty?
1051
1199
 
1052
1200
  new_bt
1053
1201
  end