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 <cstdlib>
31#include <cstring>
32
33#include <atf-c++.hpp>
34
35#include "process.hpp"
36#include "test_helpers.hpp"
37
38// TODO: Testing the fork function is a huge task and I'm afraid of
39// copy/pasting tons of stuff from the C version.  I'd rather not do that
40// until some code can be shared, which cannot happen until the C++ binding
41// is cleaned by a fair amount.  Instead... just rely (at the moment) on
42// the system tests for the tools using this module.
43
44// ------------------------------------------------------------------------
45// Auxiliary functions.
46// ------------------------------------------------------------------------
47
48static
49std::size_t
50array_size(const char* const* array)
51{
52    std::size_t size = 0;
53
54    for (const char* const* ptr = array; *ptr != NULL; ptr++)
55        size++;
56
57    return size;
58}
59
60static
61tools::process::status
62exec_process_helpers(const atf::tests::tc& tc, const char* helper_name)
63{
64    using tools::process::exec;
65
66    const tools::fs::path helpers = tools::fs::path(tc.get_config_var("srcdir")) /
67        "process_helpers";
68
69    std::vector< std::string > argv;
70    argv.push_back(helpers.leaf_name());
71    argv.push_back(helper_name);
72
73    return exec(helpers,
74                tools::process::argv_array(argv),
75                tools::process::stream_inherit(),
76                tools::process::stream_inherit());
77}
78
79// ------------------------------------------------------------------------
80// Tests for the "argv_array" type.
81// ------------------------------------------------------------------------
82
83ATF_TEST_CASE(argv_array_init_carray);
84ATF_TEST_CASE_HEAD(argv_array_init_carray)
85{
86    set_md_var("descr", "Tests that argv_array is correctly constructed "
87               "from a C-style array of strings");
88}
89ATF_TEST_CASE_BODY(argv_array_init_carray)
90{
91    {
92        const char* const carray[] = { NULL };
93        tools::process::argv_array argv(carray);
94
95        ATF_REQUIRE_EQ(argv.size(), 0);
96    }
97
98    {
99        const char* const carray[] = { "arg0", NULL };
100        tools::process::argv_array argv(carray);
101
102        ATF_REQUIRE_EQ(argv.size(), 1);
103        ATF_REQUIRE(std::strcmp(argv[0], carray[0]) == 0);
104    }
105
106    {
107        const char* const carray[] = { "arg0", "arg1", "arg2", NULL };
108        tools::process::argv_array argv(carray);
109
110        ATF_REQUIRE_EQ(argv.size(), 3);
111        ATF_REQUIRE(std::strcmp(argv[0], carray[0]) == 0);
112        ATF_REQUIRE(std::strcmp(argv[1], carray[1]) == 0);
113        ATF_REQUIRE(std::strcmp(argv[2], carray[2]) == 0);
114    }
115}
116
117ATF_TEST_CASE(argv_array_init_col);
118ATF_TEST_CASE_HEAD(argv_array_init_col)
119{
120    set_md_var("descr", "Tests that argv_array is correctly constructed "
121               "from a string collection");
122}
123ATF_TEST_CASE_BODY(argv_array_init_col)
124{
125    {
126        std::vector< std::string > col;
127        tools::process::argv_array argv(col);
128
129        ATF_REQUIRE_EQ(argv.size(), 0);
130    }
131
132    {
133        std::vector< std::string > col;
134        col.push_back("arg0");
135        tools::process::argv_array argv(col);
136
137        ATF_REQUIRE_EQ(argv.size(), 1);
138        ATF_REQUIRE_EQ(argv[0], col[0]);
139    }
140
141    {
142        std::vector< std::string > col;
143        col.push_back("arg0");
144        col.push_back("arg1");
145        col.push_back("arg2");
146        tools::process::argv_array argv(col);
147
148        ATF_REQUIRE_EQ(argv.size(), 3);
149        ATF_REQUIRE_EQ(argv[0], col[0]);
150        ATF_REQUIRE_EQ(argv[1], col[1]);
151        ATF_REQUIRE_EQ(argv[2], col[2]);
152    }
153}
154
155ATF_TEST_CASE(argv_array_init_empty);
156ATF_TEST_CASE_HEAD(argv_array_init_empty)
157{
158    set_md_var("descr", "Tests that argv_array is correctly constructed "
159               "by the default constructor");
160}
161ATF_TEST_CASE_BODY(argv_array_init_empty)
162{
163    tools::process::argv_array argv;
164
165    ATF_REQUIRE_EQ(argv.size(), 0);
166}
167
168ATF_TEST_CASE(argv_array_init_varargs);
169ATF_TEST_CASE_HEAD(argv_array_init_varargs)
170{
171    set_md_var("descr", "Tests that argv_array is correctly constructed "
172               "from a variable list of arguments");
173}
174ATF_TEST_CASE_BODY(argv_array_init_varargs)
175{
176    {
177        tools::process::argv_array argv("arg0", NULL);
178
179        ATF_REQUIRE_EQ(argv.size(), 1);
180        ATF_REQUIRE_EQ(argv[0], std::string("arg0"));
181    }
182
183    {
184        tools::process::argv_array argv("arg0", "arg1", "arg2", NULL);
185
186        ATF_REQUIRE_EQ(argv.size(), 3);
187        ATF_REQUIRE_EQ(argv[0], std::string("arg0"));
188        ATF_REQUIRE_EQ(argv[1], std::string("arg1"));
189        ATF_REQUIRE_EQ(argv[2], std::string("arg2"));
190    }
191}
192
193ATF_TEST_CASE(argv_array_assign);
194ATF_TEST_CASE_HEAD(argv_array_assign)
195{
196    set_md_var("descr", "Tests that assigning an argv_array works");
197}
198ATF_TEST_CASE_BODY(argv_array_assign)
199{
200    using tools::process::argv_array;
201
202    const char* const carray1[] = { "arg1", NULL };
203    const char* const carray2[] = { "arg1", "arg2", NULL };
204
205    std::unique_ptr< argv_array > argv1(new argv_array(carray1));
206    std::unique_ptr< argv_array > argv2(new argv_array(carray2));
207
208    *argv2 = *argv1;
209    ATF_REQUIRE_EQ(argv2->size(), argv1->size());
210    ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0);
211
212    ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv());
213    argv1.release();
214    {
215        const char* const* eargv2 = argv2->exec_argv();
216        ATF_REQUIRE(std::strcmp(eargv2[0], carray1[0]) == 0);
217        ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL));
218    }
219
220    argv2.release();
221}
222
223ATF_TEST_CASE(argv_array_copy);
224ATF_TEST_CASE_HEAD(argv_array_copy)
225{
226    set_md_var("descr", "Tests that copying an argv_array constructed from "
227               "a C-style array of strings works");
228}
229ATF_TEST_CASE_BODY(argv_array_copy)
230{
231    using tools::process::argv_array;
232
233    const char* const carray[] = { "arg0", NULL };
234
235    std::unique_ptr< argv_array > argv1(new argv_array(carray));
236    std::unique_ptr< argv_array > argv2(new argv_array(*argv1));
237
238    ATF_REQUIRE_EQ(argv2->size(), argv1->size());
239    ATF_REQUIRE(std::strcmp((*argv2)[0], (*argv1)[0]) == 0);
240
241    ATF_REQUIRE(argv2->exec_argv() != argv1->exec_argv());
242    argv1.release();
243    {
244        const char* const* eargv2 = argv2->exec_argv();
245        ATF_REQUIRE(std::strcmp(eargv2[0], carray[0]) == 0);
246        ATF_REQUIRE_EQ(eargv2[1], static_cast< const char* >(NULL));
247    }
248
249    argv2.release();
250}
251
252ATF_TEST_CASE(argv_array_exec_argv);
253ATF_TEST_CASE_HEAD(argv_array_exec_argv)
254{
255    set_md_var("descr", "Tests that the exec argv provided by an argv_array "
256               "is correct");
257}
258ATF_TEST_CASE_BODY(argv_array_exec_argv)
259{
260    using tools::process::argv_array;
261
262    {
263        argv_array argv;
264        const char* const* eargv = argv.exec_argv();
265        ATF_REQUIRE_EQ(array_size(eargv), 0);
266        ATF_REQUIRE_EQ(eargv[0], static_cast< const char* >(NULL));
267    }
268
269    {
270        const char* const carray[] = { "arg0", NULL };
271        argv_array argv(carray);
272        const char* const* eargv = argv.exec_argv();
273        ATF_REQUIRE_EQ(array_size(eargv), 1);
274        ATF_REQUIRE(std::strcmp(eargv[0], "arg0") == 0);
275        ATF_REQUIRE_EQ(eargv[1], static_cast< const char* >(NULL));
276    }
277
278    {
279        std::vector< std::string > col;
280        col.push_back("arg0");
281        argv_array argv(col);
282        const char* const* eargv = argv.exec_argv();
283        ATF_REQUIRE_EQ(array_size(eargv), 1);
284        ATF_REQUIRE(std::strcmp(eargv[0], "arg0") == 0);
285        ATF_REQUIRE_EQ(eargv[1], static_cast< const char* >(NULL));
286    }
287}
288
289ATF_TEST_CASE(argv_array_iter);
290ATF_TEST_CASE_HEAD(argv_array_iter)
291{
292    set_md_var("descr", "Tests that an argv_array can be iterated");
293}
294ATF_TEST_CASE_BODY(argv_array_iter)
295{
296    using tools::process::argv_array;
297
298    std::vector< std::string > vector;
299    vector.push_back("arg0");
300    vector.push_back("arg1");
301    vector.push_back("arg2");
302
303    argv_array argv(vector);
304    ATF_REQUIRE_EQ(argv.size(), 3);
305    std::vector< std::string >::size_type pos = 0;
306    for (argv_array::const_iterator iter = argv.begin(); iter != argv.end();
307         iter++) {
308        ATF_REQUIRE_EQ(*iter, vector[pos]);
309        pos++;
310    }
311}
312
313// ------------------------------------------------------------------------
314// Tests cases for the free functions.
315// ------------------------------------------------------------------------
316
317ATF_TEST_CASE(exec_failure);
318ATF_TEST_CASE_HEAD(exec_failure)
319{
320    set_md_var("descr", "Tests execing a command that reports failure");
321}
322ATF_TEST_CASE_BODY(exec_failure)
323{
324    const tools::process::status s = exec_process_helpers(*this, "exit-failure");
325    ATF_REQUIRE(s.exited());
326    ATF_REQUIRE_EQ(s.exitstatus(), EXIT_FAILURE);
327}
328
329ATF_TEST_CASE(exec_success);
330ATF_TEST_CASE_HEAD(exec_success)
331{
332    set_md_var("descr", "Tests execing a command that reports success");
333}
334ATF_TEST_CASE_BODY(exec_success)
335{
336    const tools::process::status s = exec_process_helpers(*this, "exit-success");
337    ATF_REQUIRE(s.exited());
338    ATF_REQUIRE_EQ(s.exitstatus(), EXIT_SUCCESS);
339}
340
341// ------------------------------------------------------------------------
342// Main.
343// ------------------------------------------------------------------------
344
345ATF_INIT_TEST_CASES(tcs)
346{
347    // Add the test cases for the "argv_array" type.
348    ATF_ADD_TEST_CASE(tcs, argv_array_assign);
349    ATF_ADD_TEST_CASE(tcs, argv_array_copy);
350    ATF_ADD_TEST_CASE(tcs, argv_array_exec_argv);
351    ATF_ADD_TEST_CASE(tcs, argv_array_init_carray);
352    ATF_ADD_TEST_CASE(tcs, argv_array_init_col);
353    ATF_ADD_TEST_CASE(tcs, argv_array_init_empty);
354    ATF_ADD_TEST_CASE(tcs, argv_array_init_varargs);
355    ATF_ADD_TEST_CASE(tcs, argv_array_iter);
356
357    // Add the test cases for the free functions.
358    ATF_ADD_TEST_CASE(tcs, exec_failure);
359    ATF_ADD_TEST_CASE(tcs, exec_success);
360}
361