minitest 5.11.3 → 5.25.4

Sign up to get free protection for your applications and to get access to all the features.
data/lib/minitest.rb CHANGED
@@ -1,61 +1,84 @@
1
1
  require "optparse"
2
- require "thread"
3
- require "mutex_m"
4
- require "minitest/parallel"
5
2
  require "stringio"
3
+ require "etc"
4
+
5
+ require_relative "minitest/parallel"
6
+ require_relative "minitest/compress"
6
7
 
7
8
  ##
8
- # :include: README.rdoc
9
+ # The top-level namespace for Minitest. Also the location of the main
10
+ # runtime. See +Minitest.run+ for more information.
9
11
 
10
12
  module Minitest
11
- VERSION = "5.11.3" # :nodoc:
12
- ENCS = "".respond_to? :encoding # :nodoc:
13
+ VERSION = "5.25.4" # :nodoc:
13
14
 
14
15
  @@installed_at_exit ||= false
15
16
  @@after_run = []
16
17
  @extensions = []
17
18
 
18
- mc = (class << self; self; end)
19
+ def self.cattr_accessor name # :nodoc:
20
+ (class << self; self; end).attr_accessor name
21
+ end
22
+
23
+ ##
24
+ # The random seed used for this run. This is used to srand at the
25
+ # start of the run and between each +Runnable.run+.
26
+ #
27
+ # Set via Minitest.run after processing args.
28
+
29
+ cattr_accessor :seed
19
30
 
20
31
  ##
21
32
  # Parallel test executor
22
33
 
23
- mc.send :attr_accessor, :parallel_executor
24
- self.parallel_executor = Parallel::Executor.new((ENV["N"] || 2).to_i)
34
+ cattr_accessor :parallel_executor
35
+
36
+ warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"] && ENV["N"].to_i > 0
37
+ n_threads = (ENV["MT_CPU"] || ENV["N"] || Etc.nprocessors).to_i
38
+
39
+ self.parallel_executor = Parallel::Executor.new n_threads
25
40
 
26
41
  ##
27
42
  # Filter object for backtraces.
28
43
 
29
- mc.send :attr_accessor, :backtrace_filter
44
+ cattr_accessor :backtrace_filter
30
45
 
31
46
  ##
32
47
  # Reporter object to be used for all runs.
33
48
  #
34
49
  # NOTE: This accessor is only available during setup, not during runs.
35
50
 
36
- mc.send :attr_accessor, :reporter
51
+ cattr_accessor :reporter
37
52
 
38
53
  ##
39
54
  # Names of known extension plugins.
40
55
 
41
- mc.send :attr_accessor, :extensions
56
+ cattr_accessor :extensions
42
57
 
43
58
  ##
44
59
  # The signal to use for dumping information to STDERR. Defaults to "INFO".
45
60
 
46
- mc.send :attr_accessor, :info_signal
61
+ cattr_accessor :info_signal
47
62
  self.info_signal = "INFO"
48
63
 
64
+ cattr_accessor :allow_fork
65
+ self.allow_fork = false
66
+
49
67
  ##
50
68
  # Registers Minitest to run at process exit
51
69
 
52
70
  def self.autorun
