fmemopen2_test.c revision 267004
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/tools/regression/lib/libc/stdio/test-fmemopen.c 267004 2014-06-03 07:11:22Z gahr $");
33
34#include <assert.h>
35#include <errno.h>
36#include <stdio.h>
37#include <string.h>
38#include <strings.h>
39
40void
41test_preexisting()
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	assert(fp != NULL);
59
60	/* Write to the buffer. */
61	nofw = fwrite(str, 1, sizeof(str), fp);
62	assert(nofw == sizeof(str));
63
64	/* Close the FILE *. */
65	rc = fclose(fp);
66	assert(rc == 0);
67
68	/* Re-open the FILE * to read back the data. */
69	fp = fmemopen(buf, sizeof(buf), "r");
70	assert(fp != NULL);
71
72	/* Read from the buffer. */
73	bzero(buf2, sizeof(buf2));
74	nofr = fread(buf2, 1, sizeof(buf2), fp);
75	assert(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	assert(strcmp(str, buf2) == 0);
83
84	/* Close the FILE *. */
85	rc = fclose(fp);
86	assert(rc == 0);
87
88	/* Now open a FILE * on the first 4 bytes of the string. */
89	fp = fmemopen(str, 4, "w");
90	assert(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	assert(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	assert(strcmp(str, str3) == 0);
103}
104
105void
106test_autoalloc()
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	assert(fp != NULL);
121
122	/* fill the buffer */
123	for (i = 0; i < 512; i++) {
124		nofw = fwrite("a", 1, 1, fp);
125		assert(nofw == 1);
126	}
127
128	/* Get the current position into the stream. */
129	pos = ftell(fp);
130	assert(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	assert(nofw == 0);
137
138	/* Close the FILE *. */
139	rc = fclose(fp);
140	assert(rc == 0);
141
142	/* Open a FILE * using a wrong mode */
143	fp = fmemopen(NULL, 512, "r");
144	assert(fp == NULL);
145
146	fp = fmemopen(NULL, 512, "w");
147	assert(fp == NULL);
148}
149
150void
151test_data_length()
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	assert(fp != NULL);
170
171	/* Write our string into the buffer. */
172	nofw = fwrite(str, 1, sizeof(str), fp);
173	assert(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	assert(rc == 0);
181	pos = ftell(fp);
182	assert(pos == sizeof(str));
183
184	/* Close the FILE *. */
185	rc = fclose(fp);
186	assert(rc == 0);
187
188	/* Reopen the buffer for appending. */
189	fp = fmemopen(buf, sizeof(buf), "a+");
190	assert(fp != NULL);
191
192	/* We should now be writing after the first string. */
193	nofw = fwrite(str2, 1, sizeof(str2), fp);
194	assert(nofw == sizeof(str2));
195
196	/* Rewind the FILE *. */
197	rc = fseek(fp, 0, SEEK_SET);
198	assert(rc == 0);
199
200	/* Make sure we're at the beginning. */
201	pos = ftell(fp);
202	assert(pos == 0);
203
204	/* Read the whole buffer. */
205	nofr = fread(str3, 1, sizeof(buf), fp);
206	assert(nofr == sizeof(str3));
207
208	/* Make sure the two strings are there. */
209	assert(strncmp(str3, str, sizeof(str) - 1) == 0);
210	assert(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
211
212	/* Close the FILE *. */
213	rc = fclose(fp);
214	assert(rc == 0);
215}
216
217void
218test_binary()
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	assert(fp != NULL);
237
238	/* Write some data into it. */
239	nofw = fwrite(str, 1, strlen(str), fp);
240	assert(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		assert(buf[i] != '\0');
245
246	/* Close the FILE *. */
247	rc = fclose(fp);
248	assert(rc == 0);
249}
250
251void
252test_append_binary_pos()
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	assert(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	assert(ftell(fp) == strlen(buf));
272	fclose(fp);
273}
274
275void
276test_size_0()
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	assert(fp == NULL);
286	assert(errno == EINVAL);
287}
288
289int
290main(void)
291{
292	test_autoalloc();
293	test_preexisting();
294	test_data_length();
295	test_binary();
296	test_append_binary_pos();
297	test_size_0();
298	return (0);
299}
300