diff --git a/spec/spec_specs/runnable_spec.rb b/spec/spec_specs/runnable_spec.rb new file mode 100644 index 000000000..fd2e48888 --- /dev/null +++ b/spec/spec_specs/runnable_spec.rb @@ -0,0 +1,95 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe PuppetTest::RunnableTest do + before do + @runnable_test = Class.new.extend(PuppetTest::RunnableTest) + end + + describe "#confine" do + subject { @runnable_test } + + it "should accept a hash" do + subject.confine({}).should_not raise_error(ArgumentError) + end + + it "should accept a message and a block" do + subject.confine(""){}.should_not raise_error(ArgumentError) + end + + end + + describe "#runnable?" do + describe "when the superclass is not runnable" do + before { @runnable_test.stubs(:superclass).returns(stub("unrunnable superclass", :runnable? => false)) } + subject { @runnable_test.runnable? } + + it { should be_false } + end + + describe "when a confine is false" do + before { @runnable_test.confine(:message => false) } + subject { @runnable_test.runnable? } + + it { should be_false } + end + + describe "when a confine has a block that returns false" do + before { @runnable_test.confine(:message){ false } } + subject { @runnable_test.runnable? } + + it { should be_false } + end + + describe "when a confine is true and no false confines" do + before { @runnable_test.confine(:message => true) } + subject { @runnable_test.runnable? } + + it { should be_true } + end + + describe "when a confine has block that returns true and no false confines" do + before { @runnable_test.confine(:message){ true } } + subject { @runnable_test.runnable? } + + it { should be_true } + end + + end + + describe "#messages" do + describe "before runnable? is called" do + subject { @runnable_test.messages } + + it { should == [] } + end + + describe "when runnable? is called and returns false" do + before do + @runnable_test.confine(:message => false) + @runnable_test.runnable? + end + + subject { @runnable_test.messages } + + it "should include the failed confine's message" do + should include(:message) + end + + end + + describe "when runnable? is called whose block returns false" do + before do + @runnable_test.confine(:message){ false } + @runnable_test.runnable? + end + + subject { @runnable_test.messages } + + it "should include the failed confine's message" do + should include(:message) + end + + end + + end +end diff --git a/test/lib/puppettest/runnable_test.rb b/test/lib/puppettest/runnable_test.rb index 977dba47a..6fcd9c6dc 100644 --- a/test/lib/puppettest/runnable_test.rb +++ b/test/lib/puppettest/runnable_test.rb @@ -1,35 +1,45 @@ # Manage whether a test is runnable. module PuppetTest module RunnableTest - # Confine this test based on specified criteria. The keys of the - # hash should be the message to use if the test is not suitable, - # and the values should be either 'true' or 'false'; true values - # mean the test is suitable. - def confine(hash) - @confines ||= {} - hash.each do |message, result| - @confines[message] = result - end + # Confine this example group based on specified criteria. This can be + # a message and its related test either as a hash or as a single + # message argument and a block to be evaluated at the time the confine + # is checked. + # + # Examples: + # + # confine "Rails is not available" => Puppet.features.rails? + # + # confine("ActiveRecord 2.1.x") { ::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1 } + # + def confine(hash_or_message, &block) + hash = block_given? ? {hash_or_message => block} : hash_or_message + confines.update hash end - attr_reader :messages - - # Evaluate all of our tests to see if any of them are false - # and thus whether this test is considered not runnable. + # Check all confines for a given example group, starting with any + # specified in the parent example group. If any confine test is false, + # the example group is not runnable (and will be skipped). Note: This + # is used directly by Rspec and is not intended for develper use. + # def runnable? - @messages ||= [] - if superclass.respond_to?(:runnable?) and ! superclass.runnable? + if superclass.respond_to?(:runnable?) and not superclass.runnable? return false end - return false unless @messages.empty? - return true unless defined? @confines - @confines.find_all do |message, result| - ! result - end.each do |message, result| - @messages << message + + confines.each do |message, is_runnable| + is_runnable = is_runnable.call if is_runnable.respond_to?(:call) + messages << message unless is_runnable end - return @messages.empty? + messages.empty? end + + def messages; @messages ||= [] end + + private + + def confines; @confines ||= {} end end + end