1247411Sjhb/*-
2283927Sjhb * Copyright (c) 2013 Hudson River Trading LLC
3247411Sjhb * Written by: John H. Baldwin <jhb@FreeBSD.org>
4247411Sjhb * All rights reserved.
5247411Sjhb *
6247411Sjhb * Redistribution and use in source and binary forms, with or without
7247411Sjhb * modification, are permitted provided that the following conditions
8247411Sjhb * are met:
9247411Sjhb * 1. Redistributions of source code must retain the above copyright
10247411Sjhb *    notice, this list of conditions and the following disclaimer.
11247411Sjhb * 2. Redistributions in binary form must reproduce the above copyright
12247411Sjhb *    notice, this list of conditions and the following disclaimer in the
13247411Sjhb *    documentation and/or other materials provided with the distribution.
14247411Sjhb *
15247411Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16247411Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17247411Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18247411Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19247411Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20247411Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21247411Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22247411Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23247411Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24247411Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25247411Sjhb * SUCH DAMAGE.
26247411Sjhb */
27247411Sjhb
28247411Sjhb#include <sys/cdefs.h>
29247411Sjhb__FBSDID("$FreeBSD: releng/10.2/tools/regression/lib/libc/stdio/test-open_wmemstream.c 283927 2015-06-02 19:20:39Z jhb $");
30247411Sjhb
31247411Sjhb#include <err.h>
32247411Sjhb#include <errno.h>
33247411Sjhb#include <limits.h>
34247411Sjhb#include <stdint.h>
35247411Sjhb#include <stdio.h>
36247411Sjhb#include <stdlib.h>
37247411Sjhb#include <string.h>
38247411Sjhb#include <wchar.h>
39247411Sjhb
40247411Sjhbstatic wchar_t *buf;
41247411Sjhbstatic size_t len;
42247411Sjhb
43247411Sjhbstatic void
44247411Sjhbassert_stream(const wchar_t *contents)
45247411Sjhb{
46247411Sjhb	if (wcslen(contents) != len)
47247411Sjhb		printf("bad length %zd for \"%ls\"\n", len, contents);
48247411Sjhb	else if (wcsncmp(buf, contents, wcslen(contents)) != 0)
49247411Sjhb		printf("bad buffer \"%ls\" for \"%ls\"\n", buf, contents);
50247411Sjhb}
51247411Sjhb
52247411Sjhbstatic void
53247411Sjhbopen_group_test(void)
54247411Sjhb{
55247411Sjhb	FILE *fp;
56247411Sjhb	off_t eob;
57247411Sjhb
58247411Sjhb	fp = open_wmemstream(&buf, &len);
59247411Sjhb	if (fp == NULL)
60247411Sjhb		err(1, "failed to open stream");
61247411Sjhb
62247411Sjhb	fwprintf(fp, L"hello my world");
63247411Sjhb	fflush(fp);
64247411Sjhb	assert_stream(L"hello my world");
65247411Sjhb	eob = ftello(fp);
66247411Sjhb	rewind(fp);
67247411Sjhb	fwprintf(fp, L"good-bye");
68247411Sjhb	fseeko(fp, eob, SEEK_SET);
69247411Sjhb	fclose(fp);
70247411Sjhb	assert_stream(L"good-bye world");
71247411Sjhb	free(buf);
72247411Sjhb}
73247411Sjhb
74247411Sjhbstatic void
75247411Sjhbsimple_tests(void)
76247411Sjhb{
77247411Sjhb	static const wchar_t zerobuf[] =
78247411Sjhb	    { L'f', L'o', L'o', 0, 0, 0, 0, L'b', L'a', L'r', 0 };
79247411Sjhb	wchar_t c;
80247411Sjhb	FILE *fp;
81247411Sjhb
82247411Sjhb	fp = open_wmemstream(&buf, NULL);
83247411Sjhb	if (fp != NULL)
84247411Sjhb		errx(1, "did not fail to open stream");
85247411Sjhb	else if (errno != EINVAL)
86247411Sjhb		err(1, "incorrect error for bad length pointer");
87247411Sjhb	fp = open_wmemstream(NULL, &len);
88247411Sjhb	if (fp != NULL)
89247411Sjhb		errx(1, "did not fail to open stream");
90247411Sjhb	else if (errno != EINVAL)
91247411Sjhb		err(1, "incorrect error for bad buffer pointer");
92247411Sjhb	fp = open_wmemstream(&buf, &len);
93247411Sjhb	if (fp == NULL)
94247411Sjhb		err(1, "failed to open stream");
95247411Sjhb	fflush(fp);
96247411Sjhb	assert_stream(L"");
97247411Sjhb	if (fwide(fp, 0) <= 0)
98247411Sjhb		printf("stream is not wide-oriented\n");
99247411Sjhb
100247411Sjhb	fwprintf(fp, L"fo");
101247411Sjhb	fflush(fp);
102247411Sjhb	assert_stream(L"fo");
103247411Sjhb	fputwc(L'o', fp);
104247411Sjhb	fflush(fp);
105247411Sjhb	assert_stream(L"foo");
106247411Sjhb	rewind(fp);
107247411Sjhb	fflush(fp);
108247411Sjhb	assert_stream(L"");
109247411Sjhb	fseek(fp, 0, SEEK_END);
110247411Sjhb	fflush(fp);
111247411Sjhb	assert_stream(L"foo");
112247411Sjhb
113247411Sjhb	/*
114247411Sjhb	 * Test seeking out past the current end.  Should zero-fill the
115247411Sjhb	 * intermediate area.
116247411Sjhb	 */
117247411Sjhb	fseek(fp, 4, SEEK_END);
118247411Sjhb	fwprintf(fp, L"bar");
119247411Sjhb	fflush(fp);
120247411Sjhb
121247411Sjhb	/*
122247411Sjhb	 * Can't use assert_stream() here since this should contain
123247411Sjhb	 * embedded null characters.
124247411Sjhb	 */
125247411Sjhb	if (len != 10)
126247411Sjhb		printf("bad length %zd for zero-fill test\n", len);
127247411Sjhb	else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
128247411Sjhb		printf("bad buffer for zero-fill test\n");
129247411Sjhb
130247411Sjhb	fseek(fp, 3, SEEK_SET);
131247411Sjhb	fwprintf(fp, L" in ");
132247411Sjhb	fflush(fp);
133247411Sjhb	assert_stream(L"foo in ");
134247411Sjhb	fseek(fp, 0, SEEK_END);
135247411Sjhb	fflush(fp);
136247411Sjhb	assert_stream(L"foo in bar");
137247411Sjhb
138247411Sjhb	rewind(fp);
139247411Sjhb	if (fread(&c, sizeof(c), 1, fp) != 0)
140247411Sjhb		printf("fread did not fail\n");
141247411Sjhb	else if (!ferror(fp))
142247411Sjhb		printf("error indicator not set after fread\n");
143247411Sjhb	else
144247411Sjhb		clearerr(fp);
145247411Sjhb
146247411Sjhb	fseek(fp, 4, SEEK_SET);
147247411Sjhb	fwprintf(fp, L"bar baz");
148247411Sjhb	fclose(fp);
149247411Sjhb	assert_stream(L"foo bar baz");
150247411Sjhb	free(buf);
151247411Sjhb}
152247411Sjhb
153247411Sjhbstatic void
154247411Sjhbseek_tests(void)
155247411Sjhb{
156247411Sjhb	FILE *fp;
157247411Sjhb
158247411Sjhb	fp = open_wmemstream(&buf, &len);
159247411Sjhb	if (fp == NULL)
160247411Sjhb		err(1, "failed to open stream");
161247411Sjhb#define SEEK_FAIL(offset, whence, error) do {				\
162247411Sjhb	errno = 0;							\
163247411Sjhb	if (fseeko(fp, (offset), (whence)) == 0)			\
164247411Sjhb		printf("fseeko(%s, %s) did not fail, set pos to %jd\n",	\
165247411Sjhb		    __STRING(offset), __STRING(whence),			\
166247411Sjhb		    (intmax_t)ftello(fp));				\
167247411Sjhb	else if (errno != (error))					\
168247411Sjhb		printf("fseeko(%s, %s) failed with %d rather than %s\n",\
169247411Sjhb		    __STRING(offset), __STRING(whence),	errno,		\
170247411Sjhb		    __STRING(error));					\
171247411Sjhb} while (0)
172247411Sjhb
173247411Sjhb#define SEEK_OK(offset, whence, result) do {				\
174247411Sjhb	if (fseeko(fp, (offset), (whence)) != 0)			\
175247411Sjhb		printf("fseeko(%s, %s) failed: %s\n",			\
176247411Sjhb		    __STRING(offset), __STRING(whence),	strerror(errno)); \
177247411Sjhb	else if (ftello(fp) != (result))				\
178247411Sjhb		printf("fseeko(%s, %s) seeked to %jd rather than %s\n",	\
179247411Sjhb		    __STRING(offset), __STRING(whence),			\
180247411Sjhb		    (intmax_t)ftello(fp), __STRING(result));		\
181247411Sjhb} while (0)
182247411Sjhb
183247411Sjhb	SEEK_FAIL(-1, SEEK_SET, EINVAL);
184247411Sjhb	SEEK_FAIL(-1, SEEK_CUR, EINVAL);
185247411Sjhb	SEEK_FAIL(-1, SEEK_END, EINVAL);
186247411Sjhb	fwprintf(fp, L"foo");
187247411Sjhb	SEEK_OK(-1, SEEK_CUR, 2);
188247411Sjhb	SEEK_OK(0, SEEK_SET, 0);
189247411Sjhb	SEEK_OK(-1, SEEK_END, 2);
190247411Sjhb	SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
191247411Sjhb	SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
192247411Sjhb	fclose(fp);
193247411Sjhb}
194247411Sjhb
195247411Sjhbint
196247411Sjhbmain(int ac, char **av)
197247411Sjhb{
198247411Sjhb
199247411Sjhb	open_group_test();
200247411Sjhb	simple_tests();
201247411Sjhb	seek_tests();
202247411Sjhb	return (0);
203247411Sjhb}
204