X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/mLib/blobdiff_plain/b64eb60f6c1fdb12f3922e04913e137199838807..db2bf4111cde36048ac66bbac58547d105bc7e80:/test/tvec-output.c?ds=inline diff --git a/test/tvec-output.c b/test/tvec-output.c index af120d9..c4809bb 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,168 +81,45 @@ 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) +static int register_maxnamelen(const 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) -{ - 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 void ..._bsession(struct tvec_output *o, struct tvec_state *tv) static int ..._esession(struct tvec_output *o) static void ..._bgroup(struct tvec_output *o) -static void ..._egroup(struct tvec_output *o, unsigned outcome) static void ..._skipgroup(struct tvec_output *o, const char *excuse, va_list *ap) +static void ..._egroup(struct tvec_output *o) 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 ..._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 ..._destroy(struct tvec_output *o) static const struct tvec_outops ..._ops = { - ..._error, ..._notice, ..._write, ..._bsession, ..._esession, ..._bgroup, ..._egroup, ..._skip, - ..._btest, ..._skip, ..._fail, ..._mismatch, ..._etest, + ..._btest, ..._skip, ..._fail, ..._dumpreg, ..._etest, ..._bbench, ..._ebench, + ..._error, ..._notice, ..._destroy }; */ @@ -287,12 +147,15 @@ static const struct tvec_outops ..._ops = { #define HA_WIN (HFG(GREEN)) #define HA_LOSE (HFG(RED) | HAF_BOLD) #define HA_SKIP (HFG(YELLOW)) +#define HA_ERR (HFG(MAGENTA) | HAF_BOLD) struct human_output { struct tvec_output _o; + struct tvec_state *tv; FILE *fp; dstr scoreboard; unsigned attr; + int maxlen; unsigned f; #define HOF_TTY 1u #define HOF_DUPERR 2u @@ -345,7 +208,7 @@ static void clear_progress(struct human_output *h) size_t i, n; if (h->f&HOF_PROGRESS) { - n = strlen(h->_o.tv->test->name) + 2 + h->scoreboard.len; + n = strlen(h->tv->test->name) + 2 + h->scoreboard.len; for (i = 0; i < n; i++) fputs("\b \b", h->fp); h->f &= ~HOF_PROGRESS; } @@ -363,10 +226,11 @@ static void write_scoreboard_char(struct human_output *h, int ch) static void show_progress(struct human_output *h) { + struct tvec_state *tv = h->tv; const char *p, *l; - if ((h->f&HOF_TTY) && !(h->f&HOF_PROGRESS)) { - fprintf(h->fp, "%s: ", h->_o.tv->test->name); + if (tv->test && (h->f&HOF_TTY) && !(h->f&HOF_PROGRESS)) { + fprintf(h->fp, "%s: ", tv->test->name); if (!(h->f&HOF_COLOUR)) dstr_write(&h->scoreboard, h->fp); else for (p = h->scoreboard.buf, l = p + h->scoreboard.len; p < l; p++) @@ -397,44 +261,8 @@ static void report_location(struct human_output *h, FILE *fp, #undef FLUSH } -static void human_report(struct human_output *h, - const char *msg, va_list *ap) -{ - struct tvec_state *tv = h->_o.tv; - - fprintf(stderr, "%s: ", QUIS); - report_location(h, stderr, tv->infile, tv->lno); - vfprintf(stderr, msg, *ap); - fputc('\n', stderr); - - if (h->f&HOF_DUPERR) { - report_location(h, stderr, tv->infile, tv->lno); - vfprintf(h->fp, msg, *ap); - fputc('\n', h->fp); - } -} - -static void human_error(struct tvec_output *o, const char *msg, va_list *ap) -{ - struct human_output *h = (struct human_output *)o; - - if (h->f&HOF_PROGRESS) fputc('\n', h->fp); - human_report(h, msg, ap); -} - -static void human_notice(struct tvec_output *o, const char *msg, va_list *ap) -{ - struct human_output *h = (struct human_output *)o; - clear_progress(h); human_report(h, msg, ap); 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 human_bsession(struct tvec_output *o, struct tvec_state *tv) + { struct human_output *h = (struct human_output *)o; h->tv = tv; } static void report_skipped(struct human_output *h, unsigned n) { @@ -448,7 +276,7 @@ static void report_skipped(struct human_output *h, unsigned n) static int human_esession(struct tvec_output *o) { struct human_output *h = (struct human_output *)o; - struct tvec_state *tv = h->_o.tv; + struct tvec_state *tv = h->tv; unsigned all_win = tv->all[TVOUT_WIN], grps_win = tv->grps[TVOUT_WIN], all_lose = tv->all[TVOUT_LOSE], grps_lose = tv->grps[TVOUT_LOSE], @@ -475,56 +303,56 @@ static int human_esession(struct tvec_output *o) } fputc('\n', h->fp); - return (tv->all[TVOUT_LOSE] ? 1 : 0); + if (tv->f&TVSF_ERROR) { + setattr(h, HA_ERR); fputs("ERRORS", h->fp); setattr(h, 0); + fputs(" found in input; tests may not have run correctly\n", h->fp); + } + + h->tv = 0; return (tv->f&TVSF_ERROR ? 2 : tv->all[TVOUT_LOSE] ? 1 : 0); } static void human_bgroup(struct tvec_output *o) { struct human_output *h = (struct human_output *)o; + + h->maxlen = register_maxnamelen(h->tv); dstr_reset(&h->scoreboard); show_progress(h); } -static void human_grpsumm(struct human_output *h, unsigned outcome) +static void human_skipgroup(struct tvec_output *o, + const char *excuse, va_list *ap) { - struct tvec_state *tv = h->_o.tv; - unsigned win = tv->curr[TVOUT_WIN], lose = tv->curr[TVOUT_LOSE], - skip = tv->curr[TVOUT_SKIP], run = win + lose; + struct human_output *h = (struct human_output *)o; - if (lose) { - assert(outcome == TVOUT_LOSE); - fprintf(h->fp, " %u/%u ", lose, run); - setattr(h, HA_LOSE); fputs("FAILED", h->fp); setattr(h, 0); - report_skipped(h, skip); + if (!(~h->f&(HOF_TTY | HOF_PROGRESS))) { + h->f &= ~HOF_PROGRESS; + setattr(h, HA_SKIP); fputs("skipped", h->fp); setattr(h, 0); } else { - assert(outcome == TVOUT_WIN); - fputc(' ', h->fp); setattr(h, HA_WIN); fputs("ok", h->fp); setattr(h, 0); - report_skipped(h, skip); + fprintf(h->fp, "%s: ", h->tv->test->name); + setattr(h, HA_SKIP); fputs("skipped", h->fp); setattr(h, 0); } + if (excuse) { fputs(": ", h->fp); vfprintf(h->fp, excuse, *ap); } fputc('\n', h->fp); } -static void human_egroup(struct tvec_output *o, unsigned outcome) +static void human_egroup(struct tvec_output *o) { struct human_output *h = (struct human_output *)o; + struct tvec_state *tv = h->tv; + unsigned win = tv->curr[TVOUT_WIN], lose = tv->curr[TVOUT_LOSE], + skip = tv->curr[TVOUT_SKIP], run = win + lose; if (h->f&HOF_TTY) h->f &= ~HOF_PROGRESS; - else fprintf(h->fp, "%s:", h->_o.tv->test->name); - human_grpsumm(h, outcome); -} + else fprintf(h->fp, "%s:", h->tv->test->name); -static void human_skipgroup(struct tvec_output *o, - const char *excuse, va_list *ap) -{ - struct human_output *h = (struct human_output *)o; - - if (!(~h->f&(HOF_TTY | HOF_PROGRESS))) { - h->f &= ~HOF_PROGRESS; - setattr(h, HA_SKIP); fputs("skipped", h->fp); setattr(h, 0); + if (lose) { + fprintf(h->fp, " %u/%u ", lose, run); + setattr(h, HA_LOSE); fputs("FAILED", h->fp); setattr(h, 0); + report_skipped(h, skip); } else { - fprintf(h->fp, "%s: ", h->_o.tv->test->name); - setattr(h, HA_SKIP); fputs("skipped", h->fp); setattr(h, 0); + fputc(' ', h->fp); setattr(h, HA_WIN); fputs("ok", h->fp); setattr(h, 0); + report_skipped(h, skip); } - if (excuse) { fputs(": ", h->fp); vfprintf(h->fp, excuse, *ap); } fputc('\n', h->fp); } @@ -535,7 +363,7 @@ static void human_skip(struct tvec_output *o, const char *excuse, va_list *ap) { struct human_output *h = (struct human_output *)o; - struct tvec_state *tv = h->_o.tv; + struct tvec_state *tv = h->tv; clear_progress(h); report_location(h, h->fp, tv->infile, tv->test_lno); @@ -549,7 +377,7 @@ static void human_fail(struct tvec_output *o, const char *detail, va_list *ap) { struct human_output *h = (struct human_output *)o; - struct tvec_state *tv = h->_o.tv; + struct tvec_state *tv = h->tv; clear_progress(h); report_location(h, h->fp, tv->infile, tv->test_lno); @@ -559,51 +387,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) @@ -624,21 +423,42 @@ 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; + struct tvec_state *tv = h->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_report(struct tvec_output *o, const char *msg, va_list *ap) +{ + struct human_output *h = (struct human_output *)o; + struct tvec_state *tv = h->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); + fwrite(d.buf, 1, d.len, stderr); + + if (h->f&HOF_DUPERR) { + report_location(h, h->fp, tv->infile, tv->lno); + fwrite(d.buf, 1, d.len, h->fp); + } + show_progress(h); } static void human_destroy(struct tvec_output *o) @@ -651,11 +471,11 @@ static void human_destroy(struct tvec_output *o) } static const struct tvec_outops human_ops = { - human_error, human_notice, human_write, human_bsession, human_esession, - human_bgroup, human_egroup, human_skipgroup, - human_btest, human_skip, human_fail, human_mismatch, human_etest, + human_bgroup, human_skipgroup, human_egroup, + human_btest, human_skip, human_fail, human_dumpreg, human_etest, human_bbench, human_ebench, + human_report, human_report, human_destroy }; @@ -668,7 +488,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; @@ -688,6 +507,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); } @@ -696,52 +516,78 @@ struct tvec_output *tvec_humanoutput(FILE *fp) struct tap_output { struct tvec_output _o; + struct tvec_state *tv; FILE *fp; + dstr d; + int maxlen; unsigned f; #define TOF_FRESHLINE 1u }; -static void tap_report(struct tap_output *t, const char *msg, va_list *ap) +static int tap_writech(void *go, int ch) { - struct tvec_state *tv = t->_o.tv; + struct tap_output *t = go; - if (tv->infile) fprintf(t->fp, "%s:%u: ", tv->infile, tv->lno); - vfprintf(t->fp, msg, *ap); fputc('\n', t->fp); + 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 void tap_error(struct tvec_output *o, const char *msg, va_list *ap) +static int tap_writem(void *go, const char *p, size_t sz) { - struct tap_output *t = (struct tap_output *)o; - fputs("Bail out! ", t->fp); tap_report(t, msg, ap); + struct tap_output *t = go; + const char *q, *l = p + sz; + size_t n; + + 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; + 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); + } + n = l - p; if (fwrite(p, 1, n, t->fp) < n) return (-1); + t->f &= ~TOF_FRESHLINE; return (0); } -static void tap_notice(struct tvec_output *o, const char *msg, va_list *ap) +static int tap_nwritef(void *go, size_t maxsz, const char *p, ...) { - struct tap_output *t = (struct tap_output *)o; - fputs("## ", t->fp); tap_report(t, msg, ap); + 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 void tap_write(struct tvec_output *o, const char *p, size_t sz) +static const struct gprintf_ops tap_printops = + { tap_writech, tap_writem, tap_nwritef }; + +static void tap_bsession(struct tvec_output *o, struct tvec_state *tv) { struct tap_output *t = (struct tap_output *)o; - const char *q, *l = p + sz; - if (p == l) return; - if (t->f&TOF_FRESHLINE) fputs("## ", t->fp); - 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); - } - fwrite(p, 1, l - p, t->fp); t->f &= ~TOF_FRESHLINE; + t->tv = tv; + fputs("TAP version 13\n", t->fp); } -static void tap_bsession(struct tvec_output *o) { ; } - static unsigned tap_grpix(struct tap_output *t) { - struct tvec_state *tv = t->_o.tv; + struct tvec_state *tv = t->tv; return (tv->grps[TVOUT_WIN] + tv->grps[TVOUT_LOSE] + @@ -751,17 +597,39 @@ static unsigned tap_grpix(struct tap_output *t) static int tap_esession(struct tvec_output *o) { struct tap_output *t = (struct tap_output *)o; + struct tvec_state *tv = t->tv; + + if (tv->f&TVSF_ERROR) { + fputs("Bail out! " + "Errors found in input; tests may not have run correctly\n", + t->fp); + return (2); + } fprintf(t->fp, "1..%u\n", tap_grpix(t)); - return (0); + t->tv = 0; 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->tv); +} -static void tap_egroup(struct tvec_output *o, unsigned outcome) +static void tap_skipgroup(struct tvec_output *o, + const char *excuse, va_list *ap) { struct tap_output *t = (struct tap_output *)o; - struct tvec_state *tv = t->_o.tv; + + fprintf(t->fp, "ok %u %s # SKIP", tap_grpix(t), t->tv->test->name); + if (excuse) { fputc(' ', t->fp); vfprintf(t->fp, excuse, *ap); } + fputc('\n', t->fp); +} + +static void tap_egroup(struct tvec_output *o) +{ + struct tap_output *t = (struct tap_output *)o; + struct tvec_state *tv = t->tv; unsigned grpix = tap_grpix(t), win = tv->curr[TVOUT_WIN], @@ -769,35 +637,22 @@ static void tap_egroup(struct tvec_output *o, unsigned outcome) skip = tv->curr[TVOUT_SKIP]; if (lose) { - assert(outcome == TVOUT_LOSE); - fprintf(t->fp, "not ok %u %s: FAILED %u/%u", + fprintf(t->fp, "not ok %u - %s: FAILED %u/%u", grpix, tv->test->name, lose, win + lose); if (skip) fprintf(t->fp, " (skipped %u)", skip); } else { - assert(outcome == TVOUT_WIN); - fprintf(t->fp, "ok %u %s: passed %u", grpix, tv->test->name, win); + fprintf(t->fp, "ok %u - %s: passed %u", grpix, tv->test->name, win); if (skip) fprintf(t->fp, " (skipped %u)", skip); } fputc('\n', t->fp); } -static void tap_skipgroup(struct tvec_output *o, - const char *excuse, va_list *ap) -{ - struct tap_output *t = (struct tap_output *)o; - - fprintf(t->fp, "ok %u %s # SKIP", tap_grpix(t), t->_o.tv->test->name); - if (excuse) - { fputc(' ', t->fp); vfprintf(t->fp, excuse, *ap); } - fputc('\n', t->fp); -} - static void tap_btest(struct tvec_output *o) { ; } static void tap_skip(struct tvec_output *o, const char *excuse, va_list *ap) { struct tap_output *t = (struct tap_output *)o; - struct tvec_state *tv = t->_o.tv; + struct tvec_state *tv = t->tv; fprintf(t->fp, "## %s:%u: `%s' skipped", tv->infile, tv->test_lno, tv->test->name); @@ -808,7 +663,7 @@ static void tap_skip(struct tvec_output *o, const char *excuse, va_list *ap) static void tap_fail(struct tvec_output *o, const char *detail, va_list *ap) { struct tap_output *t = (struct tap_output *)o; - struct tvec_state *tv = t->_o.tv; + struct tvec_state *tv = t->tv; fprintf(t->fp, "## %s:%u: `%s' FAILED", tv->infile, tv->test_lno, tv->test->name); @@ -816,21 +671,59 @@ 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; + struct tvec_state *tv = t->tv; + + 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_report(struct tap_output *t, const char *msg, va_list *ap) +{ + struct tvec_state *tv = t->tv; + + if (tv->infile) fprintf(t->fp, "%s:%u: ", tv->infile, tv->lno); + vfprintf(t->fp, msg, *ap); fputc('\n', t->fp); +} + +static void tap_error(struct tvec_output *o, const char *msg, va_list *ap) +{ + struct tap_output *t = (struct tap_output *)o; + fputs("Bail out! ", t->fp); tap_report(t, msg, ap); +} - tvec_write(tv, "%s: ", tv->test->name); bench_summary(tv); - bench_report(tv, tm); +static void tap_notice(struct tvec_output *o, const char *msg, va_list *ap) +{ + struct tap_output *t = (struct tap_output *)o; + fputs("## ", t->fp); tap_report(t, msg, ap); } static void tap_destroy(struct tvec_output *o) @@ -838,15 +731,16 @@ 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_bsession, tap_esession, - tap_bgroup, tap_egroup, tap_skipgroup, - tap_btest, tap_skip, tap_fail, tap_mismatch, tap_etest, + tap_bgroup, tap_skipgroup, tap_egroup, + tap_btest, tap_skip, tap_fail, tap_dumpreg, tap_etest, tap_bbench, tap_ebench, + tap_error, tap_notice, tap_destroy }; @@ -855,8 +749,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); }