/* * Correctness-test pnminsdel. * * Runs pnminsdel repeatedly, with randomly-chosen arguments and input * data, checking that the output is what it should be. * * Each run randomly chooses: * * * Size of input, each coordinate random in [8..16] * * Input pixels are random * * 0 to 15 command-line args * * Each command-line arg is, randomly, * * X or Y axis * * Insert [1..8] pixels of random value, at random location * * Delete [1..size-1] pixels at random location * (deletes are suppressed if size is 1) * * The correct output is computed by copying pixels around in an array; * the actual output is compared with this. */ #include #include #include #include #include #include #include #include #include #include extern const char *__progname; static unsigned char image[256][256]; static int image_x; static int image_y; static unsigned char input[16][16]; static int input_x; static int input_y; static int testpass; static void init(void) { srandom(time(0)); testpass = 0; } static void test_case(void) { int x; int y; int a; int e; int i; int c; int ip[2]; int op[2]; int xp[2]; pid_t tkid; pid_t ikid; pid_t kid; int status; char *subargs[64]; int nsubargs; FILE *f; char *hdr; auto void add_arg(const char *, ...) __attribute__((__format__(__printf__,1,2))); auto void add_arg(const char *fmt, ...) { va_list ap; va_start(ap,fmt); vasprintf(&subargs[nsubargs],fmt,ap); va_end(ap); nsubargs ++; } auto void fail(const char *, ...) __attribute__((__format__(__printf__,1,2),__noreturn__)); auto void fail(const char *fmt, ...) { int i; int x; int y; va_list ap; fprintf(stderr,"%s: failure: ",__progname); va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap); fprintf(stderr,"\narglist:"); for (i=0;subargs[i];i++) fprintf(stderr," %s",subargs[i]); fprintf(stderr,"\ninput image:\nP2\n%d %d\n255\n",input_x,input_y); for (y=0;y=0;y--) for (x=input_x-1;x>=0;x--) { input[x][y] = random() & 0xff; image[x][y] = input[x][y]; } nsubargs = 0; add_arg("pnminsdel"); for (a=15;a>0;a--) { if (random() % 3) { if (random() % 3) { char axis; int n; int loc; int v; axis = (random() & 1) ? 'y' : 'x'; n = 1 + (random() % 8); loc = random() % (1 + ((axis=='x') ? image_x : image_y)); v = random() & 0xff; add_arg("ins%c",axis); add_arg("%d@%d",n,loc); add_arg("%d",v); switch (axis) { case 'x': for (y=image_y-1;y>=0;y--) for (x=image_x-1;x>=0;x--) { if (x >= loc) image[x+n][y] = image[x][y]; } for (y=image_y-1;y>=0;y--) for (x=n-1;x>=0;x--) { image[loc+x][y] = v; } image_x += n; break; case 'y': for (y=image_y-1;y>=0;y--) for (x=image_x-1;x>=0;x--) { if (y >= loc) image[x][y+n] = image[x][y]; } for (y=n-1;y>=0;y--) for (x=image_x-1;x>=0;x--) { image[x][loc+y] = v; } image_y += n; break; default: abort(); break; } } else { char axis; int n; int d; int loc; axis = (random() & 1) ? 'y' : 'x'; d = (axis == 'x') ? image_x : image_y; if (d < 2) continue; n = (random() % (d-1)) + 1; loc = random() % (d - n + 1); add_arg("del%c",axis); add_arg("%d@%d",n,loc); switch (axis) { case 'x': for (y=0;y= n+loc) image[x-n][y] = image[x][y]; } image_x -= n; break; case 'y': for (y=0;y= n+loc) image[x][y-n] = image[x][y]; } image_y -= n; break; default: abort(); break; } } } } subargs[nsubargs] = 0; if ((pipe(&ip[0]) < 0) || (pipe(&op[0]) < 0)) { fprintf(stderr,"%s: pipe: %s\n",__progname,strerror(errno)); exit(1); } if (socketpair(AF_LOCAL,SOCK_STREAM,0,&xp[0]) < 0) { fprintf(stderr,"%s: socketpair: %s\n",__progname,strerror(errno)); exit(1); } tkid = fork(); if (tkid < 0) { fprintf(stderr,"%s: fork: %s\n",__progname,strerror(errno)); exit(1); } if (tkid == 0) { close(ip[1]); close(op[0]); if (ip[0] != 0) { dup2(ip[0],0); close(ip[0]); } if (op[1] != 1) { dup2(op[1],1); close(op[1]); } close(xp[0]); fcntl(xp[1],F_SETFD,1); execv("pnminsdel",&subargs[0]); e = errno; write(xp[1],&e,sizeof(int)); exit(1); } close(xp[0]); close(ip[0]); close(op[1]); i = recv(xp[1],&e,sizeof(e),MSG_WAITALL); if (i == sizeof(e)) { fprintf(stderr,"%s: exec pnminsdel: %s\n",__progname,strerror(e)); exit(1); } if (i != 0) { fprintf(stderr,"%s: bizarre exec pipe error: got %d not %d\n",__progname,i,(int)sizeof(e)); exit(1); } close(xp[1]); ikid = fork(); if (ikid < 0) { fprintf(stderr,"%s: fork: %s\n",__progname,strerror(errno)); exit(1); } if (ikid == 0) { close(op[0]); f = fdopen(ip[1],"w"); fprintf(f,"P5\n%d %d\n255\n",input_x,input_y); for (y=0;y= 0) || (tkid >= 0)) { kid = wait(&status); if (kid < 0) { fprintf(stderr,"%s: wait: %s\n",__progname,strerror(errno)); exit(1); } if (kid == ikid) { ikid = -1; continue; } if (kid == tkid) { tkid = -1; if (WIFEXITED(status)) { if (WEXITSTATUS(status)) { fail("exit %d",WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { fail("signal %d%s",WTERMSIG(status),WCOREDUMP(status)?" (core dumped)":""); } continue; } fprintf(stderr,"%s: unknown child %d died\n",__progname,(int)kid); } while (nsubargs > 0) free(subargs[--nsubargs]); testpass ++; if ((testpass % 1000) == 0) { printf("%d\n",testpass); fflush(stdout); } } int main(void); int main(void) { init(); while (1) test_case(); }