minitest 5.16.2 → 6.0.5

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/History.rdoc +373 -1
  4. data/Manifest.txt +16 -4
  5. data/README.rdoc +48 -118
  6. data/Rakefile +17 -2
  7. data/bin/minitest +5 -0
  8. data/design_rationale.rb +21 -19
  9. data/lib/hoe/minitest.rb +4 -2
  10. data/lib/minitest/assertions.rb +142 -124
  11. data/lib/minitest/autorun.rb +3 -11
  12. data/lib/minitest/benchmark.rb +9 -12
  13. data/lib/minitest/bisect.rb +304 -0
  14. data/lib/minitest/complete.rb +56 -0
  15. data/lib/minitest/compress.rb +94 -0
  16. data/lib/minitest/error_on_warning.rb +11 -0
  17. data/lib/minitest/expectations.rb +18 -0
  18. data/lib/minitest/find_minimal_combination.rb +127 -0
  19. data/lib/minitest/hell.rb +1 -1
  20. data/lib/minitest/manual_plugins.rb +4 -0
  21. data/lib/minitest/parallel.rb +10 -8
  22. data/lib/minitest/path_expander.rb +432 -0
  23. data/lib/minitest/pride.rb +2 -2
  24. data/lib/minitest/pride_plugin.rb +17 -24
  25. data/lib/minitest/server.rb +49 -0
  26. data/lib/minitest/server_plugin.rb +88 -0
  27. data/lib/minitest/spec.rb +27 -46
  28. data/lib/minitest/sprint.rb +105 -0
  29. data/lib/minitest/sprint_plugin.rb +39 -0
  30. data/lib/minitest/test.rb +32 -52
  31. data/lib/minitest/test_task.rb +68 -42
  32. data/lib/minitest.rb +361 -215
  33. data/test/minitest/metametameta.rb +33 -19
  34. data/test/minitest/test_bisect.rb +249 -0
  35. data/test/minitest/test_find_minimal_combination.rb +138 -0
  36. data/test/minitest/test_minitest_assertions.rb +311 -173
  37. data/test/minitest/test_minitest_benchmark.rb +15 -1
  38. data/test/minitest/test_minitest_reporter.rb +148 -23
  39. data/test/minitest/test_minitest_spec.rb +157 -132
  40. data/test/minitest/test_minitest_test.rb +270 -204
  41. data/test/minitest/test_minitest_test_task.rb +18 -7
  42. data/test/minitest/test_path_expander.rb +229 -0
  43. data/test/minitest/test_server.rb +146 -0
  44. data.tar.gz.sig +2 -2
  45. metadata +97 -37
  46. metadata.gz.sig +0 -0
  47. data/.autotest +0 -34
  48. data/lib/minitest/mock.rb +0 -323
  49. data/lib/minitest/unit.rb +0 -42
  50. data/test/minitest/test_minitest_mock.rb +0 -1139
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.16.2" # :nodoc:
13
+ VERSION = "6.0.4" # :nodoc:
13
14
 
14
15
  @@installed_at_exit ||= false
15
16
  @@after_run = []
@@ -32,10 +33,9 @@ module Minitest
32
33
 
33
34
  cattr_accessor :parallel_executor
34
35
 
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
36
+ n_threads = (ENV["MT_CPU"] || Etc.nprocessors).to_i
37
37
 
38
- self.parallel_executor = Parallel::Executor.new n_threads
38
+ self.parallel_executor = Parallel::Executor.new n_threads if n_threads > 1
39
39
 
40
40
  ##
41
41
  # Filter object for backtraces.
@@ -60,13 +60,14 @@ module Minitest
60
60
  cattr_accessor :info_signal
61
61
  self.info_signal = "INFO"
62
62
 
63
+ cattr_accessor :allow_fork
64
+ self.allow_fork = false
65
+
63
66
  ##
64
67
  # Registers Minitest to run at process exit
65
68
 
66
69
  def self.autorun
67
- if Object.const_defined?(:Warning) && Warning.respond_to?(:[]=)
68
- Warning[:deprecated] = true
69
- end
70
+ Warning[:deprecated] = true
70
71
 
