MINT-scxml 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/spec/if_spec.rb ADDED
@@ -0,0 +1,209 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'The StatemachineParser for' do
4
+ describe 'states' do
5
+ begin
6
+ describe 'with if/else' do
7
+ before (:each) do
8
+ @messenger = mock("messenger" )
9
+
10
+ parser = StatemachineParser.new(nil,@messenger)
11
+
12
+ scxml = <<EOS
13
+ <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
14
+ <state id="state1">
15
+ <transition event="event1" target="state2">
16
+ <if cond="1 > 2">
17
+ <log expr="should have failed"/>
18
+ <else/>
19
+ <log expr="should have worked"/>
20
+ </if>
21
+ </transition>
22
+ </state>
23
+
24
+ <state id="state2">
25
+ <transition event="event2" target="state1"/>
26
+ </state>
27
+ </scxml>
28
+ EOS
29
+
30
+ @sm = parser.build_from_scxml_string scxml
31
+ @sm.reset
32
+ end
33
+
34
+ it "should support logging inside a transition" do
35
+ @messenger.should_receive(:puts).with("should have worked" )
36
+ @sm.event1
37
+ end
38
+ end
39
+
40
+ describe 'with if/elseif/else' do
41
+ before (:each) do
42
+ @messenger = mock("messenger" )
43
+
44
+ parser = StatemachineParser.new(nil,@messenger)
45
+
46
+ scxml = <<EOS
47
+ <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
48
+ <state id="state1">
49
+ <transition event="event1" target="state2">
50
+ <if cond="1 > 2">
51
+ <log expr="should have failed"/>
52
+ <elseif cond="1 < 2"/>
53
+ <log expr="should have worked"/>
54
+ <else/>
55
+ <log expr="should not have entered"/>
56
+ </if>
57
+ </transition>
58
+ </state>
59
+
60
+ <state id="state2">
61
+ <transition event="event2" target="state1"/>
62
+ </state>
63
+ </scxml>
64
+ EOS
65
+
66
+ @sm = parser.build_from_scxml_string scxml
67
+ @sm.reset
68
+ end
69
+
70
+ it "should support logging inside a transition" do
71
+ @messenger.should_receive(:puts).with("should have worked" )
72
+ @sm.event1
73
+ end
74
+ end
75
+
76
+ describe 'with nested ifs' do
77
+ before (:each) do
78
+ @messenger = mock("messenger" )
79
+
80
+ parser = StatemachineParser.new(nil,@messenger)
81
+
82
+ scxml = <<EOS
83
+ <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
84
+ <state id="state1">
85
+ <transition event="event1" target="state2">
86
+ <if cond="1 <= 2">
87
+ <if cond="1 == 2">
88
+ <log expr="should have failed"/>
89
+ <else/>
90
+ <log expr="should have worked"/>
91
+ </if>
92
+ <elseif cond="1 > 2"/>
93
+ <log expr="should not have entered"/>
94
+ <else/>
95
+ <log expr="should not have entered"/>
96
+ </if>
97
+ </transition>
98
+ </state>
99
+
100
+ <state id="state2">
101
+ <transition event="event2" target="state1"/>
102
+ </state>
103
+ </scxml>
104
+ EOS
105
+
106
+ @sm = parser.build_from_scxml_string scxml
107
+ @sm.reset
108
+ end
109
+
110
+ it "should support logging inside a transition" do
111
+ @messenger.should_receive(:puts).with("should have worked" )
112
+ @sm.event1
113
+ end
114
+ end
115
+
116
+ describe 'with multiple nested ifs' do
117
+ before (:each) do
118
+ @messenger = mock("messenger" )
119
+
120
+ parser = StatemachineParser.new(nil,@messenger)
121
+
122
+ scxml = <<EOS
123
+ <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
124
+ <state id="state1">
125
+ <transition event="event1" target="state2">
126
+ <if cond="10 < 20">
127
+ <if cond="10 == 20">
128
+ <log expr="should have failed"/>
129
+ <elseif cond="10 <= 15"/>
130
+ <if cond="10 < 15">
131
+ <log expr="should have worked"/>
132
+ </if>
133
+ <else/>
134
+ <log expr="should not have entered"/>
135
+ </if>
136
+ <elseif cond="10 > 20"/>
137
+ <log expr="should not have entered"/>
138
+ <else/>
139
+ <log expr="should not have entered"/>
140
+ </if>
141
+ </transition>
142
+ </state>
143
+
144
+ <state id="state2">
145
+ <transition event="event2" target="state1"/>
146
+ </state>
147
+ </scxml>
148
+ EOS
149
+
150
+ @sm = parser.build_from_scxml_string scxml
151
+ @sm.reset
152
+ end
153
+
154
+ it "should support logging inside a transition" do
155
+ @messenger.should_receive(:puts).with("should have worked" )
156
+ @sm.event1
157
+ end
158
+ end
159
+ describe 'with multiple nested ifs' do
160
+ before (:each) do
161
+ @messenger = mock("messenger" )
162
+
163
+ parser = StatemachineParser.new(nil,@messenger)
164
+
165
+ scxml = <<EOS
166
+ <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
167
+ <state id="state1">
168
+ <transition event="event1" target="state2">
169
+ <if cond="10 < 20">
170
+ <if cond="10 == 20">
171
+ <log expr="should have failed"/>
172
+ <elseif cond="10 <= 15"/>
173
+ <if cond="10 < 15">
174
+ <if cond="10 < 10">
175
+ <log expr="should have failed"/>
176
+ <else/>
177
+ <log expr="should have worked"/>
178
+ </if>
179
+ </if>
180
+ <else/>
181
+ <log expr="should not have entered"/>
182
+ </if>
183
+ <elseif cond="10 > 20"/>
184
+ <log expr="should not have entered"/>
185
+ <else/>
186
+ <log expr="should not have entered"/>
187
+ </if>
188
+ </transition>
189
+ </state>
190
+
191
+ <state id="state2">
192
+ <transition event="event2" target="state1"/>
193
+ </state>
194
+ </scxml>
195
+ EOS
196
+
197
+ @sm = parser.build_from_scxml_string scxml
198
+ @sm.reset
199
+ end
200
+
201
+ it "should support logging inside a transition" do
202
+ @messenger.should_receive(:puts).with("should have worked" )
203
+ @sm.event1
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+
data/spec/parser_spec.rb CHANGED
@@ -2,15 +2,15 @@ require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
3
  describe 'The StatemachineParser for' do