71
+ Warning[:deprecated] = true if
72
+ Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
73
+
53
74
  at_exit {
54
75
  next if $! and not ($!.kind_of? SystemExit and $!.success?)
55
76
 
56
77
  exit_code = nil
57
78
 
79
+ pid = Process.pid
58
80
  at_exit {
81
+ next if !Minitest.allow_fork && Process.pid != pid
59
82
  @@after_run.reverse_each(&:call)
60
83
  exit exit_code || false
61
84
  }
@@ -75,20 +98,19 @@ module Minitest
75
98
  @@after_run << block
76
99
  end
77
100
 
78
- def self.init_plugins options # :nodoc:
79
- self.extensions.each do |name|
80
- msg = "plugin_#{name}_init"
81
- send msg, options if self.respond_to? msg
82
- 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
83
107
  end
84
108
 
85
109
  def self.load_plugins # :nodoc:
86
- return unless self.extensions.empty?
110
+ return unless defined? Gem
87
111
 
88
112
  seen = {}
89
113
 
90
- require "rubygems" unless defined? Gem
91
-
92
114
  Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
93
115
  name = File.basename plugin_path, "_plugin.rb"
94
116
 
@@ -100,69 +122,27 @@ module Minitest
100
122
  end
101
123
  end
102
124
 
103
- ##
104
- # This is the top-level run method. Everything starts from here. It
105
- # tells each Runnable sub-class to run, and each of those are
106
- # responsible for doing whatever they do.
107
- #
108
- # The overall structure of a run looks like this:
109
- #
110
- # Minitest.autorun
111
- # Minitest.run(args)
112
- # Minitest.__run(reporter, options)
113
- # Runnable.runnables.each
114
- # runnable.run(reporter, options)
115
- # self.runnable_methods.each
116
- # self.run_one_method(self, runnable_method, reporter)
117
- # Minitest.run_one_method(klass, runnable_method)
118
- # klass.new(runnable_method).run
119
-
120
- def self.run args = []
121
- self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
122
-
123
- options = process_args args
124
-
125
- reporter = CompositeReporter.new
126
- reporter << SummaryReporter.new(options[:io], options)
127
- reporter << ProgressReporter.new(options[:io], options)
128
-
129
- self.reporter = reporter # this makes it available to plugins
130
- self.init_plugins options
131
- self.reporter = nil # runnables shouldn't depend on the reporter, ever
132
-
133
- self.parallel_executor.start if parallel_executor.respond_to?(:start)
134
- reporter.start
135
- begin
136
- __run reporter, options
137
- rescue Interrupt
138
- 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
139
140
  end
140
- self.parallel_executor.shutdown
141
- reporter.report
142
-
143
- reporter.passed?
144
- end
145
-
146
- ##
147
- # Internal run method. Responsible for telling all Runnable
148
- # sub-classes to run.
149
-
150
- def self.__run reporter, options
151
- suites = Runnable.runnables.reject { |s| s.runnable_methods.empty? }.shuffle
152
- parallel, serial = suites.partition { |s| s.test_order == :parallel }
153
-
154
- # If we run the parallel tests before the serial tests, the parallel tests
155
- # could run in parallel with the serial tests. This would be bad because
156
- # the serial tests won't lock around Reporter#record. Run the serial tests
157
- # first, so that after they complete, the parallel tests will lock when
158
- # recording results.
159
- serial.map { |suite| suite.run reporter, options } +
160
- parallel.map { |suite| suite.run reporter, options }
161
141
  end
162
142
 
163
143
  def self.process_args args = [] # :nodoc:
164
144
  options = {
165
- :io => $stdout,
145
+ :io => $stdout,
166
146
  }
167
147
  orig_args = args.dup
168
148
 
@@ -186,6 +166,14 @@ module Minitest
186
166
  options[:verbose] = true
187
167
  end
188
168
 
169
+ opts.on "-q", "--quiet", "Quiet. Show no progress processing files." do
170
+ options[:quiet] = true
171
+ end
172
+
173
+ opts.on "--show-skips", "Show skipped at the end of run." do
174
+ options[:show_skips] = true
175
+ end
176
+
189
177
  opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
190
178
  options[:filter] = a
191
179
  end
@@ -194,13 +182,41 @@ module Minitest
194
182
  options[:exclude] = a
195
183
  end
196
184
 
185
+ opts.on "-S", "--skip CODES", String, "Skip reporting of certain types of results (eg E)." do |s|
186
+ options[:skip] = s.chars.to_a
187
+ end
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
+
197
203
  unless extensions.empty?
198
204
  opts.separator ""
199
- opts.separator "Known extensions: #{extensions.join(", ")}"
200
-
201
- extensions.each do |meth|
202
- msg = "plugin_#{meth}_options"
203
- 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
204
220
  end
205
221
  end
206
222
 
@@ -223,17 +239,104 @@ module Minitest
223
239
  orig_args << "--seed" << options[:seed].to_s
224
240
  end
225
241
 
226
- srand options[:seed]
227
-
228
242
  options[:args] = orig_args.map { |s|
229
- s =~ /[\s|&<>$()]/ ? s.inspect : s
243
+ s.match?(/[\s|&<>$()]/) ? s.inspect : s
230
244
  }.join " "
231
245
 
232
246
  options
233
247
  end
234
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
+
235
336
  def self.filter_backtrace bt # :nodoc:
236
- backtrace_filter.filter bt
337
+ result = backtrace_filter.filter bt
338
+ result = bt.dup if result.empty?
339
+ result
237
340
  end
238
341
 
239
342
  ##
@@ -300,24 +403,34 @@ module Minitest
300
403
  # reporter to record.
301
404
 
302
405
  def self.run reporter, options = {}
303
- filter = options[:filter] || "/./"
304
- filter = Regexp.new $1 if filter =~ %r%/(.*)/%
305
-
306
- filtered_methods = self.runnable_methods.find_all { |m|
307
- filter === m || filter === "#{self}##{m}"
308
- }
406
+ pos = options[:filter]
407
+ neg = options[:exclude]
309
408
 
310
- exclude = options[:exclude]
311
- exclude = Regexp.new $1 if exclude =~ %r%/(.*)/%
409
+ pos = Regexp.new $1 if pos.kind_of?(String) && pos =~ %r%/(.*)/%
410
+ neg = Regexp.new $1 if neg.kind_of?(String) && neg =~ %r%/(.*)/%
312
411
 
313
- filtered_methods.delete_if { |m|
314
- exclude === m || exclude === "#{self}##{m}"
315
- }
412
+ filtered_methods = self.runnable_methods
413
+ .select { |m| !pos || pos === m || pos === "#{self}##{m}" }
414
+ .reject { |m| neg && (neg === m || neg === "#{self}##{m}") }
316
415
 
317
416
  return if filtered_methods.empty?
318
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
+
319
429
  with_info_handler reporter do
320
430
  filtered_methods.each do |method_name|
431
+ name = method_name
432
+ t0 = Minitest.clock_time
433
+
321
434
  run_one_method self, method_name, reporter
322
435
  end
323
436
  end
@@ -334,17 +447,16 @@ module Minitest
334
447
  reporter.record Minitest.run_one_method(klass, method_name)
335
448
  end
336
449
 
337
- def self.with_info_handler reporter, &block # :nodoc:
338
- handler = lambda do
339
- unless reporter.passed? then
340
- warn "Current results:"
341
- warn ""
342
- warn reporter.reporters.first
343
- warn ""
344
- end
345
- 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.
453
+
454
+ def self.test_order
455
+ :random
456
+ end
346
457
 
347
- on_signal ::Minitest.info_signal, handler, &block
458
+ def self.with_info_handler reporter, &block # :nodoc:
459
+ on_signal ::Minitest.info_signal, @_info_handler, &block
348
460
  end
349
461
 
350
462
  SIGNALS = Signal.list # :nodoc:
@@ -382,7 +494,7 @@ module Minitest
382
494
  def marshal_dump # :nodoc:
383
495
  unless @@marshal_dump_warned then
384
496
  warn ["Minitest::Runnable#marshal_dump is deprecated.",
385
- "You might be violating internals. From", caller.first].join " "
497
+ "You might be violating internals. From", caller(1..1).first].join " "
386
498
  @@marshal_dump_warned = true
