fmemopen2_test.c revision 277446
1/*-
2Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions
6are met:
71. Redistributions of source code must retain the above copyright
8   notice, this list of conditions and the following disclaimer.
92. 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
13THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23SUCH 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: stable/10/lib/libc/tests/stdio/fmemopen2_test.c 277446 2015-01-20 21:59:48Z ngie $");
33
34#include <errno.h>
35#include <stdio.h>
36#include <string.h>
37#include <strings.h>
38#include <atf-c.h>
39
40ATF_TC_WITHOUT_HEAD(test_preexisting);
41ATF_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
105ATF_TC_WITHOUT_HEAD(test_autoalloc);
106ATF_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
150ATF_TC_WITHOUT_HEAD(test_data_length);
151ATF_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
217ATF_TC_WITHOUT_HEAD(test_binary);
218ATF_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
251ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
252ATF_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
275ATF_TC_WITHOUT_HEAD(test_size_0);
276ATF_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
289ATF_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}
301