Module: Minitest

Includes:
ErrorOnWarning
Defined in:
lib/minitest.rb,
lib/minitest/spec.rb,
lib/minitest/test.rb,
lib/minitest/bisect.rb,
lib/minitest/sprint.rb,
lib/minitest/compress.rb,
lib/minitest/parallel.rb,
lib/minitest/benchmark.rb,
lib/minitest/benchmark.rb,
lib/minitest/test_task.rb,
lib/minitest/assertions.rb,
lib/minitest/pride_plugin.rb,
lib/minitest/path_expander.rb,
lib/minitest/server_plugin.rb,
lib/minitest/sprint_plugin.rb,
lib/minitest/error_on_warning.rb

Overview

:startdoc:

Defined Under Namespace

Modules: Assertions, Compress, ErrorOnWarning, Expectations, Guard, Parallel, Reportable Classes: AbstractReporter, Assertion, BacktraceFilter, BenchSpec, Benchmark, Bisect, CompositeReporter, Expectation, PathExpander, PrideIO, PrideLOL, ProgressReporter, Reporter, Result, Runnable, Server, ServerReporter, Skip, Spec, Sprint, StatisticsReporter, SummaryReporter, Test, TestTask, UnexpectedError, UnexpectedWarning, VendoredPathExpander

Constant Summary collapse

VERSION =

:nodoc:

"6.0.1"
@@after_run =
[]

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ErrorOnWarning

#warn

Class Method Details

.after_run(&block) ⇒ Object

A simple hook allowing you to run a block of code after everything is done running. Eg:

Minitest.after_run { p $debugging_info }


95
96
97
# File 'lib/minitest.rb', line 95

def self.after_run &block
  @@after_run << block
end

.autorunObject

Registers Minitest to run at process exit



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/minitest.rb', line 69

def self.autorun
  Warning[:deprecated] = true

  at_exit {
    next if $! and not ($!.kind_of? SystemExit and $!.success?)

    exit_code = nil

    pid = Process.pid
    at_exit {
      next if !Minitest.allow_fork && Process.pid != pid
      @@after_run.reverse_each(&:call)
      exit exit_code || false
    }

    exit_code = Minitest.run ARGV
  } unless @@installed_at_exit
  @@installed_at_exit = true
end

.cattr_accessor(name) ⇒ Object

:nodoc:



19
20
21
# File 'lib/minitest.rb', line 19

def self.cattr_accessor name # :nodoc:
  (class << self; self; end).attr_accessor name
end

.clock_timeObject

:nodoc:



1208
1209
1210
# File 'lib/minitest.rb', line 1208

def self.clock_time
  Process.clock_gettime Process::CLOCK_MONOTONIC
end

.empty_run!(options) ⇒ Object

:nodoc:



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
# File 'lib/minitest.rb', line 331

def self.empty_run! options # :nodoc:
  filter = options[:include]
  return true unless filter # no filter, but nothing ran == success

  warn "Nothing ran for filter: %s" % [filter]

  require "did_you_mean" # soft dependency, punt if it doesn't load

  ms = Runnable.runnables.flat_map(&:runnable_methods)
  cs = DidYouMean::SpellChecker.new(dictionary: ms).correct filter

  warn DidYouMean::Formatter.message_for cs unless cs.empty?
rescue LoadError
  # do nothing
end

.filter_backtrace(bt) ⇒ Object

:nodoc:



364
365
366
367
368
# File 'lib/minitest.rb', line 364

def self.filter_backtrace bt # :nodoc:
  result = backtrace_filter.filter bt
  result = bt.dup if result.empty?
  result
end

.init_plugins(options) ⇒ Object

:nodoc:



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/minitest.rb', line 134

def self.init_plugins options # :nodoc:
  self.extensions.each do |mod_or_meth|
    case mod_or_meth
    when Symbol, String then
      name = mod_or_meth
      msg = "plugin_#{name}_init"
      next unless self.respond_to? msg
      send msg, options
    when Module then
      recv = mod_or_meth
      next unless recv.respond_to? :minitest_plugin_init
      recv.minitest_plugin_init options
    else
      raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
    end
  end
end

.load(*names) ⇒ Object

Manually load plugins by name.



102
103
104
105
106
107
108
# File 'lib/minitest.rb', line 102

def self.load *names
  names.each do |name|
    require "minitest/#{name}_plugin"

    self.extensions << name.to_s
  end
end

.load_pluginsObject

:nodoc:



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/minitest.rb', line 118

def self.load_plugins # :nodoc:
  return unless defined? Gem

  seen = {}

  Gem.find_files("minitest/*_plugin.rb").each do |plugin_path|
    name = File.basename plugin_path, "_plugin.rb"

    next if seen[name]
    seen[name] = true

    require plugin_path
    self.extensions << name
  end
end

.plugin_pride_init(options) ⇒ Object

:nodoc:



10
11
12
13
14
15
16
17
18
19
# File 'lib/minitest/pride_plugin.rb', line 10

