1/*
2 * Automated Testing Framework (atf)
3 *
4 * Copyright (c) 2008, 2009, 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 <fcntl.h>
31#include <signal.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35#include <unistd.h>
36
37#include <atf-c.h>
38
39#include "atf-c/check.h"
40#include "atf-c/config.h"
41
42#include "detail/fs.h"
43#include "detail/map.h"
44#include "detail/process.h"
45#include "detail/test_helpers.h"
46
47/* ---------------------------------------------------------------------
48 * Auxiliary functions.
49 * --------------------------------------------------------------------- */
50
51static
52void
53do_exec(const atf_tc_t *tc, const char *helper_name, atf_check_result_t *r)
54{
55    atf_fs_path_t process_helpers;
56    const char *argv[3];
57
58    get_process_helpers_path(tc, false, &process_helpers);
59
60    argv[0] = atf_fs_path_cstring(&process_helpers);
61    argv[1] = helper_name;
62    argv[2] = NULL;
63    printf("Executing %s %s\n", argv[0], argv[1]);
64    RE(atf_check_exec_array(argv, r));
65
66    atf_fs_path_fini(&process_helpers);
67}
68
69static
70void
71do_exec_with_arg(const atf_tc_t *tc, const char *helper_name, const char *arg,
72                 atf_check_result_t *r)
73{
74    atf_fs_path_t process_helpers;
75    const char *argv[4];
76
77    get_process_helpers_path(tc, false, &process_helpers);
78
79    argv[0] = atf_fs_path_cstring(&process_helpers);
80    argv[1] = helper_name;
81    argv[2] = arg;
82    argv[3] = NULL;
83    printf("Executing %s %s %s\n", argv[0], argv[1], argv[2]);
84    RE(atf_check_exec_array(argv, r));
85
86    atf_fs_path_fini(&process_helpers);
87}
88
89static
90void
91check_line(int fd, const char *exp)
92{
93    atf_dynstr_t line;
94
95    atf_dynstr_init(&line);
96    ATF_CHECK(!read_line(fd, &line));
97    ATF_CHECK_MSG(atf_equal_dynstr_cstring(&line, exp),
98                  "read: '%s', expected: '%s'",
99                  atf_dynstr_cstring(&line), exp);
100    atf_dynstr_fini(&line);
101}
102
103/* ---------------------------------------------------------------------
104 * Helper test cases for the free functions.
105 * --------------------------------------------------------------------- */
106
107ATF_TC(h_build_c_o_ok);
108ATF_TC_HEAD(h_build_c_o_ok, tc)
109{
110    atf_tc_set_md_var(tc, "descr", "Helper test case for build_c_o");
111}
112ATF_TC_BODY(h_build_c_o_ok, tc)
113{
114    FILE *sfile;
115    bool success;
116
117    ATF_REQUIRE((sfile = fopen("test.c", "w")) != NULL);
118    fprintf(sfile, "#include <stdio.h>\n");
119    fclose(sfile);
120
121    RE(atf_check_build_c_o("test.c", "test.o", NULL, &success));
122    ATF_REQUIRE(success);
123}
124
125ATF_TC(h_build_c_o_fail);
126ATF_TC_HEAD(h_build_c_o_fail, tc)
127{
128    atf_tc_set_md_var(tc, "descr", "Helper test case for build_c_o");
129}
130ATF_TC_BODY(h_build_c_o_fail, tc)
131{
132    FILE *sfile;
133    bool success;
134
135    ATF_REQUIRE((sfile = fopen("test.c", "w")) != NULL);
136    fprintf(sfile, "void foo(void) { int a = UNDEFINED_SYMBOL; }\n");
137    fclose(sfile);
138
139    RE(atf_check_build_c_o("test.c", "test.o", NULL, &success));
140    ATF_REQUIRE(!success);
141}
142
143ATF_TC(h_build_cpp_ok);
144ATF_TC_HEAD(h_build_cpp_ok, tc)
145{
146    atf_tc_set_md_var(tc, "descr", "Helper test case for build_cpp");
147}
148ATF_TC_BODY(h_build_cpp_ok, tc)
149{
150    FILE *sfile;
151    bool success;
152    atf_fs_path_t test_p;
153
154    RE(atf_fs_path_init_fmt(&test_p, "test.p"));
155
156    ATF_REQUIRE((sfile = fopen("test.c", "w")) != NULL);
157    fprintf(sfile, "#define A foo\n");
158    fprintf(sfile, "#define B bar\n");
159    fprintf(sfile, "A B\n");
160    fclose(sfile);
161
162    RE(atf_check_build_cpp("test.c", atf_fs_path_cstring(&test_p), NULL,
163                           &success));
164    ATF_REQUIRE(success);
165
166    atf_fs_path_fini(&test_p);
167}
168
169ATF_TC(h_build_cpp_fail);
170ATF_TC_HEAD(h_build_cpp_fail, tc)
171{
172    atf_tc_set_md_var(tc, "descr", "Helper test case for build_cpp");
173}
174ATF_TC_BODY(h_build_cpp_fail, tc)
175{
176    FILE *sfile;
177    bool success;
178
179    ATF_REQUIRE((sfile = fopen("test.c", "w")) != NULL);
180    fprintf(sfile, "#include \"./non-existent.h\"\n");
181    fclose(sfile);
182
183    RE(atf_check_build_cpp("test.c", "test.p", NULL, &success));
184    ATF_REQUIRE(!success);
185}
186
187ATF_TC(h_build_cxx_o_ok);
188ATF_TC_HEAD(h_build_cxx_o_ok, tc)
189{
190    atf_tc_set_md_var(tc, "descr", "Helper test case for build_cxx_o");
191}
192ATF_TC_BODY(h_build_cxx_o_ok, tc)
193{
194    FILE *sfile;
195    bool success;
196
197    ATF_REQUIRE((sfile = fopen("test.cpp", "w")) != NULL);
198    fprintf(sfile, "#include <iostream>\n");
199    fclose(sfile);
200
201    RE(atf_check_build_cxx_o("test.cpp", "test.o", NULL, &success));
202    ATF_REQUIRE(success);
203}
204
205ATF_TC(h_build_cxx_o_fail);
206ATF_TC_HEAD(h_build_cxx_o_fail, tc)
207{
208    atf_tc_set_md_var(tc, "descr", "Helper test case for build_cxx_o");
209}
210ATF_TC_BODY(h_build_cxx_o_fail, tc)
211{
212    FILE *sfile;
213    bool success;
214
215    ATF_REQUIRE((sfile = fopen("test.cpp", "w")) != NULL);
216    fprintf(sfile, "void foo(void) { int a = UNDEFINED_SYMBOL; }\n");
217    fclose(sfile);
218
219    RE(atf_check_build_cxx_o("test.cpp", "test.o", NULL, &success));
220    ATF_REQUIRE(!success);
221}
222
223/* ---------------------------------------------------------------------
224 * Test cases for the free functions.
225 * --------------------------------------------------------------------- */
226
227static
228void
229init_and_run_h_tc(atf_tc_t *tc, const atf_tc_pack_t *tcpack,
230                  const char *outname, const char *errname)
231{
232    const char *const config[] = { NULL };
233
234    RE(atf_tc_init_pack(tc, tcpack, config));
235    run_h_tc(tc, outname, errname, "result");
236    atf_tc_fini(tc);
237}
238
239ATF_TC(build_c_o);
240ATF_TC_HEAD(build_c_o, tc)
241{
242    atf_tc_set_md_var(tc, "descr", "Checks the atf_check_build_c_o "
243                      "function");
244}
245ATF_TC_BODY(build_c_o, tc)
246{
247    init_and_run_h_tc(&ATF_TC_NAME(h_build_c_o_ok),
248             &ATF_TC_PACK_NAME(h_build_c_o_ok), "stdout", "stderr");
249    ATF_CHECK(grep_file("stdout", "-o test.o"));
250    ATF_CHECK(grep_file("stdout", "-c test.c"));
251
252    init_and_run_h_tc(&ATF_TC_NAME(h_build_c_o_fail),
253             &ATF_TC_PACK_NAME(h_build_c_o_fail), "stdout", "stderr");
254    ATF_CHECK(grep_file("stdout", "-o test.o"));
255    ATF_CHECK(grep_file("stdout", "-c test.c"));
256    ATF_CHECK(grep_file("stderr", "test.c"));
257    ATF_CHECK(grep_file("stderr", "UNDEFINED_SYMBOL"));
258}
259
260ATF_TC(build_cpp);
261ATF_TC_HEAD(build_cpp, tc)
262{
263    atf_tc_set_md_var(tc, "descr", "Checks the atf_check_build_cpp "
264                      "function");
265}
266ATF_TC_BODY(build_cpp, tc)
267{
268    init_and_run_h_tc(&ATF_TC_NAME(h_build_cpp_ok),
269             &ATF_TC_PACK_NAME(h_build_cpp_ok), "stdout", "stderr");
270    ATF_CHECK(grep_file("stdout", "-o.*test.p"));
271    ATF_CHECK(grep_file("stdout", "test.c"));
272    ATF_CHECK(grep_file("test.p", "foo bar"));
273
274    init_and_run_h_tc(&ATF_TC_NAME(h_build_cpp_fail),
275             &ATF_TC_PACK_NAME(h_build_cpp_fail), "stdout", "stderr");
276    ATF_CHECK(grep_file("stdout", "-o test.p"));
277    ATF_CHECK(grep_file("stdout", "test.c"));
278    ATF_CHECK(grep_file("stderr", "test.c"));
279    ATF_CHECK(grep_file("stderr", "non-existent.h"));
280}
281
282ATF_TC(build_cxx_o);
283ATF_TC_HEAD(build_cxx_o, tc)
284{
285    atf_tc_set_md_var(tc, "descr", "Checks the atf_check_build_cxx_o "
286                      "function");
287}
288ATF_TC_BODY(build_cxx_o, tc)
289{
290    init_and_run_h_tc(&ATF_TC_NAME(h_build_cxx_o_ok),
291             &ATF_TC_PACK_NAME(h_build_cxx_o_ok), "stdout", "stderr");
292    ATF_CHECK(grep_file("stdout", "-o test.o"));
293    ATF_CHECK(grep_file("stdout", "-c test.cpp"));
294
295    init_and_run_h_tc(&ATF_TC_NAME(h_build_cxx_o_fail),
296             &ATF_TC_PACK_NAME(h_build_cxx_o_fail), "stdout", "stderr");
297    ATF_CHECK(grep_file("stdout", "-o test.o"));
298    ATF_CHECK(grep_file("stdout", "-c test.cpp"));
299    ATF_CHECK(grep_file("stderr", "test.cpp"));
300    ATF_CHECK(grep_file("stderr", "UNDEFINED_SYMBOL"));
301}
302
303ATF_TC(exec_array);
304ATF_TC_HEAD(exec_array, tc)
305{
306    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
307                      "works properly");
308}
309ATF_TC_BODY(exec_array, tc)
310{
311    atf_fs_path_t process_helpers;
312    atf_check_result_t result;
313
314    get_process_helpers_path(tc, false, &process_helpers);
315
316    const char *argv[4];
317    argv[0] = atf_fs_path_cstring(&process_helpers);
318    argv[1] = "echo";
319    argv[2] = "test-message";
320    argv[3] = NULL;
321
322    RE(atf_check_exec_array(argv, &result));
323
324    ATF_CHECK(atf_check_result_exited(&result));
325    ATF_CHECK(atf_check_result_exitcode(&result) == EXIT_SUCCESS);
326
327    {
328        const char *path = atf_check_result_stdout(&result);
329        int fd = open(path, O_RDONLY);
330        ATF_CHECK(fd != -1);
331        check_line(fd, "test-message");
332        close(fd);
333    }
334
335    atf_check_result_fini(&result);
336    atf_fs_path_fini(&process_helpers);
337}
338
339ATF_TC(exec_cleanup);
340ATF_TC_HEAD(exec_cleanup, tc)
341{
342    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
343                      "properly cleans up the temporary files it creates");
344}
345ATF_TC_BODY(exec_cleanup, tc)
346{
347    atf_fs_path_t out, err;
348    atf_check_result_t result;
349    bool exists;
350
351    do_exec(tc, "exit-success", &result);
352    RE(atf_fs_path_init_fmt(&out, "%s", atf_check_result_stdout(&result)));
353    RE(atf_fs_path_init_fmt(&err, "%s", atf_check_result_stderr(&result)));
354
355    RE(atf_fs_exists(&out, &exists)); ATF_CHECK(exists);
356    RE(atf_fs_exists(&err, &exists)); ATF_CHECK(exists);
357    atf_check_result_fini(&result);
358    RE(atf_fs_exists(&out, &exists)); ATF_CHECK(!exists);
359    RE(atf_fs_exists(&err, &exists)); ATF_CHECK(!exists);
360
361    atf_fs_path_fini(&err);
362    atf_fs_path_fini(&out);
363}
364
365ATF_TC(exec_exitstatus);
366ATF_TC_HEAD(exec_exitstatus, tc)
367{
368    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
369                      "properly captures the exit status of the executed "
370                      "command");
371}
372ATF_TC_BODY(exec_exitstatus, tc)
373{
374    {
375        atf_check_result_t result;
376        do_exec(tc, "exit-success", &result);
377        ATF_CHECK(atf_check_result_exited(&result));
378        ATF_CHECK(!atf_check_result_signaled(&result));
379        ATF_CHECK(atf_check_result_exitcode(&result) == EXIT_SUCCESS);
380        atf_check_result_fini(&result);
381    }
382
383    {
384        atf_check_result_t result;
385        do_exec(tc, "exit-failure", &result);
386        ATF_CHECK(atf_check_result_exited(&result));
387        ATF_CHECK(!atf_check_result_signaled(&result));
388        ATF_CHECK(atf_check_result_exitcode(&result) == EXIT_FAILURE);
389        atf_check_result_fini(&result);
390    }
391
392    {
393        atf_check_result_t result;
394        do_exec(tc, "exit-signal", &result);
395        ATF_CHECK(!atf_check_result_exited(&result));
396        ATF_CHECK(atf_check_result_signaled(&result));
397        ATF_CHECK(atf_check_result_termsig(&result) == SIGKILL);
398        atf_check_result_fini(&result);
399    }
400}
401
402ATF_TC(exec_stdout_stderr);
403ATF_TC_HEAD(exec_stdout_stderr, tc)
404{
405    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
406                      "properly captures the stdout and stderr streams "
407                      "of the child process");
408}
409ATF_TC_BODY(exec_stdout_stderr, tc)
410{
411    atf_check_result_t result1, result2;
412    const char *out1, *out2;
413    const char *err1, *err2;
414
415    do_exec_with_arg(tc, "stdout-stderr", "result1", &result1);
416    ATF_CHECK(atf_check_result_exited(&result1));
417    ATF_CHECK(atf_check_result_exitcode(&result1) == EXIT_SUCCESS);
418
419    do_exec_with_arg(tc, "stdout-stderr", "result2", &result2);
420    ATF_CHECK(atf_check_result_exited(&result2));
421    ATF_CHECK(atf_check_result_exitcode(&result2) == EXIT_SUCCESS);
422
423    out1 = atf_check_result_stdout(&result1);
424    out2 = atf_check_result_stdout(&result2);
425    err1 = atf_check_result_stderr(&result1);
426    err2 = atf_check_result_stderr(&result2);
427
428    ATF_CHECK(strstr(out1, "check.XXXXXX") == NULL);
429    ATF_CHECK(strstr(out2, "check.XXXXXX") == NULL);
430    ATF_CHECK(strstr(err1, "check.XXXXXX") == NULL);
431    ATF_CHECK(strstr(err2, "check.XXXXXX") == NULL);
432
433    ATF_CHECK(strstr(out1, "/check") != NULL);
434    ATF_CHECK(strstr(out2, "/check") != NULL);
435    ATF_CHECK(strstr(err1, "/check") != NULL);
436    ATF_CHECK(strstr(err2, "/check") != NULL);
437
438    ATF_CHECK(strstr(out1, "/stdout") != NULL);
439    ATF_CHECK(strstr(out2, "/stdout") != NULL);
440    ATF_CHECK(strstr(err1, "/stderr") != NULL);
441    ATF_CHECK(strstr(err2, "/stderr") != NULL);
442
443    ATF_CHECK(strcmp(out1, out2) != 0);
444    ATF_CHECK(strcmp(err1, err2) != 0);
445
446#define CHECK_LINES(path, outname, resname) \
447    do { \
448        int fd = open(path, O_RDONLY); \
449        ATF_CHECK(fd != -1); \
450        check_line(fd, "Line 1 to " outname " for " resname); \
451        check_line(fd, "Line 2 to " outname " for " resname); \
452        close(fd); \
453    } while (false)
454
455    CHECK_LINES(out1, "stdout", "result1");
456    CHECK_LINES(out2, "stdout", "result2");
457    CHECK_LINES(err1, "stderr", "result1");
458    CHECK_LINES(err2, "stderr", "result2");
459
460#undef CHECK_LINES
461
462    atf_check_result_fini(&result2);
463    atf_check_result_fini(&result1);
464}
465
466ATF_TC(exec_umask);
467ATF_TC_HEAD(exec_umask, tc)
468{
469    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
470                      "correctly reports an error if the umask is too "
471                      "restrictive to create temporary files");
472}
473ATF_TC_BODY(exec_umask, tc)
474{
475    atf_check_result_t result;
476    atf_fs_path_t process_helpers;
477    const char *argv[3];
478
479    get_process_helpers_path(tc, false, &process_helpers);
480    argv[0] = atf_fs_path_cstring(&process_helpers);
481    argv[1] = "exit-success";
482    argv[2] = NULL;
483
484    umask(0222);
485    atf_error_t err = atf_check_exec_array(argv, &result);
486    ATF_CHECK(atf_is_error(err));
487    ATF_CHECK(atf_error_is(err, "invalid_umask"));
488    atf_error_free(err);
489
490    atf_fs_path_fini(&process_helpers);
491}
492
493ATF_TC(exec_unknown);
494ATF_TC_HEAD(exec_unknown, tc)
495{
496    atf_tc_set_md_var(tc, "descr", "Checks that running a non-existing "
497                      "binary is handled correctly");
498}
499ATF_TC_BODY(exec_unknown, tc)
500{
501    char buf[1024];
502    snprintf(buf, sizeof(buf), "%s/non-existent",
503             atf_config_get("atf_workdir"));
504
505    const char *argv[2];
506    argv[0] = buf;
507    argv[1] = NULL;
508
509    atf_check_result_t result;
510    RE(atf_check_exec_array(argv, &result));
511    ATF_CHECK(atf_check_result_exited(&result));
512    ATF_CHECK(atf_check_result_exitcode(&result) == 127);
513    atf_check_result_fini(&result);
514}
515
516/* ---------------------------------------------------------------------
517 * Tests cases for the header file.
518 * --------------------------------------------------------------------- */
519
520HEADER_TC(include, "atf-c/check.h");
521
522/* ---------------------------------------------------------------------
523 * Main.
524 * --------------------------------------------------------------------- */
525
526ATF_TP_ADD_TCS(tp)
527{
528    /* Add the test cases for the free functions. */
529    ATF_TP_ADD_TC(tp, build_c_o);
530    ATF_TP_ADD_TC(tp, build_cpp);
531    ATF_TP_ADD_TC(tp, build_cxx_o);
532    ATF_TP_ADD_TC(tp, exec_array);
533    ATF_TP_ADD_TC(tp, exec_cleanup);
534    ATF_TP_ADD_TC(tp, exec_exitstatus);
535    ATF_TP_ADD_TC(tp, exec_stdout_stderr);
536    ATF_TP_ADD_TC(tp, exec_umask);
537    ATF_TP_ADD_TC(tp, exec_unknown);
538
539    /* Add the test cases for the header file. */
540    ATF_TP_ADD_TC(tp, include);
541
542    return atf_no_error();
543}
544