minitest 5.20.0 → 5.27.0

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.20.0" # :nodoc:
13
+ VERSION = "5.26.2" # :nodoc:
13
14
 
14
15
  @@installed_at_exit ||= false
15
16
  @@after_run = []
@@ -35,7 +36,7 @@ module Minitest
35
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
- self.parallel_executor = Parallel::Executor.new n_threads
39
+ self.parallel_executor = Parallel::Executor.new n_threads if n_threads > 1
39
40
 
40
41
  ##
41
42
  # Filter object for backtraces.
@@ -67,9 +68,7 @@ module Minitest
67
68
  # Registers Minitest to run at process exit
68
69
 
69
70
  def self.autorun
70
- if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
71
- Warning[:deprecated] = true
72
- end
71
+ Warning[:deprecated] = true
73
72
 
74
73
  at_exit {
75
74
  next if $! and not ($!.kind_of? SystemExit and $!.success?)
@@ -98,20 +97,19 @@ module Minitest
98
97
  @@after_run << block
99
98
  end
100
99
 
101
- def self.init_plugins options # :nodoc:
102
- self.extensions.each do |name|
103
- msg = "plugin_#{name}_init"
104
- send msg, options if self.respond_to? msg
105
- 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
106
106
  end
107
107
 
108
108
  def self.load_plugins # :nodoc:
109
- return unless self.extensions.empty?
109
+ return unless defined? Gem
110
110
 
111
111
  seen = {}
112
112
 
113
- require "rubygems" unless defined? Gem
114
-
115
113
  Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
116
114
  name = File.basename plugin_path, "_plugin.rb"
117
115
 
@@ -123,100 +121,65 @@ module Minitest
123
121
  end
124
122
  end
125
123
 
126
- ##
127
- # This is the top-level run method. Everything starts from here. It
128
- # tells each Runnable sub-class to run, and each of those are
129
- # responsible for doing whatever they do.
130
- #
131
- # The overall structure of a run looks like this:
132
- #
133
- # Minitest.autorun
134
- # Minitest.run(args)
135
- # Minitest.__run(reporter, options)
136
- # Runnable.runnables.each
137
- # runnable.run(reporter, options)
138
- # self.runnable_methods.each
139
- # self.run_one_method(self, runnable_method, reporter)
140
- # Minitest.run_one_method(klass, runnable_method)
141
- # klass.new(runnable_method).run
142
-
143
- def self.run args = []
144
- self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
145
-
146
- options = process_args args
147
-
148
- Minitest.seed = options[:seed]
149
- srand Minitest.seed
150
-
151
- reporter = CompositeReporter.new
152
- reporter << SummaryReporter.new(options[:io], options)
153
- reporter << ProgressReporter.new(options[:io], options)
154
-
155
- self.reporter = reporter # this makes it available to plugins
156
- self.init_plugins options
157
- self.reporter = nil # runnables shouldn't depend on the reporter, ever
158
-
159
- self.parallel_executor.start if parallel_executor.respond_to?(:start)
160
- reporter.start
161
- begin
162
- __run reporter, options
163
- rescue Interrupt
164
- 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
165
139
  end
166
- self.parallel_executor.shutdown
167
- reporter.report
168
-
169
- reporter.passed?
170
- end
171
-
172
- ##
173
- # Internal run method. Responsible for telling all Runnable
174
- # sub-classes to run.
175
-
176
- def self.__run reporter, options
177
- suites = Runnable.runnables.shuffle
178
- parallel, serial = suites.partition { |s| s.test_order == :parallel }
179
-
180
- # If we run the parallel tests before the serial tests, the parallel tests
181
- # could run in parallel with the serial tests. This would be bad because
182
- # the serial tests won't lock around Reporter#record. Run the serial tests
183
- # first, so that after they complete, the parallel tests will lock when
184
- # recording results.
185
- serial.map { |suite| suite.run reporter, options } +
186
- parallel.map { |suite| suite.run reporter, options }
187
140
  end
188
141
 
189
142
  def self.process_args args = [] # :nodoc:
190
143
  options = {
191
- :io => $stdout,
144
+ :io => $stdout,
192
145
  }
193
146
  orig_args = args.dup
194
147
 
195
148
  OptionParser.new do |opts|
196
- opts.banner = "minitest options:"
149
+ opts.program_name = "minitest"
197
150
  opts.version = Minitest::VERSION
198
151
 
152
+ opts.banner = [
153
+ "Usage: rake test [A=options] (see Minitest::TestTask for more options)",
154
+ "minitest [paths] [options] (with minitest-sprint gem)",
155
+ "ruby path/to/test.rb [options]\n\n",
156
+ ].join "\n or: "
157
+
199
158
  opts.on "-h", "--help", "Display this help." do
200
159
  puts opts
201
160
  exit
202
161
  end
203
162
 
204
- opts.on "--no-plugins", "Bypass minitest plugin auto-loading (or set $MT_NO_PLUGINS)."
163
+ opts.on "--no-plugins", "Bypass minitest plugin auto-loading (or env: MT_NO_PLUGINS=1)."
205
164
 
206
- desc = "Sets random seed. Also via env. Eg: SEED=n rake"
165
+ desc = "Sets random seed. Also via env, eg: SEED=42"
207
166
  opts.on "-s", "--seed SEED", Integer, desc do |m|
208
- options[:seed] = m.to_i
167
+ options[:seed] = m
209
168
  end
210
169
 
211
- opts.on "-v", "--verbose", "Verbose. Show progress processing files." do
170
+ opts.on "-v", "--verbose", "Verbose. Print each name as they run." do
212
171
  options[:verbose] = true
213
172
  end
214
173
 
174
+ opts.on "-q", "--quiet", "Quiet. Show no dots while processing files." do
175
+ options[:quiet] = true
176
+ end
177
+
215
178
  opts.on "--show-skips", "Show skipped at the end of run." do
216
179
  options[:show_skips] = true
217
180
  end
218
181
 
219
- opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
182
+ opts.on "-n", "--name PATTERN", "Include /regexp/ or string for run." do |a|
220
183
  options[:filter] = a
221
184
  end
222
185
 
@@ -224,17 +187,48 @@ module Minitest
224
187
  options[:exclude] = a
225
188
  end
226
189
 
190
+ # part of my unofficial embedded gem "makeoptparseworkwell"
191
+ def opts.topdict(name) = (name.length > 1 ? top.long : top.short)
192
+ def opts.alias(from, to) = (dict = topdict(from) ; dict[to] = dict[from])
193
+
194
+ # these will work but won't show up in --help output:
195
+ opts.alias "name", "include"
196
+ opts.alias "n", "i"
197
+ opts.alias "e", "x"
198
+
227
199
  opts.on "-S", "--skip CODES", String, "Skip reporting of certain types of results (eg E)." do |s|
228
200
  options[:skip] = s.chars.to_a
229
201
  end
230
202
 
203
+ opts.on "-W[error]", String, "Turn Ruby warnings into errors" do |s|
204
+ options[:Werror] = true
205
+ case s
206
+ when "error", "all", nil then
207
+ require_relative "minitest/error_on_warning"
208
+ $VERBOSE = true
209
+ ::Warning[:deprecated] = true
210
+ else
211
+ ::Warning[s.to_sym] = true # check validity of category
212
+ end
213
+ end
214
+
231
215
  unless extensions.empty?
232
216
  opts.separator ""
233
- opts.separator "Known extensions: #{extensions.join(", ")}"
234
-
235
- extensions.each do |meth|
236
- msg = "plugin_#{meth}_options"
237
- send msg, opts, options if self.respond_to?(msg)
217
+ opts.separator "Known extensions: #{extensions.join ", "}"
218
+
219
+ extensions.each do |mod_or_meth|
220
+ case mod_or_meth
221
+ when Symbol, String then
222
+ meth = mod_or_meth
223
+ msg = "plugin_#{meth}_options"
224
+ send msg, opts, options if respond_to? msg
225
+ when Module
226
+ recv = mod_or_meth
227
+ next unless recv.respond_to? :minitest_plugin_options
228
+ recv.minitest_plugin_options opts, options
229
+ else
230
+ raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
231
+ end
238
232
  end
239
233
  end
240
234
 
@@ -258,12 +252,101 @@ module Minitest
258
252
  end
259
253
 
260
254
  options[:args] = orig_args.map { |s|
261
- s =~ /[\s|&<>$()]/ ? s.inspect : s
255
+ s.match?(/[\s|&<>$()]/) ? s.inspect : s
262
256
  }.join " "
263
257
 
264
258
  options
265
259
  end
266
260
 
261
+ ##
262
+ # This is the top-level run method. Everything starts from here. It
263
+ # tells each Runnable sub-class to run, and each of those are
264
+ # responsible for doing whatever they do.
265
+ #
266
+ # The overall structure of a run looks like this:
267
+ #
268
+ # Minitest.autorun
269
+ # Minitest.run(args)
270
+ # Minitest.load_plugins
271
+ # Minitest.process_args
272
+ # Minitest.init_plugins
273
+ # Minitest.__run(reporter, options)
274
+ # Runnable.runnables.each |runnable_klass|
275
+ # runnable_klass.run(reporter, options)
276
+ # filtered_methods = runnable_methods.select {...}.reject {...}
277
+ # filtered_methods.each |runnable_method|
278
+ # runnable_klass.run_one_method(self, runnable_method, reporter)
279
+ # Minitest.run_one_method(runnable_klass, runnable_method)
280
+ # runnable_klass.new(runnable_method).run
281
+
282
+ def self.run args = []
283
+ self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
284
+
285
+ options = process_args args
286
+
287
+ Minitest.seed = options[:seed]
288
+ srand Minitest.seed
289
+
290
+ reporter = CompositeReporter.new
291
+ reporter << SummaryReporter.new(options[:io], options)
292
+ reporter << ProgressReporter.new(options[:io], options) unless options[:quiet]
293
+
294
+ self.reporter = reporter # this makes it available to plugins
295
+ self.init_plugins options
296
+ self.reporter = nil # runnables shouldn't depend on the reporter, ever
297
+
298
+ self.parallel_executor.start if parallel_executor.respond_to? :start
299
+ reporter.start
300
+ begin
301
+ __run reporter, options
302
+ finished = true
303
+ rescue Interrupt
304
+ warn "Interrupted. Exiting..."
305
+ end
306
+ self.parallel_executor.shutdown if parallel_executor.respond_to? :shutdown
307
+
308
+ # might have been removed/replaced during init_plugins:
309
+ summary = reporter.reporters.grep(SummaryReporter).first
310
+
311
+ reporter.report
312
+
313
+ return empty_run! options if finished && summary && summary.count == 0
314
+ finished and reporter.passed?
315
+ end
316
+
317
+ def self.empty_run! options # :nodoc:
318
+ filter = options[:filter]
319
+ return true unless filter # no filter, but nothing ran == success
320
+
321
+ warn "Nothing ran for filter: %s" % [filter]
322
+
323
+ require "did_you_mean" # soft dependency, punt if it doesn't load
324
+
325
+ ms = Runnable.runnables.flat_map(&:runnable_methods)
326
+ cs = DidYouMean::SpellChecker.new(dictionary: ms).correct filter
327
+
328
+ warn DidYouMean::Formatter.message_for cs unless cs.empty?
329
+ rescue LoadError
330
+ # do nothing
331
+ end
332
+
333
+ ##
334
+ # Internal run method. Responsible for telling all Runnable
335
+ # sub-classes to run.
336
+
337
+ def self.__run reporter, options
338
+ suites = Runnable.runnables.shuffle
339
+ parallel, serial = suites.partition { |s| s.test_order == :parallel }
340
+
341
+ # If we run the parallel tests before the serial tests, the parallel tests
342
+ # could run in parallel with the serial tests. This would be bad because
343
+ # the serial tests won't lock around Reporter#record. Run the serial tests
344
+ # first, so that after they complete, the parallel tests will lock when
345
+ # recording results.
346
+ serial.map { |suite| suite.run reporter, options } +
347
+ parallel.map { |suite| suite.run reporter, options }
348
+ end
349
+
267
350
  def self.filter_backtrace bt # :nodoc:
268
351
  result = backtrace_filter.filter bt
269
352
  result = bt.dup if result.empty?
@@ -334,30 +417,35 @@ module Minitest
334
417
  # reporter to record.
335
418
 
336
419
  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
420
+ pos = options[:filter]
421
+ neg = options[:exclude]
347
422
 
348
- if options[:exclude]
349
- exclude = options[:exclude]
350
- exclude = Regexp.new $1 if exclude =~ %r%/(.*)/%
423
+ pos = Regexp.new $1 if pos.kind_of?(String) && pos =~ %r%/(.*)/%
424
+ neg = Regexp.new $1 if neg.kind_of?(String) && neg =~ %r%/(.*)/%
351
425
 
352
- filtered_methods.delete_if { |m|
353
- exclude === m || exclude === "#{self}##{m}"
354
- }
355
- end
426
+ # at most 1-2% slower than a 1-pass version, stop optimizing this
427
+ filtered_methods = self.runnable_methods
428
+ .select { |m| !pos || pos === m || pos === "#{self}##{m}" }
429
+ .reject { |m| neg && (neg === m || neg === "#{self}##{m}") }
356
430
 
357
431
  return if filtered_methods.empty?
358
432
 
433
+ t0 = name = nil
434
+
435
+ @_info_handler = lambda do
436
+ unless reporter.passed? then
437
+ warn "Current results:"
438
+ warn reporter.reporters.grep(SummaryReporter).first
439
+ end
440
+
441
+ warn "Current: %s#%s %.2fs" % [self, name, Minitest.clock_time - t0]
442
+ end
443
+
359
444
  with_info_handler reporter do
360
445
  filtered_methods.each do |method_name|
446
+ name = method_name
447
+ t0 = Minitest.clock_time
448
+
361
449
  run_one_method self, method_name, reporter
362
450
  end
363
451
  end
@@ -383,16 +471,7 @@ module Minitest
383
471
  end
384
472
 
385
473
  def self.with_info_handler reporter, &block # :nodoc:
386
- handler = lambda do
387
- unless reporter.passed? then
388
- warn "Current results:"
389
- warn ""
390
- warn reporter.reporters.first
391
- warn ""
392
- end
393
- end
394
-
395
- on_signal ::Minitest.info_signal, handler, &block
474
+ on_signal ::Minitest.info_signal, @_info_handler, &block
396
475
  end
397
476
 
398
477
  SIGNALS = Signal.list # :nodoc:
@@ -430,7 +509,7 @@ module Minitest
430
509
  def marshal_dump # :nodoc:
431
510
  unless @@marshal_dump_warned then
432
511
  warn ["Minitest::Runnable#marshal_dump is deprecated.",
433
- "You might be violating internals. From", caller.first].join " "
512
+ "You might be violating internals. From", caller(1..1).first].join " "
434
513
  @@marshal_dump_warned = true
