minitest 5.10.3 → 5.18.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
@@ -3,59 +3,79 @@ require "thread"
3
3
  require "mutex_m"
4
4
  require "minitest/parallel"
5
5
  require "stringio"
6
+ require "etc"
6
7
 
7
8
  ##
8
9
  # :include: README.rdoc
9
10
 
10
11
  module Minitest
11
- VERSION = "5.10.3" # :nodoc:
12
- ENCS = "".respond_to? :encoding # :nodoc:
12
+ VERSION = "5.18.0" # :nodoc:
13
13
 
14
14
  @@installed_at_exit ||= false
15
15
  @@after_run = []
16
16
  @extensions = []
17
17
 
18
- mc = (class << self; self; end)
18
+ def self.cattr_accessor name # :nodoc:
19
+ (class << self; self; end).attr_accessor name
20
+ end
21
+
22
+ ##
23
+ # The random seed used for this run. This is used to srand at the
24
+ # start of the run and between each +Runnable.run+.
25
+ #
26
+ # Set via Minitest.run after processing args.
27
+
28
+ cattr_accessor :seed
19
29
 
20
30
  ##
21
31
  # Parallel test executor
22
32
 
23
- mc.send :attr_accessor, :parallel_executor
24
- self.parallel_executor = Parallel::Executor.new((ENV["N"] || 2).to_i)
33
+ cattr_accessor :parallel_executor
34
+
35
+ warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"]
36
+ n_threads = (ENV["MT_CPU"] || ENV["N"] || Etc.nprocessors).to_i
37
+
38
+ self.parallel_executor = Parallel::Executor.new n_threads
25
39
 
26
40
  ##
27
41
  # Filter object for backtraces.
28
42
 
29
- mc.send :attr_accessor, :backtrace_filter
43
+ cattr_accessor :backtrace_filter
30
44
 
31
45
  ##
32
46
  # Reporter object to be used for all runs.
33
47
  #
34
48
  # NOTE: This accessor is only available during setup, not during runs.
35
49
 
36
- mc.send :attr_accessor, :reporter
50
+ cattr_accessor :reporter
37
51
 
38
52
  ##
39
53
  # Names of known extension plugins.
40
54
 
41
- mc.send :attr_accessor, :extensions
55
+ cattr_accessor :extensions
42
56
 
43
57
  ##
44
58
  # The signal to use for dumping information to STDERR. Defaults to "INFO".
45
59
 
46
- mc.send :attr_accessor, :info_signal
60
+ cattr_accessor :info_signal
47
61
  self.info_signal = "INFO"
48
62
 
49
63
  ##
50
64
  # Registers Minitest to run at process exit
51
65
 
52
66
  def self.autorun
