31c984c536ba5c0dfb1458d040a2ba238f5ee17c
[reactos.git] / rostests / rosautotest / main.c
1 /*
2 * PROJECT: ReactOS Automatic Testing Utility
3 * LICENSE: GNU GPLv2 or any later version as published by the Free Software Foundation
4 * PURPOSE: Main implementation file
5 * COPYRIGHT: Copyright 2008-2009 Colin Finck <colin@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 typedef void (WINAPI *GETSYSINFO)(LPSYSTEM_INFO);
11
12 APP_OPTIONS AppOptions = {0};
13 HANDLE hProcessHeap;
14 PCHAR AuthenticationRequestString = NULL;
15 PCHAR SystemInfoRequestString = NULL;
16
17 /**
18 * Gets a value from a specified INI file and returns it converted to ASCII.
19 *
20 * @param AppName
21 * The INI section to look in (lpAppName parameter passed to GetPrivateProfileStringW)
22 *
23 * @param KeyName
24 * The key to look for in the specified section (lpKeyName parameter passed to GetPrivateProfileStringW)
25 *
26 * @param FileName
27 * The path to the INI file
28 *
29 * @param ReturnedValue
30 * Pointer to a CHAR pointer, which will receive the read and converted value.
31 * The caller needs to HeapFree that value manually.
32 *
33 * @return
34 * Returns the string length of the read value (in characters) or zero if we didn't get any value.
35 */
36 static DWORD
37 IntGetINIValueA(PCWCH AppName, PCWCH KeyName, PCWCH FileName, char** ReturnedValue)
38 {
39 DWORD Length;
40 WCHAR Buffer[2048];
41
42 /* Load the value into a temporary Unicode buffer */
43 Length = GetPrivateProfileStringW(AppName, KeyName, NULL, Buffer, sizeof(Buffer) / sizeof(WCHAR), FileName);
44
45 if(!Length)
46 return 0;
47
48 /* Convert the string to ANSI charset */
49 *ReturnedValue = HeapAlloc(hProcessHeap, 0, Length + 1);
50 WideCharToMultiByte(CP_ACP, 0, Buffer, Length + 1, *ReturnedValue, Length + 1, NULL, NULL);
51
52 return Length;
53 }
54
55 /**
56 * Gets the username and password hash from the "rosautotest.ini" file if the user enabled submitting the results to the web service.
57 * The "rosautotest.ini" file should look like this:
58 *
59 * [Login]
60 * UserName=TestMan
61 * PasswordHash=1234567890abcdef1234567890abcdef
62 */
63 static BOOL
64 IntGetConfigurationValues()
65 {
66 const CHAR PasswordHashProp[] = "&passwordhash=";
67 const CHAR UserNameProp[] = "&username=";
68
69 DWORD DataLength;
70 DWORD Length;
71 PCHAR PasswordHash;
72 PCHAR UserName;
73 WCHAR ConfigFile[MAX_PATH];
74
75 /* We only need this if the results are going to be submitted */
76 if(!AppOptions.Submit)
77 return TRUE;
78
79 /* Build the path to the configuration file */
80 Length = GetWindowsDirectoryW(ConfigFile, MAX_PATH);
81 wcscpy(&ConfigFile[Length], L"\\rosautotest.ini");
82
83 /* Check if it exists */
84 if(GetFileAttributesW(ConfigFile) == INVALID_FILE_ATTRIBUTES)
85 return FALSE;
86
87 /* Get the required length of the authentication request string */
88 DataLength = sizeof(UserNameProp) - 1;
89 Length = IntGetINIValueA(L"Login", L"UserName", ConfigFile, &UserName);
90
91 if(!Length)
92 {
93 StringOut("UserName is missing in the configuration file\n");
94 return FALSE;
95 }
96
97 /* Some characters might need to be escaped and an escaped character takes 3 bytes */
98 DataLength += 3 * Length;
99
100 DataLength += sizeof(PasswordHashProp) - 1;
101 Length = IntGetINIValueA(L"Login", L"PasswordHash", ConfigFile, &PasswordHash);
102
103 if(!Length)
104 {
105 StringOut("PasswordHash is missing in the configuration file\n");
106 return FALSE;
107 }
108
109 DataLength += 3 * Length;
110
111 /* Build the string */
112 AuthenticationRequestString = HeapAlloc(hProcessHeap, 0, DataLength + 1);
113
114 strcpy(AuthenticationRequestString, UserNameProp);
115 EscapeString(&AuthenticationRequestString[strlen(AuthenticationRequestString)], UserName);
116
117 strcat(AuthenticationRequestString, PasswordHashProp);
118 EscapeString(&AuthenticationRequestString[strlen(AuthenticationRequestString)], PasswordHash);
119
120 return TRUE;
121 }
122
123 /**
124 * Determines on which platform we're running on.
125 * Prepares the appropriate request strings needed if we want to submit test results to the web service.
126 */
127 static BOOL
128 IntGetBuildAndPlatform()
129 {
130 const CHAR PlatformProp[] = "&platform=";
131 const CHAR RevisionProp[] = "&revision=";
132
133 CHAR BuildNo[BUILDNO_LENGTH];
134 CHAR Platform[PLATFORM_LENGTH];
135 CHAR PlatformArchitecture[3];
136 CHAR ProductType;
137 DWORD DataLength;
138 GETSYSINFO GetSysInfo;
139 HANDLE hKernel32;
140 OSVERSIONINFOEXW os;
141 SYSTEM_INFO si;
142 WCHAR WindowsDirectory[MAX_PATH];
143
144 /* Get the build from the define */
145 _ultoa(KERNEL_VERSION_BUILD_HEX, BuildNo, 10);
146
147 /* Check if we are running under ReactOS from the SystemRoot directory */
148 GetWindowsDirectoryW(WindowsDirectory, MAX_PATH);
149
150 if(!_wcsnicmp(&WindowsDirectory[3], L"reactos", 7))
151 {
152 /* Yes, we are most-probably under ReactOS */
153 strcpy(Platform, "reactos");
154 }
155 else
156 {
157 /* No, then use the info from GetVersionExW */
158 os.dwOSVersionInfoSize = sizeof(os);
159
160 if(!GetVersionExW((LPOSVERSIONINFOW)&os))
161 {
162 StringOut("GetVersionExW failed\n");
163 return FALSE;
164 }
165
166 if(os.dwMajorVersion < 5)
167 {
168 StringOut("Application requires at least Windows 2000!\n");
169 return FALSE;
170 }
171
172 if(os.wProductType == VER_NT_WORKSTATION)
173 ProductType = 'w';
174 else
175 ProductType = 's';
176
177 /* Print all necessary identification information into the Platform string */
178 sprintf(Platform, "%lu.%lu.%lu.%u.%u.%c", os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber, os.wServicePackMajor, os.wServicePackMinor, ProductType);
179 }
180
181 /* We also need to know about the processor architecture.
182 To retrieve this information accurately, check whether "GetNativeSystemInfo" is exported and use it then, otherwise fall back to "GetSystemInfo". */
183 hKernel32 = GetModuleHandleW(L"KERNEL32.DLL");
184 GetSysInfo = (GETSYSINFO)GetProcAddress(hKernel32, "GetNativeSystemInfo");
185
186 if(!GetSysInfo)
187 GetSysInfo = (GETSYSINFO)GetProcAddress(hKernel32, "GetSystemInfo");
188
189 GetSysInfo(&si);
190
191 PlatformArchitecture[0] = '.';
192 _ultoa(si.wProcessorArchitecture, &PlatformArchitecture[1], 10);
193 PlatformArchitecture[2] = 0;
194 strcat(Platform, PlatformArchitecture);
195
196 /* Get the required length of the system info request string */
197 DataLength = sizeof(RevisionProp) - 1;
198 DataLength += strlen(BuildNo);
199 DataLength += sizeof(PlatformProp) - 1;
200 DataLength += strlen(Platform);
201
202 /* Now build the string */
203 SystemInfoRequestString = HeapAlloc(hProcessHeap, 0, DataLength + 1);
204 strcpy(SystemInfoRequestString, RevisionProp);
205 strcat(SystemInfoRequestString, BuildNo);
206 strcat(SystemInfoRequestString, PlatformProp);
207 strcat(SystemInfoRequestString, Platform);
208
209 return TRUE;
210 }
211
212 /**
213 * Prints the application usage.
214 */
215 static VOID
216 IntPrintUsage()
217 {
218 printf("rosautotest - ReactOS Automatic Testing Utility\n");
219 printf("Usage: rosautotest [options] [module] [test]\n");
220 printf(" options:\n");
221 printf(" /? - Shows this help\n");
222 printf(" /s - Shut down the system after finishing the tests\n");
223 printf(" /w - Submit the results to the webservice\n");
224 printf(" Requires a \"rosautotest.ini\" with valid login data.\n");
225 printf("\n");
226 printf(" module:\n");
227 printf(" The module to be tested (i.e. \"advapi32\")\n");
228 printf(" If this parameter is specified without any test parameter,\n");
229 printf(" all tests of the specified module are run.\n");
230 printf("\n");
231 printf(" test:\n");
232 printf(" The test to be run. Needs to be a test of the specified module.\n");
233 }
234
235 /**
236 * Main entry point
237 */
238 int
239 wmain(int argc, wchar_t* argv[])
240 {
241 int Result = 0;
242 UINT i;
243
244 hProcessHeap = GetProcessHeap();
245
246 /* Parse the command line arguments */
247 for(i = 1; i < (UINT)argc; i++)
248 {
249 if(argv[i][0] == '-' || argv[i][0] == '/')
250 {
251 switch(argv[i][1])
252 {
253 case 's':
254 AppOptions.Shutdown = TRUE;
255 break;
256
257 case 'w':
258 AppOptions.Submit = TRUE;
259 break;
260
261 default:
262 Result = 1;
263 /* Fall through */
264
265 case '?':
266 IntPrintUsage();
267 goto End;
268 }
269 }
270 else
271 {
272 size_t Length;
273
274 /* Which parameter is this? */
275 if(!AppOptions.Module)
276 {
277 /* Copy the parameter */
278 Length = (wcslen(argv[i]) + 1) * sizeof(WCHAR);
279 AppOptions.Module = HeapAlloc(hProcessHeap, 0, Length);
280 memcpy(AppOptions.Module, argv[i], Length);
281 }
282 else if(!AppOptions.Test)
283 {
284 /* Copy the parameter converted to ASCII */
285 Length = WideCharToMultiByte(CP_ACP, 0, argv[i], -1, NULL, 0, NULL, NULL);
286 AppOptions.Test = HeapAlloc(hProcessHeap, 0, Length);
287 WideCharToMultiByte(CP_ACP, 0, argv[i], -1, AppOptions.Test, Length, NULL, NULL);
288 }
289 else
290 {
291 Result = 1;
292 IntPrintUsage();
293 goto End;
294 }
295 }
296 }
297
298 if(!IntGetConfigurationValues() || !IntGetBuildAndPlatform() || !RunWineTests())
299 {
300 Result = 1;
301 goto End;
302 }
303
304 /* For sysreg */
305 OutputDebugStringA("SYSREG_CHECKPOINT:THIRDBOOT_COMPLETE\n");
306
307 End:
308 /* Cleanup */
309 if(AppOptions.Module)
310 HeapFree(hProcessHeap, 0, AppOptions.Module);
311
312 if(AppOptions.Test)
313 HeapFree(hProcessHeap, 0, AppOptions.Test);
314
315 if(AuthenticationRequestString)
316 HeapFree(hProcessHeap, 0, AuthenticationRequestString);
317
318 if(SystemInfoRequestString)
319 HeapFree(hProcessHeap, 0, SystemInfoRequestString);
320
321 /* Shut down the system if requested */
322 if(AppOptions.Shutdown && !ShutdownSystem())
323 Result = 1;
324
325 return Result;
326 }