diff -r cf332d440466 -r 6a13fe0fc19e test/harness/testcase.c --- a/test/harness/testcase.c Fri Jan 27 23:59:51 2012 +0000 +++ b/test/harness/testcase.c Mon Jan 30 00:36:31 2012 +0000 @@ -1,10 +1,12 @@ #include #include #include -#include #include +#include +#include #include #include "testcase.h" +#include "testcaseinput.h" GQuark testcase_error_quark(void) { @@ -12,20 +14,6 @@ } /* - * As write(), but with error handling. - */ -static size_t write_file(int fd,const char *buf,size_t count,GError **error) -{ - if (write(fd,buf,count)flags&TESTCASE_TMP_DIR) { - c=g_utf8_get_char(text); - text=g_utf8_next_char(text); - if (c=='\n') - g_string_append(string,"\r\n"); - else if (c==visible_lf) - g_string_append_c(string,'\n'); - else - g_string_append_unichar(string,c); + testcase->tmpdir=g_strdup("TEST-XXXXXX"); + if (!g_mkdtemp(testcase->tmpdir)) + { + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), + "Failed to create temporary directory: %s",g_strerror(errno)); + g_free(testcase->tmpdir); + testcase->tmpdir=NULL; + return FALSE; + } } - return g_string_free(string,FALSE); + for(link=testcase->inputs;link;link=link->next) + if (!testcase_input_create(testcase,link->data,error)) + { + for(link2=testcase->inputs;link2!=link;link2=link2->next) + (void)testcase_input_remove(testcase,link2->data,NULL); + if (testcase->tmpdir) + { + (void)g_rmdir(testcase->tmpdir); + g_free(testcase->tmpdir); + testcase->tmpdir=NULL; + } + return FALSE; + } + return TRUE; } -gboolean spawn_bootloupe(const char *encoding,const char *standard_input, - char **standard_output,char **filename,GError **error) +/* + * Remove all the input files used by a testcase and, if created, + * the temporary directory in which they are stored. + */ +gboolean testcase_remove_input_files(Testcase *testcase,GError **error) +{ + GSList *link; + GError *tmp_err=NULL; + gboolean retval=TRUE; + for(link=testcase->inputs;link;link=link->next) + if (!testcase_input_remove(testcase,link->data,&tmp_err)) + { + if (error && !*error) + g_propagate_error(error,tmp_err); + else + g_clear_error(&tmp_err); + retval=FALSE; + } + if (testcase->tmpdir) + { + if (g_rmdir(testcase->tmpdir)) + { + if (error && !*error) + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), + "Failed to remove temporary directory: %s",g_strerror(errno)); + retval=FALSE; + } + g_free(testcase->tmpdir); + testcase->tmpdir=NULL; + } + return retval; +} + +/* + * Replace every occurance of an input file name in with the + * filename which holds that input. For input files with fixed names, + * this is a noop. For input files which use the "XXXXXX" sequence + * to create a unique filename, the XXXXXX will be replaced with the + * 6 characters that were chosen to be unique. + */ +char *testcase_resolve_input_files(Testcase *testcase,const char *str) +{ + GSList *link; + gsize offset,pos; + char *s; + TestcaseInput *input; + GString *filename=g_string_new(str); + for(link=testcase->inputs;link;link=link->next) + { + input=link->data; + if (!input->name_used) + { + g_warning("%s: Input file uninstantiated",input->name); + continue; + } + offset=0; + do + { + s=strstr(filename->str+offset,input->name); + if (s) + { + pos=s-filename->str; + g_string_overwrite(filename,pos,input->name_used); + offset=pos+strlen(input->name); + } + } while(s); + } + return g_string_free(filename,FALSE); +} + +gboolean testcase_spawn_bookloupe(Testcase *testcase,char **standard_output, + GError **error) { gboolean r; - int fd,exit_status; - size_t n,pos,offset; - char input[]="TEST-XXXXXX"; - char *command[3]; - char *output,*s,*t; + int i,exit_status; + char **argv; + char *output,*s; GError *tmp_err=NULL; - if (standard_input) - { - if (encoding) - { - t=unix2dos(standard_input); - s=g_convert(t,-1,encoding,"UTF-8",NULL,&n,&tmp_err); - g_free(t); - if (!s) - { - g_propagate_prefixed_error(error,tmp_err, - "Conversion to %s failed: ",encoding); - return FALSE; - } - } - else - { - s=unix2dos(standard_input); - n=strlen(s); - } - } + if (testcase->options) + argv=g_new(char *,g_strv_length(testcase->options)+3); else - { - n=0; - s=NULL; - } - fd=g_mkstemp(input); - if (n && write_file(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; + argv=g_new(char *,3); + s=getenv("BOOKLOUPE"); + if (!s) + s="bookloupe"; + argv[0]=path_to_absolute(s); + for(i=0;testcase->options && testcase->options[i];i++) + argv[i+1]=testcase_resolve_input_files(testcase,testcase->options[i]); + argv[i+1]=testcase_resolve_input_files(testcase,"TEST-XXXXXX"); + argv[i+2]=NULL; if (standard_output) { - r=spawn_sync(command,&s,&exit_status,error); + r=spawn_sync(testcase->tmpdir,argv,&s,&exit_status,error); if (r) { - if (encoding) + if (testcase->encoding) { - output=g_convert(s,-1,"UTF-8",encoding,NULL,NULL,&tmp_err); + output=g_convert(s,-1,"UTF-8",testcase->encoding,NULL,NULL, + &tmp_err); g_free(s); if (!output) { g_propagate_prefixed_error(error,tmp_err, - "Conversion from %s failed: ",encoding); + "Conversion from %s failed: ",testcase->encoding); r=FALSE; } } @@ -182,18 +223,16 @@ } else { - r=spawn_sync(command,NULL,&exit_status,error); + r=spawn_sync(testcase->tmpdir,argv,NULL,&exit_status,error); output=NULL; } - (void)remove(input); + g_strfreev(argv); 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; @@ -211,19 +250,34 @@ GString *header,*expected; char *output,*filename,*s; GError *error=NULL; + if (!testcase_create_input_files(testcase,&error)) + { + fprintf(stderr,"%s: FAIL\n",testcase->basename); + fprintf(stderr,"%s\n",error->message); + g_error_free(error); + return FALSE; + } if (testcase->expected) - r=spawn_bootloupe(testcase->encoding,testcase->input,&output,&filename, - &error); + r=testcase_spawn_bookloupe(testcase,&output,&error); else { - r=spawn_bootloupe(testcase->encoding,testcase->input,NULL,NULL,&error); - output=filename=NULL; + r=testcase_spawn_bookloupe(testcase,NULL,&error); + output=NULL; } if (!r) { fprintf(stderr,"%s: FAIL\n",testcase->basename); fprintf(stderr,"%s\n",error->message); g_error_free(error); + (void)testcase_remove_input_files(testcase,NULL); + return FALSE; + } + filename=testcase_resolve_input_files(testcase,"TEST-XXXXXX"); + if (!testcase_remove_input_files(testcase,&error)) + { + fprintf(stderr,"%s: FAIL\n",testcase->basename); + fprintf(stderr,"%s\n",error->message); + g_error_free(error); return FALSE; } if (testcase->expected) @@ -272,8 +326,8 @@ g_string_free(header,TRUE); g_string_free(expected,TRUE); } + g_free(filename); g_free(output); - g_free(filename); if (r) fprintf(stderr,"%s: PASS\n",testcase->basename); return r; @@ -285,8 +339,10 @@ void testcase_free(Testcase *testcase) { g_free(testcase->basename); - g_free(testcase->input); + g_slist_foreach(testcase->inputs,(GFunc)testcase_input_free,NULL); + g_slist_free(testcase->inputs); g_free(testcase->expected); g_free(testcase->encoding); + g_strfreev(testcase->options); g_free(testcase); }