Class: Minitest::PathExpander

Inherits:
VendoredPathExpander show all
Defined in:
lib/minitest/path_expander.rb

Overview

Minitest's PathExpander to find and filter tests.

Defined Under Namespace

Classes: TM

Constant Summary collapse

TEST_GLOB =

:nodoc:

"**/{test_*,*_test,spec_*,*_spec}.rb"

Instance Attribute Summary collapse

Attributes inherited from VendoredPathExpander

#args, #glob, #path

Instance Method Summary collapse

Methods inherited from VendoredPathExpander

#expand_dirs_to_files, #filter_files, #pre_process, #process, #process_file

Constructor Details

#initialize(args = ARGV) ⇒ PathExpander

:nodoc:



229
230
231
232
# File 'lib/minitest/path_expander.rb', line 229

def initialize args = ARGV # :nodoc:
  super args, TEST_GLOB, "test"
  self. = {}
end

Instance Attribute Details

#by_lineObject

:nodoc:



225
226
227
# File 'lib/minitest/path_expander.rb', line 225

def 
  @by_line
end

Instance Method Details

#all_testsObject

Find and return all known tests as a hash of klass => [TM...] pairs.



298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/minitest/path_expander.rb', line 298

def all_tests
  Minitest.seed = 42 # minor hack to deal with runnable_methods shuffling
  Minitest::Runnable.runnables
    .to_h { |k|
      ms = k.runnable_methods
        .sort
        .map { |m| TM.new k, m.to_sym }
        .sort_by { |t| [t.path, t.line_s] }
      [k, ms]
    }
    .reject { |k, v| v.empty? }
end

#handle_missing_tests?(tests) ⇒ Boolean

Handle the case where a line number doesn't match any known tests. Returns true to signal that running should stop.

Returns:

  • (Boolean)


346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/minitest/path_expander.rb', line 346

def handle_missing_tests? tests
  _tests = tests.values.flatten
  not_found = 
    .flat_map { |f, ls| ls.map { |l| [f, l] } }
    .reject { |f, l|
      _tests.any? { |t| t.path == f and t.include? l }
    }

  unless not_found.empty? then
    by_path = all_tests.values.flatten.group_by(&:path)

    puts
    puts "ERROR: test(s) not found at:"
    not_found.each do |f, l|
      puts "  %s:%s" % [f, l]
      puts
      puts "Did you mean?"
      puts
      l = l.begin if l.is_a? Range
      by_path[f]
        .sort_by { |m| (m.line_s - l).abs }
        .first(2)
        .each do |m|
          puts "  %-30s (dist=%+d) (%s)" % [m, m.line_s - l, m.name]
        end
      puts
    end
    true
  end
end

#post_processObject

Add additional arguments to args to handle path:line argument filtering



283
284
285
286
287
288
289
290
291
292
# File 'lib/minitest/path_expander.rb', line 283

def post_process
  return if .empty?

  tests = tests_by_class

  exit! if handle_missing_tests? tests

  test_res = tests_to_regexp tests
  self.args << "-n" << "/#{test_res.join "|"}/"
end

#process_argsObject

:nodoc:



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
# File 'lib/minitest/path_expander.rb', line 234

def process_args # :nodoc:
  args.reject! { |arg|                # this is a good use of overriding
    case arg
    when /^(.*):([\d,-]+)$/ then
      f, ls = $1, $2
      ls = ls
        .split(/,/)
        .map { |l|
          case l
          when /^\d+$/ then
            l.to_i
          when /^(\d+)-(\d+)$/ then
            $1.to_i..$2.to_i
          else
            raise "unhandled argument format: %p" % [l]
          end
        }
      next unless File.exist? f
      args << f                       # push path on lest it run whole dir
      [f] = ls
    end
  }

  super
end

#process_flags(flags) ⇒ Object

Overrides PathExpander#process_flags to filter out ruby flags from minitest flags. Only supports -I, -d, and -w for ruby.



265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/minitest/path_expander.rb', line 265

def process_flags flags
  flags.reject { |flag| # all hits are truthy, so this works out well
    case flag
    when /^-I(.*)/ then
      $LOAD_PATH.prepend(*$1.split(/:/))
    when /^-d/ then
      $DEBUG = true
    when /^-w/ then
      $VERBOSE = true
    else
      false
    end
  }
end

#tests_by_classObject

Returns a hash mapping Minitest runnable classes to TMs



314
315
316
317
318
319
320
321
322
323
# File 'lib/minitest/path_expander.rb', line 314

def tests_by_class
  all_tests
    .transform_values { |ms|
      ms.select { |m|
        bl = [m.path]
        not bl or bl.any? { |l| m.include? l }
      }
    }
    .reject { |k, v| v.empty? }
end

#tests_to_regexp(tests) ⇒ Object

Converts tests to an array of "klass#(methods+)" regexps to be used for test selection.



329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/minitest/path_expander.rb', line 329

def tests_to_regexp tests
  tests                                         # { k1 => [Test(a), ...}
    .transform_values { |tms| tms.map(&:name) } # { k1 => %w[a, b], ...}
    .map { |k, ns|                              # [ "k1#(?:a|b)", "k2#c", ...]
      if ns.size > 1 then
        ns.map! { |n| Regexp.escape n }
        "%s#\(?:%s\)" % [Regexp.escape(k.name), ns.join("|")]
      else
        "%s#%s" % [Regexp.escape(k.name), ns.first]
      end
    }
end