Remove building with NOCRYPTO option
[minix3.git] / external / bsd / atf / dist / tools / io_test.cpp
blobb55428f2829a9dcb8038a1e50927e5878f6b69bd
1 //
2 // Automated Testing Framework (atf)
3 //
4 // Copyright (c) 2007 The NetBSD Foundation, Inc.
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
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.
30 extern "C" {
31 #include <sys/stat.h>
32 #include <sys/wait.h>
34 #include <fcntl.h>
35 #include <unistd.h>
38 #include <cassert>
39 #include <cerrno>
40 #include <cstddef>
41 #include <cstdlib>
42 #include <cstring>
43 #include <fstream>
44 #include <iostream>
45 #include <istream>
46 #include <ostream>
48 #include <atf-c++.hpp>
50 #include "io.hpp"
51 #include "signals.hpp"
53 // ------------------------------------------------------------------------
54 // Auxiliary functions.
55 // ------------------------------------------------------------------------
57 static
58 void
59 systembuf_check_data(std::istream& is, std::size_t length)
61 char ch = 'A', chr;
62 std::size_t cnt = 0;
63 while (is >> chr) {
64 ATF_REQUIRE_EQ(ch, chr);
65 if (ch == 'Z')
66 ch = 'A';
67 else
68 ch++;
69 cnt++;
71 ATF_REQUIRE_EQ(cnt, length);
74 static
75 void
76 systembuf_write_data(std::ostream& os, std::size_t length)
78 char ch = 'A';
79 for (std::size_t i = 0; i < length; i++) {
80 os << ch;
81 if (ch == 'Z')
82 ch = 'A';
83 else
84 ch++;
86 os.flush();
89 static
90 void
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);
97 f.close();
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);
104 ::close(fd);
105 ::unlink("test_read.txt");
108 static
109 void
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);
120 ::close(fd);
122 std::ifstream is("test_write.txt");
123 systembuf_check_data(is, length);
124 is.close();
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;
141 file_handle fh1;
142 ATF_REQUIRE(!fh1.is_valid());
144 file_handle fh2(STDOUT_FILENO);
145 ATF_REQUIRE(fh2.is_valid());
146 fh2.disown();
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;
158 file_handle fh1;
159 file_handle fh2(STDOUT_FILENO);
161 file_handle fh3(fh2);
162 ATF_REQUIRE(!fh2.is_valid());
163 ATF_REQUIRE(fh3.is_valid());
165 fh1 = fh3;
166 ATF_REQUIRE(!fh3.is_valid());
167 ATF_REQUIRE(fh1.is_valid());
169 fh1.disown();
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;
194 int pfd[2];
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);
206 char buf[17];
207 ATF_REQUIRE_EQ(::read(rend.get(), buf, sizeof(buf)), 16);
208 buf[16] = '\0';
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);
219 char buf[17];
220 ATF_REQUIRE_EQ(::read(rend.get(), buf, sizeof(buf)), 16);
221 buf[16] = '\0';
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;
289 int fds[2];
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";
300 wend.flush();
301 std::string tmp;
302 rend >> tmp;
303 ATF_REQUIRE_EQ(tmp, "1Test");
304 rend >> tmp;
305 ATF_REQUIRE_EQ(tmp, "1message");
308 // ------------------------------------------------------------------------
309 // Tests for the "muxer" class.
310 // ------------------------------------------------------------------------
312 namespace {
314 static void
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));
321 os.clear();
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
331 // test fails.
332 //std::cout << "line_callback(" << index << ", " << line << ")\n";
333 check_stream(std::cout);
334 switch (index) {
335 case 0: lines0.push_back(line); break;
336 case 1: lines1.push_back(line); break;
337 default: ATF_REQUIRE(false);
341 public:
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;
356 static void
357 child_printer(const int pipeout[2], const int pipeerr[2],
358 const size_t iterations)
360 ::close(pipeout[0]);
361 ::close(pipeerr[0]);
362 ATF_REQUIRE(::dup2(pipeout[1], STDOUT_FILENO) != -1);
363 ATF_REQUIRE(::dup2(pipeerr[1], STDERR_FILENO) != -1);
364 ::close(pipeout[1]);
365 ::close(pipeerr[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);
377 static void
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);
386 std::cout.flush();
387 std::cerr.flush();
389 pid_t pid = ::fork();
390 ATF_REQUIRE(pid != -1);
391 if (pid == 0) {
392 sigchld.unprogram();
393 child_printer(pipeout, pipeerr, iterations);
394 std::abort();
396 ::close(pipeout[1]);
397 ::close(pipeerr[1]);
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";
406 mux.flush();
407 std::cout << "flush done\n";
408 check_stream(std::cout);
410 sigchld.unprogram();
411 int status;
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 // ------------------------------------------------------------------------
448 // Main.
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);