e238e0eaab03b8ee4754e431900a6f6173f35ff0
[reactos.git] / reactos / tools / rbuild / testsupportcode.cpp
1 #include "pch.h"
2 #include <assert.h>
3
4 #include "rbuild.h"
5
6 using std::string;
7 using std::vector;
8
9 TestSupportCode::TestSupportCode ( const Project& project )
10 : project ( project )
11 {
12 }
13
14 TestSupportCode::~TestSupportCode ()
15 {
16 }
17
18 bool
19 TestSupportCode::IsTestModule ( const Module& module )
20 {
21 return module.type == Test;
22 }
23
24 void
25 TestSupportCode::GenerateTestSupportCode ( bool verbose )
26 {
27 for ( size_t i = 0; i < project.modules.size (); i++ )
28 {
29 if ( IsTestModule ( *project.modules[i] ) )
30 {
31 GenerateTestSupportCodeForModule ( *project.modules[i],
32 verbose );
33 }
34 }
35 }
36
37 void
38 TestSupportCode::GenerateTestSupportCodeForModule ( Module& module,
39 bool verbose )
40 {
41 if ( verbose )
42 {
43 printf ( "\nGenerating test support code for %s",
44 module.name.c_str () );
45 }
46
47 WriteHooksFile ( module );
48 WriteStubsFile ( module );
49 WriteStartupFile ( module );
50 }
51
52 string
53 TestSupportCode::GetHooksFilename ( Module& module )
54 {
55 return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP + module.GetBasePath () + SSEP + "_hooks.c" );
56 }
57
58 char*
59 TestSupportCode::WriteStubbedSymbolToHooksFile ( char* buffer,
60 const StubbedComponent& component,
61 const StubbedSymbol& symbol )
62 {
63 buffer = buffer + sprintf ( buffer,
64 " {\"%s\", \"%s\", NULL, NULL, NULL},\n",
65 component.name.c_str (),
66 symbol.newname.c_str () );
67 return buffer;
68 }
69
70 char*
71 TestSupportCode::WriteStubbedComponentToHooksFile ( char* buffer,
72 const StubbedComponent& component )
73 {
74 for ( size_t i = 0; i < component.symbols.size () ; i++ )
75 buffer = WriteStubbedSymbolToHooksFile ( buffer,
76 component,
77 *component.symbols[i] );
78 return buffer;
79 }
80
81 void
82 TestSupportCode::WriteHooksFile ( Module& module )
83 {
84 char* buf;
85 char* s;
86
87 buf = (char*) malloc ( 50*1024 );
88 if ( buf == NULL )
89 throw OutOfMemoryException ();
90
91 s = buf;
92 s = s + sprintf ( s, "/* This file is automatically generated. */\n" );
93 s = s + sprintf ( s, "#include <windows.h>\n" );
94 s = s + sprintf ( s, "#include \"regtests.h\"\n" );
95 s = s + sprintf ( s, "\n" );
96 s = s + sprintf ( s, "_API_DESCRIPTION ExternalDependencies[] =\n" );
97 s = s + sprintf ( s, "{\n" );
98
99 int symbolCount = 0;
100 for ( size_t i = 0; i < module.stubbedComponents.size () ; i++ )
101 {
102 s = WriteStubbedComponentToHooksFile ( s,
103 *module.stubbedComponents[i] );
104 symbolCount += module.stubbedComponents[i]->symbols.size ();
105 }
106
107 s = s + sprintf ( s, "};\n" );
108 s = s + sprintf ( s, "\n" );
109 s = s + sprintf ( s, "#define ExternalDependencyCount %d\n", symbolCount );
110 s = s + sprintf ( s, "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n" );
111 s = s + sprintf ( s, "\n" );
112
113 FileSupportCode::WriteIfChanged ( buf, GetHooksFilename ( module ) );
114
115 free ( buf );
116 }
117
118 string
119 TestSupportCode::GetStubsFilename ( Module& module )
120 {
121 return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP + module.GetBasePath () + SSEP + "_stubs.S" );
122 }
123
124 string
125 GetImportSymbol ( const StubbedSymbol& symbol )
126 {
127 if (symbol.symbol[0] == '@')
128 return "__imp_" + symbol.symbol;
129 else
130 return "__imp__" + symbol.symbol;
131 }
132
133 char*
134 TestSupportCode::WriteStubbedSymbolToStubsFile ( char* buffer,
135 const StubbedComponent& component,
136 const StubbedSymbol& symbol,
137 int stubIndex )
138 {
139 string importSymbol = GetImportSymbol( symbol );
140 buffer = buffer + sprintf ( buffer,
141 ".globl _%s\n",
142 symbol.symbol.c_str () );
143 buffer = buffer + sprintf ( buffer,
144 ".globl %s\n",
145 importSymbol.c_str () );
146 buffer = buffer + sprintf ( buffer,
147 "_%s:\n",
148 symbol.symbol.c_str () );
149 buffer = buffer + sprintf ( buffer,
150 "%s:\n",
151 importSymbol.c_str () );
152 buffer = buffer + sprintf ( buffer,
153 " pushl $%d\n",
154 stubIndex );
155 buffer = buffer + sprintf ( buffer,
156 " jmp passthrough\n" );
157 buffer = buffer + sprintf ( buffer, "\n" );
158 return buffer;
159 }
160
161 char*
162 TestSupportCode::WriteStubbedComponentToStubsFile ( char* buffer,
163 const StubbedComponent& component,
164 int* stubIndex )
165 {
166 for ( size_t i = 0; i < component.symbols.size () ; i++ )
167 buffer = WriteStubbedSymbolToStubsFile ( buffer,
168 component,
169 *component.symbols[i],
170 (*stubIndex)++ );
171 return buffer;
172 }
173
174 void
175 TestSupportCode::WriteStubsFile ( Module& module )
176 {
177 char* buf;
178 char* s;
179
180 buf = (char*) malloc ( 50*1024 );
181 if ( buf == NULL )
182 throw OutOfMemoryException ();
183
184 s = buf;
185 s = s + sprintf ( s, "/* This file is automatically generated. */\n" );
186 s = s + sprintf ( s, "passthrough:\n" );
187 s = s + sprintf ( s, " call _FrameworkGetHook@4\n" );
188 s = s + sprintf ( s, " test %%eax, %%eax\n" );
189 s = s + sprintf ( s, " je .return\n" );
190 s = s + sprintf ( s, " jmp *%%eax\n" );
191 s = s + sprintf ( s, ".return:\n" );
192 s = s + sprintf ( s, " /* This will most likely corrupt the stack */\n" );
193 s = s + sprintf ( s, " ret\n" );
194 s = s + sprintf ( s, "\n" );
195
196 int stubIndex = 0;
197 for ( size_t i = 0; i < module.stubbedComponents.size () ; i++ )
198 {
199 s = WriteStubbedComponentToStubsFile ( s,
200 *module.stubbedComponents[i],
201 &stubIndex );
202 }
203
204 FileSupportCode::WriteIfChanged ( buf, GetStubsFilename ( module ) );
205
206 free ( buf );
207 }
208
209 string
210 TestSupportCode::GetStartupFilename ( Module& module )
211 {
212 return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP + module.GetBasePath () + SSEP + "_startup.c" );
213 }
214
215 bool
216 TestSupportCode::IsUnknownCharacter ( char ch )
217 {
218 if ( ch >= 'a' && ch <= 'z' )
219 return false;
220 if ( ch >= 'A' && ch <= 'Z' )
221 return false;
222 if ( ch >= '0' && ch <= '9' )
223 return false;
224 return true;
225 }
226
227 string
228 TestSupportCode::GetTestDispatcherName ( string filename )
229 {
230 string filenamePart = ReplaceExtension ( GetFilename ( filename ), "" );
231 if ( filenamePart.length () > 0 )
232 filenamePart[0] = toupper ( filenamePart[0] );
233 for ( size_t i = 1; i < filenamePart.length (); i++ )
234 {
235 if ( IsUnknownCharacter ( filenamePart[i] ) )
236 filenamePart[i] = '_';
237 else
238 filenamePart[i] = tolower ( filenamePart[i] );
239 }
240 return filenamePart + "Test";
241 }
242
243 bool
244 TestSupportCode::IsTestFile ( string& filename ) const
245 {
246 if ( stricmp ( GetFilename ( filename ).c_str (), "setup.c" ) == 0 )
247 return false;
248 return true;
249 }
250
251 void
252 TestSupportCode::GetSourceFilenames ( string_list& list,
253 Module& module ) const
254 {
255 size_t i;
256
257 const vector<File*>& files = module.non_if_data.files;
258 for ( i = 0; i < files.size (); i++ )
259 {
260 if ( !files[i]->IsGeneratedFile () && IsTestFile ( files[i]->name ) )
261 list.push_back ( files[i]->name );
262 }
263 // intentionally make a copy so that we can append more work in
264 // the middle of processing without having to go recursive
265 vector<If*> v = module.non_if_data.ifs;
266 for ( i = 0; i < v.size (); i++ )
267 {
268 size_t j;
269 If& rIf = *v[i];
270 // check for sub-ifs to add to list
271 const vector<If*>& ifs = rIf.data.ifs;
272 for ( j = 0; j < ifs.size (); j++ )
273 v.push_back ( ifs[j] );
274 const vector<File*>& files = rIf.data.files;
275 for ( j = 0; j < files.size (); j++ )
276 {
277 File& file = *files[j];
278 if ( !file.IsGeneratedFile () && IsTestFile ( file.name ) )
279 {
280 list.push_back ( file.name );
281 }
282 }
283 }
284 }
285
286 char*
287 TestSupportCode::WriteTestDispatcherPrototypesToStartupFile ( char* buffer,
288 Module& module )
289 {
290 string_list files;
291 GetSourceFilenames ( files,
292 module );
293 for ( size_t i = 0; i < files.size (); i++ )
294 {
295 buffer = buffer + sprintf ( buffer,
296 "extern void %s(int Command, char *Buffer);\n",
297 GetTestDispatcherName ( files[i] ).c_str () );
298 }
299 buffer = buffer + sprintf ( buffer, "\n" );
300 return buffer;
301 }
302
303 char*
304 TestSupportCode::WriteRegisterTestsFunctionToStartupFile ( char* buffer,
305 Module& module )
306 {
307 buffer = buffer + sprintf ( buffer,
308 "extern void AddTest(TestRoutine Routine);\n" );
309 buffer = buffer + sprintf ( buffer,
310 "\n" );
311
312 buffer = buffer + sprintf ( buffer,
313 "void\n" );
314 buffer = buffer + sprintf ( buffer,
315 "RegisterTests()\n" );
316 buffer = buffer + sprintf ( buffer,
317 "{\n" );
318
319 string_list files;
320 GetSourceFilenames ( files,
321 module );
322 for ( size_t i = 0; i < files.size (); i++ )
323 {
324 buffer = buffer + sprintf ( buffer,
325 "AddTest((TestRoutine)%s);\n",
326 GetTestDispatcherName ( files[i]).c_str () );
327 }
328 buffer = buffer + sprintf ( buffer,
329 "}\n" );
330 buffer = buffer + sprintf ( buffer, "\n" );
331 return buffer;
332 }
333
334 void
335 TestSupportCode::WriteStartupFile ( Module& module )
336 {
337 char* buf;
338 char* s;
339
340 buf = (char*) malloc ( 50*1024 );
341 if ( buf == NULL )
342 throw OutOfMemoryException ();
343
344 s = buf;
345 s = s + sprintf ( s, "/* This file is automatically generated. */\n" );
346 s = s + sprintf ( s, "\n" );
347 s = s + sprintf ( s, "#include <windows.h>\n" );
348 s = s + sprintf ( s, "#include \"regtests.h\"\n" );
349 s = s + sprintf ( s, "\n" );
350 s = WriteTestDispatcherPrototypesToStartupFile ( s,
351 module );
352 s = WriteRegisterTestsFunctionToStartupFile ( s,
353 module );
354 s = s + sprintf ( s, "\n" );
355 s = s + sprintf ( s, "void\n" );
356 s = s + sprintf ( s, "ConsoleWrite(char *Buffer)\n" );
357 s = s + sprintf ( s, "{\n" );
358 s = s + sprintf ( s, " printf(Buffer);\n" );
359 s = s + sprintf ( s, "}\n" );
360 s = s + sprintf ( s, "\n" );
361 s = s + sprintf ( s, "int\n" );
362 s = s + sprintf ( s, "mainCRTStartup(HANDLE hInstance,\n" );
363 s = s + sprintf ( s, " HANDLE hPrevInstance,\n" );
364 s = s + sprintf ( s, " LPSTR lpszCmdParam,\n" );
365 s = s + sprintf ( s, " int nCmdShow)\n" );
366 s = s + sprintf ( s, "{\n" );
367 s = s + sprintf ( s, " _SetPriorityClass(_GetCurrentProcess(), HIGH_PRIORITY_CLASS);\n" );
368 s = s + sprintf ( s, " _SetThreadPriority(_GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);\n" );
369 s = s + sprintf ( s, " InitializeTests();\n" );
370 s = s + sprintf ( s, " RegisterTests();\n" );
371 s = s + sprintf ( s, " SetupOnce();\n" );
372 s = s + sprintf ( s, " PerformTests(ConsoleWrite, NULL);\n" );
373 s = s + sprintf ( s, " _ExitProcess(0);\n" );
374 s = s + sprintf ( s, " return 0;\n" );
375 s = s + sprintf ( s, "}\n" );
376 s = s + sprintf ( s, "\n" );
377
378 FileSupportCode::WriteIfChanged ( buf, GetStartupFilename ( module ) );
379
380 free ( buf );
381 }