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