2 * This file has been modified from the original CUT distribution.
5 * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley
6 * See CUT-LICENSE.TXT for details.
9 * Revision 1.4 2003/03/18 05:53:50 sfalvo
10 * ADD: cutgen.c: cut_exit() -- common exit point; returns proper error code
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.
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
{
50 typedef struct TestItem
{
51 char name
[MAX_SYMBOL_LENGTH
];
53 struct TestItem
*next
;
58 TestItem
*testList
= 0;
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
)
69 if ( !strcmp(current
->name
,basis_name
) && current
->type
== basis_type
)
71 current
= current
->next
;
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
;
85 current
= testList
= malloc( sizeof( *testList
) );
88 while ( current
->next
) current
= current
->next
;
89 current
->next
= malloc(sizeof( *testList
));
90 current
= current
->next
;
94 strcpy(current
->name
, name
);
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
++];
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
);
174 function( line
, index
);
177 void ProcessSourceFile( char *filename
)
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
);
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
);
213 void ListExternalFunctions()
215 TestItem
*current
= testList
;
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
;
230 void EmitLibrary(void)
237 void ListHeaderFiles(void)
244 void EmitIndented(int indent
,char *format
, ...)
247 /* Print two spaces per level of indentation. */
248 fprintf( outfile
, "%*s", indent
*2, "" );
251 vfprintf( outfile
, format
, v
);
254 fprintf( outfile
, "\n" );
257 void EmitBringup(int indent
,char *name
)
260 EmitIndented(indent
, "cut_start( \"group-%s\", __CUT_TAKEDOWN__%s );",
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
);
280 void EmitUnitTesterBody()
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] ) );" );
294 if (test
->type
== TYPE_BRINGUP
)
296 EmitBringup(indent
,test
->name
);
300 if (test
->type
== TYPE_TEST
)
301 EmitTest(indent
,test
->name
);
303 if (test
->type
== TYPE_TAKEDOWN
)
306 EmitTakedown(indent
,test
->name
);
312 Emit( " cut_break_formatting();" );
313 Emit( " printf(\"Done.\");" );
314 Emit( " return 0;\n}\n" );
319 Emit( "/* Automatically generated: DO NOT MODIFY. */" );
322 ListExternalFunctions();
324 EmitUnitTesterBody();
327 #if defined(_MSC_VER) // version tested for MS Visual C++ 6.0
330 void FileName(char *base
)
332 char *pos
= strrchr(g_wildcards
[g_index
],'/');
333 char *pos2
= strrchr(g_wildcards
[g_index
],'\\');
334 if ( !pos
|| pos2
> pos
)
339 size_t length
= 1 + pos
- g_wildcards
[g_index
];
340 strncpy(g_fileName
,g_wildcards
[g_index
],length
);
341 g_fileName
[length
] = 0;
343 else g_fileName
[0] = 0;
344 strcat(g_fileName
,base
);
347 int LoadArgument(void)
349 static struct _finddata_t fd
;
350 static long handle
= -1;
352 if ( g_index
>=g_count
)
357 handle
= _findfirst(g_wildcards
[g_index
], &fd
);
358 if ( -1 == handle
) // there MUST be at least a first match for each wildcard.
363 else if ( 0 == _findnext(handle
,&fd
) )
364 { // there's a 'next' filename
369 { // this wasn't the first filename, and there isn't a next.
373 return LoadArgument();
378 #if defined(__LINUX__)
380 void FileName( char *base
)
382 strncpy( g_fileName
, base
, MAX_LINE_LENGTH
);
383 g_fileName
[ MAX_LINE_LENGTH
- 1 ] = 0;
386 int LoadArgument( void )
388 if ( g_index
>= g_count
)
391 FileName( g_wildcards
[g_index
] );
392 g_index
++; /* MUST come after FileName() call; bad code smell */
398 void StartArguments( int starting
, int count
, char *array
[] )
404 g_ready
= LoadArgument();
407 int NextArgument( void )
410 g_ready
= LoadArgument();
415 char *GetArgument( void )
423 void EstablishOutputFile( int argc
, char *argv
[] )
430 if( ( argv
[i
+1] != NULL
) && ( strcmp( argv
[i
], "-o" ) == 0 ) )
432 outfile
= fopen( argv
[i
+1], "wb+" );
433 if( outfile
== NULL
)
434 fprintf( stderr
, "ERROR: Can't open %s for writing.\n", argv
[i
+1] );
436 argv
[i
] = argv
[i
+1] = DO_NOT_PROCESS
;
447 int main( int argc
,char *argv
[] )
456 " %s [options] <input file> [<input file> [...]]\n"
459 " -o filename Specifies output file.\n"
462 " If -o is left unspecified, output defaults to stdout.\n",
468 EstablishOutputFile( argc
, argv
);
470 /* Skip the executable's name and the output filename. */
471 StartArguments(0,argc
,argv
);
473 /* Consume the rest of the arguments, one at a time. */
474 while ( NextArgument() )
476 filename
= GetArgument();
478 if( strcmp( filename
, DO_NOT_PROCESS
) )
480 fprintf( stderr
, " - parsing '%s'... ", filename
);
481 ProcessSourceFile( filename
);
482 fprintf( stderr
, "done.\n");
498 " * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley",
499 " * See CUT-LICENSE.TXT for details.",
501 " * Based on WDT's 'TestAssert' package.",
506 "#include <string.h>",
507 "#include <stdlib.h>",
508 "#include <stdio.h>",
509 "#include <stdarg.h>",
510 "#include \"cut.h\"",
512 "#ifndef BOOL /* Just in case -- helps in portability */",
524 "typedef struct NameStackItem NameStackItem;",
525 "typedef struct NameStackItem *NameStack;",
527 "struct NameStackItem",
529 " NameStackItem * next;",
531 " CUTTakedownFunction *takedown;",
534 "static int breakpoint = 0;",
535 "static int count = 0;",
536 "static BOOL test_hit_error = FALSE;",
537 "static NameStack nameStack;",
539 "static void traceback( void );",
540 "static void cut_exit( void );",
542 "/* I/O Functions */",
544 "static void print_string( char *string )",
546 " printf( \"%s\", string );",
547 " fflush( stdout );",
550 "static void print_string_as_error( char *filename, int lineNumber, char *string )",
552 " printf( \"%s(%d): %s\", filename, lineNumber, string );",
553 " fflush( stdout );",
556 "static void print_integer_as_expected( int i )",
558 " printf( \"(signed) %d (unsigned) %u (hex) 0x%08X\", i, i, i );",
561 "static void print_integer( int i )",
563 " printf( \"%d\", i );",
564 " fflush( stdout );",
567 "static void print_integer_in_field( int i, int width )",
569 " printf( \"%*d\", width, i );",
570 " fflush( stdout );",
573 "static void new_line( void )",
575 " printf( \"\\n\" );",
576 " fflush( stdout );",
579 "static void print_character( char ch )",
581 " printf( \"%c\", ch );",
582 " fflush( stdout );",
585 "static void dot( void )",
587 " print_character( '.' );",
590 "static void space( void )",
592 " print_character( ' ' );",
595 "/* Name Stack Functions */",
597 "static NameStackItem *stack_topOf( NameStack *stack )",
602 "static BOOL stack_isEmpty( NameStack *stack )",
604 " return stack_topOf( stack ) == NULL;",
607 "static BOOL stack_isNotEmpty( NameStack *stack )",
609 " return !( stack_isEmpty( stack ) );",
612 "static void stack_push( NameStack *stack, char *name, CUTTakedownFunction *tdfunc )",
614 " NameStackItem *item;",
616 " item = (NameStackItem *)( malloc( sizeof( NameStackItem ) ) );",
617 " if( item != NULL )",
619 " item -> next = stack_topOf( stack );",
620 " item -> name = name;",
621 " item -> takedown = tdfunc;",
627 "static void stack_drop( NameStack *stack )",
629 " NameStackItem *oldItem;",
631 " if( stack_isNotEmpty( stack ) )",
633 " oldItem = stack_topOf( stack );",
634 " *stack = oldItem -> next;",
640 "/* CUT Initialization and Takedown Functions */",
642 "void cut_init( int brkpoint )",
644 " breakpoint = brkpoint;",
646 " test_hit_error = FALSE;",
647 " nameStack = NULL;",
649 " if( brkpoint >= 0 )",
651 " print_string( \"Breakpoint at test \" );",
652 " print_integer( brkpoint );",
657 "void cut_exit( void )",
659 " exit( test_hit_error != FALSE );",
662 "/* User Interface functions */",
664 "static void print_group( int position, int base, int leftover )",
669 " print_integer_in_field( base, position );",
670 " while( --leftover )",
674 "static void print_recap( int count )",
676 " int countsOnLastLine = count % 50;",
677 " int groupsOnLastLine = countsOnLastLine / 10;",
678 " int dotsLeftOver = countsOnLastLine % 10;",
679 " int lastGroupLocation =",
680 " countsOnLastLine - dotsLeftOver + ( 4 * groupsOnLastLine ) + 5;",
682 " if( dotsLeftOver == 0 )",
684 " if( countsOnLastLine == 0 )",
685 " lastGroupLocation = 61;",
687 " lastGroupLocation -= 14;",
689 " print_group( lastGroupLocation, countsOnLastLine-10, 10);",
694 " lastGroupLocation,",
695 " countsOnLastLine - dotsLeftOver,",
701 "void cut_break_formatting( void ) // DEPRECATED: Do not use in future software",
706 "void cut_resume_formatting( void )",
709 " print_recap( count );",
712 "void cut_interject( const char *comment, ... )",
715 " va_start(marker,comment);",
717 " cut_break_formatting();",
718 " vprintf(comment,marker);",
719 " cut_resume_formatting();",
724 "/* Test Progress Accounting functions */",
726 "void __cut_mark_point( char *filename, int lineNumber )",
728 " if( ( count % 10 ) == 0 )",
730 " if( ( count % 50 ) == 0 )",
733 " print_integer_in_field( count, 5 );",
739 " if( count == breakpoint )",
741 " print_string_as_error( filename, lineNumber, \"Breakpoint hit\" );",
748 "void __cut_assert_equals( // DEPRECATED: Do not use in future software",
752 " char *expression,",
757 " __cut_mark_point( filename, lineNumber );",
759 " if( success != FALSE )",
762 " cut_break_formatting();",
763 " print_string_as_error( filename, lineNumber, message );",
765 " print_string_as_error( filename, lineNumber, \"Failed expression: \" );",
766 " print_string( expression );",
768 " print_string_as_error( filename, lineNumber, \"Actual value: \" );",
769 " print_integer_as_expected( expected );",
772 " test_hit_error = TRUE;",
773 " cut_resume_formatting();",
777 "void __cut_assert(",
781 " char *expression,",
785 " __cut_mark_point( filename, lineNumber );",
787 " if( success != FALSE )",
790 " cut_break_formatting();",
791 " print_string_as_error( filename, lineNumber, message );",
793 " print_string_as_error( filename, lineNumber, \"Failed expression: \" );",
794 " print_string( expression );",
797 " test_hit_error = TRUE;",
798 " cut_resume_formatting();",
802 "/* Test Delineation and Teardown Support Functions */",
804 "static void traceback()",
806 " if( stack_isNotEmpty( &nameStack ) )",
807 " print_string( \"Traceback\" );",
809 " print_string( \"(No traceback available.)\" );",
811 " while( stack_isNotEmpty( &nameStack ) )",
813 " print_string( \": \" );",
814 " print_string( stack_topOf( &nameStack ) -> name );",
816 " if( stack_topOf( &nameStack ) -> takedown != NULL )",
818 " print_string( \"(taking down)\" );",
819 " stack_topOf( &nameStack ) -> takedown();",
822 " stack_drop( &nameStack );",
824 " if( stack_isNotEmpty( &nameStack ) )",
831 "void cut_start( char *name, CUTTakedownFunction *takedownFunction )",
833 " stack_push( &nameStack, name, takedownFunction );",
836 "int __cut_check_errors( char *filename, int lineNumber )",
838 " if( test_hit_error || stack_isEmpty( &nameStack ) )",
840 " cut_break_formatting();",
841 " if( stack_isEmpty( &nameStack ) )",
842 " print_string_as_error( filename, lineNumber, \"Missing cut_start(); no traceback possible.\" );",
851 "void __cut_end( char *filename, int lineNumber, char *closingFrame )",
853 " if( test_hit_error || stack_isEmpty( &nameStack ) )",
855 " cut_break_formatting();",
856 " if( stack_isEmpty( &nameStack ) )",
857 " print_string_as_error( filename, lineNumber, \"Missing cut_start(); no traceback possible.\" );",
865 " if( strcmp( stack_topOf( &nameStack ) -> name, closingFrame ) == 0 )",
866 " stack_drop( &nameStack );",
869 " print_string_as_error( filename, lineNumber, \"Mismatched cut_end().\" );",
879 * vim: tabstop=3 shiftwidth=3 expandtab