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 
12 typedef 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 
21 static char s_win_dir[MAX_PATH];
22 static char s_win_notepad[MAX_PATH];
23 static char s_sys_notepad[MAX_PATH];
24 static char s_win_test_exe[MAX_PATH];
25 static char s_sys_test_exe[MAX_PATH];
26 static char s_win_bat_file[MAX_PATH];
27 static char s_sys_bat_file[MAX_PATH];
28 static char s_win_txt_file[MAX_PATH];
29 static 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 
37 static 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, s_sys_notepad },
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, s_sys_notepad },
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, s_sys_notepad },
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, s_sys_test_exe },
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, s_sys_test_exe },
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, s_sys_test_exe },
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, s_sys_test_exe },
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, s_sys_bat_file },
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, s_sys_bat_file },
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__, 0xBEEFCAFE, "test file.txt", DIR_2, s_sys_notepad },
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 
161 static 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 
179 START_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     BOOL ret = CopyFileA(s_win_notepad, s_win_test_exe, FALSE);
200     if (!ret)
201     {
202         skip("Please retry with admin rights\n");
203         return;
204     }
205 
206     GetSystemDirectoryA(s_sys_test_exe, _countof(s_sys_test_exe));
207     PathAppendA(s_sys_test_exe, "test program.exe");
208     ret = CopyFileA(s_win_notepad, s_sys_test_exe, FALSE);
209     if (!ret)
210     {
211         skip("Please retry with admin rights\n");
212         return;
213     }
214 
215     GetWindowsDirectoryA(s_win_bat_file, _countof(s_win_bat_file));
216     PathAppendA(s_win_bat_file, "test program.bat");
217     fclose(fopen(s_win_bat_file, "wb"));
218     ok_int(PathFileExistsA(s_win_bat_file), TRUE);
219 
220     GetSystemDirectoryA(s_sys_bat_file, _countof(s_sys_bat_file));
221     PathAppendA(s_sys_bat_file, "test program.bat");
222     fclose(fopen(s_sys_bat_file, "wb"));
223     ok_int(PathFileExistsA(s_sys_bat_file), TRUE);
224 
225     GetWindowsDirectoryA(s_win_txt_file, _countof(s_win_txt_file));
226     PathAppendA(s_win_txt_file, "test file.txt");
227     fclose(fopen(s_win_txt_file, "wb"));
228     ok_int(PathFileExistsA(s_win_txt_file), TRUE);
229 
230     GetSystemDirectoryA(s_sys_txt_file, _countof(s_sys_txt_file));
231     PathAppendA(s_sys_txt_file, "test file.txt");
232     fclose(fopen(s_sys_txt_file, "wb"));
233     ok_int(PathFileExistsA(s_sys_txt_file), TRUE);
234 
235     for (UINT iTest = 0; iTest < _countof(s_entries); ++iTest)
236     {
237         DoTestEntry(&s_entries[iTest]);
238     }
239 
240     DeleteFileA(s_win_test_exe);
241     DeleteFileA(s_sys_test_exe);
242     DeleteFileA(s_win_bat_file);
243     DeleteFileA(s_sys_bat_file);
244     DeleteFileA(s_win_txt_file);
245     DeleteFileA(s_sys_txt_file);
246 }
247