diff -r faab25d520dd -r 721e468c10f3 test/harness/testcase.c --- a/test/harness/testcase.c Fri Jan 27 16:18:02 2012 +0000 +++ b/test/harness/testcase.c Fri Jan 27 21:40:35 2012 +0000 @@ -10,6 +10,11 @@ #include #include "testcase.h" +GQuark testcase_error_quark(void) +{ + return g_quark_from_static_string("testcase-error-quark"); +} + #if !HAVE_MKSTEMP /* * An insecure implementation of mkstemp(), for those platforms that @@ -45,7 +50,7 @@ /* * As write(), but always convert NL to CR NL. */ -static size_t write_text(int fd,const char *buf,size_t count) +static size_t write_text(int fd,const char *buf,size_t count,GError **error) { size_t i; FILE *fp; @@ -56,6 +61,9 @@ if (_setmode(fd,_O_BINARY)<0) { close(fd); + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), + "Failed to set mode of bookloupe input file to binary: %s", + g_strerror(errno)); return -1; } #endif @@ -63,6 +71,9 @@ if (!fp) { close(fd); + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), + "Failed to open stream to bookloupe input file: %s", + g_strerror(errno)); return -1; } for(i=0;istr,'\n'); + if (bol) + bol++; + else + bol=string->str; + col=differs_at-(bol-string->str); + fprintf(stderr,"%s\n%*s^\n",string->str,col,""); + g_string_free(string,TRUE); +} + +gboolean spawn_bootloupe(const char *encoding,const char *standard_input, + char **standard_output,char **filename,GError **error) +{ + gboolean r; + int fd,exit_status; + size_t n,pos,offset; + FILE *fp; + char input[]="TEST-XXXXXX"; + char *command[3]; + char *output,*s; + GError *tmp_err=NULL; + if (standard_input) + { + if (encoding) + { + s=g_convert(standard_input,-1,encoding,"UTF-8",NULL,&n,&tmp_err); + if (!s) + { + g_propagate_prefixed_error(error,tmp_err, + "Conversion to %s failed: ",encoding); + return FALSE; + } + } + else + { + s=g_strdup(standard_input); + n=strlen(s); + } + } + else + { + n=0; + s=NULL; + } + fd=mkstemp(input); + if (n && write_text(fd,s,n,error)!=n) + { + g_free(s); + close(fd); + (void)remove(input); + return FALSE; + } + g_free(s); + close(fd); + command[0]=getenv("BOOKLOUPE"); + if (!command[0]) + command[0]="." G_DIR_SEPARATOR_S "bookloupe"; + command[1]=input; + command[2]=NULL; + if (standard_output) + { + r=spawn_sync(command,&s,&exit_status,error); + if (r) + { + if (encoding) + { + output=g_convert(s,-1,"UTF-8",encoding,NULL,NULL,&tmp_err); + g_free(s); + if (!output) + { + g_propagate_prefixed_error(error,tmp_err, + "Conversion from %s failed: ",encoding); + r=FALSE; + } + } + else + { + output=s; + if (!g_utf8_validate(s,-1,NULL)) + { + g_set_error_literal(error,TESTCASE_ERROR, + TESTCASE_ERROR_FAILED, + "bookloupe output is not valid UTF-8"); + r=FALSE; + } + } + } + } + else + { + r=spawn_sync(command,NULL,&exit_status,error); + output=NULL; + } + (void)remove(input); + if (r && exit_status) + { + g_set_error(error,TESTCASE_ERROR,TESTCASE_ERROR_FAILED, + "bookloupe exited with code %d",exit_status); + r=FALSE; + } + if (r && filename) + *filename=g_strdup(input); + if (r && standard_output) + *standard_output=output; + return r; +} + /* * Run a testcase, returning FALSE on fail or error and * TRUE on pass or expected-fail. @@ -103,92 +238,76 @@ gboolean testcase_run(Testcase *testcase) { gboolean r; - int fd,exit_status,col; - size_t n,pos,offset,header_len; - FILE *fp; - char input[]="TEST-XXXXXX"; - char *endp,*bol; - char *command[3]; - GString *expected,*report; - char *output; - fd=mkstemp(input); - if (testcase->input) - n=strlen(testcase->input); + size_t pos,offset; + GString *header,*expected; + char *output,*filename,*s; + GError *error=NULL; + if (testcase->expected) + r=spawn_bootloupe(testcase->encoding,testcase->input,&output,&filename, + &error); else - n=0; - if (n && write_text(fd,testcase->input,n)!=n) { - perror(input); - close(fd); - (void)remove(input); + r=spawn_bootloupe(testcase->encoding,testcase->input,NULL,NULL,&error); + output=filename=NULL; + } + if (!r) + { + fprintf(stderr,"%s: FAIL\n",testcase->basename); + fprintf(stderr,"%s\n",error->message); + g_error_free(error); return FALSE; } - close(fd); - command[0]=getenv("BOOKLOUPE"); - if (!command[0]) - command[0]="." G_DIR_SEPARATOR_S "bookloupe"; - command[1]=input; - command[2]=NULL; - if (testcase->expected) - r=spawn_sync(command,&output,&exit_status); - else - { - r=spawn_sync(command,NULL,&exit_status); - output=NULL; - } - (void)remove(input); - if (!r) - return FALSE; if (testcase->expected) { - expected=g_string_new("\n\nFile: "); - g_string_append(expected,input); - g_string_append(expected,"\n\n\n"); - header_len=expected->len; - g_string_append(expected,testcase->expected); + header=g_string_new("\n\nFile: "); + g_string_append(header,filename); + g_string_append(header,"\n"); + expected=g_string_new(testcase->expected); + if (!g_str_has_prefix(output,header->str)) + { + fprintf(stderr,"%s: FAIL\n",testcase->basename); + offset=common_prefix_length(output,header->str); + fprintf(stderr,"Unexpected header from bookloupe:\n"); + print_unexpected(output,offset); + r=FALSE; + } + pos=header->len; + if (r) + { + /* Skip the summary */ + s=strstr(output+pos,"\n\n"); + if (s) + pos=s-output+2; + else + { + fprintf(stderr,"%s: FAIL\n",testcase->basename); + offset=common_prefix_length(output,header->str); + fprintf(stderr,"Unterminated summary from bookloupe:\n%s\n", + output+pos); + r=FALSE; + } + } + if (r && strcmp(output+pos,expected->str)) + { + fprintf(stderr,"%s: FAIL\n",testcase->basename); + offset=common_prefix_length(output+pos,expected->str); + if (!offset && !output[pos+offset]) + fprintf(stderr,"Unexpected zero warnings from bookloupe.\n"); + else + { + fprintf(stderr,"Unexpected output from bookloupe:\n"); + print_unexpected(output+pos,offset); + } + r=FALSE; + } + g_string_free(header,TRUE); + g_string_free(expected,TRUE); } - else - { - expected=NULL; - header_len=0; - } - if (expected && strcmp(output,expected->str)) - { - fprintf(stderr,"%s: FAIL\n",testcase->basename); - offset=common_prefix_length(output,expected->str); - if (offset==header_len && !output[offset]) - fprintf(stderr,"Unexpected zero warnings from bookloupe.\n"); - else - { - endp=strchr(output+offset,'\n'); - if (!endp) - endp=output+strlen(output); - report=g_string_new(NULL); - g_string_append_len(report,output,endp-output); - bol=strrchr(report->str,'\n'); - if (bol) - bol++; - else - bol=report->str; - col=offset-(bol-report->str); - fprintf(stderr,"Unexpected output from bookloupe:\n"); - if (report->len>=header_len) - fprintf(stderr,"%s\n%*s^\n",report->str+header_len,col,""); - else - fprintf(stderr,"%s\n%*s^\n",report->str,col,""); - g_string_free(report,TRUE); - } - g_string_free(expected,TRUE); - g_free(output); - return FALSE; - } - g_string_free(expected,TRUE); g_free(output); - if (exit_status) - fprintf(stderr,"bookloupe exited with code %d\n",r); - if (!exit_status) + g_free(filename); + if (r) fprintf(stderr,"%s: PASS\n",testcase->basename); - return !exit_status; + return r; } /* @@ -199,5 +318,6 @@ g_free(testcase->basename); g_free(testcase->input); g_free(testcase->expected); + g_free(testcase->encoding); g_free(testcase); }