4
4
  describe 'states' do
5
- begin
6
- describe 'without a superstate' do
7
- before (:each) do
8
- @messenger = mock("messenger" )
9
-
10
- parser = StatemachineParser.new(nil,@messenger)
5
+ begin
6
+ describe 'without a superstate' do
7
+ before (:each) do
8
+ @messenger = mock("messenger" )
11
9
 
12
- scxml = <<EOS
13
- <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
10
+ parser = StatemachineParser.new(nil,@messenger)
11
+
12
+ scxml = <<EOS
13
+ <scxml name="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
14
14
  <state id="state1">
15
15
  <transition event="event1" target="state2"/>
16
16
  <transition event="event4" target="state2">
@@ -28,37 +28,38 @@ describe 'The StatemachineParser for' do
28
28
  </scxml>
29
29
  EOS
30
30
 
31
- @sm = parser.build_from_scxml_string scxml
32
- end
33
-
34
- it "should start with the correct initial state without initial attribute set" do
35
- @sm.state.should==:state1
31
+ @sm = parser.build_from_scxml_string scxml
32
+ @sm.reset
33
+ end
34
+
35
+ it "should start with the correct initial state without initial attribute set" do
36
+ @sm.state.should==:state1
37
+ end
38
+
39
+ it "should support transitions " do
40
+ @sm.event1
41
+ @sm.state.should==:state2
42
+ @sm.event2
43
+ @sm.state.should==:state3
44
+ @sm.event3
45
+ @sm.state.should==:state1
46
+ end
47
+
48
+ it "should support logging inside a transition" do
49
+ @messenger.should_receive(:puts).with("transition executing" )
50
+ @sm.event4
51
+ end
36
52
  end
37
53
 
38
- it "should support transitions " do
39
- @sm.event1
40
- @sm.state.should==:state2
41
- @sm.event2
42
- @sm.state.should==:state3
43
- @sm.event3
44
- @sm.state.should==:state1
45
- end
54
+ describe "in the same superstate" do
55
+ before (:each) do
56
+ @messenger = mock("messenger" )
46
57
 
47
- it "should support logging inside a transition" do
48
- @messenger.should_receive(:puts).with("transition executing" )
49
- @sm.event4
50
- end
51
- end
52
-
53
- describe "in the same superstate" do
54
- before (:each) do
55
- @messenger = mock("messenger" )
56
-
57
- parser = StatemachineParser.new(nil,@messenger)
58
+ parser = StatemachineParser.new(nil,@messenger)
58
59
 
59
- scxml = <<EOS
60
+ scxml = <<EOS
60
61
  <?xml version="1.0"?>
61
- <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" profile="ecmascript" initial="off">
62
+ <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" profile="ecmascript">
62
63
  <state id="super" initial="child2">
63
64
  <state id="child1">
64
65
  <transition event="event1" target="child2">
@@ -78,31 +79,32 @@ EOS
78
79
  </state>
79
80
  </scxml>
80
81
  EOS
