2 // Automated Testing Framework (atf)
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
10 // 1. Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // 2. Redistributions in binary form must reproduce the above copyright
13 // notice, this list of conditions and the following disclaimer in the
14 // documentation and/or other materials provided with the distribution.
16 // THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 // CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 // IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 #include <atf-c++.hpp>
51 #include "signals.hpp"
53 // ------------------------------------------------------------------------
54 // Auxiliary functions.
55 // ------------------------------------------------------------------------
59 systembuf_check_data(std::istream
& is
, std::size_t length
)
64 ATF_REQUIRE_EQ(ch
, chr
);
71 ATF_REQUIRE_EQ(cnt
, length
);
76 systembuf_write_data(std::ostream
& os
, std::size_t length
)
79 for (std::size_t i
= 0; i
< length
; i
++) {
91 systembuf_test_read(std::size_t length
, std::size_t bufsize
)
93 using tools::io::systembuf
;
95 std::ofstream
f("test_read.txt");
96 systembuf_write_data(f
, length
);
99 int fd
= ::open("test_read.txt", O_RDONLY
);
100 ATF_REQUIRE(fd
!= -1);
101 systembuf
sb(fd
, bufsize
);
102 std::istream
is(&sb
);
103 systembuf_check_data(is
, length
);
105 ::unlink("test_read.txt");
110 systembuf_test_write(std::size_t length
, std::size_t bufsize
)
112 using tools::io::systembuf
;
114 int fd
= ::open("test_write.txt", O_WRONLY
| O_CREAT
| O_TRUNC
,
115 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
116 ATF_REQUIRE(fd
!= -1);
117 systembuf
sb(fd
, bufsize
);
118 std::ostream
os(&sb
);
119 systembuf_write_data(os
, length
);
122 std::ifstream
is("test_write.txt");
123 systembuf_check_data(is
, length
);
125 ::unlink("test_write.txt");
128 // ------------------------------------------------------------------------
129 // Test cases for the "file_handle" class.
130 // ------------------------------------------------------------------------
132 ATF_TEST_CASE(file_handle_ctor
);
133 ATF_TEST_CASE_HEAD(file_handle_ctor
)
135 set_md_var("descr", "Tests file_handle's constructors");
137 ATF_TEST_CASE_BODY(file_handle_ctor
)
139 using tools::io::file_handle
;
142 ATF_REQUIRE(!fh1
.is_valid());
144 file_handle
fh2(STDOUT_FILENO
);
145 ATF_REQUIRE(fh2
.is_valid());
149 ATF_TEST_CASE(file_handle_copy
);
150 ATF_TEST_CASE_HEAD(file_handle_copy
)
152 set_md_var("descr", "Tests file_handle's copy constructor");
154 ATF_TEST_CASE_BODY(file_handle_copy
)
156 using tools::io::file_handle
;
159 file_handle
fh2(STDOUT_FILENO
);
161 file_handle
fh3(fh2
);
162 ATF_REQUIRE(!fh2
.is_valid());
163 ATF_REQUIRE(fh3
.is_valid());
166 ATF_REQUIRE(!fh3
.is_valid());
167 ATF_REQUIRE(fh1
.is_valid());
172 ATF_TEST_CASE(file_handle_get
);
173 ATF_TEST_CASE_HEAD(file_handle_get
)
175 set_md_var("descr", "Tests the file_handle::get method");
177 ATF_TEST_CASE_BODY(file_handle_get
)
179 using tools::io::file_handle
;
181 file_handle
fh1(STDOUT_FILENO
);
182 ATF_REQUIRE_EQ(fh1
.get(), STDOUT_FILENO
);
185 ATF_TEST_CASE(file_handle_posix_remap
);
186 ATF_TEST_CASE_HEAD(file_handle_posix_remap
)
188 set_md_var("descr", "Tests the file_handle::posix_remap method");
190 ATF_TEST_CASE_BODY(file_handle_posix_remap
)
192 using tools::io::file_handle
;
196 ATF_REQUIRE(::pipe(pfd
) != -1);
197 file_handle
rend(pfd
[0]);
198 file_handle
wend(pfd
[1]);
200 ATF_REQUIRE(rend
.get() != 10);
201 ATF_REQUIRE(wend
.get() != 10);
202 wend
.posix_remap(10);
203 ATF_REQUIRE_EQ(wend
.get(), 10);
204 ATF_REQUIRE(::write(wend
.get(), "test-posix-remap", 16) != -1);
207 ATF_REQUIRE_EQ(::read(rend
.get(), buf
, sizeof(buf
)), 16);
209 ATF_REQUIRE(std::strcmp(buf
, "test-posix-remap") == 0);
212 // Redo previous to ensure that remapping over the same descriptor
213 // has no side-effects.
214 ATF_REQUIRE_EQ(wend
.get(), 10);
215 wend
.posix_remap(10);
216 ATF_REQUIRE_EQ(wend
.get(), 10);
217 ATF_REQUIRE(::write(wend
.get(), "test-posix-remap", 16) != -1);
220 ATF_REQUIRE_EQ(::read(rend
.get(), buf
, sizeof(buf
)), 16);
222 ATF_REQUIRE(std::strcmp(buf
, "test-posix-remap") == 0);
226 // ------------------------------------------------------------------------
227 // Test cases for the "systembuf" class.
228 // ------------------------------------------------------------------------
230 ATF_TEST_CASE(systembuf_short_read
);
231 ATF_TEST_CASE_HEAD(systembuf_short_read
)
233 set_md_var("descr", "Tests that a short read (one that fits in the "
234 "internal buffer) works when using systembuf");
236 ATF_TEST_CASE_BODY(systembuf_short_read
)
238 systembuf_test_read(64, 1024);
241 ATF_TEST_CASE(systembuf_long_read
);
242 ATF_TEST_CASE_HEAD(systembuf_long_read
)
244 set_md_var("descr", "Tests that a long read (one that does not fit in "
245 "the internal buffer) works when using systembuf");
247 ATF_TEST_CASE_BODY(systembuf_long_read
)
249 systembuf_test_read(64 * 1024, 1024);
252 ATF_TEST_CASE(systembuf_short_write
);
253 ATF_TEST_CASE_HEAD(systembuf_short_write
)
255 set_md_var("descr", "Tests that a short write (one that fits in the "
256 "internal buffer) works when using systembuf");
258 ATF_TEST_CASE_BODY(systembuf_short_write
)
260 systembuf_test_write(64, 1024);
263 ATF_TEST_CASE(systembuf_long_write
);
264 ATF_TEST_CASE_HEAD(systembuf_long_write
)
266 set_md_var("descr", "Tests that a long write (one that does not fit "
267 "in the internal buffer) works when using systembuf");
269 ATF_TEST_CASE_BODY(systembuf_long_write
)
271 systembuf_test_write(64 * 1024, 1024);
274 // ------------------------------------------------------------------------
275 // Test cases for the "pistream" class.
276 // ------------------------------------------------------------------------
278 ATF_TEST_CASE(pistream
);
279 ATF_TEST_CASE_HEAD(pistream
)
281 set_md_var("descr", "Tests the pistream class");
283 ATF_TEST_CASE_BODY(pistream
)
285 using tools::io::file_handle
;
286 using tools::io::pistream
;
287 using tools::io::systembuf
;
290 ATF_REQUIRE(::pipe(fds
) != -1);
292 pistream
rend(fds
[0]);
294 systembuf
wbuf(fds
[1]);
295 std::ostream
wend(&wbuf
);
297 // XXX This assumes that the pipe's buffer is big enough to accept
298 // the data written without blocking!
299 wend
<< "1Test 1message\n";
303 ATF_REQUIRE_EQ(tmp
, "1Test");
305 ATF_REQUIRE_EQ(tmp
, "1message");
308 // ------------------------------------------------------------------------
309 // Tests for the "muxer" class.
310 // ------------------------------------------------------------------------
315 check_stream(std::ostream
& os
)
317 // If we receive a signal while writing to the stream, the bad bit gets set.
318 // Things seem to behave fine afterwards if we clear such error condition.
319 // However, I'm not sure if it's safe to query errno at this point.
320 ATF_REQUIRE(os
.good() || (os
.bad() && errno
== EINTR
));
324 class mock_muxer
: public tools::io::muxer
{
325 void line_callback(const size_t index
, const std::string
& line
)
327 // The following should be enabled but causes the output to be so big
328 // that it is annoying. Reenable at some point if we make atf store
329 // the output of the test cases in some other way (e.g. only if a test
330 // failes), because this message is the only help in seeing how the
332 //std::cout << "line_callback(" << index << ", " << line << ")\n";
333 check_stream(std::cout
);
335 case 0: lines0
.push_back(line
); break;
336 case 1: lines1
.push_back(line
); break;
337 default: ATF_REQUIRE(false);
342 mock_muxer(const int* fds
, const size_t nfds
, const size_t bufsize
) :
343 muxer(fds
, nfds
, bufsize
) {}
345 std::vector
< std::string
> lines0
;
346 std::vector
< std::string
> lines1
;
349 static bool child_finished
= false;
350 static void sigchld_handler(int signo
)
352 assert(signo
== SIGCHLD
);
353 child_finished
= true;
357 child_printer(const int pipeout
[2], const int pipeerr
[2],
358 const size_t iterations
)
362 ATF_REQUIRE(::dup2(pipeout
[1], STDOUT_FILENO
) != -1);
363 ATF_REQUIRE(::dup2(pipeerr
[1], STDERR_FILENO
) != -1);
367 for (size_t i
= 0; i
< iterations
; i
++) {
368 std::cout
<< "stdout " << i
<< "\n";
369 std::cerr
<< "stderr " << i
<< "\n";
372 std::cout
<< "stdout eof\n";
373 std::cerr
<< "stderr eof\n";
374 std::exit(EXIT_SUCCESS
);
378 muxer_test(const size_t bufsize
, const size_t iterations
)
380 int pipeout
[2], pipeerr
[2];
381 ATF_REQUIRE(pipe(pipeout
) != -1);
382 ATF_REQUIRE(pipe(pipeerr
) != -1);
384 tools::signals::signal_programmer
sigchld(SIGCHLD
, sigchld_handler
);
389 pid_t pid
= ::fork();
390 ATF_REQUIRE(pid
!= -1);
393 child_printer(pipeout
, pipeerr
, iterations
);
399 int fds
[2] = {pipeout
[0], pipeerr
[0]};
400 mock_muxer
mux(fds
, 2, bufsize
);
402 mux
.mux(child_finished
);
403 check_stream(std::cout
);
404 std::cout
<< "mux done\n";
407 std::cout
<< "flush done\n";
408 check_stream(std::cout
);
412 ATF_REQUIRE(::waitpid(pid
, &status
, 0) != -1);
413 ATF_REQUIRE(WIFEXITED(status
));
414 ATF_REQUIRE(WEXITSTATUS(status
) == EXIT_SUCCESS
);
416 ATF_REQUIRE(std::cout
.good());
417 ATF_REQUIRE(std::cerr
.good());
418 for (size_t i
= 0; i
< iterations
; i
++) {
419 std::ostringstream exp0
, exp1
;
420 exp0
<< "stdout " << i
;
421 exp1
<< "stderr " << i
;
423 ATF_REQUIRE(mux
.lines0
.size() > i
);
424 ATF_REQUIRE_EQ(exp0
.str(), mux
.lines0
[i
]);
425 ATF_REQUIRE(mux
.lines1
.size() > i
);
426 ATF_REQUIRE_EQ(exp1
.str(), mux
.lines1
[i
]);
428 ATF_REQUIRE_EQ("stdout eof", mux
.lines0
[iterations
]);
429 ATF_REQUIRE_EQ("stderr eof", mux
.lines1
[iterations
]);
430 std::cout
<< "all done\n";
433 } // anonymous namespace
435 ATF_TEST_CASE_WITHOUT_HEAD(muxer_small_buffer
);
436 ATF_TEST_CASE_BODY(muxer_small_buffer
)
438 muxer_test(4, 20000);
441 ATF_TEST_CASE_WITHOUT_HEAD(muxer_large_buffer
);
442 ATF_TEST_CASE_BODY(muxer_large_buffer
)
444 muxer_test(1024, 50000);
447 // ------------------------------------------------------------------------
449 // ------------------------------------------------------------------------
451 ATF_INIT_TEST_CASES(tcs
)
453 // Add the tests for the "file_handle" class.
454 ATF_ADD_TEST_CASE(tcs
, file_handle_ctor
);
455 ATF_ADD_TEST_CASE(tcs
, file_handle_copy
);
456 ATF_ADD_TEST_CASE(tcs
, file_handle_get
);
457 ATF_ADD_TEST_CASE(tcs
, file_handle_posix_remap
);
459 // Add the tests for the "systembuf" class.
460 ATF_ADD_TEST_CASE(tcs
, systembuf_short_read
);
461 ATF_ADD_TEST_CASE(tcs
, systembuf_long_read
);
462 ATF_ADD_TEST_CASE(tcs
, systembuf_short_write
);
463 ATF_ADD_TEST_CASE(tcs
, systembuf_long_write
);
465 // Add the tests for the "pistream" class.
466 ATF_ADD_TEST_CASE(tcs
, pistream
);
468 // Add the tests for the "muxer" class.
469 ATF_ADD_TEST_CASE(tcs
, muxer_small_buffer
);
470 ATF_ADD_TEST_CASE(tcs
, muxer_large_buffer
);