check_test.c revision 275988
1/* Copyright (c) 2008 The NetBSD Foundation, Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  */
25
26#include "atf-c/check.h"
27
28#include <fcntl.h>
29#include <signal.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35#include <atf-c.h>
36
37#include "atf-c/detail/fs.h"
38#include "atf-c/detail/map.h"
39#include "atf-c/detail/process.h"
40#include "atf-c/detail/test_helpers.h"
41
42/* ---------------------------------------------------------------------
43 * Auxiliary functions.
44 * --------------------------------------------------------------------- */
45
46static
47void
48do_exec(const atf_tc_t *tc, const char *helper_name, atf_check_result_t *r)
49{
50    atf_fs_path_t process_helpers;
51    const char *argv[3];
52
53    get_process_helpers_path(tc, false, &process_helpers);
54
55    argv[0] = atf_fs_path_cstring(&process_helpers);
56    argv[1] = helper_name;
57    argv[2] = NULL;
58    printf("Executing %s %s\n", argv[0], argv[1]);
59    RE(atf_check_exec_array(argv, r));
60
61    atf_fs_path_fini(&process_helpers);
62}
63
64static
65void
66do_exec_with_arg(const atf_tc_t *tc, const char *helper_name, const char *arg,
67                 atf_check_result_t *r)
68{
69    atf_fs_path_t process_helpers;
70    const char *argv[4];
71
72    get_process_helpers_path(tc, false, &process_helpers);
73
74    argv[0] = atf_fs_path_cstring(&process_helpers);
75    argv[1] = helper_name;
76    argv[2] = arg;
77    argv[3] = NULL;
78    printf("Executing %s %s %s\n", argv[0], argv[1], argv[2]);
79    RE(atf_check_exec_array(argv, r));
80
81    atf_fs_path_fini(&process_helpers);
82}
83
84static
85void
86check_line(int fd, const char *exp)
87{
88    char *line = atf_utils_readline(fd);
89    ATF_CHECK(line != NULL);
90    ATF_CHECK_STREQ_MSG(exp, line, "read: '%s', expected: '%s'", line, exp);
91    free(line);
92}
93
94/* ---------------------------------------------------------------------
95 * Helper test cases for the free functions.
96 * --------------------------------------------------------------------- */
97
98ATF_TC(h_build_c_o_ok);
99ATF_TC_HEAD(h_build_c_o_ok, tc)
100{
101    atf_tc_set_md_var(tc, "descr", "Helper test case for build_c_o");
102}
103ATF_TC_BODY(h_build_c_o_ok, tc)
104{
105    FILE *sfile;
106    bool success;
107
108    ATF_REQUIRE((sfile = fopen("test.c", "w")) != NULL);
109    fprintf(sfile, "#include <stdio.h>\n");
110    fclose(sfile);
111
112    RE(atf_check_build_c_o("test.c", "test.o", NULL, &success));
113    ATF_REQUIRE(success);
114}
115
116ATF_TC(h_build_c_o_fail);
117ATF_TC_HEAD(h_build_c_o_fail, tc)
118{
119    atf_tc_set_md_var(tc, "descr", "Helper test case for build_c_o");
120}
121ATF_TC_BODY(h_build_c_o_fail, tc)
122{
123    FILE *sfile;
124    bool success;
125
126    ATF_REQUIRE((sfile = fopen("test.c", "w")) != NULL);
127    fprintf(sfile, "void foo(void) { int a = UNDEFINED_SYMBOL; }\n");
128    fclose(sfile);
129
130    RE(atf_check_build_c_o("test.c", "test.o", NULL, &success));
131    ATF_REQUIRE(!success);
132}
133
134ATF_TC(h_build_cpp_ok);
135ATF_TC_HEAD(h_build_cpp_ok, tc)
136{
137    atf_tc_set_md_var(tc, "descr", "Helper test case for build_cpp");
138}
139ATF_TC_BODY(h_build_cpp_ok, tc)
140{
141    FILE *sfile;
142    bool success;
143    atf_fs_path_t test_p;
144
145    RE(atf_fs_path_init_fmt(&test_p, "test.p"));
146
147    ATF_REQUIRE((sfile = fopen("test.c", "w")) != NULL);
148    fprintf(sfile, "#define A foo\n");
149    fprintf(sfile, "#define B bar\n");
150    fprintf(sfile, "A B\n");
151    fclose(sfile);
152
153    RE(atf_check_build_cpp("test.c", atf_fs_path_cstring(&test_p), NULL,
154                           &success));
155    ATF_REQUIRE(success);
156
157    atf_fs_path_fini(&test_p);
158}
159
160ATF_TC(h_build_cpp_fail);
161ATF_TC_HEAD(h_build_cpp_fail, tc)
162{
163    atf_tc_set_md_var(tc, "descr", "Helper test case for build_cpp");
164}
165ATF_TC_BODY(h_build_cpp_fail, tc)
166{
167    FILE *sfile;
168    bool success;
169
170    ATF_REQUIRE((sfile = fopen("test.c", "w")) != NULL);
171    fprintf(sfile, "#include \"./non-existent.h\"\n");
172    fclose(sfile);
173
174    RE(atf_check_build_cpp("test.c", "test.p", NULL, &success));
175    ATF_REQUIRE(!success);
176}
177
178ATF_TC(h_build_cxx_o_ok);
179ATF_TC_HEAD(h_build_cxx_o_ok, tc)
180{
181    atf_tc_set_md_var(tc, "descr", "Helper test case for build_cxx_o");
182}
183ATF_TC_BODY(h_build_cxx_o_ok, tc)
184{
185    FILE *sfile;
186    bool success;
187
188    ATF_REQUIRE((sfile = fopen("test.cpp", "w")) != NULL);
189    fprintf(sfile, "#include <iostream>\n");
190    fclose(sfile);
191
192    RE(atf_check_build_cxx_o("test.cpp", "test.o", NULL, &success));
193    ATF_REQUIRE(success);
194}
195
196ATF_TC(h_build_cxx_o_fail);
197ATF_TC_HEAD(h_build_cxx_o_fail, tc)
198{
199    atf_tc_set_md_var(tc, "descr", "Helper test case for build_cxx_o");
200}
201ATF_TC_BODY(h_build_cxx_o_fail, tc)
202{
203    FILE *sfile;
204    bool success;
205
206    ATF_REQUIRE((sfile = fopen("test.cpp", "w")) != NULL);
207    fprintf(sfile, "void foo(void) { int a = UNDEFINED_SYMBOL; }\n");
208    fclose(sfile);
209
210    RE(atf_check_build_cxx_o("test.cpp", "test.o", NULL, &success));
211    ATF_REQUIRE(!success);
212}
213
214/* ---------------------------------------------------------------------
215 * Test cases for the free functions.
216 * --------------------------------------------------------------------- */
217
218static
219void
220init_and_run_h_tc(atf_tc_t *tc, const atf_tc_pack_t *tcpack,
221                  const char *outname, const char *errname)
222{
223    const char *const config[] = { NULL };
224
225    RE(atf_tc_init_pack(tc, tcpack, config));
226    run_h_tc(tc, outname, errname, "result");
227    atf_tc_fini(tc);
228}
229
230ATF_TC(build_c_o);
231ATF_TC_HEAD(build_c_o, tc)
232{
233    atf_tc_set_md_var(tc, "descr", "Checks the atf_check_build_c_o "
234                      "function");
235}
236ATF_TC_BODY(build_c_o, tc)
237{
238    init_and_run_h_tc(&ATF_TC_NAME(h_build_c_o_ok),
239             &ATF_TC_PACK_NAME(h_build_c_o_ok), "stdout", "stderr");
240    ATF_CHECK(atf_utils_grep_file("-o test.o", "stdout"));
241    ATF_CHECK(atf_utils_grep_file("-c test.c", "stdout"));
242
243    init_and_run_h_tc(&ATF_TC_NAME(h_build_c_o_fail),
244             &ATF_TC_PACK_NAME(h_build_c_o_fail), "stdout", "stderr");
245    ATF_CHECK(atf_utils_grep_file("-o test.o", "stdout"));
246    ATF_CHECK(atf_utils_grep_file("-c test.c", "stdout"));
247    ATF_CHECK(atf_utils_grep_file("test.c", "stderr"));
248    ATF_CHECK(atf_utils_grep_file("UNDEFINED_SYMBOL", "stderr"));
249}
250
251ATF_TC(build_cpp);
252ATF_TC_HEAD(build_cpp, tc)
253{
254    atf_tc_set_md_var(tc, "descr", "Checks the atf_check_build_cpp "
255                      "function");
256}
257ATF_TC_BODY(build_cpp, tc)
258{
259    init_and_run_h_tc(&ATF_TC_NAME(h_build_cpp_ok),
260             &ATF_TC_PACK_NAME(h_build_cpp_ok), "stdout", "stderr");
261    ATF_CHECK(atf_utils_grep_file("-o.*test.p", "stdout"));
262    ATF_CHECK(atf_utils_grep_file("test.c", "stdout"));
263    ATF_CHECK(atf_utils_grep_file("foo bar", "test.p"));
264
265    init_and_run_h_tc(&ATF_TC_NAME(h_build_cpp_fail),
266             &ATF_TC_PACK_NAME(h_build_cpp_fail), "stdout", "stderr");
267    ATF_CHECK(atf_utils_grep_file("-o test.p", "stdout"));
268    ATF_CHECK(atf_utils_grep_file("test.c", "stdout"));
269    ATF_CHECK(atf_utils_grep_file("test.c", "stderr"));
270    ATF_CHECK(atf_utils_grep_file("non-existent.h", "stderr"));
271}
272
273ATF_TC(build_cxx_o);
274ATF_TC_HEAD(build_cxx_o, tc)
275{
276    atf_tc_set_md_var(tc, "descr", "Checks the atf_check_build_cxx_o "
277                      "function");
278}
279ATF_TC_BODY(build_cxx_o, tc)
280{
281    init_and_run_h_tc(&ATF_TC_NAME(h_build_cxx_o_ok),
282             &ATF_TC_PACK_NAME(h_build_cxx_o_ok), "stdout", "stderr");
283    ATF_CHECK(atf_utils_grep_file("-o test.o", "stdout"));
284    ATF_CHECK(atf_utils_grep_file("-c test.cpp", "stdout"));
285
286    init_and_run_h_tc(&ATF_TC_NAME(h_build_cxx_o_fail),
287             &ATF_TC_PACK_NAME(h_build_cxx_o_fail), "stdout", "stderr");
288    ATF_CHECK(atf_utils_grep_file("-o test.o", "stdout"));
289    ATF_CHECK(atf_utils_grep_file("-c test.cpp", "stdout"));
290    ATF_CHECK(atf_utils_grep_file("test.cpp", "stderr"));
291    ATF_CHECK(atf_utils_grep_file("UNDEFINED_SYMBOL", "stderr"));
292}
293
294ATF_TC(exec_array);
295ATF_TC_HEAD(exec_array, tc)
296{
297    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
298                      "works properly");
299}
300ATF_TC_BODY(exec_array, tc)
301{
302    atf_fs_path_t process_helpers;
303    atf_check_result_t result;
304
305    get_process_helpers_path(tc, false, &process_helpers);
306
307    const char *argv[4];
308    argv[0] = atf_fs_path_cstring(&process_helpers);
309    argv[1] = "echo";
310    argv[2] = "test-message";
311    argv[3] = NULL;
312
313    RE(atf_check_exec_array(argv, &result));
314
315    ATF_CHECK(atf_check_result_exited(&result));
316    ATF_CHECK(atf_check_result_exitcode(&result) == EXIT_SUCCESS);
317
318    {
319        const char *path = atf_check_result_stdout(&result);
320        int fd = open(path, O_RDONLY);
321        ATF_CHECK(fd != -1);
322        check_line(fd, "test-message");
323        close(fd);
324    }
325
326    atf_check_result_fini(&result);
327    atf_fs_path_fini(&process_helpers);
328}
329
330ATF_TC(exec_cleanup);
331ATF_TC_HEAD(exec_cleanup, tc)
332{
333    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
334                      "properly cleans up the temporary files it creates");
335}
336ATF_TC_BODY(exec_cleanup, tc)
337{
338    atf_fs_path_t out, err;
339    atf_check_result_t result;
340    bool exists;
341
342    do_exec(tc, "exit-success", &result);
343    RE(atf_fs_path_init_fmt(&out, "%s", atf_check_result_stdout(&result)));
344    RE(atf_fs_path_init_fmt(&err, "%s", atf_check_result_stderr(&result)));
345
346    RE(atf_fs_exists(&out, &exists)); ATF_CHECK(exists);
347    RE(atf_fs_exists(&err, &exists)); ATF_CHECK(exists);
348    atf_check_result_fini(&result);
349    RE(atf_fs_exists(&out, &exists)); ATF_CHECK(!exists);
350    RE(atf_fs_exists(&err, &exists)); ATF_CHECK(!exists);
351
352    atf_fs_path_fini(&err);
353    atf_fs_path_fini(&out);
354}
355
356ATF_TC(exec_exitstatus);
357ATF_TC_HEAD(exec_exitstatus, tc)
358{
359    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
360                      "properly captures the exit status of the executed "
361                      "command");
362}
363ATF_TC_BODY(exec_exitstatus, tc)
364{
365    {
366        atf_check_result_t result;
367        do_exec(tc, "exit-success", &result);
368        ATF_CHECK(atf_check_result_exited(&result));
369        ATF_CHECK(!atf_check_result_signaled(&result));
370        ATF_CHECK(atf_check_result_exitcode(&result) == EXIT_SUCCESS);
371        atf_check_result_fini(&result);
372    }
373
374    {
375        atf_check_result_t result;
376        do_exec(tc, "exit-failure", &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_FAILURE);
380        atf_check_result_fini(&result);
381    }
382
383    {
384        atf_check_result_t result;
385        do_exec(tc, "exit-signal", &result);
386        ATF_CHECK(!atf_check_result_exited(&result));
387        ATF_CHECK(atf_check_result_signaled(&result));
388        ATF_CHECK(atf_check_result_termsig(&result) == SIGKILL);
389        atf_check_result_fini(&result);
390    }
391}
392
393ATF_TC(exec_stdout_stderr);
394ATF_TC_HEAD(exec_stdout_stderr, tc)
395{
396    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
397                      "properly captures the stdout and stderr streams "
398                      "of the child process");
399}
400ATF_TC_BODY(exec_stdout_stderr, tc)
401{
402    atf_check_result_t result1, result2;
403    const char *out1, *out2;
404    const char *err1, *err2;
405
406    do_exec_with_arg(tc, "stdout-stderr", "result1", &result1);
407    ATF_CHECK(atf_check_result_exited(&result1));
408    ATF_CHECK(atf_check_result_exitcode(&result1) == EXIT_SUCCESS);
409
410    do_exec_with_arg(tc, "stdout-stderr", "result2", &result2);
411    ATF_CHECK(atf_check_result_exited(&result2));
412    ATF_CHECK(atf_check_result_exitcode(&result2) == EXIT_SUCCESS);
413
414    out1 = atf_check_result_stdout(&result1);
415    out2 = atf_check_result_stdout(&result2);
416    err1 = atf_check_result_stderr(&result1);
417    err2 = atf_check_result_stderr(&result2);
418
419    ATF_CHECK(strstr(out1, "check.XXXXXX") == NULL);
420    ATF_CHECK(strstr(out2, "check.XXXXXX") == NULL);
421    ATF_CHECK(strstr(err1, "check.XXXXXX") == NULL);
422    ATF_CHECK(strstr(err2, "check.XXXXXX") == NULL);
423
424    ATF_CHECK(strstr(out1, "/check") != NULL);
425    ATF_CHECK(strstr(out2, "/check") != NULL);
426    ATF_CHECK(strstr(err1, "/check") != NULL);
427    ATF_CHECK(strstr(err2, "/check") != NULL);
428
429    ATF_CHECK(strstr(out1, "/stdout") != NULL);
430    ATF_CHECK(strstr(out2, "/stdout") != NULL);
431    ATF_CHECK(strstr(err1, "/stderr") != NULL);
432    ATF_CHECK(strstr(err2, "/stderr") != NULL);
433
434    ATF_CHECK(strcmp(out1, out2) != 0);
435    ATF_CHECK(strcmp(err1, err2) != 0);
436
437#define CHECK_LINES(path, outname, resname) \
438    do { \
439        int fd = open(path, O_RDONLY); \
440        ATF_CHECK(fd != -1); \
441        check_line(fd, "Line 1 to " outname " for " resname); \
442        check_line(fd, "Line 2 to " outname " for " resname); \
443        close(fd); \
444    } while (false)
445
446    CHECK_LINES(out1, "stdout", "result1");
447    CHECK_LINES(out2, "stdout", "result2");
448    CHECK_LINES(err1, "stderr", "result1");
449    CHECK_LINES(err2, "stderr", "result2");
450
451#undef CHECK_LINES
452
453    atf_check_result_fini(&result2);
454    atf_check_result_fini(&result1);
455}
456
457ATF_TC(exec_umask);
458ATF_TC_HEAD(exec_umask, tc)
459{
460    atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
461                      "correctly reports an error if the umask is too "
462                      "restrictive to create temporary files");
463}
464ATF_TC_BODY(exec_umask, tc)
465{
466    atf_check_result_t result;
467    atf_fs_path_t process_helpers;
468    const char *argv[3];
469
470    get_process_helpers_path(tc, false, &process_helpers);
471    argv[0] = atf_fs_path_cstring(&process_helpers);
472    argv[1] = "exit-success";
473    argv[2] = NULL;
474
475    umask(0222);
476    atf_error_t err = atf_check_exec_array(argv, &result);
477    ATF_CHECK(atf_is_error(err));
478    ATF_CHECK(atf_error_is(err, "invalid_umask"));
479    atf_error_free(err);
480
481    atf_fs_path_fini(&process_helpers);
482}
483
484ATF_TC(exec_unknown);
485ATF_TC_HEAD(exec_unknown, tc)
486{
487    atf_tc_set_md_var(tc, "descr", "Checks that running a non-existing "
488                      "binary is handled correctly");
489}
490ATF_TC_BODY(exec_unknown, tc)
491{
492    const char *argv[2];
493    argv[0] = "/foo/bar/non-existent";
494    argv[1] = NULL;
495
496    atf_check_result_t result;
497    RE(atf_check_exec_array(argv, &result));
498    ATF_CHECK(atf_check_result_exited(&result));
499    ATF_CHECK(atf_check_result_exitcode(&result) == 127);
500    atf_check_result_fini(&result);
501}
502
503/* ---------------------------------------------------------------------
504 * Main.
505 * --------------------------------------------------------------------- */
506
507ATF_TP_ADD_TCS(tp)
508{
509    /* Add the test cases for the free functions. */
510    ATF_TP_ADD_TC(tp, build_c_o);
511    ATF_TP_ADD_TC(tp, build_cpp);
512    ATF_TP_ADD_TC(tp, build_cxx_o);
513    ATF_TP_ADD_TC(tp, exec_array);
514    ATF_TP_ADD_TC(tp, exec_cleanup);
515    ATF_TP_ADD_TC(tp, exec_exitstatus);
516    ATF_TP_ADD_TC(tp, exec_stdout_stderr);
517    ATF_TP_ADD_TC(tp, exec_umask);
518    ATF_TP_ADD_TC(tp, exec_unknown);
519
520    return atf_no_error();
521}
522