71
72
  at_exit {
72
73
  next if $! and not ($!.kind_of? SystemExit and $!.success?)
@@ -75,7 +76,7 @@ module Minitest
75
76
 
76
77
  pid = Process.pid
77
78
  at_exit {
78
- next if Process.pid != pid
79
+ next if !Minitest.allow_fork && Process.pid != pid
79
80
  @@after_run.reverse_each(&:call)
80
81
  exit exit_code || false
81
82
  }
@@ -95,20 +96,30 @@ module Minitest
95
96
  @@after_run << block
96
97
  end
97
98
 
98
- def self.init_plugins options # :nodoc:
99
- self.extensions.each do |name|
100
- msg = "plugin_#{name}_init"
101
- send msg, options if self.respond_to? msg
99
+ ##
100
+ # Manually load plugins by name.
101
+
102
+ def self.load *names
103
+ names.each do |name|
104
+ require "minitest/#{name}_plugin"
105
+
106
+ self.extensions << name.to_s
102
107
  end
103
108
  end
104
109
 
110
+ ##
111
+ # Register a plugin to be used. Does NOT require / load it.
112
+
113
+ def self.register_plugin name_or_mod
114
+ self.extensions << name_or_mod
115
+ nil
116
+ end
117
+
105
118
  def self.load_plugins # :nodoc:
106
- return unless self.extensions.empty?
119
+ return unless defined? Gem
107
120
 
108
121
  seen = {}
109
122
 
110
- require "rubygems" unless defined? Gem
111
-
112
123
  Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
113
124
  name = File.basename plugin_path, "_plugin.rb"
114
125
 
@@ -120,118 +131,122 @@ module Minitest
120
131
  end
121
132
  end
122
133
 
123
- ##
124
- # This is the top-level run method. Everything starts from here. It
125
- # tells each Runnable sub-class to run, and each of those are
126
- # responsible for doing whatever they do.
127
- #
128
- # The overall structure of a run looks like this:
129
- #
130
- # Minitest.autorun
131
- # Minitest.run(args)
132
- # Minitest.__run(reporter, options)
133
- # Runnable.runnables.each
134
- # runnable.run(reporter, options)
135
- # self.runnable_methods.each
136
- # self.run_one_method(self, runnable_method, reporter)
137
- # Minitest.run_one_method(klass, runnable_method)
138
- # klass.new(runnable_method).run
139
-
140
- def self.run args = []
141
- self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
142
-
143
- options = process_args args
144
-
145
- Minitest.seed = options[:seed]
146
- srand Minitest.seed
147
-
148
- reporter = CompositeReporter.new
149
- reporter << SummaryReporter.new(options[:io], options)
150
- reporter << ProgressReporter.new(options[:io], options)
151
-
152
- self.reporter = reporter # this makes it available to plugins
153
- self.init_plugins options
154
- self.reporter = nil # runnables shouldn't depend on the reporter, ever
155
-
156
- self.parallel_executor.start if parallel_executor.respond_to?(:start)
157
- reporter.start
158
- begin
159
- __run reporter, options
160
- rescue Interrupt
161
- warn "Interrupted. Exiting..."
134
+ def self.init_plugins options # :nodoc:
135
+ self.extensions.each do |mod_or_meth|
136
+ case mod_or_meth
137
+ when Symbol, String then
138
+ name = mod_or_meth
139
+ msg = "plugin_#{name}_init"
140
+ next unless self.respond_to? msg
141
+ send msg, options
142
+ when Module then
143
+ recv = mod_or_meth
144
+ next unless recv.respond_to? :minitest_plugin_init
145
+ recv.minitest_plugin_init options
146
+ else
147
+ raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
148
+ end
162
149
  end
163
- self.parallel_executor.shutdown
164
- reporter.report
165
-
166
- reporter.passed?
167
- end
168
-
169
- ##
170
- # Internal run method. Responsible for telling all Runnable
171
- # sub-classes to run.
172
-
173
- def self.__run reporter, options
174
- suites = Runnable.runnables.shuffle
175
- parallel, serial = suites.partition { |s| s.test_order == :parallel }
176
-
177
- # If we run the parallel tests before the serial tests, the parallel tests
178
- # could run in parallel with the serial tests. This would be bad because
179
- # the serial tests won't lock around Reporter#record. Run the serial tests
180
- # first, so that after they complete, the parallel tests will lock when
181
- # recording results.
182
- serial.map { |suite| suite.run reporter, options } +
183
- parallel.map { |suite| suite.run reporter, options }
184
150
  end
185
151
 
186
152
  def self.process_args args = [] # :nodoc:
187
153
  options = {
188
- :io => $stdout,
154
+ :io => $stdout,
189
155
  }
190
156
  orig_args = args.dup
191
157
 
158
+ warn "--no-plugins is a no-op" if args.delete "--no-plugins" # TODO: remove me! when?
159
+
192
160
  OptionParser.new do |opts|
193
- opts.banner = "minitest options:"
161
+ opts.program_name = "minitest"
194
162
  opts.version = Minitest::VERSION
195
163
 
164
+ opts.banner = [
165
+ "Usage: minitest [paths] [options]",
166
+ "ruby path/to/test.rb [options]",
167
+ "rake test [A=options] (see Minitest::TestTask for more options)\n\n",
168
+ ].join "\n or: "
169
+
196
170
  opts.on "-h", "--help", "Display this help." do
197
171
  puts opts
198
- exit
172
+ exit! true
199
173
  end
200
174
 
201
- opts.on "--no-plugins", "Bypass minitest plugin auto-loading (or set $MT_NO_PLUGINS)."
175
+ opts.on "-V", "--version", "Display the version." do
176
+ puts "#{opts.program_name} #{Minitest::VERSION}"
177
+ exit! true
178
+ end
202
179
 
203
- desc = "Sets random seed. Also via env. Eg: SEED=n rake"
180
+ desc = "Sets random seed. Also via env, eg: SEED=42"
204
181
  opts.on "-s", "--seed SEED", Integer, desc do |m|
205
- options[:seed] = m.to_i
182
+ options[:seed] = m
206
183
  end
207
184
 
208
- opts.on "-v", "--verbose", "Verbose. Show progress processing files." do
185
+ opts.on "-v", "--verbose", "Verbose. Print each name as they run." do
209
186
  options[:verbose] = true
210
187
  end
211
188
 
189
+ opts.on "-q", "--quiet", "Quiet. Show no dots while processing files." do
190
+ options[:quiet] = true
191
+ end
192
+
212
193
  opts.on "--show-skips", "Show skipped at the end of run." do
213
194
  options[:show_skips] = true
214
195
  end
215
196
 
216
- opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
217
- options[:filter] = a
197
+ opts.on "-b", "--bisect", "Run minitest in bisect-mode to isolate flaky tests." if
198
+ File.basename($0).match?(/minitest/)
199
+
200
+ opts.on "-i", "--include PATTERN", "Include /regexp/ or string for run." do |a|
201
+ options[:include] = a
218
202
  end
219
203
 
220
204
  opts.on "-e", "--exclude PATTERN", "Exclude /regexp/ or string from run." do |a|
221
205
  options[:exclude] = a
222
206
  end
223
207
 
208
+ # part of my unofficial embedded gem "makeoptparseworkwell"
209
+ def opts.topdict(name) = (name.length > 1 ? top.long : top.short)
210
+ def opts.alias(from, to) = (dict = topdict(from) ; dict[to] = dict[from])
211
+
212
+ # these will work but won't show up in --help output:
213
+ opts.alias "include", "name"
214
+ opts.alias "i", "n"
215
+ opts.alias "e", "x"
216
+
224
217
  opts.on "-S", "--skip CODES", String, "Skip reporting of certain types of results (eg E)." do |s|
225
218
  options[:skip] = s.chars.to_a
226
219
  end
227
220
 
221
+ opts.on "-W[error]", String, "Turn Ruby warnings into errors" do |s|
222
+ options[:Werror] = true
223
+ case s
224
+ when "error", "all", nil then
225
+ require_relative "minitest/error_on_warning"
226
+ $VERBOSE = true
227
+ ::Warning[:deprecated] = true
228
+ else
229
+ ::Warning[s.to_sym] = true # check validity of category
230
+ end
231
+ end
232
+
228
233
  unless extensions.empty?
229
234
  opts.separator ""
230
- opts.separator "Known extensions: #{extensions.join(", ")}"
231
-
232
- extensions.each do |meth|
233
- msg = "plugin_#{meth}_options"
234
- send msg, opts, options if self.respond_to?(msg)
235
+ opts.separator "Known extensions: #{extensions.join ", "}"
236
+
237
+ extensions.each do |mod_or_meth|
238
+ case mod_or_meth
239
+ when Symbol, String then
240
+ meth = mod_or_meth
241
+ msg = "plugin_#{meth}_options"
242
+ send msg, opts, options if respond_to? msg
243
+ when Module
244
+ recv = mod_or_meth
245
+ next unless recv.respond_to? :minitest_plugin_options
246
+ recv.minitest_plugin_options opts, options
247
+ else
248
+ raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
249
+ end
235
250
  end
236
251
  end
237
252
 
@@ -255,12 +270,98 @@ module Minitest
255
270
  end
256
271
 
257
272
  options[:args] = orig_args.map { |s|
258
- s =~ /[\s|&<>$()]/ ? s.inspect : s
273
+ s.match?(/[\s|&<>$()]/) ? s.inspect : s
259
274
  }.join " "
260
275
 
261
276
  options
262
277
  end
263
278
 
279
+ ##
280
+ # This is the top-level run method. Everything starts from here. It
281
+ # tells each Runnable sub-class to run, and each of those are
282
+ # responsible for doing whatever they do.
283
+ #
284
+ # The overall structure of a run looks like this:
285
+ #
286
+ # [Minitest.load_plugins] optional, called by user, or require what you want
287
+ # Minitest.autorun
288
+ # Minitest.run(args)
289
+ # Minitest.process_args
290
+ # Minitest.init_plugins
291
+ # Minitest.run_all_suites(reporter, options)
292
+ # Runnable.runnables.each |runnable_klass|
293
+ # runnable_klass.run_suite(reporter, options)
294
+ # filtered_methods = runnable_klass.filter_runnable_methods options
295
+ # filtered_methods.each |runnable_method|
296
+ # runnable_klass.run(self, runnable_method, reporter)
297
+ # runnable_klass.new(runnable_method).run
298
+
299
+ def self.run args = []
300
+ options = process_args args
301
+
302
+ Minitest.seed = options[:seed]
303
+ srand Minitest.seed
304
+
305
+ reporter = CompositeReporter.new
306
+ reporter << SummaryReporter.new(options[:io], options)
307
+ reporter << ProgressReporter.new(options[:io], options) unless options[:quiet]
308
+
309
+ self.reporter = reporter # this makes it available to plugins
310
+ self.init_plugins options
311
+ self.reporter = nil # runnables shouldn't depend on the reporter, ever
312
+
313
+ self.parallel_executor.start if parallel_executor.respond_to? :start
314
+ reporter.start
315
+ begin
316
+ run_all_suites reporter, options
317
+ finished = true
318
+ rescue Interrupt
319
+ warn "Interrupted. Exiting..."
320
+ end
321
+ self.parallel_executor.shutdown if parallel_executor.respond_to? :shutdown
322
+
323
+ # might have been removed/replaced during init_plugins:
324
+ summary = reporter.reporters.grep(SummaryReporter).first
325
+
326
+ reporter.report
327
+
328
+ return empty_run! options if finished && summary && summary.count == 0
329
+ finished and reporter.passed?
330
+ end
331
+
332
+ def self.empty_run! options # :nodoc:
333
+ filter = options[:include]
334
+ return true unless filter # no filter, but nothing ran == success
335
+
336
+ warn "Nothing ran for filter: %s" % [filter]
337
+
338
+ require "did_you_mean" # soft dependency, punt if it doesn't load
339
+
340
+ ms = Runnable.runnables.flat_map(&:runnable_methods)
341
+ cs = DidYouMean::SpellChecker.new(dictionary: ms).correct filter
342
+
343
+ warn DidYouMean::Formatter.message_for cs unless cs.empty?
344
+ rescue LoadError
345
+ # do nothing
346
+ end
347
+
348
+ ##
349
+ # Internal run method. Responsible for telling all Runnable
350
+ # sub-classes to run.
351
+
352
+ def self.run_all_suites reporter, options
353
+ suites = Runnable.runnables.shuffle
354
+ parallel, serial = suites.partition { |s| s.run_order == :parallel }
355
+
356
+ # If we run the parallel tests before the serial tests, the parallel tests
357
+ # could run in parallel with the serial tests. This would be bad because
358
+ # the serial tests won't lock around Reporter#record. Run the serial tests
359
+ # first, so that after they complete, the parallel tests will lock when
360
+ # recording results.
361
+ serial.map { |suite| suite.run_suite reporter, options } +
362
+ parallel.map { |suite| suite.run_suite reporter, options }
363
+ end
364
+
264
365
  def self.filter_backtrace bt # :nodoc:
265
366
  result = backtrace_filter.filter bt
266
367
  result = bt.dup if result.empty?
@@ -325,31 +426,51 @@ module Minitest
325
426
 
326
427
  reset
327
428
 
429
+ ##
430
+ # Returns an array of filtered +runnable_methods+. Uses
431
+ # options[:include] (--include arguments) and options[:exclude]
432
+ # (--exclude arguments) values to filter.
433
+
434
+ def self.filter_runnable_methods options={}
435
+ pos = options[:include]
436
+ neg = options[:exclude]
437
+
438
+ pos = Regexp.new $1 if pos.kind_of?(String) && pos =~ %r%/(.*)/%
439
+ neg = Regexp.new $1 if neg.kind_of?(String) && neg =~ %r%/(.*)/%
440
+
441
+ # at most 1-2% slower than a 1-pass version, stop optimizing this
442
+ self.runnable_methods
443
+ .select { |m| !pos || pos === m || pos === "#{self}##{m}" }
444
+ .reject { |m| neg && (neg === m || neg === "#{self}##{m}") }
445
+ end
446
+
328
447
  ##
329
448
  # Responsible for running all runnable methods in a given class,
330
449
  # each in its own instance. Each instance is passed to the
331
450
  # reporter to record.
332
451
 
333
- def self.run reporter, options = {}
334
- filter = options[:filter] || "/./"
335
- filter = Regexp.new $1 if filter.is_a?(String) && filter =~ %r%/(.*)/%
452
+ def Runnable.run_suite reporter, options = {}
453
+ filtered_methods = filter_runnable_methods options
336
454
 
337
- filtered_methods = self.runnable_methods.find_all { |m|
338
- filter === m || filter === "#{self}##{m}"
339
- }
455
+ return if filtered_methods.empty?
340
456
 
341
- exclude = options[:exclude]
342
- exclude = Regexp.new $1 if exclude =~ %r%/(.*)/%
457
+ t0 = name = nil
343
458
 
344
- filtered_methods.delete_if { |m|
345
- exclude === m || exclude === "#{self}##{m}"
346
- }
459
+ @_info_handler = lambda do
460
+ unless reporter.passed? then
461
+ warn "Current results:"
462
+ warn reporter.reporters.grep(SummaryReporter).first
463
+ end
347
464
 
348
- return if filtered_methods.empty?
465
+ warn "Current: %s#%s %.2fs" % [self, name, Minitest.clock_time - t0]
466
+ end
349
467
 
350
- with_info_handler reporter do
468
+ with_info_handler do
351
469
  filtered_methods.each do |method_name|
352
- run_one_method self, method_name, reporter
470
+ name = method_name
471
+ t0 = Minitest.clock_time
472
+
473
+ run self, method_name, reporter
353
474
  end
354
475
  end
355
476
  end
@@ -360,22 +481,21 @@ module Minitest
360
481
  # that subclasses can specialize the running of an individual
361
482
  # test. See Minitest::ParallelTest::ClassMethods for an example.
362
483
 
363
- def self.run_one_method klass, method_name, reporter
484
+ def Runnable.run klass, method_name, reporter
364
485
  reporter.prerecord klass, method_name
365
- reporter.record Minitest.run_one_method(klass, method_name)
486
+ reporter.record klass.new(method_name).run
366
487
  end
367
488
 
368
- def self.with_info_handler reporter, &block # :nodoc:
369
- handler = lambda do
370
- unless reporter.passed? then
371
- warn "Current results:"
372
- warn ""
373
- warn reporter.reporters.first
374
- warn ""
375
- end
376
- end
489
+ ##
490
+ # Defines the order to run tests (:random by default). Override
491
+ # this or use a convenience method to change it for your tests.
492
+
493
+ def self.run_order
494
+ :random
495
+ end
377
496
 
378
- on_signal ::Minitest.info_signal, handler, &block
497
+ def self.with_info_handler _reporter=nil, &block # :nodoc:
498
+ on_signal ::Minitest.info_signal, @_info_handler, &block
379
499
  end
380
500
 
381
501
  SIGNALS = Signal.list # :nodoc:
@@ -408,22 +528,6 @@ module Minitest
408
528
  @@runnables
409
529
  end
410
530
 
411
- @@marshal_dump_warned = false
412
-
413
- def marshal_dump # :nodoc:
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]
421
- end
422
-
423
- def marshal_load ary # :nodoc:
424
- self.name, self.failures, self.assertions, self.time = ary
425
- end
426
-
427
531
  def failure # :nodoc:
