class TestBisect::BisectTask

Attributes

name[RW]
suspects[RW]

We try to get the list of suspects from the test task, but they can be manually specified here

test_task_name[RW]

We assume the task used to run the tests is “test” but if not, specify here

Public Class Methods

new(name=:bisect) { |self| ... } click to toggle source

Create a test bisect task if the test task which runs the tests is not “test” then specify is as the second arg.

# File lib/test_bisect.rb, line 19
def initialize(name=:bisect)
  @name = name
  @test_task_name = :test
  # might as well take the last one
  ObjectSpace.each_object(Rake::TestTask) do |obj|
    @test_task = obj if obj != self
  end
  @suspects = @test_task.instance_variable_get(:@test_files) || []
  @suspects += FileList[@test_task.pattern]
  yield self if block_given?
  define
end

Public Instance Methods

bisect(suspects, victim) click to toggle source
# File lib/test_bisect.rb, line 42
def bisect(suspects, victim)
  return suspects[0] if suspects.size == 1

  pivot = suspects.size / 2
  suspects.partition {|file| suspects.index(file) < pivot }.each do |part|
    begin
      @test_task.test_files = part + [victim]
      Rake::Task[@test_task_name].reenable
      Rake::Task[@test_task_name].invoke
      puts "------ PASSED -------"
      next
    rescue RuntimeError => e
      if e.message =~ /Command failed with status/
        puts "------ FAILED -------"
        return bisect(part, victim)
      else
        raise
      end
    end
  end
end
define() click to toggle source
# File lib/test_bisect.rb, line 32
def define
  desc "Bisect test suite files to find file which makes victim fail"
  task @name, [:victim] do |task, args|
    @test_task.pattern = nil
    criminal = bisect(@suspects, args.victim)
    puts "FOUND: #{criminal}"
  end
  self
end