def self.plugin_pride_init options # :nodoc:
  return unless PrideIO.pride?

  klass = ENV["TERM"] =~ /^xterm|-(?:256color|direct)$/ ? PrideLOL : PrideIO
  io    = klass.new options[:io]

  self.reporter.reporters.grep(Minitest::Reporter).each do |rep|
    rep.io = io if rep.io.tty?
  end
end

.plugin_pride_options(opts, _options) ⇒ Object

:nodoc:



4
5
6
7
8
# File 'lib/minitest/pride_plugin.rb', line 4

def self.plugin_pride_options opts, _options # :nodoc:
  opts.on "-p", "--pride", "Pride. Show your testing pride!" do
    PrideIO.pride!
  end
end

.plugin_server_init(options) ⇒ Object



12
13
14
15
16
17
# File 'lib/minitest/server_plugin.rb', line 12

def self.plugin_server_init options
  if @server then
    require_relative "server"
    self.reporter << Minitest::ServerReporter.new(@server)
  end
end

.plugin_server_options(opts, options) ⇒ Object

:nodoc:



6
7
8
9
10
# File 'lib/minitest/server_plugin.rb', line 6

def self.plugin_server_options opts, options # :nodoc:
  opts.on "--server=pid", Integer, "Connect to minitest server w/ pid." do |s|
    @server = s
  end
end

.plugin_sprint_init(options) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/minitest/sprint_plugin.rb', line 28

def self.plugin_sprint_init options
  require_relative "sprint"
  case options[:sprint]
  when :rake then
    self.reporter << Minitest::Sprint::RakeReporter.new(options[:rake_task])
  when :binstub, :names then
    self.reporter << Minitest::Sprint::SprintReporter.new
  when :lines then
    self.reporter << Minitest::Sprint::SprintReporter.new(:lines)
  end
end

.plugin_sprint_options(opts, options) ⇒ Object

:nodoc:



13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/minitest/sprint_plugin.rb', line 13

def self.plugin_sprint_options opts, options # :nodoc:
  opts.on "--rake [TASK]", "Report how to re-run failures with rake." do |task|
    options[:sprint] = :rake
    options[:rake_task] = task
  end

  opts.deprecate "--binstub", "--rerun"

  sprint_styles = %w[rake lines names binstub]

  opts.on "-r", "--rerun [STYLE]", sprint_styles, "Report how to re-run failures using STYLE (names, lines)." do |style|
    options[:sprint] = (style || :lines).to_sym
  end
end

.process_args(args = []) ⇒ Object

:nodoc:



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/minitest.rb', line 152

def self.process_args args = [] # :nodoc:
  options = {
              :io => $stdout,
            }
  orig_args = args.dup

  warn "--no-plugins is a no-op" if args.delete "--no-plugins" # TODO: remove me! when?

  OptionParser.new do |opts|
    opts.program_name = "minitest"
    opts.version = Minitest::VERSION

    opts.banner = [
      "Usage: minitest [paths]     [options]",
      "ruby path/to/test.rb [options]",
      "rake test          [A=options] (see Minitest::TestTask for more options)\n\n",
    ].join "\n   or: "

    opts.on "-h", "--help", "Display this help." do
      puts opts
      exit! true
    end

    opts.on "-V", "--version", "Display the version." do
      puts "#{opts.program_name} #{Minitest::VERSION}"
      exit! true
    end

    desc = "Sets random seed. Also via env, eg: SEED=42"
    opts.on "-s", "--seed SEED", Integer, desc do |m|
      options[:seed] = m
    end

    opts.on "-v", "--verbose", "Verbose. Print each name as they run." do
      options[:verbose] = true
    end

    opts.on "-q", "--quiet", "Quiet. Show no dots while processing files." do
      options[:quiet] = true
    end

    opts.on "--show-skips", "Show skipped at the end of run." do
      options[:show_skips] = true
    end

    opts.on "-b", "--bisect", "Run minitest in bisect-mode to isolate flaky tests."

    opts.on "-i", "--include PATTERN", "Include /regexp/ or string for run." do |a|
      options[:include] = a
    end

    opts.on "-e", "--exclude PATTERN", "Exclude /regexp/ or string from run." do |a|
      options[:exclude] = a
    end

    # part of my unofficial embedded gem "makeoptparseworkwell"
    def opts.topdict(name)   = (name.length > 1 ? top.long : top.short)
    def opts.alias(from, to) = (dict = topdict(from) ; dict[to] = dict[from])

    # these will work but won't show up in --help output:
    opts.alias "include", "name"
    opts.alias "i",       "n"
    opts.alias "e",       "x"

    opts.on "-S", "--skip CODES", String, "Skip reporting of certain types of results (eg E)." do |s|
      options[:skip] = s.chars.to_a
    end

    opts.on "-W[error]", String, "Turn Ruby warnings into errors" do |s|
      options[:Werror] = true
      case s
      when "error", "all", nil then
        require_relative "minitest/error_on_warning"
        $VERBOSE = true
        ::Warning[:deprecated] = true
      else
        ::Warning[s.to_sym] = true # check validity of category
      end
    end

    unless extensions.empty?
      opts.separator ""
      opts.separator "Known extensions: #{extensions.join ", "}"

      extensions.each do |mod_or_meth|
        case mod_or_meth
        when Symbol, String then
          meth = mod_or_meth
          msg = "plugin_#{meth}_options"
          send msg, opts, options if respond_to? msg
        when Module
          recv = mod_or_meth
          next unless recv.respond_to? :minitest_plugin_options
          recv.minitest_plugin_options opts, options
        else
          raise ArgumentError, "plugin is %p, but it must be a symbol, string or module" % [mod_or_meth]
        end
      end
    end

    begin
      opts.parse! args
    rescue OptionParser::InvalidOption => e
      puts
      puts e
      puts
      puts opts
      exit 1
    end

    orig_args -= args
  end

  unless options[:seed] then
    srand
    options[:seed] = (ENV["SEED"] || srand).to_i % 0xFFFF
    orig_args << "--seed" << options[:seed].to_s
  end

  options[:args] = orig_args.map { |s|
    s.match?(/[\s|&<>$()]/) ? s.inspect : s
  }.join " "

  options