435
514
  end
436
515
 
@@ -508,7 +587,7 @@ module Minitest
508
587
  def skipped?
509
588
  raise NotImplementedError, "subclass responsibility"
510
589
  end
511
- end
590
+ end # Runnable
512
591
 
513
592
  ##
514
593
  # Shared code for anything that can get passed to a Reporter. See
@@ -525,12 +604,14 @@ module Minitest
525
604
  not self.failure
526
605
  end
527
606
 
607
+ BASE_DIR = "#{Dir.pwd}/" # :nodoc:
608
+
528
609
  ##
529
610
  # The location identifier of this test. Depends on a method
530
611
  # existing called class_name.
531
612
 
532
613
  def location
533
- loc = " [#{self.failure.location}]" unless passed? or error?
614
+ loc = " [#{self.failure.location.delete_prefix BASE_DIR}]" unless passed? or error?
534
615
  "#{self.class_name}##{self.name}#{loc}"
535
616
  end
536
617
 
@@ -556,9 +637,9 @@ module Minitest
556
637
  # Did this run error?
557
638
 
558
639
  def error?
559
- self.failures.any? { |f| UnexpectedError === f }
640
+ self.failures.any? UnexpectedError
560
641
  end
561
- end
642
+ end # Reportable
562
643
 
563
644
  ##
