# HG changeset patch # User ali # Date 1327883791 0 # Node ID 6a13fe0fc19e2ae100e0986865f6538c60d81787 # Parent cf332d440466601401a5a8ce21918dee775cec27 Add a testcase for user-defined typos diff -r cf332d440466 -r 6a13fe0fc19e bl/Makefile.am --- a/bl/Makefile.am Fri Jan 27 23:59:51 2012 +0000 +++ b/bl/Makefile.am Mon Jan 30 00:36:31 2012 +0000 @@ -3,4 +3,5 @@ LIBS=$(GLIB_LIBS) noinst_LTLIBRARIES=libbl.la -libbl_la_SOURCES=bl.h textfileutils.c textfileutils.h spawn.c spawn.h +libbl_la_SOURCES=bl.h textfileutils.c textfileutils.h spawn.c spawn.h \ + path.c path.h mkdtemp.c mkdtemp.h diff -r cf332d440466 -r 6a13fe0fc19e bl/bl.h --- a/bl/bl.h Fri Jan 27 23:59:51 2012 +0000 +++ b/bl/bl.h Mon Jan 30 00:36:31 2012 +0000 @@ -1,2 +1,4 @@ #include #include +#include +#include diff -r cf332d440466 -r 6a13fe0fc19e bl/mkdtemp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bl/mkdtemp.c Mon Jan 30 00:36:31 2012 +0000 @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include "mkdtemp.h" + +#if !HAVE_G_MKDTEMP +char *g_mkdtemp(char *template) +{ +#if !defined(WIN32) && HAVE_MKDTEMP + return mkdtemp(template); +#else + char *s; + for(;;) + { + s=g_strdup(template); + mktemp(s); + if (!*s) + { + g_free(s); + errno=EEXIST; + return NULL; + } + if (g_mkdir(s,0700)>=0) + { + strcpy(template,s); + g_free(s); + return template; + } + g_free(s); + } +#endif /* !defined(WIN32) && HAVE_MKDTEMP */ +} +#endif /* !HAVE_G_MKDTEMP */ diff -r cf332d440466 -r 6a13fe0fc19e bl/mkdtemp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bl/mkdtemp.h Mon Jan 30 00:36:31 2012 +0000 @@ -0,0 +1,8 @@ +#ifndef BL_MKDTEMP_H +#define BL_MKDTEMP_H + +#if !HAVE_G_MKDTEMP +char *g_mkdtemp(char *template); +#endif + +#endif /* BL_MKDTEMP_H */ diff -r cf332d440466 -r 6a13fe0fc19e bl/path.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bl/path.c Mon Jan 30 00:36:31 2012 +0000 @@ -0,0 +1,53 @@ +#ifdef WIN32 +#include +#endif +#include +#include +#include + +/* + * Return an absolute path to . + * Note that this function makes no attempt to return a unique path, or + * to remove "." or ".." entries. It simply returns a path which will + * be unaffected by subsequent calls to chdir(). + */ +char *path_to_absolute(const char *path) +{ +#ifdef WIN32 + long len; + gunichar2 *path2; + gunichar2 *abs2; + char *abs; + path2=g_utf8_to_utf16(path,-1,NULL,NULL,NULL); + if (!path2) + return NULL; + len=GetFullPathNameW(path2,0,NULL,NULL); /* len includes nul */ + if (!len) + { + g_free(path2); + return NULL; + } + abs2=g_new(gunichar2,len); + len=GetFullPathNameW(path2,len,abs2,NULL); /* len excludes nul */ + g_free(path2); + if (!len) + { + g_free(abs2); + return NULL; + } + abs=g_utf16_to_utf8(abs2,len,NULL,NULL,NULL); + g_free(abs2); + return abs; +#else + char *s,*abs; + if (*path=='/') + abs=g_strdup(path); + else + { + s=g_get_current_dir(); + abs=g_build_filename(s,path,NULL); + g_free(s); + } + return abs; +#endif +} diff -r cf332d440466 -r 6a13fe0fc19e bl/path.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bl/path.h Mon Jan 30 00:36:31 2012 +0000 @@ -0,0 +1,6 @@ +#ifndef BL_PATH_H +#define BL_PATH_H + +char *path_to_absolute(const char *path); + +#endif /* BL_PATH_H */ diff -r cf332d440466 -r 6a13fe0fc19e bl/spawn.c --- a/bl/spawn.c Fri Jan 27 23:59:51 2012 +0000 +++ b/bl/spawn.c Mon Jan 30 00:36:31 2012 +0000 @@ -7,8 +7,8 @@ #define SPAWN_BUFSIZE 128 -gboolean spawn_sync(char **argv,char **standard_output,int *exit_status, - GError **error) +gboolean spawn_sync(const char *working_directory,char **argv, + char **standard_output,int *exit_status,GError **error) { /* Don't use g_spawn_sync on WIN32 for now to avoid needing the helper */ #ifndef WIN32 @@ -17,8 +17,8 @@ GSpawnFlags flags=G_SPAWN_SEARCH_PATH; if (!standard_output) flags=G_SPAWN_STDOUT_TO_DEV_NULL; - retval=g_spawn_sync(NULL,argv,NULL,flags,NULL,NULL,standard_output, - &standard_error,exit_status,error); + retval=g_spawn_sync(working_directory,argv,NULL,flags,NULL,NULL, + standard_output,&standard_error,exit_status,error); if (standard_error) fputs(standard_error,stderr); g_free(standard_error); @@ -29,7 +29,21 @@ FILE *fp; int i,r; size_t n,len; + char *current_dir; GString *command_line,*string; + if (working_directory) + { + current_dir=g_get_current_dir(); + if (g_chdir(working_directory)<0) + { + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), + "%s: %s",working_directory,g_strerror(errno)); + g_free(current_dir); + return FALSE; + } + } + else + current_dir=NULL; command_line=g_string_new(NULL); for(i=0;argv[i];i++) { @@ -39,6 +53,13 @@ } fp=popen(command_line->str,"r"); g_string_free(command_line,TRUE); + if (current_dir) + { + if (g_chdir(current_dir)<0) + g_error("Failed to restore current directory: %s", + g_strerror(errno)); + g_free(current_dir); + } if (!fp) { g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), diff -r cf332d440466 -r 6a13fe0fc19e bl/spawn.h --- a/bl/spawn.h Fri Jan 27 23:59:51 2012 +0000 +++ b/bl/spawn.h Mon Jan 30 00:36:31 2012 +0000 @@ -3,7 +3,7 @@ #include -gboolean spawn_sync(char **argv,char **standard_output,int *exit_status, - GError **error); +gboolean spawn_sync(const char *working_directory,char **argv, + char **standard_output,int *exit_status,GError **error); #endif /* BL_SPAWN_H */ diff -r cf332d440466 -r 6a13fe0fc19e configure.ac --- a/configure.ac Fri Jan 27 23:59:51 2012 +0000 +++ b/configure.ac Mon Jan 30 00:36:31 2012 +0000 @@ -45,6 +45,9 @@ AS_IF([test "$enable_shared" = no],[ LDFLAGS="$LDFLAGS -static-libtool-libs" ]) +LT_OUTPUT +ac_compile="./libtool --mode=compile --tag=CC $ac_compile" +ac_link="./libtool --mode=link --tag=CC $ac_link" PKG_PROG_PKG_CONFIG ################################################## @@ -60,15 +63,6 @@ ################################################## PKG_CHECK_MODULES([GLIB],[glib-2.0]) -# NOTE: If we are using a static version of glib then we -# should define GLIB_STATIC_COMPILATION. This isn't needed -# when glib is built only for static use (in which case -# glibconfig.h will already define GLIB_STATIC_COMPILATION). -# It's not easy to tell if libtool will actually link with -# a static glib but luckily we don't currently need to; -# this pre-processor define only affects the behaviour of -# libraries which use glib and we don't have any. - # Glib 2.30 (at least) doesn't include "-framework Carbon" in Libs.private # which causes link to fail for static glib on Mac (gnome bug #668152). # Test for this problem and implement a workaround. @@ -97,10 +91,39 @@ ]) ]) +# If we are using a static version of glib then we should define +# GLIB_STATIC_COMPILATION. This isn't needed when glib is built +# only for static use (in which case glibconfig.h will already +# define GLIB_STATIC_COMPILATION). +AS_IF([test "$enable_shared" = no],[ + AC_MSG_CHECKING([whether GLIB_STATIC_COMPILATION needs to be defined]) + save_CFLAGS="$CFLAGS" + save_LIBS="$LIBS" + CFLAGS="$GLIB_CFLAGS" + LIBS="$GLIB_LIBS" + AC_TRY_LINK([ + #include + ],[ + return glib_major_version!=2; + ],[static_compilation=no],[static_compilation=yes]) + CFLAGS="$save_CFLAGS" + LIBS="$save_LIBS" + AC_MSG_RESULT([$static_compilation]) + AS_IF([test "$static_compilation" = yes],[ + GLIB_CFLAGS="$GLIB_CFLAGS -DGLIB_STATIC_COMPILATION" + ]) +]) + ################################################## # Checks for library functions. ################################################## -AC_CHECK_FUNCS_ONCE([mkstemp]) +save_CFLAGS="$CFLAGS" +save_LIBS="$LIBS" +CFLAGS="$GLIB_CFLAGS" +LIBS="$GLIB_LIBS" +AC_CHECK_FUNCS([g_mkdtemp mkdtemp],[break]) +CFLAGS="$save_CFLAGS" +LIBS="$save_LIBS" ################################################## # Checks for processor independent files. diff -r cf332d440466 -r 6a13fe0fc19e test/compatibility/Makefile.am --- a/test/compatibility/Makefile.am Fri Jan 27 23:59:51 2012 +0000 +++ b/test/compatibility/Makefile.am Mon Jan 30 00:36:31 2012 +0000 @@ -2,6 +2,7 @@ TESTS=missing-space.tst spaced-punctuation.tst html-tag.tst html-symbol.tst \ spaced-doublequote.tst mismatched-quotes.tst he-be.tst digits.tst \ extra-period.tst ellipsis.tst short-line.tst abbreviation.tst \ - example.tst non-ascii.tst embedded-lf.tst + example.tst non-ascii.tst embedded-lf.tst markup.tst \ + user-defined-typo.tst dist_pkgdata_DATA=$(TESTS) diff -r cf332d440466 -r 6a13fe0fc19e test/compatibility/markup.tst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compatibility/markup.tst Mon Jan 30 00:36:31 2012 +0000 @@ -0,0 +1,6 @@ +**************** OPTIONS **************** +-m +-d +**************** INPUT **************** +“He went thataway!” +**************** EXPECTED **************** diff -r cf332d440466 -r 6a13fe0fc19e test/compatibility/user-defined-typo.tst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compatibility/user-defined-typo.tst Mon Jan 30 00:36:31 2012 +0000 @@ -0,0 +1,17 @@ +**************** OPTIONS **************** +-u +**************** INPUT(gutcheck.typ) **************** +arid +**************** INPUT **************** +I am the very model of a modern Major-General, +I've information vegetable, animal, and mineral, +I know the kings of England, arid I quote the fights historical +From Marathon to Waterloo, in order categorical; +I'm very well acquainted, too, with matters mathematical, +I understand equations, both the simple and quadratical, +About binomial theorem I'm teeming with a lot o' news-- +With many cheerful facts about the square of the hypotenuse. +**************** EXPECTED **************** + +I know the kings of England, arid I quote the fights historical + Line 3 column 29 - Query possible scanno arid diff -r cf332d440466 -r 6a13fe0fc19e test/harness/Makefile.am --- a/test/harness/Makefile.am Fri Jan 27 23:59:51 2012 +0000 +++ b/test/harness/Makefile.am Mon Jan 30 00:36:31 2012 +0000 @@ -4,5 +4,6 @@ LIBS=$(GLIB_LIBS) loupe_test_SOURCES=loupe-test.c testcase.c testcase.h testcaseio.c \ - testcaseio.h testcaseparser.c testcaseparser.h + testcaseio.h testcaseparser.c testcaseparser.h testcaseinput.c \ + testcaseinput.h loupe_test_LDADD=../../bl/libbl.la 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); } diff -r cf332d440466 -r 6a13fe0fc19e test/harness/testcase.h --- a/test/harness/testcase.h Fri Jan 27 23:59:51 2012 +0000 +++ b/test/harness/testcase.h Mon Jan 30 00:36:31 2012 +0000 @@ -11,11 +11,14 @@ typedef struct { char *basename; - char *input; + char *tmpdir; + GSList *inputs; char *expected; char *encoding; /* The character encoding to talk to BOOKLOUPE in */ + char **options; enum { TESTCASE_XFAIL=1<<0, + TESTCASE_TMP_DIR=1<<1, } flags; } Testcase; diff -r cf332d440466 -r 6a13fe0fc19e test/harness/testcaseinput.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/harness/testcaseinput.c Mon Jan 30 00:36:31 2012 +0000 @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include +#ifdef WIN32 +#include +#endif +#include +#include +#include +#include "testcase.h" +#include "testcaseinput.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* + * 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)). + * The file is written in the encoding specified for communicating with + * bookloupe. The name_used field of is filled in with the name + * of the created file (which may be different than the name specified + * if that contained "XXXXXX" to be replaced by a unique string). + */ +gboolean testcase_input_create(Testcase *testcase,TestcaseInput *input, + GError **error) +{ + int fd; + size_t n; + char *filename,*s,*t; + GError *tmp_err=NULL; + if (input->contents) + { + if (testcase->encoding) + { + t=unix2dos(input->contents); + s=g_convert(t,-1,testcase->encoding,"UTF-8",NULL,&n,&tmp_err); + g_free(t); + if (!s) + { + g_propagate_prefixed_error(error,tmp_err, + "Conversion to %s failed: ",testcase->encoding); + return FALSE; + } + } + else + { + s=unix2dos(input->contents); + n=strlen(s); + } + } + else + { + n=0; + s=NULL; + } + g_free(input->name_used); + input->name_used=NULL; + if (testcase->tmpdir) + filename=g_build_filename(testcase->tmpdir,input->name,NULL); + else + filename=g_strdup(input->name); + if (strstr(input->name,"XXXXXX")) + fd=g_mkstemp(filename); + else + fd=g_open(filename,O_WRONLY|O_CREAT|O_EXCL|O_BINARY,0600); + if (fd<0) + { + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), + "%s: %s",filename,g_strerror(errno)); + g_free(s); + return FALSE; + } + input->name_used=g_strdup(filename+strlen(filename)-strlen(input->name)); + if (n && write_file(fd,s,n,error)!=n) + { + g_free(s); + close(fd); + (void)g_unlink(filename); + g_free(filename); + g_free(input->name_used); + input->name_used=NULL; + return FALSE; + } + g_free(s); + if (close(fd)<0) + { + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), + "%s: %s",filename,g_strerror(errno)); + (void)g_unlink(filename); + g_free(filename); + g_free(input->name_used); + input->name_used=NULL; + return FALSE; + } + g_free(filename); + return TRUE; +} + +/* + * Remove an input file created with testcase_input_create() + */ +gboolean testcase_input_remove(Testcase *testcase,TestcaseInput *input, + GError **error) +{ + char *filename; + if (input->name_used) + { + if (testcase->tmpdir) + filename=g_build_filename(testcase->tmpdir,input->name_used,NULL); + else + filename=g_strdup(input->name_used); + if (g_unlink(filename)<0) + { + g_set_error(error,G_FILE_ERROR,g_file_error_from_errno(errno), + "%s: %s",filename,g_strerror(errno)); + return FALSE; + } + g_free(filename); + g_free(input->name_used); + input->name_used=NULL; + } + return TRUE; +} + +/* Create a new description of an input file needed for a testcase */ +TestcaseInput *testcase_input_new(const char *name,const char *contents) +{ + TestcaseInput *input; + input=g_new0(TestcaseInput,1); + input->name=g_strdup(name); + input->contents=g_strdup(contents); + return input; +} + +/* Free the description of a testcase input file */ +void testcase_input_free(TestcaseInput *input) +{ + g_free(input->name); + g_free(input->name_used); + g_free(input->contents); + g_free(input); +} diff -r cf332d440466 -r 6a13fe0fc19e test/harness/testcaseinput.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/harness/testcaseinput.h Mon Jan 30 00:36:31 2012 +0000 @@ -0,0 +1,20 @@ +#ifndef TESTCASE_INPUT_H +#define TESTCASE_INPUT_H + +#include +#include "testcase.h" + +typedef struct { + char *name; + char *name_used; + char *contents; +} TestcaseInput; + +gboolean testcase_input_create(Testcase *testcase,TestcaseInput *input, + GError **error); +gboolean testcase_input_remove(Testcase *testcase,TestcaseInput *input, + GError **error); +TestcaseInput *testcase_input_new(const char *name,const char *contents); +void testcase_input_free(TestcaseInput *input); + +#endif /* TESTCASE_INPUT_H */ diff -r cf332d440466 -r 6a13fe0fc19e test/harness/testcaseio.c --- a/test/harness/testcaseio.c Fri Jan 27 23:59:51 2012 +0000 +++ b/test/harness/testcaseio.c Mon Jan 30 00:36:31 2012 +0000 @@ -4,6 +4,7 @@ #include #include #include "testcaseparser.h" +#include "testcaseinput.h" #include "testcaseio.h" /* @@ -15,7 +16,8 @@ { Testcase *testcase; TestcaseParser *parser; - char *s; + TestcaseInput *input=NULL; + char *s,*arg; const char *tag,*text; gboolean found_tag=FALSE; parser=testcase_parser_new_from_file(filename); @@ -34,12 +36,44 @@ *s='\0'; while(testcase_parser_get_next_tag(parser,&tag,&text)) { - if (!testcase->input && !strcmp(tag,"INPUT")) - testcase->input=g_strdup(text); + if (!input && !strcmp(tag,"INPUT")) + input=testcase_input_new("TEST-XXXXXX",text); + else if (g_str_has_prefix(tag,"INPUT(") && tag[strlen(tag)-1]==')') + { + arg=g_strndup(tag+6,strlen(tag)-7); + s=g_path_get_dirname(arg); + if (strcmp(s,".")) + { + /* + * Otherwise it would be possible to overwrite an arbitary + * file on somebody's computer by getting them to run a + * testcase! + */ + fprintf(stderr, + "%s: Input files may not have a directory component\n",arg); + g_free(s); + g_free(arg); + testcase_free(testcase); + testcase_parser_free(parser); + return NULL; + } + g_free(s); + testcase->inputs=g_slist_prepend(testcase->inputs, + testcase_input_new(arg,text)); + if (!strstr(arg,"XXXXXX")) + testcase->flags|=TESTCASE_TMP_DIR; + g_free(arg); + } else if (!testcase->expected && !strcmp(tag,"EXPECTED")) testcase->expected=g_strdup(text); else if (!testcase->encoding && !strcmp(tag,"ENCODING")) testcase->encoding=g_strchomp(g_strdup(text)); + else if (!testcase->encoding && !strcmp(tag,"OPTIONS")) + { + testcase->options=g_strsplit(text,"\n",0); + g_free(testcase->options[g_strv_length(testcase->options)-1]); + testcase->options[g_strv_length(testcase->options)-1]=NULL; + } else { fprintf(stderr,"%s: Not a valid testcase (%s)\n",filename,tag); @@ -61,6 +95,9 @@ testcase_parser_free(parser); return NULL; } + if (!input) + input=testcase_input_new("TEST-XXXXXX",NULL); + testcase->inputs=g_slist_prepend(testcase->inputs,input); testcase_parser_free(parser); return testcase; }