v/vlib/datatypes/fsm/fsm_test.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
}