81
- @sm = parser.build_from_scxml_string scxml
82
- end
83
-
84
- it "should start with the correct state" do
85
- @sm.state.should==:child2
86
- end
87
-
88
- it "should support transitions and logging inside transitions" do
89
- @messenger.should_receive(:puts).with("'This is action2'" )
90
- @sm.event2
91
- @sm.state.should==:child3
92
-
93
- @messenger.should_receive(:puts).with("'This is action3'" )
94
- @sm.event3
95
- @sm.state.should==:child1
96
-
97
- @messenger.should_receive(:puts).with("'This is action1'" )
98
- @sm.event1
99
- @sm.state.should==:child2
100
- end
101
-
102
- it 'should start with the correct state even if the initial state has not been explicitly set' do
103
- scxml = <<EOS
82
+ @sm = parser.build_from_scxml_string scxml
83
+ @sm.reset
84
+ end
85
+
86
+ it "should start with the correct state" do
87
+ @sm.state.should==:child2
88
+ end
89
+
90
+ it "should support transitions and logging inside transitions" do
91
+ @messenger.should_receive(:puts).with("'This is action2'" )
92
+ @sm.event2
93
+ @sm.state.should==:child3
94
+
95
+ @messenger.should_receive(:puts).with("'This is action3'" )
96
+ @sm.event3
97
+ @sm.state.should==:child1
98
+
99
+ @messenger.should_receive(:puts).with("'This is action1'" )
100
+ @sm.event1
101
+ @sm.state.should==:child2
102
+ end
103
+
104
+ it 'should start with the correct state even if the initial state has not been explicitly set' do
105
+ scxml = <<EOS
104
106
  <?xml version="1.0"?>
105
- <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" profile="ecmascript" initial="off">
107
+ <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" profile="ecmascript">
106
108
  <state id="state">
107
109
  <state id="state1">
108
110
  <transition event="event1" target="state2">
@@ -117,19 +119,21 @@ EOS
117
119
  </state>
118
120
  </scxml>
119
121
  EOS
120
- parser = StatemachineParser.new
121
- @sm = parser.build_from_scxml_string scxml
122
- @sm.state.should==:state1
123
-
124
- end
125
- end
126
- describe "in double nested superstates" do
127
- before (:each) do
122
+ parser = StatemachineParser.new
123
+ @sm = parser.build_from_scxml_string scxml
124
+ @sm.reset
125
+ @sm.state.should==:state1
128
126
 
129
- parser = StatemachineParser.new
130
- scxml = <<EOS
127
+ end
128
+ end
129
+
130
+ describe "in double nested superstates" do
131
+ before (:each) do
132
+
133
+ parser = StatemachineParser.new
134
+ scxml = <<EOS
131
135
  <?xml version="1.0"?>
132
- <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" profile="ecmascript" initial="off">
136
+ <scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" profile="ecmascript">
133
137
  <state id="state1" initial="state12">
134
138
  <transition event="to_state2" target="state2"/>
135
139
  <state id="state11" initial="state111">
@@ -150,115 +154,103 @@ EOS
150
154
  </scxml>
151
155
  EOS
152
156
 
153
- @sm = parser.build_from_scxml_string scxml
154
- end
155
-
156
- it "should support starting with the correct inital state that has been excplicitely set" do
157
- @sm.state.should==:state12
158
- @sm.to_state13
159
- @sm.to_state11
160
- @sm.state.should==:state111
161
- end
162
-
163
- it "should support transitions the are defined for a superstate to get into a nested state of the same superstate" do
164
- @sm.to_state13
165
- @sm.to_state11
166
- @sm.to_state111
167
- @sm.state.should==:state111
168
- @sm.to_state12
169
- @sm.state.should==:state12
157
+ @sm = parser.build_from_scxml_string scxml
158
+ @sm.reset
159
+ end
160
+
161
+ it "should support starting with the correct inital state that has been excplicitely set" do
162
+ @sm.state.should==:state12
163
+ @sm.to_state13
164
+ @sm.to_state11
165
+ @sm.state.should==:state111
166
+ end
167
+
168
+ it "should support transitions the are defined for a superstate to get into a nested state of the same superstate" do
169
+ @sm.to_state13
170
+ @sm.to_state11
171
+ @sm.to_state111
172
+ @sm.state.should==:state111
173
+ @sm.to_state12
174
+ @sm.state.should==:state12
175
+ end
176
+ it "should support transitions the are defined for a superstate to get into another state on the same level of the superstate" do
177
+ @sm.to_state13
178
+ @sm.to_state11
179
+ @sm.to_state111
180
+ @sm.state.should==:state111
181
+ @sm.to_state13
182
+ @sm.state.should==:state13
183
+ end
184
+
185
+ it "should support transitions the are defined from a super-superstate " do
186
+ @sm.to_state13
187
+ @sm.to_state11
188
+ @sm.to_state111
189
+ @sm.state.should==:state111
190
+ @sm.to_state2
191
+ @sm.state.should==:state2
192
+ end
170
193
  end
