1*0a6a1f1dSLionel Sambuc //
2*0a6a1f1dSLionel Sambuc // Automated Testing Framework (atf)
3*0a6a1f1dSLionel Sambuc //
4*0a6a1f1dSLionel Sambuc // Copyright (c) 2007 The NetBSD Foundation, Inc.
5*0a6a1f1dSLionel Sambuc // All rights reserved.
6*0a6a1f1dSLionel Sambuc //
7*0a6a1f1dSLionel Sambuc // Redistribution and use in source and binary forms, with or without
8*0a6a1f1dSLionel Sambuc // modification, are permitted provided that the following conditions
9*0a6a1f1dSLionel Sambuc // are met:
10*0a6a1f1dSLionel Sambuc // 1. Redistributions of source code must retain the above copyright
11*0a6a1f1dSLionel Sambuc // notice, this list of conditions and the following disclaimer.
12*0a6a1f1dSLionel Sambuc // 2. Redistributions in binary form must reproduce the above copyright
13*0a6a1f1dSLionel Sambuc // notice, this list of conditions and the following disclaimer in the
14*0a6a1f1dSLionel Sambuc // documentation and/or other materials provided with the distribution.
15*0a6a1f1dSLionel Sambuc //
16*0a6a1f1dSLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17*0a6a1f1dSLionel Sambuc // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18*0a6a1f1dSLionel Sambuc // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*0a6a1f1dSLionel Sambuc // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*0a6a1f1dSLionel Sambuc // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21*0a6a1f1dSLionel Sambuc // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*0a6a1f1dSLionel Sambuc // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23*0a6a1f1dSLionel Sambuc // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*0a6a1f1dSLionel Sambuc // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*0a6a1f1dSLionel Sambuc // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26*0a6a1f1dSLionel Sambuc // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*0a6a1f1dSLionel Sambuc // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*0a6a1f1dSLionel Sambuc //
29*0a6a1f1dSLionel Sambuc
30*0a6a1f1dSLionel Sambuc extern "C" {
31*0a6a1f1dSLionel Sambuc #include <sys/stat.h>
32*0a6a1f1dSLionel Sambuc #include <sys/wait.h>
33*0a6a1f1dSLionel Sambuc
34*0a6a1f1dSLionel Sambuc #include <fcntl.h>
35*0a6a1f1dSLionel Sambuc #include <unistd.h>
36*0a6a1f1dSLionel Sambuc }
37*0a6a1f1dSLionel Sambuc
38*0a6a1f1dSLionel Sambuc #include <cassert>
39*0a6a1f1dSLionel Sambuc #include <cerrno>
40*0a6a1f1dSLionel Sambuc #include <cstddef>
41*0a6a1f1dSLionel Sambuc #include <cstdlib>
42*0a6a1f1dSLionel Sambuc #include <cstring>
43*0a6a1f1dSLionel Sambuc #include <fstream>
44*0a6a1f1dSLionel Sambuc #include <iostream>
45*0a6a1f1dSLionel Sambuc #include <istream>
46*0a6a1f1dSLionel Sambuc #include <ostream>
47*0a6a1f1dSLionel Sambuc
48*0a6a1f1dSLionel Sambuc #include <atf-c++.hpp>
49*0a6a1f1dSLionel Sambuc
50*0a6a1f1dSLionel Sambuc #include "io.hpp"
51*0a6a1f1dSLionel Sambuc #include "signals.hpp"
52*0a6a1f1dSLionel Sambuc
53*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
54*0a6a1f1dSLionel Sambuc // Auxiliary functions.
55*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
56*0a6a1f1dSLionel Sambuc
57*0a6a1f1dSLionel Sambuc static
58*0a6a1f1dSLionel Sambuc void
systembuf_check_data(std::istream & is,std::size_t length)59*0a6a1f1dSLionel Sambuc systembuf_check_data(std::istream& is, std::size_t length)
60*0a6a1f1dSLionel Sambuc {
61*0a6a1f1dSLionel Sambuc char ch = 'A', chr;
62*0a6a1f1dSLionel Sambuc std::size_t cnt = 0;
63*0a6a1f1dSLionel Sambuc while (is >> chr) {
64*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(ch, chr);
65*0a6a1f1dSLionel Sambuc if (ch == 'Z')
66*0a6a1f1dSLionel Sambuc ch = 'A';
67*0a6a1f1dSLionel Sambuc else
68*0a6a1f1dSLionel Sambuc ch++;
69*0a6a1f1dSLionel Sambuc cnt++;
70*0a6a1f1dSLionel Sambuc }
71*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(cnt, length);
72*0a6a1f1dSLionel Sambuc }
73*0a6a1f1dSLionel Sambuc
74*0a6a1f1dSLionel Sambuc static
75*0a6a1f1dSLionel Sambuc void
systembuf_write_data(std::ostream & os,std::size_t length)76*0a6a1f1dSLionel Sambuc systembuf_write_data(std::ostream& os, std::size_t length)
77*0a6a1f1dSLionel Sambuc {
78*0a6a1f1dSLionel Sambuc char ch = 'A';
79*0a6a1f1dSLionel Sambuc for (std::size_t i = 0; i < length; i++) {
80*0a6a1f1dSLionel Sambuc os << ch;
81*0a6a1f1dSLionel Sambuc if (ch == 'Z')
82*0a6a1f1dSLionel Sambuc ch = 'A';
83*0a6a1f1dSLionel Sambuc else
84*0a6a1f1dSLionel Sambuc ch++;
85*0a6a1f1dSLionel Sambuc }
86*0a6a1f1dSLionel Sambuc os.flush();
87*0a6a1f1dSLionel Sambuc }
88*0a6a1f1dSLionel Sambuc
89*0a6a1f1dSLionel Sambuc static
90*0a6a1f1dSLionel Sambuc void
systembuf_test_read(std::size_t length,std::size_t bufsize)91*0a6a1f1dSLionel Sambuc systembuf_test_read(std::size_t length, std::size_t bufsize)
92*0a6a1f1dSLionel Sambuc {
93*0a6a1f1dSLionel Sambuc using tools::io::systembuf;
94*0a6a1f1dSLionel Sambuc
95*0a6a1f1dSLionel Sambuc std::ofstream f("test_read.txt");
96*0a6a1f1dSLionel Sambuc systembuf_write_data(f, length);
97*0a6a1f1dSLionel Sambuc f.close();
98*0a6a1f1dSLionel Sambuc
99*0a6a1f1dSLionel Sambuc int fd = ::open("test_read.txt", O_RDONLY);
100*0a6a1f1dSLionel Sambuc ATF_REQUIRE(fd != -1);
101*0a6a1f1dSLionel Sambuc systembuf sb(fd, bufsize);
102*0a6a1f1dSLionel Sambuc std::istream is(&sb);
103*0a6a1f1dSLionel Sambuc systembuf_check_data(is, length);
104*0a6a1f1dSLionel Sambuc ::close(fd);
105*0a6a1f1dSLionel Sambuc ::unlink("test_read.txt");
106*0a6a1f1dSLionel Sambuc }
107*0a6a1f1dSLionel Sambuc
108*0a6a1f1dSLionel Sambuc static
109*0a6a1f1dSLionel Sambuc void
systembuf_test_write(std::size_t length,std::size_t bufsize)110*0a6a1f1dSLionel Sambuc systembuf_test_write(std::size_t length, std::size_t bufsize)
111*0a6a1f1dSLionel Sambuc {
112*0a6a1f1dSLionel Sambuc using tools::io::systembuf;
113*0a6a1f1dSLionel Sambuc
114*0a6a1f1dSLionel Sambuc int fd = ::open("test_write.txt", O_WRONLY | O_CREAT | O_TRUNC,
115*0a6a1f1dSLionel Sambuc S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
116*0a6a1f1dSLionel Sambuc ATF_REQUIRE(fd != -1);
117*0a6a1f1dSLionel Sambuc systembuf sb(fd, bufsize);
118*0a6a1f1dSLionel Sambuc std::ostream os(&sb);
119*0a6a1f1dSLionel Sambuc systembuf_write_data(os, length);
120*0a6a1f1dSLionel Sambuc ::close(fd);
121*0a6a1f1dSLionel Sambuc
122*0a6a1f1dSLionel Sambuc std::ifstream is("test_write.txt");
123*0a6a1f1dSLionel Sambuc systembuf_check_data(is, length);
124*0a6a1f1dSLionel Sambuc is.close();
125*0a6a1f1dSLionel Sambuc ::unlink("test_write.txt");
126*0a6a1f1dSLionel Sambuc }
127*0a6a1f1dSLionel Sambuc
128*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
129*0a6a1f1dSLionel Sambuc // Test cases for the "file_handle" class.
130*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
131*0a6a1f1dSLionel Sambuc
132*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(file_handle_ctor);
ATF_TEST_CASE_HEAD(file_handle_ctor)133*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(file_handle_ctor)
134*0a6a1f1dSLionel Sambuc {
135*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests file_handle's constructors");
136*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(file_handle_ctor)137*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(file_handle_ctor)
138*0a6a1f1dSLionel Sambuc {
139*0a6a1f1dSLionel Sambuc using tools::io::file_handle;
140*0a6a1f1dSLionel Sambuc
141*0a6a1f1dSLionel Sambuc file_handle fh1;
142*0a6a1f1dSLionel Sambuc ATF_REQUIRE(!fh1.is_valid());
143*0a6a1f1dSLionel Sambuc
144*0a6a1f1dSLionel Sambuc file_handle fh2(STDOUT_FILENO);
145*0a6a1f1dSLionel Sambuc ATF_REQUIRE(fh2.is_valid());
146*0a6a1f1dSLionel Sambuc fh2.disown();
147*0a6a1f1dSLionel Sambuc }
148*0a6a1f1dSLionel Sambuc
149*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(file_handle_copy);
ATF_TEST_CASE_HEAD(file_handle_copy)150*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(file_handle_copy)
151*0a6a1f1dSLionel Sambuc {
152*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests file_handle's copy constructor");
153*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(file_handle_copy)154*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(file_handle_copy)
155*0a6a1f1dSLionel Sambuc {
156*0a6a1f1dSLionel Sambuc using tools::io::file_handle;
157*0a6a1f1dSLionel Sambuc
158*0a6a1f1dSLionel Sambuc file_handle fh1;
159*0a6a1f1dSLionel Sambuc file_handle fh2(STDOUT_FILENO);
160*0a6a1f1dSLionel Sambuc
161*0a6a1f1dSLionel Sambuc file_handle fh3(fh2);
162*0a6a1f1dSLionel Sambuc ATF_REQUIRE(!fh2.is_valid());
163*0a6a1f1dSLionel Sambuc ATF_REQUIRE(fh3.is_valid());
164*0a6a1f1dSLionel Sambuc
165*0a6a1f1dSLionel Sambuc fh1 = fh3;
166*0a6a1f1dSLionel Sambuc ATF_REQUIRE(!fh3.is_valid());
167*0a6a1f1dSLionel Sambuc ATF_REQUIRE(fh1.is_valid());
168*0a6a1f1dSLionel Sambuc
169*0a6a1f1dSLionel Sambuc fh1.disown();
170*0a6a1f1dSLionel Sambuc }
171*0a6a1f1dSLionel Sambuc
172*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(file_handle_get);
ATF_TEST_CASE_HEAD(file_handle_get)173*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(file_handle_get)
174*0a6a1f1dSLionel Sambuc {
175*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests the file_handle::get method");
176*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(file_handle_get)177*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(file_handle_get)
178*0a6a1f1dSLionel Sambuc {
179*0a6a1f1dSLionel Sambuc using tools::io::file_handle;
180*0a6a1f1dSLionel Sambuc
181*0a6a1f1dSLionel Sambuc file_handle fh1(STDOUT_FILENO);
182*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(fh1.get(), STDOUT_FILENO);
183*0a6a1f1dSLionel Sambuc }
184*0a6a1f1dSLionel Sambuc
185*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(file_handle_posix_remap);
ATF_TEST_CASE_HEAD(file_handle_posix_remap)186*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(file_handle_posix_remap)
187*0a6a1f1dSLionel Sambuc {
188*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests the file_handle::posix_remap method");
189*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(file_handle_posix_remap)190*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(file_handle_posix_remap)
191*0a6a1f1dSLionel Sambuc {
192*0a6a1f1dSLionel Sambuc using tools::io::file_handle;
193*0a6a1f1dSLionel Sambuc
194*0a6a1f1dSLionel Sambuc int pfd[2];
195*0a6a1f1dSLionel Sambuc
196*0a6a1f1dSLionel Sambuc ATF_REQUIRE(::pipe(pfd) != -1);
197*0a6a1f1dSLionel Sambuc file_handle rend(pfd[0]);
198*0a6a1f1dSLionel Sambuc file_handle wend(pfd[1]);
199*0a6a1f1dSLionel Sambuc
200*0a6a1f1dSLionel Sambuc ATF_REQUIRE(rend.get() != 10);
201*0a6a1f1dSLionel Sambuc ATF_REQUIRE(wend.get() != 10);
202*0a6a1f1dSLionel Sambuc wend.posix_remap(10);
203*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(wend.get(), 10);
204*0a6a1f1dSLionel Sambuc ATF_REQUIRE(::write(wend.get(), "test-posix-remap", 16) != -1);
205*0a6a1f1dSLionel Sambuc {
206*0a6a1f1dSLionel Sambuc char buf[17];
207*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(::read(rend.get(), buf, sizeof(buf)), 16);
208*0a6a1f1dSLionel Sambuc buf[16] = '\0';
209*0a6a1f1dSLionel Sambuc ATF_REQUIRE(std::strcmp(buf, "test-posix-remap") == 0);
210*0a6a1f1dSLionel Sambuc }
211*0a6a1f1dSLionel Sambuc
212*0a6a1f1dSLionel Sambuc // Redo previous to ensure that remapping over the same descriptor
213*0a6a1f1dSLionel Sambuc // has no side-effects.
214*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(wend.get(), 10);
215*0a6a1f1dSLionel Sambuc wend.posix_remap(10);
216*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(wend.get(), 10);
217*0a6a1f1dSLionel Sambuc ATF_REQUIRE(::write(wend.get(), "test-posix-remap", 16) != -1);
218*0a6a1f1dSLionel Sambuc {
219*0a6a1f1dSLionel Sambuc char buf[17];
220*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(::read(rend.get(), buf, sizeof(buf)), 16);
221*0a6a1f1dSLionel Sambuc buf[16] = '\0';
222*0a6a1f1dSLionel Sambuc ATF_REQUIRE(std::strcmp(buf, "test-posix-remap") == 0);
223*0a6a1f1dSLionel Sambuc }
224*0a6a1f1dSLionel Sambuc }
225*0a6a1f1dSLionel Sambuc
226*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
227*0a6a1f1dSLionel Sambuc // Test cases for the "systembuf" class.
228*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
229*0a6a1f1dSLionel Sambuc
230*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(systembuf_short_read);
ATF_TEST_CASE_HEAD(systembuf_short_read)231*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(systembuf_short_read)
232*0a6a1f1dSLionel Sambuc {
233*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests that a short read (one that fits in the "
234*0a6a1f1dSLionel Sambuc "internal buffer) works when using systembuf");
235*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(systembuf_short_read)236*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(systembuf_short_read)
237*0a6a1f1dSLionel Sambuc {
238*0a6a1f1dSLionel Sambuc systembuf_test_read(64, 1024);
239*0a6a1f1dSLionel Sambuc }
240*0a6a1f1dSLionel Sambuc
241*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(systembuf_long_read);
ATF_TEST_CASE_HEAD(systembuf_long_read)242*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(systembuf_long_read)
243*0a6a1f1dSLionel Sambuc {
244*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests that a long read (one that does not fit in "
245*0a6a1f1dSLionel Sambuc "the internal buffer) works when using systembuf");
246*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(systembuf_long_read)247*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(systembuf_long_read)
248*0a6a1f1dSLionel Sambuc {
249*0a6a1f1dSLionel Sambuc systembuf_test_read(64 * 1024, 1024);
250*0a6a1f1dSLionel Sambuc }
251*0a6a1f1dSLionel Sambuc
252*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(systembuf_short_write);
ATF_TEST_CASE_HEAD(systembuf_short_write)253*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(systembuf_short_write)
254*0a6a1f1dSLionel Sambuc {
255*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests that a short write (one that fits in the "
256*0a6a1f1dSLionel Sambuc "internal buffer) works when using systembuf");
257*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(systembuf_short_write)258*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(systembuf_short_write)
259*0a6a1f1dSLionel Sambuc {
260*0a6a1f1dSLionel Sambuc systembuf_test_write(64, 1024);
261*0a6a1f1dSLionel Sambuc }
262*0a6a1f1dSLionel Sambuc
263*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(systembuf_long_write);
ATF_TEST_CASE_HEAD(systembuf_long_write)264*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(systembuf_long_write)
265*0a6a1f1dSLionel Sambuc {
266*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests that a long write (one that does not fit "
267*0a6a1f1dSLionel Sambuc "in the internal buffer) works when using systembuf");
268*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(systembuf_long_write)269*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(systembuf_long_write)
270*0a6a1f1dSLionel Sambuc {
271*0a6a1f1dSLionel Sambuc systembuf_test_write(64 * 1024, 1024);
272*0a6a1f1dSLionel Sambuc }
273*0a6a1f1dSLionel Sambuc
274*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
275*0a6a1f1dSLionel Sambuc // Test cases for the "pistream" class.
276*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
277*0a6a1f1dSLionel Sambuc
278*0a6a1f1dSLionel Sambuc ATF_TEST_CASE(pistream);
ATF_TEST_CASE_HEAD(pistream)279*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_HEAD(pistream)
280*0a6a1f1dSLionel Sambuc {
281*0a6a1f1dSLionel Sambuc set_md_var("descr", "Tests the pistream class");
282*0a6a1f1dSLionel Sambuc }
ATF_TEST_CASE_BODY(pistream)283*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(pistream)
284*0a6a1f1dSLionel Sambuc {
285*0a6a1f1dSLionel Sambuc using tools::io::file_handle;
286*0a6a1f1dSLionel Sambuc using tools::io::pistream;
287*0a6a1f1dSLionel Sambuc using tools::io::systembuf;
288*0a6a1f1dSLionel Sambuc
289*0a6a1f1dSLionel Sambuc int fds[2];
290*0a6a1f1dSLionel Sambuc ATF_REQUIRE(::pipe(fds) != -1);
291*0a6a1f1dSLionel Sambuc
292*0a6a1f1dSLionel Sambuc pistream rend(fds[0]);
293*0a6a1f1dSLionel Sambuc
294*0a6a1f1dSLionel Sambuc systembuf wbuf(fds[1]);
295*0a6a1f1dSLionel Sambuc std::ostream wend(&wbuf);
296*0a6a1f1dSLionel Sambuc
297*0a6a1f1dSLionel Sambuc // XXX This assumes that the pipe's buffer is big enough to accept
298*0a6a1f1dSLionel Sambuc // the data written without blocking!
299*0a6a1f1dSLionel Sambuc wend << "1Test 1message\n";
300*0a6a1f1dSLionel Sambuc wend.flush();
301*0a6a1f1dSLionel Sambuc std::string tmp;
302*0a6a1f1dSLionel Sambuc rend >> tmp;
303*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(tmp, "1Test");
304*0a6a1f1dSLionel Sambuc rend >> tmp;
305*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(tmp, "1message");
306*0a6a1f1dSLionel Sambuc }
307*0a6a1f1dSLionel Sambuc
308*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
309*0a6a1f1dSLionel Sambuc // Tests for the "muxer" class.
310*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
311*0a6a1f1dSLionel Sambuc
312*0a6a1f1dSLionel Sambuc namespace {
313*0a6a1f1dSLionel Sambuc
314*0a6a1f1dSLionel Sambuc static void
check_stream(std::ostream & os)315*0a6a1f1dSLionel Sambuc check_stream(std::ostream& os)
316*0a6a1f1dSLionel Sambuc {
317*0a6a1f1dSLionel Sambuc // If we receive a signal while writing to the stream, the bad bit gets set.
318*0a6a1f1dSLionel Sambuc // Things seem to behave fine afterwards if we clear such error condition.
319*0a6a1f1dSLionel Sambuc // However, I'm not sure if it's safe to query errno at this point.
320*0a6a1f1dSLionel Sambuc ATF_REQUIRE(os.good() || (os.bad() && errno == EINTR));
321*0a6a1f1dSLionel Sambuc os.clear();
322*0a6a1f1dSLionel Sambuc }
323*0a6a1f1dSLionel Sambuc
324*0a6a1f1dSLionel Sambuc class mock_muxer : public tools::io::muxer {
line_callback(const size_t index,const std::string & line)325*0a6a1f1dSLionel Sambuc void line_callback(const size_t index, const std::string& line)
326*0a6a1f1dSLionel Sambuc {
327*0a6a1f1dSLionel Sambuc // The following should be enabled but causes the output to be so big
328*0a6a1f1dSLionel Sambuc // that it is annoying. Reenable at some point if we make atf store
329*0a6a1f1dSLionel Sambuc // the output of the test cases in some other way (e.g. only if a test
330*0a6a1f1dSLionel Sambuc // failes), because this message is the only help in seeing how the
331*0a6a1f1dSLionel Sambuc // test fails.
332*0a6a1f1dSLionel Sambuc //std::cout << "line_callback(" << index << ", " << line << ")\n";
333*0a6a1f1dSLionel Sambuc check_stream(std::cout);
334*0a6a1f1dSLionel Sambuc switch (index) {
335*0a6a1f1dSLionel Sambuc case 0: lines0.push_back(line); break;
336*0a6a1f1dSLionel Sambuc case 1: lines1.push_back(line); break;
337*0a6a1f1dSLionel Sambuc default: ATF_REQUIRE(false);
338*0a6a1f1dSLionel Sambuc }
339*0a6a1f1dSLionel Sambuc }
340*0a6a1f1dSLionel Sambuc
341*0a6a1f1dSLionel Sambuc public:
mock_muxer(const int * fds,const size_t nfds,const size_t bufsize)342*0a6a1f1dSLionel Sambuc mock_muxer(const int* fds, const size_t nfds, const size_t bufsize) :
343*0a6a1f1dSLionel Sambuc muxer(fds, nfds, bufsize) {}
344*0a6a1f1dSLionel Sambuc
345*0a6a1f1dSLionel Sambuc std::vector< std::string > lines0;
346*0a6a1f1dSLionel Sambuc std::vector< std::string > lines1;
347*0a6a1f1dSLionel Sambuc };
348*0a6a1f1dSLionel Sambuc
349*0a6a1f1dSLionel Sambuc static bool child_finished = false;
sigchld_handler(int signo)350*0a6a1f1dSLionel Sambuc static void sigchld_handler(int signo)
351*0a6a1f1dSLionel Sambuc {
352*0a6a1f1dSLionel Sambuc assert(signo == SIGCHLD);
353*0a6a1f1dSLionel Sambuc child_finished = true;
354*0a6a1f1dSLionel Sambuc }
355*0a6a1f1dSLionel Sambuc
356*0a6a1f1dSLionel Sambuc static void
child_printer(const int pipeout[2],const int pipeerr[2],const size_t iterations)357*0a6a1f1dSLionel Sambuc child_printer(const int pipeout[2], const int pipeerr[2],
358*0a6a1f1dSLionel Sambuc const size_t iterations)
359*0a6a1f1dSLionel Sambuc {
360*0a6a1f1dSLionel Sambuc ::close(pipeout[0]);
361*0a6a1f1dSLionel Sambuc ::close(pipeerr[0]);
362*0a6a1f1dSLionel Sambuc ATF_REQUIRE(::dup2(pipeout[1], STDOUT_FILENO) != -1);
363*0a6a1f1dSLionel Sambuc ATF_REQUIRE(::dup2(pipeerr[1], STDERR_FILENO) != -1);
364*0a6a1f1dSLionel Sambuc ::close(pipeout[1]);
365*0a6a1f1dSLionel Sambuc ::close(pipeerr[1]);
366*0a6a1f1dSLionel Sambuc
367*0a6a1f1dSLionel Sambuc for (size_t i = 0; i < iterations; i++) {
368*0a6a1f1dSLionel Sambuc std::cout << "stdout " << i << "\n";
369*0a6a1f1dSLionel Sambuc std::cerr << "stderr " << i << "\n";
370*0a6a1f1dSLionel Sambuc }
371*0a6a1f1dSLionel Sambuc
372*0a6a1f1dSLionel Sambuc std::cout << "stdout eof\n";
373*0a6a1f1dSLionel Sambuc std::cerr << "stderr eof\n";
374*0a6a1f1dSLionel Sambuc std::exit(EXIT_SUCCESS);
375*0a6a1f1dSLionel Sambuc }
376*0a6a1f1dSLionel Sambuc
377*0a6a1f1dSLionel Sambuc static void
muxer_test(const size_t bufsize,const size_t iterations)378*0a6a1f1dSLionel Sambuc muxer_test(const size_t bufsize, const size_t iterations)
379*0a6a1f1dSLionel Sambuc {
380*0a6a1f1dSLionel Sambuc int pipeout[2], pipeerr[2];
381*0a6a1f1dSLionel Sambuc ATF_REQUIRE(pipe(pipeout) != -1);
382*0a6a1f1dSLionel Sambuc ATF_REQUIRE(pipe(pipeerr) != -1);
383*0a6a1f1dSLionel Sambuc
384*0a6a1f1dSLionel Sambuc tools::signals::signal_programmer sigchld(SIGCHLD, sigchld_handler);
385*0a6a1f1dSLionel Sambuc
386*0a6a1f1dSLionel Sambuc std::cout.flush();
387*0a6a1f1dSLionel Sambuc std::cerr.flush();
388*0a6a1f1dSLionel Sambuc
389*0a6a1f1dSLionel Sambuc pid_t pid = ::fork();
390*0a6a1f1dSLionel Sambuc ATF_REQUIRE(pid != -1);
391*0a6a1f1dSLionel Sambuc if (pid == 0) {
392*0a6a1f1dSLionel Sambuc sigchld.unprogram();
393*0a6a1f1dSLionel Sambuc child_printer(pipeout, pipeerr, iterations);
394*0a6a1f1dSLionel Sambuc std::abort();
395*0a6a1f1dSLionel Sambuc }
396*0a6a1f1dSLionel Sambuc ::close(pipeout[1]);
397*0a6a1f1dSLionel Sambuc ::close(pipeerr[1]);
398*0a6a1f1dSLionel Sambuc
399*0a6a1f1dSLionel Sambuc int fds[2] = {pipeout[0], pipeerr[0]};
400*0a6a1f1dSLionel Sambuc mock_muxer mux(fds, 2, bufsize);
401*0a6a1f1dSLionel Sambuc
402*0a6a1f1dSLionel Sambuc mux.mux(child_finished);
403*0a6a1f1dSLionel Sambuc check_stream(std::cout);
404*0a6a1f1dSLionel Sambuc std::cout << "mux done\n";
405*0a6a1f1dSLionel Sambuc
406*0a6a1f1dSLionel Sambuc mux.flush();
407*0a6a1f1dSLionel Sambuc std::cout << "flush done\n";
408*0a6a1f1dSLionel Sambuc check_stream(std::cout);
409*0a6a1f1dSLionel Sambuc
410*0a6a1f1dSLionel Sambuc sigchld.unprogram();
411*0a6a1f1dSLionel Sambuc int status;
412*0a6a1f1dSLionel Sambuc ATF_REQUIRE(::waitpid(pid, &status, 0) != -1);
413*0a6a1f1dSLionel Sambuc ATF_REQUIRE(WIFEXITED(status));
414*0a6a1f1dSLionel Sambuc ATF_REQUIRE(WEXITSTATUS(status) == EXIT_SUCCESS);
415*0a6a1f1dSLionel Sambuc
416*0a6a1f1dSLionel Sambuc ATF_REQUIRE(std::cout.good());
417*0a6a1f1dSLionel Sambuc ATF_REQUIRE(std::cerr.good());
418*0a6a1f1dSLionel Sambuc for (size_t i = 0; i < iterations; i++) {
419*0a6a1f1dSLionel Sambuc std::ostringstream exp0, exp1;
420*0a6a1f1dSLionel Sambuc exp0 << "stdout " << i;
421*0a6a1f1dSLionel Sambuc exp1 << "stderr " << i;
422*0a6a1f1dSLionel Sambuc
423*0a6a1f1dSLionel Sambuc ATF_REQUIRE(mux.lines0.size() > i);
424*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(exp0.str(), mux.lines0[i]);
425*0a6a1f1dSLionel Sambuc ATF_REQUIRE(mux.lines1.size() > i);
426*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ(exp1.str(), mux.lines1[i]);
427*0a6a1f1dSLionel Sambuc }
428*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ("stdout eof", mux.lines0[iterations]);
429*0a6a1f1dSLionel Sambuc ATF_REQUIRE_EQ("stderr eof", mux.lines1[iterations]);
430*0a6a1f1dSLionel Sambuc std::cout << "all done\n";
431*0a6a1f1dSLionel Sambuc }
432*0a6a1f1dSLionel Sambuc
433*0a6a1f1dSLionel Sambuc } // anonymous namespace
434*0a6a1f1dSLionel Sambuc
435*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(muxer_small_buffer);
ATF_TEST_CASE_BODY(muxer_small_buffer)436*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(muxer_small_buffer)
437*0a6a1f1dSLionel Sambuc {
438*0a6a1f1dSLionel Sambuc muxer_test(4, 20000);
439*0a6a1f1dSLionel Sambuc }
440*0a6a1f1dSLionel Sambuc
441*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_WITHOUT_HEAD(muxer_large_buffer);
ATF_TEST_CASE_BODY(muxer_large_buffer)442*0a6a1f1dSLionel Sambuc ATF_TEST_CASE_BODY(muxer_large_buffer)
443*0a6a1f1dSLionel Sambuc {
444*0a6a1f1dSLionel Sambuc muxer_test(1024, 50000);
445*0a6a1f1dSLionel Sambuc }
446*0a6a1f1dSLionel Sambuc
447*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
448*0a6a1f1dSLionel Sambuc // Main.
449*0a6a1f1dSLionel Sambuc // ------------------------------------------------------------------------
450*0a6a1f1dSLionel Sambuc
ATF_INIT_TEST_CASES(tcs)451*0a6a1f1dSLionel Sambuc ATF_INIT_TEST_CASES(tcs)
452*0a6a1f1dSLionel Sambuc {
453*0a6a1f1dSLionel Sambuc // Add the tests for the "file_handle" class.
454*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, file_handle_ctor);
455*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, file_handle_copy);
456*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, file_handle_get);
457*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, file_handle_posix_remap);
458*0a6a1f1dSLionel Sambuc
459*0a6a1f1dSLionel Sambuc // Add the tests for the "systembuf" class.
460*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, systembuf_short_read);
461*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, systembuf_long_read);
462*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, systembuf_short_write);
463*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, systembuf_long_write);
464*0a6a1f1dSLionel Sambuc
465*0a6a1f1dSLionel Sambuc // Add the tests for the "pistream" class.
466*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, pistream);
467*0a6a1f1dSLionel Sambuc
468*0a6a1f1dSLionel Sambuc // Add the tests for the "muxer" class.
469*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, muxer_small_buffer);
470*0a6a1f1dSLionel Sambuc ATF_ADD_TEST_CASE(tcs, muxer_large_buffer);
471*0a6a1f1dSLionel Sambuc }
472