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