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 GetImportSymbol ( const StubbedSymbol
& symbol
)
144 if (symbol
.symbol
[0] == '@')
145 return "__imp_" + symbol
.symbol
;
147 return "__imp__" + symbol
.symbol
;
151 TestSupportCode::WriteStubbedSymbolToStubsFile ( char* buffer
,
152 const StubbedComponent
& component
,
153 const StubbedSymbol
& symbol
,
156 string importSymbol
= GetImportSymbol( symbol
);
157 buffer
= buffer
+ sprintf ( buffer
,
159 symbol
.symbol
.c_str () );
160 buffer
= buffer
+ sprintf ( buffer
,
162 importSymbol
.c_str () );
163 buffer
= buffer
+ sprintf ( buffer
,
165 symbol
.symbol
.c_str () );
166 buffer
= buffer
+ sprintf ( buffer
,
168 importSymbol
.c_str () );
169 buffer
= buffer
+ sprintf ( buffer
,
172 buffer
= buffer
+ sprintf ( buffer
,
173 " jmp passthrough\n" );
174 buffer
= buffer
+ sprintf ( buffer
, "\n" );
179 TestSupportCode::WriteStubbedComponentToStubsFile ( char* buffer
,
180 const StubbedComponent
& component
,
183 for ( size_t i
= 0; i
< component
.symbols
.size () ; i
++ )
184 buffer
= WriteStubbedSymbolToStubsFile ( buffer
,
186 *component
.symbols
[i
],
192 TestSupportCode::WriteStubsFile ( Module
& module
)
197 buf
= (char*) malloc ( 50*1024 );
199 throw OutOfMemoryException ();
202 s
= s
+ sprintf ( s
, "/* This file is automatically generated. */\n" );
203 s
= s
+ sprintf ( s
, "passthrough:\n" );
204 s
= s
+ sprintf ( s
, " call _FrameworkGetHook@4\n" );
205 s
= s
+ sprintf ( s
, " test %%eax, %%eax\n" );
206 s
= s
+ sprintf ( s
, " je .return\n" );
207 s
= s
+ sprintf ( s
, " jmp *%%eax\n" );
208 s
= s
+ sprintf ( s
, ".return:\n" );
209 s
= s
+ sprintf ( s
, " /* This will most likely corrupt the stack */\n" );
210 s
= s
+ sprintf ( s
, " ret\n" );
211 s
= s
+ sprintf ( s
, "\n" );
214 for ( size_t i
= 0; i
< module
.stubbedComponents
.size () ; i
++ )
216 s
= WriteStubbedComponentToStubsFile ( s
,
217 *module
.stubbedComponents
[i
],
221 FileSupportCode::WriteIfChanged ( buf
, GetStubsFilename ( module
) );
227 TestSupportCode::GetStartupFilename ( Module
& module
)
229 return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP
+ module
.GetBasePath () + SSEP
+ "_startup.c" );
233 TestSupportCode::IsUnknownCharacter ( char ch
)
235 if ( ch
>= 'a' && ch
<= 'z' )
237 if ( ch
>= 'A' && ch
<= 'Z' )
239 if ( ch
>= '0' && ch
<= '9' )
245 TestSupportCode::GetTestDispatcherName ( string filename
)
247 string filenamePart
= ReplaceExtension ( GetFilename ( filename
), "" );
248 if ( filenamePart
.length () > 0 )
249 filenamePart
[0] = toupper ( filenamePart
[0] );
250 for ( size_t i
= 1; i
< filenamePart
.length (); i
++ )
252 if ( IsUnknownCharacter ( filenamePart
[i
] ) )
253 filenamePart
[i
] = '_';
255 filenamePart
[i
] = tolower ( filenamePart
[i
] );
257 return filenamePart
+ "Test";
261 TestSupportCode::IsTestFile ( string
& filename
) const
263 if ( stricmp ( GetFilename ( filename
).c_str (), "setup.c" ) == 0 )
269 TestSupportCode::GetSourceFilenames ( string_list
& list
,
270 Module
& module
) const
274 const vector
<File
*>& files
= module
.non_if_data
.files
;
275 for ( i
= 0; i
< files
.size (); i
++ )
277 if ( !files
[i
]->IsGeneratedFile () && IsTestFile ( files
[i
]->name
) )
278 list
.push_back ( files
[i
]->name
);
280 // intentionally make a copy so that we can append more work in
281 // the middle of processing without having to go recursive
282 vector
<If
*> v
= module
.non_if_data
.ifs
;
283 for ( i
= 0; i
< v
.size (); i
++ )
287 // check for sub-ifs to add to list
288 const vector
<If
*>& ifs
= rIf
.data
.ifs
;
289 for ( j
= 0; j
< ifs
.size (); j
++ )
290 v
.push_back ( ifs
[j
] );
291 const vector
<File
*>& files
= rIf
.data
.files
;
292 for ( j
= 0; j
< files
.size (); j
++ )
294 File
& file
= *files
[j
];
295 if ( !file
.IsGeneratedFile () && IsTestFile ( file
.name
) )
297 list
.push_back ( file
.name
);
304 TestSupportCode::WriteTestDispatcherPrototypesToStartupFile ( char* buffer
,
308 GetSourceFilenames ( files
,
310 for ( size_t i
= 0; i
< files
.size (); i
++ )
312 buffer
= buffer
+ sprintf ( buffer
,
313 "extern void %s(int Command, char *Buffer);\n",
314 GetTestDispatcherName ( files
[i
] ).c_str () );
316 buffer
= buffer
+ sprintf ( buffer
, "\n" );
321 TestSupportCode::WriteRegisterTestsFunctionToStartupFile ( char* buffer
,
324 buffer
= buffer
+ sprintf ( buffer
,
325 "extern void AddTest(TestRoutine Routine);\n" );
326 buffer
= buffer
+ sprintf ( buffer
,
329 buffer
= buffer
+ sprintf ( buffer
,
331 buffer
= buffer
+ sprintf ( buffer
,
332 "RegisterTests()\n" );
333 buffer
= buffer
+ sprintf ( buffer
,
337 GetSourceFilenames ( files
,
339 for ( size_t i
= 0; i
< files
.size (); i
++ )
341 buffer
= buffer
+ sprintf ( buffer
,
342 "AddTest((TestRoutine)%s);\n",
343 GetTestDispatcherName ( files
[i
]).c_str () );
345 buffer
= buffer
+ sprintf ( buffer
,
347 buffer
= buffer
+ sprintf ( buffer
, "\n" );
352 TestSupportCode::WriteStartupFile ( Module
& module
)
357 buf
= (char*) malloc ( 50*1024 );
359 throw OutOfMemoryException ();
362 s
= s
+ sprintf ( s
, "/* This file is automatically generated. */\n" );
363 s
= s
+ sprintf ( s
, "\n" );
364 s
= s
+ sprintf ( s
, "#include <windows.h>\n" );
365 s
= s
+ sprintf ( s
, "#include \"regtests.h\"\n" );
366 s
= s
+ sprintf ( s
, "\n" );
367 s
= WriteTestDispatcherPrototypesToStartupFile ( s
,
369 s
= WriteRegisterTestsFunctionToStartupFile ( s
,
371 s
= s
+ sprintf ( s
, "\n" );
372 s
= s
+ sprintf ( s
, "void\n" );
373 s
= s
+ sprintf ( s
, "ConsoleWrite(char *Buffer)\n" );
374 s
= s
+ sprintf ( s
, "{\n" );
375 s
= s
+ sprintf ( s
, " printf(Buffer);\n" );
376 s
= s
+ sprintf ( s
, "}\n" );
377 s
= s
+ sprintf ( s
, "\n" );
378 s
= s
+ sprintf ( s
, "int\n" );
379 s
= s
+ sprintf ( s
, "STDCALL\n" );
380 s
= s
+ sprintf ( s
, "WinMain(HINSTANCE hInstance,\n" );
381 s
= s
+ sprintf ( s
, " HINSTANCE hPrevInstance,\n" );
382 s
= s
+ sprintf ( s
, " LPSTR lpszCmdParam,\n" );
383 s
= s
+ sprintf ( s
, " int nCmdShow)\n" );
384 s
= s
+ sprintf ( s
, "{\n" );
385 s
= s
+ sprintf ( s
, " _SetPriorityClass(_GetCurrentProcess(), HIGH_PRIORITY_CLASS);\n" );
386 s
= s
+ sprintf ( s
, " _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);\n" );
387 s
= s
+ sprintf ( s
, " InitializeTests();\n" );
388 s
= s
+ sprintf ( s
, " RegisterTests();\n" );
389 s
= s
+ sprintf ( s
, " SetupOnce();\n" );
390 s
= s
+ sprintf ( s
, " PerformTests(ConsoleWrite, NULL);\n" );
391 s
= s
+ sprintf ( s
, " _ExitProcess(0);\n" );
392 s
= s
+ sprintf ( s
, " return 0;\n" );
393 s
= s
+ sprintf ( s
, "}\n" );
394 s
= s
+ sprintf ( s
, "\n" );
396 FileSupportCode::WriteIfChanged ( buf
, GetStartupFilename ( module
) );