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
do_exec(const atf_tc_t * tc,const char * helper_name,atf_check_result_t * r)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
do_exec_with_arg(const atf_tc_t * tc,const char * helper_name,const char * arg,atf_check_result_t * r)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
check_line(int fd,const char * exp)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);
ATF_TC_HEAD(h_build_c_o_ok,tc)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 }
ATF_TC_BODY(h_build_c_o_ok,tc)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);
ATF_TC_HEAD(h_build_c_o_fail,tc)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 }
ATF_TC_BODY(h_build_c_o_fail,tc)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);
ATF_TC_HEAD(h_build_cpp_ok,tc)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 }
ATF_TC_BODY(h_build_cpp_ok,tc)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);
ATF_TC_HEAD(h_build_cpp_fail,tc)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 }
ATF_TC_BODY(h_build_cpp_fail,tc)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);
ATF_TC_HEAD(h_build_cxx_o_ok,tc)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 }
ATF_TC_BODY(h_build_cxx_o_ok,tc)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);
ATF_TC_HEAD(h_build_cxx_o_fail,tc)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 }
ATF_TC_BODY(h_build_cxx_o_fail,tc)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
init_and_run_h_tc(atf_tc_t * tc,const atf_tc_pack_t * tcpack,const char * outname,const char * errname)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);
ATF_TC_HEAD(build_c_o,tc)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 }
ATF_TC_BODY(build_c_o,tc)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);
ATF_TC_HEAD(build_cpp,tc)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 }
ATF_TC_BODY(build_cpp,tc)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);
ATF_TC_HEAD(build_cxx_o,tc)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 }
ATF_TC_BODY(build_cxx_o,tc)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);
ATF_TC_HEAD(exec_array,tc)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 }
ATF_TC_BODY(exec_array,tc)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);
ATF_TC_HEAD(exec_cleanup,tc)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 }
ATF_TC_BODY(exec_cleanup,tc)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);
ATF_TC_HEAD(exec_exitstatus,tc)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 }
ATF_TC_BODY(exec_exitstatus,tc)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);
ATF_TC_HEAD(exec_stdout_stderr,tc)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 }
ATF_TC_BODY(exec_stdout_stderr,tc)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);
ATF_TC_HEAD(exec_umask,tc)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 }
ATF_TC_BODY(exec_umask,tc)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);
ATF_TC_HEAD(exec_unknown,tc)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 }
ATF_TC_BODY(exec_unknown,tc)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
ATF_TP_ADD_TCS(tp)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