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,159 @@
|
|
|
1
|
+
# test/ActiveRecord/WithColumnName.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
|
+
class CreateTableMachines < ActiveRecord::Migration[6.0]
|
|
17
|
+
def change
|
|
18
|
+
create_table :active_record_machine8s do |t|
|
|
19
|
+
t.string :status
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class ActiveRecordMachine8 < ActiveRecord::Base
|
|
25
|
+
@stateful_column_name = 'status'
|
|
26
|
+
|
|
27
|
+
extend Stateful
|
|
28
|
+
|
|
29
|
+
initial_state :initial_state do
|
|
30
|
+
on :an_event => :next_state
|
|
31
|
+
on :another_event => :final_state
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
state :next_state do
|
|
35
|
+
on :yet_another_event => :final_state
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
final_state :final_state
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
CreateTableMachines.new.change
|
|
42
|
+
|
|
43
|
+
describe Stateful::ActiveRecord do
|
|
44
|
+
let(:machine){ActiveRecordMachine8.create}
|
|
45
|
+
|
|
46
|
+
it "must have an initial state" do
|
|
47
|
+
_(machine.initial_state).wont_be_nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "must have a final state (if one has been specified)" do
|
|
51
|
+
if ActiveRecordMachine8.final_state?
|
|
52
|
+
_(machine.final_state).wont_be_nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context "initial_state" do
|
|
57
|
+
it "must have an initial state before any events occur" do
|
|
58
|
+
_(machine.initial_state?).must_equal true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "must have an initial state consistent with what is given" do
|
|
62
|
+
_(machine.initial_state).must_equal ActiveRecordMachine8.stateful_state_machine.initial_state
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "must have an initial state with name as per the name given" do
|
|
66
|
+
_(machine.initial_state.name).must_equal :initial_state
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "must not be in the final state (assuming that initial and final are different states)" do
|
|
70
|
+
_(machine.final_state?).must_equal false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "must know what it's next state is given an event name" do
|
|
74
|
+
_(machine.next_state(:an_event)).must_equal ActiveRecordMachine8.stateful_state_machine.find(:next_state)
|
|
75
|
+
_(machine.next_state(:another_event)).must_equal ActiveRecordMachine8.stateful_state_machine.find(:final_state)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "must have an intial state which has as set of transitions to other states" do
|
|
79
|
+
_(machine.transitions.class).must_equal Array
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "must have two transitions to other states" do
|
|
83
|
+
_(machine.transitions.size).must_equal 2
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "must know what transitions are available" do
|
|
87
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:an_event, :next_state], [:another_event, :final_state]]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "must be active" do
|
|
91
|
+
_(machine.active?).must_equal true
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context "next_state" do
|
|
96
|
+
before do
|
|
97
|
+
machine.an_event
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "must not be in the initial state" do
|
|
101
|
+
_(machine.initial_state?).must_equal false
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "must not be in the final state" do
|
|
105
|
+
_(machine.final_state?).must_equal false
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "must be in the next_state state" do
|
|
109
|
+
_(machine.status.name).must_equal :next_state
|
|
110
|
+
_(machine.next_state?).must_equal true
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "must have a set of transitions to other states" do
|
|
114
|
+
_(machine.transitions.class).must_equal Array
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "must have one transition to other states" do
|
|
118
|
+
_(machine.transitions.size).must_equal 1
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "must know what transitions are available" do
|
|
122
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "must be active" do
|
|
126
|
+
_(machine.active?).must_equal true
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context "final_state" do
|
|
131
|
+
before do
|
|
132
|
+
machine.another_event
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "must have a final state" do
|
|
136
|
+
_(machine.final_state?).must_equal true
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "must have a final state consistent with what is given" do
|
|
140
|
+
_(machine.final_state).must_equal ActiveRecordMachine8.stateful_state_machine.final_state
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "must have a state with name as per the name given" do
|
|
144
|
+
_(machine.status.name).must_equal :final_state
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "must not be in the initial state (assuming that initial and final are different states)" do
|
|
148
|
+
_(machine.initial_state?).must_equal false
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "must have no transitions" do
|
|
152
|
+
_(machine.transitions.empty?).must_equal true
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "must not be active" do
|
|
156
|
+
_(machine.active?).must_equal false
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# test/ActiveRecord/WithExplicitDeterministicEventOrdering.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
|
+
class CreateTableMachines < ActiveRecord::Migration[6.0]
|
|
17
|
+
def change
|
|
18
|
+
create_table :active_record_machine5s do |t|
|
|
19
|
+
t.string :current_state
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class ActiveRecordMachine5 < ActiveRecord::Base
|
|
25
|
+
extend Stateful
|
|
26
|
+
|
|
27
|
+
initial_state :initial_state, deterministic: true do
|
|
28
|
+
on :an_event => :next_state
|
|
29
|
+
on :another_event => :final_state
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
state :next_state do
|
|
33
|
+
on :yet_another_event => :final_state
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
final_state :final_state
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
CreateTableMachines.new.change
|
|
40
|
+
|
|
41
|
+
describe Stateful::ActiveRecord do
|
|
42
|
+
let(:machine){ActiveRecordMachine5.create}
|
|
43
|
+
|
|
44
|
+
it "must have an initial state" do
|
|
45
|
+
_(machine.initial_state).wont_be_nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "must have a final state (if one has been specified)" do
|
|
49
|
+
if ActiveRecordMachine5.final_state?
|
|
50
|
+
_(machine.final_state).wont_be_nil
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "initial_state" do
|
|
55
|
+
it "must have an initial state before any events occur" do
|
|
56
|
+
_(machine.initial_state?).must_equal true
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "must have an initial state consistent with what is given" do
|
|
60
|
+
_(machine.initial_state).must_equal ActiveRecordMachine5.stateful_state_machine.initial_state
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "must have an initial state with name as per the name given" do
|
|
64
|
+
_(machine.initial_state.name).must_equal :initial_state
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "must not be in the final state (assuming that initial and final are different states)" do
|
|
68
|
+
_(machine.final_state?).must_equal false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "must know what it's next state is given an event name" do
|
|
72
|
+
_(machine.next_state(:an_event)).must_equal ActiveRecordMachine5.stateful_state_machine.find(:next_state)
|
|
73
|
+
_(machine.next_state(:another_event)).must_equal ActiveRecordMachine5.stateful_state_machine.find(:final_state)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "must have an intial state which has a collection of transitions to other states" do
|
|
77
|
+
_(machine.transitions.class).must_equal Array
|
|
78
|
+
_(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "must have two transitions to other states" do
|
|
82
|
+
_(machine.transitions.size).must_equal 2
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "must know what transitions are available and in what order they are presented" do
|
|
86
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:an_event, :next_state], [:another_event, :final_state]]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "must be active" do
|
|
90
|
+
_(machine.active?).must_equal true
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
context "next_state" do
|
|
95
|
+
before do
|
|
96
|
+
machine.an_event
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it "must not be in the initial state" do
|
|
100
|
+
_(machine.initial_state?).must_equal false
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "must not be in the final state" do
|
|
104
|
+
_(machine.final_state?).must_equal false
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "must be in the next_state state" do
|
|
108
|
+
_(machine.current_state.name).must_equal :next_state
|
|
109
|
+
_(machine.next_state?).must_equal true
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "must have a collection of transitions to other states" do
|
|
113
|
+
_(machine.transitions.class).must_equal Array
|
|
114
|
+
_(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "must have one transition to other states" do
|
|
118
|
+
_(machine.transitions.size).must_equal 1
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "must know what transitions are available" do
|
|
122
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "must be active" do
|
|
126
|
+
_(machine.active?).must_equal true
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context "final_state" do
|
|
131
|
+
before do
|
|
132
|
+
machine.another_event
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "must have a final state" do
|
|
136
|
+
_(machine.final_state?).must_equal true
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "must have a final state consistent with what is given" do
|
|
140
|
+
_(machine.final_state).must_equal ActiveRecordMachine5.stateful_state_machine.final_state
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "must have a state with name as per the name given" do
|
|
144
|
+
_(machine.current_state.name).must_equal :final_state
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "must not be in the initial state (assuming that initial and final are different states)" do
|
|
148
|
+
_(machine.initial_state?).must_equal false
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "must have no transitions" do
|
|
152
|
+
_(machine.transitions.empty?).must_equal true
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "must not be active" do
|
|
156
|
+
_(machine.active?).must_equal false
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# test/ActiveRecord/WithExplicitGlobalNonDeterministicEventOrdering.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
|
+
class CreateTableMachines < ActiveRecord::Migration[6.0]
|
|
17
|
+
def change
|
|
18
|
+
create_table :active_record_machine9s do |t|
|
|
19
|
+
t.string :current_state
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class ActiveRecordMachine9 < ActiveRecord::Base
|
|
25
|
+
extend Stateful
|
|
26
|
+
|
|
27
|
+
stateful global_non_deterministic_event_ordering: true do
|
|
28
|
+
initial_state :initial_state
|
|
29
|
+
|
|
30
|
+
state :initial_state do
|
|
31
|
+
on :an_event => :next_state
|
|
32
|
+
on :another_event => :final_state
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
state :next_state do
|
|
36
|
+
on :yet_another_event => :final_state
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
final_state :final_state
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
CreateTableMachines.new.change
|
|
44
|
+
|
|
45
|
+
describe Stateful::ActiveRecord do
|
|
46
|
+
let(:machine){ActiveRecordMachine9.create}
|
|
47
|
+
|
|
48
|
+
it "must have an initial state" do
|
|
49
|
+
_(machine.initial_state).wont_be_nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "must have a final state (if one has been specified)" do
|
|
53
|
+
if ActiveRecordMachine9.final_state?
|
|
54
|
+
_(machine.final_state).wont_be_nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
context "initial_state" do
|
|
59
|
+
it "must have an initial state before any events occur" do
|
|
60
|
+
_(machine.initial_state?).must_equal true
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "must have an initial state consistent with what is given" do
|
|
64
|
+
_(machine.initial_state).must_equal ActiveRecordMachine9.stateful_state_machine.initial_state
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "must have an initial state with name as per the name given" do
|
|
68
|
+
_(machine.initial_state.name).must_equal :initial_state
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "must not be in the final state (assuming that initial and final are different states)" do
|
|
72
|
+
_(machine.final_state?).must_equal false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "must know what it's next state is given an event name" do
|
|
76
|
+
_(machine.next_state(:an_event)).must_equal ActiveRecordMachine9.stateful_state_machine.find(:next_state)
|
|
77
|
+
_(machine.next_state(:another_event)).must_equal ActiveRecordMachine9.stateful_state_machine.find(:final_state)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "must have an intial state which has a collection of transitions to other states" do
|
|
81
|
+
_(machine.transitions.class).must_equal Array
|
|
82
|
+
_(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "must have two transitions to other states" do
|
|
86
|
+
_(machine.transitions.size).must_equal 2
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "must know what transitions are available" do
|
|
90
|
+
transition_pairs = machine.transitions.collect{|t| [t.event_name, t.next_state_name]}
|
|
91
|
+
_(transition_pairs).must_include [:an_event, :next_state]
|
|
92
|
+
_(transition_pairs).must_include [:another_event, :final_state]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "must be active" do
|
|
96
|
+
_(machine.active?).must_equal true
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context "next_state" do
|
|
101
|
+
before do
|
|
102
|
+
machine.an_event
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "must not be in the initial state" do
|
|
106
|
+
_(machine.initial_state?).must_equal false
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "must not be in the final state" do
|
|
110
|
+
_(machine.final_state?).must_equal false
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "must be in the next_state state" do
|
|
114
|
+
_(machine.current_state.name).must_equal :next_state
|
|
115
|
+
_(machine.next_state?).must_equal true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "must have a collection of transitions to other states" do
|
|
119
|
+
_(machine.transitions.class).must_equal Array
|
|
120
|
+
_(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "must have one transition to other states" do
|
|
124
|
+
_(machine.transitions.size).must_equal 1
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "must know what transitions are available" do
|
|
128
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "must be active" do
|
|
132
|
+
_(machine.active?).must_equal true
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
context "final_state" do
|
|
137
|
+
before do
|
|
138
|
+
machine.another_event
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "must have a final state" do
|
|
142
|
+
_(machine.final_state?).must_equal true
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "must have a final state consistent with what is given" do
|
|
146
|
+
_(machine.final_state).must_equal ActiveRecordMachine9.stateful_state_machine.final_state
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "must have a state with name as per the name given" do
|
|
150
|
+
_(machine.current_state.name).must_equal :final_state
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "must not be in the initial state (assuming that initial and final are different states)" do
|
|
154
|
+
_(machine.initial_state?).must_equal false
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "must have no transitions" do
|
|
158
|
+
_(machine.transitions.empty?).must_equal true
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
it "must not be active" do
|
|
162
|
+
_(machine.active?).must_equal false
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# test/ActiveRecord/WithExplicitGlobalNonDeterministicEventOrderingAndInitialStateBlock.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
|
+
class CreateTableMachines < ActiveRecord::Migration[6.0]
|
|
17
|
+
def change
|
|
18
|
+
create_table :active_record_machine10s do |t|
|
|
19
|
+
t.string :current_state
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class ActiveRecordMachine10 < ActiveRecord::Base
|
|
25
|
+
extend Stateful
|
|
26
|
+
|
|
27
|
+
stateful global_non_deterministic_event_ordering: true do
|
|
28
|
+
initial_state :initial_state do
|
|
29
|
+
on :an_event => :next_state
|
|
30
|
+
on :another_event => :final_state
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
state :next_state do
|
|
34
|
+
on :yet_another_event => :final_state
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
final_state :final_state
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
CreateTableMachines.new.change
|
|
42
|
+
|
|
43
|
+
describe Stateful::ActiveRecord do
|
|
44
|
+
let(:machine){ActiveRecordMachine10.create}
|
|
45
|
+
|
|
46
|
+
it "must have an initial state" do
|
|
47
|
+
_(machine.initial_state).wont_be_nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "must have a final state (if one has been specified)" do
|
|
51
|
+
if ActiveRecordMachine10.final_state?
|
|
52
|
+
_(machine.final_state).wont_be_nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context "initial_state" do
|
|
57
|
+
it "must have an initial state before any events occur" do
|
|
58
|
+
_(machine.initial_state?).must_equal true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "must have an initial state consistent with what is given" do
|
|
62
|
+
_(machine.initial_state).must_equal ActiveRecordMachine10.stateful_state_machine.initial_state
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "must have an initial state with name as per the name given" do
|
|
66
|
+
_(machine.initial_state.name).must_equal :initial_state
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "must not be in the final state (assuming that initial and final are different states)" do
|
|
70
|
+
_(machine.final_state?).must_equal false
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "must know what it's next state is given an event name" do
|
|
74
|
+
_(machine.next_state(:an_event)).must_equal ActiveRecordMachine10.stateful_state_machine.find(:next_state)
|
|
75
|
+
_(machine.next_state(:another_event)).must_equal ActiveRecordMachine10.stateful_state_machine.find(:final_state)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "must have an intial state which has a collection of transitions to other states" do
|
|
79
|
+
_(machine.transitions.class).must_equal Array
|
|
80
|
+
_(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "must have two transitions to other states" do
|
|
84
|
+
_(machine.transitions.size).must_equal 2
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "must know what transitions are available" do
|
|
88
|
+
transition_pairs = machine.transitions.collect{|t| [t.event_name, t.next_state_name]}
|
|
89
|
+
_(transition_pairs).must_include [:an_event, :next_state]
|
|
90
|
+
_(transition_pairs).must_include [:another_event, :final_state]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "must be active" do
|
|
94
|
+
_(machine.active?).must_equal true
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
context "next_state" do
|
|
99
|
+
before do
|
|
100
|
+
machine.an_event
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "must not be in the initial state" do
|
|
104
|
+
_(machine.initial_state?).must_equal false
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "must not be in the final state" do
|
|
108
|
+
_(machine.final_state?).must_equal false
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "must be in the next_state state" do
|
|
112
|
+
_(machine.current_state.name).must_equal :next_state
|
|
113
|
+
_(machine.next_state?).must_equal true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it "must have a collection of transitions to other states" do
|
|
117
|
+
_(machine.transitions.class).must_equal Array
|
|
118
|
+
_(machine.transitions.all?{|transition| transition.is_a?(Stateful::Transition)}).must_equal true
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "must have one transition to other states" do
|
|
122
|
+
_(machine.transitions.size).must_equal 1
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "must know what transitions are available" do
|
|
126
|
+
_(machine.transitions.collect{|t| [t.event_name, t.next_state_name]}).must_equal [[:yet_another_event, :final_state]]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it "must be active" do
|
|
130
|
+
_(machine.active?).must_equal true
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context "final_state" do
|
|
135
|
+
before do
|
|
136
|
+
machine.another_event
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "must have a final state" do
|
|
140
|
+
_(machine.final_state?).must_equal true
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "must have a final state consistent with what is given" do
|
|
144
|
+
_(machine.final_state).must_equal ActiveRecordMachine10.stateful_state_machine.final_state
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "must have a state with name as per the name given" do
|
|
148
|
+
_(machine.current_state.name).must_equal :final_state
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "must not be in the initial state (assuming that initial and final are different states)" do
|
|
152
|
+
_(machine.initial_state?).must_equal false
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "must have no transitions" do
|
|
156
|
+
_(machine.transitions.empty?).must_equal true
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "must not be active" do
|
|
160
|
+
_(machine.active?).must_equal false
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|