minitest 5.10.3 → 5.15.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -53,7 +53,7 @@ module Minitest
53
53
  end
54
54
  end
55
55
 
56
- module Test
56
+ module Test # :nodoc:
57
57
  def _synchronize; Minitest::Test.io_lock.synchronize { yield }; end # :nodoc:
58
58
 
59
59
  module ClassMethods # :nodoc:
data/lib/minitest/spec.rb CHANGED
@@ -4,16 +4,21 @@ class Module # :nodoc:
4
4
  def infect_an_assertion meth, new_name, dont_flip = false # :nodoc:
5
5
  block = dont_flip == :block
6
6
  dont_flip = false if block
7
+ target_obj = block ? '_{obj.method}' : '_(obj)'
7
8
 
8
9
  # warn "%-22p -> %p %p" % [meth, new_name, dont_flip]
9
10
  self.class_eval <<-EOM, __FILE__, __LINE__ + 1
10
11
  def #{new_name} *args
12
+ where = Minitest.filter_backtrace(caller).first
13
+ where = where.split(/:in /, 2).first # clean up noise
14
+ Kernel.warn "DEPRECATED: global use of #{new_name} from #\{where}. Use #{target_obj}.#{new_name} instead. This will fail in Minitest 6."
11
15
  Minitest::Expectation.new(self, Minitest::Spec.current).#{new_name}(*args)
12
16
  end
13
17
  EOM
14
18
 
15
19
  Minitest::Expectation.class_eval <<-EOM, __FILE__, __LINE__ + 1
16
20
  def #{new_name} *args
21
+ raise "Calling ##{new_name} outside of test." unless ctx
17
22
  case
18
23
  when #{!!dont_flip} then
19
24
  ctx.#{meth}(target, *args)
@@ -285,21 +290,28 @@ class Minitest::Spec < Minitest::Test
285
290
 
286
291
  module InstanceMethods
287
292
  ##
288
- # Returns a value monad that has all of Expectations methods
289
- # available to it.
293
+ # Takes a value or a block and returns a value monad that has
294
+ # all of Expectations methods available to it.
290
295
  #
291
- # Also aliased to #value and #expect for your aesthetic pleasure:
296
+ # _(1 + 1).must_equal 2
292
297
  #
293
- # _(1 + 1).must_equal 2
294
- # value(1 + 1).must_equal 2
295
- # expect(1 + 1).must_equal 2
298
+ # And for blocks:
299
+ #
300
+ # _ { 1 + "1" }.must_raise TypeError
296
301
  #
297
302
  # This method of expectation-based testing is preferable to
298
303
  # straight-expectation methods (on Object) because it stores its
299
304
  # test context, bypassing our hacky use of thread-local variables.
300
305
  #
301
- # At some point, the methods on Object will be deprecated and then
302
- # removed.
306
+ # NOTE: At some point, the methods on Object will be deprecated
307
+ # and then removed.
308
+ #
309
+ # It is also aliased to #value and #expect for your aesthetic
310
+ # pleasure:
311
+ #
312
+ # _(1 + 1).must_equal 2
313
+ # value(1 + 1).must_equal 2
314
+ # expect(1 + 1).must_equal 2
303
315
 
304
316
  def _ value = nil, &block
305
317
  Minitest::Expectation.new block || value, self
data/lib/minitest/test.rb CHANGED
@@ -10,6 +10,11 @@ module Minitest
10
10
  class Test < Runnable
11
11
  require "minitest/assertions"
12
12
  include Minitest::Assertions
13
+ include Minitest::Reportable
14
+
15
+ def class_name # :nodoc:
16
+ self.class.name # for Minitest::Reportable
17
+ end
13
18
 
14
19
  PASSTHROUGH_EXCEPTIONS = [NoMemoryError, SignalException, SystemExit] # :nodoc:
15
20
 
@@ -79,20 +84,6 @@ module Minitest
79
84
  :random
80
85
  end
81
86
 
82
- ##
83
- # The time it took to run this test.
84
-
85
- attr_accessor :time
86
-
87
- def marshal_dump # :nodoc:
88
- super << self.time
89
- end
90
-
91
- def marshal_load ary # :nodoc:
92
- self.time = ary.pop
93
- super
94
- end
95
-
96
87
  TEARDOWN_METHODS = %w[ before_teardown teardown after_teardown ] # :nodoc:
97
88
 
98
89
  ##
@@ -115,7 +106,7 @@ module Minitest
115
106
  end
116
107
  end
117
108
 
118
- self # per contract
109
+ Result.from self # per contract
119
110
  end
120
111
 
