xref: /freebsd/contrib/atf/atf-c++/utils_test.cpp (revision 8eb2bee6c0f4957c6c1cea826e59cda4d18a2a64)
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++/utils.hpp"
27 
28 extern "C" {
29 #include <sys/stat.h>
30 #include <sys/wait.h>
31 
32 #include <fcntl.h>
33 #include <unistd.h>
34 }
35 
36 #include <cstdlib>
37 #include <iostream>
38 #include <set>
39 #include <sstream>
40 #include <string>
41 #include <vector>
42 
43 #include <atf-c++.hpp>
44 
45 static std::string
46 read_file(const std::string& path)
47 {
48     char buffer[1024];
49 
50     const int fd = open(path.c_str(), O_RDONLY);
51     if (fd == -1)
52         ATF_FAIL("Cannot open " + path);
53     const ssize_t length = read(fd, buffer, sizeof(buffer) - 1);
54     close(fd);
55     ATF_REQUIRE(length != -1);
56     if (length == sizeof(buffer) - 1)
57         ATF_FAIL("Internal buffer not long enough to read temporary file");
58     ((char *)buffer)[length] = '\0';
59 
60     return buffer;
61 }
62 
63 // ------------------------------------------------------------------------
64 // Tests cases for the free functions.
65 // ------------------------------------------------------------------------
66 
67 ATF_TEST_CASE_WITHOUT_HEAD(cat_file__empty);
68 ATF_TEST_CASE_BODY(cat_file__empty)
69 {
70     atf::utils::create_file("file.txt", "");
71     atf::utils::redirect(STDOUT_FILENO, "captured.txt");
72     atf::utils::cat_file("file.txt", "PREFIX");
73     std::cout.flush();
74     close(STDOUT_FILENO);
75 
76     ATF_REQUIRE_EQ("", read_file("captured.txt"));
77 }
78 
79 ATF_TEST_CASE_WITHOUT_HEAD(cat_file__one_line);
80 ATF_TEST_CASE_BODY(cat_file__one_line)
81 {
82     atf::utils::create_file("file.txt", "This is a single line\n");
83     atf::utils::redirect(STDOUT_FILENO, "captured.txt");
84     atf::utils::cat_file("file.txt", "PREFIX");
85     std::cout.flush();
86     close(STDOUT_FILENO);
87 
88     ATF_REQUIRE_EQ("PREFIXThis is a single line\n", read_file("captured.txt"));
89 }
90 
91 ATF_TEST_CASE_WITHOUT_HEAD(cat_file__several_lines);
92 ATF_TEST_CASE_BODY(cat_file__several_lines)
93 {
94     atf::utils::create_file("file.txt", "First\nSecond line\nAnd third\n");
95     atf::utils::redirect(STDOUT_FILENO, "captured.txt");
96     atf::utils::cat_file("file.txt", ">");
97     std::cout.flush();
98     close(STDOUT_FILENO);
99 
100     ATF_REQUIRE_EQ(">First\n>Second line\n>And third\n",
101                    read_file("captured.txt"));
102 }
103 
104 ATF_TEST_CASE_WITHOUT_HEAD(cat_file__no_newline_eof);
105 ATF_TEST_CASE_BODY(cat_file__no_newline_eof)
106 {
107     atf::utils::create_file("file.txt", "Foo\n bar baz");
108     atf::utils::redirect(STDOUT_FILENO, "captured.txt");
109     atf::utils::cat_file("file.txt", "PREFIX");
110     std::cout.flush();
111     close(STDOUT_FILENO);
112 
113     ATF_REQUIRE_EQ("PREFIXFoo\nPREFIX bar baz", read_file("captured.txt"));
114 }
115 
116 ATF_TEST_CASE_WITHOUT_HEAD(compare_file__empty__match);
117 ATF_TEST_CASE_BODY(compare_file__empty__match)
118 {
119     atf::utils::create_file("test.txt", "");
120     ATF_REQUIRE(atf::utils::compare_file("test.txt", ""));
121 }
122 
123 ATF_TEST_CASE_WITHOUT_HEAD(compare_file__empty__not_match);
124 ATF_TEST_CASE_BODY(compare_file__empty__not_match)
125 {
126     atf::utils::create_file("test.txt", "");
127     ATF_REQUIRE(!atf::utils::compare_file("test.txt", "\n"));
128     ATF_REQUIRE(!atf::utils::compare_file("test.txt", "foo"));
129     ATF_REQUIRE(!atf::utils::compare_file("test.txt", " "));
130 }
131 
132 ATF_TEST_CASE_WITHOUT_HEAD(compare_file__short__match);
133 ATF_TEST_CASE_BODY(compare_file__short__match)
134 {
135     atf::utils::create_file("test.txt", "this is a short file");
136     ATF_REQUIRE(atf::utils::compare_file("test.txt", "this is a short file"));
137 }
138 
139 ATF_TEST_CASE_WITHOUT_HEAD(compare_file__short__not_match);
140 ATF_TEST_CASE_BODY(compare_file__short__not_match)
141 {
142     atf::utils::create_file("test.txt", "this is a short file");
143     ATF_REQUIRE(!atf::utils::compare_file("test.txt", ""));
144     ATF_REQUIRE(!atf::utils::compare_file("test.txt", "\n"));
145     ATF_REQUIRE(!atf::utils::compare_file("test.txt", "this is a Short file"));
146     ATF_REQUIRE(!atf::utils::compare_file("test.txt", "this is a short fil"));
147     ATF_REQUIRE(!atf::utils::compare_file("test.txt", "this is a short file "));
148 }
149 
150 ATF_TEST_CASE_WITHOUT_HEAD(compare_file__long__match);
151 ATF_TEST_CASE_BODY(compare_file__long__match)
152 {
153     char long_contents[3456];
154     size_t i = 0;
155     for (; i < sizeof(long_contents) - 1; i++)
156         long_contents[i] = '0' + (i % 10);
157     long_contents[i] = '\0';
158     atf::utils::create_file("test.txt", long_contents);
159 
160     ATF_REQUIRE(atf::utils::compare_file("test.txt", long_contents));
161 }
162 
163 ATF_TEST_CASE_WITHOUT_HEAD(compare_file__long__not_match);
164 ATF_TEST_CASE_BODY(compare_file__long__not_match)
165 {
166     char long_contents[3456];
167     size_t i = 0;
168     for (; i < sizeof(long_contents) - 1; i++)
169         long_contents[i] = '0' + (i % 10);
170     long_contents[i] = '\0';
171     atf::utils::create_file("test.txt", long_contents);
172 
173     ATF_REQUIRE(!atf::utils::compare_file("test.txt", ""));
174     ATF_REQUIRE(!atf::utils::compare_file("test.txt", "\n"));
175     ATF_REQUIRE(!atf::utils::compare_file("test.txt", "0123456789"));
176     long_contents[i - 1] = 'Z';
177     ATF_REQUIRE(!atf::utils::compare_file("test.txt", long_contents));
178 }
179 
180 ATF_TEST_CASE_WITHOUT_HEAD(copy_file__empty);
181 ATF_TEST_CASE_BODY(copy_file__empty)
182 {
183     atf::utils::create_file("src.txt", "");
184     ATF_REQUIRE(chmod("src.txt", 0520) != -1);
185 
186     atf::utils::copy_file("src.txt", "dest.txt");
187     ATF_REQUIRE(atf::utils::compare_file("dest.txt", ""));
188     struct stat sb;
189     ATF_REQUIRE(stat("dest.txt", &sb) != -1);
190     ATF_REQUIRE_EQ(0520, sb.st_mode & 0xfff);
191 }
192 
193 ATF_TEST_CASE_WITHOUT_HEAD(copy_file__some_contents);
194 ATF_TEST_CASE_BODY(copy_file__some_contents)
195 {
196     atf::utils::create_file("src.txt", "This is a\ntest file\n");
197     atf::utils::copy_file("src.txt", "dest.txt");
198     ATF_REQUIRE(atf::utils::compare_file("dest.txt", "This is a\ntest file\n"));
199 }
200 
201 ATF_TEST_CASE_WITHOUT_HEAD(create_file);
202 ATF_TEST_CASE_BODY(create_file)
203 {
204     atf::utils::create_file("test.txt", "This is a %d test");
205 
206     ATF_REQUIRE_EQ("This is a %d test", read_file("test.txt"));
207 }
208 
209 ATF_TEST_CASE_WITHOUT_HEAD(file_exists);
210 ATF_TEST_CASE_BODY(file_exists)
211 {
212     atf::utils::create_file("test.txt", "foo");
213 
214     ATF_REQUIRE( atf::utils::file_exists("test.txt"));
215     ATF_REQUIRE( atf::utils::file_exists("./test.txt"));
216     ATF_REQUIRE(!atf::utils::file_exists("./test.tx"));
217     ATF_REQUIRE(!atf::utils::file_exists("test.txt2"));
218 }
219 
220 ATF_TEST_CASE_WITHOUT_HEAD(fork);
221 ATF_TEST_CASE_BODY(fork)
222 {
223     std::cout << "Should not get into child\n";
224     std::cerr << "Should not get into child\n";
225     pid_t pid = atf::utils::fork();
226     if (pid == 0) {
227         std::cout << "Child stdout\n";
228         std::cerr << "Child stderr\n";
229         exit(EXIT_SUCCESS);
230     }
231 
232     int status;
233     ATF_REQUIRE(waitpid(pid, &status, 0) != -1);
234     ATF_REQUIRE(WIFEXITED(status));
235     ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
236 
237     std::ostringstream out_name;
238     out_name << "atf_utils_fork_" << pid << "_out.txt";
239     std::ostringstream err_name;
240     err_name << "atf_utils_fork_" << pid << "_err.txt";
241 
242     ATF_REQUIRE_EQ("Child stdout\n", read_file(out_name.str()));
243     ATF_REQUIRE_EQ("Child stderr\n", read_file(err_name.str()));
244 }
245 
246 ATF_TEST_CASE_WITHOUT_HEAD(grep_collection__set);
247 ATF_TEST_CASE_BODY(grep_collection__set)
248 {
249     std::set< std::string > strings;
250     strings.insert("First");
251     strings.insert("Second");
252 
253     ATF_REQUIRE( atf::utils::grep_collection("irs", strings));
254     ATF_REQUIRE( atf::utils::grep_collection("cond", strings));
255     ATF_REQUIRE(!atf::utils::grep_collection("Third", strings));
256 }
257 
258 ATF_TEST_CASE_WITHOUT_HEAD(grep_collection__vector);
259 ATF_TEST_CASE_BODY(grep_collection__vector)
260 {
261     std::vector< std::string > strings;
262     strings.push_back("First");
263     strings.push_back("Second");
264 
265     ATF_REQUIRE( atf::utils::grep_collection("irs", strings));
266     ATF_REQUIRE( atf::utils::grep_collection("cond", strings));
267     ATF_REQUIRE(!atf::utils::grep_collection("Third", strings));
268 }
269 
270 ATF_TEST_CASE_WITHOUT_HEAD(grep_file);
271 ATF_TEST_CASE_BODY(grep_file)
272 {
273     atf::utils::create_file("test.txt", "line1\nthe second line\naaaabbbb\n");
274 
275     ATF_REQUIRE(atf::utils::grep_file("line1", "test.txt"));
276     ATF_REQUIRE(atf::utils::grep_file("second line", "test.txt"));
277     ATF_REQUIRE(atf::utils::grep_file("aa.*bb", "test.txt"));
278     ATF_REQUIRE(!atf::utils::grep_file("foo", "test.txt"));
279     ATF_REQUIRE(!atf::utils::grep_file("bar", "test.txt"));
280     ATF_REQUIRE(!atf::utils::grep_file("aaaaa", "test.txt"));
281 }
282 
283 ATF_TEST_CASE_WITHOUT_HEAD(grep_string);
284 ATF_TEST_CASE_BODY(grep_string)
285 {
286     const char *str = "a string - aaaabbbb";
287     ATF_REQUIRE(atf::utils::grep_string("a string", str));
288     ATF_REQUIRE(atf::utils::grep_string("^a string", str));
289     ATF_REQUIRE(atf::utils::grep_string("aaaabbbb$", str));
290     ATF_REQUIRE(atf::utils::grep_string("aa.*bb", str));
291     ATF_REQUIRE(!atf::utils::grep_string("foo", str));
292     ATF_REQUIRE(!atf::utils::grep_string("bar", str));
293     ATF_REQUIRE(!atf::utils::grep_string("aaaaa", str));
294 }
295 
296 ATF_TEST_CASE_WITHOUT_HEAD(redirect__stdout);
297 ATF_TEST_CASE_BODY(redirect__stdout)
298 {
299     std::cout << "Buffer this";
300     atf::utils::redirect(STDOUT_FILENO, "captured.txt");
301     std::cout << "The printed message";
302     std::cout.flush();
303 
304     ATF_REQUIRE_EQ("The printed message", read_file("captured.txt"));
305 }
306 
307 ATF_TEST_CASE_WITHOUT_HEAD(redirect__stderr);
308 ATF_TEST_CASE_BODY(redirect__stderr)
309 {
310     std::cerr << "Buffer this";
311     atf::utils::redirect(STDERR_FILENO, "captured.txt");
312     std::cerr << "The printed message";
313     std::cerr.flush();
314 
315     ATF_REQUIRE_EQ("The printed message", read_file("captured.txt"));
316 }
317 
318 ATF_TEST_CASE_WITHOUT_HEAD(redirect__other);
319 ATF_TEST_CASE_BODY(redirect__other)
320 {
321     const std::string message = "Foo bar\nbaz\n";
322     atf::utils::redirect(15, "captured.txt");
323     ATF_REQUIRE(write(15, message.c_str(), message.length()) != -1);
324     close(15);
325 
326     ATF_REQUIRE_EQ(message, read_file("captured.txt"));
327 }
328 
329 static void
330 fork_and_wait(const int exitstatus, const char* expout, const char* experr)
331 {
332     const pid_t pid = atf::utils::fork();
333     if (pid == 0) {
334         std::cout << "Some output\n";
335         std::cerr << "Some error\n";
336         exit(123);
337     }
338     atf::utils::reset_resultsfile();
339     atf::utils::wait(pid, exitstatus, expout, experr);
340     exit(EXIT_SUCCESS);
341 }
342 
343 ATF_TEST_CASE_WITHOUT_HEAD(wait__ok);
344 ATF_TEST_CASE_BODY(wait__ok)
345 {
346     const pid_t control = fork();
347     ATF_REQUIRE(control != -1);
348     if (control == 0)
349         fork_and_wait(123, "Some output\n", "Some error\n");
350     else {
351         int status;
352         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
353         ATF_REQUIRE(WIFEXITED(status));
354         ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
355     }
356 }
357 
358 ATF_TEST_CASE_WITHOUT_HEAD(wait__ok_nested);
359 ATF_TEST_CASE_BODY(wait__ok_nested)
360 {
361     const pid_t parent = atf::utils::fork();
362     ATF_REQUIRE(parent != -1);
363     if (parent == 0) {
364         const pid_t child = atf::utils::fork();
365         ATF_REQUIRE(child != -1);
366         if (child == 0) {
367             std::cerr.flush();
368             std::cout << "Child output\n";
369             std::cout.flush();
370             std::cerr << "Child error\n";
371             std::exit(50);
372         } else {
373             std::cout << "Parent output\n";
374             std::cerr << "Parent error\n";
375             atf::utils::wait(child, 50, "Child output\n", "Child error\n");
376             std::exit(40);
377         }
378     } else {
379         atf::utils::wait(parent, 40,
380                          "Parent output\n"
381                          "subprocess stdout: Child output\n"
382                          "subprocess stderr: Child error\n",
383                          "Parent error\n");
384     }
385 }
386 
387 ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_exitstatus);
388 ATF_TEST_CASE_BODY(wait__invalid_exitstatus)
389 {
390     const pid_t control = fork();
391     ATF_REQUIRE(control != -1);
392     if (control == 0)
393         fork_and_wait(120, "Some output\n", "Some error\n");
394     else {
395         int status;
396         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
397         ATF_REQUIRE(WIFEXITED(status));
398         ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
399     }
400 }
401 
402 ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_stdout);
403 ATF_TEST_CASE_BODY(wait__invalid_stdout)
404 {
405     const pid_t control = fork();
406     ATF_REQUIRE(control != -1);
407     if (control == 0)
408         fork_and_wait(123, "Some output foo\n", "Some error\n");
409     else {
410         int status;
411         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
412         ATF_REQUIRE(WIFEXITED(status));
413         ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
414     }
415 }
416 
417 ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_stderr);
418 ATF_TEST_CASE_BODY(wait__invalid_stderr)
419 {
420     const pid_t control = fork();
421     ATF_REQUIRE(control != -1);
422     if (control == 0)
423         fork_and_wait(123, "Some output\n", "Some error foo\n");
424     else {
425         int status;
426         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
427         ATF_REQUIRE(WIFEXITED(status));
428         ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
429     }
430 }
431 
432 ATF_TEST_CASE_WITHOUT_HEAD(wait__save_stdout);
433 ATF_TEST_CASE_BODY(wait__save_stdout)
434 {
435     const pid_t control = fork();
436     ATF_REQUIRE(control != -1);
437     if (control == 0)
438         fork_and_wait(123, "save:my-output.txt", "Some error\n");
439     else {
440         int status;
441         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
442         ATF_REQUIRE(WIFEXITED(status));
443         ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
444 
445         ATF_REQUIRE(atf::utils::compare_file("my-output.txt", "Some output\n"));
446     }
447 }
448 
449 ATF_TEST_CASE_WITHOUT_HEAD(wait__save_stderr);
450 ATF_TEST_CASE_BODY(wait__save_stderr)
451 {
452     const pid_t control = fork();
453     ATF_REQUIRE(control != -1);
454     if (control == 0)
455         fork_and_wait(123, "Some output\n", "save:my-output.txt");
456     else {
457         int status;
458         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
459         ATF_REQUIRE(WIFEXITED(status));
460         ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
461 
462         ATF_REQUIRE(atf::utils::compare_file("my-output.txt", "Some error\n"));
463     }
464 }
465 
466 // ------------------------------------------------------------------------
467 // Main.
468 // ------------------------------------------------------------------------
469 
470 ATF_INIT_TEST_CASES(tcs)
471 {
472     // Add the test for the free functions.
473     ATF_ADD_TEST_CASE(tcs, cat_file__empty);
474     ATF_ADD_TEST_CASE(tcs, cat_file__one_line);
475     ATF_ADD_TEST_CASE(tcs, cat_file__several_lines);
476     ATF_ADD_TEST_CASE(tcs, cat_file__no_newline_eof);
477 
478     ATF_ADD_TEST_CASE(tcs, compare_file__empty__match);
479     ATF_ADD_TEST_CASE(tcs, compare_file__empty__not_match);
480     ATF_ADD_TEST_CASE(tcs, compare_file__short__match);
481     ATF_ADD_TEST_CASE(tcs, compare_file__short__not_match);
482     ATF_ADD_TEST_CASE(tcs, compare_file__long__match);
483     ATF_ADD_TEST_CASE(tcs, compare_file__long__not_match);
484 
485     ATF_ADD_TEST_CASE(tcs, copy_file__empty);
486     ATF_ADD_TEST_CASE(tcs, copy_file__some_contents);
487 
488     ATF_ADD_TEST_CASE(tcs, create_file);
489 
490     ATF_ADD_TEST_CASE(tcs, file_exists);
491 
492     ATF_ADD_TEST_CASE(tcs, fork);
493 
494     ATF_ADD_TEST_CASE(tcs, grep_collection__set);
495     ATF_ADD_TEST_CASE(tcs, grep_collection__vector);
496     ATF_ADD_TEST_CASE(tcs, grep_file);
497     ATF_ADD_TEST_CASE(tcs, grep_string);
498 
499     ATF_ADD_TEST_CASE(tcs, redirect__stdout);
500     ATF_ADD_TEST_CASE(tcs, redirect__stderr);
501     ATF_ADD_TEST_CASE(tcs, redirect__other);
502 
503     ATF_ADD_TEST_CASE(tcs, wait__ok);
504     ATF_ADD_TEST_CASE(tcs, wait__ok_nested);
505     ATF_ADD_TEST_CASE(tcs, wait__invalid_exitstatus);
506     ATF_ADD_TEST_CASE(tcs, wait__invalid_stdout);
507     ATF_ADD_TEST_CASE(tcs, wait__invalid_stderr);
508     ATF_ADD_TEST_CASE(tcs, wait__save_stdout);
509     ATF_ADD_TEST_CASE(tcs, wait__save_stderr);
510 }
511