require 'spec_helper' module RSpec::Core describe Subject do before(:each) { RSpec.configuration.configure_expectation_framework } describe "implicit subject" do describe "with a class" do it "returns an instance of the class" do ExampleGroup.describe(Array).subject.call.should eq([]) end end describe "with a Module" do it "returns the Module" do ExampleGroup.describe(Enumerable).subject.call.should eq(Enumerable) end end describe "with a string" do it "return the string" do ExampleGroup.describe("Foo").subject.call.should eq("Foo") end end describe "with a number" do it "returns the number" do ExampleGroup.describe(15).subject.call.should eq(15) end end end describe "explicit subject" do [false, nil].each do |falsy_value| context "with a value of #{falsy_value.inspect}" do it "is evaluated once per example" do group = ExampleGroup.describe(Array) group.before do Object.should_receive(:this_question?).once.and_return(falsy_value) end group.subject do Object.this_question? end group.example do subject subject end group.run.should be_true, "expected subject block to be evaluated only once" end end end describe "defined in a top level group" do it "replaces the implicit subject in that group" do group = ExampleGroup.describe(Array) group.subject { [1,2,3] } group.subject.call.should eq([1,2,3]) end end describe "defined in a top level group" do let(:group) do ExampleGroup.describe do subject{ [4,5,6] } end end it "is available in a nested group (subclass)" do nested_group = group.describe("I'm nested!") { } nested_group.subject.call.should eq([4,5,6]) end it "is available in a doubly nested group (subclass)" do nested_group = group.describe("Nesting level 1") { } doubly_nested_group = nested_group.describe("Nesting level 2") { } doubly_nested_group.subject.call.should eq([4,5,6]) end end end context "using 'self' as an explicit subject" do it "delegates matcher to the ExampleGroup" do group = ExampleGroup.describe("group") do subject { self } def ok?; true; end def not_ok?; false; end it { should eq(self) } it { should be_ok } it { should_not be_not_ok } end group.run.should be_true end end describe "#its" do subject do Class.new do def initialize @call_count = 0 end def call_count @call_count += 1 end end.new end context "with a call counter" do its(:call_count) { should eq(1) } end context "with nil value" do subject do Class.new do def nil_value nil end end.new end its(:nil_value) { should be_nil } end context "with nested attributes" do subject do Class.new do def name "John" end end.new end its("name") { should eq("John") } its("name.size") { should eq(4) } its("name.size.class") { should eq(Fixnum) } end context "when it responds to #[]" do subject do Class.new do def [](*objects) objects.map do |object| "#{object.class}: #{object.to_s}" end.join("; ") end def name "George" end end.new end its([:a]) { should eq("Symbol: a") } its(['a']) { should eq("String: a") } its([:b, 'c', 4]) { should eq("Symbol: b; String: c; Fixnum: 4") } its(:name) { should eq("George") } context "when referring to an attribute without the proper array syntax" do context "it raises an error" do its(:age) do expect do should eq(64) end.to raise_error(NoMethodError) end end end end context "when it does not respond to #[]" do subject { Object.new } context "it raises an error" do its([:a]) do expect do should eq("Symbol: a") end.to raise_error(NoMethodError) end end end context "calling and overriding super" do it "calls to the subject defined in the parent group" do group = ExampleGroup.describe(Array) do subject { [1, 'a'] } its(:last) { should eq("a") } describe '.first' do def subject; super().first; end its(:next) { should eq(2) } end end group.run.should be_true end end context "with nil subject" do subject do Class.new do def initialize @counter = -1 end def nil_if_first_time @counter += 1 @counter == 0 ? nil : true end end.new end its(:nil_if_first_time) { should be(nil) } end context "with false subject" do subject do Class.new do def initialize @counter = -1 end def false_if_first_time @counter += 1 @counter > 0 end end.new end its(:false_if_first_time) { should be(false) } end end end end