387
499
  end
388
500
 
@@ -401,6 +513,31 @@ module Minitest
401
513
  self.name = name
402
514
  self.failures = []
403
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
404
541
  end
405
542
 
406
543
  ##
@@ -422,7 +559,8 @@ module Minitest
422
559
 
423
560
  ##
424
561
  # Returns a single character string to print based on the result
425
- # of the run. Eg ".", "F", or "E".
562
+ # of the run. One of <tt>"."</tt>, <tt>"F"</tt>,
563
+ # <tt>"E"</tt> or <tt>"S"</tt>.
426
564
 
427
565
  def result_code
428
566
  raise NotImplementedError, "subclass responsibility"
@@ -451,12 +589,14 @@ module Minitest
451
589
  not self.failure
452
590
  end
453
591
 
592
+ BASE_DIR = "#{Dir.pwd}/" # :nodoc:
593
+
454
594
  ##
455
595
  # The location identifier of this test. Depends on a method
456
596
  # existing called class_name.
457
597
 
458
598
  def location
459
- loc = " [#{self.failure.location}]" unless passed? or error?
599
+ loc = " [#{self.failure.location.delete_prefix BASE_DIR}]" unless passed? or error?
460
600
  "#{self.class_name}##{self.name}#{loc}"
461
601
  end
462
602
 
@@ -482,7 +622,7 @@ module Minitest
482
622
  # Did this run error?
483
623
 
484
624
  def error?
485
- self.failures.any? { |f| UnexpectedError === f }
625
+ self.failures.any? UnexpectedError
486
626
  end