171
- it "should support transitions the are defined for a superstate to get into another state on the same level of the superstate" do
172
- @sm.to_state13
173
- @sm.to_state11
174
- @sm.to_state111
175
- @sm.state.should==:state111
176
- @sm.to_state13
177
- @sm.state.should==:state13
178
- end
179
-
180
- it "should support transitions the are defined from a super-superstate " do
181
- @sm.to_state13
182
- @sm.to_state11
183
- @sm.to_state111
184
- @sm.state.should==:state111
185
- @sm.to_state2
186
- @sm.state.should==:state2
187
- end
188
- end
189
-
190
- describe 'with onentry or onexit' do
191
-
192
- before (:each) do
193
- @messenger = mock("messenger" )
194
-
195
- @message_queue = mock("message_queue" )
196
-
197
- parser = StatemachineParser.new(nil, @messenger, @message_queue)
198
194
 
199
- scxml = <<EOS
195
+ describe 'with spontaneous transitions' do
196
+ before (:each) do
197
+ @log = ""
198
+ parser = StatemachineParser.new(nil,nil)
199
+ scxml = <<EOS
200
200
  <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
201
- <state id="state1">
202
- <transition event="to_state2" target="state2"/>
203
- </state>
204
- <state id="state2">
201
+ <state id="off">
205
202
  <onentry>
206
- <log expr="'inside state2 onentry'"/>
207
- <send type="'x-mint'" target="target" event="fax.SEND"/>
203
+ <script>Proc.new {puts "entering off"}</script>
208
204
  </onentry>
209
205
  <onexit>
210
- <log expr="'inside state2 onexit'"/>
206
+ <script>Proc.new {puts "exiting off"}</script>
211
207
  </onexit>
212
- <transition event="to_state1" target="state1">
213
- <send type="'x-mint'" target="target-2" event="fax.SEND-2"/>
214
- </transition>
208
+ <transition event="toggle" target="on">
209
+ <script>@log += "on"</script>
210
+ </transition>
211
+ <transition target="done" cond="@log == 'onoff'"/>
215
212
  </state>
216
213
 
214
+ <state id="on">
215
+ <transition event="toggle" target="off">
216
+ <script>@log += "off"</script>
217
+ </transition>
218
+ </state>
217
219
  </scxml>
218
220
  EOS
219
221
 
220
- @sm = parser.build_from_scxml_string scxml
221
- end
222
+ @sm = parser.build_from_scxml_string scxml
223
+ @sm.reset
224
+ @sm.context = self
225
+ end
226
+
227
+ it "should be done" do
228
+ @sm.toggle
229
+ @sm.state.should == :on
230
+ @sm.toggle
231
+ @sm.state.should == :done
232
+ end
233
+
234
+ it "should execute inside parallel states as well" do
235
+ parser = StatemachineParser.new(nil,nil)
236
+ @sm = parser.build_from_scxml(File.dirname(__FILE__) + "/testmachines/button.scxml")
237
+ @sm.reset
238
+ @sm.position
239
+ @sm.calculated
240
+ @sm.process_event :display
241
+ @sm.states_id.should == [:displayed,:released]
242
+ end
222
243
 
223
- it "should consider onentry" do
224
- @messenger.should_receive(:puts).with("'inside state2 onentry'" )
225
- @message_queue.should_receive(:send).with("target","fax.SEND")
226
- @sm.to_state2
227
- end
228
-
229
- it "should consider onexit" do
230
- @messenger.should_receive(:puts).with("'inside state2 onentry'" )
231
- @message_queue.should_receive(:send).with("target","fax.SEND")
232
- @sm.to_state2
233
- @messenger.should_receive(:puts).with("'inside state2 onexit'" )
234
- @message_queue.should_receive(:send).with("target-2","fax.SEND-2")
235
- @sm.to_state1
236
- end
237
-
238
- it "should receive send inside onentry" do
239
- @messenger.should_receive(:puts).with("'inside state2 onentry'" )
240
- @message_queue.should_receive(:send).with("target","fax.SEND")
241
- @sm.to_state2
242
- end
243
-
244
- it "should receive send inside a transition" do
245
- @messenger.should_receive(:puts).with("'inside state2 onentry'" )
246
- @message_queue.should_receive(:send).with("target","fax.SEND")
247
- @sm.to_state2
248
- @messenger.should_receive(:puts).with("'inside state2 onexit'" )
249
- @message_queue.should_receive(:send).with("target-2","fax.SEND-2")
250
- @sm.to_state1
251
244
  end
252
245
  end
253
- end
254
246
 
255
- describe 'parallel' do
247
+ describe 'parallel' do
256
248
  before (:each) do
257
249
  parser = StatemachineParser.new
258
250
 
259
251
  scxml = <<EOS
260
252
  <?xml version="1.0"?>
261
- <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
253
+ <scxml name="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
262
254
  <state id="state0">
263
255
  <transition event="to_p" target="parallel"/>
264
256
  </state>
@@ -267,10 +259,10 @@ EOS
267
259
  <parallel id="parallel">
268
260
  <state id="state1">
269
261
  <state id="state11">
270
- <transition event="to_12" cond="In('state22')" target="state12"/>
262
+ <transition event="to_12" cond="In(:state22)" target="state12"/>
271
263
  </state>
