X-Git-Url: https://git.distorted.org.uk/~mdw/mLib/blobdiff_plain/c7da785d89746cbcdc25bdea0fd66156d4c61cb9..e63124bc579bfd97cfe2f620ddd84df9f20477d8:/test/tvec-output.c diff --git a/test/tvec-output.c b/test/tvec-output.c index 015013b..fbdb347 100644 --- a/test/tvec-output.c +++ b/test/tvec-output.c @@ -27,6 +27,8 @@ /*----- Header files ------------------------------------------------------*/ +#include "config.h" + #include #include #include @@ -43,34 +45,14 @@ /*----- Common machinery --------------------------------------------------*/ -enum { INPUT, OUTPUT, MATCH, EXPECT, FOUND }; -struct mismatchfns { - void (*report_status)(unsigned /*disp*/, int /*st*/, - struct tvec_state */*tv*/); - void (*report_register)(unsigned /*disp*/, - const struct tvec_reg */*r*/, - const struct tvec_regdef */*rd*/, - struct tvec_state */*tv*/); -}; - -static const char *stdisp(unsigned disp) -{ - switch (disp) { - case MATCH: return "final"; - case EXPECT: return "expected"; - case FOUND: return "actual"; - default: abort(); - } -} - static const char *regdisp(unsigned disp) { switch (disp) { - case INPUT: return "input"; - case OUTPUT: return "output"; - case MATCH: return "matched"; - case EXPECT: return "expected"; - case FOUND: return "computed"; + case TVRD_INPUT: return "input"; + case TVRD_OUTPUT: return "output"; + case TVRD_MATCH: return "matched"; + case TVRD_EXPECT: return "expected"; + case TVRD_FOUND: return "found"; default: abort(); } } @@ -88,6 +70,7 @@ static int getenv_boolean(const char *var, int dflt) STRCMP(p, ==, "1")) return (1); else if (STRCMP(p, ==, "n") || STRCMP(p, ==, "no") || + STRCMP(p, ==, "f") || STRCMP(p, ==, "false") || STRCMP(p, ==, "nil") || STRCMP(p, ==, "off") || STRCMP(p, ==, "0")) return (0); @@ -98,147 +81,20 @@ static int getenv_boolean(const char *var, int dflt) } } -static void basic_report_status(unsigned disp, int st, struct tvec_state *tv) - { tvec_write(tv, " %8s status = `%c'\n", stdisp(disp), st); } - -static void basic_report_register(unsigned disp, - const struct tvec_reg *r, - const struct tvec_regdef *rd, - struct tvec_state *tv) -{ - tvec_write(tv, " %8s %s = ", regdisp(disp), rd->name); - if (r->f&TVRF_LIVE) rd->ty->dump(&r->v, rd, tv, 0); - else tvec_write(tv, "#"); - tvec_write(tv, "\n"); -} - -static const struct mismatchfns basic_mismatchfns = - { basic_report_status, basic_report_register }; - -static void dump_inreg(const struct tvec_regdef *rd, - const struct mismatchfns *fns, struct tvec_state *tv) - { fns->report_register(INPUT, TVEC_REG(tv, in, rd->i), rd, tv); } - -static void dump_outreg(const struct tvec_regdef *rd, - const struct mismatchfns *fns, struct tvec_state *tv) -{ - const struct tvec_reg - *rin = TVEC_REG(tv, in, rd->i), *rout = TVEC_REG(tv, out, rd->i); - - if (tv->st == '.') { - if (!(rout->f&TVRF_LIVE)) { - if (!(rin->f&TVRF_LIVE)) - fns->report_register(INPUT, rin, rd, tv); - else { - fns->report_register(FOUND, rout, rd, tv); - fns->report_register(EXPECT, rin, rd, tv); - } - } else { - if (!(rin->f&TVRF_LIVE)) fns->report_register(OUTPUT, rout, rd, tv); - else if (rd->ty->eq(&rin->v, &rout->v, rd)) - fns->report_register(MATCH, rin, rd, tv); - else { - fns->report_register(FOUND, rout, rd, tv); - fns->report_register(EXPECT, rin, rd, tv); - } - } - } -} - -static void mismatch(const struct mismatchfns *fns, struct tvec_state *tv) -{ - const struct tvec_regdef *rd; - - if (tv->st != tv->expst) { - fns->report_status(FOUND, tv->st, tv); - fns->report_status(EXPECT, tv->expst, tv); - } else if (tv->st != '.') - fns->report_status(MATCH, tv->st, tv); - - for (rd = tv->test->regs; rd->name; rd++) { - if (rd->i < tv->nrout) dump_outreg(rd, fns, tv); - else dump_inreg(rd, fns, tv); - } -} - -static void bench_summary(struct tvec_state *tv) +static int register_maxnamelen(const struct tvec_state *tv) { const struct tvec_regdef *rd; - unsigned f = 0; -#define f_any 1u + int maxlen = 6, n; for (rd = tv->test->regs; rd->name; rd++) - if (rd->f&TVRF_ID) { - if (f&f_any) tvec_write(tv, ", "); - else f |= f_any; - tvec_write(tv, "%s = ", rd->name); - rd->ty->dump(&TVEC_REG(tv, in, rd->i)->v, rd, tv, TVSF_COMPACT); - } - -#undef f_any -} - -static void normalize(double *x_inout, const char **unit_out, double scale) -{ - static const char - *const nothing = "", - *const big[] = { "k", "M", "G", "T", "P", "E", 0 }, - *const little[] = { "m", "µ", "n", "p", "f", "a", 0 }; - const char *const *u; - double x = *x_inout; - - if (x < 1) - for (u = little, x *= scale; x < 1 && u[1]; u++, x *= scale); - else if (x >= scale) - for (u = big, x /= scale; x >= scale && u[1]; u++, x /= scale); - else - u = ¬hing; - - *x_inout = x; *unit_out = *u; -} - -static void bench_report(struct tvec_state *tv, - const struct bench_timing *tm) -{ - const struct tvec_bench *b = tv->test->arg.p; - double n = (double)tm->n*b->niter; - double x, scale; - const char *u, *what, *whats; - - assert(tm->f&BTF_TIMEOK); - - if (b->rbuf == -1) { - tvec_write(tv, " -- %.0f iterations ", n); - what = "op"; whats = "ops"; scale = 1000; - } else { - n *= TVEC_REG(tv, in, b->rbuf)->v.bytes.sz; - x = n; normalize(&x, &u, 1024); tvec_write(tv, " -- %.3f %sB ", x, u); - what = whats = "B"; scale = 1024; - } - x = tm->t; normalize(&x, &u, 1000); - tvec_write(tv, "in %.3f %ss", x, u); - if (tm->f&BTF_CYOK) { - x = tm->cy; normalize(&x, &u, 1000); - tvec_write(tv, " (%.3f %scy)", x, u); - } - tvec_write(tv, ": "); - - x = n/tm->t; normalize(&x, &u, scale); - tvec_write(tv, "%.3f %s%s/s", x, u, whats); - x = tm->t/n; normalize(&x, &u, 1000); - tvec_write(tv, ", %.3f %ss/%s", x, u, what); - if (tm->f&BTF_CYOK) { - x = tm->cy/n; normalize(&x, &u, 1000); - tvec_write(tv, " (%.3f %scy/%s)", x, u, what); - } - tvec_write(tv, "\n"); + { n = strlen(rd->name); if (n > maxlen) maxlen = n; } + return (maxlen); } /*----- Skeleton ----------------------------------------------------------*/ /* static void ..._error(struct tvec_output *o, const char *msg, va_list *ap) static void ..._notice(struct tvec_output *o, const char *msg, va_list *ap) -static void ..._write(struct tvec_output *o, const char *p, size_t sz) static void ..._bsession(struct tvec_output *o) static int ..._esession(struct tvec_output *o) static void ..._bgroup(struct tvec_output *o) @@ -246,19 +102,23 @@ static void ..._egroup(struct tvec_output *o, unsigned outcome) static void ..._skipgroup(struct tvec_output *o, const char *excuse, va_list *ap) static void ..._btest(struct tvec_output *o) -static void ..._skip(struct tvec_output *o, const char *detail, va_list *ap) +static void ..._skip(struct tvec_output *o, const char *excuse, va_list *ap) static void ..._fail(struct tvec_output *o, const char *detail, va_list *ap) -static void ..._mismatch(struct tvec_output *o) +static void ..._dumpreg(struct tvec_output *o, unsigned disp, + union tvec_regval *rv, const struct tvec_regdef *rd) static void ..._etest(struct tvec_output *o, unsigned outcome) -static void ..._bbench(struct tvec_output *o) -static void ..._ebench(struct tvec_output *o, const struct tvec_timing *t) +static void ..._bbench(struct tvec_output *o, + const char *ident, unsigned unit) +static void ..._ebench(struct tvec_output *o, + const char *ident, unsigned unit, + const struct tvec_timing *t) static void ..._destroy(struct tvec_output *o) static const struct tvec_outops ..._ops = { - ..._error, ..._notice, ..._write, + ..._error, ..._notice, ..._bsession, ..._esession, ..._bgroup, ..._egroup, ..._skip, - ..._btest, ..._skip, ..._fail, ..._mismatch, ..._etest, + ..._btest, ..._skip, ..._fail, ..._dumpreg, ..._etest, ..._bbench, ..._ebench, ..._destroy }; @@ -294,6 +154,7 @@ struct human_output { FILE *fp; dstr scoreboard; unsigned attr; + int maxlen; unsigned f; #define HOF_TTY 1u #define HOF_DUPERR 2u @@ -403,27 +264,22 @@ static void human_report(struct tvec_output *o, const char *msg, va_list *ap) { struct human_output *h = (struct human_output *)o; struct tvec_state *tv = h->_o.tv; + dstr d = DSTR_INIT; + + dstr_vputf(&d, msg, ap); dstr_putc(&d, '\n'); clear_progress(h); fflush(h->fp); fprintf(stderr, "%s: ", QUIS); report_location(h, stderr, tv->infile, tv->lno); - vfprintf(stderr, msg, *ap); - fputc('\n', stderr); + fwrite(d.buf, 1, d.len, stderr); if (h->f&HOF_DUPERR) { - report_location(h, stderr, tv->infile, tv->lno); - vfprintf(h->fp, msg, *ap); - fputc('\n', h->fp); + report_location(h, h->fp, tv->infile, tv->lno); + fwrite(d.buf, 1, d.len, h->fp); } show_progress(h); } -static void human_write(struct tvec_output *o, const char *p, size_t sz) -{ - struct human_output *h = (struct human_output *)o; - fwrite(p, 1, sz, h->fp); -} - static void human_bsession(struct tvec_output *o) { ; } static void report_skipped(struct human_output *h, unsigned n) @@ -476,6 +332,8 @@ static int human_esession(struct tvec_output *o) static void human_bgroup(struct tvec_output *o) { struct human_output *h = (struct human_output *)o; + + h->maxlen = register_maxnamelen(h->_o.tv); dstr_reset(&h->scoreboard); show_progress(h); } @@ -554,51 +412,22 @@ static void human_fail(struct tvec_output *o, fputc('\n', h->fp); } -static void set_dispattr(struct human_output *h, unsigned disp) -{ - switch (disp) { - case EXPECT: setattr(h, HFG(GREEN)); break; - case FOUND: setattr(h, HFG(RED)); break; - default: setattr(h, 0); break; - } -} - -static void human_report_status(unsigned disp, int st, struct tvec_state *tv) -{ - struct human_output *h = (struct human_output *)tv->output; - - fprintf(h->fp, " %8s status = ", stdisp(disp)); - set_dispattr(h, disp); fprintf(h->fp, "`%c'", st); setattr(h, 0); - fputc('\n', h->fp); -} - -static void human_report_register(unsigned disp, - const struct tvec_reg *r, - const struct tvec_regdef *rd, - struct tvec_state *tv) -{ - struct human_output *h = (struct human_output *)tv->output; - - fprintf(h->fp, " %8s %s = ", regdisp(disp), rd->name); - if (!(r->f&TVRF_LIVE)) - tvec_write(tv, "#"); - else { - set_dispattr(h, disp); - rd->ty->dump(&r->v, rd, tv, 0); - setattr(h, 0); - } - tvec_write(tv, "\n"); -} - -static const struct mismatchfns human_mismatchfns = - { human_report_status, human_report_register }; - -static void human_mismatch(struct tvec_output *o) +static void human_dumpreg(struct tvec_output *o, + unsigned disp, const union tvec_regval *rv, + const struct tvec_regdef *rd) { struct human_output *h = (struct human_output *)o; + const char *ds = regdisp(disp); int n = strlen(ds) + strlen(rd->name); - if (h->f&HOF_COLOUR) mismatch(&human_mismatchfns, h->_o.tv); - else mismatch(&basic_mismatchfns, h->_o.tv); + fprintf(h->fp, "%*s%s %s = ", 10 + h->maxlen - n, "", ds, rd->name); + if (h->f&HOF_COLOUR) { + if (!rv) setattr(h, HFG(YELLOW)); + else if (disp == TVRD_FOUND) setattr(h, HFG(RED)); + else if (disp == TVRD_EXPECT) setattr(h, HFG(GREEN)); + } + if (!rv) fprintf(h->fp, "#"); + else rd->ty->dump(rv, rd, 0, &file_printops, h->fp); + setattr(h, 0); fputc('\n', h->fp); } static void human_etest(struct tvec_output *o, unsigned outcome) @@ -619,21 +448,22 @@ static void human_etest(struct tvec_output *o, unsigned outcome) } } -static void human_bbench(struct tvec_output *o) +static void human_bbench(struct tvec_output *o, + const char *ident, unsigned unit) { struct human_output *h = (struct human_output *)o; struct tvec_state *tv = h->_o.tv; clear_progress(h); - fprintf(h->fp, "%s: ", tv->test->name); - bench_summary(tv); fflush(h->fp); + fprintf(h->fp, "%s: %s: ", tv->test->name, ident); fflush(h->fp); } static void human_ebench(struct tvec_output *o, + const char *ident, unsigned unit, const struct bench_timing *tm) { struct human_output *h = (struct human_output *)o; - bench_report(h->_o.tv, tm); + tvec_benchreport(&file_printops, h->fp, unit, tm); fputc('\n', h->fp); } static void human_destroy(struct tvec_output *o) @@ -646,10 +476,10 @@ static void human_destroy(struct tvec_output *o) } static const struct tvec_outops human_ops = { - human_report, human_report, human_write, + human_report, human_report, human_bsession, human_esession, human_bgroup, human_egroup, human_skipgroup, - human_btest, human_skip, human_fail, human_mismatch, human_etest, + human_btest, human_skip, human_fail, human_dumpreg, human_etest, human_bbench, human_ebench, human_destroy }; @@ -663,7 +493,6 @@ struct tvec_output *tvec_humanoutput(FILE *fp) h->f = 0; h->attr = 0; h->fp = fp; - if (fp != stdout && fp != stderr) h->f |= HOF_DUPERR; switch (getenv_boolean("TVEC_TTY", -1)) { case 1: h->f |= HOF_TTY; break; @@ -683,6 +512,7 @@ struct tvec_output *tvec_humanoutput(FILE *fp) break; } + if (fp != stderr && (fp != stdout || !(h->f&HOF_TTY))) h->f |= HOF_DUPERR; dstr_create(&h->scoreboard); return (&h->_o); } @@ -692,6 +522,8 @@ struct tvec_output *tvec_humanoutput(FILE *fp) struct tap_output { struct tvec_output _o; FILE *fp; + dstr d; + int maxlen; unsigned f; #define TOF_FRESHLINE 1u }; @@ -716,22 +548,59 @@ static void tap_notice(struct tvec_output *o, const char *msg, va_list *ap) fputs("## ", t->fp); tap_report(t, msg, ap); } -static void tap_write(struct tvec_output *o, const char *p, size_t sz) +static int tap_writech(void *go, int ch) { - struct tap_output *t = (struct tap_output *)o; + struct tap_output *t = go; + + if (t->f&TOF_FRESHLINE) { + if (fputs("## ", t->fp) < 0) return (-1); + t->f &= ~TOF_FRESHLINE; + } + if (putc(ch, t->fp) < 0) return (-1); + if (ch == '\n') t->f |= TOF_FRESHLINE; + return (1); +} + +static int tap_writem(void *go, const char *p, size_t sz) +{ + struct tap_output *t = go; const char *q, *l = p + sz; + size_t n; - if (p == l) return; - if (t->f&TOF_FRESHLINE) fputs("## ", t->fp); + if (p == l) return (0); + if (t->f&TOF_FRESHLINE) + if (fputs("## ", t->fp) < 0) return (-1); for (;;) { q = memchr(p, '\n', l - p); if (!q) break; - fwrite(p, 1, q + 1 - p, t->fp); p = q + 1; - if (p == l) { t->f |= TOF_FRESHLINE; return; } - fputs("## ", t->fp); + n = q + 1 - p; if (fwrite(p, 1, n, t->fp) < n) return (-1); + p = q + 1; + if (p == l) { t->f |= TOF_FRESHLINE; return (sz); } + if (fputs("## ", t->fp) < 0) return (-1); } - fwrite(p, 1, l - p, t->fp); t->f &= ~TOF_FRESHLINE; + n = l - p; if (fwrite(p, 1, n, t->fp) < n) return (-1); + t->f &= ~TOF_FRESHLINE; return (0); +} + +static int tap_nwritef(void *go, size_t maxsz, const char *p, ...) +{ + struct tap_output *t = go; + va_list ap; + int n; + + va_start(ap, p); DRESET(&t->d); DENSURE(&t->d, maxsz + 1); +#ifdef HAVE_SNPRINTF + n = vsnprintf(t->d.buf, maxsz + 1, p, ap); +#else + n = vsprintf(t->d.buf, p, ap); +#endif + assert(0 <= n && n <= maxsz); + va_end(ap); + return (tap_writem(t, t->d.buf, n)); } +static const struct gprintf_ops tap_printops = + { tap_writech, tap_writem, tap_nwritef }; + static void tap_bsession(struct tvec_output *o) { ; } static unsigned tap_grpix(struct tap_output *t) @@ -759,7 +628,11 @@ static int tap_esession(struct tvec_output *o) return (tv->all[TVOUT_LOSE] ? 1 : 0); } -static void tap_bgroup(struct tvec_output *o) { ; } +static void tap_bgroup(struct tvec_output *o) +{ + struct tap_output *t = (struct tap_output *)o; + t->maxlen = register_maxnamelen(t->_o.tv); +} static void tap_egroup(struct tvec_output *o, unsigned outcome) { @@ -819,21 +692,39 @@ static void tap_fail(struct tvec_output *o, const char *detail, va_list *ap) fputc('\n', t->fp); } -static void tap_mismatch(struct tvec_output *o) - { mismatch(&basic_mismatchfns, o->tv); } +static void tap_dumpreg(struct tvec_output *o, + unsigned disp, const union tvec_regval *rv, + const struct tvec_regdef *rd) +{ + struct tap_output *t = (struct tap_output *)o; + const char *ds = regdisp(disp); int n = strlen(ds) + strlen(rd->name); + + fprintf(t->fp, "## %*s%s %s = ", 10 + t->maxlen - n, "", ds, rd->name); + if (!rv) + fprintf(t->fp, "#\n"); + else { + t->f &= ~TOF_FRESHLINE; + rd->ty->dump(rv, rd, 0, &tap_printops, t); + fputc('\n', t->fp); + } +} static void tap_etest(struct tvec_output *o, unsigned outcome) { ; } -static void tap_bbench(struct tvec_output *o) { ; } +static void tap_bbench(struct tvec_output *o, + const char *ident, unsigned unit) + { ; } static void tap_ebench(struct tvec_output *o, + const char *ident, unsigned unit, const struct bench_timing *tm) { struct tap_output *t = (struct tap_output *)o; struct tvec_state *tv = t->_o.tv; - tvec_write(tv, "%s: ", tv->test->name); bench_summary(tv); - bench_report(tv, tm); + fprintf(t->fp, "## %s: %s: ", tv->test->name, ident); + t->f &= ~TOF_FRESHLINE; tvec_benchreport(&tap_printops, t, unit, tm); + fputc('\n', t->fp); } static void tap_destroy(struct tvec_output *o) @@ -841,14 +732,15 @@ static void tap_destroy(struct tvec_output *o) struct tap_output *t = (struct tap_output *)o; if (t->fp != stdout && t->fp != stderr) fclose(t->fp); + dstr_destroy(&t->d); xfree(t); } static const struct tvec_outops tap_ops = { - tap_error, tap_notice, tap_write, + tap_error, tap_notice, tap_bsession, tap_esession, tap_bgroup, tap_egroup, tap_skipgroup, - tap_btest, tap_skip, tap_fail, tap_mismatch, tap_etest, + tap_btest, tap_skip, tap_fail, tap_dumpreg, tap_etest, tap_bbench, tap_ebench, tap_destroy }; @@ -858,8 +750,8 @@ struct tvec_output *tvec_tapoutput(FILE *fp) struct tap_output *t; t = xmalloc(sizeof(*t)); t->_o.ops = &tap_ops; - t->f = TOF_FRESHLINE; - t->fp = fp; + dstr_create(&t->d); + t->f = 0; t->fp = fp; return (&t->_o); }