mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-20 15:44:21 +01:00
test/test_state_coverage: --dump-states
Simple code to dump the state transitions into text form. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <ccan/htable/htable_type.h>
|
||||
#include <ccan/hash/hash.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/asort/asort.h>
|
||||
#include "version.h"
|
||||
|
||||
static bool record_input_mapping(int b);
|
||||
@@ -17,11 +18,12 @@ static bool record_input_mapping(int b);
|
||||
#include "state.h"
|
||||
#include "gen_state_names.h"
|
||||
|
||||
static bool quick = false;
|
||||
static bool dot_simplify = false;
|
||||
static bool dot_enable = false;
|
||||
static bool dot_include_abnormal = false;
|
||||
static bool dot_include_errors = false;
|
||||
static bool dot_include_nops = false;
|
||||
static bool include_nops = false;
|
||||
static enum state_input *mapping_inputs;
|
||||
static bool do_decline;
|
||||
|
||||
@@ -159,8 +161,15 @@ struct hist {
|
||||
|
||||
/* Edges for the dot graph, if any. */
|
||||
struct edge_hash edges;
|
||||
|
||||
/* For dumping states. */
|
||||
struct state_dump {
|
||||
enum state_input input;
|
||||
enum state next;
|
||||
enum state_input pkt;
|
||||
} **state_dump;
|
||||
};
|
||||
|
||||
|
||||
static const char *state_name(enum state s)
|
||||
{
|
||||
size_t i;
|
||||
@@ -733,6 +742,35 @@ static void record_output(enum state_input **outputs, enum state_input out)
|
||||
(*outputs)[n] = out;
|
||||
}
|
||||
|
||||
static void record_state(struct state_dump **sd,
|
||||
enum state_input input,
|
||||
enum state newstate,
|
||||
const char *pktstr)
|
||||
{
|
||||
size_t i, n = tal_count(*sd);
|
||||
enum state_input pkt;
|
||||
|
||||
if (!pktstr)
|
||||
pkt = INPUT_NONE;
|
||||
else
|
||||
pkt = input_by_name(pktstr);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if ((*sd)[i].input != input)
|
||||
continue;
|
||||
if ((*sd)[i].next != newstate)
|
||||
continue;
|
||||
if ((*sd)[i].pkt != pkt)
|
||||
continue;
|
||||
/* Duplicate. */
|
||||
return;
|
||||
}
|
||||
tal_resize(sd, n+1);
|
||||
(*sd)[n].input = input;
|
||||
(*sd)[n].next = newstate;
|
||||
(*sd)[n].pkt = pkt;
|
||||
}
|
||||
|
||||
static bool error_path(enum state_input i, enum state src, enum state dst)
|
||||
{
|
||||
return state_is_error(dst) || i == PKT_ERROR;
|
||||
@@ -886,7 +924,7 @@ static struct trail *try_input(const struct state_data *sdata,
|
||||
oldstr = state_name(sdata->state) + 6;
|
||||
newstr = state_name(newstate) + 6;
|
||||
}
|
||||
if (newstr != oldstr || dot_include_nops)
|
||||
if (newstr != oldstr || include_nops)
|
||||
add_dot(&hist->edges, oldstr, newstr, i, effect->send);
|
||||
}
|
||||
|
||||
@@ -904,6 +942,11 @@ static struct trail *try_input(const struct state_data *sdata,
|
||||
record_output(&hist->outputs,
|
||||
input_by_name((const char *)effect->send));
|
||||
}
|
||||
|
||||
if (hist->state_dump) {
|
||||
record_state(&hist->state_dump[sdata->state], i, newstate,
|
||||
(const char *)effect->send);
|
||||
}
|
||||
|
||||
/* Have we been in this overall situation before? */
|
||||
if (!sithash_update(&hist->sithash, ©)) {
|
||||
@@ -913,12 +956,12 @@ static struct trail *try_input(const struct state_data *sdata,
|
||||
* 2) We get repeated BITCOIN_ANCHOR_OTHERSPEND, OR
|
||||
* 3) We pass through NORMAL state.
|
||||
*
|
||||
* And if we're rendering the dot diagram, don't bother.
|
||||
* And if we're being quick, always stop.
|
||||
*/
|
||||
if (effect->defer != INPUT_NONE
|
||||
|| newstate == STATE_NORMAL_LOWPRIO
|
||||
|| i == BITCOIN_ANCHOR_OTHERSPEND
|
||||
|| dot_enable) {
|
||||
|| quick) {
|
||||
tal_free(effect);
|
||||
return NULL;
|
||||
}
|
||||
@@ -1154,12 +1197,24 @@ static void report_trail(const struct trail *t)
|
||||
}
|
||||
}
|
||||
|
||||
static int state_dump_cmp(const struct state_dump *a,
|
||||
const struct state_dump *b,
|
||||
void *unused)
|
||||
{
|
||||
if (a->input != b->input)
|
||||
return a->input - b->input;
|
||||
if (a->next != b->next)
|
||||
return a->next - b->next;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct state_data a, b;
|
||||
unsigned int i;
|
||||
struct hist hist;
|
||||
struct trail *t;
|
||||
bool dump_states = false;
|
||||
|
||||
err_set_progname(argv[0]);
|
||||
|
||||
@@ -1176,12 +1231,15 @@ int main(int argc, char *argv[])
|
||||
opt_register_noarg("--dot-include-errors",
|
||||
opt_set_bool, &dot_include_errors,
|
||||
"Output dot format for error paths");
|
||||
opt_register_noarg("--dot-include-nops",
|
||||
opt_set_bool, &dot_include_nops,
|
||||
"Output dot format even for inputs which don't change state");
|
||||
opt_register_noarg("--include-nops",
|
||||
opt_set_bool, &include_nops,
|
||||
"Output even for inputs which don't change state");
|
||||
opt_register_noarg("--dot-simplify",
|
||||
opt_set_bool, &dot_simplify,
|
||||
"Merge high and low priority states");
|
||||
opt_register_noarg("--dump-states",
|
||||
opt_set_bool, &dump_states,
|
||||
"Summarize all state transitions");
|
||||
opt_register_version();
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
@@ -1191,15 +1249,24 @@ int main(int argc, char *argv[])
|
||||
opt_usage_exit_fail("--dot-simplify needs --dot/--dot-all");
|
||||
if (dot_include_errors && !dot_enable)
|
||||
opt_usage_exit_fail("--dot-include-errors needs --dot/--dot-all");
|
||||
if (dot_include_nops && !dot_enable)
|
||||
opt_usage_exit_fail("--dot-include-nops needs --dot/--dot-all");
|
||||
if (include_nops && !dot_enable && !dump_states)
|
||||
opt_usage_exit_fail("--include-nops needs --dot/--dot-all/--dump-states");
|
||||
|
||||
/* Map the inputs tested in each state. */
|
||||
hist.inputs_per_state = map_inputs();
|
||||
sithash_init(&hist.sithash);
|
||||
hist.outputs = tal_arr(NULL, enum state_input, 0);
|
||||
edge_hash_init(&hist.edges);
|
||||
if (dump_states) {
|
||||
hist.state_dump = tal_arr(NULL, struct state_dump *, STATE_MAX);
|
||||
for (i = 0; i < STATE_MAX; i++)
|
||||
hist.state_dump[i] = tal_arr(hist.state_dump,
|
||||
struct state_dump, 0);
|
||||
} else
|
||||
hist.state_dump = NULL;
|
||||
|
||||
quick = dot_enable || dump_states;
|
||||
|
||||
/* Initialize universe. */
|
||||
sdata_init(&a, &b, STATE_INIT_WITHANCHOR, "A");
|
||||
sdata_init(&b, &a, STATE_INIT_NOANCHOR, "B");
|
||||
@@ -1283,5 +1350,29 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
if (dump_states) {
|
||||
for (i = 0; i < STATE_MAX; i++) {
|
||||
size_t j;
|
||||
size_t n = tal_count(hist.state_dump[i]);
|
||||
if (!n)
|
||||
continue;
|
||||
printf("%s:\n", state_name(i) + 6);
|
||||
asort(hist.state_dump[i], n, state_dump_cmp, NULL);
|
||||
for (j = 0; j < n; j++) {
|
||||
if (!include_nops
|
||||
&& hist.state_dump[i][j].next == i)
|
||||
continue;
|
||||
printf("\t%s -> %s",
|
||||
input_name(hist.state_dump[i][j].input),
|
||||
state_name(hist.state_dump[i][j].next)+6);
|
||||
if (hist.state_dump[i][j].pkt != INPUT_NONE)
|
||||
printf(" (%s)",
|
||||
input_name(hist.state_dump[i][j].pkt));
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user