121
112
  ##
@@ -207,62 +198,17 @@ module Minitest
207
198
  rescue Assertion => e
208
199
  self.failures << e
209
200
  rescue Exception => e
210
- self.failures << UnexpectedError.new(e)
201
+ self.failures << UnexpectedError.new(sanitize_exception e)
211
202
  end
212
203
 
213
- ##
214
- # Did this run error?
215
-
216
- def error?
217
- self.failures.any? { |f| UnexpectedError === f }
218
- end
219
-
220
- ##
221
- # The location identifier of this test.
222
-
223
- def location
224
- loc = " [#{self.failure.location}]" unless passed? or error?
225
- "#{self.class}##{self.name}#{loc}"
226
- end
227
-
228
- ##
229
- # Did this run pass?
230
- #
231
- # Note: skipped runs are not considered passing, but they don't
232
- # cause the process to exit non-zero.
233
-
234
- def passed?
235
- not self.failure
236
- end
237
-
238
- ##
239
- # Returns ".", "F", or "E" based on the result of the run.
240
-
241
- def result_code
242
- self.failure and self.failure.result_code or "."
243
- end
244
-
245
- ##
246
- # Was this run skipped?
247
-
248
- def skipped?
249
- self.failure and Skip === self.failure
250
- end
251
-
252
- def time_it # :nodoc:
253
- t0 = Minitest.clock_time
254
-
255
- yield
256
- ensure
257
- self.time = Minitest.clock_time - t0
258
- end
259
-
260
- def to_s # :nodoc:
261
- return location if passed? and not skipped?
262
-
263
- failures.map { |failure|
264
- "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
265
- }.join "\n"
204
+ def sanitize_exception e # :nodoc:
205
+ Marshal.dump e
206
+ e
207
+ rescue TypeError
208
+ bt = e.backtrace
209
+ e = RuntimeError.new "Wrapped undumpable exception for: #{e.class}: #{e.message}"
210
+ e.set_backtrace bt
211
+ e
266
212
  end
267
213
 
268
214
  def with_info_handler &block # :nodoc:
data/lib/minitest.rb CHANGED
@@ -3,12 +3,13 @@ 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
+ VERSION = "5.15.0" # :nodoc:
12
13
  ENCS = "".respond_to? :encoding # :nodoc:
13
14
 
14
15
  @@installed_at_exit ||= false
@@ -21,7 +22,10 @@ module Minitest
21
22
  # Parallel test executor
22
23
 
23
24
  mc.send :attr_accessor, :parallel_executor
24
- self.parallel_executor = Parallel::Executor.new((ENV["N"] || 2).to_i)
25
+
26
+ warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"]
27
+ n_threads = (ENV["MT_CPU"] || ENV["N"] || Etc.nprocessors).to_i
28
+ self.parallel_executor = Parallel::Executor.new n_threads
25
29
 
26
30
  ##
27
31
  # Filter object for backtraces.
@@ -50,12 +54,18 @@ module Minitest
50
54
  # Registers Minitest to run at process exit
51
55
 
52
56
  def self.autorun