67
+ if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
68
+ Warning[:deprecated] = true
69
+ end
70
+
53
71
  at_exit {
54
72
  next if $! and not ($!.kind_of? SystemExit and $!.success?)
55
73
 
56
74
  exit_code = nil
57
75
 
76
+ pid = Process.pid
58
77
  at_exit {
78
+ next if Process.pid != pid
59
79
  @@after_run.reverse_each(&:call)
60
80
  exit exit_code || false
61
81
  }
@@ -118,10 +138,13 @@ module Minitest
118
138
  # klass.new(runnable_method).run
119
139
 
120
140
  def self.run args = []
121
- self.load_plugins
141
+ self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
122
142
 
123
143
  options = process_args args
124
144
 
145
+ Minitest.seed = options[:seed]
146
+ srand Minitest.seed
147
+
125
148
  reporter = CompositeReporter.new
126
149
  reporter << SummaryReporter.new(options[:io], options)
127
150
  reporter << ProgressReporter.new(options[:io], options)
@@ -148,7 +171,7 @@ module Minitest
148
171
  # sub-classes to run.
149
172
 
150
173
  def self.__run reporter, options
151
- suites = Runnable.runnables.reject { |s| s.runnable_methods.empty? }.shuffle
174
+ suites = Runnable.runnables.shuffle
152
175
  parallel, serial = suites.partition { |s| s.test_order == :parallel }
153
176
 
154
177
  # If we run the parallel tests before the serial tests, the parallel tests
@@ -175,6 +198,8 @@ module Minitest
175
198
  exit
176
199
  end
177
200
 
201
+ opts.on "--no-plugins", "Bypass minitest plugin auto-loading (or set $MT_NO_PLUGINS)."
202
+
178
203
  desc = "Sets random seed. Also via env. Eg: SEED=n rake"
179
204
  opts.on "-s", "--seed SEED", Integer, desc do |m|
180
205
  options[:seed] = m.to_i
@@ -184,6 +209,10 @@ module Minitest
184
209
  options[:verbose] = true
185
210
  end
186
211
 
212
+ opts.on "--show-skips", "Show skipped at the end of run." do
213
+ options[:show_skips] = true
214
+ end
215
+
187
216
  opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
188
217
  options[:filter] = a
189
218
  end
@@ -192,6 +221,10 @@ module Minitest
192
221
  options[:exclude] = a
193
222
  end
194
223
 
224
+ opts.on "-S", "--skip CODES", String, "Skip reporting of certain types of results (eg E)." do |s|
225
+ options[:skip] = s.chars.to_a
226
+ end
227
+
195
228
  unless extensions.empty?
196
229
  opts.separator ""
197
230
  opts.separator "Known extensions: #{extensions.join(", ")}"
@@ -221,8 +254,6 @@ module Minitest
221
254
  orig_args << "--seed" << options[:seed].to_s
222
255
  end
223
256
 
224
- srand options[:seed]
225
-
226
257
  options[:args] = orig_args.map { |s|
227
258
  s =~ /[\s|&<>$()]/ ? s.inspect : s
228
259
  }.join " "
@@ -231,7 +262,9 @@ module Minitest
231
262
  end
232
263
 
233
264
  def self.filter_backtrace bt # :nodoc:
234
- backtrace_filter.filter bt
265
+ result = backtrace_filter.filter bt
266
+ result = bt.dup if result.empty?
267
+ result
235
268
  end
236
269
 
237
270
  ##
@@ -252,6 +285,19 @@ module Minitest
252
285
 
253
286
  attr_accessor :failures
254
287
 
288
+ ##
289
+ # The time it took to run.
290
+
291
+ attr_accessor :time
292
+
293
+ def time_it # :nodoc:
294
+ t0 = Minitest.clock_time
295
+
296
+ yield
297
+ ensure
298
+ self.time = Minitest.clock_time - t0
299
+ end
300
+
255
301
  ##
256
302
  # Name of the run.
257
303
 
@@ -266,11 +312,6 @@ module Minitest
266
312
  @NAME = o
267
313
  end
268
314
 
269
- def self.inherited klass # :nodoc:
270
- self.runnables << klass
271
- super
272
- end
273
-
274
315
  ##
275
316
  # Returns all instance methods matching the pattern +re+.
276
317
 
@@ -291,7 +332,7 @@ module Minitest
291
332
 
292
333
  def self.run reporter, options = {}
293
334
  filter = options[:filter] || "/./"
294
- filter = Regexp.new $1 if filter =~ %r%/(.*)/%
335
+ filter = Regexp.new $1 if filter.is_a?(String) && filter =~ %r%/(.*)/%
295
336
 
296
337
  filtered_methods = self.runnable_methods.find_all { |m|
297
338
  filter === m || filter === "#{self}##{m}"
@@ -367,12 +408,20 @@ module Minitest
367
408
  @@runnables
368
409
  end
369
410
 
411
+ @@marshal_dump_warned = false
412
+
370
413
  def marshal_dump # :nodoc:
371
- [self.name, self.failures, self.assertions]
414
+ unless @@marshal_dump_warned then
415
+ warn ["Minitest::Runnable#marshal_dump is deprecated.",
416
+ "You might be violating internals. From", caller.first].join " "
417
+ @@marshal_dump_warned = true
418
+ end
419
+
420
+ [self.name, self.failures, self.assertions, self.time]
372
421
  end
373
422
 
374
423
  def marshal_load ary # :nodoc:
375
- self.name, self.failures, self.assertions = ary
424
+ self.name, self.failures, self.assertions, self.time = ary
376
425
  end
377
426
 
378
427
  def failure # :nodoc:
@@ -404,7 +453,8 @@ module Minitest
404
453
 
405
454
  ##
406
455
  # Returns a single character string to print based on the result
407
- # of the run. Eg ".", "F", or "E".
456
+ # of the run. One of <tt>"."</tt>, <tt>"F"</tt>,
457
+ # <tt>"E"</tt> or <tt>"S"</tt>.
408
458
 
409
459
  def result_code
410
460
  raise NotImplementedError, "subclass responsibility"
@@ -418,6 +468,109 @@ module Minitest
418
468
  end
419
469
  end
420
470
 
471
+ ##
472
+ # Shared code for anything that can get passed to a Reporter. See
473
+ # Minitest::Test & Minitest::Result.
474
+
475
+ module Reportable
476
+ ##
477
+ # Did this run pass?
478
+ #
479
+ # Note: skipped runs are not considered passing, but they don't
480
+ # cause the process to exit non-zero.
481
+
482
+ def passed?
483
+ not self.failure
484
+ end
485
+
486
+ ##
487
+ # The location identifier of this test. Depends on a method
488
+ # existing called class_name.
489
+
490
+ def location
491
+ loc = " [#{self.failure.location}]" unless passed? or error?
492
+ "#{self.class_name}##{self.name}#{loc}"
493
+ end
494
+
495
+ def class_name # :nodoc:
496
+ raise NotImplementedError, "subclass responsibility"
497
+ end
498
+
499
+ ##
500
+ # Returns ".", "F", or "E" based on the result of the run.
501
+
502
+ def result_code
503
+ self.failure and self.failure.result_code or "."
504
+ end
505
+
506
+ ##
507
+ # Was this run skipped?
508
+
509
+ def skipped?
510
+ self.failure and Skip === self.failure
511
+ end
512
+
513
+ ##
514
+ # Did this run error?
515
+
516
+ def error?
517
+ self.failures.any? { |f| UnexpectedError === f }
518
+ end
519
+ end
520
+
521
+ ##
522
+ # This represents a test result in a clean way that can be
523
+ # marshalled over a wire. Tests can do anything they want to the
524
+ # test instance and can create conditions that cause Marshal.dump to
525
+ # blow up. By using Result.from(a_test) you can be reasonably sure
526
+ # that the test result can be marshalled.
527
+
528
+ class Result < Runnable
529
+ include Minitest::Reportable
530
+
531
+ undef_method :marshal_dump
532
+ undef_method :marshal_load
533
+
534
+ ##
535
+ # The class name of the test result.
536
+
537
+ attr_accessor :klass
538
+
539
+ ##
540
+ # The location of the test method.
541
+
542
+ attr_accessor :source_location
543
+
544
+ ##
545
+ # Create a new test result from a Runnable instance.
546
+
547
+ def self.from runnable
548
+ o = runnable
549
+
550
+ r = self.new o.name
551
+ r.klass = o.class.name
552
+ r.assertions = o.assertions
553
+ r.failures = o.failures.dup
554
+ r.time = o.time
555
+
556
+ r.source_location = o.method(o.name).source_location rescue ["unknown", -1]
557
+
558
+ r
559
+ end
560
+
561
+ def class_name # :nodoc:
562
+ self.klass # for Minitest::Reportable
563
+ end
564
+
565
+ def to_s # :nodoc:
566
+ return location if passed? and not skipped?
567
+
568
+ failures.map { |failure|
569
+ "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
570
+ }.join "\n"
571
+ end
572
+ end
573
+
421
574
  ##
422
575
  # Defines the API for Reporters. Subclass this and override whatever
423
576
  # you want. Go nuts.
@@ -439,8 +592,10 @@ module Minitest
439
592
  end
440
593
 
441
594
  ##
442
- # Record a result and output the Runnable#result_code. Stores the
443
- # result of the run if the run did not pass.
595
+ # Output and record the result of the test. Call
596
+ # {result#result_code}[rdoc-ref:Runnable#result_code] to get the
597
+ # result character string. Stores the result of the run if the run
598
+ # did not pass.
444
599
 
445
600
  def record result
446
601
  end
@@ -488,7 +643,7 @@ module Minitest
488
643
  class ProgressReporter < Reporter
489
644
  def prerecord klass, name #:nodoc:
490
645
  if options[:verbose] then
491
- io.print "%s#%s = " % [klass, name]
646
+ io.print "%s#%s = " % [klass.name, name]
492
647
  io.flush
493
648
  end
494
649
  end
@@ -507,18 +662,63 @@ module Minitest
507
662
  #
508
663
  # If you want to create an entirely different type of output (eg,
509
664
  # CI, HTML, etc), this is the place to start.
665
+ #
666
+ # Example:
667
+ #
668
+ # class JenkinsCIReporter < StatisticsReporter
669
+ # def report
670
+ # super # Needed to calculate some statistics
671
+ #
672
+ # print "<testsuite "
673
+ # print "tests='#{count}' "
674
+ # print "failures='#{failures}' "
675
+ # # Remaining XML...
676
+ # end
677
+ # end
510
678
 
511
679
  class StatisticsReporter < Reporter
512
- # :stopdoc:
680
+ ##
681
+ # Total number of assertions.
682
+
513
683
  attr_accessor :assertions
684
+
685
+ ##
686
+ # Total number of test cases.
687
+
514
688
  attr_accessor :count
689
+
690
+ ##
691
+ # An +Array+ of test cases that failed or were skipped.
692
+
515
693
  attr_accessor :results
694
+
695
+ ##
696
+ # Time the test run started. If available, the monotonic clock is
697
+ # used and this is a +Float+, otherwise it's an instance of
698
+ # +Time+.
699
+
516
700
  attr_accessor :start_time
701
+
702
+ ##
703
+ # Test run time. If available, the monotonic clock is used and
704
+ # this is a +Float+, otherwise it's an instance of +Time+.
705
+
517
706
  attr_accessor :total_time
707
+
708
+ ##
709
+ # Total number of tests that failed.
710
+
518
711
  attr_accessor :failures
712
+
713
+ ##
714
+ # Total number of tests that erred.
715
+
519
716
  attr_accessor :errors
717
+
718
+ ##
719
+ # Total number of tests that where skipped.
720
+
520
721
  attr_accessor :skips
521
- # :startdoc:
522
722
 
523
723
  def initialize io = $stdout, options = {} # :nodoc:
524
724
  super
@@ -548,7 +748,10 @@ module Minitest
548
748
  results << result if not result.passed? or result.skipped?
549
749
  end
550
750
 
551
- def report # :nodoc:
751
+ ##
752
+ # Report on the tracked statistics.
753
+
754
+ def report
552
755
  aggregate = results.group_by { |r| r.failure.class }
553
756
  aggregate.default = [] # dumb. group_by should provide this
554
757
 
@@ -605,9 +808,14 @@ module Minitest
605
808
 
606
809
  def aggregated_results io # :nodoc:
607
810
  filtered_results = results.dup
608
- filtered_results.reject!(&:skipped?) unless options[:verbose]
811
+ filtered_results.reject!(&:skipped?) unless
812
+ options[:verbose] or options[:show_skips]
813
+
814
+ skip = options[:skip] || []
609
815
 
610
816
  filtered_results.each_with_index { |result, i|
817
+ next if skip.include? result.result_code
818
+
611
819
  io.puts "\n%3d) %s" % [i+1, result]
612
820
  }
613
821
  io.puts
@@ -615,26 +823,19 @@ module Minitest
615
823
  end
616
824
 
617
825
  def to_s # :nodoc:
618
- aggregated_results(StringIO.new(binary_string)).string
826
+ aggregated_results(StringIO.new(''.b)).string
619
827
  end
620
828
 
621
829
  def summary # :nodoc:
622
830
  extra = ""
623
831
 
624
832
  extra = "\n\nYou have skipped tests. Run with --verbose for details." if
625
- results.any?(&:skipped?) unless options[:verbose] or ENV["MT_NO_SKIP_MSG"]
833
+ results.any?(&:skipped?) unless
834
+ options[:verbose] or options[:show_skips] or ENV["MT_NO_SKIP_MSG"]
626
835
 
627
836
  "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
628
837
  [count, assertions, failures, errors, skips, extra]
629
838
  end
630
-
631
- private
632
-
633
- if '<3'.respond_to? :b
634
- def binary_string; ''.b; end
635
- else
636
- def binary_string; ''.force_encoding(Encoding::ASCII_8BIT); end
637
- end
638
839
  end
639
840
 
640
841
  ##
@@ -730,24 +931,21 @@ module Minitest
730
931
  # Assertion wrapping an unexpected error that was raised during a run.
731
932
 
732
933
  class UnexpectedError < Assertion
733
- attr_accessor :exception # :nodoc:
934
+ # TODO: figure out how to use `cause` instead
935
+ attr_accessor :error # :nodoc:
734
936
 
735
- def initialize exception # :nodoc:
937
+ def initialize error # :nodoc:
736
938
  super "Unexpected exception"
737
- self.exception = exception
939
+ self.error = error
738
940
  end
739
941
 
740
942
  def backtrace # :nodoc:
741
- self.exception.backtrace
742
- end
743
-
744
- def error # :nodoc:
745
- self.exception
943
+ self.error.backtrace
746
944
  end
747
945
 
748
946
  def message # :nodoc:
749
947
  bt = Minitest.filter_backtrace(self.backtrace).join "\n "
750
- "#{self.exception.class}: #{self.exception.message}\n #{bt}"
948
+ "#{self.error.class}: #{self.error.message}\n #{bt}"
751
949
  end
752
950
 
753
951
  def result_label # :nodoc:
@@ -783,6 +981,9 @@ module Minitest
783
981
  # Is this running on maglev?
784
982
 
785
983
  def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
984
+ where = Minitest.filter_backtrace(caller).first
985
+ where = where.split(/:in /, 2).first # clean up noise
986
+ warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
786
987
  "maglev" == platform
787
988
  end
788
989
 
@@ -793,10 +994,20 @@ module Minitest
793
994
  /^ruby/ =~ platform
794
995
  end
795
996
 
997
+ ##
998
+ # Is this running on macOS?
999
+
1000
+ def osx? platform = RUBY_PLATFORM
1001
+ /darwin/ =~ platform
1002
+ end
1003
+
796
1004
  ##
797
1005
  # Is this running on rubinius?
798
1006
 
799
1007
  def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1008
+ where = Minitest.filter_backtrace(caller).first
1009
+ where = where.split(/:in /, 2).first # clean up noise
1010
+ warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
800
1011
  "rbx" == platform
801
1012
  end
802
1013
 
@@ -818,12 +1029,13 @@ module Minitest
818
1029
  MT_RE = %r%lib/minitest% #:nodoc:
819
1030
 
820
1031
  ##
821
- # Filter +bt+ to something useful. Returns the whole thing if $DEBUG.
1032
+ # Filter +bt+ to something useful. Returns the whole thing if
1033
+ # $DEBUG (ruby) or $MT_DEBUG (env).
822
1034
 
823
1035
  def filter bt
824
1036
  return ["No backtrace"] unless bt
825
1037
 
826
- return bt.dup if $DEBUG
1038
+ return bt.dup if $DEBUG || ENV["MT_DEBUG"]
827
1039
 
828
1040
  new_bt = bt.take_while { |line| line !~ MT_RE }
829
1041
  new_bt = bt.select { |line| line !~ MT_RE } if new_bt.empty?
@@ -837,7 +1049,7 @@ module Minitest
837
1049
 
838
1050
  def self.run_one_method klass, method_name # :nodoc:
839
1051
  result = klass.new(method_name).run
840
- raise "#{klass}#run _must_ return self" unless klass === result
1052
+ raise "#{klass}#run _must_ return a Result" unless Result === result
841
1053
  result
842
1054
  end
843
1055
 
@@ -853,6 +1065,13 @@ module Minitest
853
1065
  end
854
1066
  end
855
1067
 
1068
+ class Runnable # re-open
1069
+ def self.inherited klass # :nodoc:
1070
+ self.runnables << klass
1071
+ super
1072
+ end
1073
+ end
1074
+
856
1075
  # :startdoc:
857
1076
  end
858
1077
 
@@ -6,8 +6,27 @@ class Minitest::Test
6
6
  def clean s
7
7
  s.gsub(/^ {6}/, "")
8
8
  end
9
+
10
+ def with_empty_backtrace_filter
11
+ original = Minitest.backtrace_filter
12
+
13
+ obj = Minitest::BacktraceFilter.new
14
+ def obj.filter _bt
15
+ []
16
+ end
17
+
18
+ Minitest::Test.io_lock.synchronize do # try not to trounce in parallel
19
+ begin
20
+ Minitest.backtrace_filter = obj
21
+ yield
22
+ ensure
23
+ Minitest.backtrace_filter = original
24
+ end
25
+ end
26
+ end
9
27
  end
10
28
 
29
+
11
30
  class FakeNamedTest < Minitest::Test
12
31
  @@count = 0
13
32
 
@@ -19,9 +38,20 @@ class FakeNamedTest < Minitest::Test
19
38
  end
20
39
  end
21
40
 
41
+ module MyModule; end
42
+ class AnError < StandardError; include MyModule; end
43
+
22
44
  class MetaMetaMetaTestCase < Minitest::Test
23
45
  attr_accessor :reporter, :output, :tu
24
46
 
47
+ def with_stderr err
48
+ old = $stderr
49
+ $stderr = err
50
+ yield
51
+ ensure
52
+ $stderr = old
53
+ end
54
+
25
55
  def run_tu_with_fresh_reporter flags = %w[--seed 42]
26
56
  options = Minitest.process_args flags
27
57
 
@@ -31,18 +61,20 @@ class MetaMetaMetaTestCase < Minitest::Test
31
61
  reporter << Minitest::SummaryReporter.new(@output, options)
32
62
  reporter << Minitest::ProgressReporter.new(@output, options)
33
63
 
34
- reporter.start
64
+ with_stderr @output do
65
+ reporter.start
35
66
 
36
- yield(reporter) if block_given?
67
+ yield(reporter) if block_given?
37
68
 
38
- @tus ||= [@tu]
39
- @tus.each do |tu|
40
- Minitest::Runnable.runnables.delete tu
69
+ @tus ||= [@tu]
70
+ @tus.each do |tu|
71
+ Minitest::Runnable.runnables.delete tu
41
72
 
42
- tu.run reporter, options
43
- end
73
+ tu.run reporter, options
74
+ end
44
75
 
45
- reporter.report
76
+ reporter.report
77
+ end
46
78
  end
47
79
 
48
80
  def first_reporter
@@ -68,6 +100,7 @@ class MetaMetaMetaTestCase < Minitest::Test
68
100
  output.sub!(/Finished in .*/, "Finished in 0.00")
69
101
  output.sub!(/Loaded suite .*/, "Loaded suite blah")
70
102
 
103
+ output.gsub!(/FakeNamedTest\d+/, "FakeNamedTestXX")
71
104
  output.gsub!(/ = \d+.\d\d s = /, " = 0.00 s = ")
72
105
  output.gsub!(/0x[A-Fa-f0-9]+/, "0xXXX")
73
106
  output.gsub!(/ +$/, "")
@@ -80,6 +113,8 @@ class MetaMetaMetaTestCase < Minitest::Test
80
113
  output.gsub!(/^(\s+)[^:]+:\d+:in/, '\1FILE:LINE:in')
81
114
  end
82
115
 
116
+ output.gsub!(/( at )[^:]+:\d+/, '\1[FILE:LINE]')
117
+
83
118
  output
84
119
  end
85
120
 
@@ -94,7 +129,7 @@ class MetaMetaMetaTestCase < Minitest::Test
94
129
 
95
130
  def setup
96
131
  super
97
- srand 42
132
+ Minitest.seed = 42
98
133
  Minitest::Test.reset
99
134
  @tu = nil
100
135
  end