487
627
  end
488
628
 
@@ -520,6 +660,7 @@ module Minitest
520
660
  r.assertions = o.assertions
521
661
  r.failures = o.failures.dup
522
662
  r.time = o.time
663
+ r.metadata = o.metadata if o.metadata?
523
664
 
524
665
  r.source_location = o.method(o.name).source_location rescue ["unknown", -1]
525
666
 
@@ -544,7 +685,10 @@ module Minitest
544
685
  # you want. Go nuts.
545
686
 
546
687
  class AbstractReporter
547
- include Mutex_m
688
+
689
+ def initialize # :nodoc:
690
+ @mutex = Mutex.new
691
+ end
548
692
 
549
693
  ##
550
694
  # Starts reporting on the run.
@@ -560,8 +704,10 @@ module Minitest
560
704
  end
561
705
 
562
706
  ##
563
- # Record a result and output the Runnable#result_code. Stores the
564
- # result of the run if the run did not pass.
707
+ # Output and record the result of the test. Call
708
+ # {result#result_code}[rdoc-ref:Runnable#result_code] to get the
709
+ # result character string. Stores the result of the run if the run
710
+ # did not pass.
565
711
 
566
712
  def record result
567
713
  end
@@ -578,6 +724,10 @@ module Minitest
578
724
  def passed?
579
725
  true
580
726
  end
727
+
728
+ def synchronize &block # :nodoc:
729
+ @mutex.synchronize(&block)
730
+ end
581
731
  end
582
732
 
583
733
  class Reporter < AbstractReporter # :nodoc:
@@ -607,11 +757,11 @@ module Minitest
607
757
  # own.
608
758
 
609
759
  class ProgressReporter < Reporter
610
- def prerecord klass, name #:nodoc:
611
- if options[:verbose] then
612
- io.print "%s#%s = " % [klass.name, name]
613
- io.flush
614
- end
760
+ def prerecord klass, name # :nodoc:
761
+ return unless options[:verbose]
762
+
763
+ io.print "%s#%s = " % [klass.name, name]
764
+ io.flush
615
765
  end
616
766
 
617
767
  def record result # :nodoc:
@@ -628,18 +778,68 @@ module Minitest
628
778
  #
629
779
  # If you want to create an entirely different type of output (eg,
630
780
  # CI, HTML, etc), this is the place to start.
781
+ #
782
+ # Example:
783
+ #
784
+ # class JenkinsCIReporter < StatisticsReporter
785
+ # def report
786
+ # super # Needed to calculate some statistics
787
+ #
788
+ # print "<testsuite "
789
+ # print "tests='#{count}' "
790
+ # print "failures='#{failures}' "
791
+ # # Remaining XML...
792
+ # end
793
+ # end
631
794
 
632
795
  class StatisticsReporter < Reporter
633
- # :stopdoc:
796
+ ##
797
+ # Total number of assertions.
798
+
634
799
  attr_accessor :assertions
800
+
801
+ ##
802
+ # Total number of test cases.
803
+
635
804
  attr_accessor :count
805
+
806
+ ##
807
+ # An +Array+ of test cases that failed or were skipped.
808
+
636
809
  attr_accessor :results
810
+
811
+ ##
812
+ # Time the test run started. If available, the monotonic clock is
813
+ # used and this is a +Float+, otherwise it's an instance of
814
+ # +Time+.
815
+
637
816
  attr_accessor :start_time
817
+
818
+ ##
819
+ # Test run time. If available, the monotonic clock is used and
820
+ # this is a +Float+, otherwise it's an instance of +Time+.
821
+
638
822
  attr_accessor :total_time
823
+
824
+ ##
825
+ # Total number of tests that failed.
826
+
639
827
  attr_accessor :failures
828
+
829
+ ##
830
+ # Total number of tests that erred.
831
+
640
832
  attr_accessor :errors
833
+
834
+ ##
835
+ # Total number of tests that warned.
836
+
837
+ attr_accessor :warnings
838
+
839
+ ##
840
+ # Total number of tests that where skipped.
841
+
641
842
  attr_accessor :skips
642
- # :startdoc:
643
843
 
644
844
  def initialize io = $stdout, options = {} # :nodoc:
645
845
  super
@@ -651,6 +851,7 @@ module Minitest
651
851
  self.total_time = nil
652
852
  self.failures = nil
