ali@0: #include ali@0: #include ali@0: #include ali@0: #include ali@0: #include ali@5: #include ali@0: #include "testcase.h" ali@0: ali@7: GQuark testcase_error_quark(void) ali@7: { ali@7: return g_quark_from_static_string("testcase-error-quark"); ali@7: } ali@7: ali@0: /* ali@8: * As write(), but with error handling. ali@0: */ ali@8: static size_t write_file(int fd,const char *buf,size_t count,GError **error) ali@0: { ali@8: if (write(fd,buf,count)str,'\n'); ali@7: if (bol) ali@7: bol++; ali@7: else ali@7: bol=string->str; ali@8: col=0; ali@8: s=bol; ali@8: endp=string->str+differs_at; ali@8: while(sstr,col,""); ali@7: g_string_free(string,TRUE); ali@7: } ali@7: ali@8: /* ali@8: * Replace \n with \r\n and U+240A (visible symbol for LF) with \n ali@8: */ ali@8: char *unix2dos(const char *text) ali@8: { ali@8: gunichar c; ali@8: const gunichar visible_lf=0x240A; ali@8: GString *string; ali@8: string=g_string_new(NULL); ali@8: while(*text) ali@8: { ali@8: c=g_utf8_get_char(text); ali@8: text=g_utf8_next_char(text); ali@8: if (c=='\n') ali@8: g_string_append(string,"\r\n"); ali@8: else if (c==visible_lf) ali@8: g_string_append_c(string,'\n'); ali@8: else ali@8: g_string_append_unichar(string,c); ali@8: } ali@8: return g_string_free(string,FALSE); ali@8: } ali@8: ali@7: gboolean spawn_bootloupe(const char *encoding,const char *standard_input, ali@7: char **standard_output,char **filename,GError **error) ali@7: { ali@7: gboolean r; ali@7: int fd,exit_status; ali@7: size_t n,pos,offset; ali@7: char input[]="TEST-XXXXXX"; ali@7: char *command[3]; ali@8: char *output,*s,*t; ali@7: GError *tmp_err=NULL; ali@7: if (standard_input) ali@7: { ali@7: if (encoding) ali@7: { ali@8: t=unix2dos(standard_input); ali@8: s=g_convert(t,-1,encoding,"UTF-8",NULL,&n,&tmp_err); ali@8: g_free(t); ali@7: if (!s) ali@7: { ali@7: g_propagate_prefixed_error(error,tmp_err, ali@7: "Conversion to %s failed: ",encoding); ali@7: return FALSE; ali@7: } ali@7: } ali@7: else ali@7: { ali@8: s=unix2dos(standard_input); ali@7: n=strlen(s); ali@7: } ali@7: } ali@7: else ali@7: { ali@7: n=0; ali@7: s=NULL; ali@7: } ali@8: fd=g_mkstemp(input); ali@8: if (n && write_file(fd,s,n,error)!=n) ali@7: { ali@7: g_free(s); ali@7: close(fd); ali@7: (void)remove(input); ali@7: return FALSE; ali@7: } ali@7: g_free(s); ali@7: close(fd); ali@7: command[0]=getenv("BOOKLOUPE"); ali@7: if (!command[0]) ali@7: command[0]="." G_DIR_SEPARATOR_S "bookloupe"; ali@7: command[1]=input; ali@7: command[2]=NULL; ali@7: if (standard_output) ali@7: { ali@7: r=spawn_sync(command,&s,&exit_status,error); ali@7: if (r) ali@7: { ali@7: if (encoding) ali@7: { ali@7: output=g_convert(s,-1,"UTF-8",encoding,NULL,NULL,&tmp_err); ali@7: g_free(s); ali@7: if (!output) ali@7: { ali@7: g_propagate_prefixed_error(error,tmp_err, ali@7: "Conversion from %s failed: ",encoding); ali@7: r=FALSE; ali@7: } ali@7: } ali@7: else ali@7: { ali@7: output=s; ali@7: if (!g_utf8_validate(s,-1,NULL)) ali@7: { ali@7: g_set_error_literal(error,TESTCASE_ERROR, ali@7: TESTCASE_ERROR_FAILED, ali@7: "bookloupe output is not valid UTF-8"); ali@7: r=FALSE; ali@7: } ali@7: } ali@7: } ali@7: } ali@7: else ali@7: { ali@7: r=spawn_sync(command,NULL,&exit_status,error); ali@7: output=NULL; ali@7: } ali@7: (void)remove(input); ali@7: if (r && exit_status) ali@7: { ali@7: g_set_error(error,TESTCASE_ERROR,TESTCASE_ERROR_FAILED, ali@7: "bookloupe exited with code %d",exit_status); ali@7: r=FALSE; ali@7: } ali@7: if (r && filename) ali@7: *filename=g_strdup(input); ali@7: if (r && standard_output) ali@7: *standard_output=output; ali@7: return r; ali@7: } ali@7: ali@0: /* ali@0: * Run a testcase, returning FALSE on fail or error and ali@0: * TRUE on pass or expected-fail. ali@0: * Suitable message(s) will be printed in all cases. ali@0: */ ali@6: gboolean testcase_run(Testcase *testcase) ali@0: { ali@6: gboolean r; ali@7: size_t pos,offset; ali@7: GString *header,*expected; ali@7: char *output,*filename,*s; ali@7: GError *error=NULL; ali@7: if (testcase->expected) ali@7: r=spawn_bootloupe(testcase->encoding,testcase->input,&output,&filename, ali@7: &error); ali@0: else ali@0: { ali@7: r=spawn_bootloupe(testcase->encoding,testcase->input,NULL,NULL,&error); ali@7: output=filename=NULL; ali@7: } ali@7: if (!r) ali@7: { ali@7: fprintf(stderr,"%s: FAIL\n",testcase->basename); ali@7: fprintf(stderr,"%s\n",error->message); ali@7: g_error_free(error); ali@0: return FALSE; ali@0: } ali@0: if (testcase->expected) ali@0: { ali@7: header=g_string_new("\n\nFile: "); ali@7: g_string_append(header,filename); ali@7: g_string_append(header,"\n"); ali@7: expected=g_string_new(testcase->expected); ali@7: if (!g_str_has_prefix(output,header->str)) ali@7: { ali@7: fprintf(stderr,"%s: FAIL\n",testcase->basename); ali@7: offset=common_prefix_length(output,header->str); ali@7: fprintf(stderr,"Unexpected header from bookloupe:\n"); ali@7: print_unexpected(output,offset); ali@7: r=FALSE; ali@7: } ali@7: pos=header->len; ali@7: if (r) ali@7: { ali@7: /* Skip the summary */ ali@7: s=strstr(output+pos,"\n\n"); ali@7: if (s) ali@7: pos=s-output+2; ali@7: else ali@7: { ali@7: fprintf(stderr,"%s: FAIL\n",testcase->basename); ali@7: offset=common_prefix_length(output,header->str); ali@7: fprintf(stderr,"Unterminated summary from bookloupe:\n%s\n", ali@7: output+pos); ali@7: r=FALSE; ali@7: } ali@7: } ali@7: if (r && strcmp(output+pos,expected->str)) ali@7: { ali@7: fprintf(stderr,"%s: FAIL\n",testcase->basename); ali@7: offset=common_prefix_length(output+pos,expected->str); ali@7: if (!offset && !output[pos+offset]) ali@7: fprintf(stderr,"Unexpected zero warnings from bookloupe.\n"); ali@7: else ali@7: { ali@7: fprintf(stderr,"Unexpected output from bookloupe:\n"); ali@7: print_unexpected(output+pos,offset); ali@7: } ali@7: r=FALSE; ali@7: } ali@7: g_string_free(header,TRUE); ali@7: g_string_free(expected,TRUE); ali@0: } ali@6: g_free(output); ali@7: g_free(filename); ali@7: if (r) ali@0: fprintf(stderr,"%s: PASS\n",testcase->basename); ali@7: return r; ali@0: } ali@0: ali@0: /* ali@0: * Free a testcase. ali@0: */ ali@0: void testcase_free(Testcase *testcase) ali@0: { ali@6: g_free(testcase->basename); ali@6: g_free(testcase->input); ali@6: g_free(testcase->expected); ali@7: g_free(testcase->encoding); ali@6: g_free(testcase); ali@0: }