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