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.  */
28 static int
do_test_with_buffer(void)29 do_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 ("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 (fp);
47   if (o != nstr)
48     {
49       printf ("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 (fp);
58   if (o != 0)
59     {
60       printf ("FAIL: second ftello returned %jd, expected 0\n",
61 	      (intmax_t)o);
62       result = 1;
63     }
64   if (fseeko (fp, 0, SEEK_END) != 0)
65     {
66       printf ("FAIL: fseeko failed\n");
67       result = 1;
68     }
69   o = ftello (fp);
70   if (o != nstr)
71     {
72       printf ("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 (fp);
84   if (o != nstr2)
85     {
86       printf ("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 ("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.  */
104 static int
do_test_without_buffer(void)105 do_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 ("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 (fp);
123   if (o != nstr)
124     {
125       printf ("FAIL: first ftello returned %jd, expected %zu\n",
126 	      (intmax_t) o, nstr);
127       result = 1;
128     }
129   if (fseeko (fp, 0, SEEK_END) != 0)
130     {
131       printf ("FAIL: fseeko failed\n");
132       result = 1;
133     }
134   o = ftello (fp);
135   if (o != nstr)
136     {
137       printf ("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 (fp);
149   if (o != nstr2)
150     {
151       printf ("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.  */
161 static int
do_test_length_zero(void)162 do_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 ("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 (fp)) != EOF)
180     {
181       printf ("FAIL: fgetc on a zero-length returned: %d\n", r);
182       result = 1;
183     }
184   off_t o = ftello (fp);
185   if (o != 0)
186     {
187       printf ("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 ("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 ("FAIL: fflush did not return EOF\n");
212       fclose (fp);
213       return 1;
214     }
215   if (errno != ENOSPC)
216     {
217       printf ("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 ("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 ("FAIL: third fmemopen failed (%s)\n", __FUNCTION__);
235       return 1;
236     }
237 
238   fclose (fp);
239 
240   if (strcmp (buf, "") != 0)
241     {
242       printf ("FAIL: strcmp (%s, \"\") failed\n", buf);
243       return 1;
244     }
245 
246   return result;
247 }
248 
249 static int
do_test(void)250 do_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