1// Copyright (c) 2007 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.hpp"
27
28extern "C" {
29#include <fcntl.h>
30#include <signal.h>
31#include <unistd.h>
32}
33
34#include <cstdlib>
35#include <cstring>
36#include <fstream>
37#include <iostream>
38#include <list>
39#include <memory>
40#include <vector>
41
42#include <atf-c++.hpp>
43
44#include "atf-c++/detail/fs.hpp"
45#include "atf-c++/detail/process.hpp"
46#include "atf-c++/detail/test_helpers.hpp"
47#include "atf-c++/detail/text.hpp"
48#include "atf-c++/utils.hpp"
49
50// ------------------------------------------------------------------------
51// Auxiliary functions.
52// ------------------------------------------------------------------------
53
54static
55std::auto_ptr< atf::check::check_result >
56do_exec(const atf::tests::tc* tc, const char* helper_name)
57{
58    std::vector< std::string > argv;
59    argv.push_back(get_process_helpers_path(*tc, false).str());
60    argv.push_back(helper_name);
61    std::cout << "Executing " << argv[0] << " " << argv[1] << "\n";
62
63    atf::process::argv_array argva(argv);
64    return atf::check::exec(argva);
65}
66
67static
68std::auto_ptr< atf::check::check_result >
69do_exec(const atf::tests::tc* tc, const char* helper_name, const char *carg2)
70{
71    std::vector< std::string > argv;
72    argv.push_back(get_process_helpers_path(*tc, false).str());
73    argv.push_back(helper_name);
74    argv.push_back(carg2);
75    std::cout << "Executing " << argv[0] << " " << argv[1] << " "
76              << argv[2] << "\n";
77
78    atf::process::argv_array argva(argv);
79    return atf::check::exec(argva);
80}
81
82// ------------------------------------------------------------------------
83// Helper test cases for the free functions.
84// ------------------------------------------------------------------------
85
86ATF_TEST_CASE(h_build_c_o_ok);
87ATF_TEST_CASE_HEAD(h_build_c_o_ok)
88{
89    set_md_var("descr", "Helper test case for build_c_o");
90}
91ATF_TEST_CASE_BODY(h_build_c_o_ok)
92{
93    std::ofstream sfile("test.c");
94    sfile << "#include <stdio.h>\n";
95    sfile.close();
96
97    ATF_REQUIRE(atf::check::build_c_o("test.c", "test.o",
98                                      atf::process::argv_array()));
99}
100
101ATF_TEST_CASE(h_build_c_o_fail);
102ATF_TEST_CASE_HEAD(h_build_c_o_fail)
103{
104    set_md_var("descr", "Helper test case for build_c_o");
105}
106ATF_TEST_CASE_BODY(h_build_c_o_fail)
107{
108    std::ofstream sfile("test.c");
109    sfile << "void foo(void) { int a = UNDEFINED_SYMBOL; }\n";
110    sfile.close();
111
112    ATF_REQUIRE(!atf::check::build_c_o("test.c", "test.o",
113                                       atf::process::argv_array()));
114}
115
116ATF_TEST_CASE(h_build_cpp_ok);
117ATF_TEST_CASE_HEAD(h_build_cpp_ok)
118{
119    set_md_var("descr", "Helper test case for build_cpp");
120}
121ATF_TEST_CASE_BODY(h_build_cpp_ok)
122{
123    std::ofstream sfile("test.c");
124    sfile << "#define A foo\n";
125    sfile << "#define B bar\n";
126    sfile << "A B\n";
127    sfile.close();
128
129    ATF_REQUIRE(atf::check::build_cpp("test.c", "test.p",
130                                      atf::process::argv_array()));
131}
132
133ATF_TEST_CASE(h_build_cpp_fail);
134ATF_TEST_CASE_HEAD(h_build_cpp_fail)
135{
136    set_md_var("descr", "Helper test case for build_cpp");
137}
138ATF_TEST_CASE_BODY(h_build_cpp_fail)
139{
140    std::ofstream sfile("test.c");
141    sfile << "#include \"./non-existent.h\"\n";
142    sfile.close();
143
144    ATF_REQUIRE(!atf::check::build_cpp("test.c", "test.p",
145                                       atf::process::argv_array()));
146}
147
148ATF_TEST_CASE(h_build_cxx_o_ok);
149ATF_TEST_CASE_HEAD(h_build_cxx_o_ok)
150{
151    set_md_var("descr", "Helper test case for build_cxx_o");
152}
153ATF_TEST_CASE_BODY(h_build_cxx_o_ok)
154{
155    std::ofstream sfile("test.cpp");
156    sfile << "#include <iostream>\n";
157    sfile.close();
158
159    ATF_REQUIRE(atf::check::build_cxx_o("test.cpp", "test.o",
160                                        atf::process::argv_array()));
161}
162
163ATF_TEST_CASE(h_build_cxx_o_fail);
164ATF_TEST_CASE_HEAD(h_build_cxx_o_fail)
165{
166    set_md_var("descr", "Helper test case for build_cxx_o");
167}
168ATF_TEST_CASE_BODY(h_build_cxx_o_fail)
169{
170    std::ofstream sfile("test.cpp");
171    sfile << "void foo(void) { int a = UNDEFINED_SYMBOL; }\n";
172    sfile.close();
173
174    ATF_REQUIRE(!atf::check::build_cxx_o("test.cpp", "test.o",
175                                         atf::process::argv_array()));
176}
177
178// ------------------------------------------------------------------------
179// Test cases for the free functions.
180// ------------------------------------------------------------------------
181
182ATF_TEST_CASE(build_c_o);
183ATF_TEST_CASE_HEAD(build_c_o)
184{
185    set_md_var("descr", "Tests the build_c_o function");
186}
187ATF_TEST_CASE_BODY(build_c_o)
188{
189    ATF_TEST_CASE_USE(h_build_c_o_ok);
190    run_h_tc< ATF_TEST_CASE_NAME(h_build_c_o_ok) >();
191    ATF_REQUIRE(atf::utils::grep_file("-o test.o", "stdout"));
192    ATF_REQUIRE(atf::utils::grep_file("-c test.c", "stdout"));
193
194    ATF_TEST_CASE_USE(h_build_c_o_fail);
195    run_h_tc< ATF_TEST_CASE_NAME(h_build_c_o_fail) >();
196    ATF_REQUIRE(atf::utils::grep_file("-o test.o", "stdout"));
197    ATF_REQUIRE(atf::utils::grep_file("-c test.c", "stdout"));
198    ATF_REQUIRE(atf::utils::grep_file("test.c", "stderr"));
199    ATF_REQUIRE(atf::utils::grep_file("UNDEFINED_SYMBOL", "stderr"));
200}
201
202ATF_TEST_CASE(build_cpp);
203ATF_TEST_CASE_HEAD(build_cpp)
204{
205    set_md_var("descr", "Tests the build_cpp function");
206}
207ATF_TEST_CASE_BODY(build_cpp)
208{
209    ATF_TEST_CASE_USE(h_build_cpp_ok);
210    run_h_tc< ATF_TEST_CASE_NAME(h_build_cpp_ok) >();
211    ATF_REQUIRE(atf::utils::grep_file("-o.*test.p", "stdout"));
212    ATF_REQUIRE(atf::utils::grep_file("test.c", "stdout"));
213    ATF_REQUIRE(atf::utils::grep_file("foo bar", "test.p"));
214
215    ATF_TEST_CASE_USE(h_build_cpp_fail);
216    run_h_tc< ATF_TEST_CASE_NAME(h_build_cpp_fail) >();
217    ATF_REQUIRE(atf::utils::grep_file("-o test.p", "stdout"));
218    ATF_REQUIRE(atf::utils::grep_file("test.c", "stdout"));
219    ATF_REQUIRE(atf::utils::grep_file("test.c", "stderr"));
220    ATF_REQUIRE(atf::utils::grep_file("non-existent.h", "stderr"));
221}
222
223ATF_TEST_CASE(build_cxx_o);
224ATF_TEST_CASE_HEAD(build_cxx_o)
225{
226    set_md_var("descr", "Tests the build_cxx_o function");
227}
228ATF_TEST_CASE_BODY(build_cxx_o)
229{
230    ATF_TEST_CASE_USE(h_build_cxx_o_ok);
231    run_h_tc< ATF_TEST_CASE_NAME(h_build_cxx_o_ok) >();
232    ATF_REQUIRE(atf::utils::grep_file("-o test.o", "stdout"));
233    ATF_REQUIRE(atf::utils::grep_file("-c test.cpp", "stdout"));
234
235    ATF_TEST_CASE_USE(h_build_cxx_o_fail);
236    run_h_tc< ATF_TEST_CASE_NAME(h_build_cxx_o_fail) >();
237    ATF_REQUIRE(atf::utils::grep_file("-o test.o", "stdout"));
238    ATF_REQUIRE(atf::utils::grep_file("-c test.cpp", "stdout"));
239    ATF_REQUIRE(atf::utils::grep_file("test.cpp", "stderr"));
240    ATF_REQUIRE(atf::utils::grep_file("UNDEFINED_SYMBOL", "stderr"));
241}
242
243ATF_TEST_CASE(exec_cleanup);
244ATF_TEST_CASE_HEAD(exec_cleanup)
245{
246    set_md_var("descr", "Tests that exec properly cleans up the temporary "
247               "files it creates");
248}
249ATF_TEST_CASE_BODY(exec_cleanup)
250{
251    std::auto_ptr< atf::fs::path > out;
252    std::auto_ptr< atf::fs::path > err;
253
254    {
255        std::auto_ptr< atf::check::check_result > r =
256            do_exec(this, "exit-success");
257        out.reset(new atf::fs::path(r->stdout_path()));
258        err.reset(new atf::fs::path(r->stderr_path()));
259        ATF_REQUIRE(atf::fs::exists(*out.get()));
260        ATF_REQUIRE(atf::fs::exists(*err.get()));
261    }
262    ATF_REQUIRE(!atf::fs::exists(*out.get()));
263    ATF_REQUIRE(!atf::fs::exists(*err.get()));
264}
265
266ATF_TEST_CASE(exec_exitstatus);
267ATF_TEST_CASE_HEAD(exec_exitstatus)
268{
269    set_md_var("descr", "Tests that exec properly captures the exit "
270               "status of the executed command");
271}
272ATF_TEST_CASE_BODY(exec_exitstatus)
273{
274    {
275        std::auto_ptr< atf::check::check_result > r =
276            do_exec(this, "exit-success");
277        ATF_REQUIRE(r->exited());
278        ATF_REQUIRE(!r->signaled());
279        ATF_REQUIRE_EQ(r->exitcode(), EXIT_SUCCESS);
280    }
281
282    {
283        std::auto_ptr< atf::check::check_result > r =
284            do_exec(this, "exit-failure");
285        ATF_REQUIRE(r->exited());
286        ATF_REQUIRE(!r->signaled());
287        ATF_REQUIRE_EQ(r->exitcode(), EXIT_FAILURE);
288    }
289
290    {
291        std::auto_ptr< atf::check::check_result > r =
292            do_exec(this, "exit-signal");
293        ATF_REQUIRE(!r->exited());
294        ATF_REQUIRE(r->signaled());
295        ATF_REQUIRE_EQ(r->termsig(), SIGKILL);
296    }
297}
298
299static
300void
301check_lines(const std::string& path, const char* outname,
302            const char* resname)
303{
304    std::ifstream f(path.c_str());
305    ATF_REQUIRE(f);
306
307    std::string line;
308    std::getline(f, line);
309    ATF_REQUIRE_EQ(line, std::string("Line 1 to ") + outname + " for " +
310                    resname);
311    std::getline(f, line);
312    ATF_REQUIRE_EQ(line, std::string("Line 2 to ") + outname + " for " +
313                    resname);
314}
315
316ATF_TEST_CASE(exec_stdout_stderr);
317ATF_TEST_CASE_HEAD(exec_stdout_stderr)
318{
319    set_md_var("descr", "Tests that exec properly captures the stdout "
320               "and stderr streams of the child process");
321}
322ATF_TEST_CASE_BODY(exec_stdout_stderr)
323{
324    std::auto_ptr< atf::check::check_result > r1 =
325        do_exec(this, "stdout-stderr", "result1");
326    ATF_REQUIRE(r1->exited());
327    ATF_REQUIRE_EQ(r1->exitcode(), EXIT_SUCCESS);
328
329    std::auto_ptr< atf::check::check_result > r2 =
330        do_exec(this, "stdout-stderr", "result2");
331    ATF_REQUIRE(r2->exited());
332    ATF_REQUIRE_EQ(r2->exitcode(), EXIT_SUCCESS);
333
334    const std::string out1 = r1->stdout_path();
335    const std::string out2 = r2->stdout_path();
336    const std::string err1 = r1->stderr_path();
337    const std::string err2 = r2->stderr_path();
338
339    ATF_REQUIRE(out1.find("check.XXXXXX") == std::string::npos);
340    ATF_REQUIRE(out2.find("check.XXXXXX") == std::string::npos);
341    ATF_REQUIRE(err1.find("check.XXXXXX") == std::string::npos);
342    ATF_REQUIRE(err2.find("check.XXXXXX") == std::string::npos);
343
344    ATF_REQUIRE(out1.find("/check") != std::string::npos);
345    ATF_REQUIRE(out2.find("/check") != std::string::npos);
346    ATF_REQUIRE(err1.find("/check") != std::string::npos);
347    ATF_REQUIRE(err2.find("/check") != std::string::npos);
348
349    ATF_REQUIRE(out1.find("/stdout") != std::string::npos);
350    ATF_REQUIRE(out2.find("/stdout") != std::string::npos);
351    ATF_REQUIRE(err1.find("/stderr") != std::string::npos);
352    ATF_REQUIRE(err2.find("/stderr") != std::string::npos);
353
354    ATF_REQUIRE(out1 != out2);
355    ATF_REQUIRE(err1 != err2);
356
357    check_lines(out1, "stdout", "result1");
358    check_lines(out2, "stdout", "result2");
359    check_lines(err1, "stderr", "result1");
360    check_lines(err2, "stderr", "result2");
361}
362
363ATF_TEST_CASE(exec_unknown);
364ATF_TEST_CASE_HEAD(exec_unknown)
365{
366    set_md_var("descr", "Tests that running a non-existing binary "
367               "is handled correctly");
368}
369ATF_TEST_CASE_BODY(exec_unknown)
370{
371    std::vector< std::string > argv;
372    argv.push_back("/foo/bar/non-existent");
373
374    atf::process::argv_array argva(argv);
375    std::auto_ptr< atf::check::check_result > r = atf::check::exec(argva);
376    ATF_REQUIRE(r->exited());
377    ATF_REQUIRE_EQ(r->exitcode(), 127);
378}
379
380// ------------------------------------------------------------------------
381// Main.
382// ------------------------------------------------------------------------
383
384ATF_INIT_TEST_CASES(tcs)
385{
386    // Add the test cases for the free functions.
387    ATF_ADD_TEST_CASE(tcs, build_c_o);
388    ATF_ADD_TEST_CASE(tcs, build_cpp);
389    ATF_ADD_TEST_CASE(tcs, build_cxx_o);
390    ATF_ADD_TEST_CASE(tcs, exec_cleanup);
391    ATF_ADD_TEST_CASE(tcs, exec_exitstatus);
392    ATF_ADD_TEST_CASE(tcs, exec_stdout_stderr);
393    ATF_ADD_TEST_CASE(tcs, exec_unknown);
394}
395