end_state 0.12.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,185 +6,13 @@ module EndState
6
6
  subject(:machine) { StateMachine.new(object) }
7
7
  let(:object) { OpenStruct.new(state: nil) }
8
8
  before do
9
- StateMachine.instance_variable_set '@transitions'.to_sym, nil
9
+ StateMachine.instance_variable_set '@transition_configurations'.to_sym, nil
10
10
  StateMachine.instance_variable_set '@events'.to_sym, nil
11
11
  StateMachine.instance_variable_set '@store_states_as_strings'.to_sym, nil
12
12
  StateMachine.instance_variable_set '@initial_state'.to_sym, :__nil__
13
13
  StateMachine.instance_variable_set '@mode'.to_sym, :soft
14
14
  end
15
15
 
16
- describe '.transition' do
17
- let(:options) { { a: :b } }
18
-
19
- before do
20
- @transitions = []
21
- StateMachine.transition(options) { |transition| @transitions << transition }
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 for the supplied end state' do
30
- expect(@transitions.count).to eq 1
31
- expect(@transitions[0].state).to eq :b
32
- end
33
-
34
- it 'adds the transition to the state machine' do
35
- expect(StateMachine.transitions[a: :b]).to eq @transitions[0]
36
- end
37
-
38
- context 'with as' do
39
- let(:options) { { a: :b, as: :go } }
40
-
41
- it 'creates an alias' do
42
- expect(StateMachine.events[:go]).to eq [{ a: :b }]
43
- end
44
-
45
- context 'another single transition with as' do
46
- before { StateMachine.transition({c: :d, as: :go}) }
47
-
48
- it 'appends to the event' do
49
- expect(StateMachine.events[:go]).to eq [{ a: :b }, { c: :d }]
50
- end
51
- end
52
-
53
- context 'another single transition with as that conflicts' do
54
- it 'raises an error' do
55
- expect{ StateMachine.transition({a: :c, as: :go}) }.to raise_error EventConflict,
56
- 'Attempting to define :go as transitioning from :a => :c when :a => :b already exists. ' \
57
- 'You cannot define multiple transitions from a single state with the same event name.'
58
- end
59
- end
60
-
61
- context 'another single transition with as that conflicts' do
62
- it 'raises an error' do
63
- expect{ StateMachine.transition({any_state: :c, as: :go}) }.to raise_error EventConflict,
64
- 'Attempting to define :go as transitioning from :any_state => :c when :a => :b already exists. ' \
65
- 'You cannot define multiple transitions from a single state with the same event name.'
66
- end
67
- end
68
- end
69
- end
70
-
71
- context 'multiple start states' do
72
- let(:options) { { [:a, :b] => :c } }
73
-
74
- it 'yields each transition for the supplied end state' do
75
- expect(@transitions.count).to eq 1
76
- expect(@transitions[0].state).to eq :c
77
- end
78
-
79
- it 'adds the transitions to the state machine' do
80
- expect(StateMachine.transitions[a: :c]).to eq @transitions[0]
81
- expect(StateMachine.transitions[b: :c]).to eq @transitions[0]
82
- end
83
-
84
- context 'with as' do
85
- let(:options) { { [:a, :b] => :c, as: :go } }
86
-
87
- it 'creates an alias' do
88
- expect(StateMachine.events[:go]).to eq [{ a: :c }, { b: :c }]
89
- end
90
- end
91
- end
92
-
93
- context 'multiple transitions' do
94
- let(:options) { { a: :b, c: :d } }
95
-
96
- it 'yields each transition for the supplied end state' do
97
- expect(@transitions.count).to eq 2
98
- expect(@transitions[0].state).to eq :b
99
- expect(@transitions[1].state).to eq :d
100
- end
101
-
102
- it 'adds the transitions to the state machine' do
103
- expect(StateMachine.transitions[a: :b]).to eq @transitions[0]
104
- expect(StateMachine.transitions[c: :d]).to eq @transitions[1]
105
- end
106
-
107
- context 'with as' do
108
- let(:options) { { a: :b, c: :d, as: :go } }
109
-
110
- it 'creates an alias' do
111
- expect(StateMachine.events[:go]).to eq [{ a: :b }, { c: :d }]
112
- end
113
- end
114
- end
115
- end
116
-
117
- describe '.state_attribute' do
118
- context 'when set to :foobar' do
119
- let(:object) { OpenStruct.new(foobar: :a) }
120
- before { StateMachine.state_attribute :foobar }
121
-
122
- it 'answers state with foobar' do
123
- expect(machine.state).to eq object.foobar
124
- end
125
-
126
- it 'answers state= with foobar=' do
127
- machine.state = :b
128
- expect(object.foobar).to eq :b
129
- end
130
-
131
- after do
132
- StateMachine.send(:remove_method, :state)
133
- StateMachine.send(:remove_method, :state=)
134
- end
135
- end
136
- end
137
-
138
- describe '.states' do
139
- before do
140
- StateMachine.transition(a: :b)
141
- StateMachine.transition(b: :c)
142
- end
143
-
144
- specify { expect(StateMachine.states).to eq [:a, :b, :c] }
145
- end
146
-
147
- describe '.start_states' do
148
- before do
149
- StateMachine.transition(a: :b)
150
- StateMachine.transition(b: :c)
151
- end
152
-
153
- specify { expect(StateMachine.start_states).to eq [:a, :b] }
154
- end
155
-
156
- describe '.end_states' do
157
- before do
158
- StateMachine.transition(a: :b)
159
- StateMachine.transition(b: :c)
160
- end
161
-
162
- specify { expect(StateMachine.end_states).to eq [:b, :c] }
163
- end
164
-
165
- describe '.store_states_as_strings!' do
166
- it 'sets the flag' do
167
- StateMachine.store_states_as_strings!
168
- expect(StateMachine.store_states_as_strings).to be true
169
- end
170
- end
171
-
172
- describe '#store_states_as_strings' do
173
- it 'is false by default' do
174
- expect(StateMachine.store_states_as_strings).to be false
175
- end
176
- end
177
-
178
- describe '.initial_state' do
179
- context 'when set to :first' do
180
- before { StateMachine.set_initial_state :first }
181
-
182
- it 'has that initial state' do
183
- expect(machine.state).to eq :first
184
- end
185
- end
186
- end
187
-
188
16
  describe '#state' do
