MINT-scxml 1.0.0 → 1.1.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.
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
-