3 * Main test vector driver
5 * (c) 2023 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
12 * mLib is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU Library General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or (at
15 * your option) any later version.
17 * mLib is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
20 * License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with mLib. If not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
28 /*----- Header files ------------------------------------------------------*/
38 /*----- Output ------------------------------------------------------------*/
40 int tvec_error(struct tvec_state
*tv
, const char *msg
, ...)
44 va_start(ap
, msg
); tvec_error_v(tv
, msg
, &ap
); va_end(ap
);
45 tv
->f
|= TVSF_ERROR
; return (-1);
47 int tvec_error_v(struct tvec_state
*tv
, const char *msg
, va_list *ap
)
48 { tv
->output
->ops
->error(tv
->output
, msg
, ap
); return (-1); }
50 void tvec_notice(struct tvec_state
*tv
, const char *msg
, ...)
53 va_start(ap
, msg
); tvec_notice_v(tv
, msg
, &ap
); va_end(ap
);
55 void tvec_notice_v(struct tvec_state
*tv
, const char *msg
, va_list *ap
)
56 { tv
->output
->ops
->notice(tv
->output
, msg
, ap
); }
58 int tvec_syntax(struct tvec_state
*tv
, int ch
, const char *expect
, ...)
62 va_start(ap
, expect
); tvec_syntax_v(tv
, ch
, expect
, &ap
); va_end(ap
);
65 int tvec_syntax_v(struct tvec_state
*tv
, int ch
,
66 const char *expect
, va_list *ap
)
72 case EOF
: strcpy(found
, "#<eof>"); break;
73 case '\n': strcpy(found
, "#<eol>"); ungetc(ch
, tv
->fp
); break;
75 if (isprint(ch
)) sprintf(found
, "`%c'", ch
);
76 else sprintf(found
, "#<\\x%02x>", ch
);
79 dstr_vputf(&d
, expect
, ap
);
80 tvec_error(tv
, "syntax error: expected %s but found %s", expect
, found
);
84 void tvec_skipgroup(struct tvec_state
*tv
, const char *excuse
, ...)
87 va_start(ap
, excuse
); tvec_skipgroup_v(tv
, excuse
, &ap
); va_end(ap
);
89 void tvec_skipgroup_v(struct tvec_state
*tv
, const char *excuse
, va_list *ap
)
91 tv
->f
|= TVSF_SKIP
; tv
->grps
[TVOUT_SKIP
]++;
92 tv
->output
->ops
->skipgroup(tv
->output
, excuse
, ap
);
95 static void set_outcome(struct tvec_state
*tv
, unsigned out
)
97 tv
->f
&= ~(TVSF_ACTIVE
| TVSF_OUTMASK
);
98 tv
->f
|= out
<< TVSF_OUTSHIFT
;
101 void tvec_skip(struct tvec_state
*tv
, const char *excuse
, ...)
104 va_start(ap
, excuse
); tvec_skip_v(tv
, excuse
, &ap
); va_end(ap
);
106 void tvec_skip_v(struct tvec_state
*tv
, const char *excuse
, va_list *ap
)
108 assert(tv
->f
&TVSF_ACTIVE
);
109 set_outcome(tv
, TVOUT_SKIP
);
110 tv
->output
->ops
->skip(tv
->output
, excuse
, ap
);
113 void tvec_fail(struct tvec_state
*tv
, const char *detail
, ...)
116 va_start(ap
, detail
); tvec_fail_v(tv
, detail
, &ap
); va_end(ap
);
118 void tvec_fail_v(struct tvec_state
*tv
, const char *detail
, va_list *ap
)
120 assert((tv
->f
&TVSF_ACTIVE
) ||
121 (tv
->f
&TVSF_OUTMASK
) == (TVOUT_LOSE
<< TVSF_OUTSHIFT
));
122 set_outcome(tv
, TVOUT_LOSE
); tv
->output
->ops
->fail(tv
->output
, detail
, ap
);
125 void tvec_dumpreg(struct tvec_state
*tv
,
126 unsigned disp
, const union tvec_regval
*r
,
127 const struct tvec_regdef
*rd
)
128 { tv
->output
->ops
->dumpreg(tv
->output
, disp
, r
, rd
); }
130 void tvec_mismatch(struct tvec_state
*tv
, unsigned f
)
132 const struct tvec_regdef
*rd
;
133 const struct tvec_reg
*rin
, *rout
;
135 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
136 if (rd
->i
>= tv
->nrout
) {
137 if (!(f
&TVMF_IN
)) continue;
138 rin
= TVEC_REG(tv
, in
, rd
->i
);
139 tvec_dumpreg(tv
, TVRD_INPUT
, rin
->f
&TVRF_LIVE ?
&rin
->v
: 0, rd
);
141 if (!(f
&TVMF_OUT
)) continue;
142 rin
= TVEC_REG(tv
, in
, rd
->i
); rout
= TVEC_REG(tv
, out
, rd
->i
);
143 if (!(rin
->f
&TVRF_LIVE
))
144 tvec_dumpreg(tv
, TVRD_OUTPUT
, rout
->f
&TVRF_LIVE ?
&rout
->v
: 0, rd
);
145 else if ((rout
->f
&TVRF_LIVE
) && rd
->ty
->eq(&rin
->v
, &rout
->v
, rd
))
146 tvec_dumpreg(tv
, TVRD_MATCH
, &rin
->v
, rd
);
148 tvec_dumpreg(tv
, TVRD_FOUND
, rout
->f
&TVRF_LIVE ?
&rout
->v
: 0, rd
);
149 tvec_dumpreg(tv
, TVRD_EXPECT
, &rin
->v
, rd
);
155 /*----- Main machinery ----------------------------------------------------*/
160 #define GROUPSTATE_INIT { 0 }
162 void tvec_skipspc(struct tvec_state
*tv
)
168 if (ch
== EOF
) break;
169 else if (ch
== '\n' || !isspace(ch
)) { ungetc(ch
, tv
->fp
); break; }
173 int tvec_flushtoeol(struct tvec_state
*tv
, unsigned f
)
180 case '\n': tv
->lno
++; return (rc
);
181 case EOF
: return (rc
);
182 case ';': f
|= TVFF_ALLOWANY
; break;
184 if (!(f
&TVFF_ALLOWANY
) && !isspace(ch
)) {
185 tvec_syntax(tv
, ch
, "end-of-line");
186 rc
= -1; f
|= TVFF_ALLOWANY
;
193 int tvec_nexttoken(struct tvec_state
*tv
)
195 enum { TAIL
, NEWLINE
, INDENT
, COMMENT
};
210 if (s
== NEWLINE
|| s
== INDENT
) { ungetc(ch
, tv
->fp
); return (-1); }
211 else { tv
->lno
++; s
= NEWLINE
; }
216 { if (s
== NEWLINE
) s
= INDENT
; }
217 else if (s
!= COMMENT
) {
219 if (s
== NEWLINE
) return (-1);
227 int tvec_readword(struct tvec_state
*tv
, dstr
*d
, const char *delims
,
228 const char *expect
, ...)
233 va_start(ap
, expect
);
234 rc
= tvec_readword_v(tv
, d
, delims
, expect
, &ap
);
238 int tvec_readword_v(struct tvec_state
*tv
, dstr
*d
, const char *delims
,
239 const char *expect
, va_list *ap
)
244 if (!ch
|| ch
== '\n' || ch
== EOF
|| ch
== ';' ||
245 (delims
&& strchr(delims
, ch
))) {
246 if (expect
) return (tvec_syntax(tv
, ch
, expect
, ap
));
247 else { ungetc(ch
, tv
->fp
); return (-1); }
249 if (d
->len
) DPUTC(d
, ' ');
253 } while (ch
&& ch
!= EOF
&& !isspace(ch
) &&
254 (!delims
|| !strchr(delims
, ch
)));
255 DPUTZ(d
); if (ch
!= EOF
) ungetc(ch
, tv
->fp
);
259 void tvec_resetoutputs(struct tvec_state
*tv
)
261 const struct tvec_regdef
*rd
;
264 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
265 assert(rd
->i
< tv
->nreg
);
266 if (rd
->i
>= tv
->nrout
) continue;
267 r
= TVEC_REG(tv
, out
, rd
->i
);
268 rd
->ty
->release(&r
->v
, rd
);
269 rd
->ty
->init(&r
->v
, rd
);
270 r
->f
= TVEC_REG(tv
, in
, rd
->i
)->f
&TVRF_LIVE
;
274 static void init_registers(struct tvec_state
*tv
)
276 const struct tvec_regdef
*rd
;
279 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
280 assert(rd
->i
< tv
->nreg
); r
= TVEC_REG(tv
, in
, rd
->i
);
281 rd
->ty
->init(&r
->v
, rd
); r
->f
= 0;
282 if (rd
->i
< tv
->nrout
)
283 { r
= TVEC_REG(tv
, out
, rd
->i
); rd
->ty
->init(&r
->v
, rd
); r
->f
= 0; }
287 static void release_registers(struct tvec_state
*tv
)
289 const struct tvec_regdef
*rd
;
292 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
293 assert(rd
->i
< tv
->nreg
); r
= TVEC_REG(tv
, in
, rd
->i
);
294 rd
->ty
->release(&r
->v
, rd
); r
->f
= 0;
295 if (rd
->i
< tv
->nrout
)
296 { r
= TVEC_REG(tv
, out
, rd
->i
); rd
->ty
->release(&r
->v
, rd
); r
->f
= 0; }
300 int tvec_checkregs(struct tvec_state
*tv
)
302 const struct tvec_regdef
*rd
;
303 const struct tvec_reg
*rin
, *rout
;
305 for (rd
= tv
->test
->regs
; rd
->name
; rd
++) {
306 if (rd
->i
>= tv
->nrout
) continue;
307 rin
= TVEC_REG(tv
, in
, rd
->i
); rout
= TVEC_REG(tv
, out
, rd
->i
);
308 if (!rin
->f
&TVRF_LIVE
) continue;
309 if (!(rout
->f
&TVRF_LIVE
) || !rd
->ty
->eq(&rin
->v
, &rout
->v
, rd
))
315 void tvec_check(struct tvec_state
*tv
, const char *detail
, ...)
318 va_start(ap
, detail
); tvec_check_v(tv
, detail
, &ap
); va_end(ap
);
320 void tvec_check_v(struct tvec_state
*tv
, const char *detail
, va_list *ap
)
322 if (tvec_checkregs(tv
))
323 { tvec_fail_v(tv
, detail
, ap
); tvec_mismatch(tv
, TVMF_IN
| TVMF_OUT
); }
326 static void begin_test(struct tvec_state
*tv
)
328 tv
->f
|= TVSF_ACTIVE
; tv
->f
&= ~TVSF_OUTMASK
;
329 tv
->output
->ops
->btest(tv
->output
);
332 void tvec_endtest(struct tvec_state
*tv
)
336 if (tv
->f
&TVSF_ACTIVE
) out
= TVOUT_WIN
;
337 else out
= (tv
->f
&TVSF_OUTMASK
) >> TVSF_OUTSHIFT
;
338 assert(out
< TVOUT_LIMIT
); tv
->curr
[out
]++;
339 tv
->output
->ops
->etest(tv
->output
, out
);
343 static void check(struct tvec_state
*tv
, struct groupstate
*g
)
345 const struct tvec_test
*t
= tv
->test
;
346 const struct tvec_env
*env
;
347 const struct tvec_regdef
*rd
;
349 if (!(tv
->f
&TVSF_OPEN
)) return;
351 for (rd
= t
->regs
; rd
->name
; rd
++) {
352 if (TVEC_REG(tv
, in
, rd
->i
)->f
&TVRF_LIVE
)
353 { if (rd
->i
< tv
->nrout
) TVEC_REG(tv
, out
, rd
->i
)->f
|= TVRF_LIVE
; }
354 else if (!(rd
->f
&TVRF_OPT
)) {
355 tvec_error(tv
, "required register `%s' not set in test `%s'",
361 if (!(tv
->f
&TVSF_SKIP
)) {
364 if (env
&& env
->before
&& env
->before(tv
, g
->ctx
))
365 tvec_skip(tv
, "test setup failed");
367 if (env
&& env
->run
) env
->run(tv
, t
->fn
, g
->ctx
);
368 else { t
->fn(tv
->in
, tv
->out
, g
->ctx
); tvec_check(tv
, 0); }
370 if (env
&& env
->after
) env
->after(tv
, g
->ctx
);
375 tv
->f
&= ~TVSF_OPEN
; release_registers(tv
); init_registers(tv
);
378 static void begin_test_group(struct tvec_state
*tv
, struct groupstate
*g
)
380 const struct tvec_test
*t
= tv
->test
;
381 const struct tvec_env
*env
= t
->env
;
384 tv
->output
->ops
->bgroup(tv
->output
);
387 for (i
= 0; i
< TVOUT_LIMIT
; i
++) tv
->curr
[i
] = 0;
388 if (env
&& env
->ctxsz
) g
->ctx
= xmalloc(env
->ctxsz
);
389 if (env
&& env
->setup
&& env
->setup(tv
, env
, 0, g
->ctx
)) {
390 tvec_skipgroup(tv
, "setup failed");
391 xfree(g
->ctx
); g
->ctx
= 0;
395 static void report_group(struct tvec_state
*tv
)
397 unsigned i
, out
, nrun
;
399 for (i
= 0, nrun
= 0; i
< TVOUT_LIMIT
; i
++)
400 { nrun
+= tv
->curr
[i
]; tv
->all
[i
] += tv
->curr
[i
]; }
402 if (tv
->curr
[TVOUT_SKIP
] == nrun
)
403 { out
= TVOUT_SKIP
; tvec_skipgroup(tv
, nrun ?
0 : "no tests to run"); }
405 if (tv
->curr
[TVOUT_LOSE
]) out
= TVOUT_LOSE
;
406 else out
= TVOUT_WIN
;
407 tv
->grps
[out
]++; tv
->output
->ops
->egroup(tv
->output
);
411 static void end_test_group(struct tvec_state
*tv
, struct groupstate
*g
)
413 const struct tvec_test
*t
= tv
->test
;
414 const struct tvec_env
*env
;
417 if (tv
->f
&TVSF_OPEN
) check(tv
, g
);
418 if (!(tv
->f
&TVSF_SKIP
)) report_group(tv
);
419 env
= t
->env
; if (env
&& env
->teardown
) env
->teardown(tv
, g
->ctx
);
420 release_registers(tv
); tv
->test
= 0; xfree(g
->ctx
); g
->ctx
= 0;
423 int tvec_read(struct tvec_state
*tv
, const char *infile
, FILE *fp
)
426 const struct tvec_test
*test
;
427 const struct tvec_env
*env
;
428 const struct tvec_regdef
*rd
;
430 struct groupstate g
= GROUPSTATE_INIT
;
433 tv
->infile
= infile
; tv
->lno
= 1; tv
->fp
= fp
;
443 end_test_group(tv
, &g
);
445 DRESET(&d
); tvec_readword(tv
, &d
, "];", "group name");
447 ch
= getc(tv
->fp
); if (ch
!= ']') tvec_syntax(tv
, ch
, "`]'");
448 for (test
= tv
->tests
; test
->name
; test
++)
449 if (STRCMP(d
.buf
, ==, test
->name
)) goto found_test
;
450 tvec_error(tv
, "unknown test group `%s'", d
.buf
); goto flush_line
;
452 tvec_flushtoeol(tv
, 0); tv
->test
= test
; begin_test_group(tv
, &g
);
457 if (tv
->f
&TVSF_OPEN
) check(tv
, &g
);
464 if (ch
== EOF
) goto end
;
465 else if (ch
== ';') tvec_flushtoeol(tv
, TVFF_ALLOWANY
);
466 else if (tvec_flushtoeol(tv
, 0)) rc
= -1;
468 } else if (ch
== ';')
469 tvec_flushtoeol(tv
, TVFF_ALLOWANY
);
473 if (tvec_readword(tv
, &d
, "=:;", "register name")) goto flush_line
;
474 tvec_skipspc(tv
); ch
= getc(tv
->fp
);
475 if (ch
!= '=' && ch
!= ':')
476 { tvec_syntax(tv
, ch
, "`=' or `:'"); goto flush_line
; }
479 { tvec_error(tv
, "no current test"); goto flush_line
; }
480 if (d
.buf
[0] == '@') {
482 if (!env
|| !env
->set
) ret
= 0;
483 else ret
= env
->set(tv
, d
.buf
, env
, g
.ctx
);
486 tvec_error(tv
, "unknown special register `%s'", d
.buf
);
489 if (!(tv
->f
&TVSF_OPEN
))
490 { tv
->test_lno
= tv
->lno
; tv
->f
|= TVSF_OPEN
; }
492 for (rd
= tv
->test
->regs
; rd
->name
; rd
++)
493 if (STRCMP(rd
->name
, ==, d
.buf
)) goto found_reg
;
494 tvec_error(tv
, "unknown register `%s' for test `%s'",
495 d
.buf
, tv
->test
->name
);
498 if (!(tv
->f
&TVSF_OPEN
))
499 { tv
->test_lno
= tv
->lno
; tv
->f
|= TVSF_OPEN
; }
501 r
= TVEC_REG(tv
, in
, rd
->i
);
502 if (r
->f
&TVRF_LIVE
) {
503 tvec_error(tv
, "register `%s' already set", rd
->name
);
506 if (rd
->ty
->parse(&r
->v
, rd
, tv
)) goto flush_line
;
515 tvec_flushtoeol(tv
, TVFF_ALLOWANY
); rc
= -1;
518 { tvec_error(tv
, "error reading input: %s", strerror(errno
)); rc
= -1; }
520 end_test_group(tv
, &g
);
521 tv
->infile
= 0; tv
->fp
= 0;
526 /*----- Session lifecycle -------------------------------------------------*/
528 void tvec_begin(struct tvec_state
*tv_out
,
529 const struct tvec_config
*config
,
530 struct tvec_output
*o
)
536 assert(config
->nrout
<= config
->nreg
);
537 tv_out
->nrout
= config
->nrout
; tv_out
->nreg
= config
->nreg
;
538 tv_out
->regsz
= config
->regsz
;
539 tv_out
->in
= xmalloc(tv_out
->nreg
*tv_out
->regsz
);
540 tv_out
->out
= xmalloc(tv_out
->nrout
*tv_out
->regsz
);
541 for (i
= 0; i
< tv_out
->nreg
; i
++) {
542 TVEC_REG(tv_out
, in
, i
)->f
= 0;
543 if (i
< tv_out
->nrout
) TVEC_REG(tv_out
, out
, i
)->f
= 0;
546 for (i
= 0; i
< TVOUT_LIMIT
; i
++)
547 tv_out
->curr
[i
] = tv_out
->all
[i
] = tv_out
->grps
[i
] = 0;
549 tv_out
->tests
= config
->tests
; tv_out
->test
= 0;
550 tv_out
->infile
= 0; tv_out
->lno
= 0; tv_out
->fp
= 0;
551 tv_out
->output
= o
; tv_out
->output
->ops
->bsession(tv_out
->output
, tv_out
);
554 int tvec_end(struct tvec_state
*tv
)
556 int rc
= tv
->output
->ops
->esession(tv
->output
);
558 tv
->output
->ops
->destroy(tv
->output
);
559 xfree(tv
->in
); xfree(tv
->out
);
563 /*----- Serialization and deserialization ---------------------------------*/
565 int tvec_serialize(const struct tvec_reg
*rv
, buf
*b
,
566 const struct tvec_regdef
*regs
,
567 unsigned nr
, size_t regsz
)
569 unsigned char *bitmap
;
570 size_t i
, bitoff
, nbits
, bitsz
;
571 const struct tvec_regdef
*rd
;
572 const struct tvec_reg
*r
;
575 for (rd
= regs
, nbits
= 0; rd
->name
; rd
++, nbits
++);
576 bitsz
= (nbits
+ 7)/8;
578 bitmap
= buf_get(b
, bitsz
); if (!bitmap
) return (-1);
579 memset(bitmap
, 0, bitsz
);
580 for (rd
= regs
, i
= 0; rd
->name
; rd
++, i
++) {
581 if (rd
->i
>= nr
) continue;
582 r
= TVEC_GREG(rv
, rd
->i
, regsz
); if (!(r
->f
&TVRF_LIVE
)) continue;
583 bitmap
= BBASE(b
) + bitoff
; bitmap
[rd
->i
/8] |= 1 << rd
->i
%8;
584 if (rd
->ty
->tobuf(b
, &r
->v
, rd
)) return (-1);
589 int tvec_deserialize(struct tvec_reg
*rv
, buf
*b
,
590 const struct tvec_regdef
*regs
,
591 unsigned nr
, size_t regsz
)
593 const unsigned char *bitmap
;
594 size_t i
, nbits
, bitsz
;
595 const struct tvec_regdef
*rd
;
598 for (rd
= regs
, nbits
= 0; rd
->name
; rd
++, nbits
++);
599 bitsz
= (nbits
+ 7)/8;
601 bitmap
= buf_get(b
, bitsz
); if (!bitmap
) return (-1);
602 for (rd
= regs
, i
= 0; rd
->name
; rd
++, i
++) {
603 if (rd
->i
>= nr
) continue;
604 if (!(bitmap
[rd
->i
/8]&(1 << rd
->i
%8))) continue;
605 r
= TVEC_GREG(rv
, rd
->i
, regsz
);
606 if (rd
->ty
->frombuf(b
, &r
->v
, rd
)) return (-1);
612 /*----- Ad-hoc testing ----------------------------------------------------*/
614 static const struct tvec_regdef no_regs
= { 0, 0, 0, 0, { 0 } };
616 static void fakefn(const struct tvec_reg
*in
, struct tvec_reg
*out
, void *p
)
617 { assert(!"fake test function"); }
619 void tvec_adhoc(struct tvec_state
*tv
, struct tvec_test
*t
)
621 t
->name
= "<unset>"; t
->regs
= &no_regs
; t
->env
= 0; t
->fn
= fakefn
;
625 void tvec_begingroup(struct tvec_state
*tv
, const char *name
,
626 const char *file
, unsigned lno
)
628 struct tvec_test
*t
= (/*unconst*/ struct tvec_test
*)tv
->tests
;
630 t
->name
= name
; tv
->test
= t
;
631 tv
->infile
= file
; tv
->lno
= tv
->test_lno
= lno
;
632 begin_test_group(tv
, 0);
635 void tvec_endgroup(struct tvec_state
*tv
)
637 if (!(tv
->f
&TVSF_SKIP
)) report_group(tv
);
641 void tvec_begintest(struct tvec_state
*tv
, const char *file
, unsigned lno
)
643 tv
->infile
= file
; tv
->lno
= tv
->test_lno
= lno
;
644 begin_test(tv
); tv
->f
|= TVSF_OPEN
;
650 const char *saved_file
; unsigned saved_lno
;
653 static void adhoc_claim_setup(struct tvec_state
*tv
,
654 struct adhoc_claim
*ck
,
655 const struct tvec_regdef
*regs
,
656 const char *file
, unsigned lno
)
658 struct tvec_test
*t
= (/*unconst*/ struct tvec_test
*)tv
->test
;
662 if (!(tv
->f
&TVSF_OPEN
))
663 { ck
->f
|= ACF_FRESH
; tvec_begintest(tv
, file
, lno
); }
665 ck
->saved_file
= tv
->infile
; if (file
) tv
->infile
= file
;
666 ck
->saved_lno
= tv
->test_lno
; if (file
) tv
->test_lno
= lno
;
667 t
->regs
= regs ? regs
: &no_regs
;
670 static void adhoc_claim_teardown(struct tvec_state
*tv
,
671 struct adhoc_claim
*ck
)
673 struct tvec_test
*t
= (/*unconst*/ struct tvec_test
*)tv
->test
;
676 tv
->infile
= ck
->saved_file
; tv
->test_lno
= ck
->saved_lno
;
678 if (ck
->f
&ACF_FRESH
) tvec_endtest(tv
);
681 int tvec_claim_v(struct tvec_state
*tv
, int ok
,
682 const char *file
, unsigned lno
,
683 const char *msg
, va_list *ap
)
685 struct adhoc_claim ck
;
687 adhoc_claim_setup(tv
, &ck
, 0, file
, lno
);
688 if (!ok
) tvec_fail_v(tv
, msg
, ap
);
689 adhoc_claim_teardown(tv
, &ck
);
693 int tvec_claim(struct tvec_state
*tv
, int ok
,
694 const char *file
, unsigned lno
, const char *msg
, ...)
698 va_start(ap
, msg
); tvec_claim_v(tv
, ok
, file
, lno
, msg
, &ap
); va_end(ap
);
702 int tvec_claimeq(struct tvec_state
*tv
,
703 const struct tvec_regty
*ty
, const union tvec_misc
*arg
,
704 const char *file
, unsigned lno
, const char *expr
)
706 struct tvec_regdef regs
[2];
707 struct adhoc_claim ck
;
710 tv
->in
[0].f
= tv
->out
[0].f
= TVRF_LIVE
;
712 regs
[0].name
= "value"; regs
[0].i
= 0;
713 regs
[0].ty
= ty
; regs
[0].f
= 0;
714 if (arg
) regs
[0].arg
= *arg
;
715 else regs
[0].arg
.p
= 0;
719 adhoc_claim_setup(tv
, &ck
, regs
, file
, lno
);
720 ok
= ty
->eq(&tv
->in
[0].v
, &tv
->out
[0].v
, ®s
[0]);
722 { tvec_fail(tv
, "%s", expr
); tvec_mismatch(tv
, TVMF_IN
| TVMF_OUT
); }
723 adhoc_claim_teardown(tv
, &ck
);
727 /*----- That's all, folks -------------------------------------------------*/