428
532
  self.failures.first
429
533
  end
@@ -432,6 +536,31 @@ module Minitest
432
536
  self.name = name
433
537
  self.failures = []
434
538
  self.assertions = 0
539
+ # lazy initializer for metadata
540
+ end
541
+
542
+ ##
543
+ # Metadata you attach to the test results that get sent to the reporter.
544
+ #
545
+ # Lazily initializes to a hash, to keep memory down.
546
+ #
547
+ # NOTE: this data *must* be plain (read: marshal-able) data!
548
+ # Hashes! Arrays! Strings!
549
+
550
+ def metadata
551
+ @metadata ||= {}
552
+ end
553
+
554
+ ##
555
+ # Sets metadata, mainly used for +Result.from+.
556
+
557
+ attr_writer :metadata
558
+
559
+ ##
560
+ # Returns true if metadata exists.
561
+
562
+ def metadata?
563
+ defined? @metadata
435
564
  end
436
565
 
437
566
  ##
@@ -466,7 +595,7 @@ module Minitest
466
595
  def skipped?
467
596
  raise NotImplementedError, "subclass responsibility"
468
597
  end
469
- end
598
+ end # Runnable
470
599
 
471
600
  ##
472
601
  # Shared code for anything that can get passed to a Reporter. See
@@ -483,12 +612,14 @@ module Minitest
483
612
  not self.failure
