1// Copyright (c) 2007 The NetBSD Foundation, Inc. 2// All rights reserved. 3// 4// Redistribution and use in source and binary forms, with or without 5// modification, are permitted provided that the following conditions 6// are met: 7// 1. Redistributions of source code must retain the above copyright 8// notice, this list of conditions and the following disclaimer. 9// 2. Redistributions in binary form must reproduce the above copyright 10// notice, this list of conditions and the following disclaimer in the 11// documentation and/or other materials provided with the distribution. 12// 13// THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 14// CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 15// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17// IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 18// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 20// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 22// IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 24// IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 26#include "atf-c++/utils.hpp" 27 28extern "C" { 29#include <sys/stat.h> 30#include <sys/wait.h> 31 32#include <fcntl.h> 33#include <unistd.h> 34} 35 36#include <cstdlib> 37#include <iostream> 38#include <set> 39#include <sstream> 40#include <string> 41#include <vector> 42 43#include <atf-c++.hpp> 44 45static std::string 46read_file(const std::string& path) 47{ 48 char buffer[1024]; 49 50 const int fd = open(path.c_str(), O_RDONLY); 51 if (fd == -1) 52 ATF_FAIL("Cannot open " + path); 53 const ssize_t length = read(fd, buffer, sizeof(buffer) - 1); 54 close(fd); 55 ATF_REQUIRE(length != -1); 56 if (length == sizeof(buffer) - 1) 57 ATF_FAIL("Internal buffer not long enough to read temporary file"); 58 ((char *)buffer)[length] = '\0'; 59 60 return buffer; 61} 62 63// ------------------------------------------------------------------------ 64// Tests cases for the free functions. 65// ------------------------------------------------------------------------ 66 67ATF_TEST_CASE_WITHOUT_HEAD(cat_file__empty); 68ATF_TEST_CASE_BODY(cat_file__empty) 69{ 70 atf::utils::create_file("file.txt", ""); 71 atf::utils::redirect(STDOUT_FILENO, "captured.txt"); 72 atf::utils::cat_file("file.txt", "PREFIX"); 73 std::cout.flush(); 74 close(STDOUT_FILENO); 75 76 ATF_REQUIRE_EQ("", read_file("captured.txt")); 77} 78 79ATF_TEST_CASE_WITHOUT_HEAD(cat_file__one_line); 80ATF_TEST_CASE_BODY(cat_file__one_line) 81{ 82 atf::utils::create_file("file.txt", "This is a single line\n"); 83 atf::utils::redirect(STDOUT_FILENO, "captured.txt"); 84 atf::utils::cat_file("file.txt", "PREFIX"); 85 std::cout.flush(); 86 close(STDOUT_FILENO); 87 88 ATF_REQUIRE_EQ("PREFIXThis is a single line\n", read_file("captured.txt")); 89} 90 91ATF_TEST_CASE_WITHOUT_HEAD(cat_file__several_lines); 92ATF_TEST_CASE_BODY(cat_file__several_lines) 93{ 94 atf::utils::create_file("file.txt", "First\nSecond line\nAnd third\n"); 95 atf::utils::redirect(STDOUT_FILENO, "captured.txt"); 96 atf::utils::cat_file("file.txt", ">"); 97 std::cout.flush(); 98 close(STDOUT_FILENO); 99 100 ATF_REQUIRE_EQ(">First\n>Second line\n>And third\n", 101 read_file("captured.txt")); 102} 103 104ATF_TEST_CASE_WITHOUT_HEAD(cat_file__no_newline_eof); 105ATF_TEST_CASE_BODY(cat_file__no_newline_eof) 106{ 107 atf::utils::create_file("file.txt", "Foo\n bar baz"); 108 atf::utils::redirect(STDOUT_FILENO, "captured.txt"); 109 atf::utils::cat_file("file.txt", "PREFIX"); 110 std::cout.flush(); 111 close(STDOUT_FILENO); 112 113 ATF_REQUIRE_EQ("PREFIXFoo\nPREFIX bar baz", read_file("captured.txt")); 114} 115 116ATF_TEST_CASE_WITHOUT_HEAD(compare_file__empty__match); 117ATF_TEST_CASE_BODY(compare_file__empty__match) 118{ 119 atf::utils::create_file("test.txt", ""); 120 ATF_REQUIRE(atf::utils::compare_file("test.txt", "")); 121} 122 123ATF_TEST_CASE_WITHOUT_HEAD(compare_file__empty__not_match); 124ATF_TEST_CASE_BODY(compare_file__empty__not_match) 125{ 126 atf::utils::create_file("test.txt", ""); 127 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "\n")); 128 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "foo")); 129 ATF_REQUIRE(!atf::utils::compare_file("test.txt", " ")); 130} 131 132ATF_TEST_CASE_WITHOUT_HEAD(compare_file__short__match); 133ATF_TEST_CASE_BODY(compare_file__short__match) 134{ 135 atf::utils::create_file("test.txt", "this is a short file"); 136 ATF_REQUIRE(atf::utils::compare_file("test.txt", "this is a short file")); 137} 138 139ATF_TEST_CASE_WITHOUT_HEAD(compare_file__short__not_match); 140ATF_TEST_CASE_BODY(compare_file__short__not_match) 141{ 142 atf::utils::create_file("test.txt", "this is a short file"); 143 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "")); 144 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "\n")); 145 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "this is a Short file")); 146 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "this is a short fil")); 147 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "this is a short file ")); 148} 149 150ATF_TEST_CASE_WITHOUT_HEAD(compare_file__long__match); 151ATF_TEST_CASE_BODY(compare_file__long__match) 152{ 153 char long_contents[3456]; 154 size_t i = 0; 155 for (; i < sizeof(long_contents) - 1; i++) 156 long_contents[i] = '0' + (i % 10); 157 long_contents[i] = '\0'; 158 atf::utils::create_file("test.txt", long_contents); 159 160 ATF_REQUIRE(atf::utils::compare_file("test.txt", long_contents)); 161} 162 163ATF_TEST_CASE_WITHOUT_HEAD(compare_file__long__not_match); 164ATF_TEST_CASE_BODY(compare_file__long__not_match) 165{ 166 char long_contents[3456]; 167 size_t i = 0; 168 for (; i < sizeof(long_contents) - 1; i++) 169 long_contents[i] = '0' + (i % 10); 170 long_contents[i] = '\0'; 171 atf::utils::create_file("test.txt", long_contents); 172 173 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "")); 174 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "\n")); 175 ATF_REQUIRE(!atf::utils::compare_file("test.txt", "0123456789")); 176 long_contents[i - 1] = 'Z'; 177 ATF_REQUIRE(!atf::utils::compare_file("test.txt", long_contents)); 178} 179 180ATF_TEST_CASE_WITHOUT_HEAD(copy_file__empty); 181ATF_TEST_CASE_BODY(copy_file__empty) 182{ 183 atf::utils::create_file("src.txt", ""); 184 ATF_REQUIRE(chmod("src.txt", 0520) != -1); 185 186 atf::utils::copy_file("src.txt", "dest.txt"); 187 ATF_REQUIRE(atf::utils::compare_file("dest.txt", "")); 188 struct stat sb; 189 ATF_REQUIRE(stat("dest.txt", &sb) != -1); 190 ATF_REQUIRE_EQ(0520, sb.st_mode & 0xfff); 191} 192 193ATF_TEST_CASE_WITHOUT_HEAD(copy_file__some_contents); 194ATF_TEST_CASE_BODY(copy_file__some_contents) 195{ 196 atf::utils::create_file("src.txt", "This is a\ntest file\n"); 197 atf::utils::copy_file("src.txt", "dest.txt"); 198 ATF_REQUIRE(atf::utils::compare_file("dest.txt", "This is a\ntest file\n")); 199} 200 201ATF_TEST_CASE_WITHOUT_HEAD(create_file); 202ATF_TEST_CASE_BODY(create_file) 203{ 204 atf::utils::create_file("test.txt", "This is a %d test"); 205 206 ATF_REQUIRE_EQ("This is a %d test", read_file("test.txt")); 207} 208 209ATF_TEST_CASE_WITHOUT_HEAD(file_exists); 210ATF_TEST_CASE_BODY(file_exists) 211{ 212 atf::utils::create_file("test.txt", "foo"); 213 214 ATF_REQUIRE( atf::utils::file_exists("test.txt")); 215 ATF_REQUIRE( atf::utils::file_exists("./test.txt")); 216 ATF_REQUIRE(!atf::utils::file_exists("./test.tx")); 217 ATF_REQUIRE(!atf::utils::file_exists("test.txt2")); 218} 219 220ATF_TEST_CASE_WITHOUT_HEAD(fork); 221ATF_TEST_CASE_BODY(fork) 222{ 223 std::cout << "Should not get into child\n"; 224 std::cerr << "Should not get into child\n"; 225 pid_t pid = atf::utils::fork(); 226 if (pid == 0) { 227 std::cout << "Child stdout\n"; 228 std::cerr << "Child stderr\n"; 229 exit(EXIT_SUCCESS); 230 } 231 232 int status; 233 ATF_REQUIRE(waitpid(pid, &status, 0) != -1); 234 ATF_REQUIRE(WIFEXITED(status)); 235 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 236 237 std::ostringstream out_name; 238 out_name << "atf_utils_fork_" << pid << "_out.txt"; 239 std::ostringstream err_name; 240 err_name << "atf_utils_fork_" << pid << "_err.txt"; 241 242 ATF_REQUIRE_EQ("Child stdout\n", read_file(out_name.str())); 243 ATF_REQUIRE_EQ("Child stderr\n", read_file(err_name.str())); 244} 245 246ATF_TEST_CASE_WITHOUT_HEAD(grep_collection__set); 247ATF_TEST_CASE_BODY(grep_collection__set) 248{ 249 std::set< std::string > strings; 250 strings.insert("First"); 251 strings.insert("Second"); 252 253 ATF_REQUIRE( atf::utils::grep_collection("irs", strings)); 254 ATF_REQUIRE( atf::utils::grep_collection("cond", strings)); 255 ATF_REQUIRE(!atf::utils::grep_collection("Third", strings)); 256} 257 258ATF_TEST_CASE_WITHOUT_HEAD(grep_collection__vector); 259ATF_TEST_CASE_BODY(grep_collection__vector) 260{ 261 std::vector< std::string > strings; 262 strings.push_back("First"); 263 strings.push_back("Second"); 264 265 ATF_REQUIRE( atf::utils::grep_collection("irs", strings)); 266 ATF_REQUIRE( atf::utils::grep_collection("cond", strings)); 267 ATF_REQUIRE(!atf::utils::grep_collection("Third", strings)); 268} 269 270ATF_TEST_CASE_WITHOUT_HEAD(grep_file); 271ATF_TEST_CASE_BODY(grep_file) 272{ 273 atf::utils::create_file("test.txt", "line1\nthe second line\naaaabbbb\n"); 274 275 ATF_REQUIRE(atf::utils::grep_file("line1", "test.txt")); 276 ATF_REQUIRE(atf::utils::grep_file("second line", "test.txt")); 277 ATF_REQUIRE(atf::utils::grep_file("aa.*bb", "test.txt")); 278 ATF_REQUIRE(!atf::utils::grep_file("foo", "test.txt")); 279 ATF_REQUIRE(!atf::utils::grep_file("bar", "test.txt")); 280 ATF_REQUIRE(!atf::utils::grep_file("aaaaa", "test.txt")); 281} 282 283ATF_TEST_CASE_WITHOUT_HEAD(grep_string); 284ATF_TEST_CASE_BODY(grep_string) 285{ 286 const char *str = "a string - aaaabbbb"; 287 ATF_REQUIRE(atf::utils::grep_string("a string", str)); 288 ATF_REQUIRE(atf::utils::grep_string("^a string", str)); 289 ATF_REQUIRE(atf::utils::grep_string("aaaabbbb$", str)); 290 ATF_REQUIRE(atf::utils::grep_string("aa.*bb", str)); 291 ATF_REQUIRE(!atf::utils::grep_string("foo", str)); 292 ATF_REQUIRE(!atf::utils::grep_string("bar", str)); 293 ATF_REQUIRE(!atf::utils::grep_string("aaaaa", str)); 294} 295 296ATF_TEST_CASE_WITHOUT_HEAD(redirect__stdout); 297ATF_TEST_CASE_BODY(redirect__stdout) 298{ 299 std::cout << "Buffer this"; 300 atf::utils::redirect(STDOUT_FILENO, "captured.txt"); 301 std::cout << "The printed message"; 302 std::cout.flush(); 303 304 ATF_REQUIRE_EQ("The printed message", read_file("captured.txt")); 305} 306 307ATF_TEST_CASE_WITHOUT_HEAD(redirect__stderr); 308ATF_TEST_CASE_BODY(redirect__stderr) 309{ 310 std::cerr << "Buffer this"; 311 atf::utils::redirect(STDERR_FILENO, "captured.txt"); 312 std::cerr << "The printed message"; 313 std::cerr.flush(); 314 315 ATF_REQUIRE_EQ("The printed message", read_file("captured.txt")); 316} 317 318ATF_TEST_CASE_WITHOUT_HEAD(redirect__other); 319ATF_TEST_CASE_BODY(redirect__other) 320{ 321 const std::string message = "Foo bar\nbaz\n"; 322 atf::utils::redirect(15, "captured.txt"); 323 ATF_REQUIRE(write(15, message.c_str(), message.length()) != -1); 324 close(15); 325 326 ATF_REQUIRE_EQ(message, read_file("captured.txt")); 327} 328 329static void 330fork_and_wait(const int exitstatus, const char* expout, const char* experr) 331{ 332 const pid_t pid = atf::utils::fork(); 333 if (pid == 0) { 334 std::cout << "Some output\n"; 335 std::cerr << "Some error\n"; 336 exit(123); 337 } 338 atf::utils::wait(pid, exitstatus, expout, experr); 339 exit(EXIT_SUCCESS); 340} 341 342ATF_TEST_CASE_WITHOUT_HEAD(wait__ok); 343ATF_TEST_CASE_BODY(wait__ok) 344{ 345 const pid_t control = fork(); 346 ATF_REQUIRE(control != -1); 347 if (control == 0) 348 fork_and_wait(123, "Some output\n", "Some error\n"); 349 else { 350 int status; 351 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 352 ATF_REQUIRE(WIFEXITED(status)); 353 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 354 } 355} 356 357ATF_TEST_CASE_WITHOUT_HEAD(wait__ok_nested); 358ATF_TEST_CASE_BODY(wait__ok_nested) 359{ 360 const pid_t parent = atf::utils::fork(); 361 ATF_REQUIRE(parent != -1); 362 if (parent == 0) { 363 const pid_t child = atf::utils::fork(); 364 ATF_REQUIRE(child != -1); 365 if (child == 0) { 366 std::cerr.flush(); 367 std::cout << "Child output\n"; 368 std::cout.flush(); 369 std::cerr << "Child error\n"; 370 std::exit(50); 371 } else { 372 std::cout << "Parent output\n"; 373 std::cerr << "Parent error\n"; 374 atf::utils::wait(child, 50, "Child output\n", "Child error\n"); 375 std::exit(40); 376 } 377 } else { 378 atf::utils::wait(parent, 40, 379 "Parent output\n" 380 "subprocess stdout: Child output\n" 381 "subprocess stderr: Child error\n", 382 "Parent error\n"); 383 } 384} 385 386ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_exitstatus); 387ATF_TEST_CASE_BODY(wait__invalid_exitstatus) 388{ 389 const pid_t control = fork(); 390 ATF_REQUIRE(control != -1); 391 if (control == 0) 392 fork_and_wait(120, "Some output\n", "Some error\n"); 393 else { 394 int status; 395 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 396 ATF_REQUIRE(WIFEXITED(status)); 397 ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); 398 } 399} 400 401ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_stdout); 402ATF_TEST_CASE_BODY(wait__invalid_stdout) 403{ 404 const pid_t control = fork(); 405 ATF_REQUIRE(control != -1); 406 if (control == 0) 407 fork_and_wait(123, "Some output foo\n", "Some error\n"); 408 else { 409 int status; 410 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 411 ATF_REQUIRE(WIFEXITED(status)); 412 ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); 413 } 414} 415 416ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_stderr); 417ATF_TEST_CASE_BODY(wait__invalid_stderr) 418{ 419 const pid_t control = fork(); 420 ATF_REQUIRE(control != -1); 421 if (control == 0) 422 fork_and_wait(123, "Some output\n", "Some error foo\n"); 423 else { 424 int status; 425 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 426 ATF_REQUIRE(WIFEXITED(status)); 427 ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); 428 } 429} 430 431ATF_TEST_CASE_WITHOUT_HEAD(wait__save_stdout); 432ATF_TEST_CASE_BODY(wait__save_stdout) 433{ 434 const pid_t control = fork(); 435 ATF_REQUIRE(control != -1); 436 if (control == 0) 437 fork_and_wait(123, "save:my-output.txt", "Some error\n"); 438 else { 439 int status; 440 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 441 ATF_REQUIRE(WIFEXITED(status)); 442 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 443 444 ATF_REQUIRE(atf::utils::compare_file("my-output.txt", "Some output\n")); 445 } 446} 447 448ATF_TEST_CASE_WITHOUT_HEAD(wait__save_stderr); 449ATF_TEST_CASE_BODY(wait__save_stderr) 450{ 451 const pid_t control = fork(); 452 ATF_REQUIRE(control != -1); 453 if (control == 0) 454 fork_and_wait(123, "Some output\n", "save:my-output.txt"); 455 else { 456 int status; 457 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 458 ATF_REQUIRE(WIFEXITED(status)); 459 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 460 461 ATF_REQUIRE(atf::utils::compare_file("my-output.txt", "Some error\n")); 462 } 463} 464 465// ------------------------------------------------------------------------ 466// Main. 467// ------------------------------------------------------------------------ 468 469ATF_INIT_TEST_CASES(tcs) 470{ 471 // Add the test for the free functions. 472 ATF_ADD_TEST_CASE(tcs, cat_file__empty); 473 ATF_ADD_TEST_CASE(tcs, cat_file__one_line); 474 ATF_ADD_TEST_CASE(tcs, cat_file__several_lines); 475 ATF_ADD_TEST_CASE(tcs, cat_file__no_newline_eof); 476 477 ATF_ADD_TEST_CASE(tcs, compare_file__empty__match); 478 ATF_ADD_TEST_CASE(tcs, compare_file__empty__not_match); 479 ATF_ADD_TEST_CASE(tcs, compare_file__short__match); 480 ATF_ADD_TEST_CASE(tcs, compare_file__short__not_match); 481 ATF_ADD_TEST_CASE(tcs, compare_file__long__match); 482 ATF_ADD_TEST_CASE(tcs, compare_file__long__not_match); 483 484 ATF_ADD_TEST_CASE(tcs, copy_file__empty); 485 ATF_ADD_TEST_CASE(tcs, copy_file__some_contents); 486 487 ATF_ADD_TEST_CASE(tcs, create_file); 488 489 ATF_ADD_TEST_CASE(tcs, file_exists); 490 491 ATF_ADD_TEST_CASE(tcs, fork); 492 493 ATF_ADD_TEST_CASE(tcs, grep_collection__set); 494 ATF_ADD_TEST_CASE(tcs, grep_collection__vector); 495 ATF_ADD_TEST_CASE(tcs, grep_file); 496 ATF_ADD_TEST_CASE(tcs, grep_string); 497 498 ATF_ADD_TEST_CASE(tcs, redirect__stdout); 499 ATF_ADD_TEST_CASE(tcs, redirect__stderr); 500 ATF_ADD_TEST_CASE(tcs, redirect__other); 501 502 ATF_ADD_TEST_CASE(tcs, wait__ok); 503 ATF_ADD_TEST_CASE(tcs, wait__ok_nested); 504 ATF_ADD_TEST_CASE(tcs, wait__invalid_exitstatus); 505 ATF_ADD_TEST_CASE(tcs, wait__invalid_stdout); 506 ATF_ADD_TEST_CASE(tcs, wait__invalid_stderr); 507 ATF_ADD_TEST_CASE(tcs, wait__save_stdout); 508 ATF_ADD_TEST_CASE(tcs, wait__save_stderr); 509} 510