aasm 2.2.0 → 2.3.1
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.
- data/.gitignore +4 -0
- data/Gemfile +3 -0
- data/{README.rdoc → README.md} +53 -41
- data/Rakefile +13 -94
- data/aasm.gemspec +21 -87
- data/lib/aasm/aasm.rb +28 -2
- data/lib/aasm/event.rb +19 -1
- data/lib/aasm/localizer.rb +36 -0
- data/lib/aasm/state_machine.rb +6 -7
- data/lib/aasm/state_transition.rb +7 -7
- data/lib/aasm/version.rb +3 -0
- data/lib/aasm.rb +1 -0
- data/spec/database.yml +3 -0
- data/spec/en.yml +10 -0
- data/spec/schema.rb +7 -0
- data/spec/spec_helper.rb +10 -5
- data/spec/unit/active_record_persistence_spec.rb +42 -51
- data/spec/unit/event_spec.rb +14 -0
- data/spec/unit/localizer_spec.rb +51 -0
- data/spec/unit/state_transition_spec.rb +79 -0
- data/test/functional/auth_machine_test.rb +28 -0
- data/test/models/process.rb +18 -0
- data/test/test_helper.rb +12 -2
- data/test/unit/state_machine_test.rb +37 -0
- metadata +121 -16
- data/VERSION +0 -1
|
@@ -2,20 +2,18 @@ begin
|
|
|
2
2
|
require 'rubygems'
|
|
3
3
|
require 'active_record'
|
|
4
4
|
require 'logger'
|
|
5
|
-
|
|
6
|
-
ActiveRecord::Base.logger = Logger.new(STDERR)
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
class Connection
|
|
10
|
-
end
|
|
6
|
+
load_schema
|
|
11
7
|
|
|
12
|
-
|
|
8
|
+
ActiveRecord::Base.logger = Logger.new(STDERR)
|
|
9
|
+
|
|
10
|
+
class Gate < ActiveRecord::Base
|
|
13
11
|
include AASM
|
|
14
12
|
|
|
15
13
|
# Fake this column for testing purposes
|
|
16
14
|
attr_accessor :aasm_state
|
|
17
15
|
|
|
18
|
-
aasm_state :
|
|
16
|
+
aasm_state :opened
|
|
19
17
|
aasm_state :closed
|
|
20
18
|
|
|
21
19
|
aasm_event :view do
|
|
@@ -23,36 +21,37 @@ begin
|
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
23
|
|
|
26
|
-
class
|
|
24
|
+
class Reader < ActiveRecord::Base
|
|
27
25
|
def aasm_read_state
|
|
28
26
|
"fi"
|
|
29
27
|
end
|
|
30
28
|
include AASM
|
|
31
29
|
end
|
|
32
30
|
|
|
33
|
-
class
|
|
31
|
+
class Writer < ActiveRecord::Base
|
|
34
32
|
def aasm_write_state(state)
|
|
35
33
|
"fo"
|
|
36
34
|
end
|
|
37
35
|
include AASM
|
|
38
36
|
end
|
|
39
37
|
|
|
40
|
-
class
|
|
38
|
+
class Transient < ActiveRecord::Base
|
|
41
39
|
def aasm_write_state_without_persistence(state)
|
|
42
40
|
"fum"
|
|
43
41
|
end
|
|
44
42
|
include AASM
|
|
45
43
|
end
|
|
46
44
|
|
|
47
|
-
class
|
|
45
|
+
class Simple < ActiveRecord::Base
|
|
48
46
|
include AASM
|
|
49
47
|
aasm_column :status
|
|
50
48
|
end
|
|
51
49
|
|
|
52
|
-
class
|
|
50
|
+
class Derivate < Simple
|
|
53
51
|
end
|
|
54
52
|
|
|
55
53
|
class Thief < ActiveRecord::Base
|
|
54
|
+
set_table_name "thieves"
|
|
56
55
|
include AASM
|
|
57
56
|
aasm_initial_state Proc.new { |thief| thief.skilled ? :rich : :jailed }
|
|
58
57
|
aasm_state :rich
|
|
@@ -60,7 +59,7 @@ begin
|
|
|
60
59
|
attr_accessor :skilled, :aasm_state
|
|
61
60
|
end
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
shared_examples_for "aasm model" do
|
|
64
63
|
it "should include AASM::Persistence::ActiveRecordPersistence" do
|
|
65
64
|
@klass.included_modules.should be_include(AASM::Persistence::ActiveRecordPersistence)
|
|
66
65
|
end
|
|
@@ -69,9 +68,9 @@ begin
|
|
|
69
68
|
end
|
|
70
69
|
end
|
|
71
70
|
|
|
72
|
-
describe
|
|
71
|
+
describe Gate, "class methods" do
|
|
73
72
|
before(:each) do
|
|
74
|
-
@klass =
|
|
73
|
+
@klass = Gate
|
|
75
74
|
end
|
|
76
75
|
it_should_behave_like "aasm model"
|
|
77
76
|
it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
|
|
@@ -85,9 +84,9 @@ begin
|
|
|
85
84
|
end
|
|
86
85
|
end
|
|
87
86
|
|
|
88
|
-
describe
|
|
87
|
+
describe Reader, "class methods" do
|
|
89
88
|
before(:each) do
|
|
90
|
-
@klass =
|
|
89
|
+
@klass = Reader
|
|
91
90
|
end
|
|
92
91
|
it_should_behave_like "aasm model"
|
|
93
92
|
it "should not include AASM::Persistence::ActiveRecordPersistence::ReadState" do
|
|
@@ -101,9 +100,9 @@ begin
|
|
|
101
100
|
end
|
|
102
101
|
end
|
|
103
102
|
|
|
104
|
-
describe
|
|
103
|
+
describe Writer, "class methods" do
|
|
105
104
|
before(:each) do
|
|
106
|
-
@klass =
|
|
105
|
+
@klass = Writer
|
|
107
106
|
end
|
|
108
107
|
it_should_behave_like "aasm model"
|
|
109
108
|
it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
|
|
@@ -117,9 +116,9 @@ begin
|
|
|
117
116
|
end
|
|
118
117
|
end
|
|
119
118
|
|
|
120
|
-
describe
|
|
119
|
+
describe Transient, "class methods" do
|
|
121
120
|
before(:each) do
|
|
122
|
-
@klass =
|
|
121
|
+
@klass = Transient
|
|
123
122
|
end
|
|
124
123
|
it_should_behave_like "aasm model"
|
|
125
124
|
it "should include AASM::Persistence::ActiveRecordPersistence::ReadState" do
|
|
@@ -133,61 +132,57 @@ begin
|
|
|
133
132
|
end
|
|
134
133
|
end
|
|
135
134
|
|
|
136
|
-
describe
|
|
137
|
-
before(:each) do
|
|
138
|
-
connection = mock(Connection, :columns => [])
|
|
139
|
-
FooBar.stub!(:connection).and_return(connection)
|
|
140
|
-
end
|
|
135
|
+
describe Gate, "instance methods" do
|
|
141
136
|
|
|
142
137
|
it "should respond to aasm read state when not previously defined" do
|
|
143
|
-
|
|
138
|
+
Gate.new.should respond_to(:aasm_read_state)
|
|
144
139
|
end
|
|
145
140
|
|
|
146
141
|
it "should respond to aasm write state when not previously defined" do
|
|
147
|
-
|
|
142
|
+
Gate.new.should respond_to(:aasm_write_state)
|
|
148
143
|
end
|
|
149
144
|
|
|
150
145
|
it "should respond to aasm write state without persistence when not previously defined" do
|
|
151
|
-
|
|
146
|
+
Gate.new.should respond_to(:aasm_write_state_without_persistence)
|
|
152
147
|
end
|
|
153
148
|
|
|
154
149
|
it "should return the initial state when new and the aasm field is nil" do
|
|
155
|
-
|
|
150
|
+
Gate.new.aasm_current_state.should == :opened
|
|
156
151
|
end
|
|
157
152
|
|
|
158
153
|
it "should return the aasm column when new and the aasm field is not nil" do
|
|
159
|
-
foo =
|
|
154
|
+
foo = Gate.new
|
|
160
155
|
foo.aasm_state = "closed"
|
|
161
156
|
foo.aasm_current_state.should == :closed
|
|
162
157
|
end
|
|
163
158
|
|
|
164
159
|
it "should return the aasm column when not new and the aasm_column is not nil" do
|
|
165
|
-
foo =
|
|
160
|
+
foo = Gate.new
|
|
166
161
|
foo.stub!(:new_record?).and_return(false)
|
|
167
162
|
foo.aasm_state = "state"
|
|
168
163
|
foo.aasm_current_state.should == :state
|
|
169
164
|
end
|
|
170
165
|
|
|
171
166
|
it "should allow a nil state" do
|
|
172
|
-
foo =
|
|
167
|
+
foo = Gate.new
|
|
173
168
|
foo.stub!(:new_record?).and_return(false)
|
|
174
169
|
foo.aasm_state = nil
|
|
175
170
|
foo.aasm_current_state.should be_nil
|
|
176
171
|
end
|
|
177
172
|
|
|
178
173
|
it "should have aasm_ensure_initial_state" do
|
|
179
|
-
foo =
|
|
174
|
+
foo = Gate.new
|
|
180
175
|
foo.send :aasm_ensure_initial_state
|
|
181
176
|
end
|
|
182
177
|
|
|
183
178
|
it "should call aasm_ensure_initial_state on validation before create" do
|
|
184
|
-
foo =
|
|
179
|
+
foo = Gate.new
|
|
185
180
|
foo.should_receive(:aasm_ensure_initial_state).and_return(true)
|
|
186
181
|
foo.valid?
|
|
187
182
|
end
|
|
188
183
|
|
|
189
184
|
it "should call aasm_ensure_initial_state on validation before create" do
|
|
190
|
-
foo =
|
|
185
|
+
foo = Gate.new
|
|
191
186
|
foo.stub!(:new_record?).and_return(false)
|
|
192
187
|
foo.should_not_receive(:aasm_ensure_initial_state)
|
|
193
188
|
foo.valid?
|
|
@@ -195,45 +190,41 @@ begin
|
|
|
195
190
|
|
|
196
191
|
end
|
|
197
192
|
|
|
198
|
-
describe '
|
|
193
|
+
describe 'Derivates' do
|
|
199
194
|
it "should have the same states as it's parent" do
|
|
200
|
-
|
|
195
|
+
Derivate.aasm_states.should == Simple.aasm_states
|
|
201
196
|
end
|
|
202
197
|
|
|
203
198
|
it "should have the same events as it's parent" do
|
|
204
|
-
|
|
199
|
+
Derivate.aasm_events.should == Simple.aasm_events
|
|
205
200
|
end
|
|
206
201
|
|
|
207
202
|
it "should have the same column as it's parent" do
|
|
208
|
-
|
|
203
|
+
Derivate.aasm_column.should == :status
|
|
209
204
|
end
|
|
210
205
|
end
|
|
211
206
|
|
|
212
207
|
describe AASM::Persistence::ActiveRecordPersistence::NamedScopeMethods do
|
|
213
|
-
class NamedScopeExample < ActiveRecord::Base
|
|
214
|
-
include AASM
|
|
215
|
-
end
|
|
216
208
|
|
|
217
209
|
context "Does not already respond_to? the scope name" do
|
|
218
210
|
it "should add a scope" do
|
|
219
|
-
|
|
220
|
-
|
|
211
|
+
Simple.should_not respond_to(:unknown_scope)
|
|
212
|
+
Simple.aasm_state :unknown_scope
|
|
213
|
+
Simple.should respond_to(:unknown_scope)
|
|
214
|
+
Simple.unknown_scope.class.should == ActiveRecord::Relation
|
|
221
215
|
end
|
|
222
216
|
end
|
|
223
217
|
|
|
224
218
|
context "Already respond_to? the scope name" do
|
|
225
219
|
it "should not add a scope" do
|
|
226
|
-
|
|
227
|
-
|
|
220
|
+
Simple.aasm_state :new
|
|
221
|
+
Simple.should respond_to(:new)
|
|
222
|
+
Simple.new.class.should == Simple
|
|
228
223
|
end
|
|
229
224
|
end
|
|
230
225
|
end
|
|
231
226
|
|
|
232
227
|
describe 'Thieves' do
|
|
233
|
-
before(:each) do
|
|
234
|
-
connection = mock(Connection, :columns => [])
|
|
235
|
-
Thief.stub!(:connection).and_return(connection)
|
|
236
|
-
end
|
|
237
228
|
|
|
238
229
|
it 'should be rich if they\'re skilled' do
|
|
239
230
|
Thief.new(:skilled => true).aasm_current_state.should == :rich
|
data/spec/unit/event_spec.rb
CHANGED
|
@@ -48,6 +48,20 @@ describe AASM::SupportingClasses::Event, 'when firing an event' do
|
|
|
48
48
|
|
|
49
49
|
event.fire(obj).should == :closed
|
|
50
50
|
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
it 'should call the guard with the params passed in' do
|
|
54
|
+
event = AASM::SupportingClasses::Event.new(:event) do
|
|
55
|
+
transitions :to => :closed, :from => [:open, :received], :guard => :guard_fn
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
obj = mock('object')
|
|
59
|
+
obj.stub!(:aasm_current_state).and_return(:open)
|
|
60
|
+
obj.should_receive(:guard_fn).with('arg1', 'arg2').and_return(true)
|
|
61
|
+
|
|
62
|
+
event.fire(obj, nil, 'arg1', 'arg2').should == :closed
|
|
63
|
+
end
|
|
64
|
+
|
|
51
65
|
end
|
|
52
66
|
|
|
53
67
|
describe AASM::SupportingClasses::Event, 'when executing the success callback' do
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'active_record'
|
|
3
|
+
require 'logger'
|
|
4
|
+
require 'i18n'
|
|
5
|
+
|
|
6
|
+
ActiveRecord::Base.logger = Logger.new(STDERR)
|
|
7
|
+
|
|
8
|
+
class LocalizerTestModel < ActiveRecord::Base
|
|
9
|
+
include AASM
|
|
10
|
+
|
|
11
|
+
attr_accessor :aasm_state
|
|
12
|
+
|
|
13
|
+
aasm_initial_state :open
|
|
14
|
+
aasm_state :opened
|
|
15
|
+
aasm_state :closed
|
|
16
|
+
|
|
17
|
+
aasm_event :close
|
|
18
|
+
aasm_event :open
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe AASM::Localizer do
|
|
22
|
+
before(:all) do
|
|
23
|
+
I18n.load_path << 'spec/en.yml'
|
|
24
|
+
I18n.default_locale = :en
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
after(:all) { I18n.load_path.clear }
|
|
28
|
+
|
|
29
|
+
let (:foo_opened) { LocalizerTestModel.new }
|
|
30
|
+
let (:foo_closed) { LocalizerTestModel.new.tap { |x| x.aasm_state = :closed } }
|
|
31
|
+
|
|
32
|
+
context '.human_state' do
|
|
33
|
+
it 'should return translated state value' do
|
|
34
|
+
foo_opened.human_state.should == "It's opened now!"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'should return humanized value if not localized' do
|
|
38
|
+
foo_closed.human_state.should == "Closed"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
context '.human_event_name' do
|
|
43
|
+
it 'should return translated event name' do
|
|
44
|
+
LocalizerTestModel.human_event_name(:close).should == "Let's close it!"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'should return humanized event name' do
|
|
48
|
+
LocalizerTestModel.human_event_name(:open).should == "Open"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -82,3 +82,82 @@ describe AASM::SupportingClasses::StateTransition, '- when performing guard chec
|
|
|
82
82
|
st.perform(obj)
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
|
+
|
|
86
|
+
describe AASM::SupportingClasses::StateTransition, '- when executing the transition with a Proc' do
|
|
87
|
+
it 'should call a Proc on the object with args' do
|
|
88
|
+
opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {|o| o.test}}
|
|
89
|
+
st = AASM::SupportingClasses::StateTransition.new(opts)
|
|
90
|
+
args = {:arg1 => '1', :arg2 => '2'}
|
|
91
|
+
obj = mock('object')
|
|
92
|
+
|
|
93
|
+
opts[:on_transition].should_receive(:call).with(any_args)
|
|
94
|
+
|
|
95
|
+
st.execute(obj, args)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'should call a Proc on the object without args' do
|
|
99
|
+
opts = {:from => 'foo', :to => 'bar', :on_transition => Proc.new {||}}
|
|
100
|
+
st = AASM::SupportingClasses::StateTransition.new(opts)
|
|
101
|
+
args = {:arg1 => '1', :arg2 => '2'}
|
|
102
|
+
obj = mock('object')
|
|
103
|
+
|
|
104
|
+
opts[:on_transition].should_receive(:call).with(no_args)
|
|
105
|
+
|
|
106
|
+
st.execute(obj, args)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe AASM::SupportingClasses::StateTransition, '- when executing the transition with an :on_transtion method call' do
|
|
111
|
+
it 'should accept a String for the method name' do
|
|
112
|
+
opts = {:from => 'foo', :to => 'bar', :on_transition => 'test'}
|
|
113
|
+
st = AASM::SupportingClasses::StateTransition.new(opts)
|
|
114
|
+
args = {:arg1 => '1', :arg2 => '2'}
|
|
115
|
+
obj = mock('object')
|
|
116
|
+
|
|
117
|
+
obj.should_receive(:test)
|
|
118
|
+
|
|
119
|
+
st.execute(obj, args)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it 'should accept a Symbol for the method name' do
|
|
123
|
+
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
|
124
|
+
st = AASM::SupportingClasses::StateTransition.new(opts)
|
|
125
|
+
args = {:arg1 => '1', :arg2 => '2'}
|
|
126
|
+
obj = mock('object')
|
|
127
|
+
|
|
128
|
+
obj.should_receive(:test)
|
|
129
|
+
|
|
130
|
+
st.execute(obj, args)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'should pass args if the target method accepts them' do
|
|
134
|
+
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
|
135
|
+
st = AASM::SupportingClasses::StateTransition.new(opts)
|
|
136
|
+
args = {:arg1 => '1', :arg2 => '2'}
|
|
137
|
+
obj = mock('object')
|
|
138
|
+
|
|
139
|
+
obj.class.class_eval do
|
|
140
|
+
define_method(:test) {|*args| 'success'}
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
return_value = st.execute(obj, args)
|
|
144
|
+
|
|
145
|
+
return_value.should == 'success'
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it 'should NOT pass args if the target method does NOT accept them' do
|
|
149
|
+
opts = {:from => 'foo', :to => 'bar', :on_transition => :test}
|
|
150
|
+
st = AASM::SupportingClasses::StateTransition.new(opts)
|
|
151
|
+
args = {:arg1 => '1', :arg2 => '2'}
|
|
152
|
+
obj = mock('object')
|
|
153
|
+
|
|
154
|
+
obj.class.class_eval do
|
|
155
|
+
define_method(:test) {|*args| 'success'}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
return_value = st.execute(obj, args)
|
|
159
|
+
|
|
160
|
+
return_value.should == 'success'
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|
|
@@ -29,6 +29,11 @@ class AuthMachine
|
|
|
29
29
|
transitions :from => [:passive, :pending, :active, :suspended], :to => :deleted
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# a dummy event that can never happen
|
|
33
|
+
aasm_event :unpassify do
|
|
34
|
+
transitions :from => :passive, :to => :active, :guard => Proc.new {|u| false }
|
|
35
|
+
end
|
|
36
|
+
|
|
32
37
|
aasm_event :unsuspend do
|
|
33
38
|
transitions :from => :suspended, :to => :active, :guard => Proc.new {|u| u.has_activated? }
|
|
34
39
|
transitions :from => :suspended, :to => :pending, :guard => Proc.new {|u| u.has_activation_code? }
|
|
@@ -89,6 +94,29 @@ class AuthMachineTest < Test::Unit::TestCase
|
|
|
89
94
|
end
|
|
90
95
|
|
|
91
96
|
context 'when being unsuspended' do
|
|
97
|
+
|
|
98
|
+
should 'be able to be unsuspended' do
|
|
99
|
+
@auth = AuthMachine.new
|
|
100
|
+
@auth.activate!
|
|
101
|
+
@auth.suspend!
|
|
102
|
+
assert @auth.may_unsuspend?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
should 'not be able to be unsuspended into active' do
|
|
106
|
+
@auth = AuthMachine.new
|
|
107
|
+
@auth.suspend!
|
|
108
|
+
assert_equal false, @auth.may_unsuspend?(:active)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
should 'not be able to be unpassified' do
|
|
112
|
+
@auth = AuthMachine.new
|
|
113
|
+
@auth.activate!
|
|
114
|
+
@auth.suspend!
|
|
115
|
+
@auth.unsuspend!
|
|
116
|
+
|
|
117
|
+
assert_equal false, @auth.may_unpassify?
|
|
118
|
+
end
|
|
119
|
+
|
|
92
120
|
should 'be active if previously activated' do
|
|
93
121
|
@auth = AuthMachine.new
|
|
94
122
|
@auth.activate!
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Models
|
|
2
|
+
class Process
|
|
3
|
+
include AASM
|
|
4
|
+
|
|
5
|
+
aasm_state :sleeping
|
|
6
|
+
aasm_state :running
|
|
7
|
+
aasm_state :suspended
|
|
8
|
+
|
|
9
|
+
aasm_event :start do
|
|
10
|
+
transitions :from => :sleeping, :to => :running
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
aasm_event :stop do
|
|
14
|
+
transitions :from => :running, :to => :suspended
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
data/test/test_helper.rb
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'bundler'
|
|
3
|
+
begin
|
|
4
|
+
Bundler.setup(:default, :development)
|
|
5
|
+
rescue Bundler::BundlerError => e
|
|
6
|
+
$stderr.puts e.message
|
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
|
8
|
+
exit e.status_code
|
|
9
|
+
end
|
|
10
|
+
|
|
1
11
|
require 'ostruct'
|
|
2
12
|
require 'rubygems'
|
|
3
13
|
|
|
@@ -23,8 +33,8 @@ class Test::Unit::TestCase
|
|
|
23
33
|
end
|
|
24
34
|
|
|
25
35
|
begin
|
|
26
|
-
require 'ruby-debug'
|
|
27
|
-
|
|
36
|
+
require 'ruby-debug'; Debugger.settings[:autoeval] = true; debugger; rubys_debugger = 'annoying'
|
|
37
|
+
require 'ruby-debug/completion'
|
|
28
38
|
rescue LoadError
|
|
29
39
|
end
|
|
30
40
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
|
2
|
+
|
|
3
|
+
class StateMachineTest < Test::Unit::TestCase
|
|
4
|
+
|
|
5
|
+
context "state machines" do
|
|
6
|
+
|
|
7
|
+
should "be created without memory leak" do
|
|
8
|
+
assert_equal 1, AASM::StateMachine.instance_variable_get("@machines").size # AuthMachine
|
|
9
|
+
assert_number_of_objects AASM::SupportingClasses::State, 5 # AuthMachine
|
|
10
|
+
assert_number_of_objects AASM::SupportingClasses::Event, 11 # AuthMachine
|
|
11
|
+
assert_number_of_objects AASM::SupportingClasses::StateTransition, 19 # AuthMachine
|
|
12
|
+
|
|
13
|
+
load File.expand_path(File.dirname(__FILE__) + '/../models/process.rb')
|
|
14
|
+
assert_equal 2, AASM::StateMachine.instance_variable_get("@machines").size # AuthMachine + Process
|
|
15
|
+
assert_number_of_objects Models::Process, 0
|
|
16
|
+
assert_number_of_objects AASM::SupportingClasses::State, 8 # AuthMachine + Process
|
|
17
|
+
assert_number_of_objects AASM::SupportingClasses::Event, 13 # AuthMachine + Process
|
|
18
|
+
assert_number_of_objects AASM::SupportingClasses::StateTransition, 21 # AuthMachine + Process
|
|
19
|
+
|
|
20
|
+
Models.send(:remove_const, "Process") if Models.const_defined?("Process")
|
|
21
|
+
load File.expand_path(File.dirname(__FILE__) + '/../models/process.rb')
|
|
22
|
+
assert_equal 2, AASM::StateMachine.instance_variable_get("@machines").size # AuthMachine + Process
|
|
23
|
+
assert_number_of_objects AASM::SupportingClasses::State, 8 # AuthMachine + Process
|
|
24
|
+
assert_number_of_objects AASM::SupportingClasses::Event, 13 # AuthMachine + Process
|
|
25
|
+
assert_number_of_objects AASM::SupportingClasses::StateTransition, 21 # AuthMachine + Process
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def assert_number_of_objects(clazz, num)
|
|
33
|
+
count = ObjectSpace.each_object(clazz) {}
|
|
34
|
+
assert_equal num, count, "#{num} expected, but we had #{count} #{clazz}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|