564
645
  # This represents a test result in a clean way that can be
@@ -612,14 +693,17 @@ module Minitest
612
693
  "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
613
694
  }.join "\n"
614
695
  end
615
- end
696
+ end # Result
616
697
 
617
698
  ##
618
699
  # Defines the API for Reporters. Subclass this and override whatever
619
700
  # you want. Go nuts.
620
701
 
621
702
  class AbstractReporter
622
- include Mutex_m
703
+
704
+ def initialize # :nodoc:
705
+ @mutex = Mutex.new
706
+ end
623
707
 
624
708
  ##
625
709
  # Starts reporting on the run.
@@ -655,7 +739,11 @@ module Minitest
655
739
  def passed?
656
740
  true
657
741
  end
658
- end
742
+
743
+ def synchronize &block # :nodoc:
744
+ @mutex.synchronize(&block)
745
+ end
746
+ end # AbstractReportera
659
747
 
660
748
  class Reporter < AbstractReporter # :nodoc:
661
749
  ##
@@ -684,11 +772,11 @@ module Minitest
684
772
  # own.
685
773
 
686
774
  class ProgressReporter < Reporter
687
- def prerecord klass, name #:nodoc:
688
- if options[:verbose] then
689
- io.print "%s#%s = " % [klass.name, name]
690
- io.flush
691
- end
775
+ def prerecord klass, name # :nodoc:
776
+ return unless options[:verbose]
777
+
778
+ io.print "%s#%s = " % [klass.name, name]
779
+ io.flush
692
780
  end
