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