jssm 5.35.4 → 5.42.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.
- package/.codeclimate.yml +22 -22
- package/.editorconfig +12 -12
- package/.eslintrc +20 -20
- package/.nycrc +6 -6
- package/.travis.yml +8 -8
- package/LICENSE.md +21 -21
- package/README.md +997 -993
- package/dist/es6/jssm-dot.d.ts +6 -6
- package/dist/es6/jssm-dot.js +1 -1
- package/dist/es6/jssm.d.ts +100 -100
- package/dist/es6/jssm.js +792 -792
- package/dist/es6/jssm_types.d.ts +151 -151
- package/dist/es6/jssm_types.js +1 -1
- package/dist/es6/jssm_util.d.ts +8 -8
- package/dist/es6/jssm_util.js +34 -34
- package/dist/es6/version.d.ts +2 -2
- package/dist/es6/version.js +2 -2
- package/dist/jssm.es5.cjs.js +1 -1
- package/dist/jssm.es5.iife.js +1 -0
- package/jest-spec.config.js +27 -27
- package/jest-stoch.config.js +27 -27
- package/jssm-dot.d.ts +6 -6
- package/jssm.d.ts +100 -100
- package/jssm_types.d.ts +151 -151
- package/jssm_util.d.ts +8 -8
- package/package.json +125 -122
- package/rollup.config.iife.js +44 -44
- package/rollup.config.js +44 -44
- package/src/demo/index.html +38 -38
- package/src/demo/style.css +1 -1
- package/src/ts/jssm-dot.peg +928 -874
- package/src/ts/jssm.ts +1120 -1120
- package/src/ts/jssm_types.ts +346 -346
- package/src/ts/jssm_util.ts +100 -100
- package/src/ts/tests/actions.spec.ts +167 -167
- package/src/ts/tests/arrange.spec.ts +72 -72
- package/src/ts/tests/arrange.stoch.ts +4 -4
- package/src/ts/tests/array_box_if_string.spec.ts +30 -31
- package/src/ts/tests/array_transitions.spec.ts +129 -129
- package/src/ts/tests/arrow unicode.spec.ts +88 -88
- package/src/ts/tests/arrow.spec.ts +124 -124
- package/src/ts/tests/colors.spec.ts +58 -58
- package/src/ts/tests/comment.spec.ts +134 -134
- package/src/ts/tests/compile.spec.ts +79 -79
- package/src/ts/tests/constants.spec.ts +98 -98
- package/src/ts/tests/cycles.spec.ts +153 -153
- package/src/ts/tests/dot_preamble.spec.ts +16 -16
- package/src/ts/tests/embedded_sm.spec.ts +36 -36
- package/src/ts/tests/flow.spec.ts +22 -22
- package/src/ts/tests/forced transitions.spec.ts +26 -26
- package/src/ts/tests/general.spec.ts +933 -933
- package/src/ts/tests/graph node lists.spec.ts +21 -21
- package/src/ts/tests/histo.spec.ts +24 -24
- package/src/ts/tests/hooks.spec.ts +28 -0
- package/src/ts/tests/language.spec.ts +37 -37
- package/src/ts/tests/language_data/belarussian.json +13 -13
- package/src/ts/tests/language_data/bengali.json +15 -15
- package/src/ts/tests/language_data/emoji.json +21 -21
- package/src/ts/tests/language_data/english.json +16 -16
- package/src/ts/tests/language_data/french.json +16 -16
- package/src/ts/tests/language_data/german.json +16 -16
- package/src/ts/tests/language_data/hebrew.json +16 -16
- package/src/ts/tests/language_data/portuguese.json +12 -12
- package/src/ts/tests/language_data/russian.json +12 -12
- package/src/ts/tests/language_data/spanish.json +17 -17
- package/src/ts/tests/language_data/ukrainian.json +18 -18
- package/src/ts/tests/layout.spec.ts +29 -29
- package/src/ts/tests/machine_attributes.spec.ts +398 -398
- package/src/ts/tests/machine_name.spec.ts +14 -14
- package/src/ts/tests/named lists.spec.ts +24 -19
- package/src/ts/tests/nominated states.spec.ts +133 -133
- package/src/ts/tests/parse actions.spec.ts +32 -32
- package/src/ts/tests/parse.spec.ts +94 -94
- package/src/ts/tests/probability.spec.ts +146 -146
- package/src/ts/tests/r639.spec.ts +27 -27
- package/src/ts/tests/sample_select.spec.ts +173 -173
- package/src/ts/tests/seq.spec.ts +14 -16
- package/src/ts/tests/seq.stoch.ts +83 -0
- package/src/ts/tests/shapes.spec.ts +63 -63
- package/src/ts/tests/sm_tag.spec.ts +37 -37
- package/src/ts/tests/special characters.spec.ts +39 -39
- package/src/ts/tests/state_declaration.spec.ts +214 -200
- package/src/ts/tests/state_style.spec.ts +82 -39
- package/src/ts/tests/stop light.spec.ts +157 -157
- package/src/ts/tests/stripes.spec.ts +52 -52
- package/src/ts/tests/theme.spec.ts +45 -45
- package/src/ts/tests/weighted_histo_key.spec.ts +22 -22
- package/src/ts/tests/weighted_rand_select.spec.ts +27 -27
- package/src/ts/tests/weighted_sample_select.spec.ts +24 -26
- package/src/ts/version.ts +1 -1
- package/tree.txt +1794 -1794
- package/tsconfig.json +27 -27
- package/version.d.ts +2 -2
|
@@ -1,933 +1,933 @@
|
|
|
1
|
-
|
|
2
|
-
/* eslint-disable max-len */
|
|
3
|
-
|
|
4
|
-
import * as jssm from '../jssm';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
test('build-set version number is present', () =>
|
|
11
|
-
expect(typeof jssm.version)
|
|
12
|
-
.toBe('string'));
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
describe('Stochastic weather', () => {
|
|
19
|
-
|
|
20
|
-
new jssm.Machine({
|
|
21
|
-
|
|
22
|
-
start_states: ['breezy'],
|
|
23
|
-
|
|
24
|
-
transitions: [
|
|
25
|
-
|
|
26
|
-
{ from: 'breezy', to: 'breezy', probability: 0.4, kind: 'legal', forced_only: false, main_path: false },
|
|
27
|
-
{ from: 'breezy', to: 'sunny', probability: 0.3, kind: 'legal', forced_only: false, main_path: false },
|
|
28
|
-
{ from: 'breezy', to: 'cloudy', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
29
|
-
{ from: 'breezy', to: 'windy', probability: 0.1, kind: 'legal', forced_only: false, main_path: false },
|
|
30
|
-
{ from: 'breezy', to: 'rain', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
31
|
-
|
|
32
|
-
{ from: 'sunny', to: 'sunny', probability: 0.5, kind: 'legal', forced_only: false, main_path: false },
|
|
33
|
-
{ from: 'sunny', to: 'hot', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
34
|
-
{ from: 'sunny', to: 'breezy', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
35
|
-
{ from: 'sunny', to: 'cloudy', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
36
|
-
{ from: 'sunny', to: 'rain', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
37
|
-
|
|
38
|
-
{ from: 'hot', to: 'hot', probability: 0.75, kind: 'legal', forced_only: false, main_path: false },
|
|
39
|
-
{ from: 'hot', to: 'breezy', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
40
|
-
{ from: 'hot', to: 'sunny', probability: 0.2, kind: 'legal', forced_only: false, main_path: false },
|
|
41
|
-
|
|
42
|
-
{ from: 'cloudy', to: 'cloudy', probability: 0.6, kind: 'legal', forced_only: false, main_path: false },
|
|
43
|
-
{ from: 'cloudy', to: 'sunny', probability: 0.2, kind: 'legal', forced_only: false, main_path: false },
|
|
44
|
-
{ from: 'cloudy', to: 'rain', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
45
|
-
{ from: 'cloudy', to: 'breezy', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
46
|
-
|
|
47
|
-
{ from: 'windy', to: 'windy', probability: 0.3, kind: 'legal', forced_only: false, main_path: false },
|
|
48
|
-
{ from: 'windy', to: 'gale', probability: 0.1, kind: 'legal', forced_only: false, main_path: false },
|
|
49
|
-
{ from: 'windy', to: 'breezy', probability: 0.4, kind: 'legal', forced_only: false, main_path: false },
|
|
50
|
-
{ from: 'windy', to: 'rain', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
51
|
-
{ from: 'windy', to: 'sunny', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
52
|
-
|
|
53
|
-
{ from: 'gale', to: 'gale', probability: 0.65, kind: 'legal', forced_only: false, main_path: false },
|
|
54
|
-
{ from: 'gale', to: 'windy', probability: 0.25, kind: 'legal', forced_only: false, main_path: false },
|
|
55
|
-
{ from: 'gale', to: 'torrent', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
56
|
-
{ from: 'gale', to: 'hot', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
57
|
-
|
|
58
|
-
{ from: 'rain', to: 'rain', probability: 0.3, kind: 'legal', forced_only: false, main_path: false },
|
|
59
|
-
{ from: 'rain', to: 'torrent', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
60
|
-
{ from: 'rain', to: 'windy', probability: 0.1, kind: 'legal', forced_only: false, main_path: false },
|
|
61
|
-
{ from: 'rain', to: 'breezy', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
62
|
-
{ from: 'rain', to: 'sunny', probability: 0.1, kind: 'legal', forced_only: false, main_path: false },
|
|
63
|
-
{ from: 'rain', to: 'cloudy', probability: 0.3, kind: 'legal', forced_only: false, main_path: false },
|
|
64
|
-
|
|
65
|
-
{ from: 'torrent', to: 'torrent', probability: 0.65, kind: 'legal', forced_only: false, main_path: false },
|
|
66
|
-
{ from: 'torrent', to: 'rain', probability: 0.25, kind: 'legal', forced_only: false, main_path: false },
|
|
67
|
-
{ from: 'torrent', to: 'cloudy', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
68
|
-
{ from: 'torrent', to: 'gale', probability: 0.05, kind: 'legal', forced_only: false, main_path: false }
|
|
69
|
-
|
|
70
|
-
]
|
|
71
|
-
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test.todo('Unfinished test case in general spec');
|
|
75
|
-
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
describe('list exit actions', () => {
|
|
83
|
-
|
|
84
|
-
const machine = new jssm.Machine({
|
|
85
|
-
start_states : ['off'],
|
|
86
|
-
transitions : [
|
|
87
|
-
{ from:'off', to:'red', action:'on', kind: 'legal', forced_only: false, main_path: false },
|
|
88
|
-
{ from:'red', to:'off', action:'off', kind: 'legal', forced_only: false, main_path: false }
|
|
89
|
-
]
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
test('shows "on" from off as default', () =>
|
|
93
|
-
expect(machine.list_exit_actions()[0])
|
|
94
|
-
.toBe('on') );
|
|
95
|
-
|
|
96
|
-
test('shows "on" from off', () =>
|
|
97
|
-
expect(machine.list_exit_actions('off')[0])
|
|
98
|
-
.toBe('on') );
|
|
99
|
-
|
|
100
|
-
test('shows "off" from red', () =>
|
|
101
|
-
expect(machine.list_exit_actions('red')[0])
|
|
102
|
-
.toBe('off') );
|
|
103
|
-
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
describe('probable exits for', () => {
|
|
111
|
-
|
|
112
|
-
const machine = new jssm.Machine({
|
|
113
|
-
start_states: ['off'],
|
|
114
|
-
transitions:[ { from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
test('probable exits are an array', () =>
|
|
118
|
-
expect(Array.isArray(machine.probable_exits_for('off')) )
|
|
119
|
-
.toBe(true) );
|
|
120
|
-
|
|
121
|
-
test('one probable exit in example', () =>
|
|
122
|
-
expect(machine.probable_exits_for('off').length)
|
|
123
|
-
.toBe(1) );
|
|
124
|
-
|
|
125
|
-
test('exit is an object', () =>
|
|
126
|
-
expect(typeof machine.probable_exits_for('off')[0])
|
|
127
|
-
.toBe('object') );
|
|
128
|
-
|
|
129
|
-
test('exit 0 has a string from property', () =>
|
|
130
|
-
expect(typeof machine.probable_exits_for('off')[0].from)
|
|
131
|
-
.toBe('string') );
|
|
132
|
-
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
describe('probable action exits', () => {
|
|
140
|
-
|
|
141
|
-
const machine = new jssm.Machine({
|
|
142
|
-
start_states : ['off'],
|
|
143
|
-
transitions : [
|
|
144
|
-
{ from:'off', to:'red', action:'on', kind: 'legal', forced_only: false, main_path: false },
|
|
145
|
-
{ from:'red', to:'off', action:'off', kind: 'legal', forced_only: false, main_path: false }
|
|
146
|
-
]
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
test('probable action exits are an array', () =>
|
|
151
|
-
expect(Array.isArray(machine.probable_action_exits()) )
|
|
152
|
-
.toBe(true) );
|
|
153
|
-
|
|
154
|
-
test('probable action exit 1 is on', () =>
|
|
155
|
-
expect(machine.probable_action_exits()[0].action)
|
|
156
|
-
.toBe('on') );
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
test('probable action exits are an array 2', () =>
|
|
160
|
-
expect(Array.isArray(machine.probable_action_exits('off')) )
|
|
161
|
-
.toBe(true) );
|
|
162
|
-
|
|
163
|
-
test('probable action exit 1 is on 2', () =>
|
|
164
|
-
expect(machine.probable_action_exits('off')[0].action)
|
|
165
|
-
.toBe('on') );
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
test('probable action exits are an array 3', () =>
|
|
169
|
-
expect(Array.isArray(machine.probable_action_exits('red')) )
|
|
170
|
-
.toBe(true) );
|
|
171
|
-
|
|
172
|
-
test('probable action exit 1 is on 3', () =>
|
|
173
|
-
expect(machine.probable_action_exits('red')[0].action)
|
|
174
|
-
.toBe('off') );
|
|
175
|
-
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
describe('probabilistic_transition', () => {
|
|
183
|
-
|
|
184
|
-
const machine = new jssm.Machine({
|
|
185
|
-
start_states : ['off'],
|
|
186
|
-
transitions : [ { from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
machine.probabilistic_transition();
|
|
190
|
-
|
|
191
|
-
test('solo after probabilistic is red', () =>
|
|
192
|
-
expect(machine.state())
|
|
193
|
-
.toBe('red') );
|
|
194
|
-
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
describe('probabilistic_walk', () => {
|
|
202
|
-
|
|
203
|
-
const machine = new jssm.Machine({
|
|
204
|
-
start_states : ['off'],
|
|
205
|
-
transitions : [
|
|
206
|
-
{ from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false },
|
|
207
|
-
{ from: 'red', to: 'off', kind: 'legal', forced_only: false, main_path: false }
|
|
208
|
-
]
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
machine.probabilistic_walk(3);
|
|
212
|
-
|
|
213
|
-
test('solo after probabilistic walk 3 is red', () =>
|
|
214
|
-
expect(machine.state())
|
|
215
|
-
.toBe('red') );
|
|
216
|
-
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
describe('probabilistic_histo_walk', () => {
|
|
224
|
-
|
|
225
|
-
const machine = new jssm.Machine({
|
|
226
|
-
start_states : ['off'],
|
|
227
|
-
transitions : [
|
|
228
|
-
{ from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false },
|
|
229
|
-
{ from: 'red', to: 'off', kind: 'legal', forced_only: false, main_path: false }
|
|
230
|
-
]
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
const histo = machine.probabilistic_histo_walk(3);
|
|
234
|
-
|
|
235
|
-
test('histo is a Map', () =>
|
|
236
|
-
expect(histo instanceof Map)
|
|
237
|
-
.toBe(true) );
|
|
238
|
-
|
|
239
|
-
test('histo red is 2', () =>
|
|
240
|
-
expect(histo.get('red'))
|
|
241
|
-
.toBe(2) );
|
|
242
|
-
|
|
243
|
-
test('histo off is 2', () =>
|
|
244
|
-
expect(histo.get('off'))
|
|
245
|
-
.toBe(2) );
|
|
246
|
-
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
describe('reports state_is_final', () => {
|
|
254
|
-
|
|
255
|
-
const machine = new jssm.Machine({
|
|
256
|
-
start_states: ['off'],
|
|
257
|
-
transitions:[
|
|
258
|
-
{ from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false },
|
|
259
|
-
{ from: 'off', to: 'mid', kind: 'legal', forced_only: false, main_path: false },
|
|
260
|
-
{ from: 'mid', to: 'fin', kind: 'legal', forced_only: false, main_path: false }
|
|
261
|
-
],
|
|
262
|
-
complete:['red', 'mid']
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
test('final false for neither', () =>
|
|
266
|
-
expect(machine.state_is_final('off') )
|
|
267
|
-
.toBe(false) );
|
|
268
|
-
|
|
269
|
-
test('final false for just terminal', () =>
|
|
270
|
-
expect(machine.state_is_final('mid') )
|
|
271
|
-
.toBe(false) );
|
|
272
|
-
|
|
273
|
-
test('final false for just complete', () =>
|
|
274
|
-
expect(machine.state_is_final('fin') )
|
|
275
|
-
.toBe(false) );
|
|
276
|
-
|
|
277
|
-
test('final true', () =>
|
|
278
|
-
expect(machine.state_is_final('red') )
|
|
279
|
-
.toBe(true) );
|
|
280
|
-
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
describe('reports is_final', () => {
|
|
288
|
-
|
|
289
|
-
const machine = new jssm.Machine({
|
|
290
|
-
start_states: ['off'],
|
|
291
|
-
transitions:[
|
|
292
|
-
{ from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
293
|
-
],
|
|
294
|
-
complete:['red']
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
const init_final = machine.is_final();
|
|
298
|
-
machine.transition('red');
|
|
299
|
-
const fin_final = machine.is_final();
|
|
300
|
-
|
|
301
|
-
test('final false', () =>
|
|
302
|
-
expect(init_final)
|
|
303
|
-
.toBe(false) );
|
|
304
|
-
|
|
305
|
-
test('final true', () =>
|
|
306
|
-
expect(fin_final)
|
|
307
|
-
.toBe(true) );
|
|
308
|
-
|
|
309
|
-
// why is this written this way?
|
|
310
|
-
|
|
311
|
-
/* todo whargarbl needs another two tests for is_changing once reintroduced */
|
|
312
|
-
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
describe('reports state_is_terminal', () => {
|
|
320
|
-
|
|
321
|
-
const machine = new jssm.Machine({
|
|
322
|
-
start_states : ['off'],
|
|
323
|
-
transitions : [ { name: 'turn_on', action: 'power_on', from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
test('terminal false', () =>
|
|
327
|
-
expect(machine.state_is_terminal('off') )
|
|
328
|
-
.toBe(false) );
|
|
329
|
-
|
|
330
|
-
test('terminal true', () =>
|
|
331
|
-
expect(machine.state_is_terminal('red') )
|
|
332
|
-
.toBe(true) );
|
|
333
|
-
|
|
334
|
-
test('terminal on missing state throws', () =>
|
|
335
|
-
expect( () => machine.state_is_terminal('notARealState') )
|
|
336
|
-
.toThrow() );
|
|
337
|
-
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
describe('reports is_terminal', () => {
|
|
345
|
-
|
|
346
|
-
const machine = new jssm.Machine({
|
|
347
|
-
start_states : ['off'],
|
|
348
|
-
transitions : [ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false} ]
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
const first = machine.is_terminal();
|
|
352
|
-
machine.transition('red');
|
|
353
|
-
const second = machine.is_terminal();
|
|
354
|
-
|
|
355
|
-
const terms = machine.has_terminals();
|
|
356
|
-
// why is this written this way?
|
|
357
|
-
|
|
358
|
-
test('terminal false', () =>
|
|
359
|
-
expect(first)
|
|
360
|
-
.toBe(false) );
|
|
361
|
-
|
|
362
|
-
test('terminal true', () =>
|
|
363
|
-
expect(second)
|
|
364
|
-
.toBe(true) );
|
|
365
|
-
|
|
366
|
-
test('has_terminals', () =>
|
|
367
|
-
expect(terms)
|
|
368
|
-
.toBe(true) );
|
|
369
|
-
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
describe('reports state_is_complete', () => {
|
|
377
|
-
|
|
378
|
-
const machine = new jssm.Machine({
|
|
379
|
-
start_states: ['off'],
|
|
380
|
-
transitions:[ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false} ],
|
|
381
|
-
complete:['off'] // huhu
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
test('state_is_complete false', () =>
|
|
385
|
-
expect(machine.state_is_complete('off') )
|
|
386
|
-
.toBe(true) );
|
|
387
|
-
|
|
388
|
-
test('state_is_complete true', () =>
|
|
389
|
-
expect(machine.state_is_complete('red') )
|
|
390
|
-
.toBe(false) );
|
|
391
|
-
|
|
392
|
-
test('throws on nonexisting state', () =>
|
|
393
|
-
expect( () => machine.state_is_complete('thisStateDoesNotExist') )
|
|
394
|
-
.toThrow() );
|
|
395
|
-
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
describe('reports is_complete', () => {
|
|
403
|
-
|
|
404
|
-
const machine = new jssm.Machine({
|
|
405
|
-
start_states: ['off'],
|
|
406
|
-
transitions:[ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false} ],
|
|
407
|
-
complete:['off'] // huhu
|
|
408
|
-
});
|
|
409
|
-
|
|
410
|
-
const first = machine.is_complete();
|
|
411
|
-
machine.transition('red');
|
|
412
|
-
const second = machine.is_complete();
|
|
413
|
-
|
|
414
|
-
const terms = machine.has_completes();
|
|
415
|
-
// why is this written this way?
|
|
416
|
-
|
|
417
|
-
test('is_complete false', () =>
|
|
418
|
-
expect(first)
|
|
419
|
-
.toBe(true) );
|
|
420
|
-
|
|
421
|
-
test('is_complete true', () =>
|
|
422
|
-
expect(second)
|
|
423
|
-
.toBe(false) );
|
|
424
|
-
|
|
425
|
-
test('has_completes', () =>
|
|
426
|
-
expect(terms)
|
|
427
|
-
.toBe(true) );
|
|
428
|
-
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
describe('reports on actions', () => {
|
|
436
|
-
|
|
437
|
-
const machine = new jssm.Machine({
|
|
438
|
-
start_states: ['off'],
|
|
439
|
-
transitions:[ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false} ]
|
|
440
|
-
});
|
|
441
|
-
|
|
442
|
-
const a = machine.list_actions(); // todo comeback
|
|
443
|
-
|
|
444
|
-
test('that it has', () =>
|
|
445
|
-
expect(typeof machine.current_action_for('power_on') )
|
|
446
|
-
.toBe('number') );
|
|
447
|
-
|
|
448
|
-
test('that it doesn\'t have', () =>
|
|
449
|
-
expect(typeof machine.current_action_for('power_left') )
|
|
450
|
-
.toBe('undefined') );
|
|
451
|
-
|
|
452
|
-
test('correct list type', () =>
|
|
453
|
-
expect(Array.isArray(a))
|
|
454
|
-
.toBe(true) );
|
|
455
|
-
|
|
456
|
-
test('correct list size', () =>
|
|
457
|
-
expect(a.length)
|
|
458
|
-
.toBe(1) );
|
|
459
|
-
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
describe('actions', () => {
|
|
467
|
-
|
|
468
|
-
const machine = new jssm.Machine({
|
|
469
|
-
start_states : ['off'],
|
|
470
|
-
transitions : [
|
|
471
|
-
{ from:'off', to:'red', action:'on', kind: 'legal', forced_only: false, main_path: false },
|
|
472
|
-
{ from:'red', to:'off', action:'off', kind: 'legal', forced_only: false, main_path: false }
|
|
473
|
-
]
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
test('red has actions().length 1', () =>
|
|
477
|
-
expect(machine.actions().length)
|
|
478
|
-
.toBe(1) );
|
|
479
|
-
|
|
480
|
-
test('red has actions()[0] "on"', () =>
|
|
481
|
-
expect(machine.actions()[0])
|
|
482
|
-
.toBe('on') );
|
|
483
|
-
|
|
484
|
-
test('red has actions().length 1 again', () =>
|
|
485
|
-
expect(machine.actions('off').length)
|
|
486
|
-
.toBe(1) );
|
|
487
|
-
|
|
488
|
-
test('red has actions()[0] "on" again', () =>
|
|
489
|
-
expect(machine.actions('off')[0])
|
|
490
|
-
.toBe('on') );
|
|
491
|
-
|
|
492
|
-
test('red has actions().length 1 re-again', () =>
|
|
493
|
-
expect(machine.actions('red').length)
|
|
494
|
-
.toBe(1) );
|
|
495
|
-
|
|
496
|
-
test('red has actions()[0] "off" re-again',
|
|
497
|
-
() => expect(machine.actions('red')[0])
|
|
498
|
-
.toBe('off') );
|
|
499
|
-
|
|
500
|
-
});
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
describe('states having action', () => {
|
|
507
|
-
|
|
508
|
-
const machine = new jssm.Machine({
|
|
509
|
-
start_states : ['off'],
|
|
510
|
-
transitions : [
|
|
511
|
-
{ from:'off', to: 'red', action: 'on', kind: 'legal', forced_only: false, main_path: false },
|
|
512
|
-
{ from:'red', to: 'off', action: 'off', kind: 'legal', forced_only: false, main_path: false }
|
|
513
|
-
]
|
|
514
|
-
});
|
|
515
|
-
|
|
516
|
-
test('one action has on', () =>
|
|
517
|
-
expect(machine.list_states_having_action('on').length)
|
|
518
|
-
.toBe(1) );
|
|
519
|
-
|
|
520
|
-
test('on is had by off', () =>
|
|
521
|
-
expect(machine.list_states_having_action('on')[0])
|
|
522
|
-
.toBe('off') );
|
|
523
|
-
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
describe('unenterables', () => {
|
|
531
|
-
|
|
532
|
-
const machine = new jssm.Machine({
|
|
533
|
-
start_states: ['off'],
|
|
534
|
-
transitions:[ { name:'turn_on', action: 'power_on', from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
test('off isn\'t enterable', () =>
|
|
538
|
-
expect(machine.is_unenterable('off') )
|
|
539
|
-
.toBe(true) );
|
|
540
|
-
|
|
541
|
-
test('red is enterable', () =>
|
|
542
|
-
expect(machine.is_unenterable('red') )
|
|
543
|
-
.toBe(false) );
|
|
544
|
-
|
|
545
|
-
test('machine has unenterables', () =>
|
|
546
|
-
expect(machine.has_unenterables() )
|
|
547
|
-
.toBe(true) );
|
|
548
|
-
|
|
549
|
-
test('unenterable test on missing state throws', () =>
|
|
550
|
-
expect( () => machine.is_unenterable('notARealState') )
|
|
551
|
-
.toThrow() );
|
|
552
|
-
|
|
553
|
-
});
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
describe('reports on action edges', () => {
|
|
560
|
-
|
|
561
|
-
const machine = new jssm.Machine({
|
|
562
|
-
start_states : ['off'],
|
|
563
|
-
transitions : [
|
|
564
|
-
{ name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
565
|
-
]
|
|
566
|
-
});
|
|
567
|
-
|
|
568
|
-
test('that it has', () =>
|
|
569
|
-
expect(typeof machine.current_action_edge_for('power_on'))
|
|
570
|
-
.toBe('object') );
|
|
571
|
-
|
|
572
|
-
test('that it doesn\'t have', () =>
|
|
573
|
-
expect(() => { machine.current_action_edge_for('power_west'); })
|
|
574
|
-
.toThrow() );
|
|
575
|
-
|
|
576
|
-
});
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
describe('reports on states', () => {
|
|
583
|
-
|
|
584
|
-
const machine = new jssm.Machine({
|
|
585
|
-
start_states : ['off'],
|
|
586
|
-
transitions : [
|
|
587
|
-
{ name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
588
|
-
]
|
|
589
|
-
});
|
|
590
|
-
|
|
591
|
-
test('that it has', () =>
|
|
592
|
-
expect(typeof machine.state_for('off') )
|
|
593
|
-
.toBe('object') );
|
|
594
|
-
|
|
595
|
-
test('that it doesn\'t have', () =>
|
|
596
|
-
expect(() => { machine.state_for('no such state'); })
|
|
597
|
-
.toThrow() );
|
|
598
|
-
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
describe('returns states', () => {
|
|
606
|
-
|
|
607
|
-
const machine = new jssm.Machine({
|
|
608
|
-
start_states : ['off'],
|
|
609
|
-
transitions : [
|
|
610
|
-
{ name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
611
|
-
]
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
test('that it has', () =>
|
|
615
|
-
expect(typeof machine.machine_state() )
|
|
616
|
-
.toBe('object') );
|
|
617
|
-
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
describe('reports on transitions', () => {
|
|
625
|
-
|
|
626
|
-
const machine = new jssm.Machine({
|
|
627
|
-
start_states : ['off'],
|
|
628
|
-
transitions : [
|
|
629
|
-
{ name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
630
|
-
]
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
test('unspecified transition return type', () =>
|
|
635
|
-
expect(typeof machine.list_transitions() )
|
|
636
|
-
.toBe('object') );
|
|
637
|
-
|
|
638
|
-
test('unspecified transition correct entrance count', () =>
|
|
639
|
-
expect(machine.list_transitions().entrances.length)
|
|
640
|
-
.toBe(0) );
|
|
641
|
-
|
|
642
|
-
test('unspecified transition correct exit count', () =>
|
|
643
|
-
expect(machine.list_transitions().exits.length)
|
|
644
|
-
.toBe(1) );
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
test('specified transition return type', () =>
|
|
648
|
-
expect(typeof machine.list_transitions('off') )
|
|
649
|
-
.toBe('object') );
|
|
650
|
-
|
|
651
|
-
test('specified transition correct entrance count', () =>
|
|
652
|
-
expect(machine.list_transitions('off').entrances.length)
|
|
653
|
-
.toBe(0) );
|
|
654
|
-
|
|
655
|
-
test('specified transition correct exit count', () =>
|
|
656
|
-
expect(machine.list_transitions('off').exits.length)
|
|
657
|
-
.toBe(1) );
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
test('no such spec trans return type', () =>
|
|
661
|
-
expect(typeof machine.list_transitions('moot') )
|
|
662
|
-
.toBe('object') );
|
|
663
|
-
|
|
664
|
-
test('no such spec trans correct entrance count', () =>
|
|
665
|
-
expect(machine.list_transitions('moot').entrances.length)
|
|
666
|
-
.toBe(0) );
|
|
667
|
-
|
|
668
|
-
test('no such spec trans correct exit count', () =>
|
|
669
|
-
expect(machine.list_transitions('moot').exits.length)
|
|
670
|
-
.toBe(0) );
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
test('unspecified entrance return type', () =>
|
|
674
|
-
expect(Array.isArray( machine.list_entrances() ))
|
|
675
|
-
.toBe(true) );
|
|
676
|
-
|
|
677
|
-
test('unspecified entrance correct count', () =>
|
|
678
|
-
expect(machine.list_entrances().length)
|
|
679
|
-
.toBe(0) );
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
test('specified entrance return type', () =>
|
|
683
|
-
expect(Array.isArray( machine.list_entrances('off') ))
|
|
684
|
-
.toBe(true) );
|
|
685
|
-
|
|
686
|
-
test('specified entrance correct count', () =>
|
|
687
|
-
expect(machine.list_entrances('off').length)
|
|
688
|
-
.toBe(0) );
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
test('no such specified entrance return type', () =>
|
|
692
|
-
expect(Array.isArray( machine.list_entrances('moot') ))
|
|
693
|
-
.toBe(true) ); // todo whargarbl should these throw?
|
|
694
|
-
|
|
695
|
-
test('no such specified entrance correct count', () =>
|
|
696
|
-
expect(machine.list_entrances('moot').length)
|
|
697
|
-
.toBe(0) );
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
test('unspecified exit return type', () =>
|
|
701
|
-
expect(Array.isArray( machine.list_exits() ))
|
|
702
|
-
.toBe(true) );
|
|
703
|
-
|
|
704
|
-
test('unspecified exit correct count', () =>
|
|
705
|
-
expect(machine.list_exits().length)
|
|
706
|
-
.toBe(1) );
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
test('specified exit return type', () =>
|
|
710
|
-
expect(Array.isArray( machine.list_exits('off') ))
|
|
711
|
-
.toBe(true) );
|
|
712
|
-
|
|
713
|
-
test('specified exit correct count', () =>
|
|
714
|
-
expect(machine.list_exits('off').length)
|
|
715
|
-
.toBe(1) );
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
test('no such specified exit return type', () =>
|
|
719
|
-
expect(Array.isArray( machine.list_exits('moot') ))
|
|
720
|
-
.toBe(true) );
|
|
721
|
-
|
|
722
|
-
test('no such specified exit correct count', () =>
|
|
723
|
-
expect(machine.list_exits('moot').length)
|
|
724
|
-
.toBe(0) );
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
test('edge list return type', () =>
|
|
728
|
-
expect(Array.isArray( machine.list_edges() ))
|
|
729
|
-
.toBe(true) );
|
|
730
|
-
|
|
731
|
-
test('edge list correct count', () =>
|
|
732
|
-
expect(machine.list_edges().length)
|
|
733
|
-
.toBe(1) );
|
|
734
|
-
|
|
735
|
-
});
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
describe('transition by state names', () => {
|
|
742
|
-
|
|
743
|
-
const machine = new jssm.Machine({
|
|
744
|
-
start_states : ['off'],
|
|
745
|
-
transitions : [ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
746
|
-
});
|
|
747
|
-
|
|
748
|
-
test('finds off -> red', () =>
|
|
749
|
-
expect(machine.get_transition_by_state_names('off', 'red') )
|
|
750
|
-
.toBe(0) );
|
|
751
|
-
|
|
752
|
-
test('does not find off -> blue', () =>
|
|
753
|
-
expect(machine.get_transition_by_state_names('off', 'blue') )
|
|
754
|
-
.toBe(undefined) );
|
|
755
|
-
|
|
756
|
-
test('does not find blue -> red', () =>
|
|
757
|
-
expect(machine.get_transition_by_state_names('blue', 'red') )
|
|
758
|
-
.toBe(undefined) );
|
|
759
|
-
|
|
760
|
-
});
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
describe('Illegal machines', () => {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
test('catch repeated names', () => expect( () => {
|
|
770
|
-
|
|
771
|
-
new jssm.Machine({
|
|
772
|
-
start_states: ['moot'],
|
|
773
|
-
transitions:[
|
|
774
|
-
{ name: 'identical', from: '1', to: '2', kind: 'legal', forced_only: false, main_path: false },
|
|
775
|
-
{ name: 'identical', from: '2', to: '3', kind: 'legal', forced_only: false, main_path: false }
|
|
776
|
-
]
|
|
777
|
-
});
|
|
778
|
-
|
|
779
|
-
}).toThrow() );
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
test('must define from', () => expect( () => {
|
|
783
|
-
|
|
784
|
-
new jssm.Machine({
|
|
785
|
-
start_states: ['moot'],
|
|
786
|
-
transitions:[
|
|
787
|
-
{ name:'identical', to:'2', kind: 'legal', forced_only: false, main_path: false }
|
|
788
|
-
]
|
|
789
|
-
} as any);
|
|
790
|
-
|
|
791
|
-
}).toThrow() );
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
test('must define to', () => expect( () => {
|
|
795
|
-
|
|
796
|
-
new jssm.Machine({
|
|
797
|
-
start_states: ['moot'],
|
|
798
|
-
transitions:[
|
|
799
|
-
{ name:'identical', from:'1', kind: 'legal', forced_only: false, main_path: false }
|
|
800
|
-
]
|
|
801
|
-
} as any);
|
|
802
|
-
|
|
803
|
-
}).toThrow() );
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
test('must not have two identical edges', () => expect( () => {
|
|
807
|
-
|
|
808
|
-
new jssm.Machine({
|
|
809
|
-
start_states: ['moot'],
|
|
810
|
-
transitions:[
|
|
811
|
-
{ name:'id1', from:'1', to:'2', kind: 'legal', forced_only: false, main_path: false },
|
|
812
|
-
{ name:'id2', from:'1', to:'2', kind: 'legal', forced_only: false, main_path: false }
|
|
813
|
-
]
|
|
814
|
-
});
|
|
815
|
-
|
|
816
|
-
}).toThrow() );
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
test('must not have two of the same action from the same source', () => expect( () => {
|
|
820
|
-
|
|
821
|
-
new jssm.Machine({
|
|
822
|
-
start_states: ['moot'],
|
|
823
|
-
transitions:[
|
|
824
|
-
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false },
|
|
825
|
-
{ name:'id2', from:'1', to:'3', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
826
|
-
]
|
|
827
|
-
});
|
|
828
|
-
|
|
829
|
-
}).toThrow() );
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
test.todo('Does is_complete need an argument?');
|
|
833
|
-
|
|
834
|
-
// test('must not have completion of non-state', () => expect( () => {
|
|
835
|
-
|
|
836
|
-
// const machine = new jssm.Machine({
|
|
837
|
-
// start_states: ['moot'],
|
|
838
|
-
// transitions:[
|
|
839
|
-
// { name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
840
|
-
// ]
|
|
841
|
-
// });
|
|
842
|
-
|
|
843
|
-
// machine.is_complete('no such state');
|
|
844
|
-
|
|
845
|
-
// }).toThrow() );
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
test.todo('is the _new_state api misunderstood in these tests?')
|
|
849
|
-
|
|
850
|
-
// test('internal state helper must not accept double states', () => expect( () => {
|
|
851
|
-
|
|
852
|
-
// const machine = new jssm.Machine({
|
|
853
|
-
// start_states: ['moot'],
|
|
854
|
-
// transitions:[
|
|
855
|
-
// { name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
856
|
-
// ]
|
|
857
|
-
// });
|
|
858
|
-
|
|
859
|
-
// machine._new_state({from: '1', name:'id1', to:'2', complete:false});
|
|
860
|
-
// machine._new_state({from: '1', name:'id1', to:'2', complete:false});
|
|
861
|
-
|
|
862
|
-
// }).toThrow() );
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
test('can\'t get actions of non-state', () => expect( () => {
|
|
866
|
-
|
|
867
|
-
const machine = new jssm.Machine({
|
|
868
|
-
start_states: ['1'],
|
|
869
|
-
transitions:[
|
|
870
|
-
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
871
|
-
]
|
|
872
|
-
});
|
|
873
|
-
|
|
874
|
-
machine.actions('three');
|
|
875
|
-
|
|
876
|
-
}).toThrow() );
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
test('can\'t get states having non-action', () => expect( () => {
|
|
880
|
-
|
|
881
|
-
const machine = new jssm.Machine({
|
|
882
|
-
start_states: ['1'],
|
|
883
|
-
transitions:[
|
|
884
|
-
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
885
|
-
]
|
|
886
|
-
});
|
|
887
|
-
|
|
888
|
-
machine.list_states_having_action('no such action');
|
|
889
|
-
|
|
890
|
-
}).toThrow() );
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
test('can\'t list exit states of non-action', () => expect( () => {
|
|
894
|
-
|
|
895
|
-
const machine = new jssm.Machine({
|
|
896
|
-
start_states: ['1'],
|
|
897
|
-
transitions:[
|
|
898
|
-
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
899
|
-
]
|
|
900
|
-
});
|
|
901
|
-
|
|
902
|
-
machine.list_exit_actions('no such action');
|
|
903
|
-
|
|
904
|
-
}).toThrow() );
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
test('probable exits for throws on non-state', () => expect( () => {
|
|
908
|
-
|
|
909
|
-
const machine = new jssm.Machine({
|
|
910
|
-
start_states: ['1'],
|
|
911
|
-
transitions:[
|
|
912
|
-
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
913
|
-
]
|
|
914
|
-
});
|
|
915
|
-
|
|
916
|
-
machine.probable_exits_for('3');
|
|
917
|
-
|
|
918
|
-
}).toThrow() );
|
|
919
|
-
|
|
920
|
-
test('no probable action exits of non-action', () => expect( () => {
|
|
921
|
-
|
|
922
|
-
const machine = new jssm.Machine({
|
|
923
|
-
start_states: ['1'],
|
|
924
|
-
transitions:[
|
|
925
|
-
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
926
|
-
]
|
|
927
|
-
});
|
|
928
|
-
|
|
929
|
-
machine.probable_action_exits('no such action');
|
|
930
|
-
|
|
931
|
-
}).toThrow() );
|
|
932
|
-
|
|
933
|
-
});
|
|
1
|
+
|
|
2
|
+
/* eslint-disable max-len */
|
|
3
|
+
|
|
4
|
+
import * as jssm from '../jssm';
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
test('build-set version number is present', () =>
|
|
11
|
+
expect(typeof jssm.version)
|
|
12
|
+
.toBe('string'));
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
describe('Stochastic weather', () => {
|
|
19
|
+
|
|
20
|
+
new jssm.Machine({
|
|
21
|
+
|
|
22
|
+
start_states: ['breezy'],
|
|
23
|
+
|
|
24
|
+
transitions: [
|
|
25
|
+
|
|
26
|
+
{ from: 'breezy', to: 'breezy', probability: 0.4, kind: 'legal', forced_only: false, main_path: false },
|
|
27
|
+
{ from: 'breezy', to: 'sunny', probability: 0.3, kind: 'legal', forced_only: false, main_path: false },
|
|
28
|
+
{ from: 'breezy', to: 'cloudy', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
29
|
+
{ from: 'breezy', to: 'windy', probability: 0.1, kind: 'legal', forced_only: false, main_path: false },
|
|
30
|
+
{ from: 'breezy', to: 'rain', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
31
|
+
|
|
32
|
+
{ from: 'sunny', to: 'sunny', probability: 0.5, kind: 'legal', forced_only: false, main_path: false },
|
|
33
|
+
{ from: 'sunny', to: 'hot', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
34
|
+
{ from: 'sunny', to: 'breezy', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
35
|
+
{ from: 'sunny', to: 'cloudy', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
36
|
+
{ from: 'sunny', to: 'rain', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
37
|
+
|
|
38
|
+
{ from: 'hot', to: 'hot', probability: 0.75, kind: 'legal', forced_only: false, main_path: false },
|
|
39
|
+
{ from: 'hot', to: 'breezy', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
40
|
+
{ from: 'hot', to: 'sunny', probability: 0.2, kind: 'legal', forced_only: false, main_path: false },
|
|
41
|
+
|
|
42
|
+
{ from: 'cloudy', to: 'cloudy', probability: 0.6, kind: 'legal', forced_only: false, main_path: false },
|
|
43
|
+
{ from: 'cloudy', to: 'sunny', probability: 0.2, kind: 'legal', forced_only: false, main_path: false },
|
|
44
|
+
{ from: 'cloudy', to: 'rain', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
45
|
+
{ from: 'cloudy', to: 'breezy', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
46
|
+
|
|
47
|
+
{ from: 'windy', to: 'windy', probability: 0.3, kind: 'legal', forced_only: false, main_path: false },
|
|
48
|
+
{ from: 'windy', to: 'gale', probability: 0.1, kind: 'legal', forced_only: false, main_path: false },
|
|
49
|
+
{ from: 'windy', to: 'breezy', probability: 0.4, kind: 'legal', forced_only: false, main_path: false },
|
|
50
|
+
{ from: 'windy', to: 'rain', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
51
|
+
{ from: 'windy', to: 'sunny', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
52
|
+
|
|
53
|
+
{ from: 'gale', to: 'gale', probability: 0.65, kind: 'legal', forced_only: false, main_path: false },
|
|
54
|
+
{ from: 'gale', to: 'windy', probability: 0.25, kind: 'legal', forced_only: false, main_path: false },
|
|
55
|
+
{ from: 'gale', to: 'torrent', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
56
|
+
{ from: 'gale', to: 'hot', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
57
|
+
|
|
58
|
+
{ from: 'rain', to: 'rain', probability: 0.3, kind: 'legal', forced_only: false, main_path: false },
|
|
59
|
+
{ from: 'rain', to: 'torrent', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
60
|
+
{ from: 'rain', to: 'windy', probability: 0.1, kind: 'legal', forced_only: false, main_path: false },
|
|
61
|
+
{ from: 'rain', to: 'breezy', probability: 0.15, kind: 'legal', forced_only: false, main_path: false },
|
|
62
|
+
{ from: 'rain', to: 'sunny', probability: 0.1, kind: 'legal', forced_only: false, main_path: false },
|
|
63
|
+
{ from: 'rain', to: 'cloudy', probability: 0.3, kind: 'legal', forced_only: false, main_path: false },
|
|
64
|
+
|
|
65
|
+
{ from: 'torrent', to: 'torrent', probability: 0.65, kind: 'legal', forced_only: false, main_path: false },
|
|
66
|
+
{ from: 'torrent', to: 'rain', probability: 0.25, kind: 'legal', forced_only: false, main_path: false },
|
|
67
|
+
{ from: 'torrent', to: 'cloudy', probability: 0.05, kind: 'legal', forced_only: false, main_path: false },
|
|
68
|
+
{ from: 'torrent', to: 'gale', probability: 0.05, kind: 'legal', forced_only: false, main_path: false }
|
|
69
|
+
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test.todo('Unfinished test case in general spec');
|
|
75
|
+
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
describe('list exit actions', () => {
|
|
83
|
+
|
|
84
|
+
const machine = new jssm.Machine({
|
|
85
|
+
start_states : ['off'],
|
|
86
|
+
transitions : [
|
|
87
|
+
{ from:'off', to:'red', action:'on', kind: 'legal', forced_only: false, main_path: false },
|
|
88
|
+
{ from:'red', to:'off', action:'off', kind: 'legal', forced_only: false, main_path: false }
|
|
89
|
+
]
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('shows "on" from off as default', () =>
|
|
93
|
+
expect(machine.list_exit_actions()[0])
|
|
94
|
+
.toBe('on') );
|
|
95
|
+
|
|
96
|
+
test('shows "on" from off', () =>
|
|
97
|
+
expect(machine.list_exit_actions('off')[0])
|
|
98
|
+
.toBe('on') );
|
|
99
|
+
|
|
100
|
+
test('shows "off" from red', () =>
|
|
101
|
+
expect(machine.list_exit_actions('red')[0])
|
|
102
|
+
.toBe('off') );
|
|
103
|
+
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
describe('probable exits for', () => {
|
|
111
|
+
|
|
112
|
+
const machine = new jssm.Machine({
|
|
113
|
+
start_states: ['off'],
|
|
114
|
+
transitions:[ { from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('probable exits are an array', () =>
|
|
118
|
+
expect(Array.isArray(machine.probable_exits_for('off')) )
|
|
119
|
+
.toBe(true) );
|
|
120
|
+
|
|
121
|
+
test('one probable exit in example', () =>
|
|
122
|
+
expect(machine.probable_exits_for('off').length)
|
|
123
|
+
.toBe(1) );
|
|
124
|
+
|
|
125
|
+
test('exit is an object', () =>
|
|
126
|
+
expect(typeof machine.probable_exits_for('off')[0])
|
|
127
|
+
.toBe('object') );
|
|
128
|
+
|
|
129
|
+
test('exit 0 has a string from property', () =>
|
|
130
|
+
expect(typeof machine.probable_exits_for('off')[0].from)
|
|
131
|
+
.toBe('string') );
|
|
132
|
+
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
describe('probable action exits', () => {
|
|
140
|
+
|
|
141
|
+
const machine = new jssm.Machine({
|
|
142
|
+
start_states : ['off'],
|
|
143
|
+
transitions : [
|
|
144
|
+
{ from:'off', to:'red', action:'on', kind: 'legal', forced_only: false, main_path: false },
|
|
145
|
+
{ from:'red', to:'off', action:'off', kind: 'legal', forced_only: false, main_path: false }
|
|
146
|
+
]
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
test('probable action exits are an array', () =>
|
|
151
|
+
expect(Array.isArray(machine.probable_action_exits()) )
|
|
152
|
+
.toBe(true) );
|
|
153
|
+
|
|
154
|
+
test('probable action exit 1 is on', () =>
|
|
155
|
+
expect(machine.probable_action_exits()[0].action)
|
|
156
|
+
.toBe('on') );
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
test('probable action exits are an array 2', () =>
|
|
160
|
+
expect(Array.isArray(machine.probable_action_exits('off')) )
|
|
161
|
+
.toBe(true) );
|
|
162
|
+
|
|
163
|
+
test('probable action exit 1 is on 2', () =>
|
|
164
|
+
expect(machine.probable_action_exits('off')[0].action)
|
|
165
|
+
.toBe('on') );
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
test('probable action exits are an array 3', () =>
|
|
169
|
+
expect(Array.isArray(machine.probable_action_exits('red')) )
|
|
170
|
+
.toBe(true) );
|
|
171
|
+
|
|
172
|
+
test('probable action exit 1 is on 3', () =>
|
|
173
|
+
expect(machine.probable_action_exits('red')[0].action)
|
|
174
|
+
.toBe('off') );
|
|
175
|
+
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
describe('probabilistic_transition', () => {
|
|
183
|
+
|
|
184
|
+
const machine = new jssm.Machine({
|
|
185
|
+
start_states : ['off'],
|
|
186
|
+
transitions : [ { from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
machine.probabilistic_transition();
|
|
190
|
+
|
|
191
|
+
test('solo after probabilistic is red', () =>
|
|
192
|
+
expect(machine.state())
|
|
193
|
+
.toBe('red') );
|
|
194
|
+
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
describe('probabilistic_walk', () => {
|
|
202
|
+
|
|
203
|
+
const machine = new jssm.Machine({
|
|
204
|
+
start_states : ['off'],
|
|
205
|
+
transitions : [
|
|
206
|
+
{ from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false },
|
|
207
|
+
{ from: 'red', to: 'off', kind: 'legal', forced_only: false, main_path: false }
|
|
208
|
+
]
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
machine.probabilistic_walk(3);
|
|
212
|
+
|
|
213
|
+
test('solo after probabilistic walk 3 is red', () =>
|
|
214
|
+
expect(machine.state())
|
|
215
|
+
.toBe('red') );
|
|
216
|
+
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
describe('probabilistic_histo_walk', () => {
|
|
224
|
+
|
|
225
|
+
const machine = new jssm.Machine({
|
|
226
|
+
start_states : ['off'],
|
|
227
|
+
transitions : [
|
|
228
|
+
{ from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false },
|
|
229
|
+
{ from: 'red', to: 'off', kind: 'legal', forced_only: false, main_path: false }
|
|
230
|
+
]
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
const histo = machine.probabilistic_histo_walk(3);
|
|
234
|
+
|
|
235
|
+
test('histo is a Map', () =>
|
|
236
|
+
expect(histo instanceof Map)
|
|
237
|
+
.toBe(true) );
|
|
238
|
+
|
|
239
|
+
test('histo red is 2', () =>
|
|
240
|
+
expect(histo.get('red'))
|
|
241
|
+
.toBe(2) );
|
|
242
|
+
|
|
243
|
+
test('histo off is 2', () =>
|
|
244
|
+
expect(histo.get('off'))
|
|
245
|
+
.toBe(2) );
|
|
246
|
+
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
describe('reports state_is_final', () => {
|
|
254
|
+
|
|
255
|
+
const machine = new jssm.Machine({
|
|
256
|
+
start_states: ['off'],
|
|
257
|
+
transitions:[
|
|
258
|
+
{ from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false },
|
|
259
|
+
{ from: 'off', to: 'mid', kind: 'legal', forced_only: false, main_path: false },
|
|
260
|
+
{ from: 'mid', to: 'fin', kind: 'legal', forced_only: false, main_path: false }
|
|
261
|
+
],
|
|
262
|
+
complete:['red', 'mid']
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test('final false for neither', () =>
|
|
266
|
+
expect(machine.state_is_final('off') )
|
|
267
|
+
.toBe(false) );
|
|
268
|
+
|
|
269
|
+
test('final false for just terminal', () =>
|
|
270
|
+
expect(machine.state_is_final('mid') )
|
|
271
|
+
.toBe(false) );
|
|
272
|
+
|
|
273
|
+
test('final false for just complete', () =>
|
|
274
|
+
expect(machine.state_is_final('fin') )
|
|
275
|
+
.toBe(false) );
|
|
276
|
+
|
|
277
|
+
test('final true', () =>
|
|
278
|
+
expect(machine.state_is_final('red') )
|
|
279
|
+
.toBe(true) );
|
|
280
|
+
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
describe('reports is_final', () => {
|
|
288
|
+
|
|
289
|
+
const machine = new jssm.Machine({
|
|
290
|
+
start_states: ['off'],
|
|
291
|
+
transitions:[
|
|
292
|
+
{ from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
293
|
+
],
|
|
294
|
+
complete:['red']
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
const init_final = machine.is_final();
|
|
298
|
+
machine.transition('red');
|
|
299
|
+
const fin_final = machine.is_final();
|
|
300
|
+
|
|
301
|
+
test('final false', () =>
|
|
302
|
+
expect(init_final)
|
|
303
|
+
.toBe(false) );
|
|
304
|
+
|
|
305
|
+
test('final true', () =>
|
|
306
|
+
expect(fin_final)
|
|
307
|
+
.toBe(true) );
|
|
308
|
+
|
|
309
|
+
// why is this written this way?
|
|
310
|
+
|
|
311
|
+
/* todo whargarbl needs another two tests for is_changing once reintroduced */
|
|
312
|
+
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
describe('reports state_is_terminal', () => {
|
|
320
|
+
|
|
321
|
+
const machine = new jssm.Machine({
|
|
322
|
+
start_states : ['off'],
|
|
323
|
+
transitions : [ { name: 'turn_on', action: 'power_on', from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test('terminal false', () =>
|
|
327
|
+
expect(machine.state_is_terminal('off') )
|
|
328
|
+
.toBe(false) );
|
|
329
|
+
|
|
330
|
+
test('terminal true', () =>
|
|
331
|
+
expect(machine.state_is_terminal('red') )
|
|
332
|
+
.toBe(true) );
|
|
333
|
+
|
|
334
|
+
test('terminal on missing state throws', () =>
|
|
335
|
+
expect( () => machine.state_is_terminal('notARealState') )
|
|
336
|
+
.toThrow() );
|
|
337
|
+
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
describe('reports is_terminal', () => {
|
|
345
|
+
|
|
346
|
+
const machine = new jssm.Machine({
|
|
347
|
+
start_states : ['off'],
|
|
348
|
+
transitions : [ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false} ]
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
const first = machine.is_terminal();
|
|
352
|
+
machine.transition('red');
|
|
353
|
+
const second = machine.is_terminal();
|
|
354
|
+
|
|
355
|
+
const terms = machine.has_terminals();
|
|
356
|
+
// why is this written this way?
|
|
357
|
+
|
|
358
|
+
test('terminal false', () =>
|
|
359
|
+
expect(first)
|
|
360
|
+
.toBe(false) );
|
|
361
|
+
|
|
362
|
+
test('terminal true', () =>
|
|
363
|
+
expect(second)
|
|
364
|
+
.toBe(true) );
|
|
365
|
+
|
|
366
|
+
test('has_terminals', () =>
|
|
367
|
+
expect(terms)
|
|
368
|
+
.toBe(true) );
|
|
369
|
+
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
describe('reports state_is_complete', () => {
|
|
377
|
+
|
|
378
|
+
const machine = new jssm.Machine({
|
|
379
|
+
start_states: ['off'],
|
|
380
|
+
transitions:[ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false} ],
|
|
381
|
+
complete:['off'] // huhu
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
test('state_is_complete false', () =>
|
|
385
|
+
expect(machine.state_is_complete('off') )
|
|
386
|
+
.toBe(true) );
|
|
387
|
+
|
|
388
|
+
test('state_is_complete true', () =>
|
|
389
|
+
expect(machine.state_is_complete('red') )
|
|
390
|
+
.toBe(false) );
|
|
391
|
+
|
|
392
|
+
test('throws on nonexisting state', () =>
|
|
393
|
+
expect( () => machine.state_is_complete('thisStateDoesNotExist') )
|
|
394
|
+
.toThrow() );
|
|
395
|
+
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
describe('reports is_complete', () => {
|
|
403
|
+
|
|
404
|
+
const machine = new jssm.Machine({
|
|
405
|
+
start_states: ['off'],
|
|
406
|
+
transitions:[ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false} ],
|
|
407
|
+
complete:['off'] // huhu
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
const first = machine.is_complete();
|
|
411
|
+
machine.transition('red');
|
|
412
|
+
const second = machine.is_complete();
|
|
413
|
+
|
|
414
|
+
const terms = machine.has_completes();
|
|
415
|
+
// why is this written this way?
|
|
416
|
+
|
|
417
|
+
test('is_complete false', () =>
|
|
418
|
+
expect(first)
|
|
419
|
+
.toBe(true) );
|
|
420
|
+
|
|
421
|
+
test('is_complete true', () =>
|
|
422
|
+
expect(second)
|
|
423
|
+
.toBe(false) );
|
|
424
|
+
|
|
425
|
+
test('has_completes', () =>
|
|
426
|
+
expect(terms)
|
|
427
|
+
.toBe(true) );
|
|
428
|
+
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
describe('reports on actions', () => {
|
|
436
|
+
|
|
437
|
+
const machine = new jssm.Machine({
|
|
438
|
+
start_states: ['off'],
|
|
439
|
+
transitions:[ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false} ]
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
const a = machine.list_actions(); // todo comeback
|
|
443
|
+
|
|
444
|
+
test('that it has', () =>
|
|
445
|
+
expect(typeof machine.current_action_for('power_on') )
|
|
446
|
+
.toBe('number') );
|
|
447
|
+
|
|
448
|
+
test('that it doesn\'t have', () =>
|
|
449
|
+
expect(typeof machine.current_action_for('power_left') )
|
|
450
|
+
.toBe('undefined') );
|
|
451
|
+
|
|
452
|
+
test('correct list type', () =>
|
|
453
|
+
expect(Array.isArray(a))
|
|
454
|
+
.toBe(true) );
|
|
455
|
+
|
|
456
|
+
test('correct list size', () =>
|
|
457
|
+
expect(a.length)
|
|
458
|
+
.toBe(1) );
|
|
459
|
+
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
describe('actions', () => {
|
|
467
|
+
|
|
468
|
+
const machine = new jssm.Machine({
|
|
469
|
+
start_states : ['off'],
|
|
470
|
+
transitions : [
|
|
471
|
+
{ from:'off', to:'red', action:'on', kind: 'legal', forced_only: false, main_path: false },
|
|
472
|
+
{ from:'red', to:'off', action:'off', kind: 'legal', forced_only: false, main_path: false }
|
|
473
|
+
]
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
test('red has actions().length 1', () =>
|
|
477
|
+
expect(machine.actions().length)
|
|
478
|
+
.toBe(1) );
|
|
479
|
+
|
|
480
|
+
test('red has actions()[0] "on"', () =>
|
|
481
|
+
expect(machine.actions()[0])
|
|
482
|
+
.toBe('on') );
|
|
483
|
+
|
|
484
|
+
test('red has actions().length 1 again', () =>
|
|
485
|
+
expect(machine.actions('off').length)
|
|
486
|
+
.toBe(1) );
|
|
487
|
+
|
|
488
|
+
test('red has actions()[0] "on" again', () =>
|
|
489
|
+
expect(machine.actions('off')[0])
|
|
490
|
+
.toBe('on') );
|
|
491
|
+
|
|
492
|
+
test('red has actions().length 1 re-again', () =>
|
|
493
|
+
expect(machine.actions('red').length)
|
|
494
|
+
.toBe(1) );
|
|
495
|
+
|
|
496
|
+
test('red has actions()[0] "off" re-again',
|
|
497
|
+
() => expect(machine.actions('red')[0])
|
|
498
|
+
.toBe('off') );
|
|
499
|
+
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
describe('states having action', () => {
|
|
507
|
+
|
|
508
|
+
const machine = new jssm.Machine({
|
|
509
|
+
start_states : ['off'],
|
|
510
|
+
transitions : [
|
|
511
|
+
{ from:'off', to: 'red', action: 'on', kind: 'legal', forced_only: false, main_path: false },
|
|
512
|
+
{ from:'red', to: 'off', action: 'off', kind: 'legal', forced_only: false, main_path: false }
|
|
513
|
+
]
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
test('one action has on', () =>
|
|
517
|
+
expect(machine.list_states_having_action('on').length)
|
|
518
|
+
.toBe(1) );
|
|
519
|
+
|
|
520
|
+
test('on is had by off', () =>
|
|
521
|
+
expect(machine.list_states_having_action('on')[0])
|
|
522
|
+
.toBe('off') );
|
|
523
|
+
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
describe('unenterables', () => {
|
|
531
|
+
|
|
532
|
+
const machine = new jssm.Machine({
|
|
533
|
+
start_states: ['off'],
|
|
534
|
+
transitions:[ { name:'turn_on', action: 'power_on', from: 'off', to: 'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
test('off isn\'t enterable', () =>
|
|
538
|
+
expect(machine.is_unenterable('off') )
|
|
539
|
+
.toBe(true) );
|
|
540
|
+
|
|
541
|
+
test('red is enterable', () =>
|
|
542
|
+
expect(machine.is_unenterable('red') )
|
|
543
|
+
.toBe(false) );
|
|
544
|
+
|
|
545
|
+
test('machine has unenterables', () =>
|
|
546
|
+
expect(machine.has_unenterables() )
|
|
547
|
+
.toBe(true) );
|
|
548
|
+
|
|
549
|
+
test('unenterable test on missing state throws', () =>
|
|
550
|
+
expect( () => machine.is_unenterable('notARealState') )
|
|
551
|
+
.toThrow() );
|
|
552
|
+
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
describe('reports on action edges', () => {
|
|
560
|
+
|
|
561
|
+
const machine = new jssm.Machine({
|
|
562
|
+
start_states : ['off'],
|
|
563
|
+
transitions : [
|
|
564
|
+
{ name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
565
|
+
]
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
test('that it has', () =>
|
|
569
|
+
expect(typeof machine.current_action_edge_for('power_on'))
|
|
570
|
+
.toBe('object') );
|
|
571
|
+
|
|
572
|
+
test('that it doesn\'t have', () =>
|
|
573
|
+
expect(() => { machine.current_action_edge_for('power_west'); })
|
|
574
|
+
.toThrow() );
|
|
575
|
+
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
describe('reports on states', () => {
|
|
583
|
+
|
|
584
|
+
const machine = new jssm.Machine({
|
|
585
|
+
start_states : ['off'],
|
|
586
|
+
transitions : [
|
|
587
|
+
{ name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
588
|
+
]
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
test('that it has', () =>
|
|
592
|
+
expect(typeof machine.state_for('off') )
|
|
593
|
+
.toBe('object') );
|
|
594
|
+
|
|
595
|
+
test('that it doesn\'t have', () =>
|
|
596
|
+
expect(() => { machine.state_for('no such state'); })
|
|
597
|
+
.toThrow() );
|
|
598
|
+
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
describe('returns states', () => {
|
|
606
|
+
|
|
607
|
+
const machine = new jssm.Machine({
|
|
608
|
+
start_states : ['off'],
|
|
609
|
+
transitions : [
|
|
610
|
+
{ name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
611
|
+
]
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
test('that it has', () =>
|
|
615
|
+
expect(typeof machine.machine_state() )
|
|
616
|
+
.toBe('object') );
|
|
617
|
+
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
describe('reports on transitions', () => {
|
|
625
|
+
|
|
626
|
+
const machine = new jssm.Machine({
|
|
627
|
+
start_states : ['off'],
|
|
628
|
+
transitions : [
|
|
629
|
+
{ name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false }
|
|
630
|
+
]
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
test('unspecified transition return type', () =>
|
|
635
|
+
expect(typeof machine.list_transitions() )
|
|
636
|
+
.toBe('object') );
|
|
637
|
+
|
|
638
|
+
test('unspecified transition correct entrance count', () =>
|
|
639
|
+
expect(machine.list_transitions().entrances.length)
|
|
640
|
+
.toBe(0) );
|
|
641
|
+
|
|
642
|
+
test('unspecified transition correct exit count', () =>
|
|
643
|
+
expect(machine.list_transitions().exits.length)
|
|
644
|
+
.toBe(1) );
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
test('specified transition return type', () =>
|
|
648
|
+
expect(typeof machine.list_transitions('off') )
|
|
649
|
+
.toBe('object') );
|
|
650
|
+
|
|
651
|
+
test('specified transition correct entrance count', () =>
|
|
652
|
+
expect(machine.list_transitions('off').entrances.length)
|
|
653
|
+
.toBe(0) );
|
|
654
|
+
|
|
655
|
+
test('specified transition correct exit count', () =>
|
|
656
|
+
expect(machine.list_transitions('off').exits.length)
|
|
657
|
+
.toBe(1) );
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
test('no such spec trans return type', () =>
|
|
661
|
+
expect(typeof machine.list_transitions('moot') )
|
|
662
|
+
.toBe('object') );
|
|
663
|
+
|
|
664
|
+
test('no such spec trans correct entrance count', () =>
|
|
665
|
+
expect(machine.list_transitions('moot').entrances.length)
|
|
666
|
+
.toBe(0) );
|
|
667
|
+
|
|
668
|
+
test('no such spec trans correct exit count', () =>
|
|
669
|
+
expect(machine.list_transitions('moot').exits.length)
|
|
670
|
+
.toBe(0) );
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
test('unspecified entrance return type', () =>
|
|
674
|
+
expect(Array.isArray( machine.list_entrances() ))
|
|
675
|
+
.toBe(true) );
|
|
676
|
+
|
|
677
|
+
test('unspecified entrance correct count', () =>
|
|
678
|
+
expect(machine.list_entrances().length)
|
|
679
|
+
.toBe(0) );
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
test('specified entrance return type', () =>
|
|
683
|
+
expect(Array.isArray( machine.list_entrances('off') ))
|
|
684
|
+
.toBe(true) );
|
|
685
|
+
|
|
686
|
+
test('specified entrance correct count', () =>
|
|
687
|
+
expect(machine.list_entrances('off').length)
|
|
688
|
+
.toBe(0) );
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
test('no such specified entrance return type', () =>
|
|
692
|
+
expect(Array.isArray( machine.list_entrances('moot') ))
|
|
693
|
+
.toBe(true) ); // todo whargarbl should these throw?
|
|
694
|
+
|
|
695
|
+
test('no such specified entrance correct count', () =>
|
|
696
|
+
expect(machine.list_entrances('moot').length)
|
|
697
|
+
.toBe(0) );
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
test('unspecified exit return type', () =>
|
|
701
|
+
expect(Array.isArray( machine.list_exits() ))
|
|
702
|
+
.toBe(true) );
|
|
703
|
+
|
|
704
|
+
test('unspecified exit correct count', () =>
|
|
705
|
+
expect(machine.list_exits().length)
|
|
706
|
+
.toBe(1) );
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
test('specified exit return type', () =>
|
|
710
|
+
expect(Array.isArray( machine.list_exits('off') ))
|
|
711
|
+
.toBe(true) );
|
|
712
|
+
|
|
713
|
+
test('specified exit correct count', () =>
|
|
714
|
+
expect(machine.list_exits('off').length)
|
|
715
|
+
.toBe(1) );
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
test('no such specified exit return type', () =>
|
|
719
|
+
expect(Array.isArray( machine.list_exits('moot') ))
|
|
720
|
+
.toBe(true) );
|
|
721
|
+
|
|
722
|
+
test('no such specified exit correct count', () =>
|
|
723
|
+
expect(machine.list_exits('moot').length)
|
|
724
|
+
.toBe(0) );
|
|
725
|
+
|
|
726
|
+
|
|
727
|
+
test('edge list return type', () =>
|
|
728
|
+
expect(Array.isArray( machine.list_edges() ))
|
|
729
|
+
.toBe(true) );
|
|
730
|
+
|
|
731
|
+
test('edge list correct count', () =>
|
|
732
|
+
expect(machine.list_edges().length)
|
|
733
|
+
.toBe(1) );
|
|
734
|
+
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
describe('transition by state names', () => {
|
|
742
|
+
|
|
743
|
+
const machine = new jssm.Machine({
|
|
744
|
+
start_states : ['off'],
|
|
745
|
+
transitions : [ { name:'turn_on', action:'power_on', from:'off', to:'red', kind: 'legal', forced_only: false, main_path: false } ]
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
test('finds off -> red', () =>
|
|
749
|
+
expect(machine.get_transition_by_state_names('off', 'red') )
|
|
750
|
+
.toBe(0) );
|
|
751
|
+
|
|
752
|
+
test('does not find off -> blue', () =>
|
|
753
|
+
expect(machine.get_transition_by_state_names('off', 'blue') )
|
|
754
|
+
.toBe(undefined) );
|
|
755
|
+
|
|
756
|
+
test('does not find blue -> red', () =>
|
|
757
|
+
expect(machine.get_transition_by_state_names('blue', 'red') )
|
|
758
|
+
.toBe(undefined) );
|
|
759
|
+
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
describe('Illegal machines', () => {
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
test('catch repeated names', () => expect( () => {
|
|
770
|
+
|
|
771
|
+
new jssm.Machine({
|
|
772
|
+
start_states: ['moot'],
|
|
773
|
+
transitions:[
|
|
774
|
+
{ name: 'identical', from: '1', to: '2', kind: 'legal', forced_only: false, main_path: false },
|
|
775
|
+
{ name: 'identical', from: '2', to: '3', kind: 'legal', forced_only: false, main_path: false }
|
|
776
|
+
]
|
|
777
|
+
});
|
|
778
|
+
|
|
779
|
+
}).toThrow() );
|
|
780
|
+
|
|
781
|
+
|
|
782
|
+
test('must define from', () => expect( () => {
|
|
783
|
+
|
|
784
|
+
new jssm.Machine({
|
|
785
|
+
start_states: ['moot'],
|
|
786
|
+
transitions:[
|
|
787
|
+
{ name:'identical', to:'2', kind: 'legal', forced_only: false, main_path: false }
|
|
788
|
+
]
|
|
789
|
+
} as any);
|
|
790
|
+
|
|
791
|
+
}).toThrow() );
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
test('must define to', () => expect( () => {
|
|
795
|
+
|
|
796
|
+
new jssm.Machine({
|
|
797
|
+
start_states: ['moot'],
|
|
798
|
+
transitions:[
|
|
799
|
+
{ name:'identical', from:'1', kind: 'legal', forced_only: false, main_path: false }
|
|
800
|
+
]
|
|
801
|
+
} as any);
|
|
802
|
+
|
|
803
|
+
}).toThrow() );
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
test('must not have two identical edges', () => expect( () => {
|
|
807
|
+
|
|
808
|
+
new jssm.Machine({
|
|
809
|
+
start_states: ['moot'],
|
|
810
|
+
transitions:[
|
|
811
|
+
{ name:'id1', from:'1', to:'2', kind: 'legal', forced_only: false, main_path: false },
|
|
812
|
+
{ name:'id2', from:'1', to:'2', kind: 'legal', forced_only: false, main_path: false }
|
|
813
|
+
]
|
|
814
|
+
});
|
|
815
|
+
|
|
816
|
+
}).toThrow() );
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
test('must not have two of the same action from the same source', () => expect( () => {
|
|
820
|
+
|
|
821
|
+
new jssm.Machine({
|
|
822
|
+
start_states: ['moot'],
|
|
823
|
+
transitions:[
|
|
824
|
+
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false },
|
|
825
|
+
{ name:'id2', from:'1', to:'3', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
826
|
+
]
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
}).toThrow() );
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
test.todo('Does is_complete need an argument?');
|
|
833
|
+
|
|
834
|
+
// test('must not have completion of non-state', () => expect( () => {
|
|
835
|
+
|
|
836
|
+
// const machine = new jssm.Machine({
|
|
837
|
+
// start_states: ['moot'],
|
|
838
|
+
// transitions:[
|
|
839
|
+
// { name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
840
|
+
// ]
|
|
841
|
+
// });
|
|
842
|
+
|
|
843
|
+
// machine.is_complete('no such state');
|
|
844
|
+
|
|
845
|
+
// }).toThrow() );
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
test.todo('is the _new_state api misunderstood in these tests?')
|
|
849
|
+
|
|
850
|
+
// test('internal state helper must not accept double states', () => expect( () => {
|
|
851
|
+
|
|
852
|
+
// const machine = new jssm.Machine({
|
|
853
|
+
// start_states: ['moot'],
|
|
854
|
+
// transitions:[
|
|
855
|
+
// { name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
856
|
+
// ]
|
|
857
|
+
// });
|
|
858
|
+
|
|
859
|
+
// machine._new_state({from: '1', name:'id1', to:'2', complete:false});
|
|
860
|
+
// machine._new_state({from: '1', name:'id1', to:'2', complete:false});
|
|
861
|
+
|
|
862
|
+
// }).toThrow() );
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
test('can\'t get actions of non-state', () => expect( () => {
|
|
866
|
+
|
|
867
|
+
const machine = new jssm.Machine({
|
|
868
|
+
start_states: ['1'],
|
|
869
|
+
transitions:[
|
|
870
|
+
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
871
|
+
]
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
machine.actions('three');
|
|
875
|
+
|
|
876
|
+
}).toThrow() );
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
test('can\'t get states having non-action', () => expect( () => {
|
|
880
|
+
|
|
881
|
+
const machine = new jssm.Machine({
|
|
882
|
+
start_states: ['1'],
|
|
883
|
+
transitions:[
|
|
884
|
+
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
885
|
+
]
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
machine.list_states_having_action('no such action');
|
|
889
|
+
|
|
890
|
+
}).toThrow() );
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
test('can\'t list exit states of non-action', () => expect( () => {
|
|
894
|
+
|
|
895
|
+
const machine = new jssm.Machine({
|
|
896
|
+
start_states: ['1'],
|
|
897
|
+
transitions:[
|
|
898
|
+
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
899
|
+
]
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
machine.list_exit_actions('no such action');
|
|
903
|
+
|
|
904
|
+
}).toThrow() );
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
test('probable exits for throws on non-state', () => expect( () => {
|
|
908
|
+
|
|
909
|
+
const machine = new jssm.Machine({
|
|
910
|
+
start_states: ['1'],
|
|
911
|
+
transitions:[
|
|
912
|
+
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
913
|
+
]
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
machine.probable_exits_for('3');
|
|
917
|
+
|
|
918
|
+
}).toThrow() );
|
|
919
|
+
|
|
920
|
+
test('no probable action exits of non-action', () => expect( () => {
|
|
921
|
+
|
|
922
|
+
const machine = new jssm.Machine({
|
|
923
|
+
start_states: ['1'],
|
|
924
|
+
transitions:[
|
|
925
|
+
{ name:'id1', from:'1', to:'2', action:'identical', kind: 'legal', forced_only: false, main_path: false }
|
|
926
|
+
]
|
|
927
|
+
});
|
|
928
|
+
|
|
929
|
+
machine.probable_action_exits('no such action');
|
|
930
|
+
|
|
931
|
+
}).toThrow() );
|
|
932
|
+
|
|
933
|
+
});
|