653
853
  self.errors = nil
854
+ self.warnings = nil
654
855
  self.skips = nil
655
856
  end
656
857
 
@@ -669,13 +870,17 @@ module Minitest
669
870
  results << result if not result.passed? or result.skipped?
670
871
  end
671
872
 
672
- def report # :nodoc:
873
+ ##
874
+ # Report on the tracked statistics.
875
+
876
+ def report
673
877
  aggregate = results.group_by { |r| r.failure.class }
674
878
  aggregate.default = [] # dumb. group_by should provide this
675
879
 
676
880
  self.total_time = Minitest.clock_time - start_time
677
881
  self.failures = aggregate[Assertion].size
678
882
  self.errors = aggregate[UnexpectedError].size
883
+ self.warnings = aggregate[UnexpectedWarning].size
679
884
  self.skips = aggregate[Skip].size
680
885
  end
681
886
  end
@@ -690,10 +895,8 @@ module Minitest
690
895
  # own.
691
896
 
692
897
  class SummaryReporter < StatisticsReporter
693
- # :stopdoc:
694
- attr_accessor :sync
695
- attr_accessor :old_sync
696
- # :startdoc:
898
+ attr_accessor :sync # :nodoc:
899
+ attr_accessor :old_sync # :nodoc:
697
900
 
698
901
  def start # :nodoc:
699
902
  super
@@ -703,7 +906,7 @@ module Minitest
703
906
  io.puts "# Running:"
704
907
  io.puts
705
908
 
706
- self.sync = io.respond_to? :"sync=" # stupid emacs
909
+ self.sync = io.respond_to? :"sync="
707
910
  self.old_sync, io.sync = io.sync, true if self.sync
708
911
  end
709
912
 
@@ -726,9 +929,14 @@ module Minitest
726
929
 
727
930
  def aggregated_results io # :nodoc:
728
931
  filtered_results = results.dup
729
- filtered_results.reject!(&:skipped?) unless options[:verbose]
932
+ filtered_results.reject!(&:skipped?) unless
933
+ options[:verbose] or options[:show_skips]
934
+
935
+ skip = options[:skip] || []
730
936
 
731
937
  filtered_results.each_with_index { |result, i|
938
+ next if skip.include? result.result_code
939
+
732
940
  io.puts "\n%3d) %s" % [i+1, result]
733
941
  }
734
942
  io.puts
@@ -736,25 +944,22 @@ module Minitest
736
944
  end
737
945
 
738
946
  def to_s # :nodoc:
739
- aggregated_results(StringIO.new(binary_string)).string
947
+ aggregated_results(StringIO.new("".b)).string
740
948
  end
741
949
 
742
950
  def summary # :nodoc:
743
- extra = ""
744
-
745
- extra = "\n\nYou have skipped tests. Run with --verbose for details." if
746
- results.any?(&:skipped?) unless options[:verbose] or ENV["MT_NO_SKIP_MSG"]
951
+ extra = []
747
952
 
748
- "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
749
- [count, assertions, failures, errors, skips, extra]
750
- end
953
+ extra << ", %d warnings" % [warnings] if options[:Werror]
751
954
 
752
- private
955
+ extra << "\n\nYou have skipped tests. Run with --verbose for details." if
956
+ results.any?(&:skipped?) unless
957
+ options[:verbose] or
958
+ options[:show_skips] or
959
+ ENV["MT_NO_SKIP_MSG"]
753
960
 
754
- if '<3'.respond_to? :b
755
- def binary_string; ''.b; end
756
- else
757
- def binary_string; ''.force_encoding(Encoding::ASCII_8BIT); end
961
+ "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
962
+ [count, assertions, failures, errors, skips, extra.join]
758
963
  end
759
964
  end
760
965
 
@@ -813,6 +1018,8 @@ module Minitest
813
1018
  # Represents run failures.
814
1019
 
815
1020
  class Assertion < Exception
