Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/find/tests/find.c
5968 views
1
/*
2
* Copyright 2019 Fabian Maurer
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 <windows.h>
20
#include <stdio.h>
21
22
#include "wine/test.h"
23
24
static void read_all_from_handle(HANDLE handle, BYTE **str, int *len)
25
{
26
char buffer[4096];
27
DWORD bytes_read;
28
DWORD length = 0;
29
BYTE *ret = calloc(1, 1);
30
31
for (;;)
32
{
33
BOOL success = ReadFile(handle, buffer, sizeof(buffer), &bytes_read, NULL);
34
if (!success || !bytes_read)
35
break;
36
ret = realloc(ret, length + bytes_read);
37
memcpy((char *)ret + length, buffer, bytes_read);
38
length += bytes_read;
39
}
40
41
*str = ret;
42
*len = length;
43
}
44
45
static void write_to_handle(HANDLE handle, const BYTE *str, int len)
46
{
47
DWORD dummy;
48
WriteFile(handle, str, len, &dummy, NULL);
49
}
50
51
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)
52
{
53
BOOL strings_are_equal;
54
char *child_output_copy;
55
char *out_expected_copy;
56
int i, pos;
57
58
if (child_output_len != out_expected_len)
59
strings_are_equal = FALSE;
60
else
61
{
62
strings_are_equal = memcmp(child_output, out_expected, out_expected_len) == 0;
63
}
64
65
/* Format strings for debug printing */
66
child_output_copy = calloc(1, child_output_len * 4 + 1);
67
out_expected_copy = calloc(1, out_expected_len * 4 + 1);
68
69
for (i = 0, pos = 0; i < child_output_len; i++)
70
{
71
if (child_output[i] && child_output[i] != '\r' && child_output[i] < 128)
72
child_output_copy[pos++] = child_output[i];
73
else
74
{
75
sprintf(&child_output_copy[pos], "\\x%02x", child_output[i]);
76
pos += 4;
77
}
78
}
79
80
for (i = 0, pos = 0; i < out_expected_len; i++)
81
{
82
if (out_expected[i] && out_expected[i] != '\r' && out_expected[i] < 128)
83
out_expected_copy[pos++] = out_expected[i];
84
else
85
{
86
sprintf(&out_expected_copy[pos], "\\x%02x", out_expected[i]);
87
pos += 4;
88
}
89
90
}
91
92
ok_(file, line)(strings_are_equal, "\n#################### Expected:\n"
93
"%s\n"
94
"#################### But got:\n"
95
"%s\n"
96
"####################\n",
97
out_expected_copy, child_output_copy);
98
99
free(child_output_copy);
100
free(out_expected_copy);
101
}
102
103
static void mangle_text(const BYTE *input, int input_len, BYTE *output, int output_max, int *output_len) {
104
WCHAR buffer[200];
105
int count_wchar;
106
107
/* Check for UTF-16 LE BOM */
108
if (input_len > 1 && input[0] == 0xFF && input[1] == 0xFE)
109
{
110
int buffer_count = 0;
111
int i;
112
113
/* Copy utf16le into a WCHAR array, stripping the BOM */
114
for (i = 2; i < input_len; i += 2)
115
{
116
buffer[buffer_count++] = input[i] + (input[i + 1] << 8);
117
}
118
119
*output_len = WideCharToMultiByte(GetConsoleCP(), 0, buffer, buffer_count, (char *)output, output_max, NULL, NULL);
120
}
121
else
122
{
123
count_wchar = MultiByteToWideChar(GetConsoleCP(), 0, (char *)input, input_len, buffer, ARRAY_SIZE(buffer));
124
*output_len = WideCharToMultiByte(GetConsoleCP(), 0, buffer, count_wchar, (char *)output, output_max, NULL, NULL);
125
}
126
}
127
128
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)
129
{
130
HANDLE child_stdin_read;
131
HANDLE child_stdout_write;
132
HANDLE parent_stdin_write;
133
HANDLE parent_stdout_read;
134
STARTUPINFOW startup_info = {0};
135
SECURITY_ATTRIBUTES security_attributes;
136
PROCESS_INFORMATION process_info = {0};
137
BYTE *child_output = NULL;
138
int child_output_len;
139
WCHAR cmd[4096];
140
DWORD exitcode;
141
142
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
143
security_attributes.bInheritHandle = TRUE;
144
security_attributes.lpSecurityDescriptor = NULL;
145
146
CreatePipe(&parent_stdout_read, &child_stdout_write, &security_attributes, 0);
147
CreatePipe(&child_stdin_read, &parent_stdin_write, &security_attributes, 0);
148
149
SetHandleInformation(parent_stdout_read, HANDLE_FLAG_INHERIT, 0);
150
SetHandleInformation(parent_stdin_write, HANDLE_FLAG_INHERIT, 0);
151
152
startup_info.cb = sizeof(STARTUPINFOW);
153
startup_info.hStdInput = child_stdin_read;
154
startup_info.hStdOutput = child_stdout_write;
155
startup_info.hStdError = NULL;
156
startup_info.dwFlags |= STARTF_USESTDHANDLES;
157
158
wsprintfW(cmd, L"find.exe %s", commandline);
159
160
CreateProcessW(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info);
161
CloseHandle(child_stdin_read);
162
CloseHandle(child_stdout_write);
163
164
write_to_handle(parent_stdin_write, input, input_len);
165
CloseHandle(parent_stdin_write);
166
167
read_all_from_handle(parent_stdout_read, &child_output, &child_output_len);
168
CloseHandle(parent_stdout_read);
169
170
GetExitCodeProcess(process_info.hProcess, &exitcode);
171
CloseHandle(process_info.hProcess);
172
CloseHandle(process_info.hThread);
173
174
check_find_output(child_output, child_output_len, out_expected, out_expected_len, file, line);
175
176
ok_(file, line)(exitcode == exitcode_expected, "Expected exitcode %d, got %ld\n", exitcode_expected, exitcode);
177
178
free(child_output);
179
}
180
181
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)
182
{
183
char path_temp_file[MAX_PATH];
184
char path_temp_dir[MAX_PATH];
185
HANDLE handle_file;
186
WCHAR commandline_new[MAX_PATH];
187
BYTE *out_expected_new;
188
char header[MAX_PATH];
189
int header_len;
190
191
GetTempPathA(ARRAY_SIZE(path_temp_dir), path_temp_dir);
192
GetTempFileNameA(path_temp_dir, "", 0, path_temp_file);
193
handle_file = CreateFileA(path_temp_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
194
write_to_handle(handle_file, input, input_len);
195
CloseHandle(handle_file);
196
197
wsprintfW(commandline_new, L"%s %hs", commandline, path_temp_file);
198
199
CharUpperA(path_temp_file);
200
wsprintfA(header, "\r\n---------- %s\r\n", path_temp_file);
201
header_len = lstrlenA(header);
202
out_expected_new = malloc(header_len + out_expected_len);
203
memcpy(out_expected_new, header, header_len);
204
memcpy(out_expected_new + header_len, out_expected, out_expected_len);
205
206
run_find_stdin_(commandline_new, (BYTE*)"", 0, out_expected_new, header_len + out_expected_len, exitcode_expected, file, line);
207
free(out_expected_new);
208
209
DeleteFileA(path_temp_file);
210
}
211
212
#define run_find_stdin_str(commandline, input, out_expected, exitcode_expected) \
213
run_find_str_(commandline, input, out_expected, exitcode_expected, 0, __FILE__, __LINE__)
214
215
#define run_find_file_str(commandline, input, out_expected, exitcode_expected) \
216
run_find_str_(commandline, input, out_expected, exitcode_expected, 1, __FILE__, __LINE__)
217
218
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)
219
{
220
WCHAR *commandlineW;
221
int len_commandlineW;
222
223
/* Turn commandline into WCHAR string */
224
len_commandlineW = MultiByteToWideChar(CP_UTF8, 0, commandline, -1, 0, 0);
225
commandlineW = malloc(len_commandlineW * sizeof(WCHAR));
226
MultiByteToWideChar(CP_UTF8, 0, commandline, -1, commandlineW, len_commandlineW);
227
228
if (is_file)
229
run_find_file_(commandlineW, (BYTE *)input, lstrlenA(input), (BYTE *)out_expected, lstrlenA(out_expected), exitcode_expected, file, line);
230
else
231
run_find_stdin_(commandlineW, (BYTE *)input, lstrlenA(input), (BYTE *)out_expected, lstrlenA(out_expected), exitcode_expected, file, line);
232
free(commandlineW);
233
}
234
235
#define run_find_stdin_unicode(input, out_expected, exitcode_expected) \
236
run_find_unicode_(input, sizeof(input), out_expected, sizeof(out_expected), exitcode_expected, 0, __FILE__, __LINE__)
237
238
#define run_find_file_unicode(input, out_expected, exitcode_expected) \
239
run_find_unicode_(input, sizeof(input), out_expected, sizeof(out_expected), exitcode_expected, 1, __FILE__, __LINE__)
240
241
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)
242
{
243
/* Need "test" as char and quoted wchar */
244
static const WCHAR wstr_quoted_test[] = L"\"test\"";
245
static const char str_test[] = "test";
246
247
BYTE out_expected_mangled[200] = {0};
248
int out_expected_mangled_len;
249
250
mangle_text(out_expected, out_expected_len, out_expected_mangled, ARRAY_SIZE(out_expected_mangled), &out_expected_mangled_len);
251
252
/* Mangling can destroy the test string, so check manually if it matches */
253
if (!strstr((char*)out_expected_mangled, str_test))
254
{
255
out_expected_mangled_len = 0;
256
exitcode_expected = 1;
257
}
258
259
if (is_file)
260
run_find_file_(wstr_quoted_test, input, input_len, out_expected_mangled, out_expected_mangled_len, exitcode_expected, file, line);
261
else
262
run_find_stdin_(wstr_quoted_test, input, input_len, out_expected_mangled, out_expected_mangled_len, exitcode_expected, file, line);
263
}
264
265
static void run_find_file_multi(void)
266
{
267
char path_temp_file1[MAX_PATH];
268
char path_temp_file2[MAX_PATH];
269
char path_temp_file3[MAX_PATH];
270
char path_temp_dir[MAX_PATH];
271
HANDLE handle_file;
272
WCHAR commandline_new[MAX_PATH];
273
char out_expected[500];
274
const char* input = "ab\nbd";
275
276
GetTempPathA(ARRAY_SIZE(path_temp_dir), path_temp_dir);
277
GetTempFileNameA(path_temp_dir, "", 0, path_temp_file1);
278
GetTempFileNameA(path_temp_dir, "", 0, path_temp_file2);
279
GetTempFileNameA(path_temp_dir, "", 0, path_temp_file3);
280
handle_file = CreateFileA(path_temp_file1, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
281
write_to_handle(handle_file, (BYTE*)input, strlen(input));
282
CloseHandle(handle_file);
283
handle_file = CreateFileA(path_temp_file2, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
284
write_to_handle(handle_file, (BYTE*)input, strlen(input));
285
CloseHandle(handle_file);
286
287
wsprintfW(commandline_new, L"\"b\" C:\\doesnotexist1 %hs C:\\doesnotexist1 %hs C:\\doesnotexist1 %hs", path_temp_file1, path_temp_file2, path_temp_file3);
288
289
/* Keep file open during the test */
290
handle_file = CreateFileA(path_temp_file3, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
291
292
CharUpperA(path_temp_file1);
293
CharUpperA(path_temp_file2);
294
CharUpperA(path_temp_file3);
295
wsprintfA(out_expected,
296
"File not found - C:\\DOESNOTEXIST1\r\n"
297
"\r\n---------- %s\r\n"
298
"ab\r\nbd\r\n"
299
"File not found - C:\\DOESNOTEXIST1\r\n"
300
"\r\n---------- %s\r\n"
301
"ab\r\nbd\r\n"
302
"File not found - C:\\DOESNOTEXIST1\r\n"
303
"File not found - %s\r\n",
304
path_temp_file1, path_temp_file2, path_temp_file3);
305
306
run_find_stdin_(commandline_new, (BYTE*)"", 0, (BYTE*)out_expected, strlen(out_expected), 0, __FILE__, __LINE__);
307
308
CloseHandle(handle_file);
309
DeleteFileA(path_temp_file1);
310
DeleteFileA(path_temp_file2);
311
DeleteFileA(path_temp_file3);
312
}
313
314
static void test_errors(void)
315
{
316
run_find_stdin_str("", "", "FIND: Parameter format not correct\r\n", 2);
317
todo_wine /* Quotes are not properly passed into wine yet */
318
run_find_stdin_str("test", "", "FIND: Parameter format not correct\r\n", 2);
319
todo_wine /* Quotes are not properly passed into wine yet */
320
run_find_stdin_str("\"test", "", "FIND: Parameter format not correct\r\n", 2);
321
run_find_stdin_str("\"test\" /XYZ", "", "FIND: Invalid switch\r\n", 2);
322
run_find_stdin_str("\"test\" C:\\doesnotexist.dat", "", "File not found - C:\\DOESNOTEXIST.DAT\r\n", 1);
323
}
324
325
static void test_singleline_without_switches(void)
326
{
327
run_find_stdin_str("\"\"", "test", "", 1);
328
run_find_stdin_str("\"test\"", "", "", 1);
329
run_find_stdin_str("\"test\"", "test", "test\r\n", 0);
330
run_find_stdin_str("\"test\"", "test2", "test2\r\n", 0);
331
run_find_stdin_str("\"test\"", "test\r2", "test\r2\r\n", 0);
332
run_find_stdin_str("\"test2\"", "test", "", 1);
333
}
334
335
static void test_multiline(void)
336
{
337
/* Newline in input shouldn't work */
338
run_find_stdin_str("\"t1\r\nt1\"", "t1\r\nt1", "", 1);
339
run_find_stdin_str("\"t1\nt1\"", "t1\nt1", "", 1);
340
341
/* Newline should always be displayed as \r\n */
342
run_find_stdin_str("\"test1\"", "test1\ntest2", "test1\r\n", 0);
343
run_find_stdin_str("\"test1\"", "test1\r\ntest2", "test1\r\n", 0);
344
345
/* Test with empty line */
346
run_find_stdin_str("\"test1\"", "test1\n\ntest2", "test1\r\n", 0);
347
348
/* Two strings to be found */
349
run_find_stdin_str("\"test\"", "junk1\ntest1\ntest2\r\njunk", "test1\r\ntest2\r\n", 0);
350
}
351
352
static const BYTE str_empty[] = {};
353
static const BYTE str_jap_shiftjis[] = { 0x8E,0x84,0x82,0xCD,'t','e','s','t','!','\r','\n' };
354
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' };
355
static const BYTE str_jap_utf8_nobom[] = { 0xE7,0xA7,0x81,0xE3,0x81,0xAF,'j','a','p','t','e','s','t','!','\r','\n' };
356
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 };
357
static const BYTE str_jap_utf16le_nobom[] = { 0xC1,0x79,0x6F,0x30,'t',0,'e',0,'s',0,'t',0,'!',0 };
358
static const BYTE str_jap_utf16be_bom[] = { 0xFE,0xFF,0x79,0xC1,0x30,0x6F,0,'t',0,'e',0,'s',0,'t',0,'!' };
359
static const BYTE str_jap_utf16be_nobom[] = { 0x79,0xC1,0x30,0x6F,0,'t',0,'e',0,'s',0,'t',0,'!' };
360
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' };
361
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' };
362
static const BYTE str_en_utf8_bom[] = { 0xEF,0xBB,0xBF,'e','n','t','e','s','t','\r','\n' };
363
static const BYTE str_en_utf8_nobom[] = { 'e','n','t','e','s','t','\r','\n' };
364
365
static void test_unicode_support_stdin(void)
366
{
367
/* Test unicode support on STDIN
368
* Those depend on the active codepage - e.g. 932 (japanese) behaves different from 1252 (latin)
369
* All unicode tests must check for the string "test".
370
*/
371
372
/* Test UTF-8 BOM */
373
run_find_stdin_unicode(str_en_utf8_nobom, str_en_utf8_nobom, 0);
374
run_find_stdin_unicode(str_en_utf8_bom, str_en_utf8_bom, 0);
375
376
/* Test russian characters */
377
run_find_stdin_unicode(str_rus_utf8_bom, str_rus_utf8_bom, 0);
378
run_find_stdin_unicode(str_rus_utf8_nobom, str_rus_utf8_nobom, 0);
379
380
/* Test japanese characters */
381
run_find_stdin_unicode(str_jap_utf8_nobom, str_jap_utf8_nobom, 0);
382
run_find_stdin_unicode(str_jap_utf8_bom, str_jap_utf8_bom, 0);
383
run_find_stdin_unicode(str_jap_shiftjis, str_jap_shiftjis, 0);
384
385
/* Test unsupported encodings */
386
run_find_stdin_unicode(str_jap_utf16le_nobom, str_empty, 1);
387
run_find_stdin_unicode(str_jap_utf16be_bom, str_empty, 1);
388
run_find_stdin_unicode(str_jap_utf16be_nobom, str_empty, 1);
389
390
/* Test utf16le */
391
todo_wine
392
run_find_stdin_unicode(str_jap_utf16le_bom, str_jap_utf16le_bom, 0);
393
}
394
395
static void test_file_search(void)
396
{
397
run_find_file_str("\"\"", "test", "", 1);
398
run_find_file_str("\"test\"", "", "", 1);
399
run_find_file_str("\"test\"", "test", "test\r\n", 0);
400
run_find_file_str("\"test\"", "test2", "test2\r\n", 0);
401
run_find_file_str("\"test\"", "test\r2", "test\r2\r\n", 0);
402
run_find_file_str("\"test2\"", "test", "", 1);
403
run_find_file_str("\"test\"", "test\nother\ntest2\ntest3", "test\r\ntest2\r\ntest3\r\n", 0);
404
}
405
406
static void test_unicode_support_file(void)
407
{
408
/* Test unicode support on files */
409
410
/* Test UTF-8 BOM */
411
run_find_file_unicode(str_en_utf8_nobom, str_en_utf8_nobom, 0);
412
run_find_file_unicode(str_en_utf8_bom, str_en_utf8_bom, 0);
413
414
/* Test russian characters */
415
run_find_file_unicode(str_rus_utf8_bom, str_rus_utf8_bom, 0);
416
run_find_file_unicode(str_rus_utf8_nobom, str_rus_utf8_nobom, 0);
417
418
/* Test japanese characters */
419
run_find_file_unicode(str_jap_utf8_nobom, str_jap_utf8_nobom, 0);
420
run_find_file_unicode(str_jap_utf8_bom, str_jap_utf8_bom, 0);
421
run_find_file_unicode(str_jap_shiftjis, str_jap_shiftjis, 0);
422
423
/* Test unsupported encodings */
424
run_find_file_unicode(str_jap_utf16le_nobom, str_empty, 1);
425
run_find_file_unicode(str_jap_utf16be_bom, str_empty, 1);
426
run_find_file_unicode(str_jap_utf16be_nobom, str_empty, 1);
427
428
/* Test utf16le */
429
todo_wine
430
run_find_file_unicode(str_jap_utf16le_bom, str_jap_utf16le_bom, 0);
431
}
432
433
434
START_TEST(find)
435
{
436
if (PRIMARYLANGID(GetUserDefaultUILanguage()) != LANG_ENGLISH)
437
{
438
skip("Error tests only work with english locale.\n");
439
}
440
else
441
{
442
test_errors();
443
run_find_file_multi();
444
}
445
test_singleline_without_switches();
446
test_multiline();
447
test_unicode_support_stdin();
448
test_file_search();
449
test_unicode_support_file();
450
}
451
452