spec/rspec/mocks/space_spec.rb in rspec-mocks-3.0.0.beta1 vs spec/rspec/mocks/space_spec.rb in rspec-mocks-3.0.0.beta2

- old
+ new

@@ -1,33 +1,244 @@ require 'spec_helper' module RSpec::Mocks describe Space do + let(:space) { Space.new } + let(:dbl_1) { Object.new } + let(:dbl_2) { Object.new } - describe "#proxies_of(klass)" do - let(:space) { Space.new } + describe "#verify_all" do + it "verifies all mocks within" do + verifies = [] + space.proxy_for(dbl_1).stub(:verify) { verifies << :dbl_1 } + space.proxy_for(dbl_2).stub(:verify) { verifies << :dbl_2 } + + space.verify_all + + expect(verifies).to match_array([:dbl_1, :dbl_2]) + end + + def define_singleton_method_on_recorder_for(klass, name, &block) + recorder = space.any_instance_recorder_for(klass) + (class << recorder; self; end).send(:define_method, name, &block) + end + + it 'verifies all any_instance recorders within' do + klass_1, klass_2 = Class.new, Class.new + + verifies = [] + + # We can't `stub` a method on the recorder because it defines its own `stub`... + define_singleton_method_on_recorder_for(klass_1, :verify) { verifies << :klass_1 } + define_singleton_method_on_recorder_for(klass_2, :verify) { verifies << :klass_2 } + + space.verify_all + + expect(verifies).to match_array([:klass_1, :klass_2]) + end + end + + describe "#reset_all" do + it "resets all mocks within" do + resets = [] + + space.proxy_for(dbl_1).stub(:reset) { resets << :dbl_1 } + space.proxy_for(dbl_2).stub(:reset) { resets << :dbl_2 } + + space.reset_all + + expect(resets).to match_array([:dbl_1, :dbl_2]) + end + end + + describe "#proxies_of(klass)" do it 'returns proxies' do space.proxy_for("") - expect(space.proxies_of(String).map(&:class)).to eq([PartialMockProxy]) + expect(space.proxies_of(String).map(&:class)).to eq([PartialDoubleProxy]) end - it 'returns only the proxies whose object is an instance of the given class' do + def create_generations grandparent_class = Class.new parent_class = Class.new(grandparent_class) child_class = Class.new(parent_class) grandparent = grandparent_class.new parent = parent_class.new child = child_class.new + return grandparent, parent, child + end + + it 'returns only the proxies whose object is an instance of the given class' do + grandparent, parent, child = create_generations + space.proxy_for(grandparent) - parent_proxy = space.proxy_for(parent) - child_proxy = space.proxy_for(child) + parent_proxy = space.proxy_for(parent) + child_proxy = space.proxy_for(child) - expect(space.proxies_of(parent_class)).to match_array([parent_proxy, child_proxy]) + expect(space.proxies_of(parent.class)).to contain_exactly(parent_proxy, child_proxy) end + + it 'looks in the parent space for matching proxies' do + _, parent, child = create_generations + + parent_proxy = space.proxy_for(parent) + subspace = space.new_scope + child_proxy = subspace.proxy_for(child) + + expect(subspace.proxies_of(parent.class)).to contain_exactly(parent_proxy, child_proxy) + end end + it 'tracks proxies in parent and child space separately' do + proxy1 = space.proxy_for(Object.new) + subspace = space.new_scope + proxy2 = subspace.proxy_for(Object.new) + + expect(space.proxies.values).to include(proxy1) + expect(space.proxies.values).not_to include(proxy2) + + expect(subspace.proxies.values).to include(proxy2) + expect(subspace.proxies.values).not_to include(proxy1) + end + + it "only adds an instance once" do + m1 = double("mock1") + + expect { + space.ensure_registered(m1) + }.to change { space.proxies } + + expect { + space.ensure_registered(m1) + }.not_to change { space.proxies } + end + + [:ensure_registered, :proxy_for].each do |method| + describe "##{method}" do + define_method :get_proxy do |space, object| + space.__send__(method, object) + end + + it 'returns the proxy for the given object' do + obj1 = Object.new + obj2 = Object.new + + expect(get_proxy(space, obj1)).to equal(get_proxy(space, obj1)) + expect(get_proxy(space, obj2)).to equal(get_proxy(space, obj2)) + expect(get_proxy(space, obj1)).not_to equal(get_proxy(space, obj2)) + end + + it 'can stil return a proxy from a parent context' do + proxy = get_proxy(space, Object) + subspace = space.new_scope + + expect(get_proxy(subspace, Object)).to equal(proxy) + end + + it "does not store a parent's proxy in the child space" do + get_proxy(space, Object) + subspace = space.new_scope + + expect { + get_proxy(subspace, Object) + }.not_to change { subspace.proxies }.from({}) + end + end + end + + describe "#registered?" do + it 'returns true if registered in this space' do + space.ensure_registered(Object) + expect(space).to be_registered(Object) + end + + it 'returns true if registered in a parent space' do + space.ensure_registered(Object) + expect(space.new_scope).to be_registered(Object) + end + + it 'returns false if not registered in this or a parent space' do + expect(space.new_scope).not_to be_registered(Object) + end + end + + describe "#constant_mutator_for" do + it 'returns the mutator for the given const name' do + space = RSpec::Mocks.space + stub_const("Foo", 3) + stub_const("Bar", 4) + + expect(space.constant_mutator_for("Foo")).to equal(space.constant_mutator_for("Foo")) + expect(space.constant_mutator_for("Bar")).to equal(space.constant_mutator_for("Bar")) + expect(space.constant_mutator_for("Foo")).not_to equal(space.constant_mutator_for("Bar")) + end + + it 'can stil return a mutator from a parent context' do + space = RSpec::Mocks.space + + stub_const("Foo", 3) + mutator = space.constant_mutator_for("Foo") + + in_new_space_scope do + subspace = RSpec::Mocks.space + expect(subspace.constant_mutator_for("Foo")).to equal(mutator) + end + end + end + + describe "#any_instance_recorder_for" do + it 'returns the recorder for the given class' do + expect(space.any_instance_recorder_for(String)).to equal(space.any_instance_recorder_for(String)) + expect(space.any_instance_recorder_for(Symbol)).to equal(space.any_instance_recorder_for(Symbol)) + expect(space.any_instance_recorder_for(String)).not_to equal(space.any_instance_recorder_for(Symbol)) + end + + it 'can stil return a recorder from a parent context' do + recorder = space.any_instance_recorder_for(String) + subspace = space.new_scope + + expect(subspace.any_instance_recorder_for(String)).to equal(recorder) + end + + it "does not store a parent's proxy in the child space" do + space.any_instance_recorder_for(String) + subspace = space.new_scope + + expect { + subspace.any_instance_recorder_for(String) + }.not_to change { subspace.any_instance_recorders }.from({}) + end + end + + it 'can be diffed in a failure when it has references to an error generator via a proxy' do + space1 = Space.new + space2 = Space.new + + space1.proxy_for("") + space2.proxy_for("") + + expect { + expect(space1).to eq(space2) + }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /Diff/) + end + + it 'removes an any_instance_recorder when requested' do + klass = Class.new + + space.any_instance_recorder_for(klass) + + expect { + space.remove_any_instance_recorder_for(klass) + }.to change { space.any_instance_recorders.size }.by(-1) + end + + def in_new_space_scope + RSpec::Mocks.setup + yield + ensure + RSpec::Mocks.teardown + end end end