forked from kmarkus/rFSM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrfsm_testing.lua
170 lines (143 loc) · 5.42 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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
--
-- This file is part of rFSM.
--
-- (C) 2010,2011 Markus Klotzbuecher, markus.klotzbuecher@mech.kuleuven.be,
-- Department of Mechanical Engineering, Katholieke Universiteit
-- Leuven, Belgium.
--
-- You may redistribute this software and/or modify it under either
-- the terms of the GNU Lesser General Public License version 2.1
-- (LGPLv2.1 <http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html>)
-- or (at your discretion) of the Modified BSD License: Redistribution
-- and use in source and binary forms, with or without modification,
-- are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above
-- copyright notice, this list of conditions and the following
-- disclaimer in the documentation and/or other materials provided
-- with the distribution.
-- 3. The name of the author may not be used to endorse or promote
-- products derived from this software without specific prior
-- written permission.
--
-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
-- OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
-- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-- GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-- WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--
--
-- testing/debugging
--
-- define sets of input events and expected trajectory and test
-- against actually executed trajectory
--
require("rfsm")
require("rfsm2uml")
require("utils")
local ac = require("ansicolors")
local tab2str = utils.tab2str
local is_leaf = rfsm.is_leaf
module("rfsm_testing", package.seeall)
verbose = false
-- output
local function stdout(...)
if verbose then utils.stdout(unpack(arg)) end
end
local function stderr(...)
utils.stderr(...)
end
function 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 reset(fsm)
assert(nil, "tbd: implement reset func!")
end
function 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 get_act_leaf(c)
end
function get_act_fqn(fsm)
local s = 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 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: " .. 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 = 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 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