minitest 5.10.3 → 5.18.0

Sign up to get free protection for your applications and to get access to all the features.
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