spec/runner/context_spec.rb in mspec-1.3.1 vs spec/runner/context_spec.rb in mspec-1.4.0

- old
+ new

@@ -3,99 +3,343 @@ require 'mspec/matchers/base' require 'mspec/runner/mspec' require 'mspec/mocks/mock' require 'mspec/runner/context' -describe ContextState do +describe ContextState, "#describe" do before :each do - @state = ContextState.new + @state = ContextState.new "C#m" + @proc = lambda { ScratchPad.record :a } + ScratchPad.clear + end + + it "evaluates the passed block" do + @state.describe(&@proc) + ScratchPad.recorded.should == :a + end + + it "evaluates the passed block via #protect" do + @state.should_receive(:protect).with("C#m", @proc, false) + @state.describe(&@proc) + end + + it "registers #parent as the current MSpec ContextState" do + parent = ContextState.new "" + @state.parent = parent + MSpec.should_receive(:register_current).with(parent) + @state.describe { } + end + + it "registers self with MSpec when #shared? is true" do + state = ContextState.new "something shared", :shared => true + MSpec.should_receive(:register_shared).with(state) + state.describe { } + end +end + +describe ContextState, "#shared?" do + it "returns false when the ContextState is not shared" do + ContextState.new("").shared?.should be_false + end + + it "returns true when the ContextState is shared" do + ContextState.new("", {:shared => true}).shared?.should be_true + end +end + +describe ContextState, "#to_s" do + it "returns a description string for self when passed a Module" do + ContextState.new(Object).to_s.should == "Object" + end + + it "returns a description string for self when passed a String" do + ContextState.new("SomeClass").to_s.should == "SomeClass" + end + + it "returns a description string for self when passed a Module, String" do + ContextState.new(Object, "when empty").to_s.should == "Object when empty" + end + + it "returns a description string for self when passed a Module and String beginning with '#'" do + ContextState.new(Object, "#to_s").to_s.should == "Object#to_s" + end + + it "returns a description string for self when passed a Module and String beginning with '.'" do + ContextState.new(Object, ".to_s").to_s.should == "Object.to_s" + end + + it "returns a description string for self when passed a Module and String beginning with '::'" do + ContextState.new(Object, "::to_s").to_s.should == "Object::to_s" + end +end + +describe ContextState, "#description" do + before :each do + @state = ContextState.new "when empty" + @parent = ContextState.new "Toplevel" + end + + it "returns a composite description string from self and all parents" do + @parent.description.should == "Toplevel" + @state.description.should == "when empty" + @state.parent = @parent + @state.description.should == "Toplevel when empty" + end +end + +describe ContextState, "#it" do + before :each do + @state = ContextState.new "" @proc = lambda { } end - it "records before(:all) blocks" do - @state.before(:all, &@proc) - @state.instance_variable_get(:@start).should == [@proc] + it "creates an ExampleState instance for the block" do + ex = ExampleState.new("", "", &@proc) + ExampleState.should_receive(:new).with(@state, "it", @proc).and_return(ex) + @state.describe(&@proc) + @state.it("it", &@proc) end +end - it "records before(:each) blocks" do +describe ContextState, "#examples" do + before :each do + @state = ContextState.new "" + end + + it "returns a list of all examples in this ContextState" do + @state.it("first") { } + @state.it("second") { } + @state.examples.size.should == 2 + end +end + +describe ContextState, "#before" do + before :each do + @state = ContextState.new "" + @proc = lambda { } + end + + it "records the block for :each" do @state.before(:each, &@proc) - @state.instance_variable_get(:@before).should == [@proc] + @state.before(:each).should == [@proc] end - it "records after(:all) blocks" do - @state.after(:all, &@proc) - @state.instance_variable_get(:@finish).should == [@proc] + it "records the block for :all" do + @state.before(:all, &@proc) + @state.before(:all).should == [@proc] end +end - it "records after(:each) blocks" do +describe ContextState, "#after" do + before :each do + @state = ContextState.new "" + @proc = lambda { } + end + + it "records the block for :each" do @state.after(:each, &@proc) - @state.instance_variable_get(:@after).should == [@proc] + @state.after(:each).should == [@proc] end - it "records it blocks" do - @state.it("message", &@proc) - msg, proc = @state.instance_variable_get(:@spec)[0] - msg.should == "message" - proc.should == @proc + it "records the block for :all" do + @state.after(:all, &@proc) + @state.after(:all).should == [@proc] end +end - it "records describe blocks" do - @state.describe(Object, "message", &@proc) - @state.instance_variable_get(:@describe).should == "Object message" - @state.instance_variable_get(:@block).should == @proc +describe ContextState, "#pre" do + before :each do + @a = lambda { } + @b = lambda { } + @c = lambda { } + + parent = ContextState.new "" + parent.before(:each, &@c) + parent.before(:all, &@c) + + @state = ContextState.new "" + @state.parent = parent end + + it "returns before(:each) actions in the order they were defined" do + @state.before(:each, &@a) + @state.before(:each, &@b) + @state.pre(:each).should == [@c, @a, @b] + end + + it "returns before(:all) actions in the order they were defined" do + @state.before(:all, &@a) + @state.before(:all, &@b) + @state.pre(:all).should == [@c, @a, @b] + end end +describe ContextState, "#post" do + before :each do + @a = lambda { } + @b = lambda { } + @c = lambda { } + + parent = ContextState.new "" + parent.after(:each, &@c) + parent.after(:all, &@c) + + @state = ContextState.new "" + @state.parent = parent + end + + it "returns after(:each) actions in the reverse order they were defined" do + @state.after(:each, &@a) + @state.after(:each, &@b) + @state.post(:each).should == [@b, @a, @c] + end + + it "returns after(:all) actions in the reverse order they were defined" do + @state.after(:all, &@a) + @state.after(:all, &@b) + @state.post(:all).should == [@b, @a, @c] + end +end + describe ContextState, "#protect" do before :each do ScratchPad.record [] @a = lambda { ScratchPad << :a } @b = lambda { ScratchPad << :b } @c = lambda { raise Exception, "Fail!" } end it "returns true and does execute any blocks if check is true and MSpec.pretend_mode? is true" do MSpec.stub!(:pretend_mode?).and_return(true) - ContextState.new.protect("message", [@a, @b]).should be_true + ContextState.new("").protect("message", [@a, @b]).should be_true ScratchPad.recorded.should == [] end it "executes the blocks if MSpec.pretend_mode? is false" do MSpec.stub!(:pretend_mode?).and_return(false) - ContextState.new.protect("message", [@a, @b]) + ContextState.new("").protect("message", [@a, @b]) ScratchPad.recorded.should == [:a, :b] end it "executes the blocks if check is false" do - ContextState.new.protect("message", [@a, @b], false) + ContextState.new("").protect("message", [@a, @b], false) ScratchPad.recorded.should == [:a, :b] end it "returns true if none of the blocks raise an exception" do - ContextState.new.protect("message", [@a, @b]).should be_true + ContextState.new("").protect("message", [@a, @b]).should be_true end it "returns false if any of the blocks raise an exception" do - ContextState.new.protect("message", [@a, @c, @b]).should be_false + ContextState.new("").protect("message", [@a, @c, @b]).should be_false end end +describe ContextState, "#parent=" do + before :each do + @state = ContextState.new "" + @parent = mock("describe") + @parent.stub!(:parent).and_return(nil) + @parent.stub!(:child) + end + + it "does not set self as a child of parent if shared" do + @parent.should_not_receive(:child) + state = ContextState.new "", :shared => true + state.parent = @parent + end + + it "sets self as a child of parent" do + @parent.should_receive(:child).with(@state) + @state.parent = @parent + end + + it "creates the list of parents" do + @state.parent = @parent + @state.parents.should == [@parent, @state] + end +end + +describe ContextState, "#parent" do + before :each do + @state = ContextState.new "" + @parent = mock("describe") + @parent.stub!(:parent).and_return(nil) + @parent.stub!(:child) + end + + it "returns nil if parent has not been set" do + @state.parent.should be_nil + end + + it "returns the parent" do + @state.parent = @parent + @state.parent.should == @parent + end +end + +describe ContextState, "#parents" do + before :each do + @first = ContextState.new "" + @second = ContextState.new "" + @parent = mock("describe") + @parent.stub!(:parent).and_return(nil) + @parent.stub!(:child) + end + + it "returns a list of all enclosing ContextState instances" do + @first.parent = @parent + @second.parent = @first + @second.parents.should == [@parent, @first, @second] + end +end + +describe ContextState, "#child" do + before :each do + @first = ContextState.new "" + @second = ContextState.new "" + @parent = mock("describe") + @parent.stub!(:parent).and_return(nil) + @parent.stub!(:child) + end + + it "adds the ContextState to the list of contained ContextStates" do + @first.child @second + @first.children.should == [@second] + end +end + +describe ContextState, "#children" do + before :each do + @parent = ContextState.new "" + @first = ContextState.new "" + @second = ContextState.new "" + end + + it "returns the list of directly contained ContextStates" do + @first.parent = @parent + @second.parent = @first + @parent.children.should == [@first] + @first.children.should == [@second] + end +end + describe ContextState, "#state" do before :each do MSpec.store :before, [] MSpec.store :after, [] - @state = ContextState.new + @state = ContextState.new "" end it "returns nil if no spec is being executed" do @state.state.should == nil end it "returns a ExampleState instance if an example is being executed" do ScratchPad.record @state - @state.describe("") { } + @state.describe { } @state.it("") { ScratchPad.record ScratchPad.recorded.state } @state.process @state.state.should == nil ScratchPad.recorded.should be_kind_of(ExampleState) end @@ -103,13 +347,14 @@ describe ContextState, "#process" do before :each do MSpec.store :before, [] MSpec.store :after, [] + MSpec.stub!(:register_current) - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } @a = lambda { ScratchPad << :a } @b = lambda { ScratchPad << :b } ScratchPad.record [] end @@ -125,20 +370,28 @@ it "calls each after(:all) block" do @state.after(:all, &@a) @state.after(:all, &@b) @state.it("") { } @state.process - ScratchPad.recorded.should == [:a, :b] + ScratchPad.recorded.should == [:b, :a] end it "calls each it block" do @state.it("one", &@a) @state.it("two", &@b) @state.process ScratchPad.recorded.should == [:a, :b] end + it "does not call the #it block if #filtered? returns true" do + @state.it("one", &@a) + @state.it("two", &@b) + @state.examples.first.stub!(:filtered?).and_return(true) + @state.process + ScratchPad.recorded.should == [:b] + end + it "calls each before(:each) block" do @state.before(:each, &@a) @state.before(:each, &@b) @state.it("") { } @state.process @@ -148,11 +401,11 @@ it "calls each after(:each) block" do @state.after(:each, &@a) @state.after(:each, &@b) @state.it("") { } @state.process - ScratchPad.recorded.should == [:a, :b] + ScratchPad.recorded.should == [:b, :a] end it "calls Mock.cleanup for each it block" do @state.it("") { } @state.it("") { } @@ -167,18 +420,18 @@ @state.process end it "calls the describe block" do ScratchPad.record [] - @state.describe(Object, "msg") { ScratchPad << :a } + @state.describe { ScratchPad << :a } @state.process ScratchPad.recorded.should == [:a] end it "creates a new ExampleState instance for each example" do ScratchPad.record @state - @state.describe("desc") { } + @state.describe { } @state.it("it") { ScratchPad.record ScratchPad.recorded.state } @state.process ScratchPad.recorded.should be_kind_of(ExampleState) end @@ -195,18 +448,49 @@ MSpec.should_receive(:shuffle) @state.it("") { } @state.process MSpec.randomize false end + + it "sets the current MSpec ContextState" do + MSpec.should_receive(:register_current).with(@state) + @state.process + end + + it "resets the current MSpec ContextState to nil when there are examples" do + MSpec.should_receive(:register_current).with(nil) + @state.it("") { } + @state.process + end + + it "resets the current MSpec ContextState to nil when there are no examples" do + MSpec.should_receive(:register_current).with(nil) + @state.process + end + + it "call #process on children when there are examples" do + child = ContextState.new "" + child.should_receive(:process) + @state.child child + @state.it("") { } + @state.process + end + + it "call #process on children when there are no examples" do + child = ContextState.new "" + child.should_receive(:process) + @state.child child + @state.process + end end describe ContextState, "#process" do before :each do MSpec.store :exception, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } action = mock("action") def action.exception(exc) ScratchPad.record :exception if exc.exception.is_a? ExpectationNotFoundError end @@ -241,12 +525,12 @@ describe ContextState, "#process" do before :each do MSpec.store :example, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } example = mock("example") def example.example(state, spec) ScratchPad << state << spec end @@ -277,12 +561,12 @@ describe ContextState, "#process" do before :each do MSpec.store :before, [] MSpec.store :after, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } @state.it("") { MSpec.expectation } end after :each do MSpec.store :before, nil @@ -313,30 +597,27 @@ @spec_state.should be_kind_of(ExampleState) end end describe ContextState, "#process" do -end - -describe ContextState, "#process" do before :each do MSpec.store :enter, [] MSpec.store :leave, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "C#m" + @state.describe { } @state.it("") { MSpec.expectation } end after :each do MSpec.store :enter, nil MSpec.store :leave, nil end it "calls registered enter actions with the current #describe string" do enter = mock("enter") - enter.should_receive(:enter).and_return { ScratchPad.record :enter } + enter.should_receive(:enter).with("C#m").and_return { ScratchPad.record :enter } MSpec.register :enter, enter @state.process ScratchPad.recorded.should == :enter end @@ -352,12 +633,12 @@ describe ContextState, "#process when an exception is raised in before(:all)" do before :each do MSpec.store :before, [] MSpec.store :after, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } @a = lambda { ScratchPad << :a } @b = lambda { ScratchPad << :b } ScratchPad.record [] @@ -412,12 +693,12 @@ describe ContextState, "#process when an exception is raised in before(:each)" do before :each do MSpec.store :before, [] MSpec.store :after, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } @a = lambda { ScratchPad << :a } @b = lambda { ScratchPad << :b } ScratchPad.record [] @@ -461,12 +742,12 @@ before :each do ScratchPad.clear MSpec.store :before, [] MSpec.store :after, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } @state.it("") { } end after :each do MSpec.store :before, nil @@ -509,21 +790,21 @@ before :each do MSpec.store :before, [] MSpec.store :after, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } @a = lambda { ScratchPad << :a } @b = lambda { ScratchPad << :b } ScratchPad.record [] end it "calls the describe block" do ScratchPad.record [] - @state.describe(Object, "msg") { ScratchPad << :a } + @state.describe { ScratchPad << :a } @state.process ScratchPad.recorded.should == [:a] end it "does not call any before(:all) block" do @@ -584,12 +865,12 @@ before :each do MSpec.store :enter, [] MSpec.store :leave, [] - @state = ContextState.new - @state.describe("") { } + @state = ContextState.new "" + @state.describe { } @state.it("") { } end after :each do MSpec.store :enter, nil @@ -608,7 +889,91 @@ leave = mock("leave") leave.should_receive(:leave).and_return { ScratchPad.record :leave } MSpec.register :leave, leave @state.process ScratchPad.recorded.should == :leave + end +end + +describe ContextState, "#it_should_behave_like" do + before :each do + @shared = ContextState.new("", :shared => true) + MSpec.stub!(:retrieve_shared).and_return(@shared) + + @state = ContextState.new "" + @a = lambda { } + @b = lambda { } + end + + it "raises an Exception if unable to find the shared ContextState" do + MSpec.should_receive(:retrieve_shared).and_return(nil) + lambda { @state.it_should_behave_like "this" }.should raise_error(Exception) + end + + it "adds examples from the shared ContextState" do + @shared.it "some", &@a + @shared.it "thing", &@b + @state.it_should_behave_like "" + @state.examples.should include(*@shared.examples) + end + + it "sets the containing ContextState for the examples" do + @shared.it "some", &@a + @shared.it "thing", &@b + @shared.examples.each { |ex| ex.should_receive(:context=).with(@state) } + @state.it_should_behave_like "" + end + + it "adds before(:all) blocks from the shared ContextState" do + @shared.before :all, &@a + @shared.before :all, &@b + @state.it_should_behave_like "" + @state.before(:all).should include(*@shared.before(:all)) + end + + it "adds before(:each) blocks from the shared ContextState" do + @shared.before :each, &@a + @shared.before :each, &@b + @state.it_should_behave_like "" + @state.before(:each).should include(*@shared.before(:each)) + end + + it "adds after(:each) blocks from the shared ContextState" do + @shared.after :each, &@a + @shared.after :each, &@b + @state.it_should_behave_like "" + @state.after(:each).should include(*@shared.after(:each)) + end + + it "adds after(:all) blocks from the shared ContextState" do + @shared.after :all, &@a + @shared.after :all, &@b + @state.it_should_behave_like "" + @state.after(:all).should include(*@shared.after(:all)) + end +end + +describe ContextState, "#filter_examples" do + before :each do + @state = ContextState.new "" + @state.it("one") { } + @state.it("two") { } + end + + it "removes examples that are filtered" do + @state.examples.first.stub!(:filtered?).and_return(true) + @state.examples.size.should == 2 + @state.filter_examples + @state.examples.size.should == 1 + end + + it "returns true if there are remaining examples to evaluate" do + @state.examples.first.stub!(:filtered?).and_return(true) + @state.filter_examples.should be_true + end + + it "returns false if there are no remaining examples to evaluate" do + @state.examples.first.stub!(:filtered?).and_return(true) + @state.examples.last.stub!(:filtered?).and_return(true) + @state.filter_examples.should be_false end end