1 /* 2 * Automated Testing Framework (atf) 3 * 4 * Copyright (c) 2010 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. 15 * 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. 28 */ 29 30 #include <sys/stat.h> 31 #include <sys/wait.h> 32 33 #include <fcntl.h> 34 #include <stddef.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 40 #include <atf-c.h> 41 42 #include "atf-c/utils.h" 43 44 #include "detail/test_helpers.h" 45 46 /** Reads the contents of a file into a buffer. 47 * 48 * Up to buflen-1 characters are read into buffer. If this function returns, 49 * the contents read into the buffer are guaranteed to be nul-terminated. 50 * Note, however, that if the file contains any nul characters itself, 51 * comparing it "as a string" will not work. 52 * 53 * \param path The file to be read, which must exist. 54 * \param buffer Buffer into which to store the file contents. 55 * \param buflen Size of the target buffer. 56 * 57 * \return The count of bytes read. */ 58 static ssize_t 59 read_file(const char *path, void *const buffer, const size_t buflen) 60 { 61 const int fd = open(path, O_RDONLY); 62 ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", path); 63 const ssize_t length = read(fd, buffer, buflen - 1); 64 close(fd); 65 ATF_REQUIRE(length != -1); 66 ((char *)buffer)[length] = '\0'; 67 return length; 68 } 69 70 ATF_TC_WITHOUT_HEAD(cat_file__empty); 71 ATF_TC_BODY(cat_file__empty, tc) 72 { 73 atf_utils_create_file("file.txt", "%s", ""); 74 atf_utils_redirect(STDOUT_FILENO, "captured.txt"); 75 atf_utils_cat_file("file.txt", "PREFIX"); 76 fflush(stdout); 77 close(STDOUT_FILENO); 78 79 char buffer[1024]; 80 read_file("captured.txt", buffer, sizeof(buffer)); 81 ATF_REQUIRE_STREQ("", buffer); 82 } 83 84 ATF_TC_WITHOUT_HEAD(cat_file__one_line); 85 ATF_TC_BODY(cat_file__one_line, tc) 86 { 87 atf_utils_create_file("file.txt", "This is a single line\n"); 88 atf_utils_redirect(STDOUT_FILENO, "captured.txt"); 89 atf_utils_cat_file("file.txt", "PREFIX"); 90 fflush(stdout); 91 close(STDOUT_FILENO); 92 93 char buffer[1024]; 94 read_file("captured.txt", buffer, sizeof(buffer)); 95 ATF_REQUIRE_STREQ("PREFIXThis is a single line\n", buffer); 96 } 97 98 ATF_TC_WITHOUT_HEAD(cat_file__several_lines); 99 ATF_TC_BODY(cat_file__several_lines, tc) 100 { 101 atf_utils_create_file("file.txt", "First\nSecond line\nAnd third\n"); 102 atf_utils_redirect(STDOUT_FILENO, "captured.txt"); 103 atf_utils_cat_file("file.txt", ">"); 104 fflush(stdout); 105 close(STDOUT_FILENO); 106 107 char buffer[1024]; 108 read_file("captured.txt", buffer, sizeof(buffer)); 109 ATF_REQUIRE_STREQ(">First\n>Second line\n>And third\n", buffer); 110 } 111 112 ATF_TC_WITHOUT_HEAD(cat_file__no_newline_eof); 113 ATF_TC_BODY(cat_file__no_newline_eof, tc) 114 { 115 atf_utils_create_file("file.txt", "Foo\n bar baz"); 116 atf_utils_redirect(STDOUT_FILENO, "captured.txt"); 117 atf_utils_cat_file("file.txt", "PREFIX"); 118 fflush(stdout); 119 close(STDOUT_FILENO); 120 121 char buffer[1024]; 122 read_file("captured.txt", buffer, sizeof(buffer)); 123 ATF_REQUIRE_STREQ("PREFIXFoo\nPREFIX bar baz", buffer); 124 } 125 126 ATF_TC_WITHOUT_HEAD(compare_file__empty__match); 127 ATF_TC_BODY(compare_file__empty__match, tc) 128 { 129 atf_utils_create_file("test.txt", "%s", ""); 130 ATF_REQUIRE(atf_utils_compare_file("test.txt", "")); 131 } 132 133 ATF_TC_WITHOUT_HEAD(compare_file__empty__not_match); 134 ATF_TC_BODY(compare_file__empty__not_match, tc) 135 { 136 atf_utils_create_file("test.txt", "%s", ""); 137 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n")); 138 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "foo")); 139 ATF_REQUIRE(!atf_utils_compare_file("test.txt", " ")); 140 } 141 142 ATF_TC_WITHOUT_HEAD(compare_file__short__match); 143 ATF_TC_BODY(compare_file__short__match, tc) 144 { 145 atf_utils_create_file("test.txt", "this is a short file"); 146 ATF_REQUIRE(atf_utils_compare_file("test.txt", "this is a short file")); 147 } 148 149 ATF_TC_WITHOUT_HEAD(compare_file__short__not_match); 150 ATF_TC_BODY(compare_file__short__not_match, tc) 151 { 152 atf_utils_create_file("test.txt", "this is a short file"); 153 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "")); 154 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n")); 155 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a Short file")); 156 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a short fil")); 157 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a short file ")); 158 } 159 160 ATF_TC_WITHOUT_HEAD(compare_file__long__match); 161 ATF_TC_BODY(compare_file__long__match, tc) 162 { 163 char long_contents[3456]; 164 size_t i = 0; 165 for (; i < sizeof(long_contents) - 1; i++) 166 long_contents[i] = '0' + (i % 10); 167 long_contents[i] = '\0'; 168 atf_utils_create_file("test.txt", "%s", long_contents); 169 170 ATF_REQUIRE(atf_utils_compare_file("test.txt", long_contents)); 171 } 172 173 ATF_TC_WITHOUT_HEAD(compare_file__long__not_match); 174 ATF_TC_BODY(compare_file__long__not_match, tc) 175 { 176 char long_contents[3456]; 177 size_t i = 0; 178 for (; i < sizeof(long_contents) - 1; i++) 179 long_contents[i] = '0' + (i % 10); 180 long_contents[i] = '\0'; 181 atf_utils_create_file("test.txt", "%s", long_contents); 182 183 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "")); 184 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n")); 185 ATF_REQUIRE(!atf_utils_compare_file("test.txt", "0123456789")); 186 long_contents[i - 1] = 'Z'; 187 ATF_REQUIRE(!atf_utils_compare_file("test.txt", long_contents)); 188 } 189 190 ATF_TC_WITHOUT_HEAD(copy_file__empty); 191 ATF_TC_BODY(copy_file__empty, tc) 192 { 193 atf_utils_create_file("src.txt", "%s", ""); 194 ATF_REQUIRE(chmod("src.txt", 0520) != -1); 195 196 atf_utils_copy_file("src.txt", "dest.txt"); 197 ATF_REQUIRE(atf_utils_compare_file("dest.txt", "")); 198 struct stat sb; 199 ATF_REQUIRE(stat("dest.txt", &sb) != -1); 200 ATF_REQUIRE_EQ(0520, sb.st_mode & 0xfff); 201 } 202 203 ATF_TC_WITHOUT_HEAD(copy_file__some_contents); 204 ATF_TC_BODY(copy_file__some_contents, tc) 205 { 206 atf_utils_create_file("src.txt", "This is a\ntest file\n"); 207 atf_utils_copy_file("src.txt", "dest.txt"); 208 ATF_REQUIRE(atf_utils_compare_file("dest.txt", "This is a\ntest file\n")); 209 } 210 211 ATF_TC_WITHOUT_HEAD(create_file); 212 ATF_TC_BODY(create_file, tc) 213 { 214 atf_utils_create_file("test.txt", "This is a test with %d", 12345); 215 216 char buffer[128]; 217 read_file("test.txt", buffer, sizeof(buffer)); 218 ATF_REQUIRE_STREQ("This is a test with 12345", buffer); 219 } 220 221 ATF_TC_WITHOUT_HEAD(file_exists); 222 ATF_TC_BODY(file_exists, tc) 223 { 224 atf_utils_create_file("test.txt", "foo"); 225 226 ATF_REQUIRE( atf_utils_file_exists("test.txt")); 227 ATF_REQUIRE( atf_utils_file_exists("./test.txt")); 228 ATF_REQUIRE(!atf_utils_file_exists("./test.tx")); 229 ATF_REQUIRE(!atf_utils_file_exists("test.txt2")); 230 } 231 232 ATF_TC_WITHOUT_HEAD(fork); 233 ATF_TC_BODY(fork, tc) 234 { 235 fprintf(stdout, "Should not get into child\n"); 236 fprintf(stderr, "Should not get into child\n"); 237 pid_t pid = atf_utils_fork(); 238 if (pid == 0) { 239 fprintf(stdout, "Child stdout\n"); 240 fprintf(stderr, "Child stderr\n"); 241 exit(EXIT_SUCCESS); 242 } 243 244 int status; 245 ATF_REQUIRE(waitpid(pid, &status, 0) != -1); 246 ATF_REQUIRE(WIFEXITED(status)); 247 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 248 249 char buffer[1024]; 250 read_file("atf_utils_fork_out.txt", buffer, sizeof(buffer)); 251 ATF_REQUIRE_STREQ("Child stdout\n", buffer); 252 read_file("atf_utils_fork_err.txt", buffer, sizeof(buffer)); 253 ATF_REQUIRE_STREQ("Child stderr\n", buffer); 254 } 255 256 ATF_TC_WITHOUT_HEAD(free_charpp__empty); 257 ATF_TC_BODY(free_charpp__empty, tc) 258 { 259 char **array = malloc(sizeof(char *) * 1); 260 array[0] = NULL; 261 262 atf_utils_free_charpp(array); 263 } 264 265 ATF_TC_WITHOUT_HEAD(free_charpp__some); 266 ATF_TC_BODY(free_charpp__some, tc) 267 { 268 char **array = malloc(sizeof(char *) * 4); 269 array[0] = strdup("first"); 270 array[1] = strdup("second"); 271 array[2] = strdup("third"); 272 array[3] = NULL; 273 274 atf_utils_free_charpp(array); 275 } 276 277 ATF_TC_WITHOUT_HEAD(grep_file); 278 ATF_TC_BODY(grep_file, tc) 279 { 280 atf_utils_create_file("test.txt", "line1\nthe second line\naaaabbbb\n"); 281 282 ATF_CHECK(atf_utils_grep_file("line1", "test.txt")); 283 ATF_CHECK(atf_utils_grep_file("line%d", "test.txt", 1)); 284 ATF_CHECK(atf_utils_grep_file("second line", "test.txt")); 285 ATF_CHECK(atf_utils_grep_file("aa.*bb", "test.txt")); 286 ATF_CHECK(!atf_utils_grep_file("foo", "test.txt")); 287 ATF_CHECK(!atf_utils_grep_file("bar", "test.txt")); 288 ATF_CHECK(!atf_utils_grep_file("aaaaa", "test.txt")); 289 } 290 291 ATF_TC_WITHOUT_HEAD(grep_string); 292 ATF_TC_BODY(grep_string, tc) 293 { 294 const char *str = "a string - aaaabbbb"; 295 ATF_CHECK(atf_utils_grep_string("a string", str)); 296 ATF_CHECK(atf_utils_grep_string("^a string", str)); 297 ATF_CHECK(atf_utils_grep_string("aaaabbbb$", str)); 298 ATF_CHECK(atf_utils_grep_string("a%s*bb", str, "a.")); 299 ATF_CHECK(!atf_utils_grep_string("foo", str)); 300 ATF_CHECK(!atf_utils_grep_string("bar", str)); 301 ATF_CHECK(!atf_utils_grep_string("aaaaa", str)); 302 } 303 304 ATF_TC_WITHOUT_HEAD(readline__none); 305 ATF_TC_BODY(readline__none, tc) 306 { 307 atf_utils_create_file("empty.txt", "%s", ""); 308 309 const int fd = open("empty.txt", O_RDONLY); 310 ATF_REQUIRE(fd != -1); 311 ATF_REQUIRE(atf_utils_readline(fd) == NULL); 312 close(fd); 313 } 314 315 ATF_TC_WITHOUT_HEAD(readline__some); 316 ATF_TC_BODY(readline__some, tc) 317 { 318 const char *l1 = "First line with % formatting % characters %"; 319 const char *l2 = "Second line; much longer than the first one"; 320 const char *l3 = "Last line, without terminator"; 321 322 atf_utils_create_file("test.txt", "%s\n%s\n%s", l1, l2, l3); 323 324 const int fd = open("test.txt", O_RDONLY); 325 ATF_REQUIRE(fd != -1); 326 327 char *line; 328 329 line = atf_utils_readline(fd); 330 ATF_REQUIRE_STREQ(l1, line); 331 free(line); 332 333 line = atf_utils_readline(fd); 334 ATF_REQUIRE_STREQ(l2, line); 335 free(line); 336 337 line = atf_utils_readline(fd); 338 ATF_REQUIRE_STREQ(l3, line); 339 free(line); 340 341 close(fd); 342 } 343 344 ATF_TC_WITHOUT_HEAD(redirect__stdout); 345 ATF_TC_BODY(redirect__stdout, tc) 346 { 347 printf("Buffer this"); 348 atf_utils_redirect(STDOUT_FILENO, "captured.txt"); 349 printf("The printed message"); 350 fflush(stdout); 351 352 char buffer[1024]; 353 read_file("captured.txt", buffer, sizeof(buffer)); 354 ATF_REQUIRE_STREQ("The printed message", buffer); 355 } 356 357 ATF_TC_WITHOUT_HEAD(redirect__stderr); 358 ATF_TC_BODY(redirect__stderr, tc) 359 { 360 fprintf(stderr, "Buffer this"); 361 atf_utils_redirect(STDERR_FILENO, "captured.txt"); 362 fprintf(stderr, "The printed message"); 363 fflush(stderr); 364 365 char buffer[1024]; 366 read_file("captured.txt", buffer, sizeof(buffer)); 367 ATF_REQUIRE_STREQ("The printed message", buffer); 368 } 369 370 ATF_TC_WITHOUT_HEAD(redirect__other); 371 ATF_TC_BODY(redirect__other, tc) 372 { 373 const char *message = "Foo bar\nbaz\n"; 374 atf_utils_redirect(15, "captured.txt"); 375 ATF_REQUIRE(write(15, message, strlen(message)) != -1); 376 close(15); 377 378 char buffer[1024]; 379 read_file("captured.txt", buffer, sizeof(buffer)); 380 ATF_REQUIRE_STREQ(message, buffer); 381 } 382 383 static void 384 fork_and_wait(const int exitstatus, const char* expout, const char* experr) 385 { 386 const pid_t pid = atf_utils_fork(); 387 if (pid == 0) { 388 fprintf(stdout, "Some output\n"); 389 fprintf(stderr, "Some error\n"); 390 exit(123); 391 } 392 atf_utils_wait(pid, exitstatus, expout, experr); 393 exit(EXIT_SUCCESS); 394 } 395 396 ATF_TC_WITHOUT_HEAD(wait__ok); 397 ATF_TC_BODY(wait__ok, tc) 398 { 399 const pid_t control = fork(); 400 ATF_REQUIRE(control != -1); 401 if (control == 0) 402 fork_and_wait(123, "Some output\n", "Some error\n"); 403 else { 404 int status; 405 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 406 ATF_REQUIRE(WIFEXITED(status)); 407 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 408 } 409 } 410 411 ATF_TC_WITHOUT_HEAD(wait__invalid_exitstatus); 412 ATF_TC_BODY(wait__invalid_exitstatus, tc) 413 { 414 const pid_t control = fork(); 415 ATF_REQUIRE(control != -1); 416 if (control == 0) 417 fork_and_wait(120, "Some output\n", "Some error\n"); 418 else { 419 int status; 420 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 421 ATF_REQUIRE(WIFEXITED(status)); 422 ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); 423 } 424 } 425 426 ATF_TC_WITHOUT_HEAD(wait__invalid_stdout); 427 ATF_TC_BODY(wait__invalid_stdout, tc) 428 { 429 const pid_t control = fork(); 430 ATF_REQUIRE(control != -1); 431 if (control == 0) 432 fork_and_wait(123, "Some output foo\n", "Some error\n"); 433 else { 434 int status; 435 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 436 ATF_REQUIRE(WIFEXITED(status)); 437 ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); 438 } 439 } 440 441 ATF_TC_WITHOUT_HEAD(wait__invalid_stderr); 442 ATF_TC_BODY(wait__invalid_stderr, tc) 443 { 444 const pid_t control = fork(); 445 ATF_REQUIRE(control != -1); 446 if (control == 0) 447 fork_and_wait(123, "Some output\n", "Some error foo\n"); 448 else { 449 int status; 450 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 451 ATF_REQUIRE(WIFEXITED(status)); 452 ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status)); 453 } 454 } 455 456 ATF_TC_WITHOUT_HEAD(wait__save_stdout); 457 ATF_TC_BODY(wait__save_stdout, tc) 458 { 459 const pid_t control = fork(); 460 ATF_REQUIRE(control != -1); 461 if (control == 0) 462 fork_and_wait(123, "save:my-output.txt", "Some error\n"); 463 else { 464 int status; 465 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 466 ATF_REQUIRE(WIFEXITED(status)); 467 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 468 469 ATF_REQUIRE(atf_utils_compare_file("my-output.txt", "Some output\n")); 470 } 471 } 472 473 ATF_TC_WITHOUT_HEAD(wait__save_stderr); 474 ATF_TC_BODY(wait__save_stderr, tc) 475 { 476 const pid_t control = fork(); 477 ATF_REQUIRE(control != -1); 478 if (control == 0) 479 fork_and_wait(123, "Some output\n", "save:my-output.txt"); 480 else { 481 int status; 482 ATF_REQUIRE(waitpid(control, &status, 0) != -1); 483 ATF_REQUIRE(WIFEXITED(status)); 484 ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); 485 486 ATF_REQUIRE(atf_utils_compare_file("my-output.txt", "Some error\n")); 487 } 488 } 489 490 HEADER_TC(include, "atf-c/utils.h"); 491 492 ATF_TP_ADD_TCS(tp) 493 { 494 ATF_TP_ADD_TC(tp, cat_file__empty); 495 ATF_TP_ADD_TC(tp, cat_file__one_line); 496 ATF_TP_ADD_TC(tp, cat_file__several_lines); 497 ATF_TP_ADD_TC(tp, cat_file__no_newline_eof); 498 499 ATF_TP_ADD_TC(tp, compare_file__empty__match); 500 ATF_TP_ADD_TC(tp, compare_file__empty__not_match); 501 ATF_TP_ADD_TC(tp, compare_file__short__match); 502 ATF_TP_ADD_TC(tp, compare_file__short__not_match); 503 ATF_TP_ADD_TC(tp, compare_file__long__match); 504 ATF_TP_ADD_TC(tp, compare_file__long__not_match); 505 506 ATF_TP_ADD_TC(tp, copy_file__empty); 507 ATF_TP_ADD_TC(tp, copy_file__some_contents); 508 509 ATF_TP_ADD_TC(tp, create_file); 510 511 ATF_TP_ADD_TC(tp, file_exists); 512 513 ATF_TP_ADD_TC(tp, fork); 514 515 ATF_TP_ADD_TC(tp, free_charpp__empty); 516 ATF_TP_ADD_TC(tp, free_charpp__some); 517 518 ATF_TP_ADD_TC(tp, grep_file); 519 ATF_TP_ADD_TC(tp, grep_string); 520 521 ATF_TP_ADD_TC(tp, readline__none); 522 ATF_TP_ADD_TC(tp, readline__some); 523 524 ATF_TP_ADD_TC(tp, redirect__stdout); 525 ATF_TP_ADD_TC(tp, redirect__stderr); 526 ATF_TP_ADD_TC(tp, redirect__other); 527 528 ATF_TP_ADD_TC(tp, wait__ok); 529 ATF_TP_ADD_TC(tp, wait__save_stdout); 530 ATF_TP_ADD_TC(tp, wait__save_stderr); 531 ATF_TP_ADD_TC(tp, wait__invalid_exitstatus); 532 ATF_TP_ADD_TC(tp, wait__invalid_stdout); 533 ATF_TP_ADD_TC(tp, wait__invalid_stderr); 534 535 ATF_TP_ADD_TC(tp, include); 536 537 return atf_no_error(); 538 } 539