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