xref: /freebsd/lib/libc/tests/stdio/fmemopen2_test.c (revision 1ee0219205d3794b5d0dc6d885fa8895a6ec1dbf)
141a3b124SEnji Cooper /*-
241a3b124SEnji Cooper Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
341a3b124SEnji Cooper 
441a3b124SEnji Cooper Redistribution and use in source and binary forms, with or without
541a3b124SEnji Cooper modification, are permitted provided that the following conditions
641a3b124SEnji Cooper are met:
741a3b124SEnji Cooper 1. Redistributions of source code must retain the above copyright
841a3b124SEnji Cooper    notice, this list of conditions and the following disclaimer.
941a3b124SEnji Cooper 2. Redistributions in binary form must reproduce the above copyright
1041a3b124SEnji Cooper    notice, this list of conditions and the following disclaimer in the
1141a3b124SEnji Cooper    documentation and/or other materials provided with the distribution.
1241a3b124SEnji Cooper 
1341a3b124SEnji Cooper THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1441a3b124SEnji Cooper ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1541a3b124SEnji Cooper IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1641a3b124SEnji Cooper ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1741a3b124SEnji Cooper FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1841a3b124SEnji Cooper DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1941a3b124SEnji Cooper OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2041a3b124SEnji Cooper HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2141a3b124SEnji Cooper LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2241a3b124SEnji Cooper OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2341a3b124SEnji Cooper SUCH DAMAGE.
2441a3b124SEnji Cooper */
2541a3b124SEnji Cooper 
2641a3b124SEnji Cooper /*
2741a3b124SEnji Cooper  * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
2841a3b124SEnji Cooper  * a FILE * retrieved using fmemopen()
2941a3b124SEnji Cooper  */
3041a3b124SEnji Cooper 
3141a3b124SEnji Cooper #include <sys/cdefs.h>
3241a3b124SEnji Cooper __FBSDID("$FreeBSD$");
3341a3b124SEnji Cooper 
3441a3b124SEnji Cooper #include <errno.h>
3541a3b124SEnji Cooper #include <stdio.h>
3641a3b124SEnji Cooper #include <string.h>
3741a3b124SEnji Cooper #include <strings.h>
38*1ee02192SEnji Cooper 
3941a3b124SEnji Cooper #include <atf-c.h>
4041a3b124SEnji Cooper 
4141a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_preexisting);
4241a3b124SEnji Cooper ATF_TC_BODY(test_preexisting, tc)
4341a3b124SEnji Cooper {
44*1ee02192SEnji Cooper 	/* Use a pre-existing buffer. */
4541a3b124SEnji Cooper 	char buf[512];
4641a3b124SEnji Cooper 	char buf2[512];
4741a3b124SEnji Cooper 	char str[]  = "Test writing some stuff";
4841a3b124SEnji Cooper 	char str2[] = "AAAAAAAAA";
4941a3b124SEnji Cooper 	char str3[] = "AAAA writing some stuff";
5041a3b124SEnji Cooper 	FILE *fp;
5141a3b124SEnji Cooper 	size_t nofw, nofr;
5241a3b124SEnji Cooper 	int rc;
5341a3b124SEnji Cooper 
5441a3b124SEnji Cooper 	/* Open a FILE * using fmemopen. */
5541a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "w");
5641a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
5741a3b124SEnji Cooper 
5841a3b124SEnji Cooper 	/* Write to the buffer. */
5941a3b124SEnji Cooper 	nofw = fwrite(str, 1, sizeof(str), fp);
6041a3b124SEnji Cooper 	ATF_REQUIRE(nofw == sizeof(str));
6141a3b124SEnji Cooper 
6241a3b124SEnji Cooper 	/* Close the FILE *. */
6341a3b124SEnji Cooper 	rc = fclose(fp);
6441a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
6541a3b124SEnji Cooper 
6641a3b124SEnji Cooper 	/* Re-open the FILE * to read back the data. */
6741a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "r");
6841a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
6941a3b124SEnji Cooper 
7041a3b124SEnji Cooper 	/* Read from the buffer. */
7141a3b124SEnji Cooper 	bzero(buf2, sizeof(buf2));
7241a3b124SEnji Cooper 	nofr = fread(buf2, 1, sizeof(buf2), fp);
7341a3b124SEnji Cooper 	ATF_REQUIRE(nofr == sizeof(buf2));
7441a3b124SEnji Cooper 
7541a3b124SEnji Cooper 	/*
7641a3b124SEnji Cooper 	 * Since a write on a FILE * retrieved by fmemopen
7741a3b124SEnji Cooper 	 * will add a '\0' (if there's space), we can check
7841a3b124SEnji Cooper 	 * the strings for equality.
7941a3b124SEnji Cooper 	 */
8041a3b124SEnji Cooper 	ATF_REQUIRE(strcmp(str, buf2) == 0);
8141a3b124SEnji Cooper 
8241a3b124SEnji Cooper 	/* Close the FILE *. */
8341a3b124SEnji Cooper 	rc = fclose(fp);
8441a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
8541a3b124SEnji Cooper 
8641a3b124SEnji Cooper 	/* Now open a FILE * on the first 4 bytes of the string. */
8741a3b124SEnji Cooper 	fp = fmemopen(str, 4, "w");
8841a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
8941a3b124SEnji Cooper 
9041a3b124SEnji Cooper 	/*
9141a3b124SEnji Cooper 	 * Try to write more bytes than we shoud, we'll get a short count (4).
9241a3b124SEnji Cooper 	 */
9341a3b124SEnji Cooper 	nofw = fwrite(str2, 1, sizeof(str2), fp);
9441a3b124SEnji Cooper 	ATF_REQUIRE(nofw == 4);
9541a3b124SEnji Cooper 
9641a3b124SEnji Cooper 	/* Close the FILE *. */
9741a3b124SEnji Cooper 	rc = fclose(fp);
98b95523e8SXin LI 	ATF_REQUIRE(rc == 0);
9941a3b124SEnji Cooper 
10041a3b124SEnji Cooper 	/* Check that the string was not modified after the first 4 bytes. */
10141a3b124SEnji Cooper 	ATF_REQUIRE(strcmp(str, str3) == 0);
10241a3b124SEnji Cooper }
10341a3b124SEnji Cooper 
10441a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_autoalloc);
10541a3b124SEnji Cooper ATF_TC_BODY(test_autoalloc, tc)
10641a3b124SEnji Cooper {
107*1ee02192SEnji Cooper 	/* Let fmemopen allocate the buffer. */
10841a3b124SEnji Cooper 	char str[] = "A quick test";
10941a3b124SEnji Cooper 	FILE *fp;
11041a3b124SEnji Cooper 	long pos;
11141a3b124SEnji Cooper 	size_t nofw, nofr, i;
11241a3b124SEnji Cooper 	int rc;
11341a3b124SEnji Cooper 
11441a3b124SEnji Cooper 	/* Open a FILE * using fmemopen. */
11541a3b124SEnji Cooper 	fp = fmemopen(NULL, 512, "w+");
11641a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
11741a3b124SEnji Cooper 
11841a3b124SEnji Cooper 	/* fill the buffer */
11941a3b124SEnji Cooper 	for (i = 0; i < 512; i++) {
12041a3b124SEnji Cooper 		nofw = fwrite("a", 1, 1, fp);
12141a3b124SEnji Cooper 		ATF_REQUIRE(nofw == 1);
12241a3b124SEnji Cooper 	}
12341a3b124SEnji Cooper 
12441a3b124SEnji Cooper 	/* Get the current position into the stream. */
12541a3b124SEnji Cooper 	pos = ftell(fp);
12641a3b124SEnji Cooper 	ATF_REQUIRE(pos == 512);
12741a3b124SEnji Cooper 
128*1ee02192SEnji Cooper 	/* Try to write past the end, we should get a short object count (0) */
12941a3b124SEnji Cooper 	nofw = fwrite("a", 1, 1, fp);
13041a3b124SEnji Cooper 	ATF_REQUIRE(nofw == 0);
13141a3b124SEnji Cooper 
13241a3b124SEnji Cooper 	/* Close the FILE *. */
13341a3b124SEnji Cooper 	rc = fclose(fp);
13441a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
13541a3b124SEnji Cooper 
13641a3b124SEnji Cooper 	/* Open a FILE * using a wrong mode */
13741a3b124SEnji Cooper 	fp = fmemopen(NULL, 512, "r");
13841a3b124SEnji Cooper 	ATF_REQUIRE(fp == NULL);
13941a3b124SEnji Cooper 
14041a3b124SEnji Cooper 	fp = fmemopen(NULL, 512, "w");
14141a3b124SEnji Cooper 	ATF_REQUIRE(fp == NULL);
14241a3b124SEnji Cooper }
14341a3b124SEnji Cooper 
14441a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_data_length);
14541a3b124SEnji Cooper ATF_TC_BODY(test_data_length, tc)
14641a3b124SEnji Cooper {
14741a3b124SEnji Cooper 	/*
14841a3b124SEnji Cooper 	 * Here we test that a read operation doesn't go past the end of the
14941a3b124SEnji Cooper 	 * data actually written, and that a SEEK_END seeks from the end of the
15041a3b124SEnji Cooper 	 * data, not of the whole buffer.
15141a3b124SEnji Cooper 	 */
15241a3b124SEnji Cooper 	FILE *fp;
15341a3b124SEnji Cooper 	char buf[512] = {'\0'};
15441a3b124SEnji Cooper 	char str[]  = "Test data length. ";
15541a3b124SEnji Cooper 	char str2[] = "Do we have two sentences?";
15641a3b124SEnji Cooper 	char str3[sizeof(str) + sizeof(str2) -1];
15741a3b124SEnji Cooper 	long pos;
15841a3b124SEnji Cooper 	size_t nofw, nofr;
15941a3b124SEnji Cooper 	int rc;
16041a3b124SEnji Cooper 
16141a3b124SEnji Cooper 	/* Open a FILE * for updating our buffer. */
16241a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "w+");
16341a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
16441a3b124SEnji Cooper 
16541a3b124SEnji Cooper 	/* Write our string into the buffer. */
16641a3b124SEnji Cooper 	nofw = fwrite(str, 1, sizeof(str), fp);
16741a3b124SEnji Cooper 	ATF_REQUIRE(nofw == sizeof(str));
16841a3b124SEnji Cooper 
169*1ee02192SEnji Cooper 	/* Now seek to the end and check that ftell gives us sizeof(str). */
17041a3b124SEnji Cooper 	rc = fseek(fp, 0, SEEK_END);
17141a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
17241a3b124SEnji Cooper 	pos = ftell(fp);
17341a3b124SEnji Cooper 	ATF_REQUIRE(pos == sizeof(str));
17441a3b124SEnji Cooper 
17541a3b124SEnji Cooper 	/* Close the FILE *. */
17641a3b124SEnji Cooper 	rc = fclose(fp);
17741a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
17841a3b124SEnji Cooper 
17941a3b124SEnji Cooper 	/* Reopen the buffer for appending. */
18041a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "a+");
18141a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
18241a3b124SEnji Cooper 
18341a3b124SEnji Cooper 	/* We should now be writing after the first string. */
18441a3b124SEnji Cooper 	nofw = fwrite(str2, 1, sizeof(str2), fp);
18541a3b124SEnji Cooper 	ATF_REQUIRE(nofw == sizeof(str2));
18641a3b124SEnji Cooper 
18741a3b124SEnji Cooper 	/* Rewind the FILE *. */
18841a3b124SEnji Cooper 	rc = fseek(fp, 0, SEEK_SET);
18941a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
19041a3b124SEnji Cooper 
19141a3b124SEnji Cooper 	/* Make sure we're at the beginning. */
19241a3b124SEnji Cooper 	pos = ftell(fp);
19341a3b124SEnji Cooper 	ATF_REQUIRE(pos == 0);
19441a3b124SEnji Cooper 
19541a3b124SEnji Cooper 	/* Read the whole buffer. */
19641a3b124SEnji Cooper 	nofr = fread(str3, 1, sizeof(buf), fp);
19741a3b124SEnji Cooper 	ATF_REQUIRE(nofr == sizeof(str3));
19841a3b124SEnji Cooper 
19941a3b124SEnji Cooper 	/* Make sure the two strings are there. */
20041a3b124SEnji Cooper 	ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
20141a3b124SEnji Cooper 	ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
20241a3b124SEnji Cooper 
20341a3b124SEnji Cooper 	/* Close the FILE *. */
20441a3b124SEnji Cooper 	rc = fclose(fp);
20541a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
20641a3b124SEnji Cooper }
20741a3b124SEnji Cooper 
20841a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_binary);
20941a3b124SEnji Cooper ATF_TC_BODY(test_binary, tc)
21041a3b124SEnji Cooper {
21141a3b124SEnji Cooper 	/*
21241a3b124SEnji Cooper 	 * Make sure that NULL bytes are never appended when opening a buffer
21341a3b124SEnji Cooper 	 * in binary mode.
21441a3b124SEnji Cooper 	 */
21541a3b124SEnji Cooper 
21641a3b124SEnji Cooper 	FILE *fp;
21741a3b124SEnji Cooper 	char buf[20];
21841a3b124SEnji Cooper 	char str[] = "Test";
21941a3b124SEnji Cooper 	size_t nofw;
22041a3b124SEnji Cooper 	int rc, i;
22141a3b124SEnji Cooper 
22241a3b124SEnji Cooper 	/* Pre-fill the buffer. */
22341a3b124SEnji Cooper 	memset(buf, 'A', sizeof(buf));
22441a3b124SEnji Cooper 
22541a3b124SEnji Cooper 	/* Open a FILE * in binary mode. */
22641a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "w+b");
22741a3b124SEnji Cooper 	ATF_REQUIRE(fp != NULL);
22841a3b124SEnji Cooper 
22941a3b124SEnji Cooper 	/* Write some data into it. */
23041a3b124SEnji Cooper 	nofw = fwrite(str, 1, strlen(str), fp);
23141a3b124SEnji Cooper 	ATF_REQUIRE(nofw == strlen(str));
23241a3b124SEnji Cooper 
23341a3b124SEnji Cooper 	/* Make sure that the buffer doesn't contain any NULL bytes. */
23441a3b124SEnji Cooper 	for (i = 0; i < sizeof(buf); i++)
23541a3b124SEnji Cooper 		ATF_REQUIRE(buf[i] != '\0');
23641a3b124SEnji Cooper 
23741a3b124SEnji Cooper 	/* Close the FILE *. */
23841a3b124SEnji Cooper 	rc = fclose(fp);
23941a3b124SEnji Cooper 	ATF_REQUIRE(rc == 0);
24041a3b124SEnji Cooper }
24141a3b124SEnji Cooper 
24241a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
24341a3b124SEnji Cooper ATF_TC_BODY(test_append_binary_pos, tc)
24441a3b124SEnji Cooper {
24541a3b124SEnji Cooper 	/*
24641a3b124SEnji Cooper 	 * For compatibility with other implementations (glibc), we set the
24741a3b124SEnji Cooper 	 * position to 0 when opening an automatically allocated binary stream
24841a3b124SEnji Cooper 	 * for appending.
24941a3b124SEnji Cooper 	 */
25041a3b124SEnji Cooper 
25141a3b124SEnji Cooper 	FILE *fp;
25241a3b124SEnji Cooper 
25341a3b124SEnji Cooper 	fp = fmemopen(NULL, 16, "ab+");
25441a3b124SEnji Cooper 	ATF_REQUIRE(ftell(fp) == 0L);
25541a3b124SEnji Cooper 	fclose(fp);
25641a3b124SEnji Cooper 
257*1ee02192SEnji Cooper 	/* Make sure that a pre-allocated buffer behaves correctly. */
25841a3b124SEnji Cooper 	char buf[] = "Hello";
25941a3b124SEnji Cooper 	fp = fmemopen(buf, sizeof(buf), "ab+");
26041a3b124SEnji Cooper 	ATF_REQUIRE(ftell(fp) == strlen(buf));
26141a3b124SEnji Cooper 	fclose(fp);
26241a3b124SEnji Cooper }
26341a3b124SEnji Cooper 
26441a3b124SEnji Cooper ATF_TC_WITHOUT_HEAD(test_size_0);
26541a3b124SEnji Cooper ATF_TC_BODY(test_size_0, tc)
26641a3b124SEnji Cooper {
267*1ee02192SEnji Cooper 	/* POSIX mandates that we return EINVAL if size is 0. */
26841a3b124SEnji Cooper 
26941a3b124SEnji Cooper 	FILE *fp;
27041a3b124SEnji Cooper 
27141a3b124SEnji Cooper 	fp = fmemopen(NULL, 0, "r+");
27241a3b124SEnji Cooper 	ATF_REQUIRE(fp == NULL);
27341a3b124SEnji Cooper 	ATF_REQUIRE(errno == EINVAL);
27441a3b124SEnji Cooper }
27541a3b124SEnji Cooper 
27641a3b124SEnji Cooper ATF_TP_ADD_TCS(tp)
27741a3b124SEnji Cooper {
27841a3b124SEnji Cooper 
27941a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_autoalloc);
28041a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_preexisting);
28141a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_data_length);
28241a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_binary);
28341a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_append_binary_pos);
28441a3b124SEnji Cooper 	ATF_TP_ADD_TC(tp, test_size_0);
28541a3b124SEnji Cooper 
28641a3b124SEnji Cooper 	return (atf_no_error());
28741a3b124SEnji Cooper }
288