require 'spec_helper' describe InfoparkComponentCache::ComponentCache do 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)) } subject { described_class.new(obj, name, params, [guard]) } 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) { subject.guards.first } it 'returns the passed the block value' do expect(subject.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!) subject.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) { Class.new(InfoparkComponentCache::ConsistencyGuard) { def consistent? cache.exist?(:guard_called) end def guard! cache.write(:guard_called, 1) end } } describe '#fetch' do let(:value) { 'very_hard_computation_required_for_this_string' } let(:specific_guard) { subject.guards.first } let(:computer) { double } it 'returns the passed the block value' do expect(subject.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 { subject.fetch { value } } end it 'only evalues the block once' do expect(computer).to receive(:compute).and_return(value).once 3.times { expect(subject.fetch { computer.compute }).to eq(value) } end end end describe '#compontent' do subject { described_class.new(obj, name, params).component } it 'stores the passed obj' do expect(subject.obj).to eq(obj) end it 'stores the passed name' do expect(subject.name).to eq(name) end it 'stores the passed params' do expect(subject.params).to eq(params) end end describe '#guards' do let(:guard_class1) { Struct.new(:component) } let(:guard_class2) { Struct.new(:compontent, :extra) } let(:guard_params) { {guard: guard_class2, something: 'more'} } subject { described_class.new(obj, name, params, [guard_class1, guard_params]).guards } it 'contains an array of passed guards' do expect(subject).to match_array([ an_instance_of(guard_class1), an_instance_of(guard_class2) ]) end it 'preserves the extra params' do expect(subject.last.extra).to eq(guard_params) end context 'with no guards specified in the constructors' do subject { described_class.new(obj, name, params).guards } it 'contains standard guards' do expect(subject).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