57
+ if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
58
+ Warning[:deprecated] = true
59
+ end
60
+
53
61
  at_exit {
54
62
  next if $! and not ($!.kind_of? SystemExit and $!.success?)
55
63
 
56
64
  exit_code = nil
57
65
 
66
+ pid = Process.pid
58
67
  at_exit {
68
+ next if Process.pid != pid
59
69
  @@after_run.reverse_each(&:call)
60
70
  exit exit_code || false
61
71
  }
@@ -118,7 +128,7 @@ module Minitest
118
128
  # klass.new(runnable_method).run
119
129
 
120
130
  def self.run args = []
121
- self.load_plugins
131
+ self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
122
132
 
123
133
  options = process_args args
124
134
 
@@ -175,6 +185,8 @@ module Minitest
175
185
  exit
176
186
  end
177
187
 
188
+ opts.on "--no-plugins", "Bypass minitest plugin auto-loading (or set $MT_NO_PLUGINS)."
189
+
178
190
  desc = "Sets random seed. Also via env. Eg: SEED=n rake"
179
191
  opts.on "-s", "--seed SEED", Integer, desc do |m|
180
192
  options[:seed] = m.to_i
@@ -192,6 +204,10 @@ module Minitest
192
204
  options[:exclude] = a
193
205
  end
194
206
 
207
+ opts.on "-S", "--skip CODES", String, "Skip reporting of certain types of results (eg E)." do |s|
208
+ options[:skip] = s.chars.to_a
209
+ end
210
+
195
211
  unless extensions.empty?
196
212
  opts.separator ""
197
213
  opts.separator "Known extensions: #{extensions.join(", ")}"
@@ -231,7 +247,9 @@ module Minitest
231
247
  end
232
248
 
233
249
  def self.filter_backtrace bt # :nodoc:
234
- backtrace_filter.filter bt
250
+ result = backtrace_filter.filter bt
251
+ result = bt.dup if result.empty?
252
+ result
235
253
  end
236
254
 
237
255
  ##
@@ -252,6 +270,19 @@ module Minitest
252
270
 
253
271
  attr_accessor :failures
254
272
 
273
+ ##
274
+ # The time it took to run.
275
+
276
+ attr_accessor :time
277
+
278
+ def time_it # :nodoc:
279
+ t0 = Minitest.clock_time
280
+
281
+ yield
282
+ ensure
283
+ self.time = Minitest.clock_time - t0
284
+ end
285
+
255
286
  ##
256
287
  # Name of the run.
257
288
 
@@ -266,11 +297,6 @@ module Minitest
266
297
  @NAME = o
267
298
  end
268
299
 
269
- def self.inherited klass # :nodoc:
270
- self.runnables << klass
271
- super
272
- end
273
-
274
300
  ##
275
301
  # Returns all instance methods matching the pattern +re+.
276
302
 
@@ -291,7 +317,7 @@ module Minitest
291
317
 
292
318
  def self.run reporter, options = {}
293
319
  filter = options[:filter] || "/./"
294
- filter = Regexp.new $1 if filter =~ %r%/(.*)/%
320
+ filter = Regexp.new $1 if filter.is_a?(String) && filter =~ %r%/(.*)/%
295
321
 
296
322
  filtered_methods = self.runnable_methods.find_all { |m|
297
323
  filter === m || filter === "#{self}##{m}"
@@ -367,12 +393,20 @@ module Minitest
367
393
  @@runnables
368
394
  end
369
395
 
396
+ @@marshal_dump_warned = false
397
+
370
398
  def marshal_dump # :nodoc:
371
- [self.name, self.failures, self.assertions]
399
+ unless @@marshal_dump_warned then
400
+ warn ["Minitest::Runnable#marshal_dump is deprecated.",
401
+ "You might be violating internals. From", caller.first].join " "
402
+ @@marshal_dump_warned = true
403
+ end
404
+
405
+ [self.name, self.failures, self.assertions, self.time]
372
406
  end
373
407
 
374
408
  def marshal_load ary # :nodoc:
375
- self.name, self.failures, self.assertions = ary
409
+ self.name, self.failures, self.assertions, self.time = ary
376
410
  end
377
411
 
378
412
  def failure # :nodoc:
@@ -404,7 +438,8 @@ module Minitest
404
438
 
405
439
  ##
406
440
  # Returns a single character string to print based on the result
407
- # of the run. Eg ".", "F", or "E".
441
+ # of the run. One of <tt>"."</tt>, <tt>"F"</tt>,
442
+ # <tt>"E"</tt> or <tt>"S"</tt>.
408
443
 
409
444
  def result_code
410
445
  raise NotImplementedError, "subclass responsibility"
@@ -418,6 +453,109 @@ module Minitest
418
453
  end
419
454
  end
420
455
 
456
+ ##
457
+ # Shared code for anything that can get passed to a Reporter. See
458
+ # Minitest::Test & Minitest::Result.
459
+
460
+ module Reportable
461
+ ##
462
+ # Did this run pass?
463
+ #
464
+ # Note: skipped runs are not considered passing, but they don't
465
+ # cause the process to exit non-zero.
466
+
467
+ def passed?
468
+ not self.failure
469
+ end
470
+
471
+ ##
472
+ # The location identifier of this test. Depends on a method
473
+ # existing called class_name.
474
+
475
+ def location
476
+ loc = " [#{self.failure.location}]" unless passed? or error?
477
+ "#{self.class_name}##{self.name}#{loc}"
478
+ end
479
+
480
+ def class_name # :nodoc:
481
+ raise NotImplementedError, "subclass responsibility"
482
+ end
483
+
484
+ ##
485
+ # Returns ".", "F", or "E" based on the result of the run.
486
+
487
+ def result_code
488
+ self.failure and self.failure.result_code or "."
489
+ end
490
+
491
+ ##
492
+ # Was this run skipped?
493
+
494
+ def skipped?
495
+ self.failure and Skip === self.failure
496
+ end
497
+
498
+ ##
499
+ # Did this run error?
500
+
501
+ def error?
502
+ self.failures.any? { |f| UnexpectedError === f }
503
+ end
504
+ end
505
+
506
+ ##
507
+ # This represents a test result in a clean way that can be
508
+ # marshalled over a wire. Tests can do anything they want to the
509
+ # test instance and can create conditions that cause Marshal.dump to
510
+ # blow up. By using Result.from(a_test) you can be reasonably sure
511
+ # that the test result can be marshalled.
512
+
513
+ class Result < Runnable
514
+ include Minitest::Reportable
515
+
516
+ undef_method :marshal_dump
517
+ undef_method :marshal_load
518
+
519
+ ##
520
+ # The class name of the test result.
521
+
522
+ attr_accessor :klass
523
+
524
+ ##
525
+ # The location of the test method.
526
+
527
+ attr_accessor :source_location
528
+
529
+ ##
530
+ # Create a new test result from a Runnable instance.
531
+
532
+ def self.from runnable
533
+ o = runnable
534
+
535
+ r = self.new o.name
536
+ r.klass = o.class.name
537
+ r.assertions = o.assertions
538
+ r.failures = o.failures.dup
539
+ r.time = o.time
540
+
541
+ r.source_location = o.method(o.name).source_location rescue ["unknown", -1]
542
+
543
+ r
544
+ end
545
+
546
+ def class_name # :nodoc:
547
+ self.klass # for Minitest::Reportable
548
+ end
549
+
550
+ def to_s # :nodoc:
551
+ return location if passed? and not skipped?
552
+
553
+ failures.map { |failure|
554
+ "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
555
+ }.join "\n"
556
+ end
557
+ end
558
+
421
559
  ##
422
560
  # Defines the API for Reporters. Subclass this and override whatever
423
561
  # you want. Go nuts.
@@ -439,8 +577,10 @@ module Minitest
439
577
  end
440
578
 
441
579
  ##
442
- # Record a result and output the Runnable#result_code. Stores the
443
- # result of the run if the run did not pass.
580
+ # Output and record the result of the test. Call
581
+ # {result#result_code}[rdoc-ref:Runnable#result_code] to get the
582
+ # result character string. Stores the result of the run if the run
583
+ # did not pass.
444
584
 
445
585
  def record result
446
586
  end
@@ -488,7 +628,7 @@ module Minitest
488
628
  class ProgressReporter < Reporter
489
629
  def prerecord klass, name #:nodoc:
490
630
  if options[:verbose] then
491
- io.print "%s#%s = " % [klass, name]
631
+ io.print "%s#%s = " % [klass.name, name]
492
632
  io.flush
493
633
  end
494
634
  end
@@ -507,18 +647,63 @@ module Minitest
507
647
  #
508
648
  # If you want to create an entirely different type of output (eg,
509
649
  # CI, HTML, etc), this is the place to start.
650
+ #
651
+ # Example:
652
+ #
653
+ # class JenkinsCIReporter < StatisticsReporter
654
+ # def report
655
+ # super # Needed to calculate some statistics
656
+ #
657
+ # print "<testsuite "
658
+ # print "tests='#{count}' "
659
+ # print "failures='#{failures}' "
660
+ # # Remaining XML...
661
+ # end
662
+ # end
510
663
 
511
664
  class StatisticsReporter < Reporter
512
- # :stopdoc:
665
+ ##
666
+ # Total number of assertions.
667
+
513
668
  attr_accessor :assertions
669
+
670
+ ##
671
+ # Total number of test cases.
672
+
514
673
  attr_accessor :count
674
+
675
+ ##
676
+ # An +Array+ of test cases that failed or were skipped.
677
+
515
678
  attr_accessor :results
679
+
680
+ ##
681
+ # Time the test run started. If available, the monotonic clock is
682
+ # used and this is a +Float+, otherwise it's an instance of
683
+ # +Time+.
684
+
516
685
  attr_accessor :start_time
686
+
687
+ ##
688
+ # Test run time. If available, the monotonic clock is used and
689
+ # this is a +Float+, otherwise it's an instance of +Time+.
690
+
517
691
  attr_accessor :total_time
692
+
693
+ ##
694
+ # Total number of tests that failed.
695
+
518
696
  attr_accessor :failures
697
+
698
+ ##
699
+ # Total number of tests that erred.
700
+
519
701
  attr_accessor :errors
702
+
703
+ ##
704
+ # Total number of tests that where skipped.
705
+
520
706
  attr_accessor :skips
521
- # :startdoc:
522
707
 
523
708
  def initialize io = $stdout, options = {} # :nodoc:
524
709
  super
@@ -548,7 +733,10 @@ module Minitest
548
733
  results << result if not result.passed? or result.skipped?
549
734
  end
550
735
 
551
- def report # :nodoc:
736
+ ##
737
+ # Report on the tracked statistics.
738
+
739
+ def report
552
740
  aggregate = results.group_by { |r| r.failure.class }
553
741
  aggregate.default = [] # dumb. group_by should provide this
554
742
 
@@ -607,7 +795,11 @@ module Minitest
607
795
  filtered_results = results.dup
608
796
  filtered_results.reject!(&:skipped?) unless options[:verbose]
609
797
 
798
+ skip = options[:skip] || []
799
+
610
800
  filtered_results.each_with_index { |result, i|
801
+ next if skip.include? result.result_code
802
+
611
803
  io.puts "\n%3d) %s" % [i+1, result]
612
804
  }
613
805
  io.puts
@@ -730,24 +922,21 @@ module Minitest
730
922
  # Assertion wrapping an unexpected error that was raised during a run.
731
923
 
732
924
  class UnexpectedError < Assertion
733
- attr_accessor :exception # :nodoc:
925
+ # TODO: figure out how to use `cause` instead
926
+ attr_accessor :error # :nodoc:
734
927
 
735
- def initialize exception # :nodoc:
928
+ def initialize error # :nodoc:
736
929
  super "Unexpected exception"
737
- self.exception = exception
930
+ self.error = error
738
931
  end
739
932
 
740
933
  def backtrace # :nodoc:
741
- self.exception.backtrace
742
- end
743
-
744
- def error # :nodoc:
745
- self.exception
934
+ self.error.backtrace
746
935
  end
747
936
 
748
937
  def message # :nodoc:
749
938
  bt = Minitest.filter_backtrace(self.backtrace).join "\n "
750
- "#{self.exception.class}: #{self.exception.message}\n #{bt}"
939
+ "#{self.error.class}: #{self.error.message}\n #{bt}"
751
940
  end
752
941
 
753
942
  def result_label # :nodoc:
@@ -783,6 +972,9 @@ module Minitest
783
972
  # Is this running on maglev?
784
973
 
785
974
  def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
975
+ where = Minitest.filter_backtrace(caller).first
976
+ where = where.split(/:in /, 2).first # clean up noise
977
+ warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
786
978
  "maglev" == platform
787
979
  end
788
980
 
@@ -793,10 +985,20 @@ module Minitest
793
985
  /^ruby/ =~ platform
794
986
  end
795
987
 
988
+ ##
989
+ # Is this running on macOS?
990
+
991
+ def osx? platform = RUBY_PLATFORM
992
+ /darwin/ =~ platform
993
+ end
994
+
796
995
  ##
797
996
  # Is this running on rubinius?
798
997
 
799
998
  def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
999
+ where = Minitest.filter_backtrace(caller).first
1000
+ where = where.split(/:in /, 2).first # clean up noise
1001
+ warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
800
1002
  "rbx" == platform
801
1003
  end
802
1004
 
@@ -818,12 +1020,13 @@ module Minitest
818
1020
  MT_RE = %r%lib/minitest% #:nodoc:
819
1021
 
820
1022
  ##
821
- # Filter +bt+ to something useful. Returns the whole thing if $DEBUG.
1023
+ # Filter +bt+ to something useful. Returns the whole thing if
1024
+ # $DEBUG (ruby) or $MT_DEBUG (env).
822
1025
 
823
1026
  def filter bt
824
1027
  return ["No backtrace"] unless bt
825
1028
 
826
- return bt.dup if $DEBUG
1029
+ return bt.dup if $DEBUG || ENV["MT_DEBUG"]
827
1030
 
828
1031
  new_bt = bt.take_while { |line| line !~ MT_RE }
829
1032
  new_bt = bt.select { |line| line !~ MT_RE } if new_bt.empty?
@@ -837,7 +1040,7 @@ module Minitest
837
1040
 
838
1041
  def self.run_one_method klass, method_name # :nodoc:
839
1042
  result = klass.new(method_name).run
840
- raise "#{klass}#run _must_ return self" unless klass === result
1043
+ raise "#{klass}#run _must_ return a Result" unless Result === result
841
1044
  result
842
1045
  end
843
1046
 
@@ -853,6 +1056,13 @@ module Minitest
853
1056
  end
854
1057
  end
855
1058
 
1059
+ class Runnable # re-open
1060
+ def self.inherited klass # :nodoc:
1061
+ self.runnables << klass
1062
+ super
1063
+ end
1064
+ end
1065
+
856
1066
  # :startdoc:
857
1067
  end
858
1068