ntoskrnl.exe/tests: Add some IOCTL_HID_WRITE_REPORT tests.
[wine.git] / programs / find / tests / find.c
blobb7c2d7b77c44bb2933f3182978e262fe96222cfb
1 /*
2 * Copyright 2019 Fabian Maurer
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.
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.
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
19 #include <windows.h>
20 #include <stdio.h>
22 #include "wine/heap.h"
23 #include "wine/test.h"
25 static void read_all_from_handle(HANDLE handle, BYTE **str, int *len)
27 char buffer[4096];
28 DWORD bytes_read;
29 DWORD length = 0;
30 BYTE *ret = heap_alloc_zero(1);
32 for (;;)
34 BOOL success = ReadFile(handle, buffer, sizeof(buffer), &bytes_read, NULL);
35 if (!success || !bytes_read)
36 break;
37 ret = heap_realloc(ret, length + bytes_read);
38 memcpy((char *)ret + length, buffer, bytes_read);
39 length += bytes_read;
42 *str = ret;
43 *len = length;
46 static void write_to_handle(HANDLE handle, const BYTE *str, int len)
48 DWORD dummy;
49 WriteFile(handle, str, len, &dummy, NULL);
52 static void check_find_output(const BYTE *child_output, int child_output_len, const BYTE *out_expected, int out_expected_len, const char *file, int line)
54 BOOL strings_are_equal;
55 char *child_output_copy;
56 char *out_expected_copy;
57 int i, pos;
59 if (child_output_len != out_expected_len)
60 strings_are_equal = FALSE;
61 else
63 strings_are_equal = memcmp(child_output, out_expected, out_expected_len) == 0;
66 /* Format strings for debug printing */
67 child_output_copy = heap_alloc_zero(child_output_len * 4 + 1);
68 out_expected_copy = heap_alloc_zero(out_expected_len * 4 + 1);
70 for (i = 0, pos = 0; i < child_output_len; i++)
72 if (child_output[i] && child_output[i] != '\r' && child_output[i] < 128)
73 child_output_copy[pos++] = child_output[i];
74 else
76 sprintf(&child_output_copy[pos], "\\x%02x", child_output[i]);
77 pos += 4;
81 for (i = 0, pos = 0; i < out_expected_len; i++)
83 if (out_expected[i] && out_expected[i] != '\r' && out_expected[i] < 128)
84 out_expected_copy[pos++] = out_expected[i];
85 else
87 sprintf(&out_expected_copy[pos], "\\x%02x", out_expected[i]);
88 pos += 4;
93 ok_(file, line)(strings_are_equal, "\n#################### Expected:\n"
94 "%s\n"
95 "#################### But got:\n"
96 "%s\n"
97 "####################\n",
98 out_expected_copy, child_output_copy);
100 heap_free(child_output_copy);
101 heap_free(out_expected_copy);
104 static void mangle_text(const BYTE *input, int input_len, BYTE *output, int output_max, int *output_len) {
105 WCHAR buffer[200];
106 int count_wchar;
108 /* Check for UTF-16 LE BOM */
109 if (input[0] == 0xFF && input[1] == 0xFE)
111 int buffer_count = 0;
112 int i;
114 /* Copy utf16le into a WCHAR array, stripping the BOM */
115 for (i = 2; i < input_len; i += 2)
117 buffer[buffer_count++] = input[i] + (input[i + 1] << 8);
120 *output_len = WideCharToMultiByte(GetConsoleCP(), 0, buffer, buffer_count, (char *)output, output_max, NULL, NULL);
122 else
124 count_wchar = MultiByteToWideChar(GetConsoleCP(), 0, (char *)input, input_len, buffer, ARRAY_SIZE(buffer));
125 *output_len = WideCharToMultiByte(GetConsoleCP(), 0, buffer, count_wchar, (char *)output, output_max, NULL, NULL);
129 static void run_find_stdin_(const WCHAR *commandline, const BYTE *input, int input_len, const BYTE *out_expected, int out_expected_len, int exitcode_expected, const char *file, int line)
131 HANDLE child_stdin_read;
132 HANDLE child_stdout_write;
133 HANDLE parent_stdin_write;
134 HANDLE parent_stdout_read;
135 STARTUPINFOW startup_info = {0};
136 SECURITY_ATTRIBUTES security_attributes;
137 PROCESS_INFORMATION process_info = {0};
138 BYTE *child_output = NULL;
139 int child_output_len;
140 WCHAR cmd[4096];
141 DWORD exitcode;
143 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
144 security_attributes.bInheritHandle = TRUE;
145 security_attributes.lpSecurityDescriptor = NULL;
147 CreatePipe(&parent_stdout_read, &child_stdout_write, &security_attributes, 0);
148 CreatePipe(&child_stdin_read, &parent_stdin_write, &security_attributes, 0);
150 SetHandleInformation(parent_stdout_read, HANDLE_FLAG_INHERIT, 0);
151 SetHandleInformation(parent_stdin_write, HANDLE_FLAG_INHERIT, 0);
153 startup_info.cb = sizeof(STARTUPINFOW);
154 startup_info.hStdInput = child_stdin_read;
155 startup_info.hStdOutput = child_stdout_write;
156 startup_info.hStdError = NULL;
157 startup_info.dwFlags |= STARTF_USESTDHANDLES;
159 wsprintfW(cmd, L"find.exe %s", commandline);
161 CreateProcessW(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info);
162 CloseHandle(child_stdin_read);
163 CloseHandle(child_stdout_write);
165 write_to_handle(parent_stdin_write, input, input_len);
166 CloseHandle(parent_stdin_write);
168 read_all_from_handle(parent_stdout_read, &child_output, &child_output_len);
169 CloseHandle(parent_stdout_read);
171 GetExitCodeProcess(process_info.hProcess, &exitcode);
172 CloseHandle(process_info.hProcess);
173 CloseHandle(process_info.hThread);
175 check_find_output(child_output, child_output_len, out_expected, out_expected_len, file, line);
177 ok_(file, line)(exitcode == exitcode_expected, "Expected exitcode %d, got %d\n", exitcode_expected, exitcode);
179 heap_free(child_output);
182 static void run_find_file_(const WCHAR *commandline, const BYTE *input, int input_len, const BYTE *out_expected, int out_expected_len, int exitcode_expected, const char *file, int line)
184 char path_temp_file[MAX_PATH];
185 char path_temp_dir[MAX_PATH];
186 HANDLE handle_file;
187 WCHAR commandline_new[MAX_PATH];
188 BYTE *out_expected_new;
189 char header[MAX_PATH];
190 int header_len;
192 GetTempPathA(ARRAY_SIZE(path_temp_dir), path_temp_dir);
193 GetTempFileNameA(path_temp_dir, "", 0, path_temp_file);
194 handle_file = CreateFileA(path_temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
195 write_to_handle(handle_file, input, input_len);
196 CloseHandle(handle_file);
198 wsprintfW(commandline_new, L"%s %hs", commandline, path_temp_file);
200 CharUpperA(path_temp_file);
201 wsprintfA(header, "\r\n---------- %s\r\n", path_temp_file);
202 header_len = lstrlenA(header);
203 out_expected_new = heap_alloc(header_len + out_expected_len);
204 memcpy(out_expected_new, header, header_len);
205 memcpy(out_expected_new + header_len, out_expected, out_expected_len);
207 run_find_stdin_(commandline_new, (BYTE*)"", 0, out_expected_new, header_len + out_expected_len, exitcode_expected, file, line);
208 heap_free(out_expected_new);
210 DeleteFileA(path_temp_file);
213 #define run_find_stdin_str(commandline, input, out_expected, exitcode_expected) \
214 run_find_str_(commandline, input, out_expected, exitcode_expected, 0, __FILE__, __LINE__)
216 #define run_find_file_str(commandline, input, out_expected, exitcode_expected) \
217 run_find_str_(commandline, input, out_expected, exitcode_expected, 1, __FILE__, __LINE__)
219 static void run_find_str_(const char *commandline, const char *input, const char *out_expected, int exitcode_expected, BOOL is_file, const char *file, int line)
221 WCHAR *commandlineW;
222 int len_commandlineW;
224 /* Turn commandline into WCHAR string */
225 len_commandlineW = MultiByteToWideChar(CP_UTF8, 0, commandline, -1, 0, 0);
226 commandlineW = heap_alloc(len_commandlineW * sizeof(WCHAR));
227 MultiByteToWideChar(CP_UTF8, 0, commandline, -1, commandlineW, len_commandlineW);
229 if (is_file)
230 run_find_file_(commandlineW, (BYTE *)input, lstrlenA(input), (BYTE *)out_expected, lstrlenA(out_expected), exitcode_expected, file, line);
231 else
232 run_find_stdin_(commandlineW, (BYTE *)input, lstrlenA(input), (BYTE *)out_expected, lstrlenA(out_expected), exitcode_expected, file, line);
233 heap_free(commandlineW);
236 #define run_find_stdin_unicode(input, out_expected, exitcode_expected) \
237 run_find_unicode_(input, sizeof(input), out_expected, sizeof(out_expected), exitcode_expected, 0, __FILE__, __LINE__)
239 #define run_find_file_unicode(input, out_expected, exitcode_expected) \
240 run_find_unicode_(input, sizeof(input), out_expected, sizeof(out_expected), exitcode_expected, 1, __FILE__, __LINE__)
242 static void run_find_unicode_(const BYTE *input, int input_len, const BYTE *out_expected, int out_expected_len, int exitcode_expected, BOOL is_file, const char *file, int line)
244 /* Need "test" as char and quoted wchar */
245 static const WCHAR wstr_quoted_test[] = L"\"test\"";
246 static const char str_test[] = "test";
248 BYTE out_expected_mangled[200] = {0};
249 int out_expected_mangled_len;
251 mangle_text(out_expected, out_expected_len, out_expected_mangled, ARRAY_SIZE(out_expected_mangled), &out_expected_mangled_len);
253 /* Mangling can destroy the test string, so check manually if it matches */
254 if (!strstr((char*)out_expected_mangled, str_test))
256 out_expected_mangled_len = 0;
257 exitcode_expected = 1;
260 if (is_file)
261 run_find_file_(wstr_quoted_test, input, input_len, out_expected_mangled, out_expected_mangled_len, exitcode_expected, file, line);
262 else
263 run_find_stdin_(wstr_quoted_test, input, input_len, out_expected_mangled, out_expected_mangled_len, exitcode_expected, file, line);
266 static void run_find_file_multi(void)
268 char path_temp_file1[MAX_PATH];
269 char path_temp_file2[MAX_PATH];
270 char path_temp_file3[MAX_PATH];
271 char path_temp_dir[MAX_PATH];
272 HANDLE handle_file;
273 WCHAR commandline_new[MAX_PATH];
274 char out_expected[500];
275 const char* input = "ab\nbd";
277 GetTempPathA(ARRAY_SIZE(path_temp_dir), path_temp_dir);
278 GetTempFileNameA(path_temp_dir, "", 0, path_temp_file1);
279 GetTempFileNameA(path_temp_dir, "", 0, path_temp_file2);
280 GetTempFileNameA(path_temp_dir, "", 0, path_temp_file3);
281 handle_file = CreateFileA(path_temp_file1, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
282 write_to_handle(handle_file, (BYTE*)input, strlen(input));
283 CloseHandle(handle_file);
284 handle_file = CreateFileA(path_temp_file2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
285 write_to_handle(handle_file, (BYTE*)input, strlen(input));
286 CloseHandle(handle_file);
288 wsprintfW(commandline_new, L"\"b\" C:\\doesnotexist1 %hs C:\\doesnotexist1 %hs C:\\doesnotexist1 %hs", path_temp_file1, path_temp_file2, path_temp_file3);
290 /* Keep file open during the test */
291 handle_file = CreateFileA(path_temp_file3, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
293 CharUpperA(path_temp_file1);
294 CharUpperA(path_temp_file2);
295 CharUpperA(path_temp_file3);
296 wsprintfA(out_expected,
297 "File not found - C:\\DOESNOTEXIST1\r\n"
298 "\r\n---------- %s\r\n"
299 "ab\r\nbd\r\n"
300 "File not found - C:\\DOESNOTEXIST1\r\n"
301 "\r\n---------- %s\r\n"
302 "ab\r\nbd\r\n"
303 "File not found - C:\\DOESNOTEXIST1\r\n"
304 "File not found - %s\r\n",
305 path_temp_file1, path_temp_file2, path_temp_file3);
307 run_find_stdin_(commandline_new, (BYTE*)"", 0, (BYTE*)out_expected, strlen(out_expected), 0, __FILE__, __LINE__);
309 CloseHandle(handle_file);
310 DeleteFileA(path_temp_file1);
311 DeleteFileA(path_temp_file2);
312 DeleteFileA(path_temp_file3);
315 static void test_errors(void)
317 run_find_stdin_str("", "", "FIND: Parameter format not correct\r\n", 2);
318 todo_wine /* Quotes are not properly passed into wine yet */
319 run_find_stdin_str("test", "", "FIND: Parameter format not correct\r\n", 2);
320 todo_wine /* Quotes are not properly passed into wine yet */
321 run_find_stdin_str("\"test", "", "FIND: Parameter format not correct\r\n", 2);
322 run_find_stdin_str("\"test\" /XYZ", "", "FIND: Invalid switch\r\n", 2);
323 run_find_stdin_str("\"test\" C:\\doesnotexist.dat", "", "File not found - C:\\DOESNOTEXIST.DAT\r\n", 1);
326 static void test_singleline_without_switches(void)
328 run_find_stdin_str("\"\"", "test", "", 1);
329 run_find_stdin_str("\"test\"", "", "", 1);
330 run_find_stdin_str("\"test\"", "test", "test\r\n", 0);
331 run_find_stdin_str("\"test\"", "test2", "test2\r\n", 0);
332 run_find_stdin_str("\"test\"", "test\r2", "test\r2\r\n", 0);
333 run_find_stdin_str("\"test2\"", "test", "", 1);
336 static void test_multiline(void)
338 /* Newline in input shouldn't work */
339 run_find_stdin_str("\"t1\r\nt1\"", "t1\r\nt1", "", 1);
340 run_find_stdin_str("\"t1\nt1\"", "t1\nt1", "", 1);
342 /* Newline should always be displayed as \r\n */
343 run_find_stdin_str("\"test1\"", "test1\ntest2", "test1\r\n", 0);
344 run_find_stdin_str("\"test1\"", "test1\r\ntest2", "test1\r\n", 0);
346 /* Test with empty line */
347 run_find_stdin_str("\"test1\"", "test1\n\ntest2", "test1\r\n", 0);
349 /* Two strings to be found */
350 run_find_stdin_str("\"test\"", "junk1\ntest1\ntest2\r\njunk", "test1\r\ntest2\r\n", 0);
353 static const BYTE str_empty[] = {};
354 static const BYTE str_jap_shiftjis[] = { 0x8E,0x84,0x82,0xCD,'t','e','s','t','!','\r','\n' };
355 static const BYTE str_jap_utf8_bom[] = { 0xEF,0xBB,0xBF,0xE7,0xA7,0x81,0xE3,0x81,0xAF,'j','a','p','t','e','s','t','!','\r','\n' };
356 static const BYTE str_jap_utf8_nobom[] = { 0xE7,0xA7,0x81,0xE3,0x81,0xAF,'j','a','p','t','e','s','t','!','\r','\n' };
357 static const BYTE str_jap_utf16le_bom[] = { 0xFF,0xFE,0xC1,0x79,0x6F,0x30,'t',0,'e',0,'s',0,'t',0,'!',0,'\r',0,'\n',0 };
358 static const BYTE str_jap_utf16le_nobom[] = { 0xC1,0x79,0x6F,0x30,'t',0,'e',0,'s',0,'t',0,'!',0 };
359 static const BYTE str_jap_utf16be_bom[] = { 0xFE,0xFF,0x79,0xC1,0x30,0x6F,0,'t',0,'e',0,'s',0,'t',0,'!' };
360 static const BYTE str_jap_utf16be_nobom[] = { 0x79,0xC1,0x30,0x6F,0,'t',0,'e',0,'s',0,'t',0,'!' };
361 static const BYTE str_rus_utf8_bom[] = { 0xEF,0xBB,0xBF,0xD0,0xBF,0xD1,0x80,0xD0,0xB8,0xD0,0xB2,0xD0,0xB5,0xD1,0x82,0x20,'t','e','s','t','!','\r','\n' };
362 static const BYTE str_rus_utf8_nobom[] = { 0xD0,0xBF,0xD1,0x80,0xD0,0xB8,0xD0,0xB2,0xD0,0xB5,0xD1,0x82,0x20,'t','e','s','t','!','\r','\n' };
363 static const BYTE str_en_utf8_bom[] = { 0xEF,0xBB,0xBF,'e','n','t','e','s','t','\r','\n' };
364 static const BYTE str_en_utf8_nobom[] = { 'e','n','t','e','s','t','\r','\n' };
366 static void test_unicode_support_stdin(void)
368 /* Test unicode support on STDIN
369 * Those depend on the active codepage - e.g. 932 (japanese) behaves different from 1252 (latin)
370 * All unicode tests must check for the string "test".
373 /* Test UTF-8 BOM */
374 run_find_stdin_unicode(str_en_utf8_nobom, str_en_utf8_nobom, 0);
375 run_find_stdin_unicode(str_en_utf8_bom, str_en_utf8_bom, 0);
377 /* Test russian characters */
378 run_find_stdin_unicode(str_rus_utf8_bom, str_rus_utf8_bom, 0);
379 run_find_stdin_unicode(str_rus_utf8_nobom, str_rus_utf8_nobom, 0);
381 /* Test japanese characters */
382 run_find_stdin_unicode(str_jap_utf8_nobom, str_jap_utf8_nobom, 0);
383 run_find_stdin_unicode(str_jap_utf8_bom, str_jap_utf8_bom, 0);
384 run_find_stdin_unicode(str_jap_shiftjis, str_jap_shiftjis, 0);
386 /* Test unsupported encodings */
387 run_find_stdin_unicode(str_jap_utf16le_nobom, str_empty, 1);
388 run_find_stdin_unicode(str_jap_utf16be_bom, str_empty, 1);
389 run_find_stdin_unicode(str_jap_utf16be_nobom, str_empty, 1);
391 /* Test utf16le */
392 todo_wine
393 run_find_stdin_unicode(str_jap_utf16le_bom, str_jap_utf16le_bom, 0);
396 static void test_file_search(void)
398 run_find_file_str("\"\"", "test", "", 1);
399 run_find_file_str("\"test\"", "", "", 1);
400 run_find_file_str("\"test\"", "test", "test\r\n", 0);
401 run_find_file_str("\"test\"", "test2", "test2\r\n", 0);
402 run_find_file_str("\"test\"", "test\r2", "test\r2\r\n", 0);
403 run_find_file_str("\"test2\"", "test", "", 1);
404 run_find_file_str("\"test\"", "test\nother\ntest2\ntest3", "test\r\ntest2\r\ntest3\r\n", 0);
407 static void test_unicode_support_file(void)
409 /* Test unicode support on files */
411 /* Test UTF-8 BOM */
412 run_find_file_unicode(str_en_utf8_nobom, str_en_utf8_nobom, 0);
413 run_find_file_unicode(str_en_utf8_bom, str_en_utf8_bom, 0);
415 /* Test russian characters */
416 run_find_file_unicode(str_rus_utf8_bom, str_rus_utf8_bom, 0);
417 run_find_file_unicode(str_rus_utf8_nobom, str_rus_utf8_nobom, 0);
419 /* Test japanese characters */
420 run_find_file_unicode(str_jap_utf8_nobom, str_jap_utf8_nobom, 0);
421 run_find_file_unicode(str_jap_utf8_bom, str_jap_utf8_bom, 0);
422 run_find_file_unicode(str_jap_shiftjis, str_jap_shiftjis, 0);
424 /* Test unsupported encodings */
425 run_find_file_unicode(str_jap_utf16le_nobom, str_empty, 1);
426 run_find_file_unicode(str_jap_utf16be_bom, str_empty, 1);
427 run_find_file_unicode(str_jap_utf16be_nobom, str_empty, 1);
429 /* Test utf16le */
430 todo_wine
431 run_find_file_unicode(str_jap_utf16le_bom, str_jap_utf16le_bom, 0);
435 START_TEST(find)
437 if (PRIMARYLANGID(GetUserDefaultUILanguage()) != LANG_ENGLISH)
439 skip("Error tests only work with english locale.\n");
441 else
443 test_errors();
444 run_find_file_multi();
446 test_singleline_without_switches();
447 test_multiline();
448 test_unicode_support_stdin();
449 test_file_search();
450 test_unicode_support_file();