693
781
 
694
782
  def record result # :nodoc:
@@ -758,6 +846,11 @@ module Minitest
758
846
 
759
847
  attr_accessor :errors
760
848
 
849
+ ##
850
+ # Total number of tests that warned.
851
+
852
+ attr_accessor :warnings
853
+
761
854
  ##
762
855
  # Total number of tests that where skipped.
763
856
 
@@ -773,6 +866,7 @@ module Minitest
773
866
  self.total_time = nil
774
867
  self.failures = nil
775
868
  self.errors = nil
869
+ self.warnings = nil
776
870
  self.skips = nil
777
871
  end
778
872
 
@@ -801,9 +895,10 @@ module Minitest
801
895
  self.total_time = Minitest.clock_time - start_time
802
896
  self.failures = aggregate[Assertion].size
803
897
  self.errors = aggregate[UnexpectedError].size
898
+ self.warnings = aggregate[UnexpectedWarning].size
804
899
  self.skips = aggregate[Skip].size
805
900
  end
806
- end
901
+ end # StatisticsReporter
807
902
 
808
903
  ##
809
904
  # A reporter that prints the header, summary, and failure details at
@@ -815,10 +910,8 @@ module Minitest
815
910
  # own.
816
911
 
817
912
  class SummaryReporter < StatisticsReporter
