test/harness/testcase.c
author ali <ali@juiblex.co.uk>
Tue Jan 24 23:54:05 2012 +0000 (2012-01-24)
changeset 0 c2f4c0285180
child 3 ec364358631b
permissions -rw-r--r--
Initial version
ali@0
     1
#include <stdlib.h>
ali@0
     2
#include <stdio.h>
ali@0
     3
#include <string.h>
ali@0
     4
#include <unistd.h>
ali@0
     5
#include <errno.h>
ali@0
     6
#ifdef WIN32
ali@0
     7
#include <io.h>
ali@0
     8
#include <fcntl.h>
ali@0
     9
#endif
ali@0
    10
#include <gclib/gclib.h>
ali@0
    11
#include "testcase.h"
ali@0
    12
ali@0
    13
#if !HAVE_MKSTEMP
ali@0
    14
/*
ali@0
    15
 * An insecure implementation of mkstemp(), for those platforms that
ali@0
    16
 * don't support it.
ali@0
    17
 */
ali@0
    18
int mkstemp(char *template)
ali@0
    19
{
ali@0
    20
    int fd;
ali@0
    21
    char *s;
ali@0
    22
    for(;;)
ali@0
    23
    {
ali@0
    24
	s=str_dup(template);
ali@0
    25
	mktemp(s);
ali@0
    26
	if (!*s)
ali@0
    27
	{
ali@0
    28
	    errno=EEXIST;
ali@0
    29
	    mem_free(s);
ali@0
    30
	    return -1;
ali@0
    31
	}
ali@0
    32
	fd=open(s,O_RDWR|O_CREAT|O_EXCL,0600);
ali@0
    33
	if (fd>0)
ali@0
    34
	{
ali@0
    35
	    strcpy(template,s);
ali@0
    36
	    mem_free(s);
ali@0
    37
	    return fd;
ali@0
    38
	}
ali@0
    39
	else
ali@0
    40
	    mem_free(s);
ali@0
    41
    }
ali@0
    42
}
ali@0
    43
#endif	/* !HAVE_MKSTEMP */
ali@0
    44
ali@0
    45
/*
ali@0
    46
 * As write(), but always convert NL to CR NL.
ali@0
    47
 */
ali@0
    48
static size_t write_text(int fd,const char *buf,size_t count)
ali@0
    49
{
ali@0
    50
    size_t i;
ali@0
    51
    FILE *fp;
ali@0
    52
    fd=dup(fd);
ali@0
    53
    if (fd<0)
ali@0
    54
	return -1;
ali@0
    55
#ifdef WIN32
ali@0
    56
    if (_setmode(fd,_O_BINARY)<0)
ali@0
    57
    {
ali@0
    58
	close(fd);
ali@0
    59
	return -1;
ali@0
    60
    }
ali@0
    61
#endif
ali@0
    62
    fp=fdopen(fd,"wb");
ali@0
    63
    if (!fp)
ali@0
    64
    {
ali@0
    65
	close(fd);
ali@0
    66
	return -1;
ali@0
    67
    }
ali@0
    68
    for(i=0;i<count;i++)
ali@0
    69
    {
ali@0
    70
	if (buf[i]=='\n')
ali@0
    71
	    if (putc('\r',fp)==EOF)
ali@0
    72
	    {
ali@0
    73
		(void)fclose(fp);
ali@0
    74
		return -1;
ali@0
    75
	    }
ali@0
    76
	if (putc(buf[i],fp)==EOF)
ali@0
    77
	{
ali@0
    78
	    (void)fclose(fp);
ali@0
    79
	    return -1;
ali@0
    80
	}
ali@0
    81
    }
ali@0
    82
    if (fclose(fp))
ali@0
    83
	return -1;
ali@0
    84
    return count;
ali@0
    85
}
ali@0
    86
ali@0
    87
/*
ali@0
    88
 * Return the length (in bytes) or any common prefix between s1 and s2.
ali@0
    89
 */
ali@0
    90
size_t common_prefix_length(const char *s1,const char *s2)
ali@0
    91
{
ali@0
    92
    size_t i;
ali@0
    93
    for(i=0;s1[i] && s2[i] && s1[i]==s2[i];i++)
ali@0
    94
	;
ali@0
    95
    return i;
ali@0
    96
}
ali@0
    97
ali@0
    98
/*
ali@0
    99
 * Run a testcase, returning FALSE on fail or error and
ali@0
   100
 * TRUE on pass or expected-fail.
ali@0
   101
 * Suitable message(s) will be printed in all cases.
ali@0
   102
 */
ali@0
   103
