xref: /freebsd/contrib/atf/atf-c/check_test.c (revision af23369a6deaaeb612ab266eb88b8bb8d560c322)
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 
46 static
47 void
48 do_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 
64 static
65 void
66 do_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 
84 static
85 void
86 check_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 
98 ATF_TC(h_build_c_o_ok);
99 ATF_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 }
103 ATF_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 
116 ATF_TC(h_build_c_o_fail);
117 ATF_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 }
121 ATF_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 
134 ATF_TC(h_build_cpp_ok);
135 ATF_TC_HEAD(h_build_cpp_ok, tc)
136 {
137     atf_tc_set_md_var(tc, "descr", "Helper test case for build_cpp");
138 }
139 ATF_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 
160 ATF_TC(h_build_cpp_fail);
161 ATF_TC_HEAD(h_build_cpp_fail, tc)
162 {
163     atf_tc_set_md_var(tc, "descr", "Helper test case for build_cpp");
164 }
165 ATF_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 
178 ATF_TC(h_build_cxx_o_ok);
179 ATF_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 }
183 ATF_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 
196 ATF_TC(h_build_cxx_o_fail);
197 ATF_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 }
201 ATF_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 
218 static
219 void
220 init_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 
230 ATF_TC(build_c_o);
231 ATF_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 }
236 ATF_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 
251 ATF_TC(build_cpp);
252 ATF_TC_HEAD(build_cpp, tc)
253 {
254     atf_tc_set_md_var(tc, "descr", "Checks the atf_check_build_cpp "
255                       "function");
256 }
257 ATF_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 
273 ATF_TC(build_cxx_o);
274 ATF_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 }
279 ATF_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 
294 ATF_TC(exec_array);
295 ATF_TC_HEAD(exec_array, tc)
296 {
297     atf_tc_set_md_var(tc, "descr", "Checks that atf_check_exec_array "
298                       "works properly");
299 }
300 ATF_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 
330 ATF_TC(exec_cleanup);
331 ATF_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 }
336 ATF_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 
356 ATF_TC(exec_exitstatus);
357 ATF_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 }
363 ATF_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 
393 ATF_TC(exec_stdout_stderr);
394 ATF_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 }
400 ATF_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 
457 ATF_TC(exec_umask);
458 ATF_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 }
464 ATF_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 
484 ATF_TC(exec_unknown);
485 ATF_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 }
490 ATF_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 
507 ATF_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