1/* fmemopen tests.
2 Copyright (C) 2015-2022 Free Software Foundation, Inc.
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 <https://www.gnu.org/licenses/>. */
18
19
20#include <assert.h>
21#include <stdio.h>
22#include <string.h>
23#include <sys/types.h>
24#include <stdint.h>
25#include <errno.h>
26
27/* Check fmemopen with user provided buffer open for write. */
28static int
29do_test_with_buffer (void)
30{
31 int result = 0;
32 char buf[100];
33 const size_t nbuf = sizeof (buf);
34
35 FILE *fp = fmemopen (buf, nbuf, "w");
36 if (fp == NULL)
37 {
38 printf (format: "FAIL: fmemopen failed (%s)\n", __FUNCTION__);
39 return 1;
40 }
41
42 /* Default write operation, check if file position is correct after it. */
43 static const char str[] = "hello world";
44 const size_t nstr = sizeof (str) - 1;
45 fputs (str, fp);
46 off_t o = ftello (stream: fp);
47 if (o != nstr)
48 {
49 printf (format: "FAIL: first ftello returned %jd, expected %zu\n",
50 (intmax_t)o, nstr);
51 result = 1;
52 }
53
54 /* Rewind stream and seek tests, the position size should be equal to
55 buffer size provided in open function. */
56 rewind (fp);
57 o = ftello (stream: fp);
58 if (o != 0)
59 {
60 printf (format: "FAIL: second ftello returned %jd, expected 0\n",
61 (intmax_t)o);
62 result = 1;
63 }
64 if (fseeko (stream: fp, off: 0, SEEK_END) != 0)
65 {
66 printf (format: "FAIL: fseeko failed\n");
67 result = 1;
68 }
69 o = ftello (stream: fp);
70 if (o != nstr)
71 {
72 printf (format: "FAIL: third ftello returned %jd, expected %zu\n",
73 (intmax_t)o, nstr);
74 result = 1;
75 }
76
77 /* Rewind the stream and recheck by using a shorter string. */
78 rewind (fp);
79 static const char str2[] = "just hello";
80 const size_t nstr2 = sizeof (str2) - 1;
81 assert (nstr2 < nstr);
82 fputs (str2, fp);
83 o = ftello (stream: fp);
84 if (o != nstr2)
85 {
86 printf (format: "FAIL: fourth ftello returned %jd, expected %zu\n",
87 (intmax_t)o, nstr2);
88 result = 1;
89 }
90 fclose (fp);
91
92 /* Again, but now with a larger string. */
93 static const char str3[] = "just hellod";
94 if (strcmp (buf, str3) != 0)
95 {
96 printf (format: "FAIL: final string is \"%s\", expected \"%s\"\n",
97 buf, str3);
98 result = 1;
99 }
100 return result;
101}
102
103/* Check fmemopen without user provided buffer open for write. */
104static int
105do_test_without_buffer (void)
106{
107 int result = 0;
108 const size_t nbuf = 100;
109
110 FILE *fp = fmemopen (NULL, nbuf, "w");
111 if (fp == NULL)
112 {
113 printf (format: "FAIL: fmemopen failed (%s)\n", __FUNCTION__);
114 return 1;
115 }
116
117 static const char str[] = "hello world";
118 const size_t nstr = sizeof (str) - 1;
119
120 /* Default write operation, check if file position is correct after it. */
121 fputs (str, fp);
122 off_t o = ftello (stream: fp);
123 if (o != nstr)
124 {
125 printf (format: "FAIL: first ftello returned %jd, expected %zu\n",
126 (intmax_t) o, nstr);
127 result = 1;
128 }
129 if (fseeko (stream: fp, off: 0, SEEK_END) != 0)
130 {
131 printf (format: "FAIL: fseeko failed\n");
132 result = 1;
133 }
134 o = ftello (stream: fp);
135 if (o != nstr)
136 {
137 printf (format: "FAIL: second ftello returned %jd, expected %zu\n",
138 (intmax_t) o, nbuf);
139 result = 1;
140 }
141
142 /* Rewind the stream and recheck by using a shorter string. */
143 rewind (fp);
144 static const char str2[] = "just hello";
145 const size_t nstr2 = sizeof (str2) - 1;
146 assert (nstr2 < nstr);
147 fputs (str2, fp);
148 o = ftello (stream: fp);
149 if (o != nstr2)
150 {
151 printf (format: "FAIL: third ftello returned %jd, expected %zu\n",
152 (intmax_t) o, nstr2);
153 result = 1;
154 }
155 fclose (fp);
156
157 return result;
158}
159
160/* Check fmemopen with a buffer lenght of zero. */
161static int
162do_test_length_zero (void)
163{
164 int result = 0;
165 FILE *fp;
166#define BUFCONTENTS "testing buffer"
167 char buf[100] = BUFCONTENTS;
168 const size_t nbuf = 0;
169 int r;
170
171 fp = fmemopen (buf, nbuf, "r");
172 if (fp == NULL)
173 {
174 printf (format: "FAIL: fmemopen failed (%s)\n", __FUNCTION__);
175 return 1;
176 }
177
178 /* Reading any data on a zero-length buffer should return EOF. */
179 if ((r = fgetc (stream: fp)) != EOF)
180 {
181 printf (format: "FAIL: fgetc on a zero-length returned: %d\n", r);
182 result = 1;
183 }
184 off_t o = ftello (stream: fp);
185 if (o != 0)
186 {
187 printf (format: "FAIL: first ftello returned %jd, expected 0\n",
188 (intmax_t) o);
189 result = 1;
190 }
191 fclose (fp);
192
193 /* Writing any data shall start at current position and shall not pass
194 current buffer size beyond the size in fmemopen call. */
195 fp = fmemopen (buf, nbuf, "w");
196 if (fp == NULL)
197 {
198 printf (format: "FAIL: second fmemopen failed (%s)\n", __FUNCTION__);
199 return 1;
200 }
201
202 static const char str[] = "hello world";
203 /* Because of buffering, the fputs call itself will not fail. However the
204 final buffer should be not changed because length 0 was passed to the
205 fmemopen call. */
206 fputs (str, fp);
207 r = 0;
208 errno = 0;
209 if (fflush (fp) != EOF)
210 {
211 printf (format: "FAIL: fflush did not return EOF\n");
212 fclose (fp);
213 return 1;
214 }
215 if (errno != ENOSPC)
216 {
217 printf (format: "FAIL: errno is %i (expected ENOSPC)\n", errno);
218 fclose (fp);
219 return 1;
220 }
221
222 fclose (fp);
223
224 if (strcmp (buf, BUFCONTENTS) != 0)
225 {
226 printf (format: "FAIL: strcmp (%s, %s) failed\n", buf, BUFCONTENTS);
227 return 1;
228 }
229
230 /* Different than 'w' mode, 'w+' truncates the buffer. */
231 fp = fmemopen (buf, nbuf, "w+");
232 if (fp == NULL)
233 {
234 printf (format: "FAIL: third fmemopen failed (%s)\n", __FUNCTION__);
235 return 1;
236 }
237
238 fclose (fp);
239
240 if (strcmp (buf, "") != 0)
241 {
242 printf (format: "FAIL: strcmp (%s, \"\") failed\n", buf);
243 return 1;
244 }
245
246 return result;
247}
248
249static int
250do_test (void)
251{
252 int ret = 0;
253
254 ret += do_test_with_buffer ();
255 ret += do_test_without_buffer ();
256 ret += do_test_length_zero ();
257
258 return ret;
259}
260
261#define TEST_FUNCTION do_test ()
262#include "../test-skeleton.c"
263

source code of glibc/stdio-common/tst-fmemopen2.c