272
264
  <state id="state12">
273
- <transition event="to_11" cond="In('state21')" target="state12"/>
265
+ <transition event="to_11" cond="In(:state21)" target="state12"/>
274
266
  </state>
275
267
  </state>
276
268
 
@@ -288,12 +280,20 @@ EOS
288
280
  EOS
289
281
 
290
282
  @sm = parser.build_from_scxml_string scxml
283
+ @sm.reset
291
284
  end
292
285
 
293
286
  it "start with the initial state and transition to the parallel states" do
294
287
  @sm.states_id.should == [:state0]
295
288
  @sm.process_event(:to_p)
296
- @sm.states_id.should == [:state11,:state22]
289
+ @sm.states_id.should == [:state11, :state22]
290
+
291
+ end
292
+
293
+ it "start set active root statemachine state to parallel id after transition to the parallel states" do
294
+ @sm.states_id.should == [:state0]
295
+ @sm.process_event(:to_p)
296
+ @sm.state.should == :parallel
297
297
  end
298
298
 
299
299
  it "support transitions for both parallel superstates" do
@@ -310,9 +310,9 @@ EOS
310
310
  @sm.states_id.should == [:state0]
311
311
  @sm.process_event(:to_p)
312
312
  @sm.process_event(:to_12)
313
- @sm.In(:state12).should == true
313
+ @sm.In(:state12).should == true
314
314
  end
315
-
315
+
316
316
  it "support testing with 'in' condition for superstates " do
317
317
  @sm.states_id.should == [:state0]
318
318
  @sm.process_event(:to_p)
@@ -327,68 +327,325 @@ EOS
327
327
  @sm.In(:state2).should == true
328
328
  @sm.In(:state1).should == true
329
329
  end
330
- end
331
330
 
332
- describe 'with history' do
333
- before (:each) do
331
+ it "should only transition if In is satisfied" do
332
+ @sm.states_id.should == [:state0]
333
+ @sm.process_event(:to_p)
334
+ @sm.process_event(:to_21)
335
+ @sm.states_id.should == [:state11,:state21]
336
+ @sm.process_event(:to_12)
337
+ @sm.states_id.should == [:state11,:state21]
338
+ end
339
+ end
334
340
 
341
+ describe "History States with default history state" do
342
+ before(:each) do
335
343
  parser = StatemachineParser.new
336
344
 
337
345
  scxml = <<EOS
338
- <?xml version="1.0"?>
339
- <scxml id="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
340
- <state id="state0">
341
- <transition event="to_p" target="parallel"/>
346
+ <scxml id="SCXML" initial="state1" name="history" xmlns="http://www.w3.org/2005/07/scxml"><!-- node-size-and-position x=0.0 y=0.0 w=280.0 h=250.0 -->
347
+ <state id="state1"><!-- node-size-and-position x=10.0 y=30.0 w=100.0 h=30.0 -->
348
+ <transition event="to_3" target="state3"></transition>
349
+ </state>
350
+ <state id="state3" initial="state3_1"><!-- node-size-and-position x=140.0 y=30.0 w=130.0 h=200.0 -->
351
+ <transition event="to_1" target="state1"></transition>
352
+ <state id="state3_1"><!-- node-size-and-position x=20.0 y=40.0 w=100.0 h=30.0 -->
353
+ <transition event="to_3_2" target="state3_2"></transition>
342
354
  </state>
343
- <state id="p_super">
344
- <transition event="to_0" target="state0"/>
345
- <parallel id="parallel">
346
- <state id="state1">
347
- <state id="state11">
348
- <transition event="to_12" cond="In('state22')" target="state12"/>
349
- </state>
350
- <state id="state12">
351
- <transition event="to_11" cond="In('state21')" target="state12"/>
352
- </state>
353
- <history id="history" type="deep">
354
- <transition target="state11"/>
355
- </history>
356
- </state>
355
+ <state id="state3_2"><!-- node-size-and-position x=20.0 y=150.0 w=100.0 h=30.0 -->
356
+ <transition event="to_3_1" target="state3_1"><!-- edge-path [state3_1] x=110.0 y=110.0 --></transition>
357
+ </state>
358
+ <history id="H" type="deep"><!-- node-size-and-position x=10.0 y=110.0 w=40.0 h=30.0 -->
359
+ <transition target="state3_2"></transition>
360
+ </history>
361
+ </state>
362
+ </scxml>
363
+ EOS
357
364
 
