minitest 5.12.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ # -*- ruby -*-
2
+
3
+ require "rubygems"
4
+ require "hoe"
5
+
6
+ Hoe.plugin :seattlerb
7
+ Hoe.plugin :rdoc
8
+
9
+ Hoe.spec "minitest" do
10
+ developer "Ryan Davis", "ryand-ruby@zenspider.com"
11
+
12
+ license "MIT"
13
+
14
+ require_ruby_version "~> 2.2"
15
+ end
16
+
17
+ desc "Find missing expectations"
18
+ task :specs do
19
+ $:.unshift "lib"
20
+ require "minitest/test"
21
+ require "minitest/spec"
22
+
23
+ pos_prefix, neg_prefix = "must", "wont"
24
+ skip_re = /^(must|wont)$|wont_(throw)|must_(block|not?_|nothing|raise$)/x
25
+ dont_flip_re = /(must|wont)_(include|respond_to)/
26
+
27
+ map = {
28
+ /(must_throw)s/ => '\1',
29
+ /(?!not)_same/ => "_be_same_as",
30
+ /_in_/ => "_be_within_",
31
+ /_operator/ => "_be",
32
+ /_includes/ => "_include",
33
+ /(must|wont)_(.*_of|nil|silent|empty)/ => '\1_be_\2',
34
+ /must_raises/ => "must_raise",
35
+ }
36
+
37
+ expectations = Minitest::Expectations.public_instance_methods.map(&:to_s)
38
+ assertions = Minitest::Assertions.public_instance_methods.map(&:to_s)
39
+
40
+ assertions.sort.each do |assertion|
41
+ expectation = case assertion
42
+ when /^assert/ then
43
+ assertion.sub(/^assert/, pos_prefix.to_s)
44
+ when /^refute/ then
45
+ assertion.sub(/^refute/, neg_prefix.to_s)
46
+ end
47
+
48
+ next unless expectation
49
+ next if expectation =~ skip_re
50
+
51
+ regexp, replacement = map.find { |re, _| expectation =~ re }
52
+ expectation.sub! regexp, replacement if replacement
53
+
54
+ next if expectations.include? expectation
55
+
56
+ args = [assertion, expectation].map(&:to_sym).map(&:inspect)
57
+ args << :reverse if expectation =~ dont_flip_re
58
+
59
+ puts
60
+ puts "##"
61
+ puts "# :method: #{expectation}"
62
+ puts "# See Minitest::Assertions##{assertion}"
63
+ puts
64
+ puts "infect_an_assertion #{args.join ", "}"
65
+ end
66
+ end
67
+
68
+ task :bugs do
69
+ sh "for f in bug*.rb ; do echo $f; echo; #{Gem.ruby} -Ilib $f && rm $f ; done"
70
+ end
71
+
72
+ # vim: syntax=Ruby
@@ -0,0 +1,52 @@
1
+ # Specs: # Equivalent Unit Tests:
2
+ ###############################################################################
3
+ describe Thingy do # class TestThingy < Minitest::Test
4
+ before do # def setup
5
+ do_some_setup # super
6
+ end # do_some_setup
7
+ # end
8
+ it "should do the first thing" do #
9
+ 1.must_equal 1 # def test_first_thing
10
+ end # assert_equal 1, 1
11
+ # end
12
+ describe SubThingy do # end
13
+ before do #
14
+ do_more_setup # class TestSubThingy < TestThingy
15
+ end # def setup
16
+ # super
17
+ it "should do the second thing" do # do_more_setup
18
+ 2.must_equal 2 # end
19
+ end #
20
+ end # def test_second_thing
21
+ end # assert_equal 2, 2
22
+ # end
23
+ # end
24
+ ###############################################################################
25
+ # runs 2 specs # runs 3 tests
26
+ ###############################################################################
27
+ # The specs generate:
28
+
29
+ class ThingySpec < Minitest::Spec
30
+ def setup
31
+ super
32
+ do_some_setup
33
+ end
34
+
35
+ def test_should_do_the_first_thing
36
+ assert_equal 1, 1
37
+ end
38
+ end
39
+
40
+ class SubThingySpec < ThingySpec
41
+ def setup
42
+ super
43
+ do_more_setup
44
+ end
45
+
46
+ # because only setup/teardown is inherited, not specs
47
+ remove_method :test_should_do_the_first_thing
48
+
49
+ def test_should_do_the_second_thing
50
+ assert_equal 2, 2
51
+ end
52
+ end
@@ -0,0 +1,32 @@
1
+ # :stopdoc:
2
+
3
+ class Hoe
4
+ end
5
+
6
+ module Hoe::Minitest
7
+ def minitest?
8
+ self.name == "minitest"
9
+ end
10
+
11
+ def initialize_minitest
12
+ unless minitest? then
13
+ dir = "../../minitest/dev/lib"
14
+ Hoe.add_include_dirs dir if File.directory? dir
15
+ end
16
+
17
+ gem "minitest"
18
+ require "minitest"
19
+ version = Minitest::VERSION.split(/\./).first(2).join(".")
20
+
21
+ dependency "minitest", "~> #{version}", :development unless
22
+ minitest? or ENV["MT_NO_ISOLATE"]
23
+ end
24
+
25
+ def define_minitest_tasks
26
+ self.testlib = :minitest
27
+
28
+ # make sure we use the gemmed minitest on 1.9
29
+ self.test_prelude = 'gem "minitest"' unless
30
+ minitest? or ENV["MT_NO_ISOLATE"]
31
+ end
32
+ end
@@ -0,0 +1,1041 @@
1
+ require "optparse"
2
+ require "thread"
3
+ require "mutex_m"
4
+ require "minitest/parallel"
5
+ require "stringio"
6
+
7
+ ##
8
+ # :include: README.rdoc
9
+
10
+ module Minitest
11
+ VERSION = "5.12.2" # :nodoc:
12
+ ENCS = "".respond_to? :encoding # :nodoc:
13
+
14
+ @@installed_at_exit ||= false
15
+ @@after_run = []
16
+ @extensions = []
17
+
18
+ mc = (class << self; self; end)
19
+
20
+ ##
21
+ # Parallel test executor
22
+
23
+ mc.send :attr_accessor, :parallel_executor
24
+
25
+ warn "DEPRECATED: use MT_CPU instead of N for parallel test runs" if ENV["N"]
26
+ n_threads = (ENV["MT_CPU"] || ENV["N"] || 2).to_i
27
+ self.parallel_executor = Parallel::Executor.new n_threads
28
+
29
+ ##
30
+ # Filter object for backtraces.
31
+
32
+ mc.send :attr_accessor, :backtrace_filter
33
+
34
+ ##
35
+ # Reporter object to be used for all runs.
36
+ #
37
+ # NOTE: This accessor is only available during setup, not during runs.
38
+
39
+ mc.send :attr_accessor, :reporter
40
+
41
+ ##
42
+ # Names of known extension plugins.
43
+
44
+ mc.send :attr_accessor, :extensions
45
+
46
+ ##
47
+ # The signal to use for dumping information to STDERR. Defaults to "INFO".
48
+
49
+ mc.send :attr_accessor, :info_signal
50
+ self.info_signal = "INFO"
51
+
52
+ ##
53
+ # Registers Minitest to run at process exit
54
+
55
+ def self.autorun
56
+ at_exit {
57
+ next if $! and not ($!.kind_of? SystemExit and $!.success?)
58
+
59
+ exit_code = nil
60
+
61
+ at_exit {
62
+ @@after_run.reverse_each(&:call)
63
+ exit exit_code || false
64
+ }
65
+
66
+ exit_code = Minitest.run ARGV
67
+ } unless @@installed_at_exit
68
+ @@installed_at_exit = true
69
+ end
70
+
71
+ ##
72
+ # A simple hook allowing you to run a block of code after everything
73
+ # is done running. Eg:
74
+ #
75
+ # Minitest.after_run { p $debugging_info }
76
+
77
+ def self.after_run &block
78
+ @@after_run << block
79
+ end
80
+
81
+ def self.init_plugins options # :nodoc:
82
+ self.extensions.each do |name|
83
+ msg = "plugin_#{name}_init"
84
+ send msg, options if self.respond_to? msg
85
+ end
86
+ end
87
+
88
+ def self.load_plugins # :nodoc:
89
+ return unless self.extensions.empty?
90
+
91
+ seen = {}
92
+
93
+ require "rubygems" unless defined? Gem
94
+
95
+ Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
96
+ name = File.basename plugin_path, "_plugin.rb"
97
+
98
+ next if seen[name]
99
+ seen[name] = true
100
+
101
+ require plugin_path
102
+ self.extensions << name
103
+ end
104
+ end
105
+
106
+ ##
107
+ # This is the top-level run method. Everything starts from here. It
108
+ # tells each Runnable sub-class to run, and each of those are
109
+ # responsible for doing whatever they do.
110
+ #
111
+ # The overall structure of a run looks like this:
112
+ #
113
+ # Minitest.autorun
114
+ # Minitest.run(args)
115
+ # Minitest.__run(reporter, options)
116
+ # Runnable.runnables.each
117
+ # runnable.run(reporter, options)
118
+ # self.runnable_methods.each
119
+ # self.run_one_method(self, runnable_method, reporter)
120
+ # Minitest.run_one_method(klass, runnable_method)
121
+ # klass.new(runnable_method).run
122
+
123
+ def self.run args = []
124
+ self.load_plugins unless args.delete("--no-plugins") || ENV["MT_NO_PLUGINS"]
125
+
126
+ options = process_args args
127
+
128
+ reporter = CompositeReporter.new
129
+ reporter << SummaryReporter.new(options[:io], options)
130
+ reporter << ProgressReporter.new(options[:io], options)
131
+
132
+ self.reporter = reporter # this makes it available to plugins
133
+ self.init_plugins options
134
+ self.reporter = nil # runnables shouldn't depend on the reporter, ever
135
+
136
+ self.parallel_executor.start if parallel_executor.respond_to?(:start)
137
+ reporter.start
138
+ begin
139
+ __run reporter, options
140
+ rescue Interrupt
141
+ warn "Interrupted. Exiting..."
142
+ end
143
+ self.parallel_executor.shutdown
144
+ reporter.report
145
+
146
+ reporter.passed?
147
+ end
148
+
149
+ ##
150
+ # Internal run method. Responsible for telling all Runnable
151
+ # sub-classes to run.
152
+
153
+ def self.__run reporter, options
154
+ suites = Runnable.runnables.reject { |s| s.runnable_methods.empty? }.shuffle
155
+ parallel, serial = suites.partition { |s| s.test_order == :parallel }
156
+
157
+ # If we run the parallel tests before the serial tests, the parallel tests
158
+ # could run in parallel with the serial tests. This would be bad because
159
+ # the serial tests won't lock around Reporter#record. Run the serial tests
160
+ # first, so that after they complete, the parallel tests will lock when
161
+ # recording results.
162
+ serial.map { |suite| suite.run reporter, options } +
163
+ parallel.map { |suite| suite.run reporter, options }
164
+ end
165
+
166
+ def self.process_args args = [] # :nodoc:
167
+ options = {
168
+ :io => $stdout,
169
+ }
170
+ orig_args = args.dup
171
+
172
+ OptionParser.new do |opts|
173
+ opts.banner = "minitest options:"
174
+ opts.version = Minitest::VERSION
175
+
176
+ opts.on "-h", "--help", "Display this help." do
177
+ puts opts
178
+ exit
179
+ end
180
+
181
+ opts.on "--no-plugins", "Bypass minitest plugin auto-loading (or set $MT_NO_PLUGINS)."
182
+
183
+ desc = "Sets random seed. Also via env. Eg: SEED=n rake"
184
+ opts.on "-s", "--seed SEED", Integer, desc do |m|
185
+ options[:seed] = m.to_i
186
+ end
187
+
188
+ opts.on "-v", "--verbose", "Verbose. Show progress processing files." do
189
+ options[:verbose] = true
190
+ end
191
+
192
+ opts.on "-n", "--name PATTERN", "Filter run on /regexp/ or string." do |a|
193
+ options[:filter] = a
194
+ end
195
+
196
+ opts.on "-e", "--exclude PATTERN", "Exclude /regexp/ or string from run." do |a|
197
+ options[:exclude] = a
198
+ end
199
+
200
+ unless extensions.empty?
201
+ opts.separator ""
202
+ opts.separator "Known extensions: #{extensions.join(", ")}"
203
+
204
+ extensions.each do |meth|
205
+ msg = "plugin_#{meth}_options"
206
+ send msg, opts, options if self.respond_to?(msg)
207
+ end
208
+ end
209
+
210
+ begin
211
+ opts.parse! args
212
+ rescue OptionParser::InvalidOption => e
213
+ puts
214
+ puts e
215
+ puts
216
+ puts opts
217
+ exit 1
218
+ end
219
+
220
+ orig_args -= args
221
+ end
222
+
223
+ unless options[:seed] then
224
+ srand
225
+ options[:seed] = (ENV["SEED"] || srand).to_i % 0xFFFF
226
+ orig_args << "--seed" << options[:seed].to_s
227
+ end
228
+
229
+ srand options[:seed]
230
+
231
+ options[:args] = orig_args.map { |s|
232
+ s =~ /[\s|&<>$()]/ ? s.inspect : s
233
+ }.join " "
234
+
235
+ options
236
+ end
237
+
238
+ def self.filter_backtrace bt # :nodoc:
239
+ backtrace_filter.filter bt
240
+ end
241
+
242
+ ##
243
+ # Represents anything "runnable", like Test, Spec, Benchmark, or
244
+ # whatever you can dream up.
245
+ #
246
+ # Subclasses of this are automatically registered and available in
247
+ # Runnable.runnables.
248
+
249
+ class Runnable
250
+ ##
251
+ # Number of assertions executed in this run.
252
+
253
+ attr_accessor :assertions
254
+
255
+ ##
256
+ # An assertion raised during the run, if any.
257
+
258
+ attr_accessor :failures
259
+
260
+ ##
261
+ # The time it took to run.
262
+
263
+ attr_accessor :time
264
+
265
+ def time_it # :nodoc:
266
+ t0 = Minitest.clock_time
267
+
268
+ yield
269
+ ensure
270
+ self.time = Minitest.clock_time - t0
271
+ end
272
+
273
+ ##
274
+ # Name of the run.
275
+
276
+ def name
277
+ @NAME
278
+ end
279
+
280
+ ##
281
+ # Set the name of the run.
282
+
283
+ def name= o
284
+ @NAME = o
285
+ end
286
+
287
+ ##
288
+ # Returns all instance methods matching the pattern +re+.
289
+
290
+ def self.methods_matching re
291
+ public_instance_methods(true).grep(re).map(&:to_s)
292
+ end
293
+
294
+ def self.reset # :nodoc:
295
+ @@runnables = []
296
+ end
297
+
298
+ reset
299
+
300
+ ##
301
+ # Responsible for running all runnable methods in a given class,
302
+ # each in its own instance. Each instance is passed to the
303
+ # reporter to record.
304
+
305
+ def self.run reporter, options = {}
306
+ filter = options[:filter] || "/./"
307
+ filter = Regexp.new $1 if filter.is_a?(String) && filter =~ %r%/(.*)/%
308
+
309
+ filtered_methods = self.runnable_methods.find_all { |m|
310
+ filter === m || filter === "#{self}##{m}"
311
+ }
312
+
313
+ exclude = options[:exclude]
314
+ exclude = Regexp.new $1 if exclude =~ %r%/(.*)/%
315
+
316
+ filtered_methods.delete_if { |m|
317
+ exclude === m || exclude === "#{self}##{m}"
318
+ }
319
+
320
+ return if filtered_methods.empty?
321
+
322
+ with_info_handler reporter do
323
+ filtered_methods.each do |method_name|
324
+ run_one_method self, method_name, reporter
325
+ end
326
+ end
327
+ end
328
+
329
+ ##
330
+ # Runs a single method and has the reporter record the result.
331
+ # This was considered internal API but is factored out of run so
332
+ # that subclasses can specialize the running of an individual
333
+ # test. See Minitest::ParallelTest::ClassMethods for an example.
334
+
335
+ def self.run_one_method klass, method_name, reporter
336
+ reporter.prerecord klass, method_name
337
+ reporter.record Minitest.run_one_method(klass, method_name)
338
+ end
339
+
340
+ def self.with_info_handler reporter, &block # :nodoc:
341
+ handler = lambda do
342
+ unless reporter.passed? then
343
+ warn "Current results:"
344
+ warn ""
345
+ warn reporter.reporters.first
346
+ warn ""
347
+ end
348
+ end
349
+
350
+ on_signal ::Minitest.info_signal, handler, &block
351
+ end
352
+
353
+ SIGNALS = Signal.list # :nodoc:
354
+
355
+ def self.on_signal name, action # :nodoc:
356
+ supported = SIGNALS[name]
357
+
358
+ old_trap = trap name do
359
+ old_trap.call if old_trap.respond_to? :call
360
+ action.call
361
+ end if supported
362
+
363
+ yield
364
+ ensure
365
+ trap name, old_trap if supported
366
+ end
367
+
368
+ ##
369
+ # Each subclass of Runnable is responsible for overriding this
370
+ # method to return all runnable methods. See #methods_matching.
371
+
372
+ def self.runnable_methods
373
+ raise NotImplementedError, "subclass responsibility"
374
+ end
375
+
376
+ ##
377
+ # Returns all subclasses of Runnable.
378
+
379
+ def self.runnables
380
+ @@runnables
381
+ end
382
+
383
+ @@marshal_dump_warned = false
384
+
385
+ def marshal_dump # :nodoc:
386
+ unless @@marshal_dump_warned then
387
+ warn ["Minitest::Runnable#marshal_dump is deprecated.",
388
+ "You might be violating internals. From", caller.first].join " "
389
+ @@marshal_dump_warned = true
390
+ end
391
+
392
+ [self.name, self.failures, self.assertions, self.time]
393
+ end
394
+
395
+ def marshal_load ary # :nodoc:
396
+ self.name, self.failures, self.assertions, self.time = ary
397
+ end
398
+
399
+ def failure # :nodoc:
400
+ self.failures.first
401
+ end
402
+
403
+ def initialize name # :nodoc:
404
+ self.name = name
405
+ self.failures = []
406
+ self.assertions = 0
407
+ end
408
+
409
+ ##
410
+ # Runs a single method. Needs to return self.
411
+
412
+ def run
413
+ raise NotImplementedError, "subclass responsibility"
414
+ end
415
+
416
+ ##
417
+ # Did this run pass?
418
+ #
419
+ # Note: skipped runs are not considered passing, but they don't
420
+ # cause the process to exit non-zero.
421
+
422
+ def passed?
423
+ raise NotImplementedError, "subclass responsibility"
424
+ end
425
+
426
+ ##
427
+ # Returns a single character string to print based on the result
428
+ # of the run. One of <tt>"."</tt>, <tt>"F"</tt>,
429
+ # <tt>"E"</tt> or <tt>"S"</tt>.
430
+
431
+ def result_code
432
+ raise NotImplementedError, "subclass responsibility"
433
+ end
434
+
435
+ ##
436
+ # Was this run skipped? See #passed? for more information.
437
+
438
+ def skipped?
439
+ raise NotImplementedError, "subclass responsibility"
440
+ end
441
+ end
442
+
443
+ ##
444
+ # Shared code for anything that can get passed to a Reporter. See
445
+ # Minitest::Test & Minitest::Result.
446
+
447
+ module Reportable
448
+ ##
449
+ # Did this run pass?
450
+ #
451
+ # Note: skipped runs are not considered passing, but they don't
452
+ # cause the process to exit non-zero.
453
+
454
+ def passed?
455
+ not self.failure
456
+ end
457
+
458
+ ##
459
+ # The location identifier of this test. Depends on a method
460
+ # existing called class_name.
461
+
462
+ def location
463
+ loc = " [#{self.failure.location}]" unless passed? or error?
464
+ "#{self.class_name}##{self.name}#{loc}"
465
+ end
466
+
467
+ def class_name # :nodoc:
468
+ raise NotImplementedError, "subclass responsibility"
469
+ end
470
+
471
+ ##
472
+ # Returns ".", "F", or "E" based on the result of the run.
473
+
474
+ def result_code
475
+ self.failure and self.failure.result_code or "."
476
+ end
477
+
478
+ ##
479
+ # Was this run skipped?
480
+
481
+ def skipped?
482
+ self.failure and Skip === self.failure
483
+ end
484
+
485
+ ##
486
+ # Did this run error?
487
+
488
+ def error?
489
+ self.failures.any? { |f| UnexpectedError === f }
490
+ end
491
+ end
492
+
493
+ ##
494
+ # This represents a test result in a clean way that can be
495
+ # marshalled over a wire. Tests can do anything they want to the
496
+ # test instance and can create conditions that cause Marshal.dump to
497
+ # blow up. By using Result.from(a_test) you can be reasonably sure
498
+ # that the test result can be marshalled.
499
+
500
+ class Result < Runnable
501
+ include Minitest::Reportable
502
+
503
+ undef_method :marshal_dump
504
+ undef_method :marshal_load
505
+
506
+ ##
507
+ # The class name of the test result.
508
+
509
+ attr_accessor :klass
510
+
511
+ ##
512
+ # The location of the test method.
513
+
514
+ attr_accessor :source_location
515
+
516
+ ##
517
+ # Create a new test result from a Runnable instance.
518
+
519
+ def self.from runnable
520
+ o = runnable
521
+
522
+ r = self.new o.name
523
+ r.klass = o.class.name
524
+ r.assertions = o.assertions
525
+ r.failures = o.failures.dup
526
+ r.time = o.time
527
+
528
+ r.source_location = o.method(o.name).source_location rescue ["unknown", -1]
529
+
530
+ r
531
+ end
532
+
533
+ def class_name # :nodoc:
534
+ self.klass # for Minitest::Reportable
535
+ end
536
+
537
+ def to_s # :nodoc:
538
+ return location if passed? and not skipped?
539
+
540
+ failures.map { |failure|
541
+ "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
542
+ }.join "\n"
543
+ end
544
+ end
545
+
546
+ ##
547
+ # Defines the API for Reporters. Subclass this and override whatever
548
+ # you want. Go nuts.
549
+
550
+ class AbstractReporter
551
+ include Mutex_m
552
+
553
+ ##
554
+ # Starts reporting on the run.
555
+
556
+ def start
557
+ end
558
+
559
+ ##
560
+ # About to start running a test. This allows a reporter to show
561
+ # that it is starting or that we are in the middle of a test run.
562
+
563
+ def prerecord klass, name
564
+ end
565
+
566
+ ##
567
+ # Output and record the result of the test. Call
568
+ # {result#result_code}[rdoc-ref:Runnable#result_code] to get the
569
+ # result character string. Stores the result of the run if the run
570
+ # did not pass.
571
+
572
+ def record result
573
+ end
574
+
575
+ ##
576
+ # Outputs the summary of the run.
577
+
578
+ def report
579
+ end
580
+
581
+ ##
582
+ # Did this run pass?
583
+
584
+ def passed?
585
+ true
586
+ end
587
+ end
588
+
589
+ class Reporter < AbstractReporter # :nodoc:
590
+ ##
591
+ # The IO used to report.
592
+
593
+ attr_accessor :io
594
+
595
+ ##
596
+ # Command-line options for this run.
597
+
598
+ attr_accessor :options
599
+
600
+ def initialize io = $stdout, options = {} # :nodoc:
601
+ super()
602
+ self.io = io
603
+ self.options = options
604
+ end
605
+ end
606
+
607
+ ##
608
+ # A very simple reporter that prints the "dots" during the run.
609
+ #
610
+ # This is added to the top-level CompositeReporter at the start of
611
+ # the run. If you want to change the output of minitest via a
612
+ # plugin, pull this out of the composite and replace it with your
613
+ # own.
614
+
615
+ class ProgressReporter < Reporter
616
+ def prerecord klass, name #:nodoc:
617
+ if options[:verbose] then
618
+ io.print "%s#%s = " % [klass.name, name]
619
+ io.flush
620
+ end
621
+ end
622
+
623
+ def record result # :nodoc:
624
+ io.print "%.2f s = " % [result.time] if options[:verbose]
625
+ io.print result.result_code
626
+ io.puts if options[:verbose]
627
+ end
628
+ end
629
+
630
+ ##
631
+ # A reporter that gathers statistics about a test run. Does not do
632
+ # any IO because meant to be used as a parent class for a reporter
633
+ # that does.
634
+ #
635
+ # If you want to create an entirely different type of output (eg,
636
+ # CI, HTML, etc), this is the place to start.
637
+ #
638
+ # Example:
639
+ #
640
+ # class JenkinsCIReporter < StatisticsReporter
641
+ # def report
642
+ # super # Needed to calculate some statistics
643
+ #
644
+ # print "<testsuite "
645
+ # print "tests='#{count}' "
646
+ # print "failures='#{failures}' "
647
+ # # Remaining XML...
648
+ # end
649
+ # end
650
+
651
+ class StatisticsReporter < Reporter
652
+ ##
653
+ # Total number of assertions.
654
+
655
+ attr_accessor :assertions
656
+
657
+ ##
658
+ # Total number of test cases.
659
+
660
+ attr_accessor :count
661
+
662
+ ##
663
+ # An +Array+ of test cases that failed or were skipped.
664
+
665
+ attr_accessor :results
666
+
667
+ ##
668
+ # Time the test run started. If available, the monotonic clock is
669
+ # used and this is a +Float+, otherwise it's an instance of
670
+ # +Time+.
671
+
672
+ attr_accessor :start_time
673
+
674
+ ##
675
+ # Test run time. If available, the monotonic clock is used and
676
+ # this is a +Float+, otherwise it's an instance of +Time+.
677
+
678
+ attr_accessor :total_time
679
+
680
+ ##
681
+ # Total number of tests that failed.
682
+
683
+ attr_accessor :failures
684
+
685
+ ##
686
+ # Total number of tests that erred.
687
+
688
+ attr_accessor :errors
689
+
690
+ ##
691
+ # Total number of tests that where skipped.
692
+
693
+ attr_accessor :skips
694
+
695
+ def initialize io = $stdout, options = {} # :nodoc:
696
+ super
697
+
698
+ self.assertions = 0
699
+ self.count = 0
700
+ self.results = []
701
+ self.start_time = nil
702
+ self.total_time = nil
703
+ self.failures = nil
704
+ self.errors = nil
705
+ self.skips = nil
706
+ end
707
+
708
+ def passed? # :nodoc:
709
+ results.all?(&:skipped?)
710
+ end
711
+
712
+ def start # :nodoc:
713
+ self.start_time = Minitest.clock_time
714
+ end
715
+
716
+ def record result # :nodoc:
717
+ self.count += 1
718
+ self.assertions += result.assertions
719
+
720
+ results << result if not result.passed? or result.skipped?
721
+ end
722
+
723
+ ##
724
+ # Report on the tracked statistics.
725
+
726
+ def report
727
+ aggregate = results.group_by { |r| r.failure.class }
728
+ aggregate.default = [] # dumb. group_by should provide this
729
+
730
+ self.total_time = Minitest.clock_time - start_time
731
+ self.failures = aggregate[Assertion].size
732
+ self.errors = aggregate[UnexpectedError].size
733
+ self.skips = aggregate[Skip].size
734
+ end
735
+ end
736
+
737
+ ##
738
+ # A reporter that prints the header, summary, and failure details at
739
+ # the end of the run.
740
+ #
741
+ # This is added to the top-level CompositeReporter at the start of
742
+ # the run. If you want to change the output of minitest via a
743
+ # plugin, pull this out of the composite and replace it with your
744
+ # own.
745
+
746
+ class SummaryReporter < StatisticsReporter
747
+ # :stopdoc:
748
+ attr_accessor :sync
749
+ attr_accessor :old_sync
750
+ # :startdoc:
751
+
752
+ def start # :nodoc:
753
+ super
754
+
755
+ io.puts "Run options: #{options[:args]}"
756
+ io.puts
757
+ io.puts "# Running:"
758
+ io.puts
759
+
760
+ self.sync = io.respond_to? :"sync=" # stupid emacs
761
+ self.old_sync, io.sync = io.sync, true if self.sync
762
+ end
763
+
764
+ def report # :nodoc:
765
+ super
766
+
767
+ io.sync = self.old_sync
768
+
769
+ io.puts unless options[:verbose] # finish the dots
770
+ io.puts
771
+ io.puts statistics
772
+ aggregated_results io
773
+ io.puts summary
774
+ end
775
+
776
+ def statistics # :nodoc:
777
+ "Finished in %.6fs, %.4f runs/s, %.4f assertions/s." %
778
+ [total_time, count / total_time, assertions / total_time]
779
+ end
780
+
781
+ def aggregated_results io # :nodoc:
782
+ filtered_results = results.dup
783
+ filtered_results.reject!(&:skipped?) unless options[:verbose]
784
+
785
+ filtered_results.each_with_index { |result, i|
786
+ io.puts "\n%3d) %s" % [i+1, result]
787
+ }
788
+ io.puts
789
+ io
790
+ end
791
+
792
+ def to_s # :nodoc:
793
+ aggregated_results(StringIO.new(binary_string)).string
794
+ end
795
+
796
+ def summary # :nodoc:
797
+ extra = ""
798
+
799
+ extra = "\n\nYou have skipped tests. Run with --verbose for details." if
800
+ results.any?(&:skipped?) unless options[:verbose] or ENV["MT_NO_SKIP_MSG"]
801
+
802
+ "%d runs, %d assertions, %d failures, %d errors, %d skips%s" %
803
+ [count, assertions, failures, errors, skips, extra]
804
+ end
805
+
806
+ private
807
+
808
+ if '<3'.respond_to? :b
809
+ def binary_string; ''.b; end
810
+ else
811
+ def binary_string; ''.force_encoding(Encoding::ASCII_8BIT); end
812
+ end
813
+ end
814
+
815
+ ##
816
+ # Dispatch to multiple reporters as one.
817
+
818
+ class CompositeReporter < AbstractReporter
819
+ ##
820
+ # The list of reporters to dispatch to.
821
+
822
+ attr_accessor :reporters
823
+
824
+ def initialize *reporters # :nodoc:
825
+ super()
826
+ self.reporters = reporters
827
+ end
828
+
829
+ def io # :nodoc:
830
+ reporters.first.io
831
+ end
832
+
833
+ ##
834
+ # Add another reporter to the mix.
835
+
836
+ def << reporter
837
+ self.reporters << reporter
838
+ end
839
+
840
+ def passed? # :nodoc:
841
+ self.reporters.all?(&:passed?)
842
+ end
843
+
844
+ def start # :nodoc:
845
+ self.reporters.each(&:start)
846
+ end
847
+
848
+ def prerecord klass, name # :nodoc:
849
+ self.reporters.each do |reporter|
850
+ # TODO: remove conditional for minitest 6
851
+ reporter.prerecord klass, name if reporter.respond_to? :prerecord
852
+ end
853
+ end
854
+
855
+ def record result # :nodoc:
856
+ self.reporters.each do |reporter|
857
+ reporter.record result
858
+ end
859
+ end
860
+
861
+ def report # :nodoc:
862
+ self.reporters.each(&:report)
863
+ end
864
+ end
865
+
866
+ ##
867
+ # Represents run failures.
868
+
869
+ class Assertion < Exception
870
+ def error # :nodoc:
871
+ self
872
+ end
873
+
874
+ ##
875
+ # Where was this run before an assertion was raised?
876
+
877
+ def location
878
+ last_before_assertion = ""
879
+ self.backtrace.reverse_each do |s|
880
+ break if s =~ /in .(assert|refute|flunk|pass|fail|raise|must|wont)/
881
+ last_before_assertion = s
882
+ end
883
+ last_before_assertion.sub(/:in .*$/, "")
884
+ end
885
+
886
+ def result_code # :nodoc:
887
+ result_label[0, 1]
888
+ end
889
+
890
+ def result_label # :nodoc:
891
+ "Failure"
892
+ end
893
+ end
894
+
895
+ ##
896
+ # Assertion raised when skipping a run.
897
+
898
+ class Skip < Assertion
899
+ def result_label # :nodoc:
900
+ "Skipped"
901
+ end
902
+ end
903
+
904
+ ##
905
+ # Assertion wrapping an unexpected error that was raised during a run.
906
+
907
+ class UnexpectedError < Assertion
908
+ attr_accessor :exception # :nodoc:
909
+
910
+ def initialize exception # :nodoc:
911
+ super "Unexpected exception"
912
+ self.exception = exception
913
+ end
914
+
915
+ def backtrace # :nodoc:
916
+ self.exception.backtrace
917
+ end
918
+
919
+ def error # :nodoc:
920
+ self.exception
921
+ end
922
+
923
+ def message # :nodoc:
924
+ bt = Minitest.filter_backtrace(self.backtrace).join "\n "
925
+ "#{self.exception.class}: #{self.exception.message}\n #{bt}"
926
+ end
927
+
928
+ def result_label # :nodoc:
929
+ "Error"
930
+ end
931
+ end
932
+
933
+ ##
934
+ # Provides a simple set of guards that you can use in your tests
935
+ # to skip execution if it is not applicable. These methods are
936
+ # mixed into Test as both instance and class methods so you
937
+ # can use them inside or outside of the test methods.
938
+ #
939
+ # def test_something_for_mri
940
+ # skip "bug 1234" if jruby?
941
+ # # ...
942
+ # end
943
+ #
944
+ # if windows? then
945
+ # # ... lots of test methods ...
946
+ # end
947
+
948
+ module Guard
949
+
950
+ ##
951
+ # Is this running on jruby?
952
+
953
+ def jruby? platform = RUBY_PLATFORM
954
+ "java" == platform
955
+ end
956
+
957
+ ##
958
+ # Is this running on maglev?
959
+
960
+ def maglev? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
961
+ "maglev" == platform
962
+ end
963
+
964
+ ##
965
+ # Is this running on mri?
966
+
967
+ def mri? platform = RUBY_DESCRIPTION
968
+ /^ruby/ =~ platform
969
+ end
970
+
971
+ ##
972
+ # Is this running on rubinius?
973
+
974
+ def rubinius? platform = defined?(RUBY_ENGINE) && RUBY_ENGINE
975
+ "rbx" == platform
976
+ end
977
+
978
+ ##
979
+ # Is this running on windows?
980
+
981
+ def windows? platform = RUBY_PLATFORM
982
+ /mswin|mingw/ =~ platform
983
+ end
984
+ end
985
+
986
+ ##
987
+ # The standard backtrace filter for minitest.
988
+ #
989
+ # See Minitest.backtrace_filter=.
990
+
991
+ class BacktraceFilter
992
+
993
+ MT_RE = %r%lib/minitest% #:nodoc:
994
+
995
+ ##
996
+ # Filter +bt+ to something useful. Returns the whole thing if $DEBUG.
997
+
998
+ def filter bt
999
+ return ["No backtrace"] unless bt
1000
+
1001
+ return bt.dup if $DEBUG
1002
+
1003
+ new_bt = bt.take_while { |line| line !~ MT_RE }
1004
+ new_bt = bt.select { |line| line !~ MT_RE } if new_bt.empty?
1005
+ new_bt = bt.dup if new_bt.empty?
1006
+
1007
+ new_bt
1008
+ end
1009
+ end
1010
+
1011
+ self.backtrace_filter = BacktraceFilter.new
1012
+
1013
+ def self.run_one_method klass, method_name # :nodoc:
1014
+ result = klass.new(method_name).run
1015
+ raise "#{klass}#run _must_ return a Result" unless Result === result
1016
+ result
1017
+ end
1018
+
1019
+ # :stopdoc:
1020
+
1021
+ if defined? Process::CLOCK_MONOTONIC # :nodoc:
1022
+ def self.clock_time
1023
+ Process.clock_gettime Process::CLOCK_MONOTONIC
1024
+ end
1025
+ else
1026
+ def self.clock_time
1027
+ Time.now
1028
+ end
1029
+ end
1030
+
1031
+ class Runnable # re-open
1032
+ def self.inherited klass # :nodoc:
1033
+ self.runnables << klass
1034
+ super
1035
+ end
1036
+ end
1037
+
1038
+ # :startdoc:
1039
+ end
1040
+
1041
+ require "minitest/test"