Skip to content

Commit 394c219

Browse files
committed
add tests and documentation to resolve github issue jakesgordon#19
1 parent 5d94074 commit 394c219

4 files changed

Lines changed: 102 additions & 39 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@ instances:
228228

229229
This should be easy to adjust to fit your appropriate mechanism for object construction.
230230

231+
>> _NOTE: the `startup` event can be given any name, but it must be present in some form to
232+
ensure that each instance constructed is initialized with its own unique `current` state._
233+
231234
Initialization Options
232235
======================
233236

@@ -286,6 +289,12 @@ same as the first example in this section where you simply define your own start
286289

287290
So you have a number of choices available to you when initializing your state machine.
288291

292+
>> _IMPORTANT NOTE: if you are using the pattern described in the previous section "State Machine
293+
Classes", and wish to declare an `initial` state in this manner, you MUST use the `defer: true`
294+
attribute and manually call the starting event in your constructor function. This will ensure
295+
that each instance gets its own unique `current` state, rather than an (unwanted) shared
296+
`current` state on the prototype object itself._
297+
289298
Handling Failures
290299
======================
291300

test/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<script src="test_basics.js"></script>
99
<script src="test_async.js"></script>
1010
<script src="test_advanced.js"></script>
11+
<script src="test_classes.js"></script>
1112
<script src="test_initialize.js"></script>
1213
</head>
1314
<body class="flora">

test/test_basics.js

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -48,45 +48,6 @@ test("targeted state machine", function() {
4848

4949
//-----------------------------------------------------------------------------
5050

51-
test("prototype based state machine", function() {
52-
53-
myFSM = function() {
54-
this.startup();
55-
};
56-
57-
StateMachine.create({
58-
target: myFSM.prototype,
59-
events: [
60-
{ name: 'startup', from: 'none', to: 'green' },
61-
{ name: 'warn', from: 'green', to: 'yellow' },
62-
{ name: 'panic', from: 'yellow', to: 'red' },
63-
{ name: 'clear', from: 'yellow', to: 'green' }
64-
]
65-
});
66-
67-
var a = new myFSM();
68-
var b = new myFSM();
69-
70-
equal(a.current, 'green', 'start with correct state');
71-
equal(b.current, 'green', 'start with correct state');
72-
73-
a.warn();
74-
75-
equal(a.current, 'yellow', 'maintain independent current state');
76-
equal(b.current, 'green', 'maintain independent current state');
77-
78-
ok(a.hasOwnProperty('current'), "each instance should have its own current state");
79-
ok(b.hasOwnProperty('current'), "each instance should have its own current state");
80-
ok(!a.hasOwnProperty('warn'), "each instance should NOT have its own event methods");
81-
ok(!b.hasOwnProperty('warn'), "each instance should NOT have its own event methods");
82-
ok(a.warn === b.warn, "each instance should share event methods");
83-
ok(a.warn === a.__proto__.warn, "each instance event methods come from its shared prototype");
84-
ok(b.warn === b.__proto__.warn, "each instance event methods come from its shared prototype");
85-
86-
});
87-
88-
//-----------------------------------------------------------------------------
89-
9051
test("can & cannot", function() {
9152

9253
var fsm = StateMachine.create({

test/test_classes.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//-----------------------------------------------------------------------------
2+
3+
module("classes");
4+
5+
//-----------------------------------------------------------------------------
6+
7+
test("prototype based state machine", function() {
8+
9+
var myFSM = function() {
10+
this.counter = 42;
11+
this.startup();
12+
};
13+
14+
myFSM.prototype = {
15+
onwarn: function() { this.counter++; }
16+
}
17+
18+
StateMachine.create({
19+
target: myFSM.prototype,
20+
events: [
21+
{ name: 'startup', from: 'none', to: 'green' },
22+
{ name: 'warn', from: 'green', to: 'yellow' },
23+
{ name: 'panic', from: 'yellow', to: 'red' },
24+
{ name: 'clear', from: 'yellow', to: 'green' }
25+
]
26+
});
27+
28+
var a = new myFSM();
29+
var b = new myFSM();
30+
31+
equal(a.current, 'green', 'start with correct state');
32+
equal(b.current, 'green', 'start with correct state');
33+
34+
equal(a.counter, 42, 'start with correct counter');
35+
equal(b.counter, 42, 'start with correct counter');
36+
37+
a.warn();
38+
39+
equal(a.current, 'yellow', 'maintain independent current state');
40+
equal(b.current, 'green', 'maintain independent current state');
41+
42+
equal(a.counter, 43, 'counter for (a) should have incremented');
43+
equal(b.counter, 42, 'counter for (b) should remain untouched');
44+
45+
ok(a.hasOwnProperty('current'), "each instance should have its own current state");
46+
ok(b.hasOwnProperty('current'), "each instance should have its own current state");
47+
ok(!a.hasOwnProperty('warn'), "each instance should NOT have its own event methods");
48+
ok(!b.hasOwnProperty('warn'), "each instance should NOT have its own event methods");
49+
ok(a.warn === b.warn, "each instance should share event methods");
50+
ok(a.warn === a.__proto__.warn, "each instance event methods come from its shared prototype");
51+
ok(b.warn === b.__proto__.warn, "each instance event methods come from its shared prototype");
52+
53+
});
54+
55+
//-----------------------------------------------------------------------------
56+
57+
test("github issue 19", function() {
58+
59+
var Foo = function() {
60+
this.counter = 7;
61+
this.initFSM();
62+
};
63+
64+
Foo.prototype.onenterready = function() { this.counter++; };
65+
Foo.prototype.onenterrunning = function() { this.counter++; };
66+
67+
StateMachine.create({
68+
target : Foo.prototype,
69+
initial: { state: 'ready', event: 'initFSM', defer: true }, // unfortunately, trying to apply an IMMEDIATE initial state wont work on prototype based FSM, it MUST be deferred and called in the constructor for each instance
70+
events : [{name: 'execute', from: 'ready', to: 'running'},
71+
{name: 'abort', from: 'running', to: 'ready'}]
72+
});
73+
74+
var foo = new Foo();
75+
var bar = new Foo();
76+
77+
equal(foo.current, 'ready', 'start with correct state');
78+
equal(bar.current, 'ready', 'start with correct state');
79+
80+
equal(foo.counter, 8, 'start with correct counter 7 (from constructor) + 1 (from onenterready)');
81+
equal(bar.counter, 8, 'start with correct counter 7 (from constructor) + 1 (from onenterready)');
82+
83+
foo.execute(); // transition foo, but NOT bar
84+
85+
equal(foo.current, 'running', 'changed state');
86+
equal(bar.current, 'ready', 'state remains the same');
87+
88+
equal(foo.counter, 9, 'incremented counter during onenterrunning');
89+
equal(bar.counter, 8, 'counter remains the same');
90+
91+
});
92+

0 commit comments

Comments
 (0)