358
- <state id="state2" initial="state22">
359
- <state id="state21">
360
- <transition event="to_22" target="state22"/>
361
- </state>
362
- <state id="state22">
363
- <transition event="to_21" target="state21"/>
364
- </state>
365
- </state>
366
- </parallel>
365
+ @sm = parser.build_from_scxml_string scxml
366
+ @sm.reset
367
+ end
368
+
369
+
370
+ it "default history" do
371
+ @sm.process_event(:to_3)
372
+ @sm.state.should eql(:state3_2)
373
+ end
374
+
375
+ it "reseting the statemachine resets history" do
376
+ @sm.process_event(:to_3)
377
+ @sm.process_event(:to_3_1)
378
+ @sm.process_event(:to_1)
379
+ @sm.get_state(:state3).history_id.should eql(:state3_1)
380
+
381
+ @sm.reset
382
+ @sm.get_state(:state3).history_id.should eql(:state3_2)
383
+ end
384
+ end
385
+
386
+ describe "History States without default history state" do
387
+ before(:each) do
388
+ parser = StatemachineParser.new
389
+
390
+ scxml = <<EOS
391
+ <scxml id="SCXML" initial="state1" name="history" xmlns="http://www.w3.org/2005/07/scxml"><!-- node-size-and-position x=0.0 y=0.0 w=280.0 h=250.0 -->
392
+ <state id="state1"><!-- node-size-and-position x=10.0 y=30.0 w=100.0 h=30.0 -->
393
+ <transition event="to_3" target="state3"></transition>
394
+ </state>
395
+ <state id="state3" initial="state3_1"><!-- node-size-and-position x=140.0 y=30.0 w=130.0 h=200.0 -->
396
+ <transition event="to_1" target="state1"></transition>
397
+ <state id="state3_1"><!-- node-size-and-position x=20.0 y=40.0 w=100.0 h=30.0 -->
398
+ <transition event="to_3_2" target="state3_2"></transition>
399
+ </state>
400
+ <state id="state3_2"><!-- node-size-and-position x=20.0 y=150.0 w=100.0 h=30.0 -->
401
+ <transition event="to_3_1" target="state3_1"><!-- edge-path [state3_1] x=110.0 y=110.0 --></transition>
367
402
  </state>
403
+ <history id="H" type="deep"><!-- node-size-and-position x=10.0 y=110.0 w=40.0 h=30.0 -->
404
+ </history>
405
+ </state>
368
406
  </scxml>
369
407
  EOS
370
408
 
371
409
  @sm = parser.build_from_scxml_string scxml
410
+ @sm.reset
372
411
  end
373
412
 
374
- it "start with the initial state and transition to the parallel states" do
375
- @sm.states_id.should == [:state0]
376
- @sm.process_event(:to_p)
377
- @sm.states_id.should == [:state11,:state22]
413
+
414
+ it "reseting the statemachine resets history" do
415
+ @sm.process_event(:to_3)
416
+ @sm.process_event(:to_1)
417
+ @sm.get_state(:state3).history_id.should eql(:state3_1)
418
+
419
+ @sm.reset
420
+ @sm.get_state(:state3).history_id.should eql(nil)
378
421
  end
422
+ end
379
423
 
380
- it "should leave the parallel states and return in the correct states" do
381
- @sm.states_id.should == [:state0]
382
- @sm.process_event(:to_p)
383
- @sm.states_id.should == [:state11,:state22]
384
- @sm.process_event(:to_12)
385
- @sm.states_id.should == [:state12,:state22]
386
- @sm.process_event(:to_0)
387
- @sm.states_id.should == [:state0]
388
- @sm.process_event(:to_p)
389
- @sm.states_id.should == [:state12,:state22]
424
+ describe "Nested Superstates" do
425
+ before(:each) do
426
+ parser = StatemachineParser.new
427
+
428
+ scxml = <<EOS
429
+ <scxml id="SCXML" initial="grandpa" name="history" xmlns="http://www.w3.org/2005/07/scxml"><!-- node-size-and-position x=0.0 y=0.0 w=250.0 h=270.0 -->
430
+ <state id="grandpa" initial="start"><!-- node-size-and-position x=10.0 y=30.0 w=230.0 h=110.0 -->
431
+ <transition event="sister" target="great_auntie"></transition>
432
+ <state id="papa" initial="son"><!-- node-size-and-position x=10.0 y=30.0 w=150.0 h=70.0 -->
433
+ <state id="daughter"><!-- node-size-and-position x=70.0 y=30.0 w=70.0 h=30.0 --></state>
434
+ <state id="son"><!-- node-size-and-position x=10.0 y=30.0 w=50.0 h=30.0 --></state>
435
+ </state>
436
+ <state id="start"><!-- node-size-and-position x=170.0 y=30.0 w=50.0 h=30.0 -->
437
+ <transition event="go" target="daughter"></transition>
438
+ </state>
439
+ <history id="H" type="deep"><!-- node-size-and-position x=180.0 y=70.0 w=30.0 h=30.0 --></history>
440
+ </state>
441
+ <state id="great_auntie"><!-- node-size-and-position x=100.0 y=230.0 w=100.0 h=30.0 -->
442
+ <transition event="foo" target="grandpa"><!-- edge-path [grandpa] x=200.0 y=200.0 --></transition>
443
+ </state>
444
+ </scxml>
445
+ EOS
446
+
447
+ @sm = parser.build_from_scxml_string scxml
448
+ @sm.reset
390
449
  end
