comparison dstress.c @ 620:03ad4005cd8e

POSIX only: added __GDB_SCRIPT__ and __GDB__PATTERN__ support
author thomask
date Thu, 11 Aug 2005 21:28:02 +0000
parents 0434764d4a66
children 7acb8b34c87a
comparison
equal deleted inserted replaced
619:107d6211c81e 620:03ad4005cd8e
32 #include <errno.h> 32 #include <errno.h>
33 33
34 #define OBJ "-odobj " 34 #define OBJ "-odobj "
35 #define TLOG "log.tmp" 35 #define TLOG "log.tmp"
36 #define CRASH_RUN "./crashRun__" 36 #define CRASH_RUN "./crashRun__"
37 #define GDB_SCRIPTER "./gdb.txt"
37 38
38 #define RUN 1 39 #define RUN 1
39 #define NORUN 2 40 #define NORUN 2
40 #define COMPILE 4 41 #define COMPILE 4
41 #define NOCOMPILE 8 42 #define NOCOMPILE 8
77 78
78 #include <sys/types.h> 79 #include <sys/types.h>
79 #include <sys/stat.h> 80 #include <sys/stat.h>
80 #include <fcntl.h> 81 #include <fcntl.h>
81 #include <unistd.h> 82 #include <unistd.h>
83 #include <regex.h>
82 84
83 #else 85 #else
84 #ifdef WIN32 86 #ifdef WIN32
85 87
86 #include <windows.h> 88 #include <windows.h>
87 89
88 #endif /* WIN 32 */ 90 #endif /* WIN 32 */
89 #endif /* USE_POSIX else */ 91 #endif /* USE_POSIX else */
90 92
93 char* errorMsg(int good_error){
94 return (good_error) ? ("") : " [bad error message]";
95 }
96
97 char* gdbMsg(int good_gdb){
98 return (good_gdb) ? ("") : " [bad debugger message]";
99 }
100
101 char* strip(char* buffer){
102 if(buffer!=NULL){
103 while(isspace(buffer[0])){
104 buffer++;
105 }
106
107 char* tmp;
108 for(tmp=buffer+strlen(buffer); isspace(tmp[0]); tmp=buffer+strlen(buffer)){
109 tmp[0]='\x00';
110 }
111 }
112 return buffer;
113 }
114
115 /* cleanup "/" versus "\" in filenames */
116 char* cleanPathSeperator(char* filename){
117 char* pos;
118 #ifdef USE_POSIX
119 for(pos=strchr(filename, '\\'); pos; pos=strchr(filename, '\\')){
120 *pos='/';
121 }
122 #else
123 #if WIN32
124 for(pos=strchr(filename, '/'); pos; pos=strchr(filename, '/')){
125 *pos='\\';
126 }
127 #else
128
129 #error no cleanPathSeperator available for this system
130
131 #endif /* WIN32 else */
132 #endif /* USE_POSIX else */
133 return filename;
134 }
91 135
92 char* loadFile(char* filename){ 136 char* loadFile(char* filename){
93 #ifdef USE_POSIX 137 #ifdef USE_POSIX
94 char* back = NULL; 138 char* back = NULL;
95 struct stat fileInfo; 139 struct stat fileInfo;
112 } 156 }
113 if(0==strcmp(filename, TLOG)){ 157 if(0==strcmp(filename, TLOG)){
114 return calloc(1,sizeof(char)); 158 return calloc(1,sizeof(char));
115 } 159 }
116 160
117 fprintf(stderr, "File not found \"%s\"\n", filename); 161 fprintf(stderr, "File not found \"%s\" (%s)\n", filename, strerror(errno));
118 exit(EXIT_FAILURE); 162 exit(EXIT_FAILURE);
119 #else /* USE_POSIX */ 163 #else /* USE_POSIX */
120 #ifdef WIN32 164 #ifdef WIN32
121 165
122 char* back=NULL; 166 char* back=NULL;
123 DWORD size, numread; 167 DWORD size, numread;
124 HANDLE file=CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, 168 HANDLE file=CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
152 196
153 #endif /* WIN32 else */ 197 #endif /* WIN32 else */
154 #endif /* USE_POSIX else */ 198 #endif /* USE_POSIX else */
155 } 199 }
156 200
157 /* cleanup "/" versus "\" in filenames */ 201 void writeFile(const char* filename, const char* content){
158 char* cleanPathSeperator(char* filename){ 202 size_t len = strlen(content);
159 char* pos; 203 FILE* file = fopen(filename, "w+");
160 #ifdef USE_POSIX 204
161 for(pos=strchr(filename, '\\'); pos; pos=strchr(filename, '\\')){ 205 if(errno == 0 && file != NULL){
162 *pos='/'; 206 if((fwrite(content, sizeof(char), len, file) != len) || (errno != 0)){
163 } 207 fprintf(stderr, "failed to write file \"%s\" (%s)\n", filename, strerror(errno));
164 #else 208 exit(EXIT_FAILURE);
165 #if WIN32 209 }
166 for(pos=strchr(filename, '/'); pos; pos=strchr(filename, '/')){ 210 if(fclose(file) || (errno != 0)){
167 *pos='\\'; 211 fprintf(stderr, "failed to close file \"%s\" (%s)\n", filename, strerror(errno));
168 } 212 exit(EXIT_FAILURE);
169 #else 213 }
170 214 return;
171 #error no cleanPathSeperator available for this system 215 }
172 216
173 #endif /* WIN32 else */ 217 fprintf(stderr, "couldn't open file \"%s\" for writing (%s)\n", filename, strerror(errno));
174 #endif /* USE_POSIX else */ 218 exit(EXIT_FAILURE);
175 return filename; 219 }
176 }
177
178 220
179 /* query the environment for the compiler name */ 221 /* query the environment for the compiler name */
180 char* getCompiler(){ 222 char* getCompiler(){
181 char* back = getenv("DMD"); 223 char* back = getenv("DMD");
182 if(back == NULL){ 224 if(back == NULL){
183 back = getenv("dmd"); 225 back = getenv("dmd");
184 if(back==NULL){ 226 if(back==NULL){
185 back = "dmd"; 227 back = "dmd";
186 } 228 }
187 } 229 }
188 return cleanPathSeperator(back); 230 return strip(cleanPathSeperator(back));
231 }
232
233 /* query the environment for the debugger name */
234 char* getGDB(){
235 char* back = getenv("GDB");
236 if(back == NULL){
237 back = getenv("gdb");
238 if(back == NULL){
239 back = "gdb";
240 }
241 }
242 return strip(cleanPathSeperator(back));
189 } 243 }
190 244
191 /* query the environment for general flags */ 245 /* query the environment for general flags */
192 char* getGeneralFlags(){ 246 char* getGeneralFlags(){
193 char* back = getenv("DFLAGS"); 247 char* back = getenv("DFLAGS");
195 back = getenv("dflags"); 249 back = getenv("dflags");
196 if(back==NULL){ 250 if(back==NULL){
197 back = calloc(1,1); 251 back = calloc(1,1);
198 } 252 }
199 } 253 }
200 return cleanPathSeperator(back); 254 return strip(cleanPathSeperator(back));
201 } 255 }
202 256
203 257
204 /* extract the FIRST occurance of a given TAG until the next linebreak */ 258 /* extract the FIRST occurance of a given TAG until the next linebreak */
205 char* getCaseFlag(const char* data, const char* tag){ 259 char* getCaseFlag(const char* data, const char* tag){
221 end1 = begin + strlen(begin); 275 end1 = begin + strlen(begin);
222 } 276 }
223 back = malloc(end1-begin+1); 277 back = malloc(end1-begin+1);
224 strncpy(back, begin, end1-begin); 278 strncpy(back, begin, end1-begin);
225 back[end1-begin+1]='\x00'; 279 back[end1-begin+1]='\x00';
226 return cleanPathSeperator(back); 280 return strip(cleanPathSeperator(back));
227 } 281 }
228 } 282 }
229 283
230 return calloc(1,1); 284 return calloc(1,1);
231 } 285 }
410 464
411 return back; 465 return back;
412 } 466 }
413 467
414 int hadExecCrash(const char* buffer){ 468 int hadExecCrash(const char* buffer){
415 if(strstr(buffer, "Segmentation fault") 469 if(strstr(buffer, "Segmentation fault")
416 || strstr(buffer, "Internal error") 470 || strstr(buffer, "Internal error")
417 || strstr(buffer, "gcc.gnu.org/bugs") 471 || strstr(buffer, "gcc.gnu.org/bugs")
418 || strstr(buffer, "EXIT CODE: signal")) 472 || strstr(buffer, "EXIT CODE: signal"))
419 { 473 {
420 return 1; 474 return 1;
421 } 475 }
443 }else{ 497 }else{
444 return RAND_MAX; 498 return RAND_MAX;
445 } 499 }
446 #else 500 #else
447 501
448 #error no crashRun implementation present 502 #error comment me out, if your test cases produce neither eternal loops nor Access Violations
449 503 return system(cmd);
504
450 #endif /* USE_POSIX else */ 505 #endif /* USE_POSIX else */
451 } 506 }
452 507
453 508
454 int main(int argc, char* arg[]){ 509 int main(int argc, char* arg[]){
455 char* compiler; /* the compiler - from enviroment flag "DMD" */ 510 char* compiler; /* the compiler - from enviroment flag "DMD" */
456 char* cmd_arg_general; /* additional arguments - from enviroment flag "DFLAGS" */ 511 char* cmd_arg_general; /* additional arguments - from enviroment flag "DFLAGS" */
457 char* cmd_arg_case; /* additional arguments - from the testcase file */ 512 char* cmd_arg_case; /* additional arguments - from the testcase file */
458 char* buffer; /* general purpos buffer */ 513 char* buffer; /* general purpose buffer */
459 int modus; /* test modus: RUN NORUN COMPILE NOCOMPILE */ 514 int modus; /* test modus: RUN NORUN COMPILE NOCOMPILE */
460 int res; /* return code from external executions */ 515 int res; /* return code from external executions */
461 char* case_file; 516 char* case_file;
462 char* error_file; /* expected sourcefile containing the error */ 517 char* error_file; /* expected sourcefile containing the error */
463 char* error_line; /* expected error line */ 518 char* error_line; /* expected error line */
464 int good_error; /* error contained file and line and matched the expectations */ 519 int good_error; /* error contained file and line and matched the expectations */
520 char* gdb; /* the debugger - from environment flag "GDB" */
521 char* gdb_script; /* gdb command sequence */
522 char* gdb_pattern_raw; /* POSIX regexp expected in GDB's output */
523 #ifdef REG_EXTENDED
524 regex_t* gdb_pattern;
525 #endif
526 int good_gdb; /* (gdb test and positive) or (no gdb test)*/
465 527
466 /* check arguments */ 528 /* check arguments */
467 if(argc != 3){ 529 if(argc != 3){
468 err: 530 err:
469 if(argc!=0) 531 if(argc!=0)
487 549
488 /* gen flags */ 550 /* gen flags */
489 case_file = cleanPathSeperator(strdup(arg[2])); 551 case_file = cleanPathSeperator(strdup(arg[2]));
490 compiler = getCompiler(); 552 compiler = getCompiler();
491 cmd_arg_general = getGeneralFlags(); 553 cmd_arg_general = getGeneralFlags();
554 gdb = getGDB();
492 buffer = loadFile(case_file); 555 buffer = loadFile(case_file);
493 556
494 cmd_arg_case = getCaseFlag(buffer, "__DSTRESS_DFLAGS__"); 557 cmd_arg_case = getCaseFlag(buffer, "__DSTRESS_DFLAGS__");
495 error_line = getCaseFlag(buffer, "__DSTRESS_ELINE__"); 558 error_line = getCaseFlag(buffer, "__DSTRESS_ELINE__");
496 error_file = getCaseFlag(buffer, "__DSTRESS_EFILE__"); 559 error_file = getCaseFlag(buffer, "__DSTRESS_EFILE__");
560 gdb_script = getCaseFlag(buffer, "__GDB_SCRIPT__");
561 gdb_pattern_raw = getCaseFlag(buffer, "__GDB_PATTERN__");
562
563
564 /* set implicit source file */
565 if(strcmp(error_line, "")!=0 && strcmp(error_file, "")==0){
566 error_file=case_file;
567 }
568
569 /* gdb pattern */
570 #ifdef REG_EXTENDED
571 if(gdb_pattern_raw!=NULL && gdb_pattern_raw[0]!='\x00'){
572
573 gdb_pattern = malloc(sizeof(regex_t));
574 if(regcomp(gdb_pattern, gdb_pattern_raw, REG_EXTENDED)){
575 fprintf(stderr, "failed to compile regular expression:\n\t%s\n", gdb_pattern_raw);
576 exit(EXIT_FAILURE);
577 }else if(gdb_script==NULL){
578 fprintf(stderr, "GDB pattern without GDB script\n");
579 exit(EXIT_FAILURE);
580 }
581 }else{
582 gdb_pattern = NULL;
583 }
584
585 /* gdb script */
586 if(gdb_script!=NULL && gdb_script[0]!='\x00'){
587 if(gdb_pattern==NULL){
588 fprintf(stderr, "GDB script without GDB pattern\n");
589 exit(EXIT_FAILURE);
590 }
591 buffer=gdb_script;
592 for(; *buffer; buffer++){
593 if(buffer[0]=='\\'){
594 if(buffer[1]=='n'){
595 buffer[0]=' ';
596 buffer[1]='\n';
597 }
598 buffer++;
599 }
600 }
601
602 buffer=malloc(strlen(gdb_script)+10);
603 strcpy(buffer, gdb_script);
604 gdb_script=strcat(buffer, "\n\nquit\ny\n\n");
605 good_gdb = 0;
606 }else{
607 good_gdb = 1;
608 gdb_script = NULL;
609 }
610
611 #else
612
613 if(gdb_script && gdb_pattern_raw){
614 fprintf(stderr, "WARNING: regex support inactive\n");
615 }else if(gdb_script && strlen(gdb_script)){
616 fprintf(stderr, "GDB script without GDB pattern\n");
617 exit(EXIT_FAILURE);
618 }else if(gdb_pattern_raw && strlen(gdb_pattern_raw)){
619 fprintf(stderr, "GDB pattern without GDB script\n");
620 exit(EXIT_FAILURE);
621 }
622
623 #endif /* REG_EXTENDED else */
624
625
497 626
498 #ifdef DEBUG 627 #ifdef DEBUG
499 fprintf(stderr, "case: \"%s\"\n", case_file); 628 fprintf(stderr, "case: \"%s\"\n", case_file);
500 fprintf(stderr, "compiler: \"%s\"\n", compiler); 629 fprintf(stderr, "compiler: \"%s\"\n", compiler);
501 fprintf(stderr, "DFLAGS G: \"%s\"\n", cmd_arg_general); 630 fprintf(stderr, "DFLAGS G: \"%s\"\n", cmd_arg_general);
502 fprintf(stderr, "DFLAGS C: \"%s\"\n", cmd_arg_case); 631 fprintf(stderr, "DFLAGS C: \"%s\"\n", cmd_arg_case);
503 fprintf(stderr, "ELINE : \"%s\"\n", error_line); 632 fprintf(stderr, "ELINE : \"%s\"\n", error_line);
504 fprintf(stderr, "EFILE : \"%s\"\n", error_file); 633 fprintf(stderr, "EFILE : \"%s\"\n", error_file);
634 fprintf(stderr, "GDB Scri: \"%s\"\n", gdb_script);
635 fprintf(stderr, "GDB Patt: \"%s\"\n", gdb_pattern_raw);
505 #endif 636 #endif
506
507 /* strip spaces */
508 while(error_line[0]==' '){
509 error_line++;
510 }
511 for(buffer=error_line+strlen(error_line)-1; buffer && buffer[0]==' '; buffer=error_line+strlen(error_line)-1){
512 buffer[0]='\x00';
513 }
514 while(error_file[0]==' '){
515 error_file++;
516 }
517 for(buffer=error_file+strlen(error_file)-1; buffer && buffer[0]==' '; buffer=error_file+strlen(error_file)-1){
518 buffer[0]='\x00';
519 }
520
521 /* set implicit source file */
522 if(strcmp(error_line, "")!=0 && strcmp(error_file, "")==0){
523 error_file=case_file;
524 }
525 637
526 /* start working */ 638 /* start working */
527 if(modus==COMPILE || modus==NOCOMPILE){ 639 if(modus==COMPILE || modus==NOCOMPILE){
528 /* gen command */ 640 /* gen command */
529 buffer = malloc(strlen(compiler)+strlen(cmd_arg_general)+strlen(cmd_arg_case)+strlen(OBJ) 641 buffer = malloc(strlen(compiler)+strlen(cmd_arg_general)+strlen(cmd_arg_case)+strlen(OBJ)
589 fprintf(stderr,"--------\n"); 701 fprintf(stderr,"--------\n");
590 }else if(modus==RUN || modus==NORUN){ 702 }else if(modus==RUN || modus==NORUN){
591 /* gen command */ 703 /* gen command */
592 buffer = malloc(strlen(compiler)+strlen(cmd_arg_general)+strlen(cmd_arg_case)+strlen(OBJ) 704 buffer = malloc(strlen(compiler)+strlen(cmd_arg_general)+strlen(cmd_arg_case)+strlen(OBJ)
593 +strlen(case_file)*2+strlen(TLOG)+64); 705 +strlen(case_file)*2+strlen(TLOG)+64);
594 buffer[0]='\x00'; 706 strcpy(buffer, compiler);
595 strcat(buffer, compiler);
596 strcat(buffer, " "); 707 strcat(buffer, " ");
597 strcat(buffer, cmd_arg_general); 708 strcat(buffer, cmd_arg_general);
598 strcat(buffer, " "); 709 strcat(buffer, " ");
599 strcat(buffer, cmd_arg_case); 710 strcat(buffer, cmd_arg_case);
600 strcat(buffer, " "); 711 strcat(buffer, " ");
610 strcat(buffer, case_file); 721 strcat(buffer, case_file);
611 strcat(buffer, " 1> "); 722 strcat(buffer, " 1> ");
612 strcat(buffer, TLOG); 723 strcat(buffer, TLOG);
613 strcat(buffer, " 2>&1"); 724 strcat(buffer, " 2>&1");
614 725
615 /* test 1/2 */ 726 /* test 1/3 - compile */
616 if(modus==RUN){ 727 if(modus==RUN){
617 fprintf(stderr, "run: %s\n", buffer); 728 fprintf(stderr, "run: %s\n", buffer);
618 }else{ 729 }else{
619 fprintf(stderr, "norun: %s\n", buffer); 730 fprintf(stderr, "norun: %s\n", buffer);
620 } 731 }
621 res = crashRun(buffer); 732 res = crashRun(buffer);
622 733
623 /* diagnostic 1/2 */ 734 /* diagnostic 1/3 */
624 buffer = loadFile(TLOG); 735 buffer = loadFile(TLOG);
625 fprintf(stderr, "%s", buffer); 736 fprintf(stderr, "%s", buffer);
626 good_error = checkErrorMessage(error_file, error_line, buffer); 737 good_error = checkErrorMessage(error_file, error_line, buffer);
627 if(hadExecCrash(buffer)){ 738 if(hadExecCrash(buffer)){
628 printf("ERROR:\t%s [internal compiler error]\n", case_file); 739 printf("ERROR:\t%s [internal compiler error]\n", case_file);
640 } 751 }
641 fprintf(stderr, "\n--------\n"); 752 fprintf(stderr, "\n--------\n");
642 return EXIT_SUCCESS; 753 return EXIT_SUCCESS;
643 } 754 }
644 755
645 /* test 2/2 */ 756 /* test 2/3 - run */
646 buffer = malloc(strlen(case_file) + strlen(TLOG) + 24); 757 buffer = malloc(strlen(case_file) + strlen(TLOG) + 30);
647 *buffer = '\x00'; 758 sprintf(buffer, "%s.exe 1> %s 2>&1\x00\n", case_file, TLOG);
648 strcat(buffer, case_file);
649 strcat(buffer, ".exe 1> ");
650 strcat(buffer, TLOG);
651 strcat(buffer, " 2>&1");
652 fprintf(stderr, "%s\n", buffer); 759 fprintf(stderr, "%s\n", buffer);
653 res=crashRun(buffer); 760 res=crashRun(buffer);
654 761
655 /* diagnostic 2/2 */ 762 /* diagnostic 2/3 */
656 buffer = loadFile(TLOG); 763 buffer = loadFile(TLOG);
657 fprintf(stderr, "%s\n", buffer); 764 fprintf(stderr, "%s\n", buffer);
658 good_error = checkRuntimeErrorMessage(error_file, error_line, buffer); 765 good_error = checkRuntimeErrorMessage(error_file, error_line, buffer);
766
767 #ifdef REG_EXTENDED
768 if(good_error && !good_gdb){
769 /* test 3/3 - gdb */
770 writeFile(GDB_SCRIPTER, gdb_script);
771 buffer = malloc(strlen(gdb) + strlen(case_file) + strlen(GDB_SCRIPTER) + strlen(TLOG) + 20);
772 sprintf(buffer, "%s %s.exe < %s > %s 2>&1", gdb, case_file, GDB_SCRIPTER, TLOG);
773 fprintf(stderr, "%s\n", buffer);
774 if(EXIT_SUCCESS==crashRun(buffer)){
775 /* diagnostic 3/3 */
776 buffer = loadFile(TLOG);
777 fprintf(stderr, "%s\n", buffer);
778 good_gdb = (regexec(gdb_pattern, buffer, 0, NULL, 0)==0);
779 }
780 }
781 #endif /* REG_EXTENDED */
782
659 if(modus==RUN){ 783 if(modus==RUN){
660 if(hadExecCrash(buffer)){ 784 if(hadExecCrash(buffer)){
661 if(good_error){ 785 printf("ERROR:\t%s [test case crash]%s%s", case_file, errorMsg(good_error), gdbMsg(good_gdb));
662 printf("ERROR:\t%s [test case crash]\"", case_file); 786 }else if(res==EXIT_SUCCESS && good_gdb){
663 }else{
664 printf("ERROR:\t%s [test case crash] [bad error message]\"", case_file);
665 }
666 }else if(res==EXIT_SUCCESS){
667 printf("PASS: \t%s\n", case_file); 787 printf("PASS: \t%s\n", case_file);
668 }else if(res==EXIT_FAILURE && good_error){ 788 }else if(res==EXIT_FAILURE && good_error && good_gdb){
669 printf("FAIL: \t%s\n", case_file); 789 printf("FAIL: \t%s\n", case_file);
670 }else{ 790 }else{
671 if(good_error){ 791 printf("ERROR:\t%s%s%s\n", case_file, errorMsg(good_error), gdbMsg(good_gdb));
672 printf("ERROR:\t%s\n", case_file);
673 }else{
674 printf("ERROR:\t%s [bad error message]\n", case_file);
675 }
676 } 792 }
677 }else{ 793 }else{
678 if(res==EXIT_FAILURE){ 794 if(res==EXIT_FAILURE){
679 if(good_error){ 795 if(good_error && good_gdb){
680 printf("XFAIL:\t%s\n", case_file); 796 printf("XFAIL:\t%s\n", case_file);
681 }else{ 797 }else{
682 printf("FAIL: \t%s [bad errror message]\n", case_file); 798 printf("FAIL:\t%s%s%s\n", case_file, errorMsg(good_error), gdbMsg(good_gdb));
683 } 799 }
684 }else if(res==EXIT_SUCCESS){ 800 }else if(res==EXIT_SUCCESS && good_error && good_gdb){
685 printf("XPASS:\t%s\n", case_file); 801 printf("XPASS:\t%s\n", case_file);
686 }else{ 802 }else{
687 printf("ERROR:\t%s\n", case_file); 803 printf("ERROR:\t%s%s%s\n", case_file, errorMsg(good_error), gdbMsg(good_gdb));
688 } 804 }
689 } 805 }
690 fprintf(stderr, "--------\n"); 806 fprintf(stderr, "--------\n");
691 }else{ 807 }else{
692 printf("@bug@ %d (%s)\n", modus, case_file); 808 printf("@bug@ %d (%s)\n", modus, case_file);