Skip to content

Commit

Permalink
Added keep_failed options (default: true)
Browse files Browse the repository at this point in the history
  • Loading branch information
thibaudgg committed Apr 23, 2011
1 parent 023363f commit d5cd494
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Guardfile
@@ -1,4 +1,4 @@
guard 'rspec', :cli => "-c -f doc" do
guard 'rspec', :version => 2 do
watch(%r{^spec/.+_spec\.rb})
watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }
Expand Down
1 change: 1 addition & 0 deletions README.rdoc
Expand Up @@ -77,6 +77,7 @@ Former <tt>:color</tt>, <tt>:drb</tt>, <tt>:fail_fast</tt> and <tt>:formatter</t
:notification => false # don't display Growl (or Libnotify) notification after the specs are done running, default: true
:all_after_pass => false # don't run all specs after changed specs pass, default: true
:all_on_start => false # don't run all the specs at startup, default: true
:keep_failed => true # keep failed specs untill them pass (useful with {:focus RSpec option}[http://relishapp.com/rspec/rspec-core/v/2-6-rc/dir/filtering/inclusion-filters]), default: true

== Notification

Expand Down
39 changes: 24 additions & 15 deletions lib/guard/rspec.rb
Expand Up @@ -3,41 +3,50 @@

module Guard
class RSpec < Guard

autoload :Runner, 'guard/rspec/runner'
autoload :Inspector, 'guard/rspec/inspector'

def initialize(watchers=[], options={})
super
@all_after_pass = options.delete(:all_after_pass)
@all_on_start = options.delete(:all_on_start)
@options = {
:all_after_pass => true,
:all_on_start => true,
:keep_failed => true
}.update(options)
@last_failed = false
@failed_paths = []

Runner.set_rspec_version(options)
end

# Call once when guard starts
def start
UI.info "Guard::RSpec is running, with RSpec #{Runner.rspec_version}!"
run_all unless @all_on_start == false
run_all if @options[:all_on_start]
end

def run_all
@last_failed = !Runner.run(["spec"], options.merge(:message => "Running all specs"))
passed = Runner.run(["spec"], options.merge(:message => "Running all specs"))

@failed_paths = [] if passed
@last_failed = !passed
end

def run_on_change(paths)
paths = Inspector.clean(paths)
passed = Runner.run(paths, options)
paths += @failed_paths if @options[:keep_failed]
passed = Runner.run(paths.uniq, options)

if @all_after_pass == false
passed
else
if passed
# clean failed paths memory
@failed_paths -= paths if @options[:keep_failed]
# run all the specs if the changed specs failed, like autotest
if passed && @last_failed
run_all
else
# track whether the changed specs failed for the next change
@last_failed = !passed
end
run_all if @last_failed && @options[:all_after_pass]
else
# remember failed paths for the next change
@failed_paths += paths if @options[:keep_failed]
# track whether the changed specs failed for the next change
@last_failed = true
end
end

Expand Down
44 changes: 32 additions & 12 deletions spec/guard/rspec_spec.rb
@@ -1,6 +1,7 @@
require 'spec_helper'

describe Guard::RSpec do
let(:default_options) { { :all_after_pass => true, :all_on_start => true, :keep_failed => true } }
subject { Guard::RSpec.new }

describe '#initialize' do
Expand All @@ -12,61 +13,80 @@

describe "#start" do
it "calls #run_all" do
Guard::RSpec::Runner.should_receive(:run).with(["spec"], :message => "Running all specs")
Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs"))
subject.start
end

it "doesn't call #run_all if the :all_on_start option is false" do
Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], :message => "Running all specs")
Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], default_options.merge(:all_on_start => false, :message => "Running all specs"))
subject = Guard::RSpec.new([], :all_on_start => false)
subject.start
end
end

describe "#run_all" do
it "runs all specs" do
Guard::RSpec::Runner.should_receive(:run).with(["spec"], :message => "Running all specs")
Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs"))
subject.run_all
end

it "directly passes :cli option to runner" do
subject = Guard::RSpec.new([], { :cli => "--color" })
Guard::RSpec::Runner.should_receive(:run).with(["spec"], :message => "Running all specs", :cli => "--color")
Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs", :cli => "--color"))
subject.run_all
end

it "should clean failed memory if passed" do
Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options).and_return(false)
subject.run_on_change(["spec/foo"])
Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs")).and_return(true)
subject.run_all
Guard::RSpec::Runner.should_receive(:run).with(["spec/bar"], default_options).and_return(true)
subject.run_on_change(["spec/bar"])
end
end

describe "#run_on_change" do
it "runs rspec with paths" do
Guard::RSpec::Runner.should_receive(:run).with(["spec"], {})
Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options)
subject.run_on_change(["spec"])
end

it "directly passes :cli option to runner" do
subject = Guard::RSpec.new([], { :cli => "--color" })
Guard::RSpec::Runner.should_receive(:run).with(["spec"], :cli => "--color")
Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:cli => "--color"))
subject.run_on_change(["spec"])
end

it "calls #run_all if the changed specs pass after failing" do
Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], {}).and_return(false, true)
Guard::RSpec::Runner.should_receive(:run).with(["spec"], :message => "Running all specs")
Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options).and_return(false, true)
Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs"))
subject.run_on_change(["spec/foo"])
subject.run_on_change(["spec/foo"])
end

it "doesn't call #run_all if the changed specs pass after failing but the :all_after_pass option is false" do
subject = Guard::RSpec.new([], :all_after_pass => false)
Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], {}).and_return(false, true)
Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], :message => "Running all specs")
Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options.merge(:all_after_pass => false)).and_return(false, true)
Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], default_options.merge(:all_after_pass => false, :message => "Running all specs"))
subject.run_on_change(["spec/foo"])
subject.run_on_change(["spec/foo"])
end

it "doesn't call #run_all if the changed specs pass without failing" do
Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], {}).and_return(true)
Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], :message => "Running all specs")
Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options).and_return(true)
Guard::RSpec::Runner.should_not_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs"))
subject.run_on_change(["spec/foo"])
end

it "should keep failed spec and rerun later" do
Guard::RSpec::Runner.should_receive(:run).with(["spec/foo"], default_options).and_return(false)
subject.run_on_change(["spec/foo"])
Guard::RSpec::Runner.should_receive(:run).with(["spec/bar", "spec/foo"], default_options).and_return(true)
Guard::RSpec::Runner.should_receive(:run).with(["spec"], default_options.merge(:message => "Running all specs")).and_return(true)
subject.run_on_change(["spec/bar"])
Guard::RSpec::Runner.should_receive(:run).with(["spec/bar"], default_options).and_return(true)
subject.run_on_change(["spec/bar"])
end
end

Expand Down

0 comments on commit d5cd494

Please sign in to comment.