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
41252343Sjhbtest_preexisting()
42246120Sgahr{
43246120Sgahr	/*
44252343Sjhb	 * 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
56252343Sjhb	/* Open a FILE * using fmemopen. */
57252343Sjhb	fp = fmemopen(buf, sizeof(buf), "w");
58252343Sjhb	assert(fp != NULL);
59246120Sgahr
60252343Sjhb	/* Write to the buffer. */
61252343Sjhb	nofw = fwrite(str, 1, sizeof(str), fp);
62252343Sjhb	assert(nofw == sizeof(str));
63246120Sgahr
64252343Sjhb	/* Close the FILE *. */
65252343Sjhb	rc = fclose(fp);
66252343Sjhb	assert(rc == 0);
67246120Sgahr
68252343Sjhb	/* Re-open the FILE * to read back the data. */
69252343Sjhb	fp = fmemopen(buf, sizeof(buf), "r");
70252343Sjhb	assert(fp != NULL);
71246120Sgahr
72252343Sjhb	/* Read from the buffer. */
73252343Sjhb	bzero(buf2, sizeof(buf2));
74252343Sjhb	nofr = fread(buf2, 1, sizeof(buf2), fp);
75252343Sjhb	assert(nofr == sizeof(buf2));
76246120Sgahr
77252343Sjhb	/*
78252343Sjhb	 * Since a write on a FILE * retrieved by fmemopen
79246120Sgahr	 * will add a '\0' (if there's space), we can check
80252343Sjhb	 * the strings for equality.
81252343Sjhb	 */
82252343Sjhb	assert(strcmp(str, buf2) == 0);
83246120Sgahr
84252343Sjhb	/* Close the FILE *. */
85252343Sjhb	rc = fclose(fp);
86252343Sjhb	assert(rc == 0);
87246120Sgahr
88252343Sjhb	/* Now open a FILE * on the first 4 bytes of the string. */
89252343Sjhb	fp = fmemopen(str, 4, "w");
90252343Sjhb	assert(fp != NULL);
91246120Sgahr
92252343Sjhb	/*
93252343Sjhb	 * Try to write more bytes than we shoud, we'll get a short count (4).
94252343Sjhb	 */
95252343Sjhb	nofw = fwrite(str2, 1, sizeof(str2), fp);
96252343Sjhb	assert(nofw == 4);
97246120Sgahr
98252343Sjhb	/* Close the FILE *. */
99252343Sjhb	rc = fclose(fp);
100246120Sgahr
101252343Sjhb	/* Check that the string was not modified after the first 4 bytes. */
102252343Sjhb	assert(strcmp(str, str3) == 0);
103246120Sgahr}
104246120Sgahr
105246120Sgahrvoid
106252343Sjhbtest_autoalloc()
107246120Sgahr{
108246120Sgahr	/*
109252343Sjhb	 * 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
118252343Sjhb	/* Open a FILE * using fmemopen. */
119252343Sjhb	fp = fmemopen(NULL, 512, "w+");
120252343Sjhb	assert(fp != NULL);
121246120Sgahr
122246120Sgahr	/* fill the buffer */
123246120Sgahr	for (i = 0; i < 512; i++) {
124252343Sjhb		nofw = fwrite("a", 1, 1, fp);
125252343Sjhb		assert(nofw == 1);
126246120Sgahr	}
127246120Sgahr
128252343Sjhb	/* Get the current position into the stream. */
129252343Sjhb	pos = ftell(fp);
130252343Sjhb	assert(pos == 512);
131246120Sgahr
132252343Sjhb	/*
133252343Sjhb	 * Try to write past the end, we should get a short object count (0)
134252343Sjhb	 */
135252343Sjhb	nofw = fwrite("a", 1, 1, fp);
136252343Sjhb	assert(nofw == 0);
137246120Sgahr
138252343Sjhb	/* Close the FILE *. */
139252343Sjhb	rc = fclose(fp);
140252343Sjhb	assert(rc == 0);
141246120Sgahr}
142246120Sgahr
143252343Sjhbvoid
144252343Sjhbtest_data_length()
145252343Sjhb{
146252343Sjhb	/*
147252343Sjhb	 * Here we test that a read operation doesn't go past the end of the
148252343Sjhb	 * data actually written, and that a SEEK_END seeks from the end of the
149252343Sjhb	 * data, not of the whole buffer.
150252343Sjhb	 */
151252343Sjhb	FILE *fp;
152252343Sjhb	char buf[512] = {'\0'};
153252343Sjhb	char str[]  = "Test data length. ";
154252343Sjhb	char str2[] = "Do we have two sentences?";
155252343Sjhb	char str3[sizeof(str) + sizeof(str2) -1];
156252343Sjhb	long pos;
157252343Sjhb	size_t nofw, nofr;
158252343Sjhb	int rc;
159252343Sjhb
160252343Sjhb	/* Open a FILE * for updating our buffer. */
161252343Sjhb	fp = fmemopen(buf, sizeof(buf), "w+");
162252343Sjhb	assert(fp != NULL);
163252343Sjhb
164252343Sjhb	/* Write our string into the buffer. */
165252343Sjhb	nofw = fwrite(str, 1, sizeof(str), fp);
166252343Sjhb	assert(nofw == sizeof(str));
167252343Sjhb
168252343Sjhb	/*
169252343Sjhb	 * Now seek to the end and check that ftell
170252343Sjhb	 * gives us sizeof(str).
171252343Sjhb	 */
172252343Sjhb	rc = fseek(fp, 0, SEEK_END);
173252343Sjhb	assert(rc == 0);
174252343Sjhb	pos = ftell(fp);
175252343Sjhb	assert(pos == sizeof(str));
176252343Sjhb
177252343Sjhb	/* Close the FILE *. */
178252343Sjhb	rc = fclose(fp);
179252343Sjhb	assert(rc == 0);
180252343Sjhb
181252343Sjhb	/* Reopen the buffer for appending. */
182252343Sjhb	fp = fmemopen(buf, sizeof(buf), "a+");
183252343Sjhb	assert(fp != NULL);
184252343Sjhb
185252343Sjhb	/* We should now be writing after the first string. */
186252343Sjhb	nofw = fwrite(str2, 1, sizeof(str2), fp);
187252343Sjhb	assert(nofw == sizeof(str2));
188252343Sjhb
189252343Sjhb	/* Rewind the FILE *. */
190252343Sjhb	rc = fseek(fp, 0, SEEK_SET);
191252343Sjhb	assert(rc == 0);
192252343Sjhb
193252343Sjhb	/* Make sure we're at the beginning. */
194252343Sjhb	pos = ftell(fp);
195252343Sjhb	assert(pos == 0);
196252343Sjhb
197252343Sjhb	/* Read the whole buffer. */
198252343Sjhb	nofr = fread(str3, 1, sizeof(buf), fp);
199252343Sjhb	assert(nofr == sizeof(str3));
200252343Sjhb
201252343Sjhb	/* Make sure the two strings are there. */
202252343Sjhb	assert(strncmp(str3, str, sizeof(str) - 1) == 0);
203252343Sjhb	assert(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
204252343Sjhb
205252343Sjhb	/* Close the FILE *. */
206252343Sjhb	rc = fclose(fp);
207252343Sjhb	assert(rc == 0);
208252343Sjhb}
209252343Sjhb
210252343Sjhbvoid
211252343Sjhbtest_binary()
212252343Sjhb{
213252343Sjhb	/*
214252343Sjhb	 * Make sure that NULL bytes are never appended when opening a buffer
215252343Sjhb	 * in binary mode.
216252343Sjhb	 */
217252343Sjhb
218252343Sjhb	FILE *fp;
219252343Sjhb	char buf[20];
220252343Sjhb	char str[] = "Test";
221252343Sjhb	size_t nofw;
222252343Sjhb	int rc, i;
223252343Sjhb
224252343Sjhb	/* Pre-fill the buffer. */
225252343Sjhb	memset(buf, 'A', sizeof(buf));
226252343Sjhb
227252343Sjhb	/* Open a FILE * in binary mode. */
228252343Sjhb	fp = fmemopen(buf, sizeof(buf), "w+b");
229252343Sjhb	assert(fp != NULL);
230252343Sjhb
231252343Sjhb	/* Write some data into it. */
232252343Sjhb	nofw = fwrite(str, 1, strlen(str), fp);
233252343Sjhb	assert(nofw == strlen(str));
234252343Sjhb
235252343Sjhb	/* Make sure that the buffer doesn't contain any NULL bytes. */
236252343Sjhb	for (i = 0; i < sizeof(buf); i++)
237252343Sjhb		assert(buf[i] != '\0');
238252343Sjhb
239252343Sjhb	/* Close the FILE *. */
240252343Sjhb	rc = fclose(fp);
241252343Sjhb	assert(rc == 0);
242252343Sjhb}
243252343Sjhb
244246120Sgahrint
245252343Sjhbmain(void)
246246120Sgahr{
247252343Sjhb	test_autoalloc();
248252343Sjhb	test_preexisting();
249252343Sjhb	test_data_length();
250252343Sjhb	test_binary();
251246120Sgahr	return (0);
252246120Sgahr}
253