391
- end
450
+
451
+ it "should use history of sub superstates when transitioning itto it's own history" do
452
+ @sm.go
453
+ @sm.sister
454
+ @sm.foo
455
+
456
+ @sm.state.should eql(:daughter)
457
+ end
458
+ end
459
+
460
+ describe "On_entry and on_exit actions in" do
461
+ begin
462
+ describe 'states' do
463
+
464
+ before (:each) do
465
+ @messenger = mock("messenger" )
466
+
467
+ @message_queue = mock("message_queue" )
468
+
469
+ parser = StatemachineParser.new(nil, @messenger, @message_queue)
470
+
471
+ scxml = <<EOS
472
+ <scxml name="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
473
+ <state id="state1">
474
+ <transition event="to_state2" target="state2"/>
475
+ </state>
476
+ <state id="state2">
477
+ <onentry>
478
+ <log expr="'inside state2 onentry'"/>
479
+ <send type="'x-mint'" target="target" event="fax.SEND"/>
480
+ </onentry>
481
+ <onexit>
482
+ <log expr="'inside state2 onexit'"/>
483
+ </onexit>
484
+ <transition event="to_state1" target="state1">
485
+ <send type="'x-mint'" target="target-2" event="fax.SEND-2"/>
486
+ </transition>
487
+ </state>
488
+
489
+ </scxml>
490
+ EOS
491
+
492
+ @sm = parser.build_from_scxml_string scxml
493
+ @sm.reset
494
+ end
495
+
496
+ it "should consider onentry" do
497
+ @messenger.should_receive(:puts).with("'inside state2 onentry'" )
498
+ @message_queue.should_receive(:send).with("target","fax.SEND")
499
+ @sm.to_state2
500
+ end
501
+
502
+ it "should consider onexit" do
503
+ @messenger.should_receive(:puts).with("'inside state2 onentry'" )
504
+ @message_queue.should_receive(:send).with("target","fax.SEND")
505
+ @sm.to_state2
506
+ @messenger.should_receive(:puts).with("'inside state2 onexit'" )
507
+ @message_queue.should_receive(:send).with("target-2","fax.SEND-2")
508
+ @sm.to_state1
509
+ end
510
+
511
+ it "should receive send inside onentry" do
512
+ @messenger.should_receive(:puts).with("'inside state2 onentry'" )
513
+ @message_queue.should_receive(:send).with("target","fax.SEND")
514
+ @sm.to_state2
515
+ end
516
+
517
+ it "should receive send inside a transition" do
518
+ @messenger.should_receive(:puts).with("'inside state2 onentry'" )
519
+ @message_queue.should_receive(:send).with("target","fax.SEND")
520
+ @sm.to_state2
521
+ @messenger.should_receive(:puts).with("'inside state2 onexit'" )
522
+ @message_queue.should_receive(:send).with("target-2","fax.SEND-2")
523
+ @sm.to_state1
524
+ end
525
+ end
526
+
527
+ describe 'superstates inside a parallel state' do
528
+ before (:each) do
529
+ def hello_world
530
+ @log = "Hello world!"
531
+ end
532
+
533
+ def goodbye
534
+ @log = "Goodbye cruel world!"
535
+ end
536
+ parser = StatemachineParser.new(nil,nil)
537
+
538
+ scxml = <<EOS
539
+ <scxml initial="disconnected" name="Mouse" version="0.9" xmlns="http://www.w3.org/2005/07/scxml"><!-- node-size-and-position x=0.0 y=0.0 w=662.0 h=660.0 -->
540
+ <state id="disconnected"><!-- node-size-and-position x=280.0 y=60.0 w=100.0 h=50.0 -->
541
+ <transition event="connect" target="connected"></transition>
542
+ </state>
543
+ <parallel id="connected"><!-- node-size-and-position x=70.0 y=190.0 w=500.0 h=470.0 -->
544
+ <transition event="disconnect" target="disconnected"><!-- edge-path [disconnected] x=400.0 y=160.0 --></transition>
545
+ <state id="leftbutton" initial="released"><!-- node-size-and-position x=40.0 y=50.0 w=210.0 h=210.0 -->
546
+ <onentry>
547
+ <script>hello_world</script>
548
+ </onentry>
549
+ <onexit>
550
+ <script>goodbye </script>
551
+ </onexit>
552
+ <state id="released"><!-- node-size-and-position x=20.0 y=50.0 w=140.0 h=40.0 -->
553
+ <transition event="press" target="pressed"><!-- edge-path [pressed] x=60.0 y=110.0 pointx=0.0 pointy=-40.0 offsetx=0.0 offsety=-5.0 --></transition>
554
+ </state>
555
+ <state id="pressed"><!-- node-size-and-position x=30.0 y=140.0 w=120.0 h=40.0 -->
556
+ <transition event="release" target="released"><!-- edge-path [released] x=140.0 y=120.0 --></transition>
557
+ </state>
558
+ </state>
559
+ <state id="pointer" initial="stopped"><!-- node-size-and-position x=270.0 y=50.0 w=210.0 h=210.0 -->
560
+ <state id="stopped"><!-- node-size-and-position x=50.0 y=60.0 w=100.0 h=40.0 -->
561
+ <transition event="move" target="moving"><!-- edge-path [moving] x=140.0 y=120.0 --></transition>
562
+ </state>
563
+ <state id="moving"><!-- node-size-and-position x=30.0 y=150.0 w=100.0 h=40.0 -->
564
+ <transition event="stop" target="stopped"><!-- edge-path [stopped] x=50.0 y=130.0 pointx=0.0 pointy=2.0 offsetx=-15.0 offsety=-2.0 --></transition>
565
+ </state>
566
+ </state>
567
+ </parallel>
568
+ </scxml>
569
+ EOS
570
+
571
+ @sm = parser.build_from_scxml_string scxml
572
+ @sm.reset
573
+ @sm.context = self
574
+ end
575
+
576
+ it "should support on entry for superstate inside a parallel state" do
577
+ @sm.connect
578
+ @log.should=="Hello world!"
579
+ end
580
+
581
+ it "should support on exit for superstate inside a parallel state" do
582
+ @sm.connect
583
+ @sm.disconnect
584
+ @log.should=="Goodbye cruel world!"
585
+ end
586
+
587
+ end
588
+
589
+ describe 'parallel states' do
590
+ before (:each) do
591
+ def hello_world
592
+ @log = "Hello world!"
593
+ end
594
+ def goodbye
595
+ @log = "Goodbye cruel world!"
596
+ end
597
+ parser = StatemachineParser.new(nil,nil)
598
+
599
+ scxml = <<EOS
600
+ <scxml initial="disconnected" name="Mouse" version="0.9" xmlns="http://www.w3.org/2005/07/scxml"><!-- node-size-and-position x=0.0 y=0.0 w=662.0 h=660.0 -->
601
+ <state id="disconnected"><!-- node-size-and-position x=280.0 y=60.0 w=100.0 h=50.0 -->
602
+ <transition event="connect" target="connected"></transition>
603
+ </state>
604
+ <parallel id="connected"><!-- node-size-and-position x=70.0 y=190.0 w=500.0 h=470.0 -->
605
+ <onentry>
606
+ <script>hello_world</script>
607
+ </onentry>
608
+ <onexit>
609
+ <script>goodbye </script>
610
+ </onexit>
611
+ <transition event="disconnect" target="disconnected"><!-- edge-path [disconnected] x=400.0 y=160.0 --></transition>
612
+ <state id="leftbutton" initial="released"><!-- node-size-and-position x=40.0 y=50.0 w=210.0 h=210.0 -->
613
+ <state id="released"><!-- node-size-and-position x=20.0 y=50.0 w=140.0 h=40.0 -->
614
+ <transition event="press" target="pressed"><!-- edge-path [pressed] x=60.0 y=110.0 pointx=0.0 pointy=-40.0 offsetx=0.0 offsety=-5.0 --></transition>
615
+ </state>
616
+ <state id="pressed"><!-- node-size-and-position x=30.0 y=140.0 w=120.0 h=40.0 -->
617
+ <transition event="release" target="released"><!-- edge-path [released] x=140.0 y=120.0 --></transition>
618
+ </state>
619
+ </state>
620
+ <state id="pointer" initial="stopped"><!-- node-size-and-position x=270.0 y=50.0 w=210.0 h=210.0 -->
621
+ <state id="stopped"><!-- node-size-and-position x=50.0 y=60.0 w=100.0 h=40.0 -->
622
+ <transition event="move" target="moving"><!-- edge-path [moving] x=140.0 y=120.0 --></transition>
623
+ </state>
624
+ <state id="moving"><!-- node-size-and-position x=30.0 y=150.0 w=100.0 h=40.0 -->
625
+ <transition event="stop" target="stopped"><!-- edge-path [stopped] x=50.0 y=130.0 pointx=0.0 pointy=2.0 offsetx=-15.0 offsety=-2.0 --></transition>
626
+ </state>
627
+ </state>
628
+ </parallel>
629
+ </scxml>
630
+ EOS
631
+
632
+ @sm = parser.build_from_scxml_string scxml
633
+ @sm.reset
634
+ @sm.context = self
635
+ end
636
+
637
+ it "should support on entry for parallel states" do
638
+ @sm.connect
639
+ @log.should=="Hello world!"
640
+ end
641
+
642
+ it "should support on exit for parallel states" do
643
+ @sm.connect
644
+ @sm.disconnect
645
+ @log.should=="Goodbye cruel world!"
646
+ end
647
+ end
648
+ end
649
+ end
392
650
  end
393
651
  end
394
-