CUT really ought to do this.
[beanstalkd.git] / tests / cutgen.c
blob04e4eb8a455145a481f96dd1314972b4066f6348
1 /*
2 * This file has been modified from the original CUT distribution.
4 * CUT 2.3-kr1
5 * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley
6 * See CUT-LICENSE.TXT for details.
8 * $Log: cutgen.c,v $
9 * Revision 1.4 2003/03/18 05:53:50 sfalvo
10 * ADD: cutgen.c: cut_exit() -- common exit point; returns proper error code
11 * at all times.
13 * FIX: cutgen.c: Factored all instances of exit() to invoke cut_exit()
14 * instead. This fixes the bug #703793.
16 * Revision 1.3 2003/03/13 04:27:54 sfalvo
17 * ADD: LICENSE.TXT -- zlib license
19 * ADD: README cut.h cutgen.c -- Changelog token for CVS
21 * FIX: test/bringup-failure -- reflects new usage for bringups and
22 * teardowns in CUT 2.2.
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
31 #define DO_NOT_PROCESS "..."
33 #define SEARCH_TOKEN_TEST "__CUT__"
34 #define SEARCH_TOKEN_BRINGUP "__CUT_BRINGUP__"
35 #define SEARCH_TOKEN_TAKEDOWN "__CUT_TAKEDOWN__"
37 #define MAX_SYMBOL_LENGTH 256 /* arbitrary */
38 #define MAX_LINE_LENGTH 1024 /* arbitrary */
40 #define SEARCH_TOKEN_TEST_LENGTH sizeof( SEARCH_TOKEN_TEST )-1
41 #define SEARCH_TOKEN_BRINGUP_LENGTH sizeof( SEARCH_TOKEN_BRINGUP )-1
42 #define SEARCH_TOKEN_TAKEDOWN_LENGTH sizeof( SEARCH_TOKEN_TAKEDOWN )-1
44 typedef enum TestType {
45 TYPE_TEST = 0,
46 TYPE_BRINGUP = 1,
47 TYPE_TAKEDOWN = 2
48 } TestType;
50 typedef struct TestItem {
51 char name[MAX_SYMBOL_LENGTH];
52 enum TestType type;
53 struct TestItem *next;
54 } TestItem;
56 /* globals */
58 TestItem *testList = 0;
59 FILE *outfile;
60 extern char *libCUT[]; /* defined at the end of this file */
62 static int g_count, g_ready, g_index; /* Used by filename globbing support for windows */
63 static char **g_wildcards, g_fileName[MAX_LINE_LENGTH];
65 TestItem *FindFirstMatch( TestItem *current, char *basis_name, int basis_type )
67 while ( current )
69 if ( !strcmp(current->name,basis_name) && current->type == basis_type )
70 return current;
71 current = current->next;
73 return 0;
76 int NameAndTypeInTestList( char *name, TestType type )
78 return 0 != FindFirstMatch(testList,name,type);
81 void AppendToTestList( char *name, TestType type )
83 struct TestItem *current = testList;
84 if ( !current )
85 current = testList = malloc( sizeof( *testList) );
86 else
88 while ( current->next ) current = current->next;
89 current->next = malloc(sizeof( *testList));
90 current = current->next;
93 current->next = 0;
94 strcpy(current->name, name);
95 current->type = type;
98 void InsertNameAndTypeIntoTestList( char *name, TestType type )
100 if ( !NameAndTypeInTestList( name, type ) )
101 AppendToTestList( name, type );
104 int CharacterIsDigit(char ch)
106 return ( ( ch >= '0') && ( ch <= '9' ) );
109 int CharacterIsUppercase(char ch)
111 return ( ( ch >= 'A' ) && ( ch <= 'Z' ) );
114 int CharacterIsLowercase(char ch)
116 return ( ( ch >= 'a' ) && ( ch <= 'z' ) );
119 int CharacterIsAlphabetic(char ch)
121 return CharacterIsUppercase(ch) || CharacterIsLowercase(ch) || ( ch == '_' );
124 int CharacterIsAlphanumeric( char ch )
126 return CharacterIsDigit(ch) || CharacterIsAlphabetic(ch);
129 void ProcessGenericFunction( char *line, int position,
130 TestType type, int tokenDisplacement )
132 char name[MAX_SYMBOL_LENGTH] = "";
133 int maxLength = strlen( line ) - 1, offset=0;
134 position = position + tokenDisplacement;
136 while ( CharacterIsAlphanumeric(line[position])
137 && (position<maxLength) && (offset<MAX_SYMBOL_LENGTH) )
139 name[offset++] = line[position++];
140 name[offset] = 0;
143 InsertNameAndTypeIntoTestList( name, type );
146 void ProcessBringupFunction( char *line, int position )
148 ProcessGenericFunction( line, position, TYPE_BRINGUP, SEARCH_TOKEN_BRINGUP_LENGTH );
151 void ProcessTestFunction( char *line, int position )
153 ProcessGenericFunction( line, position, TYPE_TEST, SEARCH_TOKEN_TEST_LENGTH );
156 void ProcessTakedownFunction( char *line, int position )
158 ProcessGenericFunction( line, position, TYPE_TAKEDOWN, SEARCH_TOKEN_TAKEDOWN_LENGTH );
162 int OffsetOfSubstring( char *line, char *token )
164 char *inset = strstr(line,token);
166 if ( !inset ) return -1;
167 else return inset - line;
170 void CallIfSubstringFound( char *line, char *token, void (*function)(char*,int) )
172 int index = OffsetOfSubstring( line, token );
173 if ( index != -1 )
174 function( line, index );
177 void ProcessSourceFile( char *filename )
179 FILE *source;
180 char line[MAX_LINE_LENGTH];
182 if( strcmp( filename, DO_NOT_PROCESS ) != 0 )
185 source = fopen(filename,"r");
187 while ( fgets(line,MAX_LINE_LENGTH,source) )
189 CallIfSubstringFound( line, SEARCH_TOKEN_BRINGUP, ProcessBringupFunction );
190 CallIfSubstringFound( line, SEARCH_TOKEN_TEST, ProcessTestFunction );
191 CallIfSubstringFound( line, SEARCH_TOKEN_TAKEDOWN, ProcessTakedownFunction );
194 fclose(source);
198 void EmitExternDeclarationFor( char *name, char *prefix )
200 fprintf( outfile, "extern void %s%s( void );\n", prefix, name );
203 void Emit(char *text)
205 fprintf(outfile, "%s\n", text);
208 void BlankLine()
210 Emit( "" );
213 void ListExternalFunctions()
215 TestItem *current = testList;
216 while ( current )
218 if (current->type == TYPE_TEST)
219 EmitExternDeclarationFor( current->name, SEARCH_TOKEN_TEST );
220 else if (current->type == TYPE_BRINGUP)
221 EmitExternDeclarationFor( current->name, SEARCH_TOKEN_BRINGUP );
222 else if (current->type == TYPE_TAKEDOWN)
223 EmitExternDeclarationFor( current->name, SEARCH_TOKEN_TAKEDOWN );
224 current = current->next;
227 BlankLine();
230 void EmitLibrary(void)
232 int i=0;
233 while ( libCUT[i] )
234 Emit(libCUT[i++]);
237 void ListHeaderFiles(void)
239 EmitLibrary();
240 BlankLine();
241 BlankLine();
244 void EmitIndented(int indent,char *format, ...)
246 va_list v;
247 /* Print two spaces per level of indentation. */
248 fprintf( outfile, "%*s", indent*2, "" );
250 va_start(v,format);
251 vfprintf( outfile, format, v );
252 va_end(v);
254 fprintf( outfile, "\n" );
257 void EmitBringup(int indent,char *name)
259 BlankLine();
260 EmitIndented(indent, "cut_start( \"group-%s\", __CUT_TAKEDOWN__%s );",
261 name, name );
262 EmitIndented(indent, "__CUT_BRINGUP__%s();", name );
263 EmitIndented(indent, "cut_check_errors();");
266 void EmitTest(int indent,char *name)
268 EmitIndented(indent, "cut_start( \"%s\", 0 );", name );
269 EmitIndented(indent, "__CUT__%s();", name );
270 EmitIndented(indent, "cut_end( \"%s\" );", name );
273 void EmitTakedown(int indent,char *name)
275 EmitIndented(indent, "cut_end( \"group-%s\" );", name );
276 EmitIndented(indent, "__CUT_TAKEDOWN__%s();", name );
277 BlankLine();
280 void EmitUnitTesterBody()
282 int indent=0;
283 TestItem *test;
284 Emit( "int main( int argc, char *argv[] )\n{" );
285 Emit( " if ( argc == 1 )" );
286 Emit( " cut_init( -1 );" );
287 Emit( " else cut_init( atoi( argv[1] ) );" );
288 BlankLine();
290 indent = 1;
291 test = testList;
292 while ( test )
294 if (test->type == TYPE_BRINGUP)
296 EmitBringup(indent,test->name);
297 indent ++;
300 if (test->type == TYPE_TEST)
301 EmitTest(indent,test->name);
303 if (test->type == TYPE_TAKEDOWN)
305 indent --;
306 EmitTakedown(indent,test->name);
308 test = test->next;
311 BlankLine();
312 Emit( " cut_break_formatting();" );
313 Emit( " printf(\"Done.\\n\");" );
314 Emit( " return 0;\n}\n" );
317 void EmitCutCheck()
319 Emit( "/* Automatically generated: DO NOT MODIFY. */" );
320 ListHeaderFiles();
321 BlankLine();
322 ListExternalFunctions();
323 BlankLine();
324 EmitUnitTesterBody();
327 void FileName( char *base )
329 strncpy( g_fileName, base, MAX_LINE_LENGTH );
330 g_fileName[ MAX_LINE_LENGTH - 1 ] = 0;
333 int LoadArgument( void )
335 if ( g_index >= g_count )
336 return 0;
338 FileName( g_wildcards[g_index] );
339 g_index++; /* MUST come after FileName() call; bad code smell */
340 return 1;
343 void StartArguments( int starting, int count, char *array[] )
345 g_index = starting;
346 g_count = count;
347 g_wildcards = array;
349 g_ready = LoadArgument();
352 int NextArgument( void )
354 if( g_ready )
355 g_ready = LoadArgument();
357 return g_ready;
360 char *GetArgument( void )
362 if( g_ready )
363 return g_fileName;
365 return NULL;
368 void EstablishOutputFile( int argc, char *argv[] )
370 int i;
372 i = 0;
373 while( i < argc )
375 if( ( argv[i+1] != NULL ) && ( strcmp( argv[i], "-o" ) == 0 ) )
377 outfile = fopen( argv[i+1], "wb+" );
378 if( outfile == NULL )
379 fprintf( stderr, "ERROR: Can't open %s for writing.\n", argv[i+1] );
381 argv[i] = argv[i+1] = DO_NOT_PROCESS;
383 return;
386 i++;
389 outfile = stdout;
392 int main( int argc,char *argv[] )
394 char *filename;
396 if ( argc < 2 )
398 fprintf(
399 stderr,
400 "USAGE:\n"
401 " %s [options] <input file> [<input file> [...]]\n"
402 "\n"
403 "OPTIONS:\n"
404 " -o filename Specifies output file.\n"
405 "\n"
406 "NOTES:\n"
407 " If -o is left unspecified, output defaults to stdout.\n",
408 argv[0]
410 return 3;
413 EstablishOutputFile( argc, argv );
415 /* Skip the executable's name and the output filename. */
416 StartArguments(0,argc,argv);
418 /* Consume the rest of the arguments, one at a time. */
419 while ( NextArgument() )
421 filename = GetArgument();
423 if( strcmp( filename, DO_NOT_PROCESS ) )
425 fprintf( stderr, " - parsing '%s'... ", filename);
426 ProcessSourceFile( filename );
427 fprintf( stderr, "done.\n");
431 EmitCutCheck();
432 fflush(outfile);
433 fclose(outfile);
434 return 0;
437 char * libCUT[] =
439 "/*",
440 " * libcut.inc",
441 " * CUT 2.1",
442 " *",
443 " * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley",
444 " * See CUT-LICENSE.TXT for details.",
445 " *",
446 " * Based on WDT's 'TestAssert' package.",
447 " *",
448 " * $log$",
449 " */",
451 "#include <string.h>",
452 "#include <stdlib.h>",
453 "#include <stdio.h>",
454 "#include <stdarg.h>",
455 "#include \"cut.h\"",
457 "#ifndef BOOL /* Just in case -- helps in portability */",
458 "#define BOOL int",
459 "#endif",
461 "#ifndef FALSE",
462 "#define FALSE (0)",
463 "#endif",
465 "#ifndef TRUE",
466 "#define TRUE 1",
467 "#endif",
469 "typedef struct NameStackItem NameStackItem;",
470 "typedef struct NameStackItem *NameStack;",
472 "struct NameStackItem",
473 "{",
474 " NameStackItem * next;",
475 " char * name;",
476 " CUTTakedownFunction *takedown;",
477 "};",
479 "static int breakpoint = 0;",
480 "static int count = 0;",
481 "static BOOL test_hit_error = FALSE;",
482 "static NameStack nameStack;",
484 "static void traceback( void );",
485 "static void cut_exit( void );",
487 "/* I/O Functions */",
489 "static void print_string( char *string )",
490 "{",
491 " printf( \"%s\", string );",
492 " fflush( stdout );",
493 "}",
495 "static void print_string_as_error( char *filename, int lineNumber, char *string )",
496 "{",
497 " printf( \"%s(%d): %s\", filename, lineNumber, string );",
498 " fflush( stdout );",
499 "}",
501 "static void print_integer_as_expected( int i )",
502 "{",
503 " printf( \"(signed) %d (unsigned) %u (hex) 0x%08X\", i, i, i );",
504 "}",
506 "static void print_integer( int i )",
507 "{",
508 " printf( \"%d\", i );",
509 " fflush( stdout );",
510 "}",
512 "static void print_integer_in_field( int i, int width )",
513 "{",
514 " printf( \"%*d\", width, i );",
515 " fflush( stdout );",
516 "}",
518 "static void new_line( void )",
519 "{",
520 " printf( \"\\n\" );",
521 " fflush( stdout );",
522 "}",
524 "static void print_character( char ch )",
525 "{",
526 " printf( \"%c\", ch );",
527 " fflush( stdout );",
528 "}",
530 "static void dot( void )",
531 "{",
532 " print_character( '.' );",
533 "}",
535 "static void space( void )",
536 "{",
537 " print_character( ' ' );",
538 "}",
540 "/* Name Stack Functions */",
542 "static NameStackItem *stack_topOf( NameStack *stack )",
543 "{",
544 " return *stack;",
545 "}",
547 "static BOOL stack_isEmpty( NameStack *stack )",
548 "{",
549 " return stack_topOf( stack ) == NULL;",
550 "}",
552 "static BOOL stack_isNotEmpty( NameStack *stack )",
553 "{",
554 " return !( stack_isEmpty( stack ) );",
555 "}",
557 "static void stack_push( NameStack *stack, char *name, CUTTakedownFunction *tdfunc )",
558 "{",
559 " NameStackItem *item;",
561 " item = (NameStackItem *)( malloc( sizeof( NameStackItem ) ) );",
562 " if( item != NULL )",
563 " {",
564 " item -> next = stack_topOf( stack );",
565 " item -> name = name;",
566 " item -> takedown = tdfunc;",
568 " *stack = item;",
569 " }",
570 "}",
572 "static void stack_drop( NameStack *stack )",
573 "{",
574 " NameStackItem *oldItem;",
576 " if( stack_isNotEmpty( stack ) )",
577 " {",
578 " oldItem = stack_topOf( stack );",
579 " *stack = oldItem -> next;",
581 " free( oldItem );",
582 " }",
583 "}",
585 "/* CUT Initialization and Takedown Functions */",
587 "void cut_init( int brkpoint )",
588 "{",
589 " breakpoint = brkpoint;",
590 " count = 0;",
591 " test_hit_error = FALSE;",
592 " nameStack = NULL;",
594 " if( brkpoint >= 0 )",
595 " {",
596 " print_string( \"Breakpoint at test \" );",
597 " print_integer( brkpoint );",
598 " new_line();",
599 " }",
600 "}",
602 "void cut_exit( void )",
603 "{",
604 " exit( test_hit_error != FALSE );",
605 "}",
607 "/* User Interface functions */",
609 "static void print_group( int position, int base, int leftover )",
610 "{",
611 " if( !leftover )",
612 " return;",
614 " print_integer_in_field( base, position );",
615 " while( --leftover )",
616 " dot();",
617 "}",
619 "static void print_recap( int count )",
620 "{",
621 " int countsOnLastLine = count % 50;",
622 " int groupsOnLastLine = countsOnLastLine / 10;",
623 " int dotsLeftOver = countsOnLastLine % 10;",
624 " int lastGroupLocation =",
625 " countsOnLastLine - dotsLeftOver + ( 4 * groupsOnLastLine ) + 5;",
627 " if( dotsLeftOver == 0 )",
628 " {",
629 " if( countsOnLastLine == 0 )",
630 " lastGroupLocation = 61;",
631 " else",
632 " lastGroupLocation -= 14;",
634 " print_group( lastGroupLocation, countsOnLastLine-10, 10);",
635 " }",
636 " else",
637 " {",
638 " print_group(",
639 " lastGroupLocation,",
640 " countsOnLastLine - dotsLeftOver,",
641 " dotsLeftOver",
642 " );",
643 " }",
644 "}",
646 "void cut_break_formatting( void ) // DEPRECATED: Do not use in future software",
647 "{",
648 " new_line();",
649 "}",
651 "void cut_resume_formatting( void )",
652 "{",
653 " new_line();",
654 " print_recap( count );",
655 "}",
657 "void cut_interject( const char *comment, ... )",
658 "{",
659 " va_list marker;",
660 " va_start(marker,comment);",
661 " ",
662 " cut_break_formatting();",
663 " vprintf(comment,marker);",
664 " cut_resume_formatting();",
665 " ",
666 " va_end(marker);",
667 "}",
669 "/* Test Progress Accounting functions */",
671 "void __cut_mark_point( char *filename, int lineNumber )",
672 "{",
673 " if( ( count % 10 ) == 0 )",
674 " {",
675 " if( ( count % 50 ) == 0 )",
676 " new_line();",
678 " print_integer_in_field( count, 5 );",
679 " }",
680 " else",
681 " dot();",
683 " count++;",
684 " if( count == breakpoint )",
685 " {",
686 " print_string_as_error( filename, lineNumber, \"Breakpoint hit\" );",
687 " new_line();",
688 " traceback();",
689 " cut_exit();",
690 " }",
691 "}",
693 "void __cut_assert_equals( // DEPRECATED: Do not use in future software",
694 " char *filename,",
695 " int lineNumber,",
696 " char *message,",
697 " char *expression,",
698 " BOOL success,",
699 " int expected",
700 " )",
701 "{",
702 " __cut_mark_point( filename, lineNumber );",
703 " ",
704 " if( success != FALSE )",
705 " return;",
706 " ",
707 " cut_break_formatting();",
708 " print_string_as_error( filename, lineNumber, message );",
709 " new_line();",
710 " print_string_as_error( filename, lineNumber, \"Failed expression: \" );",
711 " print_string( expression );",
712 " new_line();",
713 " print_string_as_error( filename, lineNumber, \"Actual value: \" );",
714 " print_integer_as_expected( expected );",
715 " new_line();",
717 " test_hit_error = TRUE;",
718 " cut_resume_formatting();",
719 "}",
722 "void __cut_assert(",
723 " char *filename,",
724 " int lineNumber,",
725 " char *message,",
726 " char *expression,",
727 " BOOL success",
728 " )",
729 "{",
730 " __cut_mark_point( filename, lineNumber );",
731 " ",
732 " if( success != FALSE )",
733 " return;",
734 " ",
735 " cut_break_formatting();",
736 " print_string_as_error( filename, lineNumber, message );",
737 " new_line();",
738 " print_string_as_error( filename, lineNumber, \"Failed expression: \" );",
739 " print_string( expression );",
740 " new_line();",
742 " test_hit_error = TRUE;",
743 " cut_resume_formatting();",
744 "}",
747 "/* Test Delineation and Teardown Support Functions */",
749 "static void traceback()",
750 "{",
751 " if( stack_isNotEmpty( &nameStack ) )",
752 " print_string( \"Traceback\" );",
753 " else",
754 " print_string( \"(No traceback available.)\" );",
756 " while( stack_isNotEmpty( &nameStack ) )",
757 " {",
758 " print_string( \": \" );",
759 " print_string( stack_topOf( &nameStack ) -> name );",
761 " if( stack_topOf( &nameStack ) -> takedown != NULL )",
762 " {",
763 " print_string( \"(taking down)\" );",
764 " stack_topOf( &nameStack ) -> takedown();",
765 " }",
767 " stack_drop( &nameStack );",
769 " if( stack_isNotEmpty( &nameStack ) )",
770 " space();",
771 " }",
773 " new_line();",
774 "}",
776 "void cut_start( char *name, CUTTakedownFunction *takedownFunction )",
777 "{",
778 " stack_push( &nameStack, name, takedownFunction );",
779 "}",
781 "int __cut_check_errors( char *filename, int lineNumber )",
782 "{",
783 " if( test_hit_error || stack_isEmpty( &nameStack ) )",
784 " {",
785 " cut_break_formatting();",
786 " if( stack_isEmpty( &nameStack ) )",
787 " print_string_as_error( filename, lineNumber, \"Missing cut_start(); no traceback possible.\" );",
788 " else",
789 " traceback();",
791 " cut_exit();",
792 " return 0;",
793 " } else return 1;",
794 "}",
796 "void __cut_end( char *filename, int lineNumber, char *closingFrame )",
797 "{",
798 " if( test_hit_error || stack_isEmpty( &nameStack ) )",
799 " {",
800 " cut_break_formatting();",
801 " if( stack_isEmpty( &nameStack ) )",
802 " print_string_as_error( filename, lineNumber, \"Missing cut_start(); no traceback possible.\" );",
803 " else",
804 " traceback();",
806 " cut_exit();",
807 " }",
808 " else",
809 " {",
810 " if( strcmp( stack_topOf( &nameStack ) -> name, closingFrame ) == 0 )",
811 " stack_drop( &nameStack );",
812 " else",
813 " {",
814 " print_string_as_error( filename, lineNumber, \"Mismatched cut_end().\" );",
815 " traceback();",
816 " cut_exit();",
817 " }",
818 " }",
819 "}",
824 * vim: tabstop=3 shiftwidth=3 expandtab