stateful.rb 2.0.0 → 2.2.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/CHANGELOG.md +137 -0
- data/Gemfile +2 -0
- data/README.md +309 -0
- data/lib/Stateful/Sequel/ClassMethods.rb +117 -0
- data/lib/Stateful/Sequel.rb +30 -0
- data/lib/Stateful/VERSION.rb +1 -1
- data/lib/Stateful.rb +4 -1
- data/stateful.rb.gemspec +42 -0
- data/test/ActiveRecord/WithColumnName.rb +159 -0
- data/test/ActiveRecord/WithExplicitDeterministicEventOrdering.rb +159 -0
- data/test/ActiveRecord/WithExplicitGlobalNonDeterministicEventOrdering.rb +165 -0
- data/test/ActiveRecord/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +163 -0
- data/test/ActiveRecord/WithExplicitNonDeterministicEventOrdering.rb +161 -0
- data/test/ActiveRecord/WithInitialStateBlock.rb +157 -0
- data/test/ActiveRecord/WithMultipleFinalStates.rb +188 -0
- data/test/ActiveRecord/WithMultipleStateMachines.rb +221 -0
- data/test/ActiveRecord/WithMultipleStateMachinesAndStatefulBlock.rb +223 -0
- data/test/ActiveRecord/WithPersistenceNonSpecificExtend.rb +159 -0
- data/test/ActiveRecord/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +161 -0
- data/test/ActiveRecord/WithPersistenceSpecificExtend.rb +159 -0
- data/test/ActiveRecord/WithPersistenceSpecificExtendAndStatefulBlock.rb +161 -0
- data/test/ActiveRecord/test_helper.rb +9 -0
- data/test/ActiveRecord.rb +5 -0
- data/test/Poro/WithExplicitDeterministicEventOrdering.rb +147 -0
- data/test/Poro/WithExplicitGlobalNonDeterministicEventOrdering.rb +153 -0
- data/test/Poro/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +151 -0
- data/test/Poro/WithExplicitNonDeterministicEventOrdering.rb +149 -0
- data/test/Poro/WithInitialStateBlock.rb +145 -0
- data/test/Poro/WithMultipleFinalStates.rb +176 -0
- data/test/Poro/WithMultipleStateMachines.rb +192 -0
- data/test/Poro/WithMultipleStateMachinesAndStatefulBlock.rb +194 -0
- data/test/Poro/WithPersistenceNonSpecificExtend.rb +147 -0
- data/test/Poro/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +149 -0
- data/test/Poro/WithPersistenceSpecificExtend.rb +147 -0
- data/test/Poro/WithPersistenceSpecificExtendAndStatefulBlock.rb +149 -0
- data/test/Poro/WithVariableName.rb +147 -0
- data/test/Poro.rb +5 -0
- data/test/Sequel/WithColumnName.rb +154 -0
- data/test/Sequel/WithExplicitDeterministicEventOrdering.rb +154 -0
- data/test/Sequel/WithExplicitGlobalNonDeterministicEventOrdering.rb +160 -0
- data/test/Sequel/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.rb +158 -0
- data/test/Sequel/WithExplicitNonDeterministicEventOrdering.rb +156 -0
- data/test/Sequel/WithInitialStateBlock.rb +152 -0
- data/test/Sequel/WithMultipleFinalStates.rb +183 -0
- data/test/Sequel/WithMultipleStateMachines.rb +216 -0
- data/test/Sequel/WithMultipleStateMachinesAndStatefulBlock.rb +218 -0
- data/test/Sequel/WithPersistenceNonSpecificExtend.rb +154 -0
- data/test/Sequel/WithPersistenceNonSpecificExtendAndStatefulBlock.rb +156 -0
- data/test/Sequel/WithPersistenceSpecificExtend.rb +154 -0
- data/test/Sequel/WithPersistenceSpecificExtendAndStatefulBlock.rb +156 -0
- data/test/Sequel/test_helper.rb +5 -0
- data/test/Sequel.rb +5 -0
- data/test/Stateful.rb +15 -0
- metadata +69 -4
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# test/Sequel/WithExplicitNonDeterministicEventOrdering.rb
|
|
2
|
+
|
|
3
|
+
gem 'minitest'
|
|
4
|
+
gem 'minitest-spec-context'
|
|
5
|
+
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
require 'minitest-spec-context'
|
|
8
|
+
|
|
9
|
+
require_relative './test_helper'
|
|
10
|
+
|
|
11
|
+
lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
|
|
12
|
+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
13
|
+
|
|
14
|
+
require 'Stateful'
|
|
15
|
+
|
|
16
|
+
DB.create_table :sequel_machine6s do
|
|
17
|
+
primary_key :id
|
|
18
|
+
String :current_state
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class SequelMachine6 < Sequel::Model
|
|
22
|
+
extend Stateful
|
|
23
|
+
|
|
24
|
+
initial_state :initial_state, non_deterministic: true do
|
|
25
|
+
on :an_event => :next_state
|
|
26
|
+
on :another_event => :final_state
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
state :next_state do
|
|
30
|
+
on :yet_another_event => :final_state
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
final_state :final_state
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe Stateful::Sequel do
|
|
37
|
+
let(:machine){SequelMachine6.create}
|
|
38
|
+
|
|
39
|
+
it "must have an initial state" do
|
|
40
|
+
_(machine.initial_state).wont_be_nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "must have a final state (if one has been specified)" do
|
|
44
|
+
if SequelMachine6.final_state?
|
|
45
|
+
_(machine.final_state).wont_be_nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "initial_state" do
|
|
50
|
+
it "must have an initial state before any events occur" do
|
|
51
|
+
_(machine.initial_state?).must_equal true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "must have an initial state consistent with what is given" do
|
|
55
|
+
_(machine.initial_state).must_equal SequelMachine6.stateful_state_machine.initial_state
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "must have an initial state with name as per the name given" do
|
|
59
|
+
_(machine.initial_state.name).must_equal :initial_state
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "must not be in the final state (assuming that initial and final are different states)" do
|
|
63
|
+
_(machine.final_state?).must_equal false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "must know what it's next state is given an event name" do
|
|
67
|
+
_(machine.next_state(:an_event)).must_equal SequelMachine6.stateful_state_machine.find(:next_state)
|
|
68
|
+
_(machine.next_state(:another_event)).must_equal SequelMachine6.stateful_state_machine.find(:final_state)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "must have an intial state which has a collection of transitions to other states" do
|
|
72
|
+
_(machine.transitions.class).must_equal Array
|
|
73
|
+
_(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "must have two transitions to other states" do
|
|
77
|
+
_(machine.transitions.size).must_equal 2
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "must know what transitions are available" do
|
|
81
|
+
transition_pairs = machine.transitions.collect{|t| [t.event_name, t.next_state_name]}
|
|
82
|
+
_(transition_pairs).must_include [:an_event, :next_state]
|
|
83
|
+
_(transition_pairs).must_include [:another_event, :final_state]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "must be active" do
|
|
87
|
+
_(machine.active?).must_equal true
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
context "next_state" do
|
|
92
|
+
before do
|
|
93
|
+
machine.an_event
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "must not be in the initial state" do
|
|
97
|
+
_(machine.initial_state?).must_equal false
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "must not be in the final state" do
|
|
101
|
+
_(machine.final_state?).must_equal false
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "must be in the next_state state" do
|
|
105
|
+
_(machine.current_state.name).must_equal :next_state
|
|
106
|
+
_(machine.next_state?).must_equal true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "must have a collection of transitions to other states" do
|
|
110
|
+
_(machine.transitions.class).must_equal Array
|
|
111
|
+
_(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "must have one transition to other states" do
|
|
115
|
+
_(machine.transitions.size).must_equal 1
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "must know what transitions are available" do
|
|
119
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "must be active" do
|
|
123
|
+
_(machine.active?).must_equal true
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
context "final_state" do
|
|
128
|
+
before do
|
|
129
|
+
machine.another_event
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "must have a final state" do
|
|
133
|
+
_(machine.final_state?).must_equal true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "must have a final state consistent with what is given" do
|
|
137
|
+
_(machine.final_state).must_equal SequelMachine6.stateful_state_machine.final_state
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "must have a state with name as per the name given" do
|
|
141
|
+
_(machine.current_state.name).must_equal :final_state
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "must not be in the initial state (assuming that initial and final are different states)" do
|
|
145
|
+
_(machine.initial_state?).must_equal false
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "must have no transitions" do
|
|
149
|
+
_(machine.transitions.empty?).must_equal true
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "must not be active" do
|
|
153
|
+
_(machine.active?).must_equal false
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# test/Sequel/WithInitialStateBlock.rb
|
|
2
|
+
|
|
3
|
+
gem 'minitest'
|
|
4
|
+
gem 'minitest-spec-context'
|
|
5
|
+
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
require 'minitest-spec-context'
|
|
8
|
+
|
|
9
|
+
require_relative './test_helper'
|
|
10
|
+
|
|
11
|
+
lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
|
|
12
|
+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
13
|
+
|
|
14
|
+
require 'Stateful'
|
|
15
|
+
|
|
16
|
+
DB.create_table :sequel_machine4s do
|
|
17
|
+
primary_key :id
|
|
18
|
+
String :current_state
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class SequelMachine4 < Sequel::Model
|
|
22
|
+
extend Stateful
|
|
23
|
+
|
|
24
|
+
initial_state :initial_state do
|
|
25
|
+
on :an_event => :next_state
|
|
26
|
+
on :another_event => :final_state
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
state :next_state do
|
|
30
|
+
on :yet_another_event => :final_state
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
final_state :final_state
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe Stateful::Sequel do
|
|
37
|
+
let(:machine){SequelMachine4.create}
|
|
38
|
+
|
|
39
|
+
it "must have an initial state" do
|
|
40
|
+
_(machine.initial_state).wont_be_nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "must have a final state (if one has been specified)" do
|
|
44
|
+
if SequelMachine4.final_state?
|
|
45
|
+
_(machine.final_state).wont_be_nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "initial_state" do
|
|
50
|
+
it "must have an initial state before any events occur" do
|
|
51
|
+
_(machine.initial_state?).must_equal true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "must have an initial state consistent with what is given" do
|
|
55
|
+
_(machine.initial_state).must_equal SequelMachine4.stateful_state_machine.initial_state
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "must have an initial state with name as per the name given" do
|
|
59
|
+
_(machine.initial_state.name).must_equal :initial_state
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "must not be in the final state (assuming that initial and final are different states)" do
|
|
63
|
+
_(machine.final_state?).must_equal false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "must know what it's next state is given an event name" do
|
|
67
|
+
_(machine.next_state(:an_event)).must_equal SequelMachine4.stateful_state_machine.find(:next_state)
|
|
68
|
+
_(machine.next_state(:another_event)).must_equal SequelMachine4.stateful_state_machine.find(:final_state)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "must have an intial state which has as set of transitions to other states" do
|
|
72
|
+
_(machine.transitions.class).must_equal Array
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "must have two transitions to other states" do
|
|
76
|
+
_(machine.transitions.size).must_equal 2
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "must know what transitions are available" do
|
|
80
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:an_event, :next_state], [:another_event, :final_state]]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "must be active" do
|
|
84
|
+
_(machine.active?).must_equal true
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
context "next_state" do
|
|
89
|
+
before do
|
|
90
|
+
machine.an_event
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "must not be in the initial state" do
|
|
94
|
+
_(machine.initial_state?).must_equal false
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "must not be in the final state" do
|
|
98
|
+
_(machine.final_state?).must_equal false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "must be in the next_state state" do
|
|
102
|
+
_(machine.current_state.name).must_equal :next_state
|
|
103
|
+
_(machine.next_state?).must_equal true
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "must have a set of transitions to other states" do
|
|
107
|
+
_(machine.transitions.class).must_equal Array
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "must have one transition to other states" do
|
|
111
|
+
_(machine.transitions.size).must_equal 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "must know what transitions are available" do
|
|
115
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "must be active" do
|
|
119
|
+
_(machine.active?).must_equal true
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
context "final_state" do
|
|
124
|
+
before do
|
|
125
|
+
machine.another_event
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "must have a final state" do
|
|
129
|
+
_(machine.final_state?).must_equal true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "must have a final state consistent with what is given" do
|
|
133
|
+
_(machine.final_state).must_equal SequelMachine4.stateful_state_machine.final_state
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "must have a state with name as per the name given" do
|
|
137
|
+
_(machine.current_state.name).must_equal :final_state
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "must not be in the initial state (assuming that initial and final are different states)" do
|
|
141
|
+
_(machine.initial_state?).must_equal false
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "must have no transitions" do
|
|
145
|
+
_(machine.transitions.empty?).must_equal true
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "must not be active" do
|
|
149
|
+
_(machine.active?).must_equal false
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# test/Sequel/WithMultipleFinalStates.rb
|
|
2
|
+
|
|
3
|
+
gem 'minitest'
|
|
4
|
+
gem 'minitest-spec-context'
|
|
5
|
+
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
require 'minitest-spec-context'
|
|
8
|
+
|
|
9
|
+
require_relative './test_helper'
|
|
10
|
+
|
|
11
|
+
lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
|
|
12
|
+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
13
|
+
|
|
14
|
+
require 'Stateful'
|
|
15
|
+
|
|
16
|
+
DB.create_table :sequel_machine7s do
|
|
17
|
+
primary_key :id
|
|
18
|
+
String :current_state
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class SequelMachine7 < Sequel::Model
|
|
22
|
+
extend Stateful
|
|
23
|
+
|
|
24
|
+
initial_state :initial_state do
|
|
25
|
+
on :an_event => :next_state
|
|
26
|
+
on :another_event => :final_state0
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
state :next_state do
|
|
30
|
+
on :yet_another_event => :final_state1
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
final_state :final_state0, :final_state1
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe Stateful::Sequel do
|
|
37
|
+
let(:machine){SequelMachine7.new}
|
|
38
|
+
|
|
39
|
+
it "must have an initial state" do
|
|
40
|
+
_(machine.initial_state).wont_be_nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "must have a final state (if one has been specified)" do
|
|
44
|
+
if SequelMachine7.final_state?
|
|
45
|
+
_(machine.final_state).wont_be_nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "initial_state" do
|
|
50
|
+
it "must have an initial state before any events occur" do
|
|
51
|
+
_(machine.initial_state?).must_equal true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "must have an initial state consistent with what is given" do
|
|
55
|
+
_(machine.initial_state).must_equal SequelMachine7.stateful_state_machine.initial_state
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "must have an initial state with name as per the name given" do
|
|
59
|
+
_(machine.initial_state.name).must_equal :initial_state
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "must not be in the final state (assuming that initial and final are different states)" do
|
|
63
|
+
_(machine.final_state?).must_equal false
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "must know what it's next state is given an event name" do
|
|
67
|
+
_(machine.next_state(:an_event)).must_equal SequelMachine7.stateful_state_machine.find(:next_state)
|
|
68
|
+
_(machine.next_state(:another_event)).must_equal SequelMachine7.stateful_state_machine.find(:final_state0)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "must have an intial state which has as set of transitions to other states" do
|
|
72
|
+
_(machine.transitions.class).must_equal Array
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "must have two transitions to other states" do
|
|
76
|
+
_(machine.transitions.size).must_equal 2
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "must know what transitions are available and in what order they are presented" do
|
|
80
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:an_event, :next_state], [:another_event, :final_state0]]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "must be active" do
|
|
84
|
+
_(machine.active?).must_equal true
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
context "next_state" do
|
|
89
|
+
before do
|
|
90
|
+
machine.an_event
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "must not be in the initial state" do
|
|
94
|
+
_(machine.initial_state?).must_equal false
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "must not be in a final state" do
|
|
98
|
+
_(machine.final_state?).must_equal false
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "must be in the next_state state" do
|
|
102
|
+
_(machine.current_state.name).must_equal :next_state
|
|
103
|
+
_(machine.next_state?).must_equal true
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "must have a set of transitions to other states" do
|
|
107
|
+
_(machine.transitions.class).must_equal Array
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "must have one transition to other states" do
|
|
111
|
+
_(machine.transitions.size).must_equal 1
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "must know what transitions are available" do
|
|
115
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state1]]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "must be active" do
|
|
119
|
+
_(machine.active?).must_equal true
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
context "final_state0" do
|
|
124
|
+
before do
|
|
125
|
+
machine.another_event
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "must have a final state" do
|
|
129
|
+
_(machine.final_state?).must_equal true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "must have a final state consistent with what is given" do
|
|
133
|
+
_(SequelMachine7.stateful_state_machine.final_states).must_include machine.final_state
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it "must have a state with name as per the name given" do
|
|
137
|
+
_(machine.current_state.name).must_equal :final_state0
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "must not be in the initial state (assuming that initial and final are different states)" do
|
|
141
|
+
_(machine.initial_state?).must_equal false
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "must have no transitions" do
|
|
145
|
+
_(machine.transitions.empty?).must_equal true
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "must not be active" do
|
|
149
|
+
_(machine.active?).must_equal false
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "final_state1" do
|
|
154
|
+
before do
|
|
155
|
+
machine.an_event
|
|
156
|
+
machine.yet_another_event
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "must have a final state" do
|
|
160
|
+
_(machine.final_state?).must_equal true
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "must have a final state consistent with what is given" do
|
|
164
|
+
_(SequelMachine7.stateful_state_machine.final_states).must_include machine.final_state
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it "must have a state with name as per the name given" do
|
|
168
|
+
_(machine.current_state.name).must_equal :final_state1
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "must not be in the initial state (assuming that initial and final are different states)" do
|
|
172
|
+
_(machine.initial_state?).must_equal false
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
it "must have no transitions" do
|
|
176
|
+
_(machine.transitions.empty?).must_equal true
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "must not be active" do
|
|
180
|
+
_(machine.active?).must_equal false
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# test/Sequel/WithMultipleStateMachines.rb
|
|
2
|
+
|
|
3
|
+
gem 'minitest'
|
|
4
|
+
gem 'minitest-spec-context'
|
|
5
|
+
|
|
6
|
+
require 'minitest/autorun'
|
|
7
|
+
require 'minitest-spec-context'
|
|
8
|
+
|
|
9
|
+
require_relative './test_helper'
|
|
10
|
+
|
|
11
|
+
lib_dir = File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
|
|
12
|
+
$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
|
|
13
|
+
|
|
14
|
+
require 'Stateful'
|
|
15
|
+
|
|
16
|
+
DB.create_table :sequel_machine11s do
|
|
17
|
+
primary_key :id
|
|
18
|
+
String :fulfilment_state
|
|
19
|
+
String :payment_state
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class SequelMachine11 < Sequel::Model
|
|
23
|
+
extend Stateful
|
|
24
|
+
|
|
25
|
+
state_machine :fulfilment do
|
|
26
|
+
initial_state :pending do
|
|
27
|
+
on :items_collected => :ready
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
state :ready do
|
|
31
|
+
on :dispatch => :dispatched
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
final_state :dispatched
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
state_machine :payment do
|
|
38
|
+
initial_state :unpaid do
|
|
39
|
+
on :pay => :paid
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
state :paid do
|
|
43
|
+
on :refund => :refunded
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
final_state :refunded
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe Stateful::Sequel do
|
|
51
|
+
let(:machine){SequelMachine11.create}
|
|
52
|
+
|
|
53
|
+
context "initial states" do
|
|
54
|
+
it "must be in the fulfilment initial state" do
|
|
55
|
+
_(machine.fulfilment_initial_state?).must_equal true
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "must be in the payment initial state" do
|
|
59
|
+
_(machine.payment_initial_state?).must_equal true
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "must have the correct fulfilment state name" do
|
|
63
|
+
_(machine.fulfilment_state.name).must_equal :pending
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "must have the correct payment state name" do
|
|
67
|
+
_(machine.payment_state.name).must_equal :unpaid
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "must have fulfilment transitions" do
|
|
71
|
+
_(machine.fulfilment_transitions.size).must_equal 1
|
|
72
|
+
_(machine.fulfilment_transitions.first.event_name).must_equal :items_collected
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "must have payment transitions" do
|
|
76
|
+
_(machine.payment_transitions.size).must_equal 1
|
|
77
|
+
_(machine.payment_transitions.first.event_name).must_equal :pay
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "must not be in a fulfilment final state" do
|
|
81
|
+
_(machine.fulfilment_final_state?).must_equal false
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "must not be in a payment final state" do
|
|
85
|
+
_(machine.payment_final_state?).must_equal false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "must have domain predicates" do
|
|
89
|
+
_(machine.pending?).must_equal true
|
|
90
|
+
_(machine.unpaid?).must_equal true
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context "independent state transitions" do
|
|
95
|
+
before do
|
|
96
|
+
machine.pay
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "must still be in the fulfilment initial state" do
|
|
100
|
+
_(machine.fulfilment_initial_state?).must_equal true
|
|
101
|
+
_(machine.pending?).must_equal true
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "must have advanced the payment state" do
|
|
105
|
+
_(machine.payment_state.name).must_equal :paid
|
|
106
|
+
_(machine.paid?).must_equal true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "must not be in the payment initial state" do
|
|
110
|
+
_(machine.payment_initial_state?).must_equal false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "must have persisted the payment state" do
|
|
114
|
+
machine.refresh
|
|
115
|
+
_(machine.payment_state.name).must_equal :paid
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "must have persisted the fulfilment state as initial" do
|
|
119
|
+
machine.refresh
|
|
120
|
+
_(machine.fulfilment_state.name).must_equal :pending
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
context "both machines advanced" do
|
|
125
|
+
before do
|
|
126
|
+
machine.items_collected
|
|
127
|
+
machine.pay
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "must be in the ready fulfilment state" do
|
|
131
|
+
_(machine.fulfilment_state.name).must_equal :ready
|
|
132
|
+
_(machine.ready?).must_equal true
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "must be in the paid payment state" do
|
|
136
|
+
_(machine.payment_state.name).must_equal :paid
|
|
137
|
+
_(machine.paid?).must_equal true
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "must have correct fulfilment transitions" do
|
|
141
|
+
_(machine.fulfilment_transitions.size).must_equal 1
|
|
142
|
+
_(machine.fulfilment_transitions.first.event_name).must_equal :dispatch
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "must have correct payment transitions" do
|
|
146
|
+
_(machine.payment_transitions.size).must_equal 1
|
|
147
|
+
_(machine.payment_transitions.first.event_name).must_equal :refund
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "must have persisted both states" do
|
|
151
|
+
machine.refresh
|
|
152
|
+
_(machine.fulfilment_state.name).must_equal :ready
|
|
153
|
+
_(machine.payment_state.name).must_equal :paid
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
context "fulfilment final state" do
|
|
158
|
+
before do
|
|
159
|
+
machine.items_collected
|
|
160
|
+
machine.dispatch
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "must be in the fulfilment final state" do
|
|
164
|
+
_(machine.fulfilment_final_state?).must_equal true
|
|
165
|
+
_(machine.dispatched?).must_equal true
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it "must have no fulfilment transitions" do
|
|
169
|
+
_(machine.fulfilment_transitions.empty?).must_equal true
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
context "payment final state" do
|
|
174
|
+
before do
|
|
175
|
+
machine.pay
|
|
176
|
+
machine.refund
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it "must be in the payment final state" do
|
|
180
|
+
_(machine.payment_final_state?).must_equal true
|
|
181
|
+
_(machine.refunded?).must_equal true
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "must have no payment transitions" do
|
|
185
|
+
_(machine.payment_transitions.empty?).must_equal true
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
context "active?" do
|
|
190
|
+
it "must be active when all machines are in initial states" do
|
|
191
|
+
_(machine.active?).must_equal true
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
it "must be active when one machine has reached final state" do
|
|
195
|
+
machine.items_collected
|
|
196
|
+
machine.dispatch
|
|
197
|
+
_(machine.fulfilment_final_state?).must_equal true
|
|
198
|
+
_(machine.active?).must_equal true
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it "must not be active when all machines have reached final states" do
|
|
202
|
+
machine.items_collected
|
|
203
|
+
machine.dispatch
|
|
204
|
+
machine.pay
|
|
205
|
+
machine.refund
|
|
206
|
+
_(machine.active?).must_equal false
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "must be able to check a specific machine" do
|
|
210
|
+
machine.items_collected
|
|
211
|
+
machine.dispatch
|
|
212
|
+
_(machine.active?(:fulfilment)).must_equal false
|
|
213
|
+
_(machine.active?(:payment)).must_equal true
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|