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.
27 GetFilename ( const std::string
& filename
)
29 size_t index
= filename
.find_last_of ( cSep
);
30 if ( index
== string::npos
)
33 return filename
.substr ( index
+ 1, filename
.length () - index
);
36 TestSupportCode::TestSupportCode ( const Project
& project
)
41 TestSupportCode::~TestSupportCode ()
46 TestSupportCode::IsTestModule ( const Module
& module
)
48 return module
.type
== Test
;
52 TestSupportCode::GenerateTestSupportCode ( bool verbose
)
54 for ( size_t i
= 0; i
< project
.modules
.size (); i
++ )
56 if ( IsTestModule ( *project
.modules
[i
] ) )
58 GenerateTestSupportCodeForModule ( *project
.modules
[i
],
65 TestSupportCode::GenerateTestSupportCodeForModule ( Module
& module
,
70 printf ( "\nGenerating test support code for %s",
71 module
.name
.c_str () );
74 WriteHooksFile ( module
);
75 WriteStubsFile ( module
);
76 WriteStartupFile ( module
);
80 TestSupportCode::GetHooksFilename ( Module
& module
)
82 return NormalizeFilename ( Environment::GetIntermediatePath () + sSep
+ module
.output
->relative_path
+ sSep
+ "_hooks.c" );
86 TestSupportCode::WriteStubbedSymbolToHooksFile ( char* buffer
,
87 const StubbedComponent
& component
,
88 const StubbedSymbol
& symbol
)
90 buffer
= buffer
+ sprintf ( buffer
,
91 " {\"%s\", \"%s\", NULL, NULL, NULL},\n",
92 component
.name
.c_str (),
93 symbol
.newname
.c_str () );
98 TestSupportCode::WriteStubbedComponentToHooksFile ( char* buffer
,
99 const StubbedComponent
& component
)
101 for ( size_t i
= 0; i
< component
.symbols
.size () ; i
++ )
102 buffer
= WriteStubbedSymbolToHooksFile ( buffer
,
104 *component
.symbols
[i
] );
109 TestSupportCode::WriteHooksFile ( Module
& module
)
114 buf
= (char*) malloc ( 50*1024 );
116 throw OutOfMemoryException ();
119 s
= s
+ sprintf ( s
, "/* This file is automatically generated. */\n" );
120 s
= s
+ sprintf ( s
, "#include <windows.h>\n" );
121 s
= s
+ sprintf ( s
, "#include \"regtests.h\"\n" );
122 s
= s
+ sprintf ( s
, "\n" );
123 s
= s
+ sprintf ( s
, "_API_DESCRIPTION ExternalDependencies[] =\n" );
124 s
= s
+ sprintf ( s
, "{\n" );
127 for ( size_t i
= 0; i
< module
.stubbedComponents
.size () ; i
++ )
129 s
= WriteStubbedComponentToHooksFile ( s
,
130 *module
.stubbedComponents
[i
] );
131 symbolCount
+= module
.stubbedComponents
[i
]->symbols
.size ();
134 s
= s
+ sprintf ( s
, "};\n" );
135 s
= s
+ sprintf ( s
, "\n" );
136 s
= s
+ sprintf ( s
, "#define ExternalDependencyCount %d\n", symbolCount
);
137 s
= s
+ sprintf ( s
, "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n" );
138 s
= s
+ sprintf ( s
, "\n" );
140 FileSupportCode::WriteIfChanged ( buf
, GetHooksFilename ( module
) );
146 TestSupportCode::GetStubsFilename ( Module
& module
)
148 return NormalizeFilename ( Environment::GetIntermediatePath () + sSep
+ module
.output
->relative_path
+ sSep
+ "_stubs.S" );
152 GetLinkerSymbol ( const StubbedSymbol
& symbol
)
154 if (symbol
.symbol
[0] == '@')
155 return symbol
.symbol
;
157 return "_" + symbol
.symbol
;
161 GetLinkerImportSymbol ( const StubbedSymbol
& symbol
)
163 if (symbol
.symbol
[0] == '@')
164 return "__imp_" + symbol
.symbol
;
166 return "__imp__" + symbol
.symbol
;
170 GetIndirectCallTargetSymbol ( const StubbedSymbol
& symbol
)
172 return GetLinkerSymbol ( symbol
) + "_";
176 TestSupportCode::WriteStubbedSymbolToStubsFile ( char* buffer
,
177 const StubbedComponent
& component
,
178 const StubbedSymbol
& symbol
,
181 string linkerSymbol
= GetLinkerSymbol ( symbol
);
182 string linkerImportSymbol
= GetLinkerImportSymbol ( symbol
);
183 string indirectCallTargetSymbol
= GetIndirectCallTargetSymbol ( symbol
);
184 buffer
= buffer
+ sprintf ( buffer
,
186 linkerSymbol
.c_str () );
187 buffer
= buffer
+ sprintf ( buffer
,
189 linkerImportSymbol
.c_str () );
190 buffer
= buffer
+ sprintf ( buffer
,
192 linkerSymbol
.c_str () );
193 buffer
= buffer
+ sprintf ( buffer
,
195 linkerImportSymbol
.c_str () );
196 buffer
= buffer
+ sprintf ( buffer
,
198 indirectCallTargetSymbol
.c_str () );
199 buffer
= buffer
+ sprintf ( buffer
,
201 indirectCallTargetSymbol
.c_str () );
202 buffer
= buffer
+ sprintf ( buffer
,
205 buffer
= buffer
+ sprintf ( buffer
,
206 " jmp passthrough\n" );
207 buffer
= buffer
+ sprintf ( buffer
, "\n" );
212 TestSupportCode::WriteStubbedComponentToStubsFile ( char* buffer
,
213 const StubbedComponent
& component
,
216 for ( size_t i
= 0; i
< component
.symbols
.size () ; i
++ )
217 buffer
= WriteStubbedSymbolToStubsFile ( buffer
,
219 *component
.symbols
[i
],
225 TestSupportCode::WriteStubsFile ( Module
& module
)
230 buf
= (char*) malloc ( 512*1024 );
232 throw OutOfMemoryException ();
235 s
= s
+ sprintf ( s
, "/* This file is automatically generated. */\n" );
236 s
= s
+ sprintf ( s
, "passthrough:\n" );
237 s
= s
+ sprintf ( s
, " call _FrameworkGetHook@4\n" );
238 s
= s
+ sprintf ( s
, " test %%eax, %%eax\n" );
239 s
= s
+ sprintf ( s
, " je .return\n" );
240 s
= s
+ sprintf ( s
, " jmp *%%eax\n" );
241 s
= s
+ sprintf ( s
, ".return:\n" );
242 s
= s
+ sprintf ( s
, " /* This will most likely corrupt the stack */\n" );
243 s
= s
+ sprintf ( s
, " ret\n" );
244 s
= s
+ sprintf ( s
, "\n" );
247 for ( size_t i
= 0; i
< module
.stubbedComponents
.size () ; i
++ )
249 s
= WriteStubbedComponentToStubsFile ( s
,
250 *module
.stubbedComponents
[i
],
254 FileSupportCode::WriteIfChanged ( buf
, GetStubsFilename ( module
) );
260 TestSupportCode::GetStartupFilename ( Module
& module
)
262 return NormalizeFilename ( Environment::GetIntermediatePath () + sSep
+ module
.output
->relative_path
+ sSep
+ "_startup.c" );
266 TestSupportCode::IsUnknownCharacter ( char ch
)
268 if ( ch
>= 'a' && ch
<= 'z' )
270 if ( ch
>= 'A' && ch
<= 'Z' )
272 if ( ch
>= '0' && ch
<= '9' )
278 TestSupportCode::GetTestDispatcherName ( string filename
)
280 string filenamePart
= ReplaceExtension ( GetFilename ( filename
), "" );
281 if ( filenamePart
.length () > 0 )
282 filenamePart
[0] = toupper ( filenamePart
[0] );
283 for ( size_t i
= 1; i
< filenamePart
.length (); i
++ )
285 if ( IsUnknownCharacter ( filenamePart
[i
] ) )
286 filenamePart
[i
] = '_';
288 filenamePart
[i
] = tolower ( filenamePart
[i
] );
290 return filenamePart
+ "Test";
294 TestSupportCode::IsTestFile ( string
& filename
) const
296 if ( stricmp ( GetFilename ( filename
).c_str (), "setup.c" ) == 0 )
302 TestSupportCode::GetSourceFilenames ( string_list
& list
,
303 Module
& module
) const
307 const vector
<CompilationUnit
*>& compilationUnits
= module
.non_if_data
.compilationUnits
;
308 for ( i
= 0; i
< compilationUnits
.size (); i
++ )
310 const FileLocation
& sourceFileLocation
= compilationUnits
[i
]->GetFilename ();
311 string filename
= sourceFileLocation
.relative_path
+ sSep
+ sourceFileLocation
.name
;
312 if ( !compilationUnits
[i
]->IsGeneratedFile () && IsTestFile ( filename
) )
313 list
.push_back ( filename
);
315 // intentionally make a copy so that we can append more work in
316 // the middle of processing without having to go recursive
317 vector
<If
*> v
= module
.non_if_data
.ifs
;
318 for ( i
= 0; i
< v
.size (); i
++ )
322 // check for sub-ifs to add to list
323 const vector
<If
*>& ifs
= rIf
.data
.ifs
;
324 for ( j
= 0; j
< ifs
.size (); j
++ )
325 v
.push_back ( ifs
[j
] );
326 const vector
<CompilationUnit
*>& compilationUnits
= rIf
.data
.compilationUnits
;
327 for ( j
= 0; j
< compilationUnits
.size (); j
++ )
329 CompilationUnit
& compilationUnit
= *compilationUnits
[j
];
330 const FileLocation
& sourceFileLocation
= compilationUnits
[j
]->GetFilename ();
331 string filename
= sourceFileLocation
.relative_path
+ sSep
+ sourceFileLocation
.name
;
332 if ( !compilationUnit
.IsGeneratedFile () && IsTestFile ( filename
) )
333 list
.push_back ( filename
);
339 TestSupportCode::WriteTestDispatcherPrototypesToStartupFile ( char* buffer
,
343 GetSourceFilenames ( files
,
345 for ( size_t i
= 0; i
< files
.size (); i
++ )
347 buffer
= buffer
+ sprintf ( buffer
,
348 "extern void %s(int Command, char *Buffer);\n",
349 GetTestDispatcherName ( files
[i
] ).c_str () );
351 buffer
= buffer
+ sprintf ( buffer
, "\n" );
356 TestSupportCode::WriteRegisterTestsFunctionToStartupFile ( char* buffer
,
359 buffer
= buffer
+ sprintf ( buffer
,
360 "extern void AddTest(TestRoutine Routine);\n" );
361 buffer
= buffer
+ sprintf ( buffer
,
364 buffer
= buffer
+ sprintf ( buffer
,
366 buffer
= buffer
+ sprintf ( buffer
,
367 "RegisterTests()\n" );
368 buffer
= buffer
+ sprintf ( buffer
,
372 GetSourceFilenames ( files
,
374 for ( size_t i
= 0; i
< files
.size (); i
++ )
376 buffer
= buffer
+ sprintf ( buffer
,
377 "AddTest((TestRoutine)%s);\n",
378 GetTestDispatcherName ( files
[i
]).c_str () );
380 buffer
= buffer
+ sprintf ( buffer
,
382 buffer
= buffer
+ sprintf ( buffer
, "\n" );
387 TestSupportCode::WriteStartupFile ( Module
& module
)
392 buf
= (char*) malloc ( 50*1024 );
394 throw OutOfMemoryException ();
397 s
= s
+ sprintf ( s
, "/* This file is automatically generated. */\n" );
398 s
= s
+ sprintf ( s
, "\n" );
399 s
= s
+ sprintf ( s
, "#include <windows.h>\n" );
400 s
= s
+ sprintf ( s
, "#include \"regtests.h\"\n" );
401 s
= s
+ sprintf ( s
, "\n" );
402 s
= WriteTestDispatcherPrototypesToStartupFile ( s
,
404 s
= WriteRegisterTestsFunctionToStartupFile ( s
,
406 s
= s
+ sprintf ( s
, "\n" );
407 s
= s
+ sprintf ( s
, "void\n" );
408 s
= s
+ sprintf ( s
, "ConsoleWrite(char *Buffer)\n" );
409 s
= s
+ sprintf ( s
, "{\n" );
410 s
= s
+ sprintf ( s
, " printf(Buffer);\n" );
411 s
= s
+ sprintf ( s
, "}\n" );
412 s
= s
+ sprintf ( s
, "\n" );
413 s
= s
+ sprintf ( s
, "int\n" );
414 s
= s
+ sprintf ( s
, "STDCALL\n" );
415 s
= s
+ sprintf ( s
, "WinMain(HINSTANCE hInstance,\n" );
416 s
= s
+ sprintf ( s
, " HINSTANCE hPrevInstance,\n" );
417 s
= s
+ sprintf ( s
, " LPSTR lpszCmdParam,\n" );
418 s
= s
+ sprintf ( s
, " int nCmdShow)\n" );
419 s
= s
+ sprintf ( s
, "{\n" );
420 s
= s
+ sprintf ( s
, " _SetPriorityClass(_GetCurrentProcess(), HIGH_PRIORITY_CLASS);\n" );
421 s
= s
+ sprintf ( s
, " _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);\n" );
422 s
= s
+ sprintf ( s
, " InitializeTests();\n" );
423 s
= s
+ sprintf ( s
, " RegisterTests();\n" );
424 s
= s
+ sprintf ( s
, " SetupOnce();\n" );
425 s
= s
+ sprintf ( s
, " PerformTests(ConsoleWrite, NULL);\n" );
426 s
= s
+ sprintf ( s
, " _ExitProcess(0);\n" );
427 s
= s
+ sprintf ( s
, " return 0;\n" );
428 s
= s
+ sprintf ( s
, "}\n" );
429 s
= s
+ sprintf ( s
, "\n" );
431 FileSupportCode::WriteIfChanged ( buf
, GetStartupFilename ( module
) );