end_state 0.12.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Gemfile +1 -0
- data/README.md +9 -11
- data/end_state.gemspec +1 -0
- data/lib/end_state/concluder.rb +0 -1
- data/lib/end_state/graph.rb +16 -12
- data/lib/end_state/no_graph.rb +12 -0
- data/lib/end_state/state_machine.rb +55 -140
- data/lib/end_state/state_machine_configuration.rb +77 -0
- data/lib/end_state/transition.rb +35 -49
- data/lib/end_state/transition_configuration.rb +49 -0
- data/lib/end_state/transition_configuration_set.rb +83 -0
- data/lib/end_state/version.rb +1 -1
- data/lib/end_state.rb +4 -1
- data/lib/end_state_matchers.rb +52 -39
- data/spec/end_state/concluder_spec.rb +9 -3
- data/spec/end_state/graph_spec.rb +35 -0
- data/spec/end_state/guard_spec.rb +29 -3
- data/spec/end_state/state_machine_configuration_spec.rb +183 -0
- data/spec/end_state/state_machine_spec.rb +8 -192
- data/spec/end_state/transition_configuration_set_spec.rb +217 -0
- data/spec/end_state/transition_configuration_spec.rb +65 -0
- data/spec/end_state/transition_spec.rb +83 -96
- data/spec/end_state_matchers_spec.rb +105 -0
- data/spec/spec_helper.rb +17 -0
- metadata +31 -8
- data/lib/end_state/state_mapping.rb +0 -25
- data/spec/end_state/state_mapping_spec.rb +0 -94
- data/spec/end_state_spec.rb +0 -4
@@ -0,0 +1,83 @@
|
|
1
|
+
module EndState
|
2
|
+
class TransitionConfigurationSet
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@end_state_map = { any_state: {} } # [start_state][event] = end_state
|
6
|
+
@configuration_map = { any_state: {} } # [start_state][end_state] = configuration
|
7
|
+
end
|
8
|
+
|
9
|
+
def add(start_state, end_state, configuration, event = nil)
|
10
|
+
if event
|
11
|
+
end_state_map[start_state] ||= {}
|
12
|
+
end_state_map[start_state][event] = end_state
|
13
|
+
end
|
14
|
+
|
15
|
+
configuration_map[start_state] ||= {}
|
16
|
+
configuration_map[start_state][end_state] = configuration
|
17
|
+
end
|
18
|
+
|
19
|
+
def get_configuration(start_state, end_state)
|
20
|
+
local_map = configuration_map[start_state] || {}
|
21
|
+
local_map[end_state] || configuration_map[:any_state][end_state]
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_end_state(start_state, event)
|
25
|
+
local_map = end_state_map[start_state] || {}
|
26
|
+
local_map[event] || end_state_map[:any_state][event]
|
27
|
+
end
|
28
|
+
|
29
|
+
def start_states
|
30
|
+
states = configuration_map.keys
|
31
|
+
states.delete(:any_state)
|
32
|
+
states += end_states unless configuration_map[:any_state].empty?
|
33
|
+
states.uniq
|
34
|
+
end
|
35
|
+
|
36
|
+
def end_states
|
37
|
+
configuration_map.map { |_, v| v.keys }.flatten.uniq
|
38
|
+
end
|
39
|
+
|
40
|
+
def events
|
41
|
+
end_state_map.map { |_, v| v.keys }.flatten.uniq
|
42
|
+
end
|
43
|
+
|
44
|
+
def event_conflicts?(start_state, event)
|
45
|
+
!!get_end_state(start_state, event) || (start_state == :any_state && events.include?(event))
|
46
|
+
end
|
47
|
+
|
48
|
+
def each &block
|
49
|
+
all_transitions.each(&block)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_reader :configuration_map, :end_state_map
|
55
|
+
|
56
|
+
def all_transitions
|
57
|
+
all_start_states = start_states
|
58
|
+
|
59
|
+
configuration_map.map do |start_state, local_config|
|
60
|
+
states = (start_state == :any_state) ? all_start_states : [start_state]
|
61
|
+
states.map { |s| transitions_for s, local_config }
|
62
|
+
end.flatten(2)
|
63
|
+
end
|
64
|
+
|
65
|
+
def transitions_for start_state, local_map
|
66
|
+
local_map.map do |end_state, config|
|
67
|
+
[start_state, end_state, config, event_for(start_state, end_state)]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def event_for start_state, end_state
|
72
|
+
(end_state_map[start_state] || {}).each do |k, v|
|
73
|
+
return k if v == end_state
|
74
|
+
end
|
75
|
+
|
76
|
+
end_state_map[:any_state].each do |k, v|
|
77
|
+
return k if v == end_state
|
78
|
+
end
|
79
|
+
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/end_state/version.rb
CHANGED
data/lib/end_state.rb
CHANGED
@@ -6,14 +6,17 @@ require 'end_state/guard'
|
|
6
6
|
require 'end_state/concluder'
|
7
7
|
require 'end_state/concluders'
|
8
8
|
require 'end_state/transition'
|
9
|
-
require 'end_state/
|
9
|
+
require 'end_state/transition_configuration'
|
10
|
+
require 'end_state/transition_configuration_set'
|
10
11
|
require 'end_state/action'
|
12
|
+
require 'end_state/state_machine_configuration'
|
11
13
|
require 'end_state/state_machine'
|
12
14
|
|
13
15
|
begin
|
14
16
|
require 'graphviz'
|
15
17
|
require 'end_state/graph'
|
16
18
|
rescue LoadError
|
19
|
+
require 'end_state/no_graph'
|
17
20
|
end
|
18
21
|
|
19
22
|
module EndState
|
data/lib/end_state_matchers.rb
CHANGED
@@ -4,14 +4,15 @@ module EndStateMatchers
|
|
4
4
|
end
|
5
5
|
|
6
6
|
class TransitionMatcher
|
7
|
-
attr_reader :
|
7
|
+
attr_reader :start_state, :end_state, :event, :machine, :failure_messages, :guards, :concluders, :required_params
|
8
8
|
|
9
9
|
def initialize(transition)
|
10
|
-
@
|
11
|
-
@
|
10
|
+
@start_state, @end_state = transition.first
|
11
|
+
@event = nil
|
12
12
|
@guards = []
|
13
13
|
@concluders = []
|
14
14
|
@required_params = []
|
15
|
+
@failure_messages = []
|
15
16
|
end
|
16
17
|
|
17
18
|
def matches?(actual)
|
@@ -24,11 +25,11 @@ module EndStateMatchers
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def description
|
27
|
-
"have transition
|
28
|
+
"have transition #{start_state} => #{end_state}"
|
28
29
|
end
|
29
30
|
|
30
|
-
def
|
31
|
-
@
|
31
|
+
def with_event(event)
|
32
|
+
@event = event
|
32
33
|
self
|
33
34
|
end
|
34
35
|
|
@@ -37,11 +38,6 @@ module EndStateMatchers
|
|
37
38
|
self
|
38
39
|
end
|
39
40
|
|
40
|
-
def with_concluder(concluder)
|
41
|
-
@concluders << concluder
|
42
|
-
self
|
43
|
-
end
|
44
|
-
|
45
41
|
def with_concluders(*concluders)
|
46
42
|
@concluders += Array(concluders).flatten
|
47
43
|
self
|
@@ -52,6 +48,10 @@ module EndStateMatchers
|
|
52
48
|
self
|
53
49
|
end
|
54
50
|
|
51
|
+
alias_method :with_guard, :with_guards
|
52
|
+
alias_method :with_concluder, :with_concluders
|
53
|
+
alias_method :with_required_param, :with_required_params
|
54
|
+
|
55
55
|
# Backward compatibility
|
56
56
|
# Finalizer is deprecated
|
57
57
|
alias_method :with_finalizer, :with_concluder
|
@@ -60,50 +60,63 @@ module EndStateMatchers
|
|
60
60
|
|
61
61
|
private
|
62
62
|
|
63
|
+
def transition_configuration
|
64
|
+
@tc = machine.transition_configurations.get_configuration(start_state, end_state)
|
65
|
+
end
|
66
|
+
|
67
|
+
def has_event?(event)
|
68
|
+
machine.transition_configurations.get_end_state(start_state, event) == end_state
|
69
|
+
end
|
70
|
+
|
71
|
+
def has_guard?(guard)
|
72
|
+
transition_configuration.guards.include?(guard)
|
73
|
+
end
|
74
|
+
|
75
|
+
def has_concluder?(concluder)
|
76
|
+
transition_configuration.concluders.include?(concluder)
|
77
|
+
end
|
78
|
+
|
79
|
+
def has_required_param?(param)
|
80
|
+
transition_configuration.required_params.include?(param)
|
81
|
+
end
|
82
|
+
|
83
|
+
def add_failure(suffix)
|
84
|
+
failure_messages << "expected transition #{start_state} => #{end_state} #{suffix}"
|
85
|
+
end
|
86
|
+
|
63
87
|
def verify
|
64
|
-
|
65
|
-
|
66
|
-
result = (result && verify_guards) if guards.any?
|
67
|
-
result = (result && verify_concluders) if concluders.any?
|
68
|
-
result = (result && verify_required_params) if required_params.any?
|
69
|
-
result
|
88
|
+
if transition_configuration.nil?
|
89
|
+
add_failure('to be defined')
|
70
90
|
else
|
71
|
-
|
72
|
-
|
91
|
+
verify_event if event
|
92
|
+
verify_guards
|
93
|
+
verify_concluders
|
94
|
+
verify_required_params
|
73
95
|
end
|
96
|
+
|
97
|
+
failure_messages.empty?
|
98
|
+
end
|
99
|
+
|
100
|
+
def verify_event
|
101
|
+
add_failure("to have event name: #{event}") unless has_event?(event)
|
74
102
|
end
|
75
103
|
|
76
104
|
def verify_guards
|
77
|
-
|
78
|
-
|
79
|
-
unless machine.transitions[transition].guards.any? { |g| g == guard }
|
80
|
-
failure_messages << "expected that transition :#{transition.keys.first} => :#{transition.values.first} would have guard #{guard.name}"
|
81
|
-
result = false
|
82
|
-
end
|
105
|
+
guards.map do |guard|
|
106
|
+
add_failure("to have guard #{guard.name}") unless has_guard?(guard)
|
83
107
|
end
|
84
|
-
result
|
85
108
|
end
|
86
109
|
|
87
110
|
def verify_concluders
|
88
|
-
|
89
|
-
|
90
|
-
unless machine.transitions[transition].concluders.any? { |f| f == concluder }
|
91
|
-
failure_messages << "expected that transition :#{transition.keys.first} => :#{transition.values.first} would have concluder #{concluder.name}"
|
92
|
-
result = false
|
93
|
-
end
|
111
|
+
concluders.map do |concluder|
|
112
|
+
add_failure("to have concluder #{concluder.name}") unless has_concluder?(concluder)
|
94
113
|
end
|
95
|
-
result
|
96
114
|
end
|
97
115
|
|
98
116
|
def verify_required_params
|
99
|
-
result = true
|
100
117
|
required_params.each do |param|
|
101
|
-
|
102
|
-
failure_messages << "expected that transition :#{transition.keys.first} => :#{transition.values.first} would have required param #{param}"
|
103
|
-
result = false
|
104
|
-
end
|
118
|
+
add_failure("to have required param #{param}") unless has_required_param?(param)
|
105
119
|
end
|
106
|
-
result
|
107
120
|
end
|
108
121
|
end
|
109
122
|
end
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
module EndState
|
4
4
|
describe Concluder do
|
5
5
|
subject(:concluder) { Concluder.new(object, state, params) }
|
6
|
-
let(:object) {
|
6
|
+
let(:object) { OpenStruct.new(failure_messages: [], success_messages: []) }
|
7
7
|
let(:state) { :a }
|
8
8
|
let(:params) { {} }
|
9
9
|
before do
|
@@ -20,8 +20,14 @@ module EndState
|
|
20
20
|
|
21
21
|
describe '#add_success' do
|
22
22
|
it 'adds an success' do
|
23
|
-
concluder.
|
24
|
-
expect(object.
|
23
|
+
concluder.add_success('success')
|
24
|
+
expect(object.success_messages).to eq ['success']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'call' do
|
29
|
+
it 'returns false' do
|
30
|
+
expect(concluder.call).to be false
|
25
31
|
end
|
26
32
|
end
|
27
33
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe EndState::Graph do
|
4
|
+
class TestMachine < EndState::StateMachine
|
5
|
+
transition a: :b
|
6
|
+
transition b: :c
|
7
|
+
transition c: :d, as: :go
|
8
|
+
transition any_state: :a
|
9
|
+
transition any_state: :e, as: :exit
|
10
|
+
end
|
11
|
+
|
12
|
+
subject(:graph) { EndState::Graph.new(TestMachine) }
|
13
|
+
|
14
|
+
describe '#draw' do
|
15
|
+
let(:description) { graph.draw.to_s }
|
16
|
+
|
17
|
+
it 'contains all the nodes' do
|
18
|
+
['a [label = "a"];', 'b [label = "b"];', 'c [label = "c"];', 'd [label = "d"];', 'e [label = "e"];'].each do |s|
|
19
|
+
expect(description).to include(s)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'contains all the edges without labels' do
|
24
|
+
['a -> b;', 'b -> c;', 'a -> a;', 'b -> a;', 'c -> a;', 'd -> a;', 'e -> a;'].each do |s|
|
25
|
+
expect(description).to include(s)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'contains all the edges with labels' do
|
30
|
+
['c -> d [label = "go"];', 'a -> e [label = "exit"];', 'b -> e [label = "exit"];', 'c -> e [label = "exit"];', 'd -> e [label = "exit"];', 'e -> e [label = "exit"];'].each do |s|
|
31
|
+
expect(description).to include(s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
module EndState
|
4
4
|
describe Guard do
|
5
5
|
subject(:guard) { Guard.new(object, state, params) }
|
6
|
-
let(:object) {
|
6
|
+
let(:object) { OpenStruct.new(failure_messages: [], success_messages: []) }
|
7
7
|
let(:state) { :a }
|
8
8
|
let(:params) { {} }
|
9
9
|
before do
|
@@ -20,8 +20,34 @@ module EndState
|
|
20
20
|
|
21
21
|
describe '#add_success' do
|
22
22
|
it 'adds an success' do
|
23
|
-
guard.
|
24
|
-
expect(object.
|
23
|
+
guard.add_success('success')
|
24
|
+
expect(object.success_messages).to eq ['success']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'will_allow?' do
|
29
|
+
it 'returns false' do
|
30
|
+
expect(guard.will_allow?).to be false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'allowed?' do
|
35
|
+
context 'will_allow? returns true' do
|
36
|
+
before { allow(guard).to receive(:will_allow?).and_return(true) }
|
37
|
+
|
38
|
+
it 'calls passed and returns true' do
|
39
|
+
expect(guard).to receive(:passed)
|
40
|
+
expect(guard.allowed?).to be true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'will_allow? returns false' do
|
45
|
+
before { allow(guard).to receive(:will_allow?).and_return(false) }
|
46
|
+
|
47
|
+
it 'calls failed and returns false' do
|
48
|
+
expect(guard).to receive(:failed)
|
49
|
+
expect(guard.allowed?).to be false
|
50
|
+
end
|
25
51
|
end
|
26
52
|
end
|
27
53
|
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
module EndState
|
5
|
+
describe StateMachineConfiguration do
|
6
|
+
subject(:machine) { StateMachine.new(object) }
|
7
|
+
let(:object) { OpenStruct.new(state: nil) }
|
8
|
+
before do
|
9
|
+
StateMachine.instance_variable_set '@transition_configurations'.to_sym, nil
|
10
|
+
StateMachine.instance_variable_set '@events'.to_sym, nil
|
11
|
+
StateMachine.instance_variable_set '@store_states_as_strings'.to_sym, nil
|
12
|
+
StateMachine.instance_variable_set '@initial_state'.to_sym, :__nil__
|
13
|
+
StateMachine.instance_variable_set '@mode'.to_sym, :soft
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '.transition' do
|
17
|
+
let(:options) { { a: :b } }
|
18
|
+
|
19
|
+
before do
|
20
|
+
@transition_configuration = nil
|
21
|
+
StateMachine.transition(options) { |tc| @transition_configuration = tc }
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'does not require a block' do
|
25
|
+
expect { StateMachine.transition(options) }.not_to raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'single transition' do
|
29
|
+
it 'yields a transition configuraton' do
|
30
|
+
expect(@transition_configuration).to be_a TransitionConfiguration
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with as' do
|
34
|
+
let(:options) { { a: :b, as: :go } }
|
35
|
+
|
36
|
+
it 'creates an alias' do
|
37
|
+
expect(StateMachine).to have_transition(a: :b).with_event(:go)
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'another single transition with as' do
|
41
|
+
before { StateMachine.transition({c: :d, as: :go}) }
|
42
|
+
|
43
|
+
it 'appends to the event' do
|
44
|
+
expect(StateMachine).to have_transition(a: :b).with_event(:go)
|
45
|
+
expect(StateMachine).to have_transition(c: :d).with_event(:go)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'another single transition with as that conflicts' do
|
50
|
+
it 'raises an error' do
|
51
|
+
expect{ StateMachine.transition({a: :c, as: :go}) }.to raise_error EventConflict,
|
52
|
+
"Attempting to define event 'go' on state 'a', but it is already defined. " \
|
53
|
+
"(Check duplicates and use of 'any_state')"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'another single transition with as that conflicts' do
|
58
|
+
it 'raises an error' do
|
59
|
+
expect{ StateMachine.transition({any_state: :c, as: :go}) }.to raise_error EventConflict,
|
60
|
+
"Attempting to define event 'go' on state 'any_state', but it is already defined. " \
|
61
|
+
"(Check duplicates and use of 'any_state')"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'multiple start states' do
|
68
|
+
let(:options) { { [:a, :b] => :c } }
|
69
|
+
|
70
|
+
it 'yields a transition configuraton' do
|
71
|
+
expect(@transition_configuration).to be_a TransitionConfiguration
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'has both transitions' do
|
75
|
+
expect(StateMachine).to have_transition(a: :c)
|
76
|
+
expect(StateMachine).to have_transition(b: :c)
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with as' do
|
80
|
+
let(:options) { { [:a, :b] => :c, as: :go } }
|
81
|
+
|
82
|
+
it 'creates an alias' do
|
83
|
+
expect(StateMachine).to have_transition(a: :c).with_event(:go)
|
84
|
+
expect(StateMachine).to have_transition(b: :c).with_event(:go)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'multiple transitions' do
|
90
|
+
let(:options) { { a: :b, c: :d } }
|
91
|
+
|
92
|
+
it 'yields a transition configuraton' do
|
93
|
+
expect(@transition_configuration).to be_a TransitionConfiguration
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'has both transitions' do
|
97
|
+
expect(StateMachine).to have_transition(a: :b)
|
98
|
+
expect(StateMachine).to have_transition(c: :d)
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with as' do
|
102
|
+
let(:options) { { a: :b, c: :d, as: :go } }
|
103
|
+
|
104
|
+
it 'creates an alias' do
|
105
|
+
expect(StateMachine).to have_transition(a: :b).with_event(:go)
|
106
|
+
expect(StateMachine).to have_transition(c: :d).with_event(:go)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '.state_attribute' do
|
113
|
+
context 'when set to :foobar' do
|
114
|
+
let(:object) { OpenStruct.new(foobar: :a) }
|
115
|
+
before { StateMachine.state_attribute :foobar }
|
116
|
+
|
117
|
+
it 'answers state with foobar' do
|
118
|
+
expect(machine.state).to eq object.foobar
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'answers state= with foobar=' do
|
122
|
+
machine.state = :b
|
123
|
+
expect(object.foobar).to eq :b
|
124
|
+
end
|
125
|
+
|
126
|
+
after do
|
127
|
+
StateMachine.send(:remove_method, :state)
|
128
|
+
StateMachine.send(:remove_method, :state=)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe '.states' do
|
134
|
+
before do
|
135
|
+
StateMachine.transition(a: :b)
|
136
|
+
StateMachine.transition(b: :c)
|
137
|
+
end
|
138
|
+
|
139
|
+
specify { expect(StateMachine.states).to eq [:a, :b, :c] }
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '.start_states' do
|
143
|
+
before do
|
144
|
+
StateMachine.transition(a: :b)
|
145
|
+
StateMachine.transition(b: :c)
|
146
|
+
end
|
147
|
+
|
148
|
+
specify { expect(StateMachine.start_states).to eq [:a, :b] }
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '.end_states' do
|
152
|
+
before do
|
153
|
+
StateMachine.transition(a: :b)
|
154
|
+
StateMachine.transition(b: :c)
|
155
|
+
end
|
156
|
+
|
157
|
+
specify { expect(StateMachine.end_states).to eq [:b, :c] }
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '.store_states_as_strings!' do
|
161
|
+
it 'sets the flag' do
|
162
|
+
StateMachine.store_states_as_strings!
|
163
|
+
expect(StateMachine.store_states_as_strings).to be true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
describe '.store_states_as_strings' do
|
168
|
+
it 'is false by default' do
|
169
|
+
expect(StateMachine.store_states_as_strings).to be false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe '.initial_state' do
|
174
|
+
context 'when set to :first' do
|
175
|
+
before { StateMachine.set_initial_state :first }
|
176
|
+
|
177
|
+
it 'has that initial state' do
|
178
|
+
expect(machine.state).to eq :first
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|