1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/test/harness/testcase.c Wed Jan 25 19:33:43 2012 +0000
1.3 @@ -0,0 +1,203 @@
1.4 +#include <stdlib.h>
1.5 +#include <stdio.h>
1.6 +#include <string.h>
1.7 +#include <unistd.h>
1.8 +#include <errno.h>
1.9 +#ifdef WIN32
1.10 +#include <io.h>
1.11 +#include <fcntl.h>
1.12 +#endif
1.13 +#include <gclib/gclib.h>
1.14 +#include "testcase.h"
1.15 +
1.16 +#if !HAVE_MKSTEMP
1.17 +/*
1.18 + * An insecure implementation of mkstemp(), for those platforms that
1.19 + * don't support it.
1.20 + */
1.21 +int mkstemp(char *template)
1.22 +{
1.23 + int fd;
1.24 + char *s;
1.25 + for(;;)
1.26 + {
1.27 + s=str_dup(template);
1.28 + mktemp(s);
1.29 + if (!*s)
1.30 + {
1.31 + errno=EEXIST;
1.32 + mem_free(s);
1.33 + return -1;
1.34 + }
1.35 + fd=open(s,O_RDWR|O_CREAT|O_EXCL,0600);
1.36 + if (fd>0)
1.37 + {
1.38 + strcpy(template,s);
1.39 + mem_free(s);
1.40 + return fd;
1.41 + }
1.42 + else
1.43 + mem_free(s);
1.44 + }
1.45 +}
1.46 +#endif /* !HAVE_MKSTEMP */
1.47 +
1.48 +/*
1.49 + * As write(), but always convert NL to CR NL.
1.50 + */
1.51 +static size_t write_text(int fd,const char *buf,size_t count)
1.52 +{
1.53 + size_t i;
1.54 + FILE *fp;
1.55 + fd=dup(fd);
1.56 + if (fd<0)
1.57 + return -1;
1.58 +#ifdef WIN32
1.59 + if (_setmode(fd,_O_BINARY)<0)
1.60 + {
1.61 + close(fd);
1.62 + return -1;
1.63 + }
1.64 +#endif
1.65 + fp=fdopen(fd,"wb");
1.66 + if (!fp)
1.67 + {
1.68 + close(fd);
1.69 + return -1;
1.70 + }
1.71 + for(i=0;i<count;i++)
1.72 + {
1.73 + if (buf[i]=='\n')
1.74 + if (putc('\r',fp)==EOF)
1.75 + {
1.76 + (void)fclose(fp);
1.77 + return -1;
1.78 + }
1.79 + if (putc(buf[i],fp)==EOF)
1.80 + {
1.81 + (void)fclose(fp);
1.82 + return -1;
1.83 + }
1.84 + }
1.85 + if (fclose(fp))
1.86 + return -1;
1.87 + return count;
1.88 +}
1.89 +
1.90 +/*
1.91 + * Return the length (in bytes) or any common prefix between s1 and s2.
1.92 + */
1.93 +size_t common_prefix_length(const char *s1,const char *s2)
1.94 +{
1.95 + size_t i;
1.96 + for(i=0;s1[i] && s2[i] && s1[i]==s2[i];i++)
1.97 + ;
1.98 + return i;
1.99 +}
1.100 +
1.101 +/*
1.102 + * Run a testcase, returning FALSE on fail or error and
1.103 + * TRUE on pass or expected-fail.
1.104 + * Suitable message(s) will be printed in all cases.
1.105 + */
1.106 +boolean testcase_run(Testcase *testcase)
1.107 +{
1.108 + boolean r;
1.109 + int fd,exit_status,col;
1.110 + size_t n,pos,offset,header_len;
1.111 + FILE *fp;
1.112 + char input[]="TEST-XXXXXX";
1.113 + char *endp,*bol;
1.114 + char *command[3];
1.115 + String *expected,*report;
1.116 + char *output;
1.117 + fd=mkstemp(input);
1.118 + if (testcase->input)
1.119 + n=strlen(testcase->input);
1.120 + else
1.121 + n=0;
1.122 + if (n && write_text(fd,testcase->input,n)!=n)
1.123 + {
1.124 + perror(input);
1.125 + close(fd);
1.126 + (void)remove(input);
1.127 + return FALSE;
1.128 + }
1.129 + close(fd);
1.130 + command[0]=getenv("GUTCHECK");
1.131 + if (!command[0])
1.132 + command[0]="." GC_DIR_SEPARATOR_S "gutcheck";
1.133 + command[1]=input;
1.134 + command[2]=NULL;
1.135 + if (testcase->expected)
1.136 + r=spawn_sync(command,&output,&exit_status);
1.137 + else
1.138 + {
1.139 + r=spawn_sync(command,NULL,&exit_status);
1.140 + output=NULL;
1.141 + }
1.142 + (void)remove(input);
1.143 + if (!r)
1.144 + return FALSE;
1.145 + if (testcase->expected)
1.146 + {
1.147 + expected=string_new("\n\nFile: ");
1.148 + string_append(expected,input);
1.149 + string_append(expected,"\n\n\n");
1.150 + header_len=expected->len;
1.151 + string_append(expected,testcase->expected);
1.152 + }
1.153 + else
1.154 + {
1.155 + expected=NULL;
1.156 + header_len=0;
1.157 + }
1.158 + if (expected && strcmp(output,expected->str))
1.159 + {
1.160 + fprintf(stderr,"%s: FAIL\n",testcase->basename);
1.161 + offset=common_prefix_length(output,expected->str);
1.162 + if (offset==header_len && !output[offset])
1.163 + fprintf(stderr,"Unexpected zero warnings from gutcheck.\n");
1.164 + else
1.165 + {
1.166 + endp=strchr(output+offset,'\n');
1.167 + if (!endp)
1.168 + endp=output+strlen(output);
1.169 + report=string_new(NULL);
1.170 + string_append_len(report,output,endp-output);
1.171 + bol=strrchr(report->str,'\n');
1.172 + if (bol)
1.173 + bol++;
1.174 + else
1.175 + bol=report->str;
1.176 + col=offset-(bol-report->str);
1.177 + fprintf(stderr,"Unexpected output from gutcheck:\n");
1.178 + if (report->len>=header_len)
1.179 + fprintf(stderr,"%s\n%*s^\n",report->str+header_len,col,"");
1.180 + else
1.181 + fprintf(stderr,"%s\n%*s^\n",report->str,col,"");
1.182 + string_free(report,TRUE);
1.183 + }
1.184 + string_free(expected,TRUE);
1.185 + mem_free(output);
1.186 + return FALSE;
1.187 + }
1.188 + string_free(expected,TRUE);
1.189 + mem_free(output);
1.190 + if (exit_status)
1.191 + fprintf(stderr,"gutcheck exited with code %d\n",r);
1.192 + if (!exit_status)
1.193 + fprintf(stderr,"%s: PASS\n",testcase->basename);
1.194 + return !exit_status;
1.195 +}
1.196 +
1.197 +/*
1.198 + * Free a testcase.
1.199 + */
1.200 +void testcase_free(Testcase *testcase)
1.201 +{
1.202 + mem_free(testcase->basename);
1.203 + mem_free(testcase->input);
1.204 + mem_free(testcase->expected);
1.205 + mem_free(testcase);
1.206 +}