fmemopen2_test.c revision 274592
1185029Spjd/*-
2185029SpjdCopyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
3185029Spjd
4185029SpjdRedistribution and use in source and binary forms, with or without
5185029Spjdmodification, are permitted provided that the following conditions
6185029Spjdare met:
7185029Spjd1. Redistributions of source code must retain the above copyright
8185029Spjd   notice, this list of conditions and the following disclaimer.
9185029Spjd2. Redistributions in binary form must reproduce the above copyright
10185029Spjd   notice, this list of conditions and the following disclaimer in the
11185029Spjd   documentation and/or other materials provided with the distribution.
12185029Spjd
13185029SpjdTHIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14185029SpjdANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15185029SpjdIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16185029SpjdARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17185029SpjdFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18185029SpjdDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19185029SpjdOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20185029SpjdHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21185029SpjdLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22185029SpjdOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23185029SpjdSUCH DAMAGE.
24185029Spjd*/
25185029Spjd
26185029Spjd/*
27185029Spjd * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
28185029Spjd * a FILE * retrieved using fmemopen()
29185029Spjd */
30185029Spjd
31185029Spjd#include <sys/cdefs.h>
32185029Spjd__FBSDID("$FreeBSD: head/lib/libc/tests/stdio/fmemopen2_test.c 274592 2014-11-16 19:57:47Z ngie $");
33185029Spjd
34185029Spjd#include <errno.h>
35185029Spjd#include <stdio.h>
36185029Spjd#include <string.h>
37185029Spjd#include <strings.h>
38185029Spjd#include <atf-c.h>
39185029Spjd
40185029SpjdATF_TC_WITHOUT_HEAD(test_preexisting);
41185029SpjdATF_TC_BODY(test_preexisting, tc)
42185029Spjd{
43185029Spjd	/*
44185029Spjd	 * Use a pre-existing buffer.
45185029Spjd	 */
46185029Spjd
47185029Spjd	char buf[512];
48185029Spjd	char buf2[512];
49185029Spjd	char str[]  = "Test writing some stuff";
50185029Spjd	char str2[] = "AAAAAAAAA";
51185029Spjd	char str3[] = "AAAA writing some stuff";
52185029Spjd	FILE *fp;
53185029Spjd	size_t nofw, nofr;
54185029Spjd	int rc;
55185029Spjd
56185029Spjd	/* Open a FILE * using fmemopen. */
57185029Spjd	fp = fmemopen(buf, sizeof(buf), "w");
58185029Spjd	ATF_REQUIRE(fp != NULL);
59185029Spjd
60185029Spjd	/* Write to the buffer. */
61185029Spjd	nofw = fwrite(str, 1, sizeof(str), fp);
62185029Spjd	ATF_REQUIRE(nofw == sizeof(str));
63185029Spjd
64185029Spjd	/* Close the FILE *. */
65185029Spjd	rc = fclose(fp);
66185029Spjd	ATF_REQUIRE(rc == 0);
67185029Spjd
68185029Spjd	/* Re-open the FILE * to read back the data. */
69185029Spjd	fp = fmemopen(buf, sizeof(buf), "r");
70185029Spjd	ATF_REQUIRE(fp != NULL);
71185029Spjd
72185029Spjd	/* Read from the buffer. */
73185029Spjd	bzero(buf2, sizeof(buf2));
74185029Spjd	nofr = fread(buf2, 1, sizeof(buf2), fp);
75185029Spjd	ATF_REQUIRE(nofr == sizeof(buf2));
76185029Spjd
77185029Spjd	/*
78185029Spjd	 * Since a write on a FILE * retrieved by fmemopen
79185029Spjd	 * will add a '\0' (if there's space), we can check
80185029Spjd	 * the strings for equality.
81185029Spjd	 */
82185029Spjd	ATF_REQUIRE(strcmp(str, buf2) == 0);
83185029Spjd
84185029Spjd	/* Close the FILE *. */
85185029Spjd	rc = fclose(fp);
86185029Spjd	ATF_REQUIRE(rc == 0);
87185029Spjd
88185029Spjd	/* Now open a FILE * on the first 4 bytes of the string. */
89185029Spjd	fp = fmemopen(str, 4, "w");
90185029Spjd	ATF_REQUIRE(fp != NULL);
91185029Spjd
92185029Spjd	/*
93185029Spjd	 * Try to write more bytes than we shoud, we'll get a short count (4).
94185029Spjd	 */
95185029Spjd	nofw = fwrite(str2, 1, sizeof(str2), fp);
96185029Spjd	ATF_REQUIRE(nofw == 4);
97185029Spjd
98185029Spjd	/* Close the FILE *. */
99185029Spjd	rc = fclose(fp);
100185029Spjd
101185029Spjd	/* Check that the string was not modified after the first 4 bytes. */
102185029Spjd	ATF_REQUIRE(strcmp(str, str3) == 0);
103185029Spjd}
104185029Spjd
105185029SpjdATF_TC_WITHOUT_HEAD(test_autoalloc);
106185029SpjdATF_TC_BODY(test_autoalloc, tc)
107185029Spjd{
108185029Spjd	/*
109185029Spjd	 * Let fmemopen allocate the buffer.
110185029Spjd	 */
111185029Spjd
112185029Spjd	char str[] = "A quick test";
113185029Spjd	FILE *fp;
114185029Spjd	long pos;
115185029Spjd	size_t nofw, nofr, i;
116185029Spjd	int rc;
117185029Spjd
118185029Spjd	/* Open a FILE * using fmemopen. */
119185029Spjd	fp = fmemopen(NULL, 512, "w+");
120185029Spjd	ATF_REQUIRE(fp != NULL);
121185029Spjd
122185029Spjd	/* fill the buffer */
123185029Spjd	for (i = 0; i < 512; i++) {
124185029Spjd		nofw = fwrite("a", 1, 1, fp);
125185029Spjd		ATF_REQUIRE(nofw == 1);
126185029Spjd	}
127185029Spjd
128185029Spjd	/* Get the current position into the stream. */
129185029Spjd	pos = ftell(fp);
130185029Spjd	ATF_REQUIRE(pos == 512);
131185029Spjd
132185029Spjd	/*
133185029Spjd	 * Try to write past the end, we should get a short object count (0)
134185029Spjd	 */
135185029Spjd	nofw = fwrite("a", 1, 1, fp);
136185029Spjd	ATF_REQUIRE(nofw == 0);
137185029Spjd
138185029Spjd	/* Close the FILE *. */
139185029Spjd	rc = fclose(fp);
140185029Spjd	ATF_REQUIRE(rc == 0);
141185029Spjd
142185029Spjd	/* Open a FILE * using a wrong mode */
143185029Spjd	fp = fmemopen(NULL, 512, "r");
144185029Spjd	ATF_REQUIRE(fp == NULL);
145185029Spjd
146185029Spjd	fp = fmemopen(NULL, 512, "w");
147185029Spjd	ATF_REQUIRE(fp == NULL);
148185029Spjd}
149185029Spjd
150185029SpjdATF_TC_WITHOUT_HEAD(test_data_length);
151185029SpjdATF_TC_BODY(test_data_length, tc)
152185029Spjd{
153185029Spjd	/*
154185029Spjd	 * Here we test that a read operation doesn't go past the end of the
155185029Spjd	 * data actually written, and that a SEEK_END seeks from the end of the
156185029Spjd	 * data, not of the whole buffer.
157185029Spjd	 */
158185029Spjd	FILE *fp;
159185029Spjd	char buf[512] = {'\0'};
160185029Spjd	char str[]  = "Test data length. ";
161185029Spjd	char str2[] = "Do we have two sentences?";
162185029Spjd	char str3[sizeof(str) + sizeof(str2) -1];
163185029Spjd	long pos;
164185029Spjd	size_t nofw, nofr;
165185029Spjd	int rc;
166185029Spjd
167185029Spjd	/* Open a FILE * for updating our buffer. */
168185029Spjd	fp = fmemopen(buf, sizeof(buf), "w+");
169185029Spjd	ATF_REQUIRE(fp != NULL);
170185029Spjd
171185029Spjd	/* Write our string into the buffer. */
172185029Spjd	nofw = fwrite(str, 1, sizeof(str), fp);
173185029Spjd	ATF_REQUIRE(nofw == sizeof(str));
174185029Spjd
175185029Spjd	/*
176185029Spjd	 * Now seek to the end and check that ftell
177185029Spjd	 * gives us sizeof(str).
178185029Spjd	 */
179185029Spjd	rc = fseek(fp, 0, SEEK_END);
180185029Spjd	ATF_REQUIRE(rc == 0);
181185029Spjd	pos = ftell(fp);
182185029Spjd	ATF_REQUIRE(pos == sizeof(str));
183185029Spjd
184185029Spjd	/* Close the FILE *. */
185185029Spjd	rc = fclose(fp);
186185029Spjd	ATF_REQUIRE(rc == 0);
187185029Spjd
188185029Spjd	/* Reopen the buffer for appending. */
189185029Spjd	fp = fmemopen(buf, sizeof(buf), "a+");
190185029Spjd	ATF_REQUIRE(fp != NULL);
191185029Spjd
192185029Spjd	/* We should now be writing after the first string. */
193185029Spjd	nofw = fwrite(str2, 1, sizeof(str2), fp);
194185029Spjd	ATF_REQUIRE(nofw == sizeof(str2));
195185029Spjd
196185029Spjd	/* Rewind the FILE *. */
197185029Spjd	rc = fseek(fp, 0, SEEK_SET);
198185029Spjd	ATF_REQUIRE(rc == 0);
199185029Spjd
200185029Spjd	/* Make sure we're at the beginning. */
201185029Spjd	pos = ftell(fp);
202185029Spjd	ATF_REQUIRE(pos == 0);
203185029Spjd
204185029Spjd	/* Read the whole buffer. */
205185029Spjd	nofr = fread(str3, 1, sizeof(buf), fp);
206185029Spjd	ATF_REQUIRE(nofr == sizeof(str3));
207185029Spjd
208185029Spjd	/* Make sure the two strings are there. */
209185029Spjd	ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
210185029Spjd	ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
211185029Spjd
212185029Spjd	/* Close the FILE *. */
213185029Spjd	rc = fclose(fp);
214185029Spjd	ATF_REQUIRE(rc == 0);
215185029Spjd}
216185029Spjd
217185029SpjdATF_TC_WITHOUT_HEAD(test_binary);
218185029SpjdATF_TC_BODY(test_binary, tc)
219185029Spjd{
220185029Spjd	/*
221185029Spjd	 * Make sure that NULL bytes are never appended when opening a buffer
222185029Spjd	 * in binary mode.
223185029Spjd	 */
224185029Spjd
225185029Spjd	FILE *fp;
226185029Spjd	char buf[20];
227185029Spjd	char str[] = "Test";
228185029Spjd	size_t nofw;
229185029Spjd	int rc, i;
230185029Spjd
231185029Spjd	/* Pre-fill the buffer. */
232185029Spjd	memset(buf, 'A', sizeof(buf));
233185029Spjd
234185029Spjd	/* Open a FILE * in binary mode. */
235185029Spjd	fp = fmemopen(buf, sizeof(buf), "w+b");
236185029Spjd	ATF_REQUIRE(fp != NULL);
237185029Spjd
238185029Spjd	/* Write some data into it. */
239185029Spjd	nofw = fwrite(str, 1, strlen(str), fp);
240185029Spjd	ATF_REQUIRE(nofw == strlen(str));
241185029Spjd
242185029Spjd	/* Make sure that the buffer doesn't contain any NULL bytes. */
243185029Spjd	for (i = 0; i < sizeof(buf); i++)
244185029Spjd		ATF_REQUIRE(buf[i] != '\0');
245185029Spjd
246185029Spjd	/* Close the FILE *. */
247185029Spjd	rc = fclose(fp);
248185029Spjd	ATF_REQUIRE(rc == 0);
249185029Spjd}
250185029Spjd
251185029SpjdATF_TC_WITHOUT_HEAD(test_append_binary_pos);
252185029SpjdATF_TC_BODY(test_append_binary_pos, tc)
253185029Spjd{
254185029Spjd	/*
255185029Spjd	 * For compatibility with other implementations (glibc), we set the
256185029Spjd	 * position to 0 when opening an automatically allocated binary stream
257185029Spjd	 * for appending.
258185029Spjd	 */
259185029Spjd
260185029Spjd	FILE *fp;
261185029Spjd
262185029Spjd	fp = fmemopen(NULL, 16, "ab+");
263185029Spjd	ATF_REQUIRE(ftell(fp) == 0L);
264185029Spjd	fclose(fp);
265185029Spjd
266185029Spjd	/*
267185029Spjd	 * Make sure that a pre-allocated buffer behaves correctly.
268185029Spjd	 */
269185029Spjd	char buf[] = "Hello";
270185029Spjd	fp = fmemopen(buf, sizeof(buf), "ab+");
271185029Spjd	ATF_REQUIRE(ftell(fp) == strlen(buf));
272185029Spjd	fclose(fp);
273185029Spjd}
274185029Spjd
275185029SpjdATF_TC_WITHOUT_HEAD(test_size_0);
276185029SpjdATF_TC_BODY(test_size_0, tc)
277185029Spjd{
278185029Spjd	/*
279185029Spjd	 * POSIX mandates that we return EINVAL if size is 0.
280185029Spjd	 */
281185029Spjd
282185029Spjd	FILE *fp;
283185029Spjd
284185029Spjd	fp = fmemopen(NULL, 0, "r+");
285185029Spjd	ATF_REQUIRE(fp == NULL);
286185029Spjd	ATF_REQUIRE(errno == EINVAL);
287185029Spjd}
288185029Spjd
289185029SpjdATF_TP_ADD_TCS(tp)
290185029Spjd{
291185029Spjd
292185029Spjd	ATF_TP_ADD_TC(tp, test_autoalloc);
293185029Spjd	ATF_TP_ADD_TC(tp, test_preexisting);
294185029Spjd	ATF_TP_ADD_TC(tp, test_data_length);
295185029Spjd	ATF_TP_ADD_TC(tp, test_binary);
296185029Spjd	ATF_TP_ADD_TC(tp, test_append_binary_pos);
297185029Spjd	ATF_TP_ADD_TC(tp, test_size_0);
298185029Spjd
299185029Spjd	return (atf_no_error());
300185029Spjd}
301185029Spjd