#include "dat.h" #include "fn.h" #include "test.h" Str mkstr(char *s) { Str r; sinit(&r, s, strlen(s)); return r; } int checkstr(struct ct *t, char *where, char *want, Str *got) { char buf[Maxutf]; stoutf(got, buf, sizeof buf); if(strcmp(want, buf) == 0) return 1; return CT_ERRORF(t, "%s: want \"%s\", got \"%s\"", where, want, buf); } void checkenginepreedit(struct ct *t, char *want) { Str preedit; testenginepreedit(&preedit); checkstr(t, "engine preedit", want, &preedit); } static void pumpthread(void *arg) { Pump *p; Keyreq req; uchar token; Alt alts[] = { {nil, &req, CHANRCV, nil}, {nil, &token, CHANRCV, nil}, {nil, nil, CHANEND, nil}, }; p = arg; alts[0].c = keyc; alts[1].c = p->stop; for(;;) switch(alt(alts)){ case 0: chansend(p->trace, &req); if(p->holdop == Pumpall || p->holdop == req.op) chanrecv(p->go, &token); testenginehandle(&req); break; case 1: chansend(p->done, &token); return; } } /* ntrace is the trace channel's depth: 0 makes every trace a rendezvous. */ void pumpstart(Pump *p, int ntrace) { memset(p, 0, sizeof *p); p->trace = chancreate(sizeof(Keyreq), ntrace); p->go = chancreate(sizeof(uchar), 0); p->stop = chancreate(sizeof(uchar), 0); p->done = chancreate(sizeof(uchar), 0); p->holdop = Pumpnone; /* Its own proc: tests block in socket I/O while the engine runs. */ proccreate(pumpthread, p, 8192); p->active = 1; } void pumphold(Pump *p, int op) { p->holdop = op; } /* Every held request must have been let go before stopping. */ void pumpstop(Pump *p) { Keyreq req; uchar token; if(!p->active) return; while(channbrecv(p->trace, &req) > 0) ; token = 0; chansend(p->stop, &token); chanrecv(p->done, &token); chanfree(p->trace); chanfree(p->go); chanfree(p->stop); chanfree(p->done); p->active = 0; }