From c19839816e745db11e3081548839a2d8cd48d396 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 25 Sep 2015 11:51:18 +0930 Subject: [PATCH] test/test_state_coverage: --dump-states Simple code to dump the state transitions into text form. Signed-off-by: Rusty Russell --- test/test_state_coverage.c | 113 +++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 11 deletions(-) diff --git a/test/test_state_coverage.c b/test/test_state_coverage.c index 773842977..213020d4c 100644 --- a/test/test_state_coverage.c +++ b/test/test_state_coverage.c @@ -8,6 +8,7 @@ #include #include #include +#include #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; }