fmemopen2_test.c revision 290537
1246120Sgahr/*-
2246120SgahrCopyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
3246120Sgahr
4246120SgahrRedistribution and use in source and binary forms, with or without
5246120Sgahrmodification, are permitted provided that the following conditions
6246120Sgahrare met:
7246120Sgahr1. Redistributions of source code must retain the above copyright
8246120Sgahr   notice, this list of conditions and the following disclaimer.
9246120Sgahr2. Redistributions in binary form must reproduce the above copyright
10246120Sgahr   notice, this list of conditions and the following disclaimer in the
11246120Sgahr   documentation and/or other materials provided with the distribution.
12246120Sgahr
13246120SgahrTHIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14246120SgahrANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15246120SgahrIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16246120SgahrARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17246120SgahrFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18246120SgahrDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19246120SgahrOR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20246120SgahrHOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21246120SgahrLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22246120SgahrOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23246120SgahrSUCH DAMAGE.
24246120Sgahr*/
25246120Sgahr
26246120Sgahr/*
27246120Sgahr * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
28246120Sgahr * a FILE * retrieved using fmemopen()
29246120Sgahr */
30246120Sgahr
31246120Sgahr#include <sys/cdefs.h>
32246120Sgahr__FBSDID("$FreeBSD: head/lib/libc/tests/stdio/fmemopen2_test.c 290537 2015-11-08 06:37:50Z ngie $");
33246120Sgahr
34246120Sgahr#include <errno.h>
35246120Sgahr#include <stdio.h>
36246120Sgahr#include <string.h>
37246120Sgahr#include <strings.h>
38290537Sngie
39274592Sngie#include <atf-c.h>
40246120Sgahr
41274592SngieATF_TC_WITHOUT_HEAD(test_preexisting);
42274592SngieATF_TC_BODY(test_preexisting, tc)
43246120Sgahr{
44290537Sngie	/* Use a pre-existing buffer. */
45246120Sgahr	char buf[512];
46246120Sgahr	char buf2[512];
47246120Sgahr	char str[]  = "Test writing some stuff";
48246120Sgahr	char str2[] = "AAAAAAAAA";
49246120Sgahr	char str3[] = "AAAA writing some stuff";
50246120Sgahr	FILE *fp;
51246120Sgahr	size_t nofw, nofr;
52246120Sgahr	int rc;
53246120Sgahr
54246148Sgahr	/* Open a FILE * using fmemopen. */
55246206Sgahr	fp = fmemopen(buf, sizeof(buf), "w");
56274592Sngie	ATF_REQUIRE(fp != NULL);
57246120Sgahr
58246148Sgahr	/* Write to the buffer. */
59246206Sgahr	nofw = fwrite(str, 1, sizeof(str), fp);
60274592Sngie	ATF_REQUIRE(nofw == sizeof(str));
61246120Sgahr
62246148Sgahr	/* Close the FILE *. */
63246206Sgahr	rc = fclose(fp);
64274592Sngie	ATF_REQUIRE(rc == 0);
65246120Sgahr
66246148Sgahr	/* Re-open the FILE * to read back the data. */
67246206Sgahr	fp = fmemopen(buf, sizeof(buf), "r");
68274592Sngie	ATF_REQUIRE(fp != NULL);
69246120Sgahr
70246148Sgahr	/* Read from the buffer. */
71246206Sgahr	bzero(buf2, sizeof(buf2));
72246206Sgahr	nofr = fread(buf2, 1, sizeof(buf2), fp);
73274592Sngie	ATF_REQUIRE(nofr == sizeof(buf2));
74246120Sgahr
75290537Sngie	/*
76246148Sgahr	 * Since a write on a FILE * retrieved by fmemopen
77246120Sgahr	 * will add a '\0' (if there's space), we can check
78246148Sgahr	 * the strings for equality.
79246148Sgahr	 */
80274592Sngie	ATF_REQUIRE(strcmp(str, buf2) == 0);
81246120Sgahr
82246148Sgahr	/* Close the FILE *. */
83246206Sgahr	rc = fclose(fp);
84274592Sngie	ATF_REQUIRE(rc == 0);
85246120Sgahr
86246148Sgahr	/* Now open a FILE * on the first 4 bytes of the string. */
87246206Sgahr	fp = fmemopen(str, 4, "w");
88274592Sngie	ATF_REQUIRE(fp != NULL);
89246120Sgahr
90246148Sgahr	/*
91246148Sgahr	 * Try to write more bytes than we shoud, we'll get a short count (4).
92246148Sgahr	 */
93246206Sgahr	nofw = fwrite(str2, 1, sizeof(str2), fp);
94274592Sngie	ATF_REQUIRE(nofw == 4);
95246120Sgahr
96246148Sgahr	/* Close the FILE *. */
97246206Sgahr	rc = fclose(fp);
98288382Sdelphij	ATF_REQUIRE(rc == 0);
99246120Sgahr
100246148Sgahr	/* Check that the string was not modified after the first 4 bytes. */
101274592Sngie	ATF_REQUIRE(strcmp(str, str3) == 0);
102246120Sgahr}
103246120Sgahr
104274592SngieATF_TC_WITHOUT_HEAD(test_autoalloc);
105274592SngieATF_TC_BODY(test_autoalloc, tc)
106246120Sgahr{
107290537Sngie	/* Let fmemopen allocate the buffer. */
108246120Sgahr	char str[] = "A quick test";
109246120Sgahr	FILE *fp;
110246120Sgahr	long pos;
111246120Sgahr	size_t nofw, nofr, i;
112246120Sgahr	int rc;
113246120Sgahr
114246148Sgahr	/* Open a FILE * using fmemopen. */
115246206Sgahr	fp = fmemopen(NULL, 512, "w+");
116274592Sngie	ATF_REQUIRE(fp != NULL);
117246120Sgahr
118246120Sgahr	/* fill the buffer */
119246120Sgahr	for (i = 0; i < 512; i++) {
120246206Sgahr		nofw = fwrite("a", 1, 1, fp);
121274592Sngie		ATF_REQUIRE(nofw == 1);
122246120Sgahr	}
123246120Sgahr
124246148Sgahr	/* Get the current position into the stream. */
125246206Sgahr	pos = ftell(fp);
126274592Sngie	ATF_REQUIRE(pos == 512);
127246120Sgahr
128290537Sngie	/* Try to write past the end, we should get a short object count (0) */
129246206Sgahr	nofw = fwrite("a", 1, 1, fp);
130274592Sngie	ATF_REQUIRE(nofw == 0);
131246120Sgahr
132246148Sgahr	/* Close the FILE *. */
133246206Sgahr	rc = fclose(fp);
134274592Sngie	ATF_REQUIRE(rc == 0);
135266971Sgahr
136266971Sgahr	/* Open a FILE * using a wrong mode */
137266971Sgahr	fp = fmemopen(NULL, 512, "r");
138274592Sngie	ATF_REQUIRE(fp == NULL);
139266971Sgahr
140266971Sgahr	fp = fmemopen(NULL, 512, "w");
141274592Sngie	ATF_REQUIRE(fp == NULL);
142246120Sgahr}
143246120Sgahr
144274592SngieATF_TC_WITHOUT_HEAD(test_data_length);
145274592SngieATF_TC_BODY(test_data_length, tc)
146246148Sgahr{
147246148Sgahr	/*
148246148Sgahr	 * Here we test that a read operation doesn't go past the end of the
149246148Sgahr	 * data actually written, and that a SEEK_END seeks from the end of the
150246148Sgahr	 * data, not of the whole buffer.
151246148Sgahr	 */
152246148Sgahr	FILE *fp;
153246148Sgahr	char buf[512] = {'\0'};
154246148Sgahr	char str[]  = "Test data length. ";
155246148Sgahr	char str2[] = "Do we have two sentences?";
156246148Sgahr	char str3[sizeof(str) + sizeof(str2) -1];
157246148Sgahr	long pos;
158246148Sgahr	size_t nofw, nofr;
159246148Sgahr	int rc;
160246148Sgahr
161246148Sgahr	/* Open a FILE * for updating our buffer. */
162246206Sgahr	fp = fmemopen(buf, sizeof(buf), "w+");
163274592Sngie	ATF_REQUIRE(fp != NULL);
164246148Sgahr
165246148Sgahr	/* Write our string into the buffer. */
166246206Sgahr	nofw = fwrite(str, 1, sizeof(str), fp);
167274592Sngie	ATF_REQUIRE(nofw == sizeof(str));
168246148Sgahr
169290537Sngie	/* Now seek to the end and check that ftell gives us sizeof(str). */
170246206Sgahr	rc = fseek(fp, 0, SEEK_END);
171274592Sngie	ATF_REQUIRE(rc == 0);
172246206Sgahr	pos = ftell(fp);
173274592Sngie	ATF_REQUIRE(pos == sizeof(str));
174246148Sgahr
175246148Sgahr	/* Close the FILE *. */
176246206Sgahr	rc = fclose(fp);
177274592Sngie	ATF_REQUIRE(rc == 0);
178246148Sgahr
179246148Sgahr	/* Reopen the buffer for appending. */
180246206Sgahr	fp = fmemopen(buf, sizeof(buf), "a+");
181274592Sngie	ATF_REQUIRE(fp != NULL);
182246148Sgahr
183246148Sgahr	/* We should now be writing after the first string. */
184246206Sgahr	nofw = fwrite(str2, 1, sizeof(str2), fp);
185274592Sngie	ATF_REQUIRE(nofw == sizeof(str2));
186246148Sgahr
187246148Sgahr	/* Rewind the FILE *. */
188246206Sgahr	rc = fseek(fp, 0, SEEK_SET);
189274592Sngie	ATF_REQUIRE(rc == 0);
190246148Sgahr
191246148Sgahr	/* Make sure we're at the beginning. */
192246206Sgahr	pos = ftell(fp);
193274592Sngie	ATF_REQUIRE(pos == 0);
194246148Sgahr
195246148Sgahr	/* Read the whole buffer. */
196246206Sgahr	nofr = fread(str3, 1, sizeof(buf), fp);
197274592Sngie	ATF_REQUIRE(nofr == sizeof(str3));
198246148Sgahr
199246148Sgahr	/* Make sure the two strings are there. */
200274592Sngie	ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
201274592Sngie	ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
202246148Sgahr
203246148Sgahr	/* Close the FILE *. */
204246206Sgahr	rc = fclose(fp);
205274592Sngie	ATF_REQUIRE(rc == 0);
206246148Sgahr}
207246148Sgahr
208274592SngieATF_TC_WITHOUT_HEAD(test_binary);
209274592SngieATF_TC_BODY(test_binary, tc)
210246148Sgahr{
211246148Sgahr	/*
212246148Sgahr	 * Make sure that NULL bytes are never appended when opening a buffer
213246148Sgahr	 * in binary mode.
214246148Sgahr	 */
215246148Sgahr
216246148Sgahr	FILE *fp;
217246148Sgahr	char buf[20];
218246148Sgahr	char str[] = "Test";
219246148Sgahr	size_t nofw;
220246148Sgahr	int rc, i;
221246148Sgahr
222246148Sgahr	/* Pre-fill the buffer. */
223246206Sgahr	memset(buf, 'A', sizeof(buf));
224246148Sgahr
225246148Sgahr	/* Open a FILE * in binary mode. */
226246206Sgahr	fp = fmemopen(buf, sizeof(buf), "w+b");
227274592Sngie	ATF_REQUIRE(fp != NULL);
228246148Sgahr
229246148Sgahr	/* Write some data into it. */
230246206Sgahr	nofw = fwrite(str, 1, strlen(str), fp);
231274592Sngie	ATF_REQUIRE(nofw == strlen(str));
232246148Sgahr
233246148Sgahr	/* Make sure that the buffer doesn't contain any NULL bytes. */
234246148Sgahr	for (i = 0; i < sizeof(buf); i++)
235274592Sngie		ATF_REQUIRE(buf[i] != '\0');
236246148Sgahr
237246148Sgahr	/* Close the FILE *. */
238246206Sgahr	rc = fclose(fp);
239274592Sngie	ATF_REQUIRE(rc == 0);
240246148Sgahr}
241246148Sgahr
242274592SngieATF_TC_WITHOUT_HEAD(test_append_binary_pos);
243274592SngieATF_TC_BODY(test_append_binary_pos, tc)
244266971Sgahr{
245266971Sgahr	/*
246266971Sgahr	 * For compatibility with other implementations (glibc), we set the
247266971Sgahr	 * position to 0 when opening an automatically allocated binary stream
248266971Sgahr	 * for appending.
249266971Sgahr	 */
250266971Sgahr
251266971Sgahr	FILE *fp;
252266971Sgahr
253266971Sgahr	fp = fmemopen(NULL, 16, "ab+");
254274592Sngie	ATF_REQUIRE(ftell(fp) == 0L);
255266971Sgahr	fclose(fp);
256266971Sgahr
257290537Sngie	/* Make sure that a pre-allocated buffer behaves correctly. */
258266971Sgahr	char buf[] = "Hello";
259266971Sgahr	fp = fmemopen(buf, sizeof(buf), "ab+");
260274592Sngie	ATF_REQUIRE(ftell(fp) == strlen(buf));
261266971Sgahr	fclose(fp);
262266971Sgahr}
263266971Sgahr
264274592SngieATF_TC_WITHOUT_HEAD(test_size_0);
265274592SngieATF_TC_BODY(test_size_0, tc)
266266971Sgahr{
267290537Sngie	/* POSIX mandates that we return EINVAL if size is 0. */
268266971Sgahr
269266971Sgahr	FILE *fp;
270266971Sgahr
271266971Sgahr	fp = fmemopen(NULL, 0, "r+");
272274592Sngie	ATF_REQUIRE(fp == NULL);
273274592Sngie	ATF_REQUIRE(errno == EINVAL);
274266971Sgahr}
275266971Sgahr
276274592SngieATF_TP_ADD_TCS(tp)
277246120Sgahr{
278274592Sngie
279274592Sngie	ATF_TP_ADD_TC(tp, test_autoalloc);
280274592Sngie	ATF_TP_ADD_TC(tp, test_preexisting);
281274592Sngie	ATF_TP_ADD_TC(tp, test_data_length);
282274592Sngie	ATF_TP_ADD_TC(tp, test_binary);
283274592Sngie	ATF_TP_ADD_TC(tp, test_append_binary_pos);
284274592Sngie	ATF_TP_ADD_TC(tp, test_size_0);
285274592Sngie
286274592Sngie	return (atf_no_error());
287246120Sgahr}
288