class Pushdown::SpecHelpers::StateTransitionMatcher

RSpec matcher for matching transitions of Pushdown::States

Constants

DEFAULT_CALLBACK

Attributes

additional_expectations[R]
callback[R]
expected_type[R]
failure_description[R]
result[R]
state[R]
target_state[R]

Public Class Methods

new() click to toggle source

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

failure_message() click to toggle source

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
failure_message_when_negated() click to toggle source

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
matches?( state ) click to toggle source

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
on_an_event( event ) click to toggle source

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
Also aliased as: on_event
on_event( event )
Alias for: on_an_event
on_update() click to toggle source

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
to( state_name )
Alias for: to_state
to_state( state_name ) click to toggle source

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
Also aliased as: to
via( transition_type )
Alias for: via_transition_type
via_transition_type( transition_type ) click to toggle source

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
Also aliased as: via

Protected Instance Methods

correct_target_state?() click to toggle source

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
correct_transition_type?() click to toggle source

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
describe_additional_expectations() click to toggle source

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
describe_failure() click to toggle source

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
describe_negated_failure() click to toggle source

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
matches_additional_expectations?() click to toggle source

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
update_ran_without_error?() click to toggle source

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
update_returned_transition?() click to toggle source

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