2 * Copyright (C) 2005 Casper S. Hornstrup
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 TestSupportCode::TestSupportCode ( const Project
& project
)
31 TestSupportCode::~TestSupportCode ()
36 TestSupportCode::IsTestModule ( const Module
& module
)
38 return module
.type
== Test
;
42 TestSupportCode::GenerateTestSupportCode ( bool verbose
)
44 for ( size_t i
= 0; i
< project
.modules
.size (); i
++ )
46 if ( IsTestModule ( *project
.modules
[i
] ) )
48 GenerateTestSupportCodeForModule ( *project
.modules
[i
],
55 TestSupportCode::GenerateTestSupportCodeForModule ( Module
& module
,
60 printf ( "\nGenerating test support code for %s",
61 module
.name
.c_str () );
64 WriteHooksFile ( module
);
65 WriteStubsFile ( module
);
66 WriteStartupFile ( module
);
70 TestSupportCode::GetHooksFilename ( Module
& module
)
72 return NormalizeFilename ( Environment::GetIntermediatePath () + sSep
+ module
.GetBasePath () + sSep
+ "_hooks.c" );
76 TestSupportCode::WriteStubbedSymbolToHooksFile ( char* buffer
,
77 const StubbedComponent
& component
,
78 const StubbedSymbol
& symbol
)
80 buffer
= buffer
+ sprintf ( buffer
,
81 " {\"%s\", \"%s\", NULL, NULL, NULL},\n",
82 component
.name
.c_str (),
83 symbol
.newname
.c_str () );
88 TestSupportCode::WriteStubbedComponentToHooksFile ( char* buffer
,
89 const StubbedComponent
& component
)
91 for ( size_t i
= 0; i
< component
.symbols
.size () ; i
++ )
92 buffer
= WriteStubbedSymbolToHooksFile ( buffer
,
94 *component
.symbols
[i
] );
99 TestSupportCode::WriteHooksFile ( Module
& module
)
104 buf
= (char*) malloc ( 50*1024 );
106 throw OutOfMemoryException ();
109 s
= s
+ sprintf ( s
, "/* This file is automatically generated. */\n" );
110 s
= s
+ sprintf ( s
, "#include <windows.h>\n" );
111 s
= s
+ sprintf ( s
, "#include \"regtests.h\"\n" );
112 s
= s
+ sprintf ( s
, "\n" );
113 s
= s
+ sprintf ( s
, "_API_DESCRIPTION ExternalDependencies[] =\n" );
114 s
= s
+ sprintf ( s
, "{\n" );
117 for ( size_t i
= 0; i
< module
.stubbedComponents
.size () ; i
++ )
119 s
= WriteStubbedComponentToHooksFile ( s
,
120 *module
.stubbedComponents
[i
] );
121 symbolCount
+= module
.stubbedComponents
[i
]->symbols
.size ();
124 s
= s
+ sprintf ( s
, "};\n" );
125 s
= s
+ sprintf ( s
, "\n" );
126 s
= s
+ sprintf ( s
, "#define ExternalDependencyCount %d\n", symbolCount
);
127 s
= s
+ sprintf ( s
, "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n" );
128 s
= s
+ sprintf ( s
, "\n" );
130 FileSupportCode::WriteIfChanged ( buf
, GetHooksFilename ( module
) );
136 TestSupportCode::GetStubsFilename ( Module
& module
)
138 return NormalizeFilename ( Environment::GetIntermediatePath () + sSep
+ module
.GetBasePath () + sSep
+ "_stubs.S" );
142 GetLinkerSymbol ( const StubbedSymbol
& symbol
)
144 if (symbol
.symbol
[0] == '@')
145 return symbol
.symbol
;
147 return "_" + symbol
.symbol
;
151 GetLinkerImportSymbol ( const StubbedSymbol
& symbol
)
153 if (symbol
.symbol
[0] == '@')
154 return "__imp_" + symbol
.symbol
;
156 return "__imp__" + symbol
.symbol
;
160 GetIndirectCallTargetSymbol ( const StubbedSymbol
& symbol
)
162 return GetLinkerSymbol ( symbol
) + "_";
166 TestSupportCode::WriteStubbedSymbolToStubsFile ( char* buffer
,
167 const StubbedComponent
& component
,
168 const StubbedSymbol
& symbol
,
171 string linkerSymbol
= GetLinkerSymbol ( symbol
);
172 string linkerImportSymbol
= GetLinkerImportSymbol ( symbol
);
173 string indirectCallTargetSymbol
= GetIndirectCallTargetSymbol ( symbol
);
174 buffer
= buffer
+ sprintf ( buffer
,
176 linkerSymbol
.c_str () );
177 buffer
= buffer
+ sprintf ( buffer
,
179 linkerImportSymbol
.c_str () );
180 buffer
= buffer
+ sprintf ( buffer
,
182 linkerSymbol
.c_str () );
183 buffer
= buffer
+ sprintf ( buffer
,
185 linkerImportSymbol
.c_str () );
186 buffer
= buffer
+ sprintf ( buffer
,
188 indirectCallTargetSymbol
.c_str () );
189 buffer
= buffer
+ sprintf ( buffer
,
191 indirectCallTargetSymbol
.c_str () );
192 buffer
= buffer
+ sprintf ( buffer
,
195 buffer
= buffer
+ sprintf ( buffer
,
196 " jmp passthrough\n" );
197 buffer
= buffer
+ sprintf ( buffer
, "\n" );
202 TestSupportCode::WriteStubbedComponentToStubsFile ( char* buffer
,
203 const StubbedComponent
& component
,
206 for ( size_t i
= 0; i
< component
.symbols
.size () ; i
++ )
207 buffer
= WriteStubbedSymbolToStubsFile ( buffer
,
209 *component
.symbols
[i
],
215 TestSupportCode::WriteStubsFile ( Module
& module
)
220 buf
= (char*) malloc ( 512*1024 );
222 throw OutOfMemoryException ();
225 s
= s
+ sprintf ( s
, "/* This file is automatically generated. */\n" );
226 s
= s
+ sprintf ( s
, "passthrough:\n" );
227 s
= s
+ sprintf ( s
, " call _FrameworkGetHook@4\n" );
228 s
= s
+ sprintf ( s
, " test %%eax, %%eax\n" );
229 s
= s
+ sprintf ( s
, " je .return\n" );
230 s
= s
+ sprintf ( s
, " jmp *%%eax\n" );
231 s
= s
+ sprintf ( s
, ".return:\n" );
232 s
= s
+ sprintf ( s
, " /* This will most likely corrupt the stack */\n" );
233 s
= s
+ sprintf ( s
, " ret\n" );
234 s
= s
+ sprintf ( s
, "\n" );
237 for ( size_t i
= 0; i
< module
.stubbedComponents
.size () ; i
++ )
239 s
= WriteStubbedComponentToStubsFile ( s
,
240 *module
.stubbedComponents
[i
],
244 FileSupportCode::WriteIfChanged ( buf
, GetStubsFilename ( module
) );
250 TestSupportCode::GetStartupFilename ( Module
& module
)
252 return NormalizeFilename ( Environment::GetIntermediatePath () + sSep
+ module
.GetBasePath () + sSep
+ "_startup.c" );
256 TestSupportCode::IsUnknownCharacter ( char ch
)
258 if ( ch
>= 'a' && ch
<= 'z' )
260 if ( ch
>= 'A' && ch
<= 'Z' )
262 if ( ch
>= '0' && ch
<= '9' )
268 TestSupportCode::GetTestDispatcherName ( string filename
)
270 string filenamePart
= ReplaceExtension ( GetFilename ( filename
), "" );
271 if ( filenamePart
.length () > 0 )
272 filenamePart
[0] = toupper ( filenamePart
[0] );
273 for ( size_t i
= 1; i
< filenamePart
.length (); i
++ )
275 if ( IsUnknownCharacter ( filenamePart
[i
] ) )
276 filenamePart
[i
] = '_';
278 filenamePart
[i
] = tolower ( filenamePart
[i
] );
280 return filenamePart
+ "Test";
284 TestSupportCode::IsTestFile ( string
& filename
) const
286 if ( stricmp ( GetFilename ( filename
).c_str (), "setup.c" ) == 0 )
292 TestSupportCode::GetSourceFilenames ( string_list
& list
,
293 Module
& module
) const
297 const vector
<CompilationUnit
*>& compilationUnits
= module
.non_if_data
.compilationUnits
;
298 for ( i
= 0; i
< compilationUnits
.size (); i
++ )
300 string filename
= compilationUnits
[i
]->GetFilename();
301 if ( !compilationUnits
[i
]->IsGeneratedFile () && IsTestFile ( filename
) )
302 list
.push_back ( filename
);
304 // intentionally make a copy so that we can append more work in
305 // the middle of processing without having to go recursive
306 vector
<If
*> v
= module
.non_if_data
.ifs
;
307 for ( i
= 0; i
< v
.size (); i
++ )
311 // check for sub-ifs to add to list
312 const vector
<If
*>& ifs
= rIf
.data
.ifs
;
313 for ( j
= 0; j
< ifs
.size (); j
++ )
314 v
.push_back ( ifs
[j
] );
315 const vector
<CompilationUnit
*>& compilationUnits
= rIf
.data
.compilationUnits
;
316 for ( j
= 0; j
< compilationUnits
.size (); j
++ )
318 CompilationUnit
& compilationUnit
= *compilationUnits
[j
];
319 string filename
= compilationUnits
[j
]->GetFilename();
320 if ( !compilationUnit
.IsGeneratedFile () && IsTestFile ( filename
) )
321 list
.push_back ( filename
);
327 TestSupportCode::WriteTestDispatcherPrototypesToStartupFile ( char* buffer
,
331 GetSourceFilenames ( files
,
333 for ( size_t i
= 0; i
< files
.size (); i
++ )
335 buffer
= buffer
+ sprintf ( buffer
,
336 "extern void %s(int Command, char *Buffer);\n",
337 GetTestDispatcherName ( files
[i
] ).c_str () );
339 buffer
= buffer
+ sprintf ( buffer
, "\n" );
344 TestSupportCode::WriteRegisterTestsFunctionToStartupFile ( char* buffer
,
347 buffer
= buffer
+ sprintf ( buffer
,
348 "extern void AddTest(TestRoutine Routine);\n" );
349 buffer
= buffer
+ sprintf ( buffer
,
352 buffer
= buffer
+ sprintf ( buffer
,
354 buffer
= buffer
+ sprintf ( buffer
,
355 "RegisterTests()\n" );
356 buffer
= buffer
+ sprintf ( buffer
,
360 GetSourceFilenames ( files
,
362 for ( size_t i
= 0; i
< files
.size (); i
++ )
364 buffer
= buffer
+ sprintf ( buffer
,
365 "AddTest((TestRoutine)%s);\n",
366 GetTestDispatcherName ( files
[i
]).c_str () );
368 buffer
= buffer
+ sprintf ( buffer
,
370 buffer
= buffer
+ sprintf ( buffer
, "\n" );
375 TestSupportCode::WriteStartupFile ( Module
& module
)
380 buf
= (char*) malloc ( 50*1024 );
382 throw OutOfMemoryException ();
385 s
= s
+ sprintf ( s
, "/* This file is automatically generated. */\n" );
386 s
= s
+ sprintf ( s
, "\n" );
387 s
= s
+ sprintf ( s
, "#include <windows.h>\n" );
388 s
= s
+ sprintf ( s
, "#include \"regtests.h\"\n" );
389 s
= s
+ sprintf ( s
, "\n" );
390 s
= WriteTestDispatcherPrototypesToStartupFile ( s
,
392 s
= WriteRegisterTestsFunctionToStartupFile ( s
,
394 s
= s
+ sprintf ( s
, "\n" );
395 s
= s
+ sprintf ( s
, "void\n" );
396 s
= s
+ sprintf ( s
, "ConsoleWrite(char *Buffer)\n" );
397 s
= s
+ sprintf ( s
, "{\n" );
398 s
= s
+ sprintf ( s
, " printf(Buffer);\n" );
399 s
= s
+ sprintf ( s
, "}\n" );
400 s
= s
+ sprintf ( s
, "\n" );
401 s
= s
+ sprintf ( s
, "int\n" );
402 s
= s
+ sprintf ( s
, "STDCALL\n" );
403 s
= s
+ sprintf ( s
, "WinMain(HINSTANCE hInstance,\n" );
404 s
= s
+ sprintf ( s
, " HINSTANCE hPrevInstance,\n" );
405 s
= s
+ sprintf ( s
, " LPSTR lpszCmdParam,\n" );
406 s
= s
+ sprintf ( s
, " int nCmdShow)\n" );
407 s
= s
+ sprintf ( s
, "{\n" );
408 s
= s
+ sprintf ( s
, " _SetPriorityClass(_GetCurrentProcess(), HIGH_PRIORITY_CLASS);\n" );
409 s
= s
+ sprintf ( s
, " _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);\n" );
410 s
= s
+ sprintf ( s
, " InitializeTests();\n" );
411 s
= s
+ sprintf ( s
, " RegisterTests();\n" );
412 s
= s
+ sprintf ( s
, " SetupOnce();\n" );
413 s
= s
+ sprintf ( s
, " PerformTests(ConsoleWrite, NULL);\n" );
414 s
= s
+ sprintf ( s
, " _ExitProcess(0);\n" );
415 s
= s
+ sprintf ( s
, " return 0;\n" );
416 s
= s
+ sprintf ( s
, "}\n" );
417 s
= s
+ sprintf ( s
, "\n" );
419 FileSupportCode::WriteIfChanged ( buf
, GetStartupFilename ( module
) );