]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - lib/libc/tests/stdio/fmemopen2_test.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.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
39 #include <atf-c.h>
40
41 ATF_TC_WITHOUT_HEAD(test_preexisting);
42 ATF_TC_BODY(test_preexisting, tc)
43 {
44         /* Use a pre-existing buffer. */
45         char buf[512];
46         char buf2[512];
47         char str[]  = "Test writing some stuff";
48         char str2[] = "AAAAAAAAA";
49         char str3[] = "AAAA writing some stuff";
50         FILE *fp;
51         size_t nofw, nofr;
52         int rc;
53
54         /* Open a FILE * using fmemopen. */
55         fp = fmemopen(buf, sizeof(buf), "w");
56         ATF_REQUIRE(fp != NULL);
57
58         /* Write to the buffer. */
59         nofw = fwrite(str, 1, sizeof(str), fp);
60         ATF_REQUIRE(nofw == sizeof(str));
61
62         /* Close the FILE *. */
63         rc = fclose(fp);
64         ATF_REQUIRE(rc == 0);
65
66         /* Re-open the FILE * to read back the data. */
67         fp = fmemopen(buf, sizeof(buf), "r");
68         ATF_REQUIRE(fp != NULL);
69
70         /* Read from the buffer. */
71         bzero(buf2, sizeof(buf2));
72         nofr = fread(buf2, 1, sizeof(buf2), fp);
73         ATF_REQUIRE(nofr == sizeof(buf2));
74
75         /*
76          * Since a write on a FILE * retrieved by fmemopen
77          * will add a '\0' (if there's space), we can check
78          * the strings for equality.
79          */
80         ATF_REQUIRE(strcmp(str, buf2) == 0);
81
82         /* Close the FILE *. */
83         rc = fclose(fp);
84         ATF_REQUIRE(rc == 0);
85
86         /* Now open a FILE * on the first 4 bytes of the string. */
87         fp = fmemopen(str, 4, "w");
88         ATF_REQUIRE(fp != NULL);
89
90         /*
91          * Try to write more bytes than we shoud, we'll get a short count (4).
92          */
93         nofw = fwrite(str2, 1, sizeof(str2), fp);
94         ATF_REQUIRE(nofw == 4);
95
96         /* Close the FILE *. */
97         rc = fclose(fp);
98
99         /* Check that the string was not modified after the first 4 bytes. */
100         ATF_REQUIRE(strcmp(str, str3) == 0);
101 }
102
103 ATF_TC_WITHOUT_HEAD(test_autoalloc);
104 ATF_TC_BODY(test_autoalloc, tc)
105 {
106         /* Let fmemopen allocate the buffer. */
107         FILE *fp;
108         long pos;
109         size_t nofw, i;
110         int rc;
111
112         /* Open a FILE * using fmemopen. */
113         fp = fmemopen(NULL, 512, "w+");
114         ATF_REQUIRE(fp != NULL);
115
116         /* fill the buffer */
117         for (i = 0; i < 512; i++) {
118                 nofw = fwrite("a", 1, 1, fp);
119                 ATF_REQUIRE(nofw == 1);
120         }
121
122         /* Get the current position into the stream. */
123         pos = ftell(fp);
124         ATF_REQUIRE(pos == 512);
125
126         /* Try to write past the end, we should get a short object count (0) */
127         nofw = fwrite("a", 1, 1, fp);
128         ATF_REQUIRE(nofw == 0);
129
130         /* Close the FILE *. */
131         rc = fclose(fp);
132         ATF_REQUIRE(rc == 0);
133
134         /* Open a FILE * using a wrong mode */
135         fp = fmemopen(NULL, 512, "r");
136         ATF_REQUIRE(fp == NULL);
137
138         fp = fmemopen(NULL, 512, "w");
139         ATF_REQUIRE(fp == NULL);
140 }
141
142 ATF_TC_WITHOUT_HEAD(test_data_length);
143 ATF_TC_BODY(test_data_length, tc)
144 {
145         /*
146          * Here we test that a read operation doesn't go past the end of the
147          * data actually written, and that a SEEK_END seeks from the end of the
148          * data, not of the whole buffer.
149          */
150         FILE *fp;
151         char buf[512] = {'\0'};
152         char str[]  = "Test data length. ";
153         char str2[] = "Do we have two sentences?";
154         char str3[sizeof(str) + sizeof(str2) -1];
155         long pos;
156         size_t nofw, nofr;
157         int rc;
158
159         /* Open a FILE * for updating our buffer. */
160         fp = fmemopen(buf, sizeof(buf), "w+");
161         ATF_REQUIRE(fp != NULL);
162
163         /* Write our string into the buffer. */
164         nofw = fwrite(str, 1, sizeof(str), fp);
165         ATF_REQUIRE(nofw == sizeof(str));
166
167         /* Now seek to the end and check that ftell gives us sizeof(str). */
168         rc = fseek(fp, 0, SEEK_END);
169         ATF_REQUIRE(rc == 0);
170         pos = ftell(fp);
171         ATF_REQUIRE(pos == sizeof(str));
172
173         /* Close the FILE *. */
174         rc = fclose(fp);
175         ATF_REQUIRE(rc == 0);
176
177         /* Reopen the buffer for appending. */
178         fp = fmemopen(buf, sizeof(buf), "a+");
179         ATF_REQUIRE(fp != NULL);
180
181         /* We should now be writing after the first string. */
182         nofw = fwrite(str2, 1, sizeof(str2), fp);
183         ATF_REQUIRE(nofw == sizeof(str2));
184
185         /* Rewind the FILE *. */
186         rc = fseek(fp, 0, SEEK_SET);
187         ATF_REQUIRE(rc == 0);
188
189         /* Make sure we're at the beginning. */
190         pos = ftell(fp);
191         ATF_REQUIRE(pos == 0);
192
193         /* Read the whole buffer. */
194         nofr = fread(str3, 1, sizeof(buf), fp);
195         ATF_REQUIRE(nofr == sizeof(str3));
196
197         /* Make sure the two strings are there. */
198         ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
199         ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
200
201         /* Close the FILE *. */
202         rc = fclose(fp);
203         ATF_REQUIRE(rc == 0);
204 }
205
206 ATF_TC_WITHOUT_HEAD(test_binary);
207 ATF_TC_BODY(test_binary, tc)
208 {
209         /*
210          * Make sure that NULL bytes are never appended when opening a buffer
211          * in binary mode.
212          */
213
214         FILE *fp;
215         char buf[20];
216         char str[] = "Test";
217         size_t nofw;
218         int rc, i;
219
220         /* Pre-fill the buffer. */
221         memset(buf, 'A', sizeof(buf));
222
223         /* Open a FILE * in binary mode. */
224         fp = fmemopen(buf, sizeof(buf), "w+b");
225         ATF_REQUIRE(fp != NULL);
226
227         /* Write some data into it. */
228         nofw = fwrite(str, 1, strlen(str), fp);
229         ATF_REQUIRE(nofw == strlen(str));
230
231         /* Make sure that the buffer doesn't contain any NULL bytes. */
232         for (i = 0; i < sizeof(buf); i++)
233                 ATF_REQUIRE(buf[i] != '\0');
234
235         /* Close the FILE *. */
236         rc = fclose(fp);
237         ATF_REQUIRE(rc == 0);
238 }
239
240 ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
241 ATF_TC_BODY(test_append_binary_pos, tc)
242 {
243         /*
244          * For compatibility with other implementations (glibc), we set the
245          * position to 0 when opening an automatically allocated binary stream
246          * for appending.
247          */
248
249         FILE *fp;
250
251         fp = fmemopen(NULL, 16, "ab+");
252         ATF_REQUIRE(ftell(fp) == 0L);
253         fclose(fp);
254
255         /* Make sure that a pre-allocated buffer behaves correctly. */
256         char buf[] = "Hello";
257         fp = fmemopen(buf, sizeof(buf), "ab+");
258         ATF_REQUIRE(ftell(fp) == strlen(buf));
259         fclose(fp);
260 }
261
262 ATF_TC_WITHOUT_HEAD(test_size_0);
263 ATF_TC_BODY(test_size_0, tc)
264 {
265         /* POSIX mandates that we return EINVAL if size is 0. */
266
267         FILE *fp;
268
269         fp = fmemopen(NULL, 0, "r+");
270         ATF_REQUIRE(fp == NULL);
271         ATF_REQUIRE(errno == EINVAL);
272 }
273
274 ATF_TP_ADD_TCS(tp)
275 {
276
277         ATF_TP_ADD_TC(tp, test_autoalloc);
278         ATF_TP_ADD_TC(tp, test_preexisting);
279         ATF_TP_ADD_TC(tp, test_data_length);
280         ATF_TP_ADD_TC(tp, test_binary);
281         ATF_TP_ADD_TC(tp, test_append_binary_pos);
282         ATF_TP_ADD_TC(tp, test_size_0);
283
284         return (atf_no_error());
285 }