boolean testcase_run(Testcase *testcase)
ali@0
   104
{
ali@0
   105
    boolean r;
ali@0
   106
    int fd,exit_status,col;
ali@0
   107
    size_t n,pos,offset,header_len;
ali@0
   108
    FILE *fp;
ali@0
   109
    char input[]="TEST-XXXXXX";
ali@0
   110
    char *endp,*bol;
ali@0
   111
    char *command[3];
ali@0
   112
    String *expected,*report;
ali@0
   113
    char *output;
ali@0
   114
    fd=mkstemp(input);
ali@0
   115
    if (testcase->input)
ali@0
   116
	n=strlen(testcase->input);
ali@0
   117
    else
ali@0
   118
	n=0;
ali@0
   119
    if (n && write_text(fd,testcase->input,n)!=n)
ali@0
   120
    {
ali@0
   121
	perror(input);
ali@0
   122
	close(fd);
ali@0
   123
	(void)remove(input);
ali@0
   124
	return FALSE;
ali@0
   125
    }
ali@0
   126
    close(fd);
ali@0
   127
    command[0]=getenv("GUTCHECK");
ali@0
   128
    if (!command[0])
ali@0
   129
	command[0]="." GC_DIR_SEPARATOR_S "gutcheck";
ali@0
   130
    command[1]=input;
ali@0
   131
    command[2]=NULL;
ali@0
   132
    if (testcase->expected)
ali@0
   133
	r=spawn_sync(command,&output,&exit_status);
ali@0
   134
    else
ali@0
   135
    {
ali@0
   136
	r=spawn_sync(command,NULL,&exit_status);
ali@0
   137
	output=NULL;
ali@0
   138
    }
ali@0
   139
    (void)remove(input);
ali@0
   140
    if (!r)
ali@0
   141
	return FALSE;
ali@0
   142
    if (testcase->expected)
ali@0
   143
    {
ali@0
   144
	expected=string_new("\n\nFile: ");
ali@0
   145
	string_append(expected,input);
ali@0
   146
	string_append(expected,"\n\n\n");
ali@0
   147
	header_len=expected->len;
ali@0
   148
	string_append(expected,testcase->expected);
ali@0
   149
    }
ali@0
   150
    else
ali@0
   151
    {
ali@0
   152
	expected=NULL;
ali@0
   153
	header_len=0;
ali@0
   154
    }
ali@0
   155
    if (expected && strcmp(output,expected->str))
ali@0
   156
    {
ali@0
   157
	fprintf(stderr,"%s: FAIL\n",testcase->basename);
ali@0
   158
	offset=common_prefix_length(output,expected->str);
ali@0
   159
	if (offset==header_len && !output[offset])
ali@0
   160
	    fprintf(stderr,"Unexpected zero warnings from gutcheck.\n");
ali@0
   161
	else
ali@0
   162
	{
ali@0
   163
	    endp=strchr(output+offset,'\n');
ali@0
   164
	    if (!endp)
ali@0
   165
		endp=output+strlen(output);
ali@0
   166
	    report=string_new(NULL);
ali@0
   167
	    string_append_len(report,output,endp-output);
ali@0
   168
	    bol=strrchr(report->str,'\n');
ali@0
   169
	    if (bol)
ali@0
   170
		bol++;
ali@0
   171
	    else
ali@0
   172
		bol=report->str;
ali@0
   173
	    col=offset-(bol-report->str);
ali@0
   174
	    fprintf(stderr,"Unexpected output from gutcheck:\n");
ali@0
   175
	    if (report->len>=header_len)
ali@0
   176
		fprintf(stderr,"%s\n%*s^\n",report->str+header_len,col,"");
ali@0
   177
	    else
ali@0
   178
		fprintf(stderr,"%s\n%*s^\n",report->str,col,"");
ali@0
   179
	    string_free(report,TRUE);
ali@0
   180
	}
ali@0
   181
	string_free(expected,TRUE);
ali@0
   182
	mem_free(output);
ali@0
   183
	return FALSE;
ali@0
   184
    }
ali@0
   185
    string_free(expected,TRUE);
ali@0
   186
    mem_free(output);
ali@0
   187
    if (exit_status)
ali@0
   188
	fprintf(stderr,"gutcheck exited with code %d\n",r);
ali@0
   189
    if (!exit_status)
ali@0
   190
	fprintf(stderr,"%s: PASS\n",testcase->basename);
ali@0
   191
    return !exit_status;
ali@0
   192
}
ali@0
   193
ali@0
   194
/*
ali@0
   195
 * Free a testcase.
ali@0
   196
 */
ali@0
   197
void testcase_free(Testcase *testcase)
ali@0
   198
{
ali@0
   199
    mem_free(testcase->basename);
ali@0
   200
    mem_free(testcase->input);
ali@0
   201
    mem_free(testcase->expected);
ali@0
   202
    mem_free(testcase);
ali@0
   203
}