fmemopen2_test.c revision 291870
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 291870 2015-12-05 21:49:35Z 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
99	/* Check that the string was not modified after the first 4 bytes. */
100	ATF_REQUIRE(strcmp(str, str3) == 0);
101}
102
103ATF_TC_WITHOUT_HEAD(test_autoalloc);
104ATF_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
142ATF_TC_WITHOUT_HEAD(test_data_length);
143ATF_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
206ATF_TC_WITHOUT_HEAD(test_binary);
207ATF_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
240ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
241ATF_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
262ATF_TC_WITHOUT_HEAD(test_size_0);
263ATF_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
274ATF_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}
286