1021
+ RE = /in [`'](?:[^']+[#.])?(?:assert|refute|flunk|pass|fail|raise|must|wont)/ # :nodoc:
1022
+
816
1023
  def error # :nodoc:
817
1024
  self
818
1025
  end
@@ -821,12 +1028,11 @@ module Minitest
821
1028
  # Where was this run before an assertion was raised?
822
1029
 
823
1030
  def location
824
- last_before_assertion = ""
825
- self.backtrace.reverse_each do |s|
826
- break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
827
- last_before_assertion = s
828
- end
829
- 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 .*$/, "")
830
1036
  end
831
1037
 
832
1038
  def result_code # :nodoc:
@@ -851,24 +1057,34 @@ module Minitest
851
1057
  # Assertion wrapping an unexpected error that was raised during a run.
852
1058
 
853
1059
  class UnexpectedError < Assertion
854
- attr_accessor :exception # :nodoc:
1060
+ include Minitest::Compress
855
1061
 
856
- def initialize exception # :nodoc:
1062
+ # TODO: figure out how to use `cause` instead
1063
+ attr_accessor :error # :nodoc:
1064
+
1065
+ def initialize error # :nodoc:
857
1066
  super "Unexpected exception"
858
- self.exception = 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
+
1075
+ self.error = error
859
1076
  end
860
1077
 
861
1078
  def backtrace # :nodoc:
862
- self.exception.backtrace
1079
+ self.error.backtrace
863
1080
  end
864
1081
 
865
- def error # :nodoc:
866
- self.exception
867
- end
1082
+ BASE_RE = %r%#{Dir.pwd}/% # :nodoc:
868
1083
 
869
1084
  def message # :nodoc:
870
- bt = Minitest.filter_backtrace(self.backtrace).join "\n "
871
- "#{self.exception.class}: #{self.exception.message}\n #{bt}"
1085
+ bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
1086
+ .gsub(BASE_RE, "")
1087
+ "#{self.error.class}: #{self.error.message}\n #{bt}"
872
1088
  end
873
1089
 
874
1090
  def result_label # :nodoc:
@@ -876,6 +1092,15 @@ module Minitest
876
1092
  end
877
1093
  end
878
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
+
879
1104
  ##
880
1105
  # Provides a simple set of guards that you can use in your tests
881
1106
  # to skip execution if it is not applicable. These methods are
@@ -904,6 +1129,9 @@ module Minitest
904
1129
  # Is this running on maglev?
905
1130
 
906
1131
  def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1132
+ where = Minitest.filter_backtrace(caller).first
1133
+ where = where.split(":in ", 2).first # clean up noise
1134
+ warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
907
1135
  "maglev" == platform
908
1136
  end
909
1137
 
@@ -911,13 +1139,23 @@ module Minitest
911
1139
  # Is this running on mri?
912
1140
 
913
1141
  def mri? platform = RUBY_DESCRIPTION
914
- /^ruby/ =~ platform
1142
+ platform.start_with? "ruby"
1143
+ end
1144
+
1145
+ ##
1146
+ # Is this running on macOS?
1147
+
1148
+ def osx? platform = RUBY_PLATFORM
1149
+ platform.include? "darwin"
915
1150
  end
916
1151
 
917
1152
  ##
918
1153
  # Is this running on rubinius?
919
1154
 
920
1155
  def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1156
+ where = Minitest.filter_backtrace(caller).first
1157
+ where = where.split(":in ", 2).first # clean up noise
1158
+ warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
921
1159
  "rbx" == platform
922
1160
  end
923
1161
 
@@ -925,7 +1163,7 @@ module Minitest
925
1163
  # Is this running on windows?
926
1164
 
927
1165
  def windows? platform = RUBY_PLATFORM
928
- /mswin|mingw/ =~ platform
1166
+ /mswin|mingw/.match? platform
929
1167
  end
930
1168
  end
931
1169
 
@@ -936,19 +1174,29 @@ module Minitest
936
1174
 
937
1175
  class BacktraceFilter
938
1176
 
939
- 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
940
1187
 
941
1188
  ##
942
- # Filter +bt+ to something useful. Returns the whole thing if $DEBUG.
1189
+ # Filter +bt+ to something useful. Returns the whole thing if
1190
+ # $DEBUG (ruby) or $MT_DEBUG (env).
943
1191
 
944
1192
  def filter bt
945
1193
  return ["No backtrace"] unless bt
946
1194
 
947
- return bt.dup if $DEBUG
1195
+ return bt.dup if $DEBUG || ENV["MT_DEBUG"]
948
1196
 
949
- new_bt = bt.take_while { |line| line !~ MT_RE }
950
- new_bt = bt.select { |line| line !~ MT_RE } if new_bt.empty?
951
- 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?
952
1200
 
953
1201
  new_bt
954
1202
  end