Browse Source

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>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
c19839816e
  1. 113
      test/test_state_coverage.c

113
test/test_state_coverage.c

@ -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, &copy)) {
@ -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;
}

Loading…
Cancel
Save