-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathrfsm_testing.lua
154 lines (126 loc) · 4.4 KB
/
rfsm_testing.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
-- rFSM testing support
--
-- (C) 2010-2013 Markus Klotzbuecher <[email protected]>
-- (C) 2014-2020 Markus Klotzbuecher <[email protected]>
--
-- SPDX-License-Identifier: BSD-3-Clause
--
-- define sets of input events and expected trajectory and test
-- against actually executed trajectory
--
local rfsm = require("rfsm")
local rfsm2uml = {}
if _VERSION == "Lua 5.2" then
rfsm2uml = require("rfsm2uml")
print(rfsm2uml.rfsm2uml)
else
-- https://packages.debian.org/buster/libgv-lua
-- https://packages.debian.org/sid/libgv-lua
-- https://packages.ubuntu.com/focal/libgv-lua
-- https://packages.ubuntu.com/noble/libgv-lua
print("debian & ubuntu package repositories ship liblua-gv based on Lua 5.2")
print("in order to use graphviz output, you most likely want to use Lua 5.2")
print("providing a no-op. please verify the lua runtime matches the gv.so library")
rfsm2uml.rfsm2uml = function(root, format, outfile, caption) print('no-op rfsm2uml') end
end
local utils = require("utils")
local ac = require("ansicolors")
local tab2str = utils.tab2str
local is_leaf = rfsm.is_leaf
local M = {}
verbose = false
-- output
local function stdout(...)
if verbose then utils.stdout(unpack(arg)) end
end
local function stderr(...)
utils.stderr(...)
end
function M.activate_leaf(fsm, node, mode)
assert(is_leaf(node), "can only activate leaf states!")
rfsm.map_from_to(fsm, function (fsm, s) set_sta_mode(s, 'active') end, node, fsm)
set_sta_mode(node, mode)
end
function M.reset(fsm)
assert(nil, "tbd: implement reset func!")
end
function M.get_act_leaf(fsm)
local c = rfsm.actchild_get(fsm)
if c == nil then
return false
end
if is_leaf(c) then return c end
return M.get_act_leaf(c)
end
function M.get_act_fqn(fsm)
local s = M.get_act_leaf(fsm)
if not s then return "<none>" end
return s._fqn
end
-- nano fsm test framework.
-- a test always includes
-- 1. setting an active configuration (optional): give table of lowest active nodes in 'preac'
-- 2. raising events: 'events' = {...}
-- 3. running step(fsm)
-- 4. asserting that the new active configuration is as exected and printing
-- Options
-- id = 'test_id', no whitespace, will be used as name for pics
-- pics = true|false, generate rfsm2uml snapshots for each step.
function M.test_fsm(fsm, test, verb, dbg)
verbose = verb or false
assert(fsm._initialized, "ERROR: test_fsm requires an initialized fsm!")
stdout("TESTING:", test.id)
if dbg then
fsm.dbg = rfsmpp.gen_dbgcolor(test.id, {}, true)
end
if test.pics then
rfsm2uml.rfsm2uml(fsm, "png", test.id .. "-0.png", test.id .. " initial state")
end
for i,t in ipairs(test.tests) do
local ret
local boiler =
"test: " .. t.descr .. '\n' ..
" initial state: " .. M.get_act_fqn(fsm) .. '\n' ..
" prior sent events: " .. tab2str(t.events) .. '\n' ..
" prior internal event queue: " .. tab2str(fsm._intq) .. '\n' ..
" expected fqn: " .. tab2str(t.expect) .. '\n'
stdout(boiler)
-- if t.preact then activate_sista(fsm, t.preact.fqn, t.preact.mode) end
-- this should work with a
utils.foreach(function (e) rfsm.send_events(fsm, e) end, t.events)
rfsm.run(fsm)
if t.expect then
local c = M.get_act_leaf(fsm)
local fqn = c._fqn
local mode = rfsm.get_sta_mode(c)
if fqn == t.expect.leaf and mode == t.expect.mode then
stdout(ac.green .. ac.bright .. 'OK.' .. ac.reset)
t.result = true
else
stderr(ac.red("Test: " .. t.descr .. " FAILED: Active configurations differ!"))
stderr(ac.red(" actual: ") .. fqn .. "=" .. mode)
stderr(ac.red(" expected: ") .. t.expect.leaf .. "=" .. t.expect.mode)
t.result = false
end
end
local imgfile = test.id .. "-" .. i .. ".png"
stdout("generating img: ", imgfile)
rfsm2uml.rfsm2uml(fsm, "png", imgfile, boiler)
stdout(string.rep("-", 80))
end
return test
end
function M.print_stats(test)
local succ, fail = 0, 0
for i = 1,#test.tests do
if test.tests[i].result then succ = succ + 1
else fail = fail + 1 end
end
local color
if fail == 0 then color = ac.green
elseif succ > 0 then color = ac.yellow
else color = ac.red end
utils.stdout(color("Test: '" .. test.id .. "'. " .. #test.tests .. " tests. " ..
succ .. " succeeded, " .. fail .. " failed."))
end
return M