818
- # :stopdoc:
819
- attr_accessor :sync
820
- attr_accessor :old_sync
821
- # :startdoc:
913
+ attr_accessor :sync # :nodoc:
914
+ attr_accessor :old_sync # :nodoc:
822
915
 
823
916
  def start # :nodoc:
824
917
  super
@@ -828,7 +921,7 @@ module Minitest
828
921
  io.puts "# Running:"
829
922
  io.puts
830
923
 
831
- self.sync = io.respond_to? :"sync=" # stupid emacs
924
+ self.sync = io.respond_to? :"sync="
832
925
  self.old_sync, io.sync = io.sync, true if self.sync
833
926
  end
834
927
 
@@ -866,20 +959,24 @@ module Minitest
866
959
  end
867
960
 
868
961
  def to_s # :nodoc:
869
- aggregated_results(StringIO.new(''.b)).string
962
+ aggregated_results(StringIO.new("".b)).string
870
963
  end
871
964
 
872
965
  def summary # :nodoc:
873
- extra = ""
966
+ extra = []
967
+
968
+ extra << ", %d warnings" % [warnings] if options[:Werror]
874
969
 
875
- extra = "\n\nYou have skipped tests. Run with --verbose for details." if
970
+ extra << "\n\nYou have skipped tests. Run with --verbose for details." if
876
971
  results.any?(&:skipped?) unless
