1275988Sngie/* Copyright (c) 2010 The NetBSD Foundation, Inc.
2240116Smarcel * All rights reserved.
3240116Smarcel *
4240116Smarcel * Redistribution and use in source and binary forms, with or without
5240116Smarcel * modification, are permitted provided that the following conditions
6240116Smarcel * are met:
7240116Smarcel * 1. Redistributions of source code must retain the above copyright
8240116Smarcel *    notice, this list of conditions and the following disclaimer.
9240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright
10240116Smarcel *    notice, this list of conditions and the following disclaimer in the
11240116Smarcel *    documentation and/or other materials provided with the distribution.
12240116Smarcel *
13240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24275988Sngie * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25240116Smarcel
26275988Sngie#include "atf-c/utils.h"
27275988Sngie
28260029Sjmmv#include <sys/stat.h>
29260029Sjmmv#include <sys/wait.h>
30260029Sjmmv
31260029Sjmmv#include <fcntl.h>
32260029Sjmmv#include <stddef.h>
33260029Sjmmv#include <stdio.h>
34240116Smarcel#include <stdlib.h>
35240116Smarcel#include <string.h>
36260029Sjmmv#include <unistd.h>
37240116Smarcel
38240116Smarcel#include <atf-c.h>
39240116Smarcel
40275988Sngie#include "atf-c/detail/dynstr.h"
41275988Sngie#include "atf-c/detail/test_helpers.h"
42240116Smarcel
43260029Sjmmv/** Reads the contents of a file into a buffer.
44260029Sjmmv *
45260029Sjmmv * Up to buflen-1 characters are read into buffer.  If this function returns,
46260029Sjmmv * the contents read into the buffer are guaranteed to be nul-terminated.
47260029Sjmmv * Note, however, that if the file contains any nul characters itself,
48260029Sjmmv * comparing it "as a string" will not work.
49260029Sjmmv *
50260029Sjmmv * \param path The file to be read, which must exist.
51260029Sjmmv * \param buffer Buffer into which to store the file contents.
52260029Sjmmv * \param buflen Size of the target buffer.
53260029Sjmmv *
54260029Sjmmv * \return The count of bytes read. */
55260029Sjmmvstatic ssize_t
56260029Sjmmvread_file(const char *path, void *const buffer, const size_t buflen)
57240116Smarcel{
58260029Sjmmv    const int fd = open(path, O_RDONLY);
59260029Sjmmv    ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", path);
60260029Sjmmv    const ssize_t length = read(fd, buffer, buflen - 1);
61260029Sjmmv    close(fd);
62260029Sjmmv    ATF_REQUIRE(length != -1);
63260029Sjmmv    ((char *)buffer)[length] = '\0';
64260029Sjmmv    return length;
65260029Sjmmv}
66260029Sjmmv
67260029SjmmvATF_TC_WITHOUT_HEAD(cat_file__empty);
68260029SjmmvATF_TC_BODY(cat_file__empty, tc)
69260029Sjmmv{
70260029Sjmmv    atf_utils_create_file("file.txt", "%s", "");
71260029Sjmmv    atf_utils_redirect(STDOUT_FILENO, "captured.txt");
72260029Sjmmv    atf_utils_cat_file("file.txt", "PREFIX");
73260029Sjmmv    fflush(stdout);
74260029Sjmmv    close(STDOUT_FILENO);
75260029Sjmmv
76260029Sjmmv    char buffer[1024];
77260029Sjmmv    read_file("captured.txt", buffer, sizeof(buffer));
78260029Sjmmv    ATF_REQUIRE_STREQ("", buffer);
79260029Sjmmv}
80260029Sjmmv
81260029SjmmvATF_TC_WITHOUT_HEAD(cat_file__one_line);
82260029SjmmvATF_TC_BODY(cat_file__one_line, tc)
83260029Sjmmv{
84260029Sjmmv    atf_utils_create_file("file.txt", "This is a single line\n");
85260029Sjmmv    atf_utils_redirect(STDOUT_FILENO, "captured.txt");
86260029Sjmmv    atf_utils_cat_file("file.txt", "PREFIX");
87260029Sjmmv    fflush(stdout);
88260029Sjmmv    close(STDOUT_FILENO);
89260029Sjmmv
90260029Sjmmv    char buffer[1024];
91260029Sjmmv    read_file("captured.txt", buffer, sizeof(buffer));
92260029Sjmmv    ATF_REQUIRE_STREQ("PREFIXThis is a single line\n", buffer);
93260029Sjmmv}
94260029Sjmmv
95260029SjmmvATF_TC_WITHOUT_HEAD(cat_file__several_lines);
96260029SjmmvATF_TC_BODY(cat_file__several_lines, tc)
97260029Sjmmv{
98260029Sjmmv    atf_utils_create_file("file.txt", "First\nSecond line\nAnd third\n");
99260029Sjmmv    atf_utils_redirect(STDOUT_FILENO, "captured.txt");
100260029Sjmmv    atf_utils_cat_file("file.txt", ">");
101260029Sjmmv    fflush(stdout);
102260029Sjmmv    close(STDOUT_FILENO);
103260029Sjmmv
104260029Sjmmv    char buffer[1024];
105260029Sjmmv    read_file("captured.txt", buffer, sizeof(buffer));
106260029Sjmmv    ATF_REQUIRE_STREQ(">First\n>Second line\n>And third\n", buffer);
107260029Sjmmv}
108260029Sjmmv
109260029SjmmvATF_TC_WITHOUT_HEAD(cat_file__no_newline_eof);
110260029SjmmvATF_TC_BODY(cat_file__no_newline_eof, tc)
111260029Sjmmv{
112260029Sjmmv    atf_utils_create_file("file.txt", "Foo\n bar baz");
113260029Sjmmv    atf_utils_redirect(STDOUT_FILENO, "captured.txt");
114260029Sjmmv    atf_utils_cat_file("file.txt", "PREFIX");
115260029Sjmmv    fflush(stdout);
116260029Sjmmv    close(STDOUT_FILENO);
117260029Sjmmv
118260029Sjmmv    char buffer[1024];
119260029Sjmmv    read_file("captured.txt", buffer, sizeof(buffer));
120260029Sjmmv    ATF_REQUIRE_STREQ("PREFIXFoo\nPREFIX bar baz", buffer);
121260029Sjmmv}
122260029Sjmmv
123260029SjmmvATF_TC_WITHOUT_HEAD(compare_file__empty__match);
124260029SjmmvATF_TC_BODY(compare_file__empty__match, tc)
125260029Sjmmv{
126260029Sjmmv    atf_utils_create_file("test.txt", "%s", "");
127260029Sjmmv    ATF_REQUIRE(atf_utils_compare_file("test.txt", ""));
128260029Sjmmv}
129260029Sjmmv
130260029SjmmvATF_TC_WITHOUT_HEAD(compare_file__empty__not_match);
131260029SjmmvATF_TC_BODY(compare_file__empty__not_match, tc)
132260029Sjmmv{
133260029Sjmmv    atf_utils_create_file("test.txt", "%s", "");
134260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n"));
135260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", "foo"));
136260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", " "));
137260029Sjmmv}
138260029Sjmmv
139260029SjmmvATF_TC_WITHOUT_HEAD(compare_file__short__match);
140260029SjmmvATF_TC_BODY(compare_file__short__match, tc)
141260029Sjmmv{
142260029Sjmmv    atf_utils_create_file("test.txt", "this is a short file");
143260029Sjmmv    ATF_REQUIRE(atf_utils_compare_file("test.txt", "this is a short file"));
144260029Sjmmv}
145260029Sjmmv
146260029SjmmvATF_TC_WITHOUT_HEAD(compare_file__short__not_match);
147260029SjmmvATF_TC_BODY(compare_file__short__not_match, tc)
148260029Sjmmv{
149260029Sjmmv    atf_utils_create_file("test.txt", "this is a short file");
150260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", ""));
151260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n"));
152260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a Short file"));
153260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a short fil"));
154260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", "this is a short file "));
155260029Sjmmv}
156260029Sjmmv
157260029SjmmvATF_TC_WITHOUT_HEAD(compare_file__long__match);
158260029SjmmvATF_TC_BODY(compare_file__long__match, tc)
159260029Sjmmv{
160260029Sjmmv    char long_contents[3456];
161260029Sjmmv    size_t i = 0;
162260029Sjmmv    for (; i < sizeof(long_contents) - 1; i++)
163260029Sjmmv        long_contents[i] = '0' + (i % 10);
164260029Sjmmv    long_contents[i] = '\0';
165260029Sjmmv    atf_utils_create_file("test.txt", "%s", long_contents);
166260029Sjmmv
167260029Sjmmv    ATF_REQUIRE(atf_utils_compare_file("test.txt", long_contents));
168260029Sjmmv}
169260029Sjmmv
170260029SjmmvATF_TC_WITHOUT_HEAD(compare_file__long__not_match);
171260029SjmmvATF_TC_BODY(compare_file__long__not_match, tc)
172260029Sjmmv{
173260029Sjmmv    char long_contents[3456];
174260029Sjmmv    size_t i = 0;
175260029Sjmmv    for (; i < sizeof(long_contents) - 1; i++)
176260029Sjmmv        long_contents[i] = '0' + (i % 10);
177260029Sjmmv    long_contents[i] = '\0';
178260029Sjmmv    atf_utils_create_file("test.txt", "%s", long_contents);
179260029Sjmmv
180260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", ""));
181260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", "\n"));
182260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", "0123456789"));
183260029Sjmmv    long_contents[i - 1] = 'Z';
184260029Sjmmv    ATF_REQUIRE(!atf_utils_compare_file("test.txt", long_contents));
185260029Sjmmv}
186260029Sjmmv
187260029SjmmvATF_TC_WITHOUT_HEAD(copy_file__empty);
188260029SjmmvATF_TC_BODY(copy_file__empty, tc)
189260029Sjmmv{
190260029Sjmmv    atf_utils_create_file("src.txt", "%s", "");
191260029Sjmmv    ATF_REQUIRE(chmod("src.txt", 0520) != -1);
192260029Sjmmv
193260029Sjmmv    atf_utils_copy_file("src.txt", "dest.txt");
194260029Sjmmv    ATF_REQUIRE(atf_utils_compare_file("dest.txt", ""));
195260029Sjmmv    struct stat sb;
196260029Sjmmv    ATF_REQUIRE(stat("dest.txt", &sb) != -1);
197260029Sjmmv    ATF_REQUIRE_EQ(0520, sb.st_mode & 0xfff);
198260029Sjmmv}
199260029Sjmmv
200260029SjmmvATF_TC_WITHOUT_HEAD(copy_file__some_contents);
201260029SjmmvATF_TC_BODY(copy_file__some_contents, tc)
202260029Sjmmv{
203260029Sjmmv    atf_utils_create_file("src.txt", "This is a\ntest file\n");
204260029Sjmmv    atf_utils_copy_file("src.txt", "dest.txt");
205260029Sjmmv    ATF_REQUIRE(atf_utils_compare_file("dest.txt", "This is a\ntest file\n"));
206260029Sjmmv}
207260029Sjmmv
208260029SjmmvATF_TC_WITHOUT_HEAD(create_file);
209260029SjmmvATF_TC_BODY(create_file, tc)
210260029Sjmmv{
211260029Sjmmv    atf_utils_create_file("test.txt", "This is a test with %d", 12345);
212260029Sjmmv
213260029Sjmmv    char buffer[128];
214260029Sjmmv    read_file("test.txt", buffer, sizeof(buffer));
215260029Sjmmv    ATF_REQUIRE_STREQ("This is a test with 12345", buffer);
216260029Sjmmv}
217260029Sjmmv
218260029SjmmvATF_TC_WITHOUT_HEAD(file_exists);
219260029SjmmvATF_TC_BODY(file_exists, tc)
220260029Sjmmv{
221260029Sjmmv    atf_utils_create_file("test.txt", "foo");
222260029Sjmmv
223260029Sjmmv    ATF_REQUIRE( atf_utils_file_exists("test.txt"));
224260029Sjmmv    ATF_REQUIRE( atf_utils_file_exists("./test.txt"));
225260029Sjmmv    ATF_REQUIRE(!atf_utils_file_exists("./test.tx"));
226260029Sjmmv    ATF_REQUIRE(!atf_utils_file_exists("test.txt2"));
227260029Sjmmv}
228260029Sjmmv
229260029SjmmvATF_TC_WITHOUT_HEAD(fork);
230260029SjmmvATF_TC_BODY(fork, tc)
231260029Sjmmv{
232260029Sjmmv    fprintf(stdout, "Should not get into child\n");
233260029Sjmmv    fprintf(stderr, "Should not get into child\n");
234260029Sjmmv    pid_t pid = atf_utils_fork();
235260029Sjmmv    if (pid == 0) {
236260029Sjmmv        fprintf(stdout, "Child stdout\n");
237260029Sjmmv        fprintf(stderr, "Child stderr\n");
238260029Sjmmv        exit(EXIT_SUCCESS);
239260029Sjmmv    }
240260029Sjmmv
241260029Sjmmv    int status;
242260029Sjmmv    ATF_REQUIRE(waitpid(pid, &status, 0) != -1);
243260029Sjmmv    ATF_REQUIRE(WIFEXITED(status));
244260029Sjmmv    ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
245260029Sjmmv
246275988Sngie    atf_dynstr_t out_name;
247275988Sngie    RE(atf_dynstr_init_fmt(&out_name, "atf_utils_fork_%d_out.txt", (int)pid));
248275988Sngie    atf_dynstr_t err_name;
249275988Sngie    RE(atf_dynstr_init_fmt(&err_name, "atf_utils_fork_%d_err.txt", (int)pid));
250275988Sngie
251260029Sjmmv    char buffer[1024];
252275988Sngie    read_file(atf_dynstr_cstring(&out_name), buffer, sizeof(buffer));
253260029Sjmmv    ATF_REQUIRE_STREQ("Child stdout\n", buffer);
254275988Sngie    read_file(atf_dynstr_cstring(&err_name), buffer, sizeof(buffer));
255260029Sjmmv    ATF_REQUIRE_STREQ("Child stderr\n", buffer);
256275988Sngie
257275988Sngie    atf_dynstr_fini(&err_name);
258275988Sngie    atf_dynstr_fini(&out_name);
259260029Sjmmv}
260260029Sjmmv
261260029SjmmvATF_TC_WITHOUT_HEAD(free_charpp__empty);
262260029SjmmvATF_TC_BODY(free_charpp__empty, tc)
263260029Sjmmv{
264240116Smarcel    char **array = malloc(sizeof(char *) * 1);
265240116Smarcel    array[0] = NULL;
266240116Smarcel
267240116Smarcel    atf_utils_free_charpp(array);
268240116Smarcel}
269240116Smarcel
270260029SjmmvATF_TC_WITHOUT_HEAD(free_charpp__some);
271260029SjmmvATF_TC_BODY(free_charpp__some, tc)
272240116Smarcel{
273240116Smarcel    char **array = malloc(sizeof(char *) * 4);
274240116Smarcel    array[0] = strdup("first");
275240116Smarcel    array[1] = strdup("second");
276240116Smarcel    array[2] = strdup("third");
277240116Smarcel    array[3] = NULL;
278240116Smarcel
279240116Smarcel    atf_utils_free_charpp(array);
280240116Smarcel}
281240116Smarcel
282260029SjmmvATF_TC_WITHOUT_HEAD(grep_file);
283260029SjmmvATF_TC_BODY(grep_file, tc)
284260029Sjmmv{
285260029Sjmmv    atf_utils_create_file("test.txt", "line1\nthe second line\naaaabbbb\n");
286260029Sjmmv
287260029Sjmmv    ATF_CHECK(atf_utils_grep_file("line1", "test.txt"));
288260029Sjmmv    ATF_CHECK(atf_utils_grep_file("line%d", "test.txt", 1));
289260029Sjmmv    ATF_CHECK(atf_utils_grep_file("second line", "test.txt"));
290260029Sjmmv    ATF_CHECK(atf_utils_grep_file("aa.*bb", "test.txt"));
291260029Sjmmv    ATF_CHECK(!atf_utils_grep_file("foo", "test.txt"));
292260029Sjmmv    ATF_CHECK(!atf_utils_grep_file("bar", "test.txt"));
293260029Sjmmv    ATF_CHECK(!atf_utils_grep_file("aaaaa", "test.txt"));
294260029Sjmmv}
295260029Sjmmv
296260029SjmmvATF_TC_WITHOUT_HEAD(grep_string);
297260029SjmmvATF_TC_BODY(grep_string, tc)
298260029Sjmmv{
299260029Sjmmv    const char *str = "a string - aaaabbbb";
300260029Sjmmv    ATF_CHECK(atf_utils_grep_string("a string", str));
301260029Sjmmv    ATF_CHECK(atf_utils_grep_string("^a string", str));
302260029Sjmmv    ATF_CHECK(atf_utils_grep_string("aaaabbbb$", str));
303260029Sjmmv    ATF_CHECK(atf_utils_grep_string("a%s*bb", str, "a."));
304260029Sjmmv    ATF_CHECK(!atf_utils_grep_string("foo", str));
305260029Sjmmv    ATF_CHECK(!atf_utils_grep_string("bar", str));
306260029Sjmmv    ATF_CHECK(!atf_utils_grep_string("aaaaa", str));
307260029Sjmmv}
308260029Sjmmv
309260029SjmmvATF_TC_WITHOUT_HEAD(readline__none);
310260029SjmmvATF_TC_BODY(readline__none, tc)
311260029Sjmmv{
312260029Sjmmv    atf_utils_create_file("empty.txt", "%s", "");
313260029Sjmmv
314260029Sjmmv    const int fd = open("empty.txt", O_RDONLY);
315260029Sjmmv    ATF_REQUIRE(fd != -1);
316260029Sjmmv    ATF_REQUIRE(atf_utils_readline(fd) == NULL);
317260029Sjmmv    close(fd);
318260029Sjmmv}
319260029Sjmmv
320260029SjmmvATF_TC_WITHOUT_HEAD(readline__some);
321260029SjmmvATF_TC_BODY(readline__some, tc)
322260029Sjmmv{
323260029Sjmmv    const char *l1 = "First line with % formatting % characters %";
324260029Sjmmv    const char *l2 = "Second line; much longer than the first one";
325260029Sjmmv    const char *l3 = "Last line, without terminator";
326260029Sjmmv
327260029Sjmmv    atf_utils_create_file("test.txt", "%s\n%s\n%s", l1, l2, l3);
328260029Sjmmv
329260029Sjmmv    const int fd = open("test.txt", O_RDONLY);
330260029Sjmmv    ATF_REQUIRE(fd != -1);
331260029Sjmmv
332260029Sjmmv    char *line;
333260029Sjmmv
334260029Sjmmv    line = atf_utils_readline(fd);
335260029Sjmmv    ATF_REQUIRE_STREQ(l1, line);
336260029Sjmmv    free(line);
337260029Sjmmv
338260029Sjmmv    line = atf_utils_readline(fd);
339260029Sjmmv    ATF_REQUIRE_STREQ(l2, line);
340260029Sjmmv    free(line);
341260029Sjmmv
342260029Sjmmv    line = atf_utils_readline(fd);
343260029Sjmmv    ATF_REQUIRE_STREQ(l3, line);
344260029Sjmmv    free(line);
345260029Sjmmv
346260029Sjmmv    close(fd);
347260029Sjmmv}
348260029Sjmmv
349260029SjmmvATF_TC_WITHOUT_HEAD(redirect__stdout);
350260029SjmmvATF_TC_BODY(redirect__stdout, tc)
351260029Sjmmv{
352260029Sjmmv    printf("Buffer this");
353260029Sjmmv    atf_utils_redirect(STDOUT_FILENO, "captured.txt");
354260029Sjmmv    printf("The printed message");
355260029Sjmmv    fflush(stdout);
356260029Sjmmv
357260029Sjmmv    char buffer[1024];
358260029Sjmmv    read_file("captured.txt", buffer, sizeof(buffer));
359260029Sjmmv    ATF_REQUIRE_STREQ("The printed message", buffer);
360260029Sjmmv}
361260029Sjmmv
362260029SjmmvATF_TC_WITHOUT_HEAD(redirect__stderr);
363260029SjmmvATF_TC_BODY(redirect__stderr, tc)
364260029Sjmmv{
365260029Sjmmv    fprintf(stderr, "Buffer this");
366260029Sjmmv    atf_utils_redirect(STDERR_FILENO, "captured.txt");
367260029Sjmmv    fprintf(stderr, "The printed message");
368260029Sjmmv    fflush(stderr);
369260029Sjmmv
370260029Sjmmv    char buffer[1024];
371260029Sjmmv    read_file("captured.txt", buffer, sizeof(buffer));
372260029Sjmmv    ATF_REQUIRE_STREQ("The printed message", buffer);
373260029Sjmmv}
374260029Sjmmv
375260029SjmmvATF_TC_WITHOUT_HEAD(redirect__other);
376260029SjmmvATF_TC_BODY(redirect__other, tc)
377260029Sjmmv{
378260029Sjmmv    const char *message = "Foo bar\nbaz\n";
379260029Sjmmv    atf_utils_redirect(15, "captured.txt");
380260029Sjmmv    ATF_REQUIRE(write(15, message, strlen(message)) != -1);
381260029Sjmmv    close(15);
382260029Sjmmv
383260029Sjmmv    char buffer[1024];
384260029Sjmmv    read_file("captured.txt", buffer, sizeof(buffer));
385260029Sjmmv    ATF_REQUIRE_STREQ(message, buffer);
386260029Sjmmv}
387260029Sjmmv
388260029Sjmmvstatic void
389260029Sjmmvfork_and_wait(const int exitstatus, const char* expout, const char* experr)
390260029Sjmmv{
391260029Sjmmv    const pid_t pid = atf_utils_fork();
392275988Sngie    ATF_REQUIRE(pid != -1);
393260029Sjmmv    if (pid == 0) {
394260029Sjmmv        fprintf(stdout, "Some output\n");
395260029Sjmmv        fprintf(stderr, "Some error\n");
396260029Sjmmv        exit(123);
397260029Sjmmv    }
398260029Sjmmv    atf_utils_wait(pid, exitstatus, expout, experr);
399260029Sjmmv    exit(EXIT_SUCCESS);
400260029Sjmmv}
401260029Sjmmv
402260029SjmmvATF_TC_WITHOUT_HEAD(wait__ok);
403260029SjmmvATF_TC_BODY(wait__ok, tc)
404260029Sjmmv{
405260029Sjmmv    const pid_t control = fork();
406260029Sjmmv    ATF_REQUIRE(control != -1);
407260029Sjmmv    if (control == 0)
408260029Sjmmv        fork_and_wait(123, "Some output\n", "Some error\n");
409260029Sjmmv    else {
410260029Sjmmv        int status;
411260029Sjmmv        ATF_REQUIRE(waitpid(control, &status, 0) != -1);
412260029Sjmmv        ATF_REQUIRE(WIFEXITED(status));
413260029Sjmmv        ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
414260029Sjmmv    }
415260029Sjmmv}
416260029Sjmmv
417275988SngieATF_TC_WITHOUT_HEAD(wait__ok_nested);
418275988SngieATF_TC_BODY(wait__ok_nested, tc)
419275988Sngie{
420275988Sngie    const pid_t parent = atf_utils_fork();
421275988Sngie    ATF_REQUIRE(parent != -1);
422275988Sngie    if (parent == 0) {
423275988Sngie        const pid_t child = atf_utils_fork();
424275988Sngie        ATF_REQUIRE(child != -1);
425275988Sngie        if (child == 0) {
426275988Sngie            fflush(stderr);
427275988Sngie            fprintf(stdout, "Child output\n");
428275988Sngie            fflush(stdout);
429275988Sngie            fprintf(stderr, "Child error\n");
430275988Sngie            exit(50);
431275988Sngie        } else {
432275988Sngie            fprintf(stdout, "Parent output\n");
433275988Sngie            fprintf(stderr, "Parent error\n");
434275988Sngie            atf_utils_wait(child, 50, "Child output\n", "Child error\n");
435275988Sngie            exit(40);
436275988Sngie        }
437275988Sngie    } else {
438275988Sngie        atf_utils_wait(parent, 40,
439275988Sngie                       "Parent output\n"
440275988Sngie                       "subprocess stdout: Child output\n"
441275988Sngie                       "subprocess stderr: Child error\n",
442275988Sngie                       "Parent error\n");
443275988Sngie    }
444275988Sngie}
445275988Sngie
446260029SjmmvATF_TC_WITHOUT_HEAD(wait__invalid_exitstatus);
447260029SjmmvATF_TC_BODY(wait__invalid_exitstatus, tc)
448260029Sjmmv{
449260029Sjmmv    const pid_t control = fork();
450260029Sjmmv    ATF_REQUIRE(control != -1);
451260029Sjmmv    if (control == 0)
452260029Sjmmv        fork_and_wait(120, "Some output\n", "Some error\n");
453260029Sjmmv    else {
454260029Sjmmv        int status;
455260029Sjmmv        ATF_REQUIRE(waitpid(control, &status, 0) != -1);
456260029Sjmmv        ATF_REQUIRE(WIFEXITED(status));
457260029Sjmmv        ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
458260029Sjmmv    }
459260029Sjmmv}
460260029Sjmmv
461260029SjmmvATF_TC_WITHOUT_HEAD(wait__invalid_stdout);
462260029SjmmvATF_TC_BODY(wait__invalid_stdout, tc)
463260029Sjmmv{
464260029Sjmmv    const pid_t control = fork();
465260029Sjmmv    ATF_REQUIRE(control != -1);
466260029Sjmmv    if (control == 0)
467260029Sjmmv        fork_and_wait(123, "Some output foo\n", "Some error\n");
468260029Sjmmv    else {
469260029Sjmmv        int status;
470260029Sjmmv        ATF_REQUIRE(waitpid(control, &status, 0) != -1);
471260029Sjmmv        ATF_REQUIRE(WIFEXITED(status));
472260029Sjmmv        ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
473260029Sjmmv    }
474260029Sjmmv}
475260029Sjmmv
476260029SjmmvATF_TC_WITHOUT_HEAD(wait__invalid_stderr);
477260029SjmmvATF_TC_BODY(wait__invalid_stderr, tc)
478260029Sjmmv{
479260029Sjmmv    const pid_t control = fork();
480260029Sjmmv    ATF_REQUIRE(control != -1);
481260029Sjmmv    if (control == 0)
482260029Sjmmv        fork_and_wait(123, "Some output\n", "Some error foo\n");
483260029Sjmmv    else {
484260029Sjmmv        int status;
485260029Sjmmv        ATF_REQUIRE(waitpid(control, &status, 0) != -1);
486260029Sjmmv        ATF_REQUIRE(WIFEXITED(status));
487260029Sjmmv        ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
488260029Sjmmv    }
489260029Sjmmv}
490260029Sjmmv
491260029SjmmvATF_TC_WITHOUT_HEAD(wait__save_stdout);
492260029SjmmvATF_TC_BODY(wait__save_stdout, tc)
493260029Sjmmv{
494260029Sjmmv    const pid_t control = fork();
495260029Sjmmv    ATF_REQUIRE(control != -1);
496260029Sjmmv    if (control == 0)
497260029Sjmmv        fork_and_wait(123, "save:my-output.txt", "Some error\n");
498260029Sjmmv    else {
499260029Sjmmv        int status;
500260029Sjmmv        ATF_REQUIRE(waitpid(control, &status, 0) != -1);
501260029Sjmmv        ATF_REQUIRE(WIFEXITED(status));
502260029Sjmmv        ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
503260029Sjmmv
504260029Sjmmv        ATF_REQUIRE(atf_utils_compare_file("my-output.txt", "Some output\n"));
505260029Sjmmv    }
506260029Sjmmv}
507260029Sjmmv
508260029SjmmvATF_TC_WITHOUT_HEAD(wait__save_stderr);
509260029SjmmvATF_TC_BODY(wait__save_stderr, tc)
510260029Sjmmv{
511260029Sjmmv    const pid_t control = fork();
512260029Sjmmv    ATF_REQUIRE(control != -1);
513260029Sjmmv    if (control == 0)
514260029Sjmmv        fork_and_wait(123, "Some output\n", "save:my-output.txt");
515260029Sjmmv    else {
516260029Sjmmv        int status;
517260029Sjmmv        ATF_REQUIRE(waitpid(control, &status, 0) != -1);
518260029Sjmmv        ATF_REQUIRE(WIFEXITED(status));
519260029Sjmmv        ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
520260029Sjmmv
521260029Sjmmv        ATF_REQUIRE(atf_utils_compare_file("my-output.txt", "Some error\n"));
522260029Sjmmv    }
523260029Sjmmv}
524260029Sjmmv
525240116SmarcelATF_TP_ADD_TCS(tp)
526240116Smarcel{
527260029Sjmmv    ATF_TP_ADD_TC(tp, cat_file__empty);
528260029Sjmmv    ATF_TP_ADD_TC(tp, cat_file__one_line);
529260029Sjmmv    ATF_TP_ADD_TC(tp, cat_file__several_lines);
530260029Sjmmv    ATF_TP_ADD_TC(tp, cat_file__no_newline_eof);
531240116Smarcel
532260029Sjmmv    ATF_TP_ADD_TC(tp, compare_file__empty__match);
533260029Sjmmv    ATF_TP_ADD_TC(tp, compare_file__empty__not_match);
534260029Sjmmv    ATF_TP_ADD_TC(tp, compare_file__short__match);
535260029Sjmmv    ATF_TP_ADD_TC(tp, compare_file__short__not_match);
536260029Sjmmv    ATF_TP_ADD_TC(tp, compare_file__long__match);
537260029Sjmmv    ATF_TP_ADD_TC(tp, compare_file__long__not_match);
538260029Sjmmv
539260029Sjmmv    ATF_TP_ADD_TC(tp, copy_file__empty);
540260029Sjmmv    ATF_TP_ADD_TC(tp, copy_file__some_contents);
541260029Sjmmv
542260029Sjmmv    ATF_TP_ADD_TC(tp, create_file);
543260029Sjmmv
544260029Sjmmv    ATF_TP_ADD_TC(tp, file_exists);
545260029Sjmmv
546260029Sjmmv    ATF_TP_ADD_TC(tp, fork);
547260029Sjmmv
548260029Sjmmv    ATF_TP_ADD_TC(tp, free_charpp__empty);
549260029Sjmmv    ATF_TP_ADD_TC(tp, free_charpp__some);
550260029Sjmmv
551260029Sjmmv    ATF_TP_ADD_TC(tp, grep_file);
552260029Sjmmv    ATF_TP_ADD_TC(tp, grep_string);
553260029Sjmmv
554260029Sjmmv    ATF_TP_ADD_TC(tp, readline__none);
555260029Sjmmv    ATF_TP_ADD_TC(tp, readline__some);
556260029Sjmmv
557260029Sjmmv    ATF_TP_ADD_TC(tp, redirect__stdout);
558260029Sjmmv    ATF_TP_ADD_TC(tp, redirect__stderr);
559260029Sjmmv    ATF_TP_ADD_TC(tp, redirect__other);
560260029Sjmmv
561260029Sjmmv    ATF_TP_ADD_TC(tp, wait__ok);
562275988Sngie    ATF_TP_ADD_TC(tp, wait__ok_nested);
563260029Sjmmv    ATF_TP_ADD_TC(tp, wait__save_stdout);
564260029Sjmmv    ATF_TP_ADD_TC(tp, wait__save_stderr);
565260029Sjmmv    ATF_TP_ADD_TC(tp, wait__invalid_exitstatus);
566260029Sjmmv    ATF_TP_ADD_TC(tp, wait__invalid_stdout);
567260029Sjmmv    ATF_TP_ADD_TC(tp, wait__invalid_stderr);
568260029Sjmmv
569240116Smarcel    return atf_no_error();
570240116Smarcel}
571