]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - lib/libc/tests/stdio/fmemopen2_test.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / lib / libc / tests / stdio / fmemopen2_test.c
1 /*-
2 Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions
6 are met:
7 1. Redistributions of source code must retain the above copyright
8    notice, this list of conditions and the following disclaimer.
9 2. Redistributions in binary form must reproduce the above copyright
10    notice, this list of conditions and the following disclaimer in the
11    documentation and/or other materials provided with the distribution.
12
13 THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 SUCH DAMAGE.
24 */
25
26 /*
27  * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
28  * a FILE * retrieved using fmemopen()
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <errno.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <atf-c.h>
39
40 ATF_TC_WITHOUT_HEAD(test_preexisting);
41 ATF_TC_BODY(test_preexisting, tc)
42 {
43         /* 
44          * Use a pre-existing buffer.
45          */
46
47         char buf[512];
48         char buf2[512];
49         char str[]  = "Test writing some stuff";
50         char str2[] = "AAAAAAAAA";
51         char str3[] = "AAAA writing some stuff";
52         FILE *fp;
53         size_t nofw, nofr;
54         int rc;
55
56         /* Open a FILE * using fmemopen. */
57         fp = fmemopen(buf, sizeof(buf), "w");
58         ATF_REQUIRE(fp != NULL);
59
60         /* Write to the buffer. */
61         nofw = fwrite(str, 1, sizeof(str), fp);
62         ATF_REQUIRE(nofw == sizeof(str));
63
64         /* Close the FILE *. */
65         rc = fclose(fp);
66         ATF_REQUIRE(rc == 0);
67
68         /* Re-open the FILE * to read back the data. */
69         fp = fmemopen(buf, sizeof(buf), "r");
70         ATF_REQUIRE(fp != NULL);
71
72         /* Read from the buffer. */
73         bzero(buf2, sizeof(buf2));
74         nofr = fread(buf2, 1, sizeof(buf2), fp);
75         ATF_REQUIRE(nofr == sizeof(buf2));
76
77         /* 
78          * Since a write on a FILE * retrieved by fmemopen
79          * will add a '\0' (if there's space), we can check
80          * the strings for equality.
81          */
82         ATF_REQUIRE(strcmp(str, buf2) == 0);
83
84         /* Close the FILE *. */
85         rc = fclose(fp);
86         ATF_REQUIRE(rc == 0);
87
88         /* Now open a FILE * on the first 4 bytes of the string. */
89         fp = fmemopen(str, 4, "w");
90         ATF_REQUIRE(fp != NULL);
91
92         /*
93          * Try to write more bytes than we shoud, we'll get a short count (4).
94          */
95         nofw = fwrite(str2, 1, sizeof(str2), fp);
96         ATF_REQUIRE(nofw == 4);
97
98         /* Close the FILE *. */
99         rc = fclose(fp);
100
101         /* Check that the string was not modified after the first 4 bytes. */
102         ATF_REQUIRE(strcmp(str, str3) == 0);
103 }
104
105 ATF_TC_WITHOUT_HEAD(test_autoalloc);
106 ATF_TC_BODY(test_autoalloc, tc)
107 {
108         /* 
109          * Let fmemopen allocate the buffer.
110          */
111
112         char str[] = "A quick test";
113         FILE *fp;
114         long pos;
115         size_t nofw, nofr, i;
116         int rc;
117
118         /* Open a FILE * using fmemopen. */
119         fp = fmemopen(NULL, 512, "w+");
120         ATF_REQUIRE(fp != NULL);
121
122         /* fill the buffer */
123         for (i = 0; i < 512; i++) {
124                 nofw = fwrite("a", 1, 1, fp);
125                 ATF_REQUIRE(nofw == 1);
126         }
127
128         /* Get the current position into the stream. */
129         pos = ftell(fp);
130         ATF_REQUIRE(pos == 512);
131
132         /* 
133          * Try to write past the end, we should get a short object count (0)
134          */
135         nofw = fwrite("a", 1, 1, fp);
136         ATF_REQUIRE(nofw == 0);
137
138         /* Close the FILE *. */
139         rc = fclose(fp);
140         ATF_REQUIRE(rc == 0);
141
142         /* Open a FILE * using a wrong mode */
143         fp = fmemopen(NULL, 512, "r");
144         ATF_REQUIRE(fp == NULL);
145
146         fp = fmemopen(NULL, 512, "w");
147         ATF_REQUIRE(fp == NULL);
148 }
149
150 ATF_TC_WITHOUT_HEAD(test_data_length);
151 ATF_TC_BODY(test_data_length, tc)
152 {
153         /*
154          * Here we test that a read operation doesn't go past the end of the
155          * data actually written, and that a SEEK_END seeks from the end of the
156          * data, not of the whole buffer.
157          */
158         FILE *fp;
159         char buf[512] = {'\0'};
160         char str[]  = "Test data length. ";
161         char str2[] = "Do we have two sentences?";
162         char str3[sizeof(str) + sizeof(str2) -1];
163         long pos;
164         size_t nofw, nofr;
165         int rc;
166
167         /* Open a FILE * for updating our buffer. */
168         fp = fmemopen(buf, sizeof(buf), "w+");
169         ATF_REQUIRE(fp != NULL);
170
171         /* Write our string into the buffer. */
172         nofw = fwrite(str, 1, sizeof(str), fp);
173         ATF_REQUIRE(nofw == sizeof(str));
174
175         /* 
176          * Now seek to the end and check that ftell
177          * gives us sizeof(str).
178          */
179         rc = fseek(fp, 0, SEEK_END);
180         ATF_REQUIRE(rc == 0);
181         pos = ftell(fp);
182         ATF_REQUIRE(pos == sizeof(str));
183
184         /* Close the FILE *. */
185         rc = fclose(fp);
186         ATF_REQUIRE(rc == 0);
187
188         /* Reopen the buffer for appending. */
189         fp = fmemopen(buf, sizeof(buf), "a+");
190         ATF_REQUIRE(fp != NULL);
191
192         /* We should now be writing after the first string. */
193         nofw = fwrite(str2, 1, sizeof(str2), fp);
194         ATF_REQUIRE(nofw == sizeof(str2));
195
196         /* Rewind the FILE *. */
197         rc = fseek(fp, 0, SEEK_SET);
198         ATF_REQUIRE(rc == 0);
199
200         /* Make sure we're at the beginning. */
201         pos = ftell(fp);
202         ATF_REQUIRE(pos == 0);
203
204         /* Read the whole buffer. */
205         nofr = fread(str3, 1, sizeof(buf), fp);
206         ATF_REQUIRE(nofr == sizeof(str3));
207
208         /* Make sure the two strings are there. */
209         ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
210         ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
211
212         /* Close the FILE *. */
213         rc = fclose(fp);
214         ATF_REQUIRE(rc == 0);
215 }
216
217 ATF_TC_WITHOUT_HEAD(test_binary);
218 ATF_TC_BODY(test_binary, tc)
219 {
220         /*
221          * Make sure that NULL bytes are never appended when opening a buffer
222          * in binary mode.
223          */
224
225         FILE *fp;
226         char buf[20];
227         char str[] = "Test";
228         size_t nofw;
229         int rc, i;
230
231         /* Pre-fill the buffer. */
232         memset(buf, 'A', sizeof(buf));
233
234         /* Open a FILE * in binary mode. */
235         fp = fmemopen(buf, sizeof(buf), "w+b");
236         ATF_REQUIRE(fp != NULL);
237
238         /* Write some data into it. */
239         nofw = fwrite(str, 1, strlen(str), fp);
240         ATF_REQUIRE(nofw == strlen(str));
241
242         /* Make sure that the buffer doesn't contain any NULL bytes. */
243         for (i = 0; i < sizeof(buf); i++)
244                 ATF_REQUIRE(buf[i] != '\0');
245
246         /* Close the FILE *. */
247         rc = fclose(fp);
248         ATF_REQUIRE(rc == 0);
249 }
250
251 ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
252 ATF_TC_BODY(test_append_binary_pos, tc)
253 {
254         /*
255          * For compatibility with other implementations (glibc), we set the
256          * position to 0 when opening an automatically allocated binary stream
257          * for appending.
258          */
259
260         FILE *fp;
261
262         fp = fmemopen(NULL, 16, "ab+");
263         ATF_REQUIRE(ftell(fp) == 0L);
264         fclose(fp);
265
266         /*
267          * Make sure that a pre-allocated buffer behaves correctly.
268          */
269         char buf[] = "Hello";
270         fp = fmemopen(buf, sizeof(buf), "ab+");
271         ATF_REQUIRE(ftell(fp) == strlen(buf));
272         fclose(fp);
273 }
274
275 ATF_TC_WITHOUT_HEAD(test_size_0);
276 ATF_TC_BODY(test_size_0, tc)
277 {
278         /*
279          * POSIX mandates that we return EINVAL if size is 0.
280          */
281
282         FILE *fp;
283
284         fp = fmemopen(NULL, 0, "r+");
285         ATF_REQUIRE(fp == NULL);
286         ATF_REQUIRE(errno == EINVAL);
287 }
288
289 ATF_TP_ADD_TCS(tp)
290 {
291
292         ATF_TP_ADD_TC(tp, test_autoalloc);
293         ATF_TP_ADD_TC(tp, test_preexisting);
294         ATF_TP_ADD_TC(tp, test_data_length);
295         ATF_TP_ADD_TC(tp, test_binary);
296         ATF_TP_ADD_TC(tp, test_append_binary_pos);
297         ATF_TP_ADD_TC(tp, test_size_0);
298
299         return (atf_no_error());
300 }