Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/fc/tests/fc.c
4389 views
1
/*
2
* Copyright 2024 Hans Leidekker for CodeWeavers
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 <stdarg.h>
20
#include <windef.h>
21
#include <winbase.h>
22
#include <winnls.h>
23
#include "wine/test.h"
24
25
#define MAX_BUF 512
26
static char tmpfile1[MAX_PATH], tmpfile2[MAX_PATH], stdout_buf[MAX_BUF], stderr_buf[MAX_BUF];
27
static DWORD stdout_size, stderr_size;
28
29
static void read_all_from_handle( HANDLE handle, char *buf, DWORD *size )
30
{
31
char tmp[32];
32
DWORD bytes_read;
33
34
memset( buf, 0, MAX_BUF );
35
*size = 0;
36
for (;;)
37
{
38
BOOL success = ReadFile( handle, tmp, sizeof(tmp), &bytes_read, NULL );
39
if (!success || !bytes_read) break;
40
if (*size + bytes_read > MAX_BUF)
41
{
42
ok( FALSE, "insufficient buffer\n" );
43
break;
44
}
45
memcpy( buf + *size, tmp, bytes_read );
46
*size += bytes_read;
47
}
48
}
49
50
static void create_temp_file( char *tmpfile, const char *prefix )
51
{
52
char tmpdir[MAX_PATH];
53
HANDLE handle;
54
55
GetTempPathA( sizeof(tmpdir), tmpdir );
56
GetTempFileNameA( tmpdir, prefix, 0, tmpfile );
57
handle = CreateFileA( tmpfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
58
CloseHandle( handle );
59
}
60
61
static void write_to_file( const char *filename, const char *str )
62
{
63
DWORD dummy;
64
HANDLE handle = CreateFileA( filename, GENERIC_WRITE, 0, NULL, TRUNCATE_EXISTING, 0, NULL );
65
WriteFile( handle, str, strlen(str), &dummy, NULL );
66
CloseHandle( handle );
67
}
68
69
static DWORD run_fc( const char *data1, const char *data2 )
70
{
71
HANDLE parent_stdout_read, parent_stderr_read, child_stdout_write, child_stderr_write;
72
SECURITY_ATTRIBUTES security_attrs = {0};
73
PROCESS_INFORMATION process_info = {0};
74
STARTUPINFOA startup_info = {0};
75
char cmd[4096];
76
DWORD exitcode;
77
BOOL ret;
78
79
write_to_file( tmpfile1, data1 );
80
write_to_file( tmpfile2, data2 );
81
82
security_attrs.nLength = sizeof(security_attrs);
83
security_attrs.bInheritHandle = TRUE;
84
85
CreatePipe( &parent_stdout_read, &child_stdout_write, &security_attrs, 0 );
86
CreatePipe( &parent_stderr_read, &child_stderr_write, &security_attrs, 0 );
87
88
SetHandleInformation( parent_stdout_read, HANDLE_FLAG_INHERIT, 0 );
89
SetHandleInformation( parent_stderr_read, HANDLE_FLAG_INHERIT, 0 );
90
91
startup_info.cb = sizeof(startup_info);
92
startup_info.hStdInput = GetStdHandle( STD_INPUT_HANDLE );
93
startup_info.hStdOutput = child_stdout_write;
94
startup_info.hStdError = child_stderr_write;
95
startup_info.dwFlags |= STARTF_USESTDHANDLES;
96
97
sprintf( cmd, "fc.exe %s %s", tmpfile1, tmpfile2 );
98
99
ret = CreateProcessA( NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &startup_info, &process_info );
100
ok( ret, "got %lu\n", GetLastError() );
101
CloseHandle( child_stdout_write );
102
CloseHandle( child_stderr_write );
103
104
read_all_from_handle( parent_stdout_read, stdout_buf, &stdout_size );
105
read_all_from_handle( parent_stderr_read, stderr_buf, &stderr_size );
106
CloseHandle( parent_stdout_read );
107
CloseHandle( parent_stderr_read );
108
109
WaitForSingleObject( process_info.hProcess, INFINITE );
110
ret = GetExitCodeProcess( process_info.hProcess, &exitcode );
111
ok( ret, "got %lu\n", GetLastError() );
112
CloseHandle( process_info.hProcess );
113
CloseHandle( process_info.hThread );
114
return exitcode;
115
}
116
117
static BOOL check_nodiff( const char *output )
118
{
119
const char *ptr = output;
120
121
if (memcmp( ptr, "Comparing files ", sizeof("Comparing files ") - 1 )) return FALSE;
122
ptr = strchr( ptr, '\n' ) + 1;
123
if (memcmp( ptr, "FC: no differences encountered\r\n", sizeof("FC: no differences encountered\r\n") - 1 ))
124
return FALSE;
125
ptr = strchr( ptr, '\n' ) + 1;
126
if (*ptr++ != '\r' || *ptr++ != '\n' || *ptr) return FALSE;
127
return TRUE;
128
}
129
130
static BOOL check_diff( const char *output, const char *str1, const char *str2, const char *str3, const char *str4 )
131
{
132
const char *ptr = output;
133
134
if (memcmp( ptr, "Comparing files ", sizeof("Comparing files ") - 1 )) return FALSE;
135
ptr = strchr( ptr, '\n' ) + 1;
136
if (memcmp( ptr, "***** ", sizeof("***** ") - 1 )) return FALSE;
137
ptr = strchr( ptr, '\n' ) + 1;
138
while (*str1)
139
{
140
if (memcmp( ptr, str1, strlen(str1) )) return FALSE;
141
ptr = strchr( ptr, '\n' ) + 1;
142
str1 += strlen(str1) + 1;
143
}
144
if (memcmp( ptr, "***** ", sizeof("***** ") - 1 )) return FALSE;
145
ptr = strchr( ptr, '\n' ) + 1;
146
while (*str2)
147
{
148
if (memcmp( ptr, str2, strlen(str2) )) return FALSE;
149
ptr = strchr( ptr, '\n' ) + 1;
150
str2 += strlen(str2) + 1;
151
}
152
if (memcmp( ptr, "*****", sizeof("*****") - 1 )) return FALSE;
153
ptr = strchr( ptr, '\n' ) + 1;
154
if (*ptr++ != '\r' || *ptr++ != '\n') return FALSE;
155
if (str3)
156
{
157
ptr = strchr( ptr, '\n' ) + 1;
158
if (memcmp( ptr, "***** ", sizeof("***** ") - 1 )) return FALSE;
159
ptr = strchr( ptr, '\n' ) + 1;
160
while (*str3)
161
{
162
if (memcmp( ptr, str3, strlen(str3) )) return FALSE;
163
ptr = strchr( ptr, '\n' ) + 1;
164
str3 += strlen(str3) + 1;
165
}
166
if (memcmp( ptr, "*****", sizeof("*****") - 1 )) return FALSE;
167
ptr = strchr( ptr, '\n' ) + 1;
168
while (*str4)
169
{
170
if (memcmp( ptr, str4, strlen(str4) )) return FALSE;
171
ptr = strchr( ptr, '\n' ) + 1;
172
str4 += strlen(str4) + 1;
173
}
174
if (*ptr++ != '\r' || *ptr++ != '\n') return FALSE;
175
}
176
if (*ptr) return FALSE;
177
return TRUE;
178
}
179
180
static void test_diff_output(void)
181
{
182
struct
183
{
184
int todo;
185
const char *data1;
186
const char *data2;
187
const char *diff1;
188
const char *diff2;
189
const char *diff3;
190
const char *diff4;
191
} tests[] =
192
{
193
/* 0 */ { 0, "", "" },
194
/* 1 */ { 0, "", "apple", "\0", "apple\0" },
195
/* 2 */ { 0, "apple", "", "apple\0", "\0" },
196
/* 3 */ { 0, "apple", "apple" },
197
/* 4 */ { 0, "apple", "orange", "apple\0", "orange\0" },
198
/* 5 */ { 0, "apple\nmango", "apple", "mango\0", "\0" },
199
/* 6 */ { 0, "apple", "apple\nmango", "\0", "mango\0" },
200
/* 7 */ { 0, "apple\nmango", "apple\nkiwi", "apple\0mango\0", "apple\0kiwi\0" },
201
/* 8 */ { 0, "apple\nmango", "kiwi\nmango", "apple\0mango\0", "kiwi\0mango\0" },
202
/* 9 */ { 0, "apple\nmango\nkiwi", "apple\nlemon\nkiwi", "apple\0mango\0kiwi\0", "apple\0lemon\0kiwi\0" },
203
/* 10 */ { 1, "apple\nmango\nkiwi\nlemon", "apple\nlemon\nkiwi\ncherry", "apple\0mango\0kiwi\0lemon\0", "apple\0lemon\0",
204
"kiwi\0cherry\0", "\0" },
205
/* 11 */ { 0, "apple\nmango\nkiwi\nlemon", "apple\nmango\nkiwi\ncherry", "kiwi\0lemon\0", "kiwi\0cherry\0" },
206
/* 12 */ { 0, "apple\t", "apple", "apple\0", "apple\0" },
207
/* 13 */ { 0, "apple\n", "apple" },
208
/* 14 */ { 0, "apple", "apple\r\nmango", "\0", "mango\0" },
209
};
210
UINT i;
211
212
for (i = 0; i < ARRAY_SIZE(tests); i++)
213
{
214
BOOL ret;
215
DWORD exitcode;
216
217
stdout_size = stderr_size = 0;
218
exitcode = run_fc( tests[i].data1, tests[i].data2 );
219
ok( stdout_size, "got %ld\n", stdout_size );
220
ok( !stderr_size, "got %ld %s\n", stderr_size, stderr_buf );
221
222
if (tests[i].diff1)
223
{
224
ok( exitcode == 1, "%u: got %lu\n", i, exitcode );
225
ret = check_diff( stdout_buf, tests[i].diff1, tests[i].diff2, tests[i].diff3, tests[i].diff4 );
226
todo_wine_if (tests[i].todo) ok( ret, "%u: got %d '%s'\n", i, ret, stdout_buf );
227
if (!ret) ok( !stderr_size, "got %ld %s\n", stderr_size, stderr_buf );
228
}
229
else
230
{
231
ok( exitcode == 0, "%u: got %lu\n", i, exitcode );
232
ret = check_nodiff( stdout_buf );
233
ok( ret, "%u: got %d '%s'\n", i, ret, stdout_buf );
234
}
235
}
236
}
237
238
START_TEST(fc)
239
{
240
if (PRIMARYLANGID( GetUserDefaultUILanguage() ) != LANG_ENGLISH)
241
{
242
skip( "tests require English locale\n" );
243
return;
244
}
245
246
create_temp_file( tmpfile1, "tst" );
247
create_temp_file( tmpfile2, "TST" );
248
249
test_diff_output();
250
251
DeleteFileA( tmpfile1 );
252
DeleteFileA( tmpfile2 );
253
}
254
255