484
613
  end
485
614
 
615
+ BASE_DIR = "#{Dir.pwd}/" # :nodoc:
616
+
486
617
  ##
487
618
  # The location identifier of this test. Depends on a method
488
619
  # existing called class_name.
489
620
 
490
621
  def location
491
- loc = " [#{self.failure.location}]" unless passed? or error?
622
+ loc = " [#{self.failure.location.delete_prefix BASE_DIR}]" unless passed? or error?
492
623
  "#{self.class_name}##{self.name}#{loc}"
493
624
  end
494
625
 
@@ -514,9 +645,9 @@ module Minitest
514
645
  # Did this run error?
515
646
 
516
647
  def error?
517
- self.failures.any? { |f| UnexpectedError === f }
648
+ self.failures.any? UnexpectedError
518
649
  end
519
- end
650
+ end # Reportable
520
651
 
521
652
  ##
522
653
  # This represents a test result in a clean way that can be
@@ -528,9 +659,6 @@ module Minitest
528
659
  class Result < Runnable
529
660
  include Minitest::Reportable
530
661
 
531
- undef_method :marshal_dump
532
- undef_method :marshal_load
533
-
534
662
  ##
535
663
  # The class name of the test result.
536
664
 
@@ -552,6 +680,7 @@ module Minitest
552
680
  r.assertions = o.assertions
