require "spec_helper" describe InfoparkComponentCache::ComponentCache do subject(:component_cache) { described_class.new(obj, name, params, [guard]) } let(:obj) { double(name: "spec_obj", id: 2001) } let(:name) { "spec_cached_component" } let(:params) { { some: "additional", params: "supplied" } } let(:guard) { Class.new(Struct.new(:component)) } context "with caching disabled" do before { allow(Rails.application.config.action_controller).to receive(:perform_caching).and_return(false) } describe "#fetch" do let(:value) { "very_hard_computation_required_for_this_string" } let(:specific_guard) { component_cache.guards.first } it "returns the passed the block value" do expect(component_cache.fetch { value }).to eq(value) end it "never calls any methods on the guard" do expect(specific_guard).not_to receive(:consistent?) expect(specific_guard).not_to receive(:guard!) component_cache.fetch { value } end end end context "with caching enabled" do before { allow(Rails.application.config.action_controller).to receive(:perform_caching).and_return(true) } let(:guard) do Class.new(InfoparkComponentCache::ConsistencyGuard) do def consistent? cache.exist?(:guard_called) end def guard! cache.write(:guard_called, 1) end end end describe "#fetch" do let(:value) { "very_hard_computation_required_for_this_string" } let(:specific_guard) { component_cache.guards.first } let(:computer) { double } it "returns the passed the block value" do expect(component_cache.fetch { value }).to eq(value) end it "calls the required methods on the guard" do expect(specific_guard).to receive(:consistent?).exactly(3).times expect(specific_guard).to receive(:guard!).exactly(3).times 3.times { component_cache.fetch { value } } end it "only evalues the block once" do expect(computer).to receive(:compute).and_return(value).once 3.times { expect(component_cache.fetch { computer.compute }).to eq(value) } end end end describe "#compontent" do subject(:component_cache) { described_class.new(obj, name, params).component } it "stores the passed obj" do expect(component_cache.obj).to eq(obj) end it "stores the passed name" do expect(component_cache.name).to eq(name) end it "stores the passed params" do expect(component_cache.params).to eq(params) end end describe "#guards" do subject(:component_cache) { described_class.new(obj, name, params, [guard_class1, guard_params]).guards } let(:guard_class1) { Struct.new(:component) } let(:guard_class2) { Struct.new(:compontent, :extra) } let(:guard_params) { { guard: guard_class2, something: "more" } } it "contains an array of passed guards" do expect(component_cache).to match_array([ an_instance_of(guard_class1), an_instance_of(guard_class2) ]) end it "preserves the extra params" do expect(component_cache.last.extra).to eq(guard_params) end context "with no guards specified in the constructors" do subject(:component_cache) { described_class.new(obj, name, params).guards } it "contains standard guards" do expect(component_cache).to match_array([ an_instance_of(InfoparkComponentCache::Guards::ValuePresent), an_instance_of(InfoparkComponentCache::Guards::LastChanged), an_instance_of(InfoparkComponentCache::Guards::ObjCount), an_instance_of(InfoparkComponentCache::Guards::ValidFrom), an_instance_of(InfoparkComponentCache::Guards::ValidUntil) ]) end end end end