Created
January 27, 2010 21:16
-
-
Save zed-0xff/288159 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# this tool is similar to "git bisect" one, but for specs. | |
# it tries to find what spec from list of specs breaks execution of one specified spec. | |
# | |
# see more at http://zed.0xff.me/2010/01/28/rspec-bisect | |
# | |
# usage example: | |
# ./rspec-bisect.rb spec/**/*_spec.rb spec/controllers/spaces/tickets_controller_spec.rb | |
# [.] rspec runner: ./script/spec | |
# [.] target spec : spec/controllers/spaces/tickets_controller_spec.rb | |
# [.] 123 candidate specs | |
# [.] running 62 specs.. Done. ( 19s) (105/0/4) : target OK | |
# [.] running 63 specs.. Done. ( 64s) (386/2/6) : target FAIL | |
# [.] running 32 specs.. Done. ( 34s) (157/0/2) : target OK | |
# [.] running 32 specs.. Done. ( 43s) (238/2/4) : target FAIL | |
# [.] running 16 specs.. Done. ( 38s) (129/2/1) : target FAIL | |
# [.] running 8 specs.. Done. ( 27s) (73/0) : target OK | |
# [.] running 9 specs.. Done. ( 19s) (65/2/1) : target FAIL | |
# [.] running 5 specs.. Done. ( 19s) (52/2/1) : target FAIL | |
# [.] running 3 specs.. Done. ( 16s) (33/0) : target OK | |
# [.] running 3 specs.. Done. ( 18s) (28/2/1) : target FAIL | |
# [.] running 2 specs.. Done. ( 17s) (27/2/1) : target FAIL | |
# [*] found matching spec: spec/models/mailman_spec.rb | |
$rspec_runner = './script/spec' | |
$target = nil | |
$shuffle = false | |
require 'optparse' | |
op = OptionParser.new do |opts| | |
opts.banner = "Usage: bisect.rb [options] [specs] [target_spec]" | |
opts.on("-r", "--runner PATHNAME", "Use specified rspec runner (default: #{$rspec_runner})") do |arg| | |
$rspec_runner = arg | |
end | |
opts.on("-t", "--target TARGET", "Specify target spec (default: last argument)") do |arg| | |
$target = arg | |
end | |
opts.on("-s", "--shuffle", "Shuffle specs before running them (default: sort by name)") do | |
$shuffle = true | |
end | |
end | |
op.parse! | |
specs = ARGV | |
if specs.size < 2 | |
puts "please give me at least 2 specs!" | |
puts op | |
exit | |
end | |
# TODO: warnings | |
target = $target || specs.pop | |
specs.delete(target) | |
specs.delete("./#{target}") | |
specs.delete(target.sub(/^\.\//,'')) | |
if $shuffle | |
specs.shuffle! | |
else | |
specs.sort! | |
end | |
puts "[.] rspec runner: #{$rspec_runner}" | |
puts "[.] target spec : #{target}" | |
puts "[.] #{specs.size} candidate specs" | |
def run_specs target, specs | |
# puts "./script/spec #{specs.join(' ')} #{target}" | |
printf "[.] running %4d specs.. ", specs.size+1 | |
STDOUT.flush | |
t0 = Time.now | |
t = `#{$rspec_runner} #{specs.join(' ')} #{target}` | |
r = false | |
if t["#{target}:"] | |
lines = t.strip.split("\n") | |
lines.each_with_index do |line,idx| | |
if line["#{target}:"] && idx>0 && !lines[idx-1]['(Not Yet Implemented)'] | |
r = true | |
break | |
end | |
end | |
end | |
counts = t[/^\d+ examples, .*$/].to_s.strip.gsub(/[a-z,]/,'').strip.gsub(/ +/,"/") | |
# puts "Done. (#{(Time.now - t0).to_i}s) (#{counts})\t: target #{r ? 'OK' : 'FAIL'}" | |
printf("Done. (%3ds) (%s)\t: target %s\n", | |
(Time.now - t0).to_i, | |
counts, | |
r ? 'FAIL' : 'OK' | |
) | |
r | |
end | |
def process_candidates target, specs | |
if specs.size <= 1 | |
puts "[*] found matching spec: #{specs.first}" | |
exit | |
else | |
if run_specs target, specs[0...specs.size/2] | |
process_candidates target, specs[0...specs.size/2] | |
elsif run_specs target, specs[specs.size/2..-1] | |
process_candidates target, specs[specs.size/2..-1] | |
else | |
puts "[?] all specs ran OK" | |
# run_specs target, specs | |
end | |
end | |
end | |
process_candidates target, specs |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is amazing. Small note. If you have any
./
before the test name rspec will run it out of order even if you specify--order defined