open_memstream2_test.c revision 313498
1/*-
2 * Copyright (c) 2013 Hudson River Trading LLC
3 * Written by: John H. Baldwin <jhb@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: stable/10/lib/libc/tests/stdio/open_memstream2_test.c 313498 2017-02-10 01:13:12Z ngie $");
30
31#include <err.h>
32#include <errno.h>
33#include <limits.h>
34#include <stdint.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <wchar.h>
39
40#include <atf-c.h>
41
42static char *buf;
43static size_t len;
44
45static void
46assert_stream(const char *contents)
47{
48	if (strlen(contents) != len)
49		printf("bad length %zd for \"%s\"\n", len, contents);
50	else if (strncmp(buf, contents, strlen(contents)) != 0)
51		printf("bad buffer \"%s\" for \"%s\"\n", buf, contents);
52}
53
54ATF_TC_WITHOUT_HEAD(open_group_test);
55ATF_TC_BODY(open_group_test, tc)
56{
57	FILE *fp;
58	off_t eob;
59
60	fp = open_memstream(&buf, &len);
61	ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed");
62
63	fprintf(fp, "hello my world");
64	fflush(fp);
65	assert_stream("hello my world");
66	eob = ftello(fp);
67	rewind(fp);
68	fprintf(fp, "good-bye");
69	fseeko(fp, eob, SEEK_SET);
70	fclose(fp);
71	assert_stream("good-bye world");
72	free(buf);
73}
74
75ATF_TC_WITHOUT_HEAD(simple_tests);
76ATF_TC_BODY(simple_tests, tc)
77{
78	static const char zerobuf[] =
79	    { 'f', 'o', 'o', 0, 0, 0, 0, 'b', 'a', 'r', 0 };
80	char c;
81	FILE *fp;
82
83	fp = open_memstream(&buf, NULL);
84	ATF_REQUIRE_MSG(fp == NULL, "open_memstream did not fail");
85	ATF_REQUIRE_MSG(errno == EINVAL,
86	    "open_memstream didn't fail with EINVAL");
87	fp = open_memstream(NULL, &len);
88	ATF_REQUIRE_MSG(fp == NULL, "open_memstream did not fail");
89	ATF_REQUIRE_MSG(errno == EINVAL,
90	    "open_memstream didn't fail with EINVAL");
91	fp = open_memstream(&buf, &len);
92	ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed; errno=%d", errno);
93	fflush(fp);
94	assert_stream("");
95	if (fwide(fp, 0) >= 0)
96		printf("stream is not byte-oriented\n");
97
98	fprintf(fp, "fo");
99	fflush(fp);
100	assert_stream("fo");
101	fputc('o', fp);
102	fflush(fp);
103	assert_stream("foo");
104	rewind(fp);
105	fflush(fp);
106	assert_stream("");
107	fseek(fp, 0, SEEK_END);
108	fflush(fp);
109	assert_stream("foo");
110
111	/*
112	 * Test seeking out past the current end.  Should zero-fill the
113	 * intermediate area.
114	 */
115	fseek(fp, 4, SEEK_END);
116	fprintf(fp, "bar");
117	fflush(fp);
118
119	/*
120	 * Can't use assert_stream() here since this should contain
121	 * embedded null characters.
122	 */
123	if (len != 10)
124		printf("bad length %zd for zero-fill test\n", len);
125	else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
126		printf("bad buffer for zero-fill test\n");
127
128	fseek(fp, 3, SEEK_SET);
129	fprintf(fp, " in ");
130	fflush(fp);
131	assert_stream("foo in ");
132	fseek(fp, 0, SEEK_END);
133	fflush(fp);
134	assert_stream("foo in bar");
135
136	rewind(fp);
137	if (fread(&c, sizeof(c), 1, fp) != 0)
138		printf("fread did not fail\n");
139	else if (!ferror(fp))
140		printf("error indicator not set after fread\n");
141	else
142		clearerr(fp);
143
144	fseek(fp, 4, SEEK_SET);
145	fprintf(fp, "bar baz");
146	fclose(fp);
147	assert_stream("foo bar baz");
148	free(buf);
149}
150
151ATF_TC_WITHOUT_HEAD(seek_tests);
152ATF_TC_BODY(seek_tests, tc)
153{
154	FILE *fp;
155
156	fp = open_memstream(&buf, &len);
157	ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed: %d", errno);
158
159#define SEEK_FAIL(offset, whence, error) do {			\
160	errno = 0;						\
161	ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) != 0,	\
162	    "fseeko(%s, %s) did not fail, set pos to %jd\n",	\
163	    __STRING(offset), __STRING(whence),			\
164	    (intmax_t)ftello(fp));				\
165	ATF_REQUIRE_MSG(errno == (error),			\
166	    "fseeko(%s, %s) failed with %d rather than %s\n",	\
167	    __STRING(offset), __STRING(whence),	errno,		\
168	    __STRING(error));					\
169} while (0)
170
171#define SEEK_OK(offset, whence, result) do {			\
172	ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) == 0,	\
173	    "fseeko(%s, %s) failed: %s",			\
174	    __STRING(offset), __STRING(whence), strerror(errno)); \
175	ATF_REQUIRE_MSG(ftello(fp) == (result),			\
176	    "fseeko(%s, %s) seeked to %jd rather than %s\n",	\
177	    __STRING(offset), __STRING(whence),			\
178	    (intmax_t)ftello(fp), __STRING(result));		\
179} while (0)
180
181	SEEK_FAIL(-1, SEEK_SET, EINVAL);
182	SEEK_FAIL(-1, SEEK_CUR, EINVAL);
183	SEEK_FAIL(-1, SEEK_END, EINVAL);
184	fprintf(fp, "foo");
185	SEEK_OK(-1, SEEK_CUR, 2);
186	SEEK_OK(0, SEEK_SET, 0);
187	SEEK_OK(-1, SEEK_END, 2);
188	SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
189	SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
190	fclose(fp);
191}
192
193ATF_TP_ADD_TCS(tp)
194{
195
196	ATF_TP_ADD_TC(tp, open_group_test);
197	ATF_TP_ADD_TC(tp, simple_tests);
198	ATF_TP_ADD_TC(tp, seek_tests);
199
200	return (atf_no_error());
201}
202