553
681
  r.failures = o.failures.dup
554
682
  r.time = o.time
683
+ r.metadata = o.metadata if o.metadata?
555
684
 
556
685
  r.source_location = o.method(o.name).source_location rescue ["unknown", -1]
557
686
 
@@ -569,14 +698,17 @@ module Minitest
569
698
  "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
570
699
  }.join "\n"
571
700
  end
572
- end
701
+ end # Result
573
702
 
574
703
  ##
575
704
  # Defines the API for Reporters. Subclass this and override whatever
576
705
  # you want. Go nuts.
577
706
 
578
707
  class AbstractReporter
579
- include Mutex_m
708
+
709
+ def initialize # :nodoc:
710
+ @mutex = Mutex.new
711
+ end
580
712
 
581
713
  ##
582
714
  # Starts reporting on the run.
@@ -612,7 +744,11 @@ module Minitest
612
744
  def passed?
613
745
  true
614
746
  end
615
- end
747
+
748
+ def synchronize &block # :nodoc:
749
+ @mutex.synchronize(&block)
750
+ end
751
+ end # AbstractReportera
616
752
 
617
753
  class Reporter < AbstractReporter # :nodoc:
618
754
  ##
@@ -641,11 +777,11 @@ module Minitest
641
777
  # own.
642
778
 