189
17
  context 'when there is no state set' do
190
18
  specify { expect(machine.state).to eq :__nil__ }
@@ -251,9 +79,7 @@ module EndState
251
79
 
252
80
  context 'single transition' do
253
81
  before do
254
- StateMachine.transition a: :b, as: :go do |t|
255
- t.blocked 'Invalid event!'
256
- end
82
+ StateMachine.transition a: :b, as: :go
257
83
  end
258
84
 
259
85
  it 'transitions the state' do
@@ -281,11 +107,6 @@ module EndState
281
107
  expect(machine.state).to eq :c
282
108
  end
283
109
 
284
- it 'adds a failure message specified by blocked' do
285
- machine.go
286
- expect(machine.failure_messages).to eq ['Invalid event!']
287
- end
288
-
289
110
  context 'and all transitions are forced to run in :hard mode' do
290
111
  before { machine.class.treat_all_transitions_as_hard! }
291
112
 
@@ -309,9 +130,7 @@ module EndState
309
130
 
310
131
  context 'multiple start states' do
311
132
  before do
312
- StateMachine.transition [:a, :b] => :c, as: :go do |t|
313
- t.blocked 'Invalid event!'
314
- end
133
+ StateMachine.transition [:a, :b] => :c, as: :go
315
134
  end
316
135
 
317
136
  context 'initial state is :a' do
@@ -344,9 +163,7 @@ module EndState
344
163
 
345
164
  context 'multiple transitions' do
346
165
  before do
347
- StateMachine.transition a: :b, c: :d, as: :go do |t|
348
- t.blocked 'Invalid event!'
349
- end
166
+ StateMachine.transition a: :b, c: :d, as: :go
350
167
  end
