minitest 5.18.0 → 5.25.5

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