643
779
  class ProgressReporter < Reporter
644
- def prerecord klass, name #:nodoc:
645
- if options[:verbose] then
646
- io.print "%s#%s = " % [klass.name, name]
647
- io.flush
648
- end
780
+ def prerecord klass, name # :nodoc:
781
+ return unless options[:verbose]
782
+
783
+ io.print "%s#%s = " % [klass.name, name]
784
+ io.flush
649
785
  end
650
786
 
651
787
  def record result # :nodoc:
@@ -715,6 +851,11 @@ module Minitest
715
851
 
716
852
  attr_accessor :errors
717
853
 
854
+ ##
855
+ # Total number of tests that warned.
856
+
857
+ attr_accessor :warnings
858
+
718
859
  ##
719
860
  # Total number of tests that where skipped.
720
861
 
@@ -730,6 +871,7 @@ module Minitest
730
871
  self.total_time = nil
731
872
  self.failures = nil
732
873
  self.errors = nil
874
+ self.warnings = nil
733
875
  self.skips = nil
734
876
  end
735
877
 
@@ -758,9 +900,10 @@ module Minitest
758
900
  self.total_time = Minitest.clock_time - start_time
759
901
  self.failures = aggregate[Assertion].size
760
902
  self.errors = aggregate[UnexpectedError].size
903
+ self.warnings = aggregate[UnexpectedWarning].size
761
904
  self.skips = aggregate[Skip].size
762
905
  end
763
- end
906
+ end # StatisticsReporter
764
907
 
765
908
  ##
766
909
  # A reporter that prints the header, summary, and failure details at
@@ -772,10 +915,8 @@ module Minitest
772
915
  # own.
773
916
 
774
917
  class SummaryReporter < StatisticsReporter
775
- # :stopdoc:
776
- attr_accessor :sync
777
- attr_accessor :old_sync
778
- # :startdoc:
918
+ attr_accessor :sync # :nodoc:
919
+ attr_accessor :old_sync # :nodoc:
779
920
 
780
921
  def start # :nodoc:
781
922
  super
@@ -785,7 +926,7 @@ module Minitest
785
926
  io.puts "# Running:"
786
927
  io.puts
787
928
 
788
- self.sync = io.respond_to? :"sync=" # stupid emacs
929
+ self.sync = io.respond_to? :"sync="
789
930
  self.old_sync, io.sync = io.sync, true if self.sync
