fmemopen2_test.c revision 290537
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: head/lib/libc/tests/stdio/fmemopen2_test.c 290537 2015-11-08 06:37:50Z ngie $");
33
34#include <errno.h>
35#include <stdio.h>
36#include <string.h>
37#include <strings.h>
38
39#include <atf-c.h>
40
41ATF_TC_WITHOUT_HEAD(test_preexisting);
42ATF_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	ATF_REQUIRE(rc == 0);
99
100	/* Check that the string was not modified after the first 4 bytes. */
101	ATF_REQUIRE(strcmp(str, str3) == 0);
102}
103
104ATF_TC_WITHOUT_HEAD(test_autoalloc);
105ATF_TC_BODY(test_autoalloc, tc)
106{
107	/* Let fmemopen allocate the buffer. */
108	char str[] = "A quick test";
109	FILE *fp;
110	long pos;
111	size_t nofw, nofr, i;
112	int rc;
113
114	/* Open a FILE * using fmemopen. */
115	fp = fmemopen(NULL, 512, "w+");
116	ATF_REQUIRE(fp != NULL);
117
118	/* fill the buffer */
119	for (i = 0; i < 512; i++) {
120		nofw = fwrite("a", 1, 1, fp);
121		ATF_REQUIRE(nofw == 1);
122	}
123
124	/* Get the current position into the stream. */
125	pos = ftell(fp);
126	ATF_REQUIRE(pos == 512);
127
128	/* Try to write past the end, we should get a short object count (0) */
129	nofw = fwrite("a", 1, 1, fp);
130	ATF_REQUIRE(nofw == 0);
131
132	/* Close the FILE *. */
133	rc = fclose(fp);
134	ATF_REQUIRE(rc == 0);
135
136	/* Open a FILE * using a wrong mode */
137	fp = fmemopen(NULL, 512, "r");
138	ATF_REQUIRE(fp == NULL);
139
140	fp = fmemopen(NULL, 512, "w");
141	ATF_REQUIRE(fp == NULL);
142}
143
144ATF_TC_WITHOUT_HEAD(test_data_length);
145ATF_TC_BODY(test_data_length, tc)
146{
147	/*
148	 * Here we test that a read operation doesn't go past the end of the
149	 * data actually written, and that a SEEK_END seeks from the end of the
150	 * data, not of the whole buffer.
151	 */
152	FILE *fp;
153	char buf[512] = {'\0'};
154	char str[]  = "Test data length. ";
155	char str2[] = "Do we have two sentences?";
156	char str3[sizeof(str) + sizeof(str2) -1];
157	long pos;
158	size_t nofw, nofr;
159	int rc;
160
161	/* Open a FILE * for updating our buffer. */
162	fp = fmemopen(buf, sizeof(buf), "w+");
163	ATF_REQUIRE(fp != NULL);
164
165	/* Write our string into the buffer. */
166	nofw = fwrite(str, 1, sizeof(str), fp);
167	ATF_REQUIRE(nofw == sizeof(str));
168
169	/* Now seek to the end and check that ftell gives us sizeof(str). */
170	rc = fseek(fp, 0, SEEK_END);
171	ATF_REQUIRE(rc == 0);
172	pos = ftell(fp);
173	ATF_REQUIRE(pos == sizeof(str));
174
175	/* Close the FILE *. */
176	rc = fclose(fp);
177	ATF_REQUIRE(rc == 0);
178
179	/* Reopen the buffer for appending. */
180	fp = fmemopen(buf, sizeof(buf), "a+");
181	ATF_REQUIRE(fp != NULL);
182
183	/* We should now be writing after the first string. */
184	nofw = fwrite(str2, 1, sizeof(str2), fp);
185	ATF_REQUIRE(nofw == sizeof(str2));
186
187	/* Rewind the FILE *. */
188	rc = fseek(fp, 0, SEEK_SET);
189	ATF_REQUIRE(rc == 0);
190
191	/* Make sure we're at the beginning. */
192	pos = ftell(fp);
193	ATF_REQUIRE(pos == 0);
194
195	/* Read the whole buffer. */
196	nofr = fread(str3, 1, sizeof(buf), fp);
197	ATF_REQUIRE(nofr == sizeof(str3));
198
199	/* Make sure the two strings are there. */
200	ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
201	ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
202
203	/* Close the FILE *. */
204	rc = fclose(fp);
205	ATF_REQUIRE(rc == 0);
206}
207
208ATF_TC_WITHOUT_HEAD(test_binary);
209ATF_TC_BODY(test_binary, tc)
210{
211	/*
212	 * Make sure that NULL bytes are never appended when opening a buffer
213	 * in binary mode.
214	 */
215
216	FILE *fp;
217	char buf[20];
218	char str[] = "Test";
219	size_t nofw;
220	int rc, i;
221
222	/* Pre-fill the buffer. */
223	memset(buf, 'A', sizeof(buf));
224
225	/* Open a FILE * in binary mode. */
226	fp = fmemopen(buf, sizeof(buf), "w+b");
227	ATF_REQUIRE(fp != NULL);
228
229	/* Write some data into it. */
230	nofw = fwrite(str, 1, strlen(str), fp);
231	ATF_REQUIRE(nofw == strlen(str));
232
233	/* Make sure that the buffer doesn't contain any NULL bytes. */
234	for (i = 0; i < sizeof(buf); i++)
235		ATF_REQUIRE(buf[i] != '\0');
236
237	/* Close the FILE *. */
238	rc = fclose(fp);
239	ATF_REQUIRE(rc == 0);
240}
241
242ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
243ATF_TC_BODY(test_append_binary_pos, tc)
244{
245	/*
246	 * For compatibility with other implementations (glibc), we set the
247	 * position to 0 when opening an automatically allocated binary stream
248	 * for appending.
249	 */
250
251	FILE *fp;
252
253	fp = fmemopen(NULL, 16, "ab+");
254	ATF_REQUIRE(ftell(fp) == 0L);
255	fclose(fp);
256
257	/* Make sure that a pre-allocated buffer behaves correctly. */
258	char buf[] = "Hello";
259	fp = fmemopen(buf, sizeof(buf), "ab+");
260	ATF_REQUIRE(ftell(fp) == strlen(buf));
261	fclose(fp);
262}
263
264ATF_TC_WITHOUT_HEAD(test_size_0);
265ATF_TC_BODY(test_size_0, tc)
266{
267	/* POSIX mandates that we return EINVAL if size is 0. */
268
269	FILE *fp;
270
271	fp = fmemopen(NULL, 0, "r+");
272	ATF_REQUIRE(fp == NULL);
273	ATF_REQUIRE(errno == EINVAL);
274}
275
276ATF_TP_ADD_TCS(tp)
277{
278
279	ATF_TP_ADD_TC(tp, test_autoalloc);
280	ATF_TP_ADD_TC(tp, test_preexisting);
281	ATF_TP_ADD_TC(tp, test_data_length);
282	ATF_TP_ADD_TC(tp, test_binary);
283	ATF_TP_ADD_TC(tp, test_append_binary_pos);
284	ATF_TP_ADD_TC(tp, test_size_0);
285
286	return (atf_no_error());
287}
288