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