790
931
  end
791
932
 
@@ -823,28 +964,24 @@ module Minitest
823
964
  end
824
965
 
825
966
  def to_s # :nodoc:
826
- aggregated_results(StringIO.new(binary_string)).string
967
+ aggregated_results(StringIO.new("".b)).string
827
968
  end
828
969
 
829
970
  def summary # :nodoc:
830
- extra = ""
971
+ extra = []
972
+
973
+ extra << ", %d warnings" % [warnings] if options[:Werror]
831
974
 
832
- extra = "\n\nYou have skipped tests. Run with --verbose for details." if
975
+ extra << "\n\nYou have skipped tests. Run with --verbose for details." if
833
976
  results.any?(&:skipped?) unless
834
- options[:verbose] or options[:show_skips] or ENV["MT_NO_SKIP_MSG"]
977
+ options[:verbose] or
978
+ options[:show_skips] or
979
+ ENV["MT_NO_SKIP_MSG"]
835
980
 
836
981
  "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
837
- [count, assertions, failures, errors, skips, extra]
982
+ [count, assertions, failures, errors, skips, extra.join]
838
983
  end
839
-
840
- private
841
-
842
- if '<3'.respond_to? :b
843
- def binary_string; ''.b; end
844
- else
845
- def binary_string; ''.force_encoding(Encoding::ASCII_8BIT); end
846
- end
847
- end
984
+ end # SummaryReporter
848
985
 
849
986
  ##
850
987
  # Dispatch to multiple reporters as one.
@@ -881,8 +1018,7 @@ module Minitest
881
1018
 
882
1019
  def prerecord klass, name # :nodoc:
883
1020
  self.reporters.each do |reporter|
884
- # TODO: remove conditional for minitest 6
885
- reporter.prerecord klass, name if reporter.respond_to? :prerecord
1021
+ reporter.prerecord klass, name
886
1022
  end
887
1023
  end
888
1024
 
@@ -895,12 +1031,14 @@ module Minitest
895
1031
  def report # :nodoc:
896
1032
  self.reporters.each(&:report)
897
1033
  end
898
- end
1034
+ end # CompositeReporter
899
1035
 
900
1036
  ##
901
1037
  # Represents run failures.
902
1038
 
903
1039
  class Assertion < Exception
