Time to commit some Work-In-Progress stuff before my diff gets too large..
[reactos.git] / rostests / apitests / ntdll / RtlDosSearchPath_U.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for RtlDosSearchPath_U
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include <apitest.h>
9
10 #define WIN32_NO_STATUS
11 #include <stdio.h>
12 #include <ndk/rtlfuncs.h>
13
14 /*
15 ULONG
16 NTAPI
17 RtlDosSearchPath_U(
18 IN PCWSTR Path,
19 IN PCWSTR FileName,
20 IN PCWSTR Extension,
21 IN ULONG BufferSize,
22 OUT PWSTR Buffer,
23 OUT PWSTR *PartName
24 );
25 */
26
27 #define PrintablePointer(p) ((p) == InvalidPointer ? NULL : (p))
28
29 static
30 BOOLEAN
31 CheckStringBuffer(
32 PCWSTR Buffer,
33 SIZE_T Length,
34 SIZE_T MaximumLength,
35 PCWSTR Expected)
36 {
37 SIZE_T ExpectedLength = wcslen(Expected) * sizeof(WCHAR);
38 SIZE_T EqualLength;
39 BOOLEAN Result = TRUE;
40 SIZE_T i;
41
42 if (Length != ExpectedLength)
43 {
44 ok(0, "String length is %lu, expected %lu\n", (ULONG)Length, (ULONG)ExpectedLength);
45 Result = FALSE;
46 }
47
48 EqualLength = RtlCompareMemory(Buffer, Expected, Length);
49 if (EqualLength != Length)
50 {
51 ok(0, "String is '%S', expected '%S'\n", Buffer, Expected);
52 Result = FALSE;
53 }
54
55 if (Buffer[Length / sizeof(WCHAR)] != UNICODE_NULL)
56 {
57 ok(0, "Not null terminated\n");
58 Result = FALSE;
59 }
60
61 /* the function nulls the rest of the buffer! */
62 for (i = Length + sizeof(UNICODE_NULL); i < MaximumLength; i++)
63 {
64 UCHAR Char = ((PUCHAR)Buffer)[i];
65 if (Char != 0)
66 {
67 ok(0, "Found 0x%x at offset %lu, expected 0x%x\n", Char, (ULONG)i, 0);
68 /* don't count this as a failure unless the string was actually wrong */
69 //Result = FALSE;
70 /* don't flood the log */
71 break;
72 }
73 }
74
75 return Result;
76 }
77
78 static
79 BOOLEAN
80 CheckBuffer(
81 PVOID Buffer,
82 SIZE_T Size,
83 UCHAR Value)
84 {
85 PUCHAR Array = Buffer;
86 SIZE_T i;
87
88 for (i = 0; i < Size; i++)
89 if (Array[i] != Value)
90 {
91 trace("Expected %x, found %x at offset %lu\n", Value, Array[i], (ULONG)i);
92 return FALSE;
93 }
94 return TRUE;
95 }
96
97 static
98 VOID
99 RunTestCases(
100 PCWSTR CustomPath)
101 {
102 struct
103 {
104 PCWSTR SearchPath;
105 PCWSTR FileName;
106 PCWSTR Extension;
107 PCWSTR ResultPath;
108 PCWSTR ResultFileName;
109 } Tests[] =
110 {
111 { L"", L"", NULL, NULL, NULL },
112 { L"C:\\%ls\\Folder1", L"File1", NULL, L"C:\\%ls\\Folder1\\", L"File1" },
113 /* No path: current directory */
114 { L"", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
115 /* Full path as FileName */
116 { L"", L"C:\\", NULL, L"C:\\", NULL },
117 { L"", L"C:\\%ls\\Folder1", NULL, L"C:\\%ls\\", L"Folder1" },
118 /* No FileName */
119 { L"C:\\", L"", NULL, L"C:\\", NULL },
120 { L"C:\\%ls\\Folder1", L"", NULL, L"C:\\%ls\\Folder1\\", NULL },
121 /* Full path as FileName */
122 { L"", L"C:\\%ls\\Folder1\\SomeProgram.exe", NULL, L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
123 { L"", L"C:\\%ls\\Folder1\\SomeProgram.exe", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
124 { L"", L"C:\\%ls\\Folder1\\SomeProgram", NULL, NULL, NULL },
125 // 10
126 { L"", L"C:\\%ls\\Folder1\\SomeProgram", L".exe", NULL, NULL },
127 /* Both SearchPath and FileName */
128 { L"C:\\%ls\\Folder1\\", L"SomeProgram.exe", NULL, L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
129 { L"C:\\%ls\\Folder1\\", L"SomeProgram.exe", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
130 { L"C:\\%ls\\Folder1\\", L"SomeProgram", NULL, NULL, NULL },
131 { L"C:\\%ls\\Folder1\\", L"SomeProgram", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
132 { L"C:\\%ls\\Folder1", L"SomeProgram.exe", NULL, L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
133 { L"C:\\%ls\\Folder1", L"SomeProgram.exe", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
134 { L"C:\\%ls\\Folder1", L"SomeProgram", NULL, NULL, NULL },
135 { L"C:\\%ls\\Folder1", L"SomeProgram", L".exe", L"C:\\%ls\\Folder1\\", L"SomeProgram.exe" },
136 /* Full path to file in SearchPath doesn't work */
137 { L"C:\\%ls\\Folder1\\SomeProgram.exe", L"", NULL, NULL, NULL },
138 // 20
139 { L"C:\\%ls\\Folder1\\SomeProgram.exe", L"", L".exe", NULL, NULL },
140 { L"C:\\%ls\\Folder1\\SomeProgram", L"", NULL, NULL, NULL },
141 { L"C:\\%ls\\Folder1\\SomeProgram", L"", L".exe", NULL, NULL },
142 /* */
143 { L"C:\\%ls\\Folder1", L"File1", NULL, L"C:\\%ls\\Folder1\\", L"File1" },
144 { L"C:\\%ls\\CurrentDirectory", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
145 { L"C:\\%ls\\Folder1 ", L"File1", NULL, NULL, NULL },
146 { L"C:\\%ls\\CurrentDirectory ",L"File1", NULL, NULL, NULL },
147 { L" C:\\%ls\\Folder1", L"File1", NULL, NULL, NULL },
148 { L" C:\\%ls\\CurrentDirectory",L"File1", NULL, NULL, NULL },
149 { L" C:\\%ls\\Folder1 ", L"File1", NULL, NULL, NULL },
150 // 30
151 { L" C:\\%ls\\CurrentDirectory ",L"File1", NULL, NULL, NULL },
152 /* Multiple search paths */
153 { L"C:\\%ls\\Folder1;C:\\%ls\\CurrentDirectory",
154 L"File1", NULL, L"C:\\%ls\\Folder1\\", L"File1" },
155 { L"C:\\%ls\\CurrentDirectory;C:\\%ls\\Folder1",
156 L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
157 { L"C:\\%ls\\CurrentDirectory ; C:\\%ls\\Folder1",
158 L"File1", NULL, NULL, NULL },
159 { L"C:\\%ls\\CurrentDirectory ;C:\\%ls\\Folder1",
160 L"File1", NULL, L"C:\\%ls\\Folder1\\", L"File1" },
161 { L"C:\\%ls\\CurrentDirectory; C:\\%ls\\Folder1",
162 L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
163 { L";C:\\%ls\\Folder1", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
164 { L";C:\\%ls\\Folder1;", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
165 { L";C:\\%ls\\Folder1;", L"File1", NULL, L"C:\\%ls\\CurrentDirectory\\", L"File1" },
166 { L"C:\\%ls\\Folder1", L"OnlyInCurr", NULL, NULL, NULL },
167 // 40
168 { L"", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
169 { L"", L"OnlyInCurr ", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
170 { L"", L" OnlyInCurr", NULL, NULL, NULL },
171 { L" ", L"OnlyInCurr", NULL, NULL, NULL },
172 { L";", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
173 { L"; ", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
174 { L" ;", L"OnlyInCurr", NULL, NULL, NULL },
175 { L" ; ", L"OnlyInCurr", NULL, NULL, NULL },
176 { L";C:\\%ls\\Folder1", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
177 { L"C:\\%ls\\Folder1;", L"OnlyInCurr", NULL, NULL, NULL },
178 // 50
179 { L"C:\\%ls\\Folder1;;", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
180 { L";C:\\%ls\\Folder1;", L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
181 { L"C:\\%ls\\Folder1;C:\\%ls\\Folder2",
182 L"OnlyInCurr", NULL, NULL, NULL },
183 { L";C:\\%ls\\Folder1;C:\\%ls\\Folder2",
184 L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
185 { L"C:\\%ls\\Folder1;;C:\\%ls\\Folder2",
186 L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
187 { L"C:\\%ls\\Folder1;C:\\%ls\\Folder2;",
188 L"OnlyInCurr", NULL, NULL, NULL },
189 { L"C:\\%ls\\Folder1;C:\\%ls\\Folder2;;",
190 L"OnlyInCurr", NULL, L"C:\\%ls\\CurrentDirectory\\", L"OnlyInCurr" },
191 /* Spaces in FileName! */
192 { L"", L"C:\\%ls\\Folder1\\SomeProgram With Spaces",
193 L".exe", NULL, NULL },
194 { L"", L"C:\\%ls\\Folder1\\SomeProgram With Spaces.exe",
195 L".exe", NULL, NULL },
196 { L"", L"C:\\%ls\\Folder1\\Program", L".exe", NULL, NULL },
197 // 60
198 { L"", L"C:\\%ls\\Folder1\\Program.exe", L".exe", L"C:\\%ls\\Folder1\\", L"Program.exe" },
199 { L"", L"C:\\%ls\\Folder1\\Program With", L".exe", NULL, NULL },
200 { L"", L"C:\\%ls\\Folder1\\Program With.exe", L".exe", L"C:\\%ls\\Folder1\\", L"Program With.exe" },
201 { L"", L"C:\\%ls\\Folder1\\Program With Spaces",L".exe", NULL, NULL },
202 { L"", L"C:\\%ls\\Folder1\\Program With Spaces.exe",
203 L".exe", L"C:\\%ls\\Folder1\\", L"Program With Spaces.exe" },
204 /* Same tests with path in SearchPath - now extensions are appended */
205 { L"C:\\%ls\\Folder1", L"SomeProgram With Spaces",
206 L".exe", NULL, NULL },
207 { L"C:\\%ls\\Folder1", L"SomeProgram With Spaces.exe",
208 L".exe", NULL, NULL },
209 { L"C:\\%ls\\Folder1", L"Program", L".exe", L"C:\\%ls\\Folder1\\", L"Program.exe" },
210 { L"C:\\%ls\\Folder1", L"Program.exe", L".exe", L"C:\\%ls\\Folder1\\", L"Program.exe" },
211 { L"C:\\%ls\\Folder1", L"Program With", L".exe", L"C:\\%ls\\Folder1\\", L"Program With.exe" },
212 // 70
213 { L"C:\\%ls\\Folder1", L"Program With.exe", L".exe", L"C:\\%ls\\Folder1\\", L"Program With.exe" },
214 { L"C:\\%ls\\Folder1", L"Program With Spaces", L".exe", L"C:\\%ls\\Folder1\\", L"Program With Spaces.exe" },
215 { L"C:\\%ls\\Folder1", L"Program With Spaces.exe",
216 L".exe", L"C:\\%ls\\Folder1\\", L"Program With Spaces.exe" },
217 };
218
219 ULONG i;
220 ULONG Length;
221 PWSTR PartName;
222 WCHAR SearchPath[MAX_PATH];
223 WCHAR FileName[MAX_PATH];
224 WCHAR ResultPath[MAX_PATH];
225 WCHAR Buffer[MAX_PATH];
226 BOOLEAN Okay;
227
228 for (i = 0; i < sizeof(Tests) / sizeof(Tests[0]); i++)
229 {
230 swprintf(SearchPath, Tests[i].SearchPath, CustomPath, CustomPath, CustomPath, CustomPath);
231 swprintf(FileName, Tests[i].FileName, CustomPath, CustomPath, CustomPath, CustomPath);
232 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
233 PartName = InvalidPointer;
234
235 StartSeh()
236 Length = RtlDosSearchPath_U(SearchPath,
237 FileName,
238 Tests[i].Extension,
239 sizeof(Buffer),
240 Buffer,
241 &PartName);
242 EndSeh(STATUS_SUCCESS);
243
244 if (Tests[i].ResultPath)
245 {
246 swprintf(ResultPath, Tests[i].ResultPath, CustomPath, CustomPath, CustomPath, CustomPath);
247 if (Tests[i].ResultFileName)
248 {
249 ok(PartName == &Buffer[wcslen(ResultPath)],
250 "PartName = %p (%ls), expected %p\n",
251 PartName, PrintablePointer(PartName), &Buffer[wcslen(ResultPath)]);
252 wcscat(ResultPath, Tests[i].ResultFileName);
253 }
254 else
255 {
256 ok(PartName == NULL,
257 "PartName = %p (%ls), expected NULL\n",
258 PartName, PrintablePointer(PartName));
259 }
260 Okay = CheckStringBuffer(Buffer, Length, sizeof(Buffer), ResultPath);
261 ok(Okay == TRUE, "CheckStringBuffer failed. Got '%ls', expected '%ls'\n", Buffer, ResultPath);
262 }
263 else
264 {
265 Okay = CheckBuffer(Buffer, sizeof(Buffer), 0x55);
266 ok(Okay == TRUE, "CheckBuffer failed\n");
267 ok(Length == 0, "Length = %lu\n", Length);
268 ok(PartName == InvalidPointer,
269 "PartName = %p (%ls), expected %p\n",
270 PartName, PrintablePointer(PartName), InvalidPointer);
271 }
272 }
273 }
274
275 #define MAKE_DIRECTORY(path) \
276 do { \
277 swprintf(FileName, path, CustomPath); \
278 Success = CreateDirectoryW(FileName, NULL); \
279 ok(Success, "CreateDirectory failed, results might not be accurate\n"); \
280 } while (0)
281
282 #define MAKE_FILE(path) \
283 do { \
284 swprintf(FileName, path, CustomPath); \
285 Handle = CreateFileW(FileName, 0, 0, NULL, CREATE_NEW, 0, NULL); \
286 ok(Handle != INVALID_HANDLE_VALUE, \
287 "CreateFile failed, results might not be accurate\n"); \
288 if (Handle != INVALID_HANDLE_VALUE) CloseHandle(Handle); \
289 } while (0)
290
291 #define DELETE_DIRECTORY(path) \
292 do { \
293 swprintf(FileName, path, CustomPath); \
294 Success = RemoveDirectoryW(FileName); \
295 ok(Success, \
296 "RemoveDirectory failed (%lu), test might leave stale directory\n", \
297 GetLastError()); \
298 } while (0)
299
300 #define DELETE_FILE(path) \
301 do { \
302 swprintf(FileName, path, CustomPath); \
303 Success = DeleteFileW(FileName); \
304 ok(Success, \
305 "DeleteFile failed (%lu), test might leave stale file\n", \
306 GetLastError()); \
307 } while (0)
308
309 START_TEST(RtlDosSearchPath_U)
310 {
311 ULONG Length = 0;
312 WCHAR Buffer[MAX_PATH];
313 PWSTR PartName;
314 BOOLEAN Okay;
315 BOOL Success;
316 WCHAR FileName[MAX_PATH];
317 WCHAR CustomPath[MAX_PATH] = L"RtlDosSearchPath_U_TestPath";
318 HANDLE Handle;
319
320 swprintf(FileName, L"C:\\%ls", CustomPath);
321 /* Make sure this directory doesn't exist */
322 while (GetFileAttributesW(FileName) != INVALID_FILE_ATTRIBUTES)
323 {
324 wcscat(CustomPath, L"X");
325 swprintf(FileName, L"C:\\%ls", CustomPath);
326 }
327 Success = CreateDirectoryW(FileName, NULL);
328 ok(Success, "CreateDirectory failed, results might not be accurate\n");
329
330 MAKE_DIRECTORY(L"C:\\%ls\\Folder1");
331 MAKE_DIRECTORY(L"C:\\%ls\\Folder2");
332 MAKE_DIRECTORY(L"C:\\%ls\\CurrentDirectory");
333 Success = SetCurrentDirectoryW(FileName);
334 ok(Success, "SetCurrentDirectory failed\n");
335 MAKE_FILE(L"C:\\%ls\\Folder1\\File1");
336 MAKE_FILE(L"C:\\%ls\\Folder1\\SomeProgram.exe");
337 MAKE_FILE(L"C:\\%ls\\Folder1\\SomeProgram2.exe");
338 MAKE_FILE(L"C:\\%ls\\Folder1\\SomeProgram2.exe.exe");
339 MAKE_FILE(L"C:\\%ls\\Folder1\\SomeProgram3.exe.exe");
340 MAKE_FILE(L"C:\\%ls\\Folder1\\Program.exe");
341 MAKE_FILE(L"C:\\%ls\\Folder1\\Program With.exe");
342 MAKE_FILE(L"C:\\%ls\\Folder1\\Program With Spaces.exe");
343 MAKE_FILE(L"C:\\%ls\\CurrentDirectory\\File1");
344 MAKE_FILE(L"C:\\%ls\\CurrentDirectory\\OnlyInCurr");
345
346 /* NULL parameters */
347 StartSeh() RtlDosSearchPath_U(NULL, NULL, NULL, 0, NULL , NULL); EndSeh(STATUS_ACCESS_VIOLATION);
348 StartSeh() RtlDosSearchPath_U(NULL, L"" , NULL, 0, NULL , NULL); EndSeh(STATUS_ACCESS_VIOLATION);
349 StartSeh() RtlDosSearchPath_U(NULL, L"" , NULL, 0, Buffer, NULL); EndSeh(STATUS_ACCESS_VIOLATION);
350 StartSeh() RtlDosSearchPath_U(NULL, L"" , NULL, 1, Buffer, NULL); EndSeh(STATUS_ACCESS_VIOLATION);
351 StartSeh() RtlDosSearchPath_U(NULL, L"" , NULL, 2, Buffer, NULL); EndSeh(STATUS_ACCESS_VIOLATION);
352 StartSeh() RtlDosSearchPath_U(L"" , NULL, NULL, 0, NULL , NULL); EndSeh(STATUS_ACCESS_VIOLATION);
353
354 /* Empty strings - first one that doesn't crash */
355 StartSeh()
356 Length = RtlDosSearchPath_U(L"", L"", NULL, 0, NULL, NULL);
357 ok(Length == 0, "Length %lu\n", Length);
358 EndSeh(STATUS_SUCCESS);
359
360 /* Check what's initialized */
361 PartName = InvalidPointer;
362 StartSeh()
363 Length = RtlDosSearchPath_U(L"", L"", NULL, 0, NULL, &PartName);
364 ok(Length == 0, "Length = %lu\n", Length);
365 EndSeh(STATUS_SUCCESS);
366 ok(PartName == InvalidPointer, "PartName = %p\n", PartName);
367
368 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
369 StartSeh()
370 Length = RtlDosSearchPath_U(L"", L"", NULL, sizeof(Buffer), Buffer, NULL);
371 ok(Length == 0, "Length %lu\n", Length);
372 EndSeh(STATUS_SUCCESS);
373 Okay = CheckBuffer(Buffer, sizeof(Buffer), 0x55);
374 ok(Okay, "CheckBuffer failed\n");
375
376 PartName = InvalidPointer;
377 RtlFillMemory(Buffer, sizeof(Buffer), 0x55);
378 StartSeh()
379 Length = RtlDosSearchPath_U(L"", L"", NULL, sizeof(Buffer), Buffer, &PartName);
380 ok(Length == 0, "Length %lu\n", Length);
381 EndSeh(STATUS_SUCCESS);
382 ok(PartName == InvalidPointer, "PartName = %p\n", PartName);
383 Okay = CheckBuffer(Buffer, sizeof(Buffer), 0x55);
384 ok(Okay, "CheckBuffer failed\n");
385
386 /* Now test the actual functionality */
387 RunTestCases(CustomPath);
388
389 /*
390 * Clean up test folder - We can't delete it
391 * if our current directory is inside.
392 */
393 SetCurrentDirectoryW(L"C:\\");
394 DELETE_FILE(L"C:\\%ls\\CurrentDirectory\\OnlyInCurr");
395 DELETE_FILE(L"C:\\%ls\\CurrentDirectory\\File1");
396 DELETE_FILE(L"C:\\%ls\\Folder1\\Program With Spaces.exe");
397 DELETE_FILE(L"C:\\%ls\\Folder1\\Program With.exe");
398 DELETE_FILE(L"C:\\%ls\\Folder1\\Program.exe");
399 DELETE_FILE(L"C:\\%ls\\Folder1\\SomeProgram3.exe.exe");
400 DELETE_FILE(L"C:\\%ls\\Folder1\\SomeProgram2.exe.exe");
401 DELETE_FILE(L"C:\\%ls\\Folder1\\SomeProgram2.exe");
402 DELETE_FILE(L"C:\\%ls\\Folder1\\SomeProgram.exe");
403 DELETE_FILE(L"C:\\%ls\\Folder1\\File1");
404 DELETE_DIRECTORY(L"C:\\%ls\\CurrentDirectory");
405 DELETE_DIRECTORY(L"C:\\%ls\\Folder2");
406 DELETE_DIRECTORY(L"C:\\%ls\\Folder1");
407 DELETE_DIRECTORY(L"C:\\%ls");
408 }