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$");
33246120Sgahr
34246120Sgahr#include <assert.h>
35246120Sgahr#include <errno.h>
36246120Sgahr#include <stdio.h>
37246120Sgahr#include <string.h>
38246120Sgahr#include <strings.h>
39246120Sgahr
40246120Sgahrvoid
41246206Sgahrtest_preexisting()
42246120Sgahr{
43246120Sgahr	/*
44246148Sgahr	 * Use a pre-existing buffer.
45246120Sgahr	 */
46246120Sgahr
47246120Sgahr	char buf[512];
48246120Sgahr	char buf2[512];
49246120Sgahr	char str[]  = "Test writing some stuff";
50246120Sgahr	char str2[] = "AAAAAAAAA";
51246120Sgahr	char str3[] = "AAAA writing some stuff";
52246120Sgahr	FILE *fp;
53246120Sgahr	size_t nofw, nofr;
54246120Sgahr	int rc;
55246120Sgahr
56246148Sgahr	/* Open a FILE * using fmemopen. */
57246206Sgahr	fp = fmemopen(buf, sizeof(buf), "w");
58246206Sgahr	assert(fp != NULL);
59246120Sgahr
60246148Sgahr	/* Write to the buffer. */
61246206Sgahr	nofw = fwrite(str, 1, sizeof(str), fp);
62246206Sgahr	assert(nofw == sizeof(str));
63246120Sgahr
64246148Sgahr	/* Close the FILE *. */
65246206Sgahr	rc = fclose(fp);
66246206Sgahr	assert(rc == 0);
67246120Sgahr
68246148Sgahr	/* Re-open the FILE * to read back the data. */
69246206Sgahr	fp = fmemopen(buf, sizeof(buf), "r");
70246206Sgahr	assert(fp != NULL);
71246120Sgahr
72246148Sgahr	/* Read from the buffer. */
73246206Sgahr	bzero(buf2, sizeof(buf2));
74246206Sgahr	nofr = fread(buf2, 1, sizeof(buf2), fp);
75246206Sgahr	assert(nofr == sizeof(buf2));
76246120Sgahr
77246148Sgahr	/*
78246148Sgahr	 * Since a write on a FILE * retrieved by fmemopen
79246120Sgahr	 * will add a '\0' (if there's space), we can check
80246148Sgahr	 * the strings for equality.
81246148Sgahr	 */
82246206Sgahr	assert(strcmp(str, buf2) == 0);
83246120Sgahr
84246148Sgahr	/* Close the FILE *. */
85246206Sgahr	rc = fclose(fp);
86246206Sgahr	assert(rc == 0);
87246120Sgahr
88246148Sgahr	/* Now open a FILE * on the first 4 bytes of the string. */
89246206Sgahr	fp = fmemopen(str, 4, "w");
90246206Sgahr	assert(fp != NULL);
91246120Sgahr
92246148Sgahr	/*
93246148Sgahr	 * Try to write more bytes than we shoud, we'll get a short count (4).
94246148Sgahr	 */
95246206Sgahr	nofw = fwrite(str2, 1, sizeof(str2), fp);
96246206Sgahr	assert(nofw == 4);
97246120Sgahr
98246148Sgahr	/* Close the FILE *. */
99246206Sgahr	rc = fclose(fp);
100246120Sgahr
101246148Sgahr	/* Check that the string was not modified after the first 4 bytes. */
102246206Sgahr	assert(strcmp(str, str3) == 0);
103246120Sgahr}
104246120Sgahr
105246120Sgahrvoid
106246206Sgahrtest_autoalloc()
107246120Sgahr{
108246120Sgahr	/*
109246148Sgahr	 * Let fmemopen allocate the buffer.
110246120Sgahr	 */
111246120Sgahr
112246120Sgahr	char str[] = "A quick test";
113246120Sgahr	FILE *fp;
114246120Sgahr	long pos;
115246120Sgahr	size_t nofw, nofr, i;
116246120Sgahr	int rc;
117246120Sgahr
118246148Sgahr	/* Open a FILE * using fmemopen. */
119246206Sgahr	fp = fmemopen(NULL, 512, "w+");
120246206Sgahr	assert(fp != NULL);
121246120Sgahr
122246120Sgahr	/* fill the buffer */
123246120Sgahr	for (i = 0; i < 512; i++) {
124246206Sgahr		nofw = fwrite("a", 1, 1, fp);
125246206Sgahr		assert(nofw == 1);
126246120Sgahr	}
127246120Sgahr
128246148Sgahr	/* Get the current position into the stream. */
129246206Sgahr	pos = ftell(fp);
130246206Sgahr	assert(pos == 512);
131246120Sgahr
132246148Sgahr	/*
133246148Sgahr	 * Try to write past the end, we should get a short object count (0)
134246148Sgahr	 */
135246206Sgahr	nofw = fwrite("a", 1, 1, fp);
136246206Sgahr	assert(nofw == 0);
137246120Sgahr
138246148Sgahr	/* Close the FILE *. */
139246206Sgahr	rc = fclose(fp);
140246206Sgahr	assert(rc == 0);
141246120Sgahr}
142246120Sgahr
143246148Sgahrvoid
144246206Sgahrtest_data_length()
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+");
162246206Sgahr	assert(fp != NULL);
163246148Sgahr
164246148Sgahr	/* Write our string into the buffer. */
165246206Sgahr	nofw = fwrite(str, 1, sizeof(str), fp);
166246206Sgahr	assert(nofw == sizeof(str));
167246148Sgahr
168246148Sgahr	/*
169246148Sgahr	 * Now seek to the end and check that ftell
170246148Sgahr	 * gives us sizeof(str).
171246148Sgahr	 */
172246206Sgahr	rc = fseek(fp, 0, SEEK_END);
173246206Sgahr	assert(rc == 0);
174246206Sgahr	pos = ftell(fp);
175246206Sgahr	assert(pos == sizeof(str));
176246148Sgahr
177246148Sgahr	/* Close the FILE *. */
178246206Sgahr	rc = fclose(fp);
179246206Sgahr	assert(rc == 0);
180246148Sgahr
181246148Sgahr	/* Reopen the buffer for appending. */
182246206Sgahr	fp = fmemopen(buf, sizeof(buf), "a+");
183246206Sgahr	assert(fp != NULL);
184246148Sgahr
185246148Sgahr	/* We should now be writing after the first string. */
186246206Sgahr	nofw = fwrite(str2, 1, sizeof(str2), fp);
187246206Sgahr	assert(nofw == sizeof(str2));
188246148Sgahr
189246148Sgahr	/* Rewind the FILE *. */
190246206Sgahr	rc = fseek(fp, 0, SEEK_SET);
191246206Sgahr	assert(rc == 0);
192246148Sgahr
193246148Sgahr	/* Make sure we're at the beginning. */
194246206Sgahr	pos = ftell(fp);
195246206Sgahr	assert(pos == 0);
196246148Sgahr
197246148Sgahr	/* Read the whole buffer. */
198246206Sgahr	nofr = fread(str3, 1, sizeof(buf), fp);
199246206Sgahr	assert(nofr == sizeof(str3));
200246148Sgahr
201246148Sgahr	/* Make sure the two strings are there. */
202246206Sgahr	assert(strncmp(str3, str, sizeof(str) - 1) == 0);
203246206Sgahr	assert(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
204246148Sgahr
205246148Sgahr	/* Close the FILE *. */
206246206Sgahr	rc = fclose(fp);
207246206Sgahr	assert(rc == 0);
208246148Sgahr}
209246148Sgahr
210246148Sgahrvoid
211246206Sgahrtest_binary()
212246148Sgahr{
213246148Sgahr	/*
214246148Sgahr	 * Make sure that NULL bytes are never appended when opening a buffer
215246148Sgahr	 * in binary mode.
216246148Sgahr	 */
217246148Sgahr
218246148Sgahr	FILE *fp;
219246148Sgahr	char buf[20];
220246148Sgahr	char str[] = "Test";
221246148Sgahr	size_t nofw;
222246148Sgahr	int rc, i;
223246148Sgahr
224246148Sgahr	/* Pre-fill the buffer. */
225246206Sgahr	memset(buf, 'A', sizeof(buf));
226246148Sgahr
227246148Sgahr	/* Open a FILE * in binary mode. */
228246206Sgahr	fp = fmemopen(buf, sizeof(buf), "w+b");
229246206Sgahr	assert(fp != NULL);
230246148Sgahr
231246148Sgahr	/* Write some data into it. */
232246206Sgahr	nofw = fwrite(str, 1, strlen(str), fp);
233246206Sgahr	assert(nofw == strlen(str));
234246148Sgahr
235246148Sgahr	/* Make sure that the buffer doesn't contain any NULL bytes. */
236246148Sgahr	for (i = 0; i < sizeof(buf); i++)
237246206Sgahr		assert(buf[i] != '\0');
238246148Sgahr
239246148Sgahr	/* Close the FILE *. */
240246206Sgahr	rc = fclose(fp);
241246206Sgahr	assert(rc == 0);
242246148Sgahr}
243246148Sgahr
244246120Sgahrint
245246206Sgahrmain(void)
246246120Sgahr{
247246206Sgahr	test_autoalloc();
248246206Sgahr	test_preexisting();
249246206Sgahr	test_data_length();
250246206Sgahr	test_binary();
251246120Sgahr	return (0);
252246120Sgahr}
253