Add SetSessionOrFlashMatcher

This commit is contained in:
Elliot Winkler 2014-11-19 11:47:33 -07:00
parent 55c8d09bf2
commit cc2772324a
3 changed files with 666 additions and 0 deletions

View File

@ -10,6 +10,7 @@ require 'shoulda/matchers/action_controller/render_template_matcher'
require 'shoulda/matchers/action_controller/rescue_from_matcher'
require 'shoulda/matchers/action_controller/callback_matcher'
require 'shoulda/matchers/action_controller/strong_parameters_matcher'
require 'shoulda/matchers/action_controller/set_session_or_flash_matcher'
module Shoulda
module Matchers

View File

@ -0,0 +1,103 @@
module Shoulda
module Matchers
module ActionController
# @private
class SetSessionOrFlashMatcher
def initialize(store)
@store = store
end
def in_context(context)
@context = context
self
end
def [](key)
@key = key
self
end
def to(expected_value = nil, &block)
if block
unless context_set?
message = "When specifying a value as a block, a context must be specified beforehand, e.g., #{store.name}.in_context(context).to { ... }"
raise ArgumentError, message
end
@expected_value = context.instance_eval(&block)
else
@expected_value = expected_value
end
self
end
def description
"should #{expectation_description}"
end
def matches?(controller)
@controller = store.controller = controller
!store.empty? && key_matches? && expected_value_matches?
end
def failure_message
"Expected #{controller.class} to #{expectation_description}, but it did not"
end
alias_method :failure_message_for_should, :failure_message
def failure_message_when_negated
"Expected #{controller.class} not to #{expectation_description}, but it did"
end
alias_method :failure_message_for_should_not,
:failure_message_when_negated
protected
attr_reader :store, :context, :key, :expected_value, :controller
private
def context_set?
defined?(@context)
end
def key_set?
defined?(@key)
end
def expected_value_set?
defined?(@expected_value)
end
def key_matches?
!key_set? || store.has_key?(key)
end
def expected_value_matches?
!expected_value_set? || store.has_value?(expected_value)
end
def expectation_description
string = 'set'
if key_set?
string << " #{store.name}[#{key.inspect}]"
else
string << " any #{store.name} key"
end
if expected_value_set?
if expected_value.is_a?(Regexp)
string << " to a value matching #{expected_value.inspect}"
else
string << " to #{expected_value.inspect}"
end
end
string
end
end
end
end
end

View File

@ -0,0 +1,562 @@
require 'unit_spec_helper'
describe Shoulda::Matchers::ActionController::SetSessionOrFlashMatcher do
context 'without any qualifiers' do
it 'produces the right description' do
store = build_store(name: 'flash')
matcher = described_class.new(store)
expected_description = 'should set any key in flash'
expect(matcher.description).to eq expected_description
end
context 'in the positive' do
context 'if the store is not empty' do
it 'accepts' do
controller = define_class('MyController').new
store = build_store(empty?: false)
matcher = described_class.new(store)
expect(controller).to matcher
end
end
context 'if the store is empty' do
it 'rejects' do
controller = define_class('MyController').new
store = build_store(empty?: true)
matcher = described_class.new(store)
expect(controller).not_to matcher
end
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash', empty?: true)
matcher = described_class.new(store)
expected_message = 'Expected MyController to set any key in flash, but it did not'
expect { expect(controller).to matcher }.
to fail_with_message(expected_message)
end
end
end
context 'in the negative' do
context 'if the given key is present in the store' do
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash', empty?: false)
matcher = described_class.new(store)
expected_message = 'Expected MyController not to set any key in flash, but it did'
expect { expect(controller).not_to matcher }.
to fail_with_message(expected_message)
end
end
end
end
context 'with #[]' do
it 'produces the right description' do
store = build_store(name: 'flash')
matcher = described_class.new(store)['the key']
expected_description = 'should set flash["the key"]'
expect(matcher.description).to eq expected_description
end
context 'in the positive' do
context 'if the given key is present in the store' do
it 'accepts' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_key?).
with('the key').
and_return(true)
matcher = described_class.new(store)['the key']
expect(controller).to matcher
end
end
context 'if the given key is not present in the store' do
it 'rejects' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_key?).
with('the key').
and_return(false)
matcher = described_class.new(store)['the key']
expect(controller).not_to matcher
end
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_key?).
with('the key').
and_return(false)
matcher = described_class.new(store)['the key']
expected_message = 'Expected MyController to set flash["the key"], but it did not'
expect { expect(controller).to matcher }.
to fail_with_message(expected_message)
end
end
end
context 'in the negative' do
context 'if the given key is present in the store' do
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_key?).
with('the key').
and_return(true)
matcher = described_class.new(store)['the key']
expected_message = 'Expected MyController not to set flash["the key"], but it did'
expect { expect(controller).not_to matcher }.
to fail_with_message(expected_message)
end
end
end
end
context 'with #to' do
context 'given a static value' do
it 'produces the right description' do
store = build_store(name: 'flash')
matcher = described_class.new(store).to('the value')
expected_description = 'should set any key in flash to "the value"'
expect(matcher.description).to eq expected_description
end
context 'in the positive' do
context 'if the given value is present in the store' do
it 'accepts' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_value?).
with('the value').
and_return(true)
matcher = described_class.new(store).to('the value')
expect(controller).to matcher
end
it 'accepts given a value of nil' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_value?).
with(nil).
and_return(true)
matcher = described_class.new(store).to(nil)
expect(controller).to matcher
end
it 'accepts given a value of false' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_value?).
with(false).
and_return(true)
matcher = described_class.new(store).to(false)
expect(controller).to matcher
end
end
context 'if the given value is not present in the store' do
it 'rejects' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_value?).
with('the value').
and_return(false)
matcher = described_class.new(store).to('the value')
expect(controller).not_to matcher
end
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_value?).
with('the value').
and_return(false)
matcher = described_class.new(store).to('the value')
expected_message = 'Expected MyController to set any key in flash to "the value", but it did not'
expect { expect(controller).to matcher }.
to fail_with_message(expected_message)
end
end
end
context 'in the negative' do
context 'if the given value is present in the store' do
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_value?).
with('the value').
and_return(true)
matcher = described_class.new(store).to('the value')
expected_message = 'Expected MyController not to set any key in flash to "the value", but it did'
expect { expect(controller).not_to matcher }.
to fail_with_message(expected_message)
end
end
end
end
context 'given a regexp' do
it 'produces the right description' do
store = build_store(name: 'flash')
matcher = described_class.new(store).to(/the value/)
expected_description = 'should set any key in flash to a value matching /the value/'
expect(matcher.description).to eq expected_description
end
context 'in the positive' do
context 'if the given value is present in the store' do
it 'accepts' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_value?).
with(/the value/).
and_return(true)
matcher = described_class.new(store).to(/the value/)
expect(controller).to matcher
end
end
context 'if the given value is not present in the store' do
it 'rejects' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_value?).
with(/the value/).
and_return(false)
matcher = described_class.new(store).to(/the value/)
expect(controller).not_to matcher
end
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_value?).
with(/the value/).
and_return(false)
matcher = described_class.new(store).to(/the value/)
expected_message = 'Expected MyController to set any key in flash to a value matching /the value/, but it did not'
expect { expect(controller).to matcher }.
to fail_with_message(expected_message)
end
end
end
context 'in the negative' do
context 'if the given value is present in the store' do
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_value?).
with(/the value/).
and_return(true)
matcher = described_class.new(store).to(/the value/)
expected_message = 'Expected MyController not to set any key in flash to a value matching /the value/, but it did'
expect { expect(controller).not_to matcher }.
to fail_with_message(expected_message)
end
end
end
end
context 'given a dynamic value' do
it 'produces the right description' do
store = build_store(name: 'flash')
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store).
in_context(context).
to { method_in_context }
expected_description = 'should set any key in flash to "the value"'
expect(matcher.description).to eq expected_description
end
it 'requires in_context to be specified beforehand' do
store = build_store(name: 'flash')
matcher = described_class.new(store)
expected_message = 'When specifying a value as a block, a context must be specified beforehand, e.g., flash.in_context(context).to { ... }'
expect { matcher.to { whatever } }.
to raise_error(ArgumentError, expected_message)
end
context 'in the positive' do
context 'if the value evaluated in the context is present in the store' do
it 'accepts' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_value?).
with('the value').
and_return(true)
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store).
in_context(context).
to { method_in_context }
expect(controller).to matcher
end
end
context 'if the value evaluated in the context is not present in the store' do
it 'rejects' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_value?).
with('the value').
and_return(false)
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store).
in_context(context).
to { method_in_context }
expect(controller).not_to matcher
end
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_value?).
with('the value').
and_return(false)
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store).
in_context(context).
to { method_in_context }
expected_message = 'Expected MyController to set any key in flash to "the value", but it did not'
expect { expect(controller).to matcher }.
to fail_with_message(expected_message)
end
end
end
context 'in the negative' do
context 'if the value evaluated in the context is present in the store' do
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_value?).
with('the value').
and_return(true)
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store).
in_context(context).
to { method_in_context }
expected_message = 'Expected MyController not to set any key in flash to "the value", but it did'
expect { expect(controller).not_to matcher }.
to fail_with_message(expected_message)
end
end
end
end
end
context 'with #[] + #to' do
context 'given a static value' do
it 'produces the right description' do
store = build_store(name: 'flash')
matcher = described_class.new(store)['the key'].to('the value')
expected_description = 'should set flash["the key"] to "the value"'
expect(matcher.description).to eq expected_description
end
context 'in the positive' do
context 'if the given value is present in the store' do
it 'accepts' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_key?).
with('the key').
and_return(true)
allow(store).to receive(:has_value?).
with('the value').
and_return(true)
matcher = described_class.new(store)['the key'].to('the value')
expect(controller).to matcher
end
end
context 'if the given value is not present in the store' do
it 'rejects' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_key?).
with('the key').
and_return(true)
allow(store).to receive(:has_value?).
with('the value').
and_return(false)
matcher = described_class.new(store)['the key'].to('the value')
expect(controller).not_to matcher
end
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_key?).
with('the key').
and_return(true)
allow(store).to receive(:has_value?).
with('the value').
and_return(false)
matcher = described_class.new(store)['the key'].to('the value')
expected_message = 'Expected MyController to set flash["the key"] to "the value", but it did not'
expect { expect(controller).to matcher }.
to fail_with_message(expected_message)
end
end
end
context 'in the negative' do
context 'if the given value is present in the store' do
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_key?).
with('the key').
and_return(true)
allow(store).to receive(:has_value?).
with('the value').
and_return(true)
matcher = described_class.new(store)['the key'].to('the value')
expected_message = 'Expected MyController not to set flash["the key"] to "the value", but it did'
expect { expect(controller).not_to matcher }.
to fail_with_message(expected_message)
end
end
end
end
context 'given a dynamic value' do
it 'produces the right description' do
store = build_store(name: 'flash')
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store)['the key'].
in_context(context).
to { method_in_context }
expected_description = 'should set flash["the key"] to "the value"'
expect(matcher.description).to eq expected_description
end
context 'in the positive' do
context 'if the value evaluated in the context is present in the store' do
it 'accepts' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_key?).
with('the key').
and_return(true)
allow(store).to receive(:has_value?).
with('the value').
and_return(true)
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store)['the key'].
in_context(context).
to { method_in_context }
expect(controller).to matcher
end
end
context 'if the value evaluated in the context is not present in the store' do
it 'rejects' do
controller = define_class('MyController').new
store = build_store
allow(store).to receive(:has_key?).
with('the key').
and_return(false)
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store)['the key'].
in_context(context).
to { method_in_context }
expect(controller).not_to matcher
end
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_key?).
with('the key').
and_return(false)
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store)['the key'].
in_context(context).
to { method_in_context }
expected_message = 'Expected MyController to set flash["the key"] to "the value", but it did not'
expect { expect(controller).to matcher }.
to fail_with_message(expected_message)
end
end
end
context 'in the negative' do
context 'if the value evaluated in the context is present in the store' do
it 'produces the correct failure message' do
controller = define_class('MyController').new
store = build_store(name: 'flash')
allow(store).to receive(:has_key?).
with('the key').
and_return(true)
allow(store).to receive(:has_value?).
with('the value').
and_return(true)
context = double('context', method_in_context: 'the value')
matcher = described_class.new(store)['the key'].
in_context(context).
to { method_in_context }
expected_message = 'Expected MyController not to set flash["the key"] to "the value", but it did'
expect { expect(controller).not_to matcher }.
to fail_with_message(expected_message)
end
end
end
end
end
def build_store(overrides = {})
defaults = {
:name => 'store',
:controller= => nil,
:has_key? => nil,
:has_value? => nil,
:empty? => nil,
}
methods = defaults.merge(overrides)
double('store', methods)
end
end