351
168
 
352
169
  context 'initial state is :a' do
@@ -372,9 +189,7 @@ module EndState
372
189
  describe '#{event}!' do
373
190
  let(:object) { OpenStruct.new(state: :a) }
374
191
  before do
375
- StateMachine.transition a: :b, as: :go do |t|
376
- t.blocked 'Invalid event!'
377
- end
192
+ StateMachine.transition a: :b, as: :go
378
193
  end
379
194
 
380
195
  it 'transitions the state' do
@@ -612,8 +427,9 @@ module EndState
612
427
  let(:guard) { double :guard, new: guard_instance }
613
428
  let(:guard_instance) { double :guard_instance, allowed?: nil }
614
429
  before do
615
- StateMachine.transition a: :b
616
- StateMachine.transitions[{ a: :b }].guards << guard
430
+ StateMachine.transition a: :b do |t|
431
+ t.guard guard
432
+ end
617
433
  end
618
434
 
619
435
  context 'and the object satisfies the guard' do
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module EndState
5
+ describe TransitionConfigurationSet do
6
+ subject(:set) { TransitionConfigurationSet.new }
7
+ let(:config1) { double :config }
8
+ let(:config2) { double :config }
9
+ let(:config3) { double :config }
10
+ let(:config4) { double :config }
11
+
12
+ describe 'without any configurations added' do
13
+ context '#get_configuration' do
14
+ it 'returns nil' do
15
+ expect(set.get_configuration(:a, :b)).to be_nil
16
+ end
17
+ end
18
+
19
+ context '#get_end_state' do
20
+ it 'returns nil' do
21
+ expect(set.get_end_state(:a, :advance)).to be_nil
22
+ end
23
+ end
24
+
25
+ context '#each' do
26
+ it 'iterates over []' do
27
+ expect{ |b| set.each(&b) }.to_not yield_control
28
+ end
29
+ end
30
+
31
+ context '#start_states' do
32
+ it 'returns []' do
33
+ expect(set.start_states).to eql []
34
+ end
35
+ end
36
+
37
+ context '#end_states' do
38
+ it 'returns []' do
39
+ expect(set.end_states).to eql []
40
+ end
41
+ end
42
+
43
+ context '#events' do
44
+ it 'returns []' do
45
+ expect(set.events).to eql []
46
+ end
47
+ end
48
+ end
49
+
50
+ describe 'with direct transitions set' do
51
+ before do
52
+ set.add(:a, :b, config1)
53
+ set.add(:b, :c, config2, :advance)
54
+ set.add(:c, :a, config3, :reset)
55
+ end
56
+
57
+ context '#get_configuration' do
58
+ it 'returns nil if the configuration does not exist' do
59
+ expect(set.get_configuration(:b, :a)).to be_nil
60
+ expect(set.get_configuration(:c, :b)).to be_nil
61
+ end
62
+
63
+ it 'returns the configuration if it exists' do
64
+ expect(set.get_configuration(:a, :b)).to eql config1
65
+ expect(set.get_configuration(:b, :c)).to eql config2
66
+ expect(set.get_configuration(:c, :a)).to eql config3
67
+ end
68
+ end
69
+
70
+ context '#get_end_state' do
71
+ it 'returns nil if the configuration does not exist' do
72
+ expect(set.get_end_state(:b, :reset)).to be_nil
73
+ expect(set.get_end_state(:c, :advance)).to be_nil
74
+ end
75
+
76
+ it 'returns the configuration if it exists' do
77
+ expect(set.get_end_state(:b, :advance)).to eql :c
78
+ expect(set.get_end_state(:c, :reset)).to eql :a
79
+ end
80
+ end
81
+
82
+ context '#each' do
83
+ it 'iterates over all transitions' do
84
+ expect{ |b| set.each(&b) }.to yield_control.exactly(3)
85
+ expect(set.each).to match_array [
86
+ [:a, :b, config1, nil], [:b, :c, config2, :advance], [:c, :a, config3, :reset]
87
+ ]
88
+ end
89
+ end
90
+
91
+ context '#start_states' do
92
+ it 'returns all the start_states' do
93
+ expect(set.start_states).to match_array [:a, :b, :c]
94
+ end
95
+ end
96
+
97
+ context '#end_states' do
98
+ it 'returns all the end_states' do
99
+ expect(set.end_states).to match_array [:a, :b, :c]
100
+ end
101
+ end
102
+
103
+ context '#events' do
104
+ it 'returns all the events' do
105
+ expect(set.events).to match_array [:advance, :reset]
106
+ end
107
+ end
108
+
109
+ context "#event_conflicts?" do
110
+ it 'returns false if the event would not conflict with an existing event' do
111
+ expect(set.event_conflicts?(:a, :advance)).to eql false
112
+ expect(set.event_conflicts?(:b, :reset)).to eql false
113
+ expect(set.event_conflicts?(:c, :other)).to eql false
114
+ expect(set.event_conflicts?(:any_state, :other)).to eql false
115
+ end
116
+
117
+ it 'returns true if the event would conflict with an existing event' do
118
+ expect(set.event_conflicts?(:b, :advance)).to eql true
119
+ expect(set.event_conflicts?(:c, :reset)).to eql true
120
+ expect(set.event_conflicts?(:any_state, :advance)).to eql true
121
+ expect(set.event_conflicts?(:any_state, :reset)).to eql true
122
+ end
123
+ end
124
+ end
125
+
126
+ describe 'with direct and :any_state transitions set' do
127
+ before do
128
+ set.add(:a, :b, config1)
129
+ set.add(:b, :c, config2)
130
+ set.add(:any_state, :d, config3, :done)
131
+ set.add(:any_state, :e, config4)
132
+ end
133
+
134
+ context '#get_configuration' do
135
+ it 'returns nil if the configuration does not exist' do
136
+ expect(set.get_configuration(:d, :a)).to be_nil
137
+ expect(set.get_configuration(:d, :b)).to be_nil
138
+ end
139
+
140
+ it 'returns the configuration if it exists' do
141
+ expect(set.get_configuration(:a, :d)).to eql config3
142
+ expect(set.get_configuration(:b, :d)).to eql config3
143
+ expect(set.get_configuration(:c, :d)).to eql config3
144
+ expect(set.get_configuration(:d, :d)).to eql config3
145
+ expect(set.get_configuration(:e, :d)).to eql config3
146
+
147
+ expect(set.get_configuration(:a, :e)).to eql config4
148
+ expect(set.get_configuration(:b, :e)).to eql config4
149
+ expect(set.get_configuration(:c, :e)).to eql config4
150
+ expect(set.get_configuration(:d, :e)).to eql config4
151
+ expect(set.get_configuration(:e, :e)).to eql config4
152
+ end
153
+ end
154
+
155
+ context '#get_end_state' do
156
+ it 'returns nil if the end_state does not exist' do
157
+ expect(set.get_end_state(:a, :invalid)).to be_nil
158
+ expect(set.get_end_state(:e, :go)).to be_nil
159
+ end
160
+
161
+ it 'returns the end state if it exists' do
162
+ expect(set.get_end_state(:a, :done)).to eql :d
163
+ expect(set.get_end_state(:b, :done)).to eql :d
164
+ expect(set.get_end_state(:c, :done)).to eql :d
165
+ expect(set.get_end_state(:d, :done)).to eql :d
166
+ expect(set.get_end_state(:e, :done)).to eql :d
167
+ end
168
+ end
169
+
170
+ context '#each' do
171
+ it 'iterates over all transitions' do
172
+ expect{ |b| set.each(&b) }.to yield_control.exactly(12)
173
+ expect(set.each).to match_array [
174
+ [:a, :b, config1, nil], [:b, :c, config2, nil],
175
+ [:a, :d, config3, :done], [:b, :d, config3, :done], [:c, :d, config3, :done], [:d, :d, config3, :done], [:e, :d, config3, :done],
176
+ [:a, :e, config4, nil], [:b, :e, config4, nil], [:c, :e, config4, nil], [:d, :e, config4, nil], [:e, :e, config4, nil]
177
+ ]
178
+ end
179
+ end
180
+
181
+ context '#start_states' do
182
+ it 'returns all the start_states' do
183
+ expect(set.start_states).to match_array [:a, :b, :c, :d, :e]
184
+ end
185
+ end
186
+
187
+ context '#end_states' do
188
+ it 'returns all the end_states' do
189
+ expect(set.end_states).to match_array [:b, :c, :d, :e]
190
+ end
191
+ end
192
+
193
+ context '#events' do
194
+ it 'returns all the events' do
195
+ expect(set.events).to match_array [:done]
196
+ end
197
+ end
198
+
199
+ context "#event_conflicts?" do
200
+ it 'returns false if the event would not conflict with an existing event' do
201
+ expect(set.event_conflicts?(:a, :other)).to eql false
202
+ expect(set.event_conflicts?(:b, :other)).to eql false
203
+ expect(set.event_conflicts?(:c, :other)).to eql false
204
+ expect(set.event_conflicts?(:any_state, :other)).to eql false
205
+ end
206
+
207
+ it 'returns true if the event would conflict with an existing event' do
208
+ expect(set.event_conflicts?(:a, :done)).to eql true
209
+ expect(set.event_conflicts?(:b, :done)).to eql true
210
+ expect(set.event_conflicts?(:c, :done)).to eql true
211
+ expect(set.event_conflicts?(:d, :done)).to eql true
212
+ expect(set.event_conflicts?(:e, :done)).to eql true
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+ require 'ostruct'
3
+
4
+ module EndState
5
+ describe TransitionConfiguration do
6
+ subject(:config) { TransitionConfiguration.new }
7
+
8
+ describe '#custom_action' do
9
+ let(:custom) { double :custom }
10
+
11
+ it 'sets the action' do
12
+ config.custom_action custom
13
+ expect(config.action).to eq custom
14
+ end
15
+ end
16
+
17
+ describe '#guard' do
18
+ let(:guard) { double :guard }
19
+ let(:another_guard) { double :another_guard }
20
+
21
+ it 'adds a guard' do
22
+ expect { config.guard guard }.to change(config.guards, :count).by(1)
23
+ end
24
+
25
+ it 'adds multiple guards' do
26
+ expect { config.guard guard, another_guard }.to change(config.guards, :count).by(2)
27
+ end
28
+ end
29
+
30
+ describe '#concluder' do
31
+ let(:concluder) { double :concluder }
32
+ let(:another_concluder) { double :another_concluder }
33
+
34
+ it 'adds a concluder' do
35
+ expect { config.concluder concluder }.to change(config.concluders, :count).by(1)
36
+ end
37
+
38
+ it 'adds multiple concluders' do
39
+ expect { config.concluder concluder, another_concluder }.to change(config.concluders, :count).by(2)
40
+ end
41
+ end
42
+
43
+ describe '#persistence_on' do
44
+ it 'adds a Persistence concluder' do
45
+ expect { config.persistence_on }.to change(config.concluders, :count).by(1)
46
+ end
47
+ end
48
+
49
+ describe '#allow_params' do
50
+ it 'adds supplied keys to the allowed_params array' do
51
+ expect { config.allow_params :foo, :bar }.to change(config.allowed_params, :count).by(2)
52
+ end
53
+ end
54
+
55
+ describe '#require_params' do
56
+ it 'adds supplied keys to the required_params array' do
57
+ expect { config.require_params :foo, :bar }.to change(config.required_params, :count).by(2)
58
+ end
59
+
60
+ it 'adds supplied keys to the allowed_params array' do
61
+ expect { config.allow_params :foo, :bar }.to change(config.allowed_params, :count).by(2)
62
+ end
63
+ end
64
+ end
65
+ end