1040
+ RE = /in [`'](?:[^']+[#.])?(?:assert|refute|flunk|pass|fail|raise|must|wont)/ # :nodoc:
1041
+
904
1042
  def error # :nodoc:
905
1043
  self
906
1044
  end
@@ -909,12 +1047,11 @@ module Minitest
909
1047
  # Where was this run before an assertion was raised?
910
1048
 
911
1049
  def location
912
- last_before_assertion = ""
913
- self.backtrace.reverse_each do |s|
914
- break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
915
- last_before_assertion = s
916
- end
917
- last_before_assertion.sub(/:in .*$/, "")
1050
+ bt = Minitest.filter_backtrace self.backtrace
1051
+ idx = bt.rindex { |s| s.match? RE } || -1 # fall back to first item
1052
+ loc = bt[idx+1] || bt.last || "unknown:-1"
1053
+
1054
+ loc.sub(/:in .*$/, "")
918
1055
  end
919
1056
 
920
1057
  def result_code # :nodoc:
@@ -939,11 +1076,21 @@ module Minitest
939
1076
  # Assertion wrapping an unexpected error that was raised during a run.
940
1077
 
941
1078
  class UnexpectedError < Assertion
1079
+ include Minitest::Compress
1080
+
942
1081
  # TODO: figure out how to use `cause` instead
943
1082
  attr_accessor :error # :nodoc:
944
1083
 
945
1084
  def initialize error # :nodoc:
946
1085
  super "Unexpected exception"
1086
+
1087
+ if SystemStackError === error then
1088
+ bt = error.backtrace
1089
+ new_bt = compress bt
1090
+ error = error.exception "#{bt.size} -> #{new_bt.size}"
1091
+ error.set_backtrace new_bt
1092
+ end
1093
+
947
1094
  self.error = error
948
1095
  end
949
1096
 
@@ -951,8 +1098,11 @@ module Minitest
951
1098
  self.error.backtrace
952
1099
  end
953
1100
 
1101
+ BASE_RE = %r%#{Regexp.escape Dir.pwd}/% # :nodoc:
1102
+
954
1103
  def message # :nodoc:
955
- bt = Minitest.filter_backtrace(self.backtrace).join "\n "
1104
+ bt = Minitest.filter_backtrace(self.backtrace).join("\n ")
1105
+ .gsub(BASE_RE, "")
956
1106
  "#{self.error.class}: #{self.error.message}\n #{bt}"
957
1107
  end
958
1108
 
@@ -961,6 +1111,15 @@ module Minitest
961
1111
  end
962
1112
  end
963
1113
 
1114
+ ##
1115
+ # Assertion raised on warning when running in -Werror mode.
1116
+
1117
+ class UnexpectedWarning < Assertion
1118
+ def result_label # :nodoc:
1119
+ "Warning"
1120
+ end
1121
+ end
1122
+
964
1123
  ##
965
1124
  # Provides a simple set of guards that you can use in your tests
966
1125
  # to skip execution if it is not applicable. These methods are
@@ -985,45 +1144,25 @@ module Minitest
985
1144
  "java" == platform
986
1145
  end
987
1146
 
988
- ##
989
- # Is this running on maglev?
990
-
991
- def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
992
- where = Minitest.filter_backtrace(caller).first
993
- where = where.split(/:in /, 2).first # clean up noise
994
- warn "DEPRECATED: `maglev?` called from #{where}. This will fail in Minitest 6."
995
- "maglev" == platform
996
- end
997
-
998
1147
  ##
999
1148
  # Is this running on mri?
1000
1149
 
1001
1150
  def mri? platform = RUBY_DESCRIPTION
1002
- /^ruby/ =~ platform
1151
+ platform.start_with? "ruby"
1003
1152
  end
1004
1153
 
1005
1154
  ##
1006
1155
  # Is this running on macOS?
1007
1156
 
1008
1157
  def osx? platform = RUBY_PLATFORM
1009
- /darwin/ =~ platform
1010
- end
1011
-
1012
- ##
1013
- # Is this running on rubinius?
1014
-
1015
- def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
1016
- where = Minitest.filter_backtrace(caller).first
1017
- where = where.split(/:in /, 2).first # clean up noise
1018
- warn "DEPRECATED: `rubinius?` called from #{where}. This will fail in Minitest 6."
1019
- "rbx" == platform
1158
+ platform.include? "darwin"
1020
1159
  end
1021
1160
 
1022
1161
  ##
1023
1162
  # Is this running on windows?
1024
1163
 
1025
1164
  def windows? platform = RUBY_PLATFORM
1026
- /mswin|mingw/ =~ platform
1165
+ /mswin|mingw/.match? platform
1027
1166
  end
1028
1167
  end
1029
1168
 
@@ -1034,7 +1173,16 @@ module Minitest
1034
1173
 
1035
1174
  class BacktraceFilter
1036
1175
 
1037
- MT_RE = %r%lib/minitest% #:nodoc:
1176
+ MT_RE = %r%lib/minitest|internal:warning% # :nodoc:
1177
+
1178
+ ##
1179
+ # The regular expression to use to filter backtraces. Defaults to +MT_RE+.
1180
+
1181
+ attr_accessor :regexp
1182
+
1183
+ def initialize regexp = MT_RE # :nodoc:
1184
+ self.regexp = regexp
1185
+ end
1038
1186
 
1039
1187
  ##
1040
1188
  # Filter +bt+ to something useful. Returns the whole thing if
@@ -1045,9 +1193,9 @@ module Minitest
1045
1193
 
1046
1194
  return bt.dup if $DEBUG || ENV["MT_DEBUG"]
1047
1195
 
1048
- new_bt = bt.take_while { |line| line !~ MT_RE }
1049
- new_bt = bt.select { |line| line !~ MT_RE } if new_bt.empty?
1050
- new_bt = bt.dup if new_bt.empty?
1196
+ new_bt = bt.take_while { |line| !regexp.match? line.to_s }
1197
+ new_bt = bt.select { |line| !regexp.match? line.to_s } if new_bt.empty?
1198
+ new_bt = bt.dup if new_bt.empty?
1051
1199
 
1052
1200
  new_bt
1053
1201
  end
@@ -1055,12 +1203,6 @@ module Minitest
1055
1203
 
1056
1204
  self.backtrace_filter = BacktraceFilter.new
1057
1205
 
1058
- def self.run_one_method klass, method_name # :nodoc:
1059
- result = klass.new(method_name).run
1060
- raise "#{klass}#run _must_ return a Result" unless Result === result
1061
- result
1062
- end
1063
-
1064
1206
  # :stopdoc:
1065
1207
 
1066
1208
  if defined? Process::CLOCK_MONOTONIC # :nodoc:
@@ -1083,4 +1225,8 @@ module Minitest
1083
1225
  # :startdoc:
1084
1226
  end
1085
1227
 
1086
- require "minitest/test"
1228
+ require_relative "minitest/test"
1229
+ if ENV["MINITEST_SERVER"] then
1230
+ require_relative "minitest/server_plugin"
1231
+ Minitest.register_plugin :server
1232
+ end