end

.register_plugin(name_or_mod) ⇒ Object

Register a plugin to be used. Does NOT require / load it.



113
114
115
116
# File 'lib/minitest.rb', line 113

def self.register_plugin name_or_mod
  self.extensions << name_or_mod
  nil
end

.run(args = []) ⇒ Object

This is the top-level run method. Everything starts from here. It tells each Runnable sub-class to run, and each of those are responsible for doing whatever they do.

The overall structure of a run looks like this:

[Minitest.load_plugins] optional, called by user, or require what you want
Minitest.autorun
  Minitest.run(args)
    Minitest.process_args
    Minitest.init_plugins
    Minitest.run_all_suites(reporter, options)
      Runnable.runnables.each |runnable_klass|
        runnable_klass.run_suite(reporter, options)
          filtered_methods = runnable_klass.filter_runnable_methods options
          filtered_methods.each |runnable_method|
            runnable_klass.run(self, runnable_method, reporter)
              runnable_klass.new(runnable_method).run


298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/minitest.rb', line 298

def self.run args = []
  options = process_args args

  Minitest.seed = options[:seed]
  srand Minitest.seed

  reporter = CompositeReporter.new
  reporter << SummaryReporter.new(options[:io], options)
  reporter << ProgressReporter.new(options[:io], options) unless options[:quiet]

  self.reporter = reporter # this makes it available to plugins
  self.init_plugins options
  self.reporter = nil # runnables shouldn't depend on the reporter, ever

  self.parallel_executor.start if parallel_executor.respond_to? :start
  reporter.start
  begin
    run_all_suites reporter, options
    finished = true
  rescue Interrupt
    warn "Interrupted. Exiting..."
  end
  self.parallel_executor.shutdown if parallel_executor.respond_to? :shutdown

  # might have been removed/replaced during init_plugins:
  summary = reporter.reporters.grep(SummaryReporter).first

  reporter.report

  return empty_run! options if finished && summary && summary.count == 0
  finished and reporter.passed?
end

.run_all_suites(reporter, options) ⇒ Object

Internal run method. Responsible for telling all Runnable sub-classes to run.



351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/minitest.rb', line 351

def self.run_all_suites reporter, options
  suites = Runnable.runnables.shuffle
  parallel, serial = suites.partition { |s| s.run_order == :parallel }

  # If we run the parallel tests before the serial tests, the parallel tests
  # could run in parallel with the serial tests. This would be bad because
  # the serial tests won't lock around Reporter#record. Run the serial tests
  # first, so that after they complete, the parallel tests will lock when
  # recording results.
  serial.map { |suite| suite.run_suite reporter, options } +
    parallel.map { |suite| suite.run_suite reporter, options }
end

Instance Method Details

#backtrace_filterObject

Filter object for backtraces.



43
# File 'lib/minitest.rb', line 43

cattr_accessor :backtrace_filter

#extensionsObject

Names of known extension plugins.



55
# File 'lib/minitest.rb', line 55

cattr_accessor :extensions

#info_signalObject

The signal to use for dumping information to STDERR. Defaults to “INFO”.



60
# File 'lib/minitest.rb', line 60

cattr_accessor :info_signal

#parallel_executorObject

Parallel test executor



34
# File 'lib/minitest.rb', line 34

cattr_accessor :parallel_executor

#reporterObject

Reporter object to be used for all runs.

NOTE: This accessor is only available during setup, not during runs.



50
# File 'lib/minitest.rb', line 50

cattr_accessor :reporter

#seedObject

The random seed used for this run. This is used to srand at the start of the run and between each Runnable.run.

Set via Minitest.run after processing args.



29
# File 'lib/minitest.rb', line 29

cattr_accessor :seed