3 * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley
4 * See LICENSE.TXT for details.
7 * Revision 1.4 2003/03/18 05:53:50 sfalvo
8 * ADD: cutgen.c: cut_exit() -- common exit point; returns proper error code
11 * FIX: cutgen.c: Factored all instances of exit() to invoke cut_exit()
12 * instead. This fixes the bug #703793.
14 * Revision 1.3 2003/03/13 04:27:54 sfalvo
15 * ADD: LICENSE.TXT -- zlib license
17 * ADD: README cut.h cutgen.c -- Changelog token for CVS
19 * FIX: test/bringup-failure -- reflects new usage for bringups and
20 * teardowns in CUT 2.2.
29 #define DO_NOT_PROCESS "..."
31 #define SEARCH_TOKEN_TEST "__CUT__"
32 #define SEARCH_TOKEN_BRINGUP "__CUT_BRINGUP__"
33 #define SEARCH_TOKEN_TAKEDOWN "__CUT_TAKEDOWN__"
35 #define MAX_SYMBOL_LENGTH 256 /* arbitrary */
36 #define MAX_LINE_LENGTH 1024 /* arbitrary */
38 #define SEARCH_TOKEN_TEST_LENGTH sizeof( SEARCH_TOKEN_TEST )-1
39 #define SEARCH_TOKEN_BRINGUP_LENGTH sizeof( SEARCH_TOKEN_BRINGUP )-1
40 #define SEARCH_TOKEN_TAKEDOWN_LENGTH sizeof( SEARCH_TOKEN_TAKEDOWN )-1
42 typedef enum TestType
{
48 typedef struct TestItem
{
49 char name
[MAX_SYMBOL_LENGTH
];
51 struct TestItem
*next
;
56 TestItem
*testList
= 0;
58 extern char *libCUT
[]; /* defined at the end of this file */
60 static int g_count
, g_ready
, g_index
; /* Used by filename globbing support for windows */
61 static char **g_wildcards
, g_fileName
[MAX_LINE_LENGTH
];
63 TestItem
*FindFirstMatch( TestItem
*current
, char *basis_name
, int basis_type
)
67 if ( !strcmp(current
->name
,basis_name
) && current
->type
== basis_type
)
69 current
= current
->next
;
74 int NameAndTypeInTestList( char *name
, TestType type
)
76 return 0 != FindFirstMatch(testList
,name
,type
);
79 void AppendToTestList( char *name
, TestType type
)
81 struct TestItem
*current
= testList
;
83 current
= testList
= malloc( sizeof( *testList
) );
86 while ( current
->next
) current
= current
->next
;
87 current
->next
= malloc(sizeof( *testList
));
88 current
= current
->next
;
92 strcpy(current
->name
, name
);
96 void InsertNameAndTypeIntoTestList( char *name
, TestType type
)
98 if ( !NameAndTypeInTestList( name
, type
) )
99 AppendToTestList( name
, type
);
102 int CharacterIsDigit(char ch
)
104 return ( ( ch
>= '0') && ( ch
<= '9' ) );
107 int CharacterIsUppercase(char ch
)
109 return ( ( ch
>= 'A' ) && ( ch
<= 'Z' ) );
112 int CharacterIsLowercase(char ch
)
114 return ( ( ch
>= 'a' ) && ( ch
<= 'z' ) );
117 int CharacterIsAlphabetic(char ch
)
119 return CharacterIsUppercase(ch
) || CharacterIsLowercase(ch
) || ( ch
== '_' );
122 int CharacterIsAlphanumeric( char ch
)
124 return CharacterIsDigit(ch
) || CharacterIsAlphabetic(ch
);
127 void ProcessGenericFunction( char *line
, int position
,
128 TestType type
, int tokenDisplacement
)
130 char name
[MAX_SYMBOL_LENGTH
] = "";
131 int maxLength
= strlen( line
) - 1, offset
=0;
132 position
= position
+ tokenDisplacement
;
134 while ( CharacterIsAlphanumeric(line
[position
])
135 && (position
<maxLength
) && (offset
<MAX_SYMBOL_LENGTH
) )
137 name
[offset
++] = line
[position
++];
141 InsertNameAndTypeIntoTestList( name
, type
);
144 void ProcessBringupFunction( char *line
, int position
)
146 ProcessGenericFunction( line
, position
, TYPE_BRINGUP
, SEARCH_TOKEN_BRINGUP_LENGTH
);
149 void ProcessTestFunction( char *line
, int position
)
151 ProcessGenericFunction( line
, position
, TYPE_TEST
, SEARCH_TOKEN_TEST_LENGTH
);
154 void ProcessTakedownFunction( char *line
, int position
)
156 ProcessGenericFunction( line
, position
, TYPE_TAKEDOWN
, SEARCH_TOKEN_TAKEDOWN_LENGTH
);
160 int OffsetOfSubstring( char *line
, char *token
)
162 char *inset
= strstr(line
,token
);
164 if ( !inset
) return -1;
165 else return inset
- line
;
168 void CallIfSubstringFound( char *line
, char *token
, void (*function
)(char*,int) )
170 int index
= OffsetOfSubstring( line
, token
);
172 function( line
, index
);
175 void ProcessSourceFile( char *filename
)
178 char line
[MAX_LINE_LENGTH
];
180 if( strcmp( filename
, DO_NOT_PROCESS
) != 0 )
183 source
= fopen(filename
,"r");
185 while ( fgets(line
,MAX_LINE_LENGTH
,source
) )
187 CallIfSubstringFound( line
, SEARCH_TOKEN_BRINGUP
, ProcessBringupFunction
);
188 CallIfSubstringFound( line
, SEARCH_TOKEN_TEST
, ProcessTestFunction
);
189 CallIfSubstringFound( line
, SEARCH_TOKEN_TAKEDOWN
, ProcessTakedownFunction
);
196 void EmitExternDeclarationFor( char *name
, char *prefix
)
198 fprintf( outfile
, "extern void %s%s( void );\n", prefix
, name
);
201 void Emit(char *text
)
203 fprintf(outfile
, "%s\n", text
);
211 void ListExternalFunctions()
213 TestItem
*current
= testList
;
216 if (current
->type
== TYPE_TEST
)
217 EmitExternDeclarationFor( current
->name
, SEARCH_TOKEN_TEST
);
218 else if (current
->type
== TYPE_BRINGUP
)
219 EmitExternDeclarationFor( current
->name
, SEARCH_TOKEN_BRINGUP
);
220 else if (current
->type
== TYPE_TAKEDOWN
)
221 EmitExternDeclarationFor( current
->name
, SEARCH_TOKEN_TAKEDOWN
);
222 current
= current
->next
;
228 void EmitLibrary(void)
235 void ListHeaderFiles(void)
242 void EmitIndented(int indent
,char *format
, ...)
245 /* Print two spaces per level of indentation. */
246 fprintf( outfile
, "%*s", indent
*2, "" );
249 vfprintf( outfile
, format
, v
);
252 fprintf( outfile
, "\n" );
255 void EmitBringup(int indent
,char *name
)
258 EmitIndented(indent
, "cut_start( \"group-%s\", __CUT_TAKEDOWN__%s );",
260 EmitIndented(indent
, "__CUT_BRINGUP__%s();", name
);
261 EmitIndented(indent
, "cut_check_errors();");
264 void EmitTest(int indent
,char *name
)
266 EmitIndented(indent
, "cut_start( \"%s\", 0 );", name
);
267 EmitIndented(indent
, "__CUT__%s();", name
);
268 EmitIndented(indent
, "cut_end( \"%s\" );", name
);
271 void EmitTakedown(int indent
,char *name
)
273 EmitIndented(indent
, "cut_end( \"group-%s\" );", name
);
274 EmitIndented(indent
, "__CUT_TAKEDOWN__%s();", name
);
278 void EmitUnitTesterBody()
282 Emit( "int main( int argc, char *argv[] )\n{" );
283 Emit( " if ( argc == 1 )" );
284 Emit( " cut_init( -1 );" );
285 Emit( " else cut_init( atoi( argv[1] ) );" );
292 if (test
->type
== TYPE_BRINGUP
)
294 EmitBringup(indent
,test
->name
);
298 if (test
->type
== TYPE_TEST
)
299 EmitTest(indent
,test
->name
);
301 if (test
->type
== TYPE_TAKEDOWN
)
304 EmitTakedown(indent
,test
->name
);
310 Emit( " cut_break_formatting();" );
311 Emit( " printf(\"Done.\");" );
312 Emit( " return 0;\n}\n" );
317 Emit( "/* Automatically generated: DO NOT MODIFY. */" );
320 ListExternalFunctions();
322 EmitUnitTesterBody();
325 #if defined(_MSC_VER) // version tested for MS Visual C++ 6.0
328 void FileName(char *base
)
330 char *pos
= strrchr(g_wildcards
[g_index
],'/');
331 char *pos2
= strrchr(g_wildcards
[g_index
],'\\');
332 if ( !pos
|| pos2
> pos
)
337 size_t length
= 1 + pos
- g_wildcards
[g_index
];
338 strncpy(g_fileName
,g_wildcards
[g_index
],length
);
339 g_fileName
[length
] = 0;
341 else g_fileName
[0] = 0;
342 strcat(g_fileName
,base
);
345 int LoadArgument(void)
347 static struct _finddata_t fd
;
348 static long handle
= -1;
350 if ( g_index
>=g_count
)
355 handle
= _findfirst(g_wildcards
[g_index
], &fd
);
356 if ( -1 == handle
) // there MUST be at least a first match for each wildcard.
361 else if ( 0 == _findnext(handle
,&fd
) )
362 { // there's a 'next' filename
367 { // this wasn't the first filename, and there isn't a next.
371 return LoadArgument();
376 #if defined(__LINUX__)
378 void FileName( char *base
)
380 strncpy( g_fileName
, base
, MAX_LINE_LENGTH
);
381 g_fileName
[ MAX_LINE_LENGTH
- 1 ] = 0;
384 int LoadArgument( void )
386 if ( g_index
>= g_count
)
389 FileName( g_wildcards
[g_index
] );
390 g_index
++; /* MUST come after FileName() call; bad code smell */
396 void StartArguments( int starting
, int count
, char *array
[] )
402 g_ready
= LoadArgument();
405 int NextArgument( void )
408 g_ready
= LoadArgument();
413 char *GetArgument( void )
421 void EstablishOutputFile( int argc
, char *argv
[] )
428 if( ( argv
[i
+1] != NULL
) && ( strcmp( argv
[i
], "-o" ) == 0 ) )
430 outfile
= fopen( argv
[i
+1], "wb+" );
431 if( outfile
== NULL
)
432 fprintf( stderr
, "ERROR: Can't open %s for writing.\n", argv
[i
+1] );
434 argv
[i
] = argv
[i
+1] = DO_NOT_PROCESS
;
445 int main( int argc
,char *argv
[] )
454 " %s [options] <input file> [<input file> [...]]\n"
457 " -o filename Specifies output file.\n"
460 " If -o is left unspecified, output defaults to stdout.\n",
466 EstablishOutputFile( argc
, argv
);
468 /* Skip the executable's name and the output filename. */
469 StartArguments(0,argc
,argv
);
471 /* Consume the rest of the arguments, one at a time. */
472 while ( NextArgument() )
474 filename
= GetArgument();
476 if( strcmp( filename
, DO_NOT_PROCESS
) )
478 fprintf( stderr
, " - parsing '%s'... ", filename
);
479 ProcessSourceFile( filename
);
480 fprintf( stderr
, "done.\n");
496 " * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley",
497 " * See LICENSE.TXT for details.",
499 " * Based on WDT's 'TestAssert' package.",
504 "#include <string.h>",
505 "#include <stdlib.h>",
506 "#include <stdio.h>",
507 "#include <stdarg.h>",
508 "#include \"cut.h\"",
510 "#ifndef BOOL /* Just in case -- helps in portability */",
522 "typedef struct NameStackItem NameStackItem;",
523 "typedef struct NameStackItem *NameStack;",
525 "struct NameStackItem",
527 " NameStackItem * next;",
529 " CUTTakedownFunction *takedown;",
532 "static int breakpoint = 0;",
533 "static int count = 0;",
534 "static BOOL test_hit_error = FALSE;",
535 "static NameStack nameStack;",
537 "static void traceback( void );",
538 "static void cut_exit( void );",
540 "/* I/O Functions */",
542 "static void print_string( char *string )",
544 " printf( \"%s\", string );",
545 " fflush( stdout );",
548 "static void print_string_as_error( char *filename, int lineNumber, char *string )",
550 " printf( \"%s(%d): %s\", filename, lineNumber, string );",
551 " fflush( stdout );",
554 "static void print_integer_as_expected( int i )",
556 " printf( \"(signed) %d (unsigned) %u (hex) 0x%08X\", i, i, i );",
559 "static void print_integer( int i )",
561 " printf( \"%d\", i );",
562 " fflush( stdout );",
565 "static void print_integer_in_field( int i, int width )",
567 " printf( \"%*d\", width, i );",
568 " fflush( stdout );",
571 "static void new_line( void )",
573 " printf( \"\\n\" );",
574 " fflush( stdout );",
577 "static void print_character( char ch )",
579 " printf( \"%c\", ch );",
580 " fflush( stdout );",
583 "static void dot( void )",
585 " print_character( '.' );",
588 "static void space( void )",
590 " print_character( ' ' );",
593 "/* Name Stack Functions */",
595 "static NameStackItem *stack_topOf( NameStack *stack )",
600 "static BOOL stack_isEmpty( NameStack *stack )",
602 " return stack_topOf( stack ) == NULL;",
605 "static BOOL stack_isNotEmpty( NameStack *stack )",
607 " return !( stack_isEmpty( stack ) );",
610 "static void stack_push( NameStack *stack, char *name, CUTTakedownFunction *tdfunc )",
612 " NameStackItem *item;",
614 " item = (NameStackItem *)( malloc( sizeof( NameStackItem ) ) );",
615 " if( item != NULL )",
617 " item -> next = stack_topOf( stack );",
618 " item -> name = name;",
619 " item -> takedown = tdfunc;",
625 "static void stack_drop( NameStack *stack )",
627 " NameStackItem *oldItem;",
629 " if( stack_isNotEmpty( stack ) )",
631 " oldItem = stack_topOf( stack );",
632 " *stack = oldItem -> next;",
638 "/* CUT Initialization and Takedown Functions */",
640 "void cut_init( int brkpoint )",
642 " breakpoint = brkpoint;",
644 " test_hit_error = FALSE;",
645 " nameStack = NULL;",
647 " if( brkpoint >= 0 )",
649 " print_string( \"Breakpoint at test \" );",
650 " print_integer( brkpoint );",
655 "void cut_exit( void )",
657 " exit( test_hit_error != FALSE );",
660 "/* User Interface functions */",
662 "static void print_group( int position, int base, int leftover )",
667 " print_integer_in_field( base, position );",
668 " while( --leftover )",
672 "static void print_recap( int count )",
674 " int countsOnLastLine = count % 50;",
675 " int groupsOnLastLine = countsOnLastLine / 10;",
676 " int dotsLeftOver = countsOnLastLine % 10;",
677 " int lastGroupLocation =",
678 " countsOnLastLine - dotsLeftOver + ( 4 * groupsOnLastLine ) + 5;",
680 " if( dotsLeftOver == 0 )",
682 " if( countsOnLastLine == 0 )",
683 " lastGroupLocation = 61;",
685 " lastGroupLocation -= 14;",
687 " print_group( lastGroupLocation, countsOnLastLine-10, 10);",
692 " lastGroupLocation,",
693 " countsOnLastLine - dotsLeftOver,",
699 "void cut_break_formatting( void ) // DEPRECATED: Do not use in future software",
704 "void cut_resume_formatting( void )",
707 " print_recap( count );",
710 "void cut_interject( const char *comment, ... )",
713 " va_start(marker,comment);",
715 " cut_break_formatting();",
716 " vprintf(comment,marker);",
717 " cut_resume_formatting();",
722 "/* Test Progress Accounting functions */",
724 "void __cut_mark_point( char *filename, int lineNumber )",
726 " if( ( count % 10 ) == 0 )",
728 " if( ( count % 50 ) == 0 )",
731 " print_integer_in_field( count, 5 );",
737 " if( count == breakpoint )",
739 " print_string_as_error( filename, lineNumber, \"Breakpoint hit\" );",
746 "void __cut_assert_equals( // DEPRECATED: Do not use in future software",
750 " char *expression,",
755 " __cut_mark_point( filename, lineNumber );",
757 " if( success != FALSE )",
760 " cut_break_formatting();",
761 " print_string_as_error( filename, lineNumber, message );",
763 " print_string_as_error( filename, lineNumber, \"Failed expression: \" );",
764 " print_string( expression );",
766 " print_string_as_error( filename, lineNumber, \"Actual value: \" );",
767 " print_integer_as_expected( expected );",
770 " test_hit_error = TRUE;",
771 " cut_resume_formatting();",
775 "void __cut_assert(",
779 " char *expression,",
783 " __cut_mark_point( filename, lineNumber );",
785 " if( success != FALSE )",
788 " cut_break_formatting();",
789 " print_string_as_error( filename, lineNumber, message );",
791 " print_string_as_error( filename, lineNumber, \"Failed expression: \" );",
792 " print_string( expression );",
795 " test_hit_error = TRUE;",
796 " cut_resume_formatting();",
800 "/* Test Delineation and Teardown Support Functions */",
802 "static void traceback()",
804 " if( stack_isNotEmpty( &nameStack ) )",
805 " print_string( \"Traceback\" );",
807 " print_string( \"(No traceback available.)\" );",
809 " while( stack_isNotEmpty( &nameStack ) )",
811 " print_string( \": \" );",
812 " print_string( stack_topOf( &nameStack ) -> name );",
814 " if( stack_topOf( &nameStack ) -> takedown != NULL )",
816 " print_string( \"(taking down)\" );",
817 " stack_topOf( &nameStack ) -> takedown();",
820 " stack_drop( &nameStack );",
822 " if( stack_isNotEmpty( &nameStack ) )",
829 "void cut_start( char *name, CUTTakedownFunction *takedownFunction )",
831 " stack_push( &nameStack, name, takedownFunction );",
834 "int __cut_check_errors( char *filename, int lineNumber )",
836 " if( test_hit_error || stack_isEmpty( &nameStack ) )",
838 " cut_break_formatting();",
839 " if( stack_isEmpty( &nameStack ) )",
840 " print_string_as_error( filename, lineNumber, \"Missing cut_start(); no traceback possible.\" );",
849 "void __cut_end( char *filename, int lineNumber, char *closingFrame )",
851 " if( test_hit_error || stack_isEmpty( &nameStack ) )",
853 " cut_break_formatting();",
854 " if( stack_isEmpty( &nameStack ) )",
855 " print_string_as_error( filename, lineNumber, \"Missing cut_start(); no traceback possible.\" );",
863 " if( strcmp( stack_topOf( &nameStack ) -> name, closingFrame ) == 0 )",
864 " stack_drop( &nameStack );",
867 " print_string_as_error( filename, lineNumber, \"Mismatched cut_end().\" );",
877 * vim: tabstop=3 shiftwidth=3 expandtab