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.\\n\");" );
314 Emit( " return 0;\n}\n" );
319 Emit( "/* Automatically generated: DO NOT MODIFY. */" );
322 ListExternalFunctions();
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
)
338 FileName( g_wildcards
[g_index
] );
339 g_index
++; /* MUST come after FileName() call; bad code smell */
343 void StartArguments( int starting
, int count
, char *array
[] )
349 g_ready
= LoadArgument();
352 int NextArgument( void )
355 g_ready
= LoadArgument();
360 char *GetArgument( void )
368 void EstablishOutputFile( int argc
, char *argv
[] )
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
;
392 int main( int argc
,char *argv
[] )
401 " %s [options] <input file> [<input file> [...]]\n"
404 " -o filename Specifies output file.\n"
407 " If -o is left unspecified, output defaults to stdout.\n",
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");
443 " * Copyright (c) 2001-2002 Samuel A. Falvo II, William D. Tanksley",
444 " * See CUT-LICENSE.TXT for details.",
446 " * Based on WDT's 'TestAssert' package.",
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 */",
469 "typedef struct NameStackItem NameStackItem;",
470 "typedef struct NameStackItem *NameStack;",
472 "struct NameStackItem",
474 " NameStackItem * next;",
476 " CUTTakedownFunction *takedown;",
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 )",
491 " printf( \"%s\", string );",
492 " fflush( stdout );",
495 "static void print_string_as_error( char *filename, int lineNumber, char *string )",
497 " printf( \"%s(%d): %s\", filename, lineNumber, string );",
498 " fflush( stdout );",
501 "static void print_integer_as_expected( int i )",
503 " printf( \"(signed) %d (unsigned) %u (hex) 0x%08X\", i, i, i );",
506 "static void print_integer( int i )",
508 " printf( \"%d\", i );",
509 " fflush( stdout );",
512 "static void print_integer_in_field( int i, int width )",
514 " printf( \"%*d\", width, i );",
515 " fflush( stdout );",
518 "static void new_line( void )",
520 " printf( \"\\n\" );",
521 " fflush( stdout );",
524 "static void print_character( char ch )",
526 " printf( \"%c\", ch );",
527 " fflush( stdout );",
530 "static void dot( void )",
532 " print_character( '.' );",
535 "static void space( void )",
537 " print_character( ' ' );",
540 "/* Name Stack Functions */",
542 "static NameStackItem *stack_topOf( NameStack *stack )",
547 "static BOOL stack_isEmpty( NameStack *stack )",
549 " return stack_topOf( stack ) == NULL;",
552 "static BOOL stack_isNotEmpty( NameStack *stack )",
554 " return !( stack_isEmpty( stack ) );",
557 "static void stack_push( NameStack *stack, char *name, CUTTakedownFunction *tdfunc )",
559 " NameStackItem *item;",
561 " item = (NameStackItem *)( malloc( sizeof( NameStackItem ) ) );",
562 " if( item != NULL )",
564 " item -> next = stack_topOf( stack );",
565 " item -> name = name;",
566 " item -> takedown = tdfunc;",
572 "static void stack_drop( NameStack *stack )",
574 " NameStackItem *oldItem;",
576 " if( stack_isNotEmpty( stack ) )",
578 " oldItem = stack_topOf( stack );",
579 " *stack = oldItem -> next;",
585 "/* CUT Initialization and Takedown Functions */",
587 "void cut_init( int brkpoint )",
589 " breakpoint = brkpoint;",
591 " test_hit_error = FALSE;",
592 " nameStack = NULL;",
594 " if( brkpoint >= 0 )",
596 " print_string( \"Breakpoint at test \" );",
597 " print_integer( brkpoint );",
602 "void cut_exit( void )",
604 " exit( test_hit_error != FALSE );",
607 "/* User Interface functions */",
609 "static void print_group( int position, int base, int leftover )",
614 " print_integer_in_field( base, position );",
615 " while( --leftover )",
619 "static void print_recap( int count )",
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 )",
629 " if( countsOnLastLine == 0 )",
630 " lastGroupLocation = 61;",
632 " lastGroupLocation -= 14;",
634 " print_group( lastGroupLocation, countsOnLastLine-10, 10);",
639 " lastGroupLocation,",
640 " countsOnLastLine - dotsLeftOver,",
646 "void cut_break_formatting( void ) // DEPRECATED: Do not use in future software",
651 "void cut_resume_formatting( void )",
654 " print_recap( count );",
657 "void cut_interject( const char *comment, ... )",
660 " va_start(marker,comment);",
662 " cut_break_formatting();",
663 " vprintf(comment,marker);",
664 " cut_resume_formatting();",
669 "/* Test Progress Accounting functions */",
671 "void __cut_mark_point( char *filename, int lineNumber )",
673 " if( ( count % 10 ) == 0 )",
675 " if( ( count % 50 ) == 0 )",
678 " print_integer_in_field( count, 5 );",
684 " if( count == breakpoint )",
686 " print_string_as_error( filename, lineNumber, \"Breakpoint hit\" );",
693 "void __cut_assert_equals( // DEPRECATED: Do not use in future software",
697 " char *expression,",
702 " __cut_mark_point( filename, lineNumber );",
704 " if( success != FALSE )",
707 " cut_break_formatting();",
708 " print_string_as_error( filename, lineNumber, message );",
710 " print_string_as_error( filename, lineNumber, \"Failed expression: \" );",
711 " print_string( expression );",
713 " print_string_as_error( filename, lineNumber, \"Actual value: \" );",
714 " print_integer_as_expected( expected );",
717 " test_hit_error = TRUE;",
718 " cut_resume_formatting();",
722 "void __cut_assert(",
726 " char *expression,",
730 " __cut_mark_point( filename, lineNumber );",
732 " if( success != FALSE )",
735 " cut_break_formatting();",
736 " print_string_as_error( filename, lineNumber, message );",
738 " print_string_as_error( filename, lineNumber, \"Failed expression: \" );",
739 " print_string( expression );",
742 " test_hit_error = TRUE;",
743 " cut_resume_formatting();",
747 "/* Test Delineation and Teardown Support Functions */",
749 "static void traceback()",
751 " if( stack_isNotEmpty( &nameStack ) )",
752 " print_string( \"Traceback\" );",
754 " print_string( \"(No traceback available.)\" );",
756 " while( stack_isNotEmpty( &nameStack ) )",
758 " print_string( \": \" );",
759 " print_string( stack_topOf( &nameStack ) -> name );",
761 " if( stack_topOf( &nameStack ) -> takedown != NULL )",
763 " print_string( \"(taking down)\" );",
764 " stack_topOf( &nameStack ) -> takedown();",
767 " stack_drop( &nameStack );",
769 " if( stack_isNotEmpty( &nameStack ) )",
776 "void cut_start( char *name, CUTTakedownFunction *takedownFunction )",
778 " stack_push( &nameStack, name, takedownFunction );",
781 "int __cut_check_errors( char *filename, int lineNumber )",
783 " if( test_hit_error || stack_isEmpty( &nameStack ) )",
785 " cut_break_formatting();",
786 " if( stack_isEmpty( &nameStack ) )",
787 " print_string_as_error( filename, lineNumber, \"Missing cut_start(); no traceback possible.\" );",
796 "void __cut_end( char *filename, int lineNumber, char *closingFrame )",
798 " if( test_hit_error || stack_isEmpty( &nameStack ) )",
800 " cut_break_formatting();",
801 " if( stack_isEmpty( &nameStack ) )",
802 " print_string_as_error( filename, lineNumber, \"Missing cut_start(); no traceback possible.\" );",
810 " if( strcmp( stack_topOf( &nameStack ) -> name, closingFrame ) == 0 )",
811 " stack_drop( &nameStack );",
814 " print_string_as_error( filename, lineNumber, \"Mismatched cut_end().\" );",
824 * vim: tabstop=3 shiftwidth=3 expandtab