xref: /freebsd/contrib/atf/atf-c/utils_test.c (revision ab0b9f6b3073e6c4d1dfbf07444d7db67a189a96)
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