877
- options[:verbose] or options[:show_skips] or ENV["MT_NO_SKIP_MSG"]
972
+ options[:verbose] or
973
+ options[:show_skips] or
974
+ ENV["MT_NO_SKIP_MSG"]
878
975
 
879
976
  "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
880
- [count, assertions, failures, errors, skips, extra]
977
+ [count, assertions, failures, errors, skips, extra.join]
881
978
  end
882
- end
979
+ end # SummaryReporter
883
980
 
884
981
  ##
885
982
  # Dispatch to multiple reporters as one.
@@ -930,12 +1027,14 @@ module Minitest
930
1027
  def report # :nodoc:
931
1028
  self.reporters.each(&:report)
932
1029
  end
933
- end
1030
+ end # CompositeReporter
934
1031
 
935
1032
  ##
936
1033
  # Represents run failures.
937
1034
 
938
1035
  class Assertion < Exception
1036
+ RE = /in [`'](?:[^']+[#.])?(?:assert|refute|flunk|pass|fail|raise|must|wont)/ # :nodoc:
1037
+
939
1038
  def error # :nodoc:
940
1039
  self
941
1040
  end
@@ -944,12 +1043,11 @@ module Minitest
944
1043
  # Where was this run before an assertion was raised?
945
1044
 
946
1045
  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 .*$/, "")
1046
+ bt = Minitest.filter_backtrace self.backtrace
1047
+ idx = bt.rindex { |s| s.match? RE } || -1 # fall back to first item
1048
+ loc = bt[idx+1] || bt.last || "unknown:-1"
1049
+
1050
+ loc.sub(/:in .*$/, "")
953
1051
  end
954
1052
 
955
1053
  def result_code # :nodoc:
@@ -974,11 +1072,21 @@ module Minitest
974
1072
  # Assertion wrapping an unexpected error that was raised during a run.
975
1073
 
976
1074
  class UnexpectedError < Assertion
1075
+ include Minitest::Compress
1076
+
977
1077
  # TODO: figure out how to use `cause` instead
978
1078
  attr_accessor :error # :nodoc:
979
1079
 
980
1080
  def initialize error # :nodoc:
981
1081
  super "Unexpected exception"
1082
+
1083
+ if SystemStackError === error then
1084
+ bt = error.backtrace
1085
+ new_bt = compress bt
1086
+ error = error.exception "#{bt.size} -> #{new_bt.size}"
1087
+ error.set_backtrace new_bt
1088
+ end
1089
+
982
1090
  self.error = error
983
1091
  end
984
1092
 
@@ -986,8 +1094,11 @@ module Minitest
986
1094
  self.error.backtrace
987
1095
  end
988
1096
 
1097
+ BASE_RE = %r%#{Regexp.escape Dir.pwd}/% # :nodoc:
1098
+
989
1099
  def message # :nodoc:
990
- bt = Minitest.filter_backtrace(self.backtrace).join "\n "
1100
+ bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
1101
+ .gsub(BASE_RE, "")
991
1102
  "#{self.error.class}: #{self.error.message}\n #{bt}"
992
1103
  end
993
1104
 
@@ -996,6 +1107,15 @@ module Minitest
996
1107
  end
997
1108
  end
998
1109
 
1110
+ ##
1111
+ # Assertion raised on warning when running in -Werror mode.
1112
+
1113
+ class UnexpectedWarning < Assertion
1114
+ def result_label # :nodoc:
1115
+ "Warning"
1116
+ end
1117
+ end
1118
+
999
1119
  ##
1000
1120
  # Provides a simple set of guards that you can use in your tests
1001
1121
  # to skip execution if it is not applicable. These methods are
@@ -1025,7 +1145,7 @@ module Minitest
1025
1145
 
1026
1146
  def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1027
1147
  where = Minitest.filter_backtrace(caller).first
1028
- where = where.split(/:in /, 2).first # clean up noise
1148
+ where = where.split(":in ", 2).first # clean up noise
1029
1149
  warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
1030
1150
  "maglev" == platform
1031
1151
  end
@@ -1034,14 +1154,14 @@ module Minitest
1034
1154
  # Is this running on mri?
1035
1155
 
1036
1156
  def mri? platform = RUBY_DESCRIPTION
1037
- /^ruby/ =~ platform
1157
+ platform.start_with? "ruby"
1038
1158
  end
1039
1159
 
1040
1160
  ##
1041
1161
  # Is this running on macOS?
1042
1162
 
1043
1163
  def osx? platform = RUBY_PLATFORM
1044
- /darwin/ =~ platform
1164
+ platform.include? "darwin"
1045
1165
  end
1046
1166
 
1047
1167
  ##
@@ -1049,7 +1169,7 @@ module Minitest
1049
1169
 
1050
1170
  def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1051
1171
  where = Minitest.filter_backtrace(caller).first
1052
- where = where.split(/:in /, 2).first # clean up noise
1172
+ where = where.split(":in ", 2).first # clean up noise
1053
1173
  warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
1054
1174
  "rbx" == platform
1055
1175
  end
@@ -1058,7 +1178,7 @@ module Minitest
1058
1178
  # Is this running on windows?
1059
1179
 
1060
1180
  def windows? platform = RUBY_PLATFORM
1061
- /mswin|mingw/ =~ platform
1181
+ /mswin|mingw/.match? platform
1062
1182
  end
1063
1183
  end
1064
1184
 
@@ -1069,7 +1189,16 @@ module Minitest
1069
1189
 
1070
1190
  class BacktraceFilter
1071
1191
 
1072
- MT_RE = %r%lib/minitest% #:nodoc:
1192
+ MT_RE = %r%lib/minitest|internal:warning% # :nodoc:
1193
+
1194
+ ##
1195
+ # The regular expression to use to filter backtraces. Defaults to +MT_RE+.
1196
+
1197
+ attr_accessor :regexp
1198
+
1199
+ def initialize regexp = MT_RE # :nodoc:
1200
+ self.regexp = regexp
1201
+ end
1073
1202
 
1074
1203
  ##
1075
1204
  # Filter +bt+ to something useful. Returns the whole thing if
@@ -1080,9 +1209,9 @@ module Minitest
1080
1209
 
1081
1210
  return bt.dup if $DEBUG || ENV["MT_DEBUG"]
1082
1211
 
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?
1212
+ new_bt = bt.take_while { |line| !regexp.match? line.to_s }
1213
+ new_bt = bt.select { |line| !regexp.match? line.to_s } if new_bt.empty?
1214
+ new_bt = bt.dup if new_bt.empty?
1086
1215
 
1087
1216
  new_bt
1088
1217
  end
@@ -1118,4 +1247,4 @@ module Minitest
1118
1247
  # :startdoc:
1119
1248
  end
1120
1249
 
1121
- require "minitest/test"
1250
+ require_relative "minitest/test"