1 /*
2 * Copyright 2017 Katayama Hirofumi MZ
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include <apitest.h>
20 #include <shlwapi.h>
21 #include <assert.h>
22
23 #include <pseh/pseh2.h>
24
25 #define EF_FULLPATH 1
26 #define EF_TESTDATA 2
27 #define EF_WIN_DIR 4
28 #define EF_SYS_DIR 8
29 #define EF_TYPE_MASK 0xF
30
31 #define EF_NAME_ONLY 16
32
33 typedef struct ENTRY
34 {
35 INT EntryNumber; /* # */
36 INT Ret;
37 DWORD Error;
38 UINT EF_;
39 LPCWSTR NameBefore;
40 LPCWSTR NameExpected;
41 LPCWSTR PathExpected;
42 LPWSTR * Dirs;
43 } ENTRY;
44
45 #define BEEF 0xBEEF /* Error Code 48879 */
46 #define DEAD 0xDEAD /* Error Code 57005 */
47 #define IGNORE_ERR 0x7F7F7F7F /* Ignore Error Code */
48 #define RAISED 9999 /* exception raised */
49
50 static WCHAR s_TestDataPath[MAX_PATH];
51 static LPWSTR s_Dirs[2];
52 static WCHAR s_WinDir[MAX_PATH];
53 static WCHAR s_SysDir[MAX_PATH];
54 static WCHAR s_FontsDir[MAX_PATH];
55 static WCHAR s_NotepadPath[MAX_PATH];
56
57 static const ENTRY s_Entries[] =
58 {
59 /* NULL or empty path */
60 { 0, 0, BEEF, EF_FULLPATH, NULL, NULL },
61 { 1, 1, BEEF, EF_FULLPATH, L"", s_SysDir },
62 /* path without dirs in Windows */
63 { 2, 0, BEEF, EF_WIN_DIR, L"", L"" },
64 { 3, 0, BEEF, EF_WIN_DIR, L"Fonts", L"Fonts" },
65 { 4, 0, BEEF, EF_WIN_DIR, L"notepad", L"notepad" },
66 { 5, 0, BEEF, EF_WIN_DIR, L"notepad.exe", L"notepad.exe" },
67 { 6, 0, BEEF, EF_WIN_DIR, L"system32", L"system32" },
68 { 7, 0, BEEF, EF_WIN_DIR, L"invalid name", L"invalid name" },
69 /* path with dirs in Windows */
70 { 8, 0, BEEF, EF_WIN_DIR, L"", L"", NULL, s_Dirs },
71 { 9, 0, BEEF, EF_WIN_DIR, L"Fonts", L"Fonts", NULL, s_Dirs },
72 { 10, 0, BEEF, EF_WIN_DIR, L"notepad", L"notepad", NULL, s_Dirs },
73 { 11, 0, BEEF, EF_WIN_DIR, L"notepad.exe", L"notepad.exe", NULL, s_Dirs },
74 { 12, 0, BEEF, EF_WIN_DIR, L"system32", L"system32", NULL, s_Dirs },
75 { 13, 0, BEEF, EF_WIN_DIR, L"invalid name", L"invalid name", NULL, s_Dirs },
76 /* name only without dirs in Windows */
77 { 14, 1, BEEF, EF_WIN_DIR | EF_NAME_ONLY, L"", L"system32" },
78 { 15, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"Fonts", L"Fonts" },
79 { 16, 0, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"notepad" },
80 { 17, 1, BEEF, EF_WIN_DIR | EF_NAME_ONLY, L"notepad.exe", NULL, s_NotepadPath },
81 { 18, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"system32" },
82 { 19, 0, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name" },
83 /* name only with dirs in Windows */
84 { 20, 1, BEEF, EF_WIN_DIR | EF_NAME_ONLY, L"", NULL, s_TestDataPath, s_Dirs },
85 { 21, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"Fonts", L"Fonts", NULL, s_Dirs },
86 { 22, 0, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"notepad", NULL, L"notepad", s_Dirs },
87 { 23, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"notepad.exe", NULL, s_NotepadPath, s_Dirs },
88 { 24, 1, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"system32", L"system32", NULL, s_Dirs },
89 { 25, 0, ERROR_FILE_NOT_FOUND, EF_WIN_DIR | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name", s_Dirs },
90 /* path without dirs in system32 */
91 { 26, 0, BEEF, EF_SYS_DIR, L"", L"" },
92 { 27, 0, BEEF, EF_SYS_DIR, L"Fonts", L"Fonts" },
93 { 28, 0, BEEF, EF_SYS_DIR, L"notepad", L"notepad" },
94 { 29, 0, BEEF, EF_SYS_DIR, L"notepad.exe", L"notepad.exe" },
95 { 30, 0, BEEF, EF_SYS_DIR, L"system32", L"system32" },
96 { 31, 0, BEEF, EF_SYS_DIR, L"invalid name", L"invalid name" },
97 /* path with dirs in system32 */
98 { 32, 0, BEEF, EF_SYS_DIR, L"", L"", NULL, s_Dirs },
99 { 33, 0, BEEF, EF_SYS_DIR, L"Fonts", L"Fonts", NULL, s_Dirs },
100 { 34, 0, BEEF, EF_SYS_DIR, L"notepad", L"notepad", NULL, s_Dirs },
101 { 35, 0, BEEF, EF_SYS_DIR, L"notepad.exe", L"notepad.exe", NULL, s_Dirs },
102 { 36, 0, BEEF, EF_SYS_DIR, L"system32", L"system32", NULL, s_Dirs },
103 { 37, 0, BEEF, EF_SYS_DIR, L"invalid name", L"invalid name", NULL, s_Dirs },
104 /* name only without dirs in system32 */
105 { 38, 1, BEEF, EF_SYS_DIR | EF_NAME_ONLY, L"", NULL, s_SysDir },
106 { 39, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"Fonts", NULL, s_FontsDir },
107 { 40, 0, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"notepad", NULL, L"notepad" },
108 { 41, 1, BEEF, EF_SYS_DIR | EF_NAME_ONLY, L"notepad.exe", L"notepad.exe" },
109 { 42, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"system32", NULL, s_SysDir },
110 { 43, 0, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name" },
111 /* name only with dirs in system32 */
112 { 44, 1, BEEF, EF_SYS_DIR | EF_NAME_ONLY, L"", NULL, s_TestDataPath, s_Dirs },
113 { 45, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"Fonts", NULL, s_FontsDir, s_Dirs },
114 { 46, 0, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"notepad", NULL, L"notepad", s_Dirs },
115 { 47, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"notepad.exe", L"notepad.exe", NULL, s_Dirs },
116 { 48, 1, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"system32", NULL, s_SysDir, s_Dirs },
117 { 49, 0, ERROR_FILE_NOT_FOUND, EF_SYS_DIR | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name", s_Dirs },
118 /* path without dirs in testdata dir */
119 { 50, 0, BEEF, EF_TESTDATA, L"", L"" },
120 { 51, 0, BEEF, EF_TESTDATA, L"Fonts", L"Fonts" },
121 { 52, 0, BEEF, EF_TESTDATA, L"notepad", L"notepad" },
122 { 53, 0, BEEF, EF_TESTDATA, L"notepad.exe", L"notepad.exe" },
123 { 54, 0, BEEF, EF_TESTDATA, L"system32", L"system32" },
124 { 55, 0, BEEF, EF_TESTDATA, L"invalid name", L"invalid name" },
125 { 56, 0, BEEF, EF_TESTDATA, L"README.txt", L"README.txt" },
126 { 57, 0, BEEF, EF_TESTDATA, L"CmdLineUtils", L"CmdLineUtils" },
127 { 58, 0, BEEF, EF_TESTDATA, L"CmdLineUtils.exe", L"CmdLineUtils.exe" },
128 /* path with dirs in testdata dir */
129 { 59, 0, BEEF, EF_TESTDATA, L"", L"", NULL, s_Dirs },
130 { 60, 0, BEEF, EF_TESTDATA, L"Fonts", L"Fonts", NULL, s_Dirs },
131 { 61, 0, BEEF, EF_TESTDATA, L"notepad", L"notepad", NULL, s_Dirs },
132 { 62, 0, BEEF, EF_TESTDATA, L"notepad.exe", L"notepad.exe", NULL, s_Dirs },
133 { 63, 0, BEEF, EF_TESTDATA, L"system32", L"system32", NULL, s_Dirs },
134 { 64, 0, BEEF, EF_TESTDATA, L"invalid name", L"invalid name", NULL, s_Dirs },
135 { 65, 0, BEEF, EF_TESTDATA, L"README.txt", L"README.txt", NULL, s_Dirs },
136 { 66, 0, BEEF, EF_TESTDATA, L"CmdLineUtils", L"CmdLineUtils", NULL, s_Dirs },
137 { 67, 0, BEEF, EF_TESTDATA, L"CmdLineUtils.exe", L"CmdLineUtils.exe", NULL, s_Dirs },
138 /* name only without dirs in testdata dir */
139 { 68, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"", NULL, s_SysDir },
140 { 69, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"Fonts", NULL, s_FontsDir },
141 { 70, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"notepad", NULL, L"notepad" },
142 { 71, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"notepad.exe", NULL, s_NotepadPath },
143 { 72, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"system32", NULL, s_SysDir },
144 { 73, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name" },
145 { 74, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"README.txt", L"README.txt", NULL, s_Dirs },
146 { 75, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"CmdLineUtils", NULL, L"CmdLineUtils", s_Dirs },
147 { 76, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"CmdLineUtils.exe", NULL, L"CmdLineUtils.exe", s_Dirs },
148 /* name only with dirs in testdata dir */
149 { 77, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"", NULL, s_TestDataPath, s_Dirs },
150 { 78, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"Fonts", NULL, s_FontsDir, s_Dirs },
151 { 79, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"notepad", NULL, L"notepad", s_Dirs },
152 { 80, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"notepad.exe", NULL, s_NotepadPath, s_Dirs },
153 { 81, 1, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"system32", NULL, s_SysDir, s_Dirs },
154 { 82, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"invalid name", NULL, L"invalid name", s_Dirs },
155 { 83, 1, BEEF, EF_TESTDATA | EF_NAME_ONLY, L"README.txt", L"README.txt", NULL, s_Dirs },
156 { 84, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"CmdLineUtils", NULL, L"CmdLineUtils", s_Dirs },
157 { 85, 0, ERROR_FILE_NOT_FOUND, EF_TESTDATA | EF_NAME_ONLY, L"CmdLineUtils.exe", NULL, L"CmdLineUtils.exe", s_Dirs },
158 };
159
DoEntry(INT EntryNumber,const ENTRY * pEntry,const WCHAR * PathVar)160 static void DoEntry(INT EntryNumber, const ENTRY *pEntry, const WCHAR *PathVar)
161 {
162 WCHAR Path[MAX_PATH], PathExpected[MAX_PATH], OldPathVar[256];
163 INT Ret;
164 DWORD Error;
165
166 if (pEntry->NameBefore == NULL)
167 {
168 assert(pEntry->NameExpected == NULL);
169 assert(pEntry->PathExpected == NULL);
170 }
171
172 switch (pEntry->EF_ & EF_TYPE_MASK)
173 {
174 case EF_FULLPATH:
175 if (pEntry->NameBefore)
176 {
177 lstrcpyW(Path, pEntry->NameBefore);
178 }
179 if (pEntry->NameExpected)
180 {
181 lstrcpyW(PathExpected, pEntry->NameExpected);
182 }
183 break;
184
185 case EF_TESTDATA:
186 if (pEntry->EF_ & EF_NAME_ONLY)
187 {
188 lstrcpyW(Path, pEntry->NameBefore);
189 }
190 else
191 {
192 lstrcpyW(Path, s_TestDataPath);
193 lstrcatW(Path, L"\\");
194 lstrcatW(Path, pEntry->NameBefore);
195 }
196
197 if (pEntry->NameExpected)
198 {
199 lstrcpyW(PathExpected, s_TestDataPath);
200 lstrcatW(PathExpected, L"\\");
201 lstrcatW(PathExpected, pEntry->NameExpected);
202 }
203 break;
204
205 case EF_WIN_DIR:
206 if (pEntry->EF_ & EF_NAME_ONLY)
207 {
208 lstrcpyW(Path, pEntry->NameBefore);
209 }
210 else
211 {
212 GetWindowsDirectoryW(Path, _countof(Path));
213 lstrcatW(Path, L"\\");
214 lstrcatW(Path, pEntry->NameBefore);
215 }
216
217 if (pEntry->NameExpected)
218 {
219 GetWindowsDirectoryW(PathExpected, _countof(PathExpected));
220 lstrcatW(PathExpected, L"\\");
221 lstrcatW(PathExpected, pEntry->NameExpected);
222 }
223 break;
224
225 case EF_SYS_DIR:
226 if (pEntry->EF_ & EF_NAME_ONLY)
227 {
228 lstrcpyW(Path, pEntry->NameBefore);
229 }
230 else
231 {
232 GetSystemDirectoryW(Path, _countof(Path));
233 lstrcatW(Path, L"\\");
234 lstrcatW(Path, pEntry->NameBefore);
235 }
236
237 if (pEntry->NameExpected)
238 {
239 GetSystemDirectoryW(PathExpected, _countof(PathExpected));
240 lstrcatW(PathExpected, L"\\");
241 lstrcatW(PathExpected, pEntry->NameExpected);
242 }
243 break;
244 }
245
246 if (PathVar)
247 {
248 if (!GetEnvironmentVariableW(L"PATH", OldPathVar, _countof(OldPathVar)))
249 {
250 skip("#%d: GetEnvironmentVariableW failed\n", EntryNumber);
251 return;
252 }
253 if (!SetEnvironmentVariableW(L"PATH", PathVar))
254 {
255 skip("#%d: SetEnvironmentVariableW failed\n", EntryNumber);
256 return;
257 }
258 }
259
260 _SEH2_TRY
261 {
262 SetLastError(BEEF);
263 if (pEntry->NameBefore)
264 {
265 Ret = PathFindOnPathW(Path, (LPCWSTR *)pEntry->Dirs);
266 }
267 else
268 {
269 Ret = PathFindOnPathW(NULL, (LPCWSTR *)pEntry->Dirs);
270 }
271 Error = GetLastError();
272 }
273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
274 {
275 Ret = RAISED;
276 Error = DEAD;
277 }
278 _SEH2_END;
279
280 if (PathVar)
281 {
282 ok(SetEnvironmentVariableW(L"PATH", OldPathVar),
283 "#%d: SetEnvironmentVariableW failed\n", EntryNumber);
284 }
285
286 ok(Ret == pEntry->Ret, "#%d: Ret expected %d, was %d.\n",
287 EntryNumber, pEntry->Ret, Ret);
288
289 if (pEntry->Error != IGNORE_ERR)
290 {
291 ok(Error == pEntry->Error, "#%d: last error expected %ld, was %ld.\n",
292 EntryNumber, pEntry->Error, Error);
293 }
294
295 if (pEntry->PathExpected)
296 {
297 ok(lstrcmpiW(Path, pEntry->PathExpected) == 0, "#%d: Path expected %s, was %s.\n",
298 EntryNumber, wine_dbgstr_w(pEntry->PathExpected), wine_dbgstr_w(Path));
299 }
300 else if (pEntry->NameExpected)
301 {
302 ok(lstrcmpiW(Path, PathExpected) == 0, "#%d: Path expected %s, was %s.\n",
303 EntryNumber, wine_dbgstr_w(PathExpected), wine_dbgstr_w(Path));
304 }
305 }
306
Test_PathFindOnPathW(void)307 static void Test_PathFindOnPathW(void)
308 {
309 UINT i;
310
311 for (i = 0; i < _countof(s_Entries); ++i)
312 {
313 DoEntry(s_Entries[i].EntryNumber, &s_Entries[i], NULL);
314 }
315 }
316
START_TEST(PathFindOnPath)317 START_TEST(PathFindOnPath)
318 {
319 LPWSTR pch;
320
321 GetWindowsDirectoryW(s_WinDir, _countof(s_WinDir));
322 GetSystemDirectoryW(s_SysDir, _countof(s_SysDir));
323
324 lstrcpyW(s_FontsDir, s_WinDir);
325 lstrcatW(s_FontsDir, L"\\Fonts");
326
327 lstrcpyW(s_NotepadPath, s_SysDir);
328 lstrcatW(s_NotepadPath, L"\\notepad.exe");
329
330 GetModuleFileNameW(NULL, s_TestDataPath, _countof(s_TestDataPath));
331 pch = wcsrchr(s_TestDataPath, L'\\');
332 if (pch == NULL)
333 pch = wcsrchr(s_TestDataPath, L'/');
334 if (pch == NULL)
335 {
336 skip("GetModuleFileName and/or wcsrchr are insane.\n");
337 return;
338 }
339 lstrcpyW(pch, L"\\testdata");
340 if (GetFileAttributesW(s_TestDataPath) == INVALID_FILE_ATTRIBUTES)
341 {
342 skip("testdata is not found.\n");
343 return;
344 }
345
346 s_Dirs[0] = s_TestDataPath;
347 s_Dirs[1] = NULL;
348
349 Test_PathFindOnPathW();
350 }
351