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