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: releng/11.0/lib/libc/tests/stdio/fmemopen2_test.c 298311 2016-04-19 23:59:10Z 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	FILE *fp;
109246120Sgahr	long pos;
110290860Sbapt	size_t nofw, i;
111246120Sgahr	int rc;
112246120Sgahr
113246148Sgahr	/* Open a FILE * using fmemopen. */
114246206Sgahr	fp = fmemopen(NULL, 512, "w+");
115274592Sngie	ATF_REQUIRE(fp != NULL);
116246120Sgahr
117246120Sgahr	/* fill the buffer */
118246120Sgahr	for (i = 0; i < 512; i++) {
119246206Sgahr		nofw = fwrite("a", 1, 1, fp);
120274592Sngie		ATF_REQUIRE(nofw == 1);
121246120Sgahr	}
122246120Sgahr
123246148Sgahr	/* Get the current position into the stream. */
124246206Sgahr	pos = ftell(fp);
125274592Sngie	ATF_REQUIRE(pos == 512);
126246120Sgahr
127290537Sngie	/* Try to write past the end, we should get a short object count (0) */
128246206Sgahr	nofw = fwrite("a", 1, 1, fp);
129274592Sngie	ATF_REQUIRE(nofw == 0);
130246120Sgahr
131246148Sgahr	/* Close the FILE *. */
132246206Sgahr	rc = fclose(fp);
133274592Sngie	ATF_REQUIRE(rc == 0);
134266971Sgahr
135266971Sgahr	/* Open a FILE * using a wrong mode */
136266971Sgahr	fp = fmemopen(NULL, 512, "r");
137274592Sngie	ATF_REQUIRE(fp == NULL);
138266971Sgahr
139266971Sgahr	fp = fmemopen(NULL, 512, "w");
140274592Sngie	ATF_REQUIRE(fp == NULL);
141246120Sgahr}
142246120Sgahr
143274592SngieATF_TC_WITHOUT_HEAD(test_data_length);
144274592SngieATF_TC_BODY(test_data_length, tc)
145246148Sgahr{
146246148Sgahr	/*
147246148Sgahr	 * Here we test that a read operation doesn't go past the end of the
148246148Sgahr	 * data actually written, and that a SEEK_END seeks from the end of the
149246148Sgahr	 * data, not of the whole buffer.
150246148Sgahr	 */
151246148Sgahr	FILE *fp;
152246148Sgahr	char buf[512] = {'\0'};
153246148Sgahr	char str[]  = "Test data length. ";
154246148Sgahr	char str2[] = "Do we have two sentences?";
155246148Sgahr	char str3[sizeof(str) + sizeof(str2) -1];
156246148Sgahr	long pos;
157246148Sgahr	size_t nofw, nofr;
158246148Sgahr	int rc;
159246148Sgahr
160246148Sgahr	/* Open a FILE * for updating our buffer. */
161246206Sgahr	fp = fmemopen(buf, sizeof(buf), "w+");
162274592Sngie	ATF_REQUIRE(fp != NULL);
163246148Sgahr
164246148Sgahr	/* Write our string into the buffer. */
165246206Sgahr	nofw = fwrite(str, 1, sizeof(str), fp);
166274592Sngie	ATF_REQUIRE(nofw == sizeof(str));
167246148Sgahr
168290537Sngie	/* Now seek to the end and check that ftell gives us sizeof(str). */
169246206Sgahr	rc = fseek(fp, 0, SEEK_END);
170274592Sngie	ATF_REQUIRE(rc == 0);
171246206Sgahr	pos = ftell(fp);
172274592Sngie	ATF_REQUIRE(pos == sizeof(str));
173246148Sgahr
174246148Sgahr	/* Close the FILE *. */
175246206Sgahr	rc = fclose(fp);
176274592Sngie	ATF_REQUIRE(rc == 0);
177246148Sgahr
178246148Sgahr	/* Reopen the buffer for appending. */
179246206Sgahr	fp = fmemopen(buf, sizeof(buf), "a+");
180274592Sngie	ATF_REQUIRE(fp != NULL);
181246148Sgahr
182246148Sgahr	/* We should now be writing after the first string. */
183246206Sgahr	nofw = fwrite(str2, 1, sizeof(str2), fp);
184274592Sngie	ATF_REQUIRE(nofw == sizeof(str2));
185246148Sgahr
186246148Sgahr	/* Rewind the FILE *. */
187246206Sgahr	rc = fseek(fp, 0, SEEK_SET);
188274592Sngie	ATF_REQUIRE(rc == 0);
189246148Sgahr
190246148Sgahr	/* Make sure we're at the beginning. */
191246206Sgahr	pos = ftell(fp);
192274592Sngie	ATF_REQUIRE(pos == 0);
193246148Sgahr
194246148Sgahr	/* Read the whole buffer. */
195246206Sgahr	nofr = fread(str3, 1, sizeof(buf), fp);
196274592Sngie	ATF_REQUIRE(nofr == sizeof(str3));
197246148Sgahr
198246148Sgahr	/* Make sure the two strings are there. */
199274592Sngie	ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
200274592Sngie	ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
201246148Sgahr
202246148Sgahr	/* Close the FILE *. */
203246206Sgahr	rc = fclose(fp);
204274592Sngie	ATF_REQUIRE(rc == 0);
205246148Sgahr}
206246148Sgahr
207274592SngieATF_TC_WITHOUT_HEAD(test_binary);
208274592SngieATF_TC_BODY(test_binary, tc)
209246148Sgahr{
210246148Sgahr	/*
211246148Sgahr	 * Make sure that NULL bytes are never appended when opening a buffer
212246148Sgahr	 * in binary mode.
213246148Sgahr	 */
214246148Sgahr
215246148Sgahr	FILE *fp;
216246148Sgahr	char buf[20];
217246148Sgahr	char str[] = "Test";
218246148Sgahr	size_t nofw;
219246148Sgahr	int rc, i;
220246148Sgahr
221246148Sgahr	/* Pre-fill the buffer. */
222246206Sgahr	memset(buf, 'A', sizeof(buf));
223246148Sgahr
224246148Sgahr	/* Open a FILE * in binary mode. */
225246206Sgahr	fp = fmemopen(buf, sizeof(buf), "w+b");
226274592Sngie	ATF_REQUIRE(fp != NULL);
227246148Sgahr
228246148Sgahr	/* Write some data into it. */
229246206Sgahr	nofw = fwrite(str, 1, strlen(str), fp);
230274592Sngie	ATF_REQUIRE(nofw == strlen(str));
231246148Sgahr
232246148Sgahr	/* Make sure that the buffer doesn't contain any NULL bytes. */
233246148Sgahr	for (i = 0; i < sizeof(buf); i++)
234274592Sngie		ATF_REQUIRE(buf[i] != '\0');
235246148Sgahr
236246148Sgahr	/* Close the FILE *. */
237246206Sgahr	rc = fclose(fp);
238274592Sngie	ATF_REQUIRE(rc == 0);
239246148Sgahr}
240246148Sgahr
241274592SngieATF_TC_WITHOUT_HEAD(test_append_binary_pos);
242274592SngieATF_TC_BODY(test_append_binary_pos, tc)
243266971Sgahr{
244266971Sgahr	/*
245266971Sgahr	 * For compatibility with other implementations (glibc), we set the
246266971Sgahr	 * position to 0 when opening an automatically allocated binary stream
247266971Sgahr	 * for appending.
248266971Sgahr	 */
249266971Sgahr
250266971Sgahr	FILE *fp;
251266971Sgahr
252266971Sgahr	fp = fmemopen(NULL, 16, "ab+");
253298311Sngie	ATF_REQUIRE(fp != NULL);
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+");
260298311Sngie	ATF_REQUIRE(fp != NULL);
261274592Sngie	ATF_REQUIRE(ftell(fp) == strlen(buf));
262266971Sgahr	fclose(fp);
263266971Sgahr}
264266971Sgahr
265274592SngieATF_TC_WITHOUT_HEAD(test_size_0);
266274592SngieATF_TC_BODY(test_size_0, tc)
267266971Sgahr{
268290537Sngie	/* POSIX mandates that we return EINVAL if size is 0. */
269266971Sgahr
270266971Sgahr	FILE *fp;
271266971Sgahr
272266971Sgahr	fp = fmemopen(NULL, 0, "r+");
273274592Sngie	ATF_REQUIRE(fp == NULL);
274274592Sngie	ATF_REQUIRE(errno == EINVAL);
275266971Sgahr}
276266971Sgahr
277274592SngieATF_TP_ADD_TCS(tp)
278246120Sgahr{
279274592Sngie
280274592Sngie	ATF_TP_ADD_TC(tp, test_autoalloc);
281274592Sngie	ATF_TP_ADD_TC(tp, test_preexisting);
282274592Sngie	ATF_TP_ADD_TC(tp, test_data_length);
283274592Sngie	ATF_TP_ADD_TC(tp, test_binary);
284274592Sngie	ATF_TP_ADD_TC(tp, test_append_binary_pos);
285274592Sngie	ATF_TP_ADD_TC(tp, test_size_0);
286274592Sngie
287274592Sngie	return (atf_no_error());
288246120Sgahr}
289