]>
Commit | Line | Data |
---|---|---|
fdb7d390 | 1 | /* fmemopen tests for append and read mode. |
bfff8b1b | 2 | Copyright (C) 2015-2017 Free Software Foundation, Inc. |
fdb7d390 AZ |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #include <assert.h> | |
20 | #include <stdio.h> | |
21 | #include <string.h> | |
22 | #include <sys/types.h> | |
23 | ||
24 | static void | |
25 | print_buffer (const char *s, size_t n) | |
26 | { | |
27 | size_t i; | |
b65b205f | 28 | printf ("{"); |
fdb7d390 | 29 | for (i=0; i<n; ++i) |
b65b205f AZ |
30 | { |
31 | printf ("0x%02X (%c)", s[i], s[i]); | |
32 | if (i != n) | |
33 | printf (", "); | |
34 | } | |
fdb7d390 AZ |
35 | } |
36 | ||
37 | /* This test check append mode initial position (a/a+) based on POSIX defition | |
38 | (BZ#6544 and BZ#13151). */ | |
39 | static int | |
40 | do_test_write_append (const char *mode) | |
41 | { | |
42 | char buf[32] = "testing buffer"; | |
43 | char exp[32] = "testing bufferXX"; | |
44 | ||
45 | FILE *fp = fmemopen (buf, sizeof (buf), mode); | |
46 | ||
47 | fflush (fp); | |
48 | fprintf (fp, "X"); | |
49 | fseek (fp, 0, SEEK_SET); | |
50 | fprintf (fp, "X"); | |
51 | fclose (fp); | |
52 | ||
53 | if (strcmp (buf, exp) != 0) | |
54 | { | |
55 | printf ("%s: check failed: %s != %s\n", __FUNCTION__, buf, exp); | |
56 | return 1; | |
57 | } | |
58 | ||
59 | return 0; | |
60 | } | |
61 | ||
62 | /* This test check append mode initial position (a/a+) based on POSIX defition | |
63 | (BZ#6544 and BZ#13151) for buffer without null byte end. */ | |
64 | static int | |
65 | do_test_write_append_without_null (const char *mode) | |
66 | { | |
67 | char buf[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; | |
68 | char exp[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 }; | |
69 | ||
70 | /* If '\0' is not found in buffer, POSIX states that SEEK_SET should be | |
71 | the size argument. */ | |
72 | FILE *fp = fmemopen (buf, sizeof (buf) - 2, "a"); | |
73 | ||
74 | fflush (fp); | |
75 | fputc (0x70, fp); | |
76 | fseek (fp, 0, SEEK_SET); | |
77 | fputc (0x70, fp); | |
78 | fputc (0x70, fp); | |
79 | fclose (fp); | |
80 | ||
81 | /* POSIX also states that a write operation on the stream shall not advance | |
82 | the current buffer size beyond the size given in fmemopen, so the string | |
83 | should be same. */ | |
84 | if (memcmp (buf, exp, sizeof (buf)) != 0) | |
85 | { | |
86 | printf ("%s: check failed: ", __FUNCTION__); | |
87 | print_buffer (buf, sizeof (buf)); | |
88 | printf ("!= "); | |
89 | print_buffer (exp, sizeof (exp)); | |
90 | printf ("\n"); | |
91 | return 1; | |
92 | } | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | /* This test check for initial position and feek value for fmemopen objects | |
98 | opened with append mode. */ | |
99 | static int | |
100 | do_test_read_append (void) | |
101 | { | |
102 | char buf[32] = "testing buffer"; | |
103 | size_t buflen = strlen (buf); | |
104 | long fpos; | |
105 | ||
106 | /* POSIX defines for 'a+' the initial position is the first null byte. */ | |
107 | FILE *fp = fmemopen (buf, sizeof (buf), "a+"); | |
108 | ||
109 | fpos = ftell (fp); | |
110 | if (fpos != buflen) | |
111 | { | |
112 | printf ("%s: ftell|SEEK_SET (fp) %li != strlen (%s) %zu\n", | |
113 | __FUNCTION__, fpos, buf, buflen); | |
114 | fclose (fp); | |
115 | return 1; | |
116 | } | |
117 | ||
118 | fseek (fp, 0, SEEK_END); | |
119 | ||
120 | if (fpos != buflen) | |
121 | { | |
122 | printf ("%s: ftell|SEEK_END (fp) %li != strlen (%s) %zu\n", | |
123 | __FUNCTION__, fpos, buf, buflen); | |
124 | fclose (fp); | |
125 | return 1; | |
126 | } | |
127 | fclose (fp); | |
128 | ||
129 | /* Check if attempting to read past the current size, defined as strlen (buf) | |
130 | yield an EOF. */ | |
131 | fp = fmemopen (buf, sizeof (buf), "a+"); | |
132 | if (getc(fp) != EOF) | |
133 | { | |
134 | printf ("%s: getc(fp) != EOF\n", __FUNCTION__); | |
135 | fclose (fp); | |
136 | return -1; | |
137 | } | |
138 | ||
139 | fclose (fp); | |
140 | ||
141 | return 0; | |
142 | } | |
143 | ||
144 | /* This test check for fseek (SEEK_END) using negative offsets (BZ#14292). The | |
145 | starting position of descriptor is different base on the opening mode. */ | |
146 | static int | |
147 | do_test_read_seek_neg (const char *mode, const char *expected) | |
148 | { | |
149 | char buf[] = "abcdefghijklmnopqrstuvxz0123456789"; | |
150 | char tmp[10]; | |
151 | size_t tmps = sizeof (tmps); | |
152 | long offset = -11; | |
153 | ||
154 | FILE *fp = fmemopen (buf, sizeof (buf), mode); | |
155 | fseek (fp, offset, SEEK_END); | |
156 | fread (tmp, tmps, 1, fp); | |
157 | ||
158 | if (memcmp (tmp, expected, tmps) != 0) | |
159 | { | |
160 | printf ("%s: fmemopen(%s) - fseek (fp, %li, SEEK_END):\n", | |
161 | __FUNCTION__, mode, offset); | |
162 | printf (" returned: "); | |
163 | print_buffer (tmp, tmps); | |
164 | printf ("\n"); | |
165 | printf (" expected: "); | |
166 | print_buffer (expected, tmps); | |
167 | printf ("\n"); | |
168 | return 1; | |
169 | } | |
170 | ||
171 | fclose (fp); | |
172 | ||
173 | return 0; | |
174 | } | |
175 | ||
176 | static int | |
177 | do_test_read_seek_negative (void) | |
178 | { | |
179 | int ret = 0; | |
180 | ||
181 | /* 'r' and 'w' modes defines the initial position at the buffer start and | |
182 | seek with SEEK_END shall seek relative to its size give in fmemopen | |
183 | call. The expected tmp result is 0 to 9 *without* the ending null */ | |
184 | ret += do_test_read_seek_neg ("r", "0123456789"); | |
185 | /* 'a+' mode sets the initial position at the first null byte in buffer and | |
186 | SEEK_END shall seek relative to its size as well. The expected result is | |
187 | z012345678, since SEEK_END plus a+ start at '\0', not size. */ | |
188 | ret += do_test_read_seek_neg ("a+", "z012345678"); | |
189 | ||
190 | return ret; | |
191 | } | |
192 | ||
b65b205f AZ |
193 | static int |
194 | do_test_write_append_2 (const char *str) | |
195 | { | |
196 | char buf[10]; | |
197 | size_t strn = strlen (str); | |
198 | strcpy (buf, str); | |
199 | ||
200 | FILE *fp = fmemopen (buf, sizeof (buf), "a+"); | |
201 | size_t r = ftell (fp); | |
202 | size_t e = strlen (buf); | |
203 | if (r != e) | |
204 | { | |
205 | printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e); | |
206 | return 1; | |
207 | } | |
208 | ||
209 | if (fseek (fp, 0, SEEK_SET) == -1) | |
210 | { | |
211 | printf ("%s: fseek returned -1\n", __FUNCTION__); | |
212 | return 1; | |
213 | } | |
214 | ||
215 | int gr; | |
216 | for (int i=0; i<strn; ++i) | |
217 | { | |
218 | if ((gr = getc (fp)) != str[i]) | |
219 | { | |
220 | printf ("%s: getc failed returned %d, expected %d\n", __FUNCTION__, | |
221 | gr, str[i]); | |
222 | return 1; | |
223 | } | |
224 | } | |
225 | if ((gr = getc (fp)) != EOF) | |
226 | { | |
227 | printf ("%s: getc failed returned %d, expected EOF\n", __FUNCTION__, | |
228 | gr); | |
229 | return 1; | |
230 | } | |
231 | ||
232 | if (fseek (fp, e+1, SEEK_SET) == -1) | |
233 | { | |
234 | printf ("%s: fseek returned -1\n", __FUNCTION__); | |
235 | return 1; | |
236 | } | |
237 | ||
238 | if ((r = ftell (fp)) != e+1) | |
239 | { | |
240 | printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+1); | |
241 | return 1; | |
242 | } | |
243 | ||
244 | if ((gr = getc (fp)) != EOF) | |
245 | { | |
246 | printf ("%s: getc failed returned %i\n", __FUNCTION__, gr); | |
247 | return 1; | |
248 | } | |
249 | ||
250 | /* Check if internal position is not changed with a getc returning EOF. */ | |
251 | if ((r = ftell (fp)) != e+1) | |
252 | { | |
253 | printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+1); | |
254 | return 1; | |
255 | } | |
256 | ||
257 | if (fseek (fp, 0, SEEK_CUR) == -1) | |
258 | { | |
259 | printf ("%s: fseek returned -1\n", __FUNCTION__); | |
260 | return 1; | |
261 | } | |
262 | ||
263 | /* This should be overwritten by fprintf + fflush. */ | |
264 | buf[e+2] = 'X'; | |
265 | ||
266 | if ((r = fprintf (fp, "%d", 101)) != 3) | |
267 | { | |
268 | printf ("%s: fprintf returned %zu, expected %d\n", __FUNCTION__, r, 3); | |
269 | return 1; | |
270 | } | |
271 | ||
272 | fflush (fp); | |
273 | ||
274 | /* Check if internal position is changed by 3 (strlen of '101'). */ | |
275 | if ((r = ftell (fp)) != e+3) | |
276 | { | |
277 | printf ("%s: ftell returned %zu, expected %zu\n", __FUNCTION__, r, e+3); | |
278 | return 1; | |
279 | } | |
280 | ||
281 | char exp[20]; | |
282 | sprintf (exp, "%s%d", str, 101); | |
283 | if (memcmp (buf, exp, strlen (exp)) != 0) | |
284 | { | |
285 | printf ("%s: check failed:", __FUNCTION__); | |
286 | printf ("\nexpected: "); | |
287 | print_buffer (buf, sizeof (buf)); | |
288 | printf ("\nbuffer: "); | |
289 | print_buffer (exp, sizeof (exp)); | |
290 | printf ("\n"); | |
291 | return 1; | |
292 | } | |
293 | ||
294 | fclose(fp); | |
295 | ||
296 | return 0; | |
297 | } | |
298 | ||
fdb7d390 AZ |
299 | static int |
300 | do_test (void) | |
301 | { | |
302 | int ret = 0; | |
303 | ||
304 | ret += do_test_write_append ("a"); | |
305 | ret += do_test_write_append_without_null ("a"); | |
306 | ret += do_test_write_append ("a+"); | |
307 | ret += do_test_write_append_without_null ("a+"); | |
308 | ||
309 | ret += do_test_read_append (); | |
310 | ||
311 | ret += do_test_read_seek_negative (); | |
312 | ||
b65b205f AZ |
313 | /* First test plus addend will fit in the define buffer of size 10. */ |
314 | ret += do_test_write_append_2 ("test"); | |
315 | /* The second test will also fit, but not the final '\0'. */ | |
316 | ret += do_test_write_append_2 ("testing"); | |
317 | ||
fdb7d390 AZ |
318 | return ret; |
319 | } | |
320 | ||
321 | #define TEST_FUNCTION do_test () | |
322 | #include "../test-skeleton.c" |