Reactos
1/*
2 * PROJECT: ReactOS api tests
3 * LICENSE: LGPL-2.0-or-later (https://spdx.org/licenses/LGPL-2.0-or-later)
4 * PURPOSE: Test for FindExecutable
5 * COPYRIGHT: Copyright 2021-2024 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6 */
7
8#include "shelltest.h"
9#include <stdio.h>
10#include <shlwapi.h>
11
12typedef struct TEST_ENTRY
13{
14 INT lineno;
15 UINT ret; // SE_ERR_NOASSOC, SE_ERR_FNF, or 0xBEEFCAFE (success).
16 LPCSTR file;
17 LPCSTR dir;
18 LPCSTR result;
19} TEST_ENTRY;
20
21static char s_win_dir[MAX_PATH];
22static char s_win_notepad[MAX_PATH];
23static char s_sys_notepad[MAX_PATH];
24static char s_win_test_exe[MAX_PATH];
25static char s_sys_test_exe[MAX_PATH];
26static char s_win_bat_file[MAX_PATH];
27static char s_sys_bat_file[MAX_PATH];
28static char s_win_txt_file[MAX_PATH];
29static char s_sys_txt_file[MAX_PATH];
30
31#define DIR_0 NULL
32#define DIR_1 "."
33#define DIR_2 ".."
34#define DIR_3 s_win_dir
35#define DIR_4 "(invalid)"
36
37static const TEST_ENTRY s_entries[] =
38{
39 { __LINE__, 0xBEEFCAFE, "notepad", DIR_0, s_sys_notepad },
40 { __LINE__, 0xBEEFCAFE, "notepad", DIR_1, s_sys_notepad },
41 // { __LINE__, 0xBEEFCAFE, "notepad", DIR_2, "notepad.exe" }, // Results vary between Windows versions
42 { __LINE__, 0xBEEFCAFE, "notepad", DIR_3, s_win_notepad },
43 { __LINE__, 0xBEEFCAFE, "notepad", DIR_4, s_sys_notepad },
44 { __LINE__, SE_ERR_FNF, " notepad", DIR_0, "" },
45 { __LINE__, SE_ERR_FNF, " notepad", DIR_1, "" },
46 { __LINE__, SE_ERR_FNF, " notepad", DIR_2, "" },
47 { __LINE__, SE_ERR_FNF, " notepad", DIR_3, "" },
48 { __LINE__, SE_ERR_FNF, " notepad", DIR_4, "" },
49 { __LINE__, SE_ERR_FNF, "notepad ", DIR_0, "" },
50 { __LINE__, SE_ERR_FNF, "notepad ", DIR_1, "" },
51 { __LINE__, SE_ERR_FNF, "notepad ", DIR_2, "" },
52 { __LINE__, SE_ERR_FNF, "notepad ", DIR_3, "" },
53 { __LINE__, SE_ERR_FNF, "notepad ", DIR_4, "" },
54 { __LINE__, 0xBEEFCAFE, "\"notepad\"", DIR_0, s_sys_notepad },
55 { __LINE__, 0xBEEFCAFE, "\"notepad\"", DIR_1, s_sys_notepad },
56 // { __LINE__, 0xBEEFCAFE, "\"notepad\"", DIR_2, "notepad.exe" }, // Results vary between Windows versions
57 { __LINE__, 0xBEEFCAFE, "\"notepad\"", DIR_3, s_win_notepad },
58 { __LINE__, 0xBEEFCAFE, "\"notepad\"", DIR_4, s_sys_notepad },
59 { __LINE__, 0xBEEFCAFE, "notepad.exe", DIR_0, s_sys_notepad },
60 { __LINE__, 0xBEEFCAFE, "notepad.exe", DIR_1, s_sys_notepad },
61 // { __LINE__, 0xBEEFCAFE, "notepad.exe", DIR_2, "notepad.exe" }, // Results vary between Windows versions
62 { __LINE__, 0xBEEFCAFE, "notepad.exe", DIR_3, s_win_notepad },
63 { __LINE__, 0xBEEFCAFE, "notepad.exe", DIR_4, s_sys_notepad },
64 { __LINE__, SE_ERR_FNF, "notepad.bat", DIR_0, "" },
65 { __LINE__, SE_ERR_FNF, "notepad.bat", DIR_1, "" },
66 { __LINE__, SE_ERR_FNF, "notepad.bat", DIR_2, "" },
67 { __LINE__, SE_ERR_FNF, "notepad.bat", DIR_3, "" },
68 { __LINE__, SE_ERR_FNF, "notepad.bat", DIR_4, "" },
69 { __LINE__, SE_ERR_FNF, "C:\\notepad.exe", DIR_0, "" },
70 { __LINE__, SE_ERR_FNF, "C:\\notepad.exe", DIR_1, "" },
71 { __LINE__, SE_ERR_FNF, "C:\\notepad.exe", DIR_2, "" },
72 { __LINE__, SE_ERR_FNF, "C:\\notepad.exe", DIR_3, "" },
73 { __LINE__, SE_ERR_FNF, "C:\\notepad.exe", DIR_4, "" },
74 { __LINE__, SE_ERR_FNF, ".\\notepad.exe", DIR_0, "" },
75 { __LINE__, SE_ERR_FNF, ".\\notepad.exe", DIR_1, "" },
76 { __LINE__, SE_ERR_FNF, ".\\notepad.exe", DIR_2, "" },
77 { __LINE__, 0xBEEFCAFE, ".\\notepad.exe", DIR_3, s_win_notepad },
78 { __LINE__, SE_ERR_FNF, ".\\notepad.exe", DIR_4, "" },
79 { __LINE__, SE_ERR_FNF, "system32\\notepad.exe", DIR_0, "" },
80 { __LINE__, SE_ERR_FNF, "system32\\notepad.exe", DIR_1, "" },
81 { __LINE__, SE_ERR_FNF, "system32\\notepad.exe", DIR_2, "" },
82 { __LINE__, 0xBEEFCAFE, "system32\\notepad.exe", DIR_3, s_sys_notepad },
83 { __LINE__, SE_ERR_FNF, "system32\\notepad.exe", DIR_4, "" },
84 { __LINE__, 0xBEEFCAFE, s_win_notepad, DIR_0, s_win_notepad },
85 { __LINE__, 0xBEEFCAFE, s_win_notepad, DIR_1, s_win_notepad },
86 { __LINE__, 0xBEEFCAFE, s_win_notepad, DIR_2, s_win_notepad },
87 { __LINE__, 0xBEEFCAFE, s_win_notepad, DIR_3, s_win_notepad },
88 { __LINE__, 0xBEEFCAFE, s_win_notepad, DIR_4, s_win_notepad },
89 { __LINE__, 0xBEEFCAFE, "test program", DIR_0, s_sys_test_exe },
90 { __LINE__, 0xBEEFCAFE, "test program", DIR_1, s_sys_test_exe },
91 // { __LINE__, 0xBEEFCAFE, "test program", DIR_2, "test program.exe" }, // Results vary between Windows versions
92 { __LINE__, 0xBEEFCAFE, "test program", DIR_3, s_win_test_exe },
93 { __LINE__, 0xBEEFCAFE, "test program", DIR_4, s_sys_test_exe },
94 { __LINE__, SE_ERR_FNF, " test program", DIR_0, "" },
95 { __LINE__, SE_ERR_FNF, " test program", DIR_1, "" },
96 { __LINE__, SE_ERR_FNF, " test program", DIR_2, "" },
97 { __LINE__, SE_ERR_FNF, " test program", DIR_3, "" },
98 { __LINE__, SE_ERR_FNF, " test program", DIR_4, "" },
99 { __LINE__, SE_ERR_FNF, "test program ", DIR_0, "" },
100 { __LINE__, SE_ERR_FNF, "test program ", DIR_1, "" },
101 { __LINE__, SE_ERR_FNF, "test program ", DIR_2, "" },
102 { __LINE__, SE_ERR_FNF, "test program ", DIR_3, "" },
103 { __LINE__, SE_ERR_FNF, "test program ", DIR_4, "" },
104 { __LINE__, 0xBEEFCAFE, "\"test program\"", DIR_0, s_sys_test_exe },
105 { __LINE__, 0xBEEFCAFE, "\"test program\"", DIR_1, s_sys_test_exe },
106 // { __LINE__, 0xBEEFCAFE, "\"test program\"", DIR_2, "test program.exe" }, // Results vary between Windows versions
107 { __LINE__, 0xBEEFCAFE, "\"test program\"", DIR_3, s_win_test_exe },
108 { __LINE__, 0xBEEFCAFE, "\"test program\"", DIR_4, s_sys_test_exe },
109 { __LINE__, 0xBEEFCAFE, "test program.exe", DIR_0, s_sys_test_exe },
110 { __LINE__, 0xBEEFCAFE, "test program.exe", DIR_1, s_sys_test_exe },
111 // { __LINE__, 0xBEEFCAFE, "test program.exe", DIR_2, "TESTPR~1.EXE" }, // Results vary between Windows versions
112 { __LINE__, 0xBEEFCAFE, "test program.exe", DIR_3, s_win_test_exe },
113 { __LINE__, 0xBEEFCAFE, "test program.exe", DIR_4, s_sys_test_exe },
114 { __LINE__, 0xBEEFCAFE, "\"test program.exe\"", DIR_0, s_sys_test_exe },
115 { __LINE__, 0xBEEFCAFE, "\"test program.exe\"", DIR_1, s_sys_test_exe },
116 // { __LINE__, 0xBEEFCAFE, "\"test program.exe\"", DIR_2, "test program.exe" }, // Results vary between Windows versions
117 { __LINE__, 0xBEEFCAFE, "\"test program.exe\"", DIR_3, s_win_test_exe },
118 { __LINE__, 0xBEEFCAFE, "\"test program.exe\"", DIR_4, s_sys_test_exe },
119 { __LINE__, SE_ERR_NOASSOC, "\"test program.exe \"", DIR_0, "" },
120 { __LINE__, SE_ERR_NOASSOC, "\"test program.exe \"", DIR_1, "" },
121 { __LINE__, SE_ERR_NOASSOC, "\"test program.exe \"", DIR_2, "" },
122 { __LINE__, SE_ERR_NOASSOC, "\"test program.exe \"", DIR_3, "" },
123 { __LINE__, SE_ERR_NOASSOC, "\"test program.exe \"", DIR_4, "" },
124 { __LINE__, SE_ERR_FNF, "\" test program.exe\"", DIR_0, "" },
125 { __LINE__, SE_ERR_FNF, "\" test program.exe\"", DIR_1, "" },
126 { __LINE__, SE_ERR_FNF, "\" test program.exe\"", DIR_2, "" },
127 { __LINE__, SE_ERR_FNF, "\" test program.exe\"", DIR_3, "" },
128 { __LINE__, SE_ERR_FNF, "\" test program.exe\"", DIR_4, "" },
129 { __LINE__, 0xBEEFCAFE, "test program.bat", DIR_0, s_sys_bat_file },
130 { __LINE__, 0xBEEFCAFE, "test program.bat", DIR_1, s_sys_bat_file },
131 // { __LINE__, 0xBEEFCAFE, "test program.bat", DIR_2, "TESTPR~1.BAT" }, // Results vary between Windows versions
132 { __LINE__, 0xBEEFCAFE, "test program.bat", DIR_3, s_win_bat_file },
133 { __LINE__, 0xBEEFCAFE, "test program.bat", DIR_4, s_sys_bat_file },
134 { __LINE__, SE_ERR_FNF, " test program.bat ", DIR_0, "" },
135 { __LINE__, SE_ERR_FNF, " test program.bat ", DIR_1, "" },
136 { __LINE__, SE_ERR_FNF, " test program.bat ", DIR_2, "" },
137 { __LINE__, SE_ERR_FNF, " test program.bat ", DIR_3, "" },
138 { __LINE__, SE_ERR_FNF, " test program.bat ", DIR_4, "" },
139 { __LINE__, 0xBEEFCAFE, "\"test program.bat\"", DIR_0, s_sys_bat_file },
140 { __LINE__, 0xBEEFCAFE, "\"test program.bat\"", DIR_1, s_sys_bat_file },
141 // { __LINE__, 0xBEEFCAFE, "\"test program.bat\"", DIR_2, "test program.bat" }, // Results vary between Windows versions
142 { __LINE__, 0xBEEFCAFE, "\"test program.bat\"", DIR_3, s_win_bat_file },
143 { __LINE__, 0xBEEFCAFE, "\"test program.bat\"", DIR_4, s_sys_bat_file },
144 { __LINE__, 0xBEEFCAFE, "test file.txt", DIR_0, s_sys_notepad },
145 { __LINE__, 0xBEEFCAFE, "test file.txt", DIR_1, s_sys_notepad },
146 // { __LINE__, SE_ERR_NOASSOC, "test file.txt", DIR_2, "" }, // Results vary between Windows versions
147 { __LINE__, 0xBEEFCAFE, "test file.txt", DIR_3, s_sys_notepad },
148 { __LINE__, 0xBEEFCAFE, "test file.txt", DIR_4, s_sys_notepad },
149 { __LINE__, SE_ERR_FNF, "invalid file.txt", DIR_0, "" },
150 { __LINE__, SE_ERR_FNF, "invalid file.txt", DIR_1, "" },
151 { __LINE__, SE_ERR_FNF, "invalid file.txt", DIR_2, "" },
152 { __LINE__, SE_ERR_FNF, "invalid file.txt", DIR_3, "" },
153 { __LINE__, SE_ERR_FNF, "invalid file.txt", DIR_4, "" },
154 { __LINE__, SE_ERR_FNF, "invalid file.InvalidExtension", DIR_0, "" },
155 { __LINE__, SE_ERR_FNF, "invalid file.InvalidExtension", DIR_1, "" },
156 { __LINE__, SE_ERR_FNF, "invalid file.InvalidExtension", DIR_2, "" },
157 { __LINE__, SE_ERR_FNF, "invalid file.InvalidExtension", DIR_3, "" },
158 { __LINE__, SE_ERR_FNF, "invalid file.InvalidExtension", DIR_4, "" },
159};
160
161static void DoTestEntry(const TEST_ENTRY *pEntry)
162{
163 char result[MAX_PATH];
164 result[0] = 0;
165
166 UINT ret = (UINT)(UINT_PTR)FindExecutableA(pEntry->file, pEntry->dir, result);
167 if (ret > 32)
168 ret = 0xBEEFCAFE;
169
170 ok(ret == pEntry->ret, "Line %u: ret expected %d, got %d\n", pEntry->lineno, pEntry->ret, ret);
171
172 GetLongPathNameA(result, result, _countof(result));
173
174 ok(lstrcmpiA(result, pEntry->result) == 0,
175 "Line %u: result expected '%s', got '%s'\n",
176 pEntry->lineno, pEntry->result, result);
177}
178
179START_TEST(FindExecutable)
180{
181 char cur_dir[MAX_PATH];
182 GetCurrentDirectoryA(_countof(cur_dir), cur_dir);
183 if (PathIsRootA(cur_dir))
184 {
185 skip("Don't use this program at root directory\n");
186 return;
187 }
188
189 GetWindowsDirectoryA(s_win_dir, _countof(s_win_dir));
190
191 GetWindowsDirectoryA(s_win_notepad, _countof(s_win_notepad));
192 PathAppendA(s_win_notepad, "notepad.exe");
193
194 GetSystemDirectoryA(s_sys_notepad, _countof(s_sys_notepad));
195 PathAppendA(s_sys_notepad, "notepad.exe");
196
197 GetWindowsDirectoryA(s_win_test_exe, _countof(s_win_test_exe));
198 PathAppendA(s_win_test_exe, "test program.exe");
199 SetFileAttributesA(s_win_test_exe, FILE_ATTRIBUTE_NORMAL); // If the file exists, strip the readonly flag
200 BOOL ret = CopyFileA(s_win_notepad, s_win_test_exe, FALSE);
201 if (!ret)
202 {
203 skip("Cannot copy test files to the system root directory. (Error: %lu)\n", GetLastError());
204 return;
205 }
206
207 GetSystemDirectoryA(s_sys_test_exe, _countof(s_sys_test_exe));
208 PathAppendA(s_sys_test_exe, "test program.exe");
209 SetFileAttributesA(s_sys_test_exe, FILE_ATTRIBUTE_NORMAL); // If the file exists, strip the readonly flag
210 ret = CopyFileA(s_win_notepad, s_sys_test_exe, FALSE);
211 if (!ret)
212 {
213 skip("Cannot copy test files to the system directory. (Error: %lu)\n", GetLastError());
214 DeleteFileA(s_win_test_exe);
215 return;
216 }
217
218 GetWindowsDirectoryA(s_win_bat_file, _countof(s_win_bat_file));
219 PathAppendA(s_win_bat_file, "test program.bat");
220 fclose(fopen(s_win_bat_file, "wb"));
221 ok_int(PathFileExistsA(s_win_bat_file), TRUE);
222
223 GetSystemDirectoryA(s_sys_bat_file, _countof(s_sys_bat_file));
224 PathAppendA(s_sys_bat_file, "test program.bat");
225 fclose(fopen(s_sys_bat_file, "wb"));
226 ok_int(PathFileExistsA(s_sys_bat_file), TRUE);
227
228 GetWindowsDirectoryA(s_win_txt_file, _countof(s_win_txt_file));
229 PathAppendA(s_win_txt_file, "test file.txt");
230 fclose(fopen(s_win_txt_file, "wb"));
231 ok_int(PathFileExistsA(s_win_txt_file), TRUE);
232
233 GetSystemDirectoryA(s_sys_txt_file, _countof(s_sys_txt_file));
234 PathAppendA(s_sys_txt_file, "test file.txt");
235 fclose(fopen(s_sys_txt_file, "wb"));
236 ok_int(PathFileExistsA(s_sys_txt_file), TRUE);
237
238 for (UINT iTest = 0; iTest < _countof(s_entries); ++iTest)
239 {
240 DoTestEntry(&s_entries[iTest]);
241 }
242
243 /* Cleanup:
244 * s_win_test_exe and s_sys_test_exe inherit the readonly flag,
245 * so we need to reset it before we can successfully delete it.
246 */
247 SetFileAttributesA(s_win_test_exe, FILE_ATTRIBUTE_NORMAL);
248 DeleteFileA(s_win_test_exe);
249 SetFileAttributesA(s_sys_test_exe, FILE_ATTRIBUTE_NORMAL);
250 DeleteFileA(s_sys_test_exe);
251 DeleteFileA(s_win_bat_file);
252 DeleteFileA(s_sys_bat_file);
253 DeleteFileA(s_win_txt_file);
254 DeleteFileA(s_sys_txt_file);
255}