mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
89 lines
2.5 KiB
V
89 lines
2.5 KiB
V
|
import datatypes.fsm
|
||
|
|
||
|
struct MyReceiver {
|
||
|
mut:
|
||
|
data []string
|
||
|
}
|
||
|
|
||
|
fn default_setup() (MyReceiver, fsm.StateMachine) {
|
||
|
mut receiver := MyReceiver{}
|
||
|
mut s := fsm.new()
|
||
|
s.add_state('A', on_state_entry, on_state_run, on_state_exit)
|
||
|
s.add_state('B', on_state_entry, on_state_run, on_state_exit)
|
||
|
s.add_transition('A', 'B', condition_transition)
|
||
|
return receiver, s
|
||
|
}
|
||
|
|
||
|
fn test_statemachine_number_of_callbacks_correct_when_single_transition() ? {
|
||
|
mut receiver, mut s := default_setup()
|
||
|
|
||
|
s.run(receiver) ?
|
||
|
|
||
|
assert receiver.data.len == 3
|
||
|
}
|
||
|
|
||
|
fn test_statemachine_sequence_works_when_typical() ? {
|
||
|
mut receiver, mut s := default_setup()
|
||
|
|
||
|
s.run(receiver) ?
|
||
|
|
||
|
assert receiver.data[0] == 'on_state_exit: A -> B'
|
||
|
assert receiver.data[1] == 'on_state_entry: A -> B'
|
||
|
assert receiver.data[2] == 'on_state_run: A -> B'
|
||
|
}
|
||
|
|
||
|
fn test_statemachine_works_when_final_state() ? {
|
||
|
mut receiver, mut s := default_setup()
|
||
|
|
||
|
// current state `A`, with a possible transition to `B`:
|
||
|
s.run(receiver) ? // run should not error here
|
||
|
|
||
|
// Note: run will now return error, because for state `B`,
|
||
|
// there are no more transitions:
|
||
|
s.run(receiver) or { assert true }
|
||
|
s.run(receiver) or { assert true }
|
||
|
|
||
|
assert receiver.data.len == 5
|
||
|
assert receiver.data[2] == 'on_state_run: A -> B'
|
||
|
assert receiver.data[3] == 'on_state_run: B -> B'
|
||
|
assert receiver.data[4] == 'on_state_run: B -> B'
|
||
|
}
|
||
|
|
||
|
fn test_simple_loop() ? {
|
||
|
mut receiver, mut s := default_setup()
|
||
|
|
||
|
// Add a transition back to `A` too:
|
||
|
s.add_transition('B', 'A', condition_transition)
|
||
|
|
||
|
// Run the FSM for a while.
|
||
|
// It will loop forever between `A` -> `B` -> `A` -> `B` ...
|
||
|
for _ in 0 .. 100 {
|
||
|
s.run(receiver) or { assert false }
|
||
|
}
|
||
|
assert receiver.data[1] == 'on_state_entry: A -> B'
|
||
|
assert receiver.data[4] == 'on_state_entry: B -> A'
|
||
|
assert receiver.data[7] == 'on_state_entry: A -> B'
|
||
|
assert receiver.data[10] == 'on_state_entry: B -> A'
|
||
|
}
|
||
|
|
||
|
// Helper functions
|
||
|
|
||
|
fn on_state_entry(mut receiver MyReceiver, from string, to string) {
|
||
|
receiver.data << 'on_state_entry: ' + from + ' -> ' + to
|
||
|
}
|
||
|
|
||
|
fn on_state_run(mut receiver MyReceiver, from string, to string) {
|
||
|
receiver.data << 'on_state_run: ' + from + ' -> ' + to
|
||
|
}
|
||
|
|
||
|
fn on_state_exit(mut receiver MyReceiver, from string, to string) {
|
||
|
receiver.data << 'on_state_exit: ' + from + ' -> ' + to
|
||
|
}
|
||
|
|
||
|
fn condition_transition(receiver &MyReceiver, from string, to string) bool {
|
||
|
// The condition callback is a way to provide input to the FSM
|
||
|
// It can return true or false, based on external events/state.
|
||
|
// For these tests however, that is not used, and it simply always returns true.
|
||
|
return true
|
||
|
}
|