class Pushdown::SpecHelpers::StateTransitionMatcher
RSpec matcher for matching transitions of Pushdown::States
Constants
- DEFAULT_CALLBACK
Attributes
Public Class Methods
Create a new matcher that expects a transition to occur.
# File lib/pushdown/spec_helpers.rb, line 25 def initialize @expected_type = nil @target_state = nil @callback = nil @additional_expectations = [] @state = nil @result = nil @failure_description = nil end
Public Instance Methods
RSpec matcher API – return a message describing an expectation failure.
# File lib/pushdown/spec_helpers.rb, line 59 def failure_message return "%p: %s" % [ self.state, self.describe_failure ] end
RSpec matcher API – return a message describing an expectation being met when the matcher was used in a negated context.
# File lib/pushdown/spec_helpers.rb, line 66 def failure_message_when_negated return "%p: %s" % [ self.state, self.describe_negated_failure ] end
RSpec matcher API – returns true
if all expectations are met after calling update on the specified state
.
# File lib/pushdown/spec_helpers.rb, line 47 def matches?( state ) @state = state return self.update_ran_without_error? && self.update_returned_transition? && self.correct_transition_type? && self.correct_target_state? && self.matches_additional_expectations? end
Specify that the operation that should cause the transition is the on_event
callback.
# File lib/pushdown/spec_helpers.rb, line 105 def on_an_event( event ) raise ScriptError, "can't specify more than one callback" if self.callback @callback = [ :on_event, event ] return self end
Specify that the operation that should cause the transition is the update callback. This is the default.
# File lib/pushdown/spec_helpers.rb, line 97 def on_update raise ScriptError, "can't specify more than one callback" if self.callback @callback = [ :update ] return self end
Add an additional expectation that the state that is transitioned to be of the given state_name
. This only applies to transitions that take a target state type. Expecting a particular state_name in transitions which do not take a state is undefined behavior.
# File lib/pushdown/spec_helpers.rb, line 88 def to_state( state_name ) @target_state = state_name return self end
Add an additional expectation that the transition that occurs be of the specified transition_type
.
# File lib/pushdown/spec_helpers.rb, line 77 def via_transition_type( transition_type ) @expected_type = transition_type return self end
Protected Instance Methods
Returns true
if a target state was specified and the transition which occurred was to that state.
# File lib/pushdown/spec_helpers.rb, line 164 def correct_target_state? state_name = self.target_state or return true case self.result when Pushdown::Transition return self.result.respond_to?( :state_class ) && self.result.state_class.type_name == state_name when Symbol self.state.class.transitions[ self.result ][ 1 ] == state_name end end
Returns true
if a transition type was specified and the transition which occurred was of that type.
# File lib/pushdown/spec_helpers.rb, line 148 def correct_transition_type? type = self.expected_type or return true case self.result when Pushdown::Transition self.result.type_name == type when Symbol self.state.class.transitions[ self.result ].first == type else raise "unexpected transition result type %p" % [ self.result ] end end
Return an Array of descriptions of the members that were expected to be included in the state body, if any were specified. If none were specified, returns an empty Array.
# File lib/pushdown/spec_helpers.rb, line 233 def describe_additional_expectations return self.additional_expectations.map( &:description ) end
Build an appropriate failure messages for the matcher.
# File lib/pushdown/spec_helpers.rb, line 178 def describe_failure desc = String.new( "expected to transition" ) desc << " via %s" % [ self.expected_type ] if self.expected_type desc << " to %s" % [ self.target_state ] if self.target_state if self.callback methname, arg = self.callback desc << " when #%s is called" % [ methname ] desc << " with %p" % [ arg ] if arg end desc << ', but ' case self.result when Exception err = self.result desc << "got %p: %s" % [ err.class, err.message ] when Symbol transition = self.state.class.transitions[ self.result ] if transition desc << "it returned a %s transition " % [ transition.first ] desc << "to %s " % [ transition[1] ] if transition[1] desc << " instead" else desc << "it returned an unmapped Symbol (%p)" % [ self.result ] end when Pushdown::Transition desc << "it returned a %s transition" % [ self.result.type_name ] desc << " to %s" % [ self.result.state_class.type_name ] if self.result.respond_to?( :state_class ) desc << " instead" else desc << "it did not (returned: %p)" % [ self.result ] end return desc end
Build an appropriate failure message for the matcher.
# File lib/pushdown/spec_helpers.rb, line 219 def describe_negated_failure desc = String.new( "expected not to transition" ) desc << " via %s" % [ self.expected_type ] if self.expected_type desc << " to %s" % [ self.target_state ] if self.target_state desc << ', but it did.' return desc end
Check that any additional matchers registered via the `.and` mutator also match the parsed state body.
# File lib/pushdown/spec_helpers.rb, line 240 def matches_additional_expectations? return self.additional_expectations.all? do |matcher| matcher.matches?( self.parsed_state_body ) or fail_with( matcher.failure_message ) end end
Call the state's update callback and record the result, then return true
if no exception was raised.
# File lib/pushdown/spec_helpers.rb, line 119 def update_ran_without_error? operation = self.callback || DEFAULT_CALLBACK @result = begin self.state.public_send( *operation ) rescue => err err end return !@result.is_a?( Exception ) end
Returns true
if the result of calling update was a Transition
or a Symbol that corresponds with a valid transition.
# File lib/pushdown/spec_helpers.rb, line 134 def update_returned_transition? case self.result when Pushdown::Transition return true when Symbol return self.state.class.transitions.include?( self.result ) else return false end end