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 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
6  */
7 
8 #include "shelltest.h"
9 #include <stdio.h>
10 #include <shlwapi.h>
11 #include "shell32_apitest_sub.h"
12 
13 static char s_sub_program[MAX_PATH];
14 
15 static BOOL
16 GetSubProgramPath(void)
17 {
18     GetModuleFileNameA(NULL, s_sub_program, _countof(s_sub_program));
19     PathRemoveFileSpecA(s_sub_program);
20     PathAppendA(s_sub_program, "shell32_apitest_sub.exe");
21 
22     if (!PathFileExistsA(s_sub_program))
23     {
24         PathRemoveFileSpecA(s_sub_program);
25         PathAppendA(s_sub_program, "testdata\\shell32_apitest_sub.exe");
26 
27         if (!PathFileExistsA(s_sub_program))
28         {
29             return FALSE;
30         }
31     }
32 
33     return TRUE;
34 }
35 
36 typedef struct TEST_ENTRY
37 {
38     INT lineno;
39     BOOL ret;
40     LPCSTR file;
41     LPCSTR dir;
42     LPCSTR result;
43 } TEST_ENTRY;
44 
45 static char s_win_dir[MAX_PATH];
46 static char s_win_notepad[MAX_PATH];
47 static char s_sys_notepad[MAX_PATH];
48 static char s_win_test_exe[MAX_PATH];
49 static char s_sys_test_exe[MAX_PATH];
50 static char s_win_bat_file[MAX_PATH];
51 static char s_sys_bat_file[MAX_PATH];
52 static char s_win_txt_file[MAX_PATH];
53 static char s_sys_txt_file[MAX_PATH];
54 
55 #define DIR_0 NULL
56 #define DIR_1 "."
57 #define DIR_2 ".."
58 #define DIR_3 s_win_dir
59 #define DIR_4 "(invalid)"
60 
61 static const TEST_ENTRY s_entries[] =
62 {
63     { __LINE__, TRUE, "notepad", DIR_0, s_sys_notepad },
64     { __LINE__, TRUE, "notepad", DIR_1, s_sys_notepad },
65     { __LINE__, TRUE, "notepad", DIR_2, s_sys_notepad },
66     { __LINE__, TRUE, "notepad", DIR_3, s_win_notepad },
67     { __LINE__, TRUE, "notepad", DIR_4, s_sys_notepad },
68     { __LINE__, FALSE, "  notepad", DIR_0, "" },
69     { __LINE__, FALSE, "  notepad", DIR_1, "" },
70     { __LINE__, FALSE, "  notepad", DIR_2, "" },
71     { __LINE__, FALSE, "  notepad", DIR_3, "" },
72     { __LINE__, FALSE, "  notepad", DIR_4, "" },
73     { __LINE__, FALSE, "notepad  ", DIR_0, "" },
74     { __LINE__, FALSE, "notepad  ", DIR_1, "" },
75     { __LINE__, FALSE, "notepad  ", DIR_2, "" },
76     { __LINE__, FALSE, "notepad  ", DIR_3, "" },
77     { __LINE__, FALSE, "notepad  ", DIR_4, "" },
78     { __LINE__, TRUE, "\"notepad\"", DIR_0, s_sys_notepad },
79     { __LINE__, TRUE, "\"notepad\"", DIR_1, s_sys_notepad },
80     { __LINE__, TRUE, "\"notepad\"", DIR_2, s_sys_notepad },
81     { __LINE__, TRUE, "\"notepad\"", DIR_3, s_win_notepad },
82     { __LINE__, TRUE, "\"notepad\"", DIR_4, s_sys_notepad },
83     { __LINE__, TRUE, "notepad.exe", DIR_0, s_sys_notepad },
84     { __LINE__, TRUE, "notepad.exe", DIR_1, s_sys_notepad },
85     { __LINE__, TRUE, "notepad.exe", DIR_2, s_sys_notepad },
86     { __LINE__, TRUE, "notepad.exe", DIR_3, s_win_notepad },
87     { __LINE__, TRUE, "notepad.exe", DIR_4, s_sys_notepad },
88     { __LINE__, FALSE, "notepad.bat", DIR_0, "" },
89     { __LINE__, FALSE, "notepad.bat", DIR_1, "" },
90     { __LINE__, FALSE, "notepad.bat", DIR_2, "" },
91     { __LINE__, FALSE, "notepad.bat", DIR_3, "" },
92     { __LINE__, FALSE, "notepad.bat", DIR_4, "" },
93     { __LINE__, FALSE, "C:\\notepad.exe", DIR_0, "" },
94     { __LINE__, FALSE, "C:\\notepad.exe", DIR_1, "" },
95     { __LINE__, FALSE, "C:\\notepad.exe", DIR_2, "" },
96     { __LINE__, FALSE, "C:\\notepad.exe", DIR_3, "" },
97     { __LINE__, FALSE, "C:\\notepad.exe", DIR_4, "" },
98     { __LINE__, FALSE, "..\\notepad.exe", DIR_0, "" },
99     { __LINE__, FALSE, "..\\notepad.exe", DIR_1, "" },
100     { __LINE__, FALSE, "..\\notepad.exe", DIR_2, "" },
101     { __LINE__, FALSE, "..\\notepad.exe", DIR_3, "" },
102     { __LINE__, FALSE, "..\\notepad.exe", DIR_4, "" },
103     { __LINE__, FALSE, ".\\notepad.exe", DIR_0, "" },
104     { __LINE__, FALSE, ".\\notepad.exe", DIR_1, "" },
105     { __LINE__, FALSE, ".\\notepad.exe", DIR_2, "" },
106     { __LINE__, TRUE, ".\\notepad.exe", DIR_3, s_win_notepad },
107     { __LINE__, FALSE, ".\\notepad.exe", DIR_4, "" },
108     { __LINE__, FALSE, "system32\\notepad.exe", DIR_0, "" },
109     { __LINE__, FALSE, "system32\\notepad.exe", DIR_1, "" },
110     { __LINE__, FALSE, "system32\\notepad.exe", DIR_2, "" },
111     { __LINE__, TRUE, "system32\\notepad.exe", DIR_3, s_sys_notepad },
112     { __LINE__, FALSE, "system32\\notepad.exe", DIR_4, "" },
113     { __LINE__, TRUE, s_win_notepad, DIR_0, s_win_notepad },
114     { __LINE__, TRUE, s_win_notepad, DIR_1, s_win_notepad },
115     { __LINE__, TRUE, s_win_notepad, DIR_2, s_win_notepad },
116     { __LINE__, TRUE, s_win_notepad, DIR_3, s_win_notepad },
117     { __LINE__, TRUE, s_win_notepad, DIR_4, s_win_notepad },
118     { __LINE__, TRUE, "test program", DIR_0, s_sys_test_exe },
119     { __LINE__, TRUE, "test program", DIR_1, s_sys_test_exe },
120     { __LINE__, TRUE, "test program", DIR_2, s_sys_test_exe },
121     { __LINE__, TRUE, "test program", DIR_3, s_win_test_exe },
122     { __LINE__, TRUE, "test program", DIR_4, s_sys_test_exe },
123     { __LINE__, FALSE, "  test program", DIR_0, "" },
124     { __LINE__, FALSE, "  test program", DIR_1, "" },
125     { __LINE__, FALSE, "  test program", DIR_2, "" },
126     { __LINE__, FALSE, "  test program", DIR_3, "" },
127     { __LINE__, FALSE, "  test program", DIR_4, "" },
128     { __LINE__, FALSE, "test program  ", DIR_0, "" },
129     { __LINE__, FALSE, "test program  ", DIR_1, "" },
130     { __LINE__, FALSE, "test program  ", DIR_2, "" },
131     { __LINE__, FALSE, "test program  ", DIR_3, "" },
132     { __LINE__, FALSE, "test program  ", DIR_4, "" },
133     { __LINE__, TRUE, "\"test program\"", DIR_0, s_sys_test_exe },
134     { __LINE__, TRUE, "\"test program\"", DIR_1, s_sys_test_exe },
135     { __LINE__, TRUE, "\"test program\"", DIR_2, s_sys_test_exe },
136     { __LINE__, TRUE, "\"test program\"", DIR_3, s_win_test_exe },
137     { __LINE__, TRUE, "\"test program\"", DIR_4, s_sys_test_exe },
138     { __LINE__, TRUE, "test program.exe", DIR_0, s_sys_test_exe },
139     { __LINE__, TRUE, "test program.exe", DIR_1, s_sys_test_exe },
140     { __LINE__, TRUE, "test program.exe", DIR_2, s_sys_test_exe },
141     { __LINE__, TRUE, "test program.exe", DIR_3, s_win_test_exe },
142     { __LINE__, TRUE, "test program.exe", DIR_4, s_sys_test_exe },
143     { __LINE__, TRUE, "\"test program.exe\"", DIR_0, s_sys_test_exe },
144     { __LINE__, TRUE, "\"test program.exe\"", DIR_1, s_sys_test_exe },
145     { __LINE__, TRUE, "\"test program.exe\"", DIR_2, s_sys_test_exe },
146     { __LINE__, TRUE, "\"test program.exe\"", DIR_3, s_win_test_exe },
147     { __LINE__, TRUE, "\"test program.exe\"", DIR_4, s_sys_test_exe },
148     { __LINE__, FALSE, "\"test program.exe \"", DIR_0, "" },
149     { __LINE__, FALSE, "\"test program.exe \"", DIR_1, "" },
150     { __LINE__, FALSE, "\"test program.exe \"", DIR_2, "" },
151     { __LINE__, FALSE, "\"test program.exe \"", DIR_3, "" },
152     { __LINE__, FALSE, "\"test program.exe \"", DIR_4, "" },
153     { __LINE__, FALSE, "\" test program.exe\"", DIR_0, "" },
154     { __LINE__, FALSE, "\" test program.exe\"", DIR_1, "" },
155     { __LINE__, FALSE, "\" test program.exe\"", DIR_2, "" },
156     { __LINE__, FALSE, "\" test program.exe\"", DIR_3, "" },
157     { __LINE__, FALSE, "\" test program.exe\"", DIR_4, "" },
158     { __LINE__, TRUE, "test program.bat", DIR_0, s_sys_bat_file },
159     { __LINE__, TRUE, "test program.bat", DIR_1, s_sys_bat_file },
160     { __LINE__, TRUE, "test program.bat", DIR_2, s_sys_bat_file },
161     { __LINE__, TRUE, "test program.bat", DIR_3, s_win_bat_file },
162     { __LINE__, TRUE, "test program.bat", DIR_4, s_sys_bat_file },
163     { __LINE__, FALSE, "  test program.bat  ", DIR_0, "" },
164     { __LINE__, FALSE, "  test program.bat  ", DIR_1, "" },
165     { __LINE__, FALSE, "  test program.bat  ", DIR_2, "" },
166     { __LINE__, FALSE, "  test program.bat  ", DIR_3, "" },
167     { __LINE__, FALSE, "  test program.bat  ", DIR_4, "" },
168     { __LINE__, TRUE, "\"test program.bat\"", DIR_0, s_sys_bat_file },
169     { __LINE__, TRUE, "\"test program.bat\"", DIR_1, s_sys_bat_file },
170     { __LINE__, TRUE, "\"test program.bat\"", DIR_2, s_sys_bat_file },
171     { __LINE__, TRUE, "\"test program.bat\"", DIR_3, s_win_bat_file },
172     { __LINE__, TRUE, "\"test program.bat\"", DIR_4, s_sys_bat_file },
173     { __LINE__, TRUE, "shell32_apitest_sub.exe", DIR_0, s_sub_program },
174     { __LINE__, TRUE, "shell32_apitest_sub.exe", DIR_1, "shell32_apitest_sub.exe" },
175     { __LINE__, FALSE, "shell32_apitest_sub.exe", DIR_2, "" },
176     { __LINE__, FALSE, "shell32_apitest_sub.exe", DIR_3, "" },
177     { __LINE__, FALSE, "shell32_apitest_sub.exe", DIR_4, "" },
178     { __LINE__, TRUE, "test file.txt", DIR_0, s_sys_notepad },
179     { __LINE__, TRUE, "test file.txt", DIR_1, s_sys_notepad },
180     { __LINE__, TRUE, "test file.txt", DIR_2, s_sys_notepad },
181     { __LINE__, TRUE, "test file.txt", DIR_3, s_sys_notepad },
182     { __LINE__, TRUE, "test file.txt", DIR_4, s_sys_notepad },
183     { __LINE__, FALSE, "invalid file.txt", DIR_0, "" },
184     { __LINE__, FALSE, "invalid file.txt", DIR_1, "" },
185     { __LINE__, FALSE, "invalid file.txt", DIR_2, "" },
186     { __LINE__, FALSE, "invalid file.txt", DIR_3, "" },
187     { __LINE__, FALSE, "invalid file.txt", DIR_4, "" },
188 };
189 
190 static void DoTestEntry(const TEST_ENTRY *pEntry)
191 {
192     char result[MAX_PATH];
193     result[0] = 0;
194     BOOL ret = ((INT_PTR)FindExecutableA(pEntry->file, pEntry->dir, result) > 32);
195     ok(ret == pEntry->ret, "Line %u: ret expected %d, got %d\n", pEntry->lineno, pEntry->ret, ret);
196 
197     GetLongPathNameA(result, result, _countof(result));
198 
199     ok(lstrcmpiA(result, pEntry->result) == 0,
200        "Line %u: result expected '%s', got '%s'\n",
201        pEntry->lineno, pEntry->result, result);
202 }
203 
204 START_TEST(FindExecutable)
205 {
206     if (!GetSubProgramPath())
207     {
208         skip("shell32_apitest_sub.exe not found\n");
209         return;
210     }
211 
212     char cur_dir[MAX_PATH];
213     GetCurrentDirectoryA(_countof(cur_dir), cur_dir);
214     if (PathIsRootA(cur_dir))
215     {
216         skip("Don't use this program at root directory\n");
217         return;
218     }
219 
220     GetWindowsDirectoryA(s_win_dir, _countof(s_win_dir));
221 
222     GetWindowsDirectoryA(s_win_notepad, _countof(s_win_notepad));
223     PathAppendA(s_win_notepad, "notepad.exe");
224 
225     GetSystemDirectoryA(s_sys_notepad, _countof(s_sys_notepad));
226     PathAppendA(s_sys_notepad, "notepad.exe");
227 
228     GetWindowsDirectoryA(s_win_test_exe, _countof(s_win_test_exe));
229     PathAppendA(s_win_test_exe, "test program.exe");
230     BOOL ret = CopyFileA(s_sub_program, s_win_test_exe, FALSE);
231     if (!ret)
232     {
233         skip("Please retry with admin rights\n");
234         return;
235     }
236 
237     GetSystemDirectoryA(s_sys_test_exe, _countof(s_sys_test_exe));
238     PathAppendA(s_sys_test_exe, "test program.exe");
239     ok_int(CopyFileA(s_sub_program, s_sys_test_exe, FALSE), TRUE);
240 
241     GetWindowsDirectoryA(s_win_bat_file, _countof(s_win_bat_file));
242     PathAppendA(s_win_bat_file, "test program.bat");
243     fclose(fopen(s_win_bat_file, "wb"));
244     ok_int(PathFileExistsA(s_win_bat_file), TRUE);
245 
246     GetSystemDirectoryA(s_sys_bat_file, _countof(s_sys_bat_file));
247     PathAppendA(s_sys_bat_file, "test program.bat");
248     fclose(fopen(s_sys_bat_file, "wb"));
249     ok_int(PathFileExistsA(s_sys_bat_file), TRUE);
250 
251     GetWindowsDirectoryA(s_win_txt_file, _countof(s_win_txt_file));
252     PathAppendA(s_win_txt_file, "test file.txt");
253     fclose(fopen(s_win_txt_file, "wb"));
254     ok_int(PathFileExistsA(s_win_txt_file), TRUE);
255 
256     GetSystemDirectoryA(s_sys_txt_file, _countof(s_sys_txt_file));
257     PathAppendA(s_sys_txt_file, "test file.txt");
258     fclose(fopen(s_sys_txt_file, "wb"));
259     ok_int(PathFileExistsA(s_sys_txt_file), TRUE);
260 
261     for (UINT iTest = 0; iTest < _countof(s_entries); ++iTest)
262     {
263         DoTestEntry(&s_entries[iTest]);
264     }
265 
266     DeleteFileA(s_win_test_exe);
267     DeleteFileA(s_sys_test_exe);
268     DeleteFileA(s_win_bat_file);
269     DeleteFileA(s_sys_bat_file);
270     DeleteFileA(s_win_txt_file);
271     DeleteFileA(s_sys_txt_file);
272 
273     DoWaitForWindow(CLASSNAME, CLASSNAME, TRUE, TRUE);
274 }
275