xref: /freebsd/contrib/atf/atf-c++/utils_test.cpp (revision 396c556d77189a5c474d35cec6f44a762e310b7d)
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::wait(pid, exitstatus, expout, experr);
339     exit(EXIT_SUCCESS);
340 }
341 
342 ATF_TEST_CASE_WITHOUT_HEAD(wait__ok);
343 ATF_TEST_CASE_BODY(wait__ok)
344 {
345     const pid_t control = fork();
346     ATF_REQUIRE(control != -1);
347     if (control == 0)
348         fork_and_wait(123, "Some output\n", "Some error\n");
349     else {
350         int status;
351         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
352         ATF_REQUIRE(WIFEXITED(status));
353         ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
354     }
355 }
356 
357 ATF_TEST_CASE_WITHOUT_HEAD(wait__ok_nested);
358 ATF_TEST_CASE_BODY(wait__ok_nested)
359 {
360     const pid_t parent = atf::utils::fork();
361     ATF_REQUIRE(parent != -1);
362     if (parent == 0) {
363         const pid_t child = atf::utils::fork();
364         ATF_REQUIRE(child != -1);
365         if (child == 0) {
366             std::cerr.flush();
367             std::cout << "Child output\n";
368             std::cout.flush();
369             std::cerr << "Child error\n";
370             std::exit(50);
371         } else {
372             std::cout << "Parent output\n";
373             std::cerr << "Parent error\n";
374             atf::utils::wait(child, 50, "Child output\n", "Child error\n");
375             std::exit(40);
376         }
377     } else {
378         atf::utils::wait(parent, 40,
379                          "Parent output\n"
380                          "subprocess stdout: Child output\n"
381                          "subprocess stderr: Child error\n",
382                          "Parent error\n");
383     }
384 }
385 
386 ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_exitstatus);
387 ATF_TEST_CASE_BODY(wait__invalid_exitstatus)
388 {
389     const pid_t control = fork();
390     ATF_REQUIRE(control != -1);
391     if (control == 0)
392         fork_and_wait(120, "Some output\n", "Some error\n");
393     else {
394         int status;
395         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
396         ATF_REQUIRE(WIFEXITED(status));
397         ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
398     }
399 }
400 
401 ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_stdout);
402 ATF_TEST_CASE_BODY(wait__invalid_stdout)
403 {
404     const pid_t control = fork();
405     ATF_REQUIRE(control != -1);
406     if (control == 0)
407         fork_and_wait(123, "Some output foo\n", "Some error\n");
408     else {
409         int status;
410         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
411         ATF_REQUIRE(WIFEXITED(status));
412         ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
413     }
414 }
415 
416 ATF_TEST_CASE_WITHOUT_HEAD(wait__invalid_stderr);
417 ATF_TEST_CASE_BODY(wait__invalid_stderr)
418 {
419     const pid_t control = fork();
420     ATF_REQUIRE(control != -1);
421     if (control == 0)
422         fork_and_wait(123, "Some output\n", "Some error foo\n");
423     else {
424         int status;
425         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
426         ATF_REQUIRE(WIFEXITED(status));
427         ATF_REQUIRE_EQ(EXIT_FAILURE, WEXITSTATUS(status));
428     }
429 }
430 
431 ATF_TEST_CASE_WITHOUT_HEAD(wait__save_stdout);
432 ATF_TEST_CASE_BODY(wait__save_stdout)
433 {
434     const pid_t control = fork();
435     ATF_REQUIRE(control != -1);
436     if (control == 0)
437         fork_and_wait(123, "save:my-output.txt", "Some error\n");
438     else {
439         int status;
440         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
441         ATF_REQUIRE(WIFEXITED(status));
442         ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
443 
444         ATF_REQUIRE(atf::utils::compare_file("my-output.txt", "Some output\n"));
445     }
446 }
447 
448 ATF_TEST_CASE_WITHOUT_HEAD(wait__save_stderr);
449 ATF_TEST_CASE_BODY(wait__save_stderr)
450 {
451     const pid_t control = fork();
452     ATF_REQUIRE(control != -1);
453     if (control == 0)
454         fork_and_wait(123, "Some output\n", "save:my-output.txt");
455     else {
456         int status;
457         ATF_REQUIRE(waitpid(control, &status, 0) != -1);
458         ATF_REQUIRE(WIFEXITED(status));
459         ATF_REQUIRE_EQ(EXIT_SUCCESS, WEXITSTATUS(status));
460 
461         ATF_REQUIRE(atf::utils::compare_file("my-output.txt", "Some error\n"));
462     }
463 }
464 
465 // ------------------------------------------------------------------------
466 // Main.
467 // ------------------------------------------------------------------------
468 
469 ATF_INIT_TEST_CASES(tcs)
470 {
471     // Add the test for the free functions.
472     ATF_ADD_TEST_CASE(tcs, cat_file__empty);
473     ATF_ADD_TEST_CASE(tcs, cat_file__one_line);
474     ATF_ADD_TEST_CASE(tcs, cat_file__several_lines);
475     ATF_ADD_TEST_CASE(tcs, cat_file__no_newline_eof);
476 
477     ATF_ADD_TEST_CASE(tcs, compare_file__empty__match);
478     ATF_ADD_TEST_CASE(tcs, compare_file__empty__not_match);
479     ATF_ADD_TEST_CASE(tcs, compare_file__short__match);
480     ATF_ADD_TEST_CASE(tcs, compare_file__short__not_match);
481     ATF_ADD_TEST_CASE(tcs, compare_file__long__match);
482     ATF_ADD_TEST_CASE(tcs, compare_file__long__not_match);
483 
484     ATF_ADD_TEST_CASE(tcs, copy_file__empty);
485     ATF_ADD_TEST_CASE(tcs, copy_file__some_contents);
486 
487     ATF_ADD_TEST_CASE(tcs, create_file);
488 
489     ATF_ADD_TEST_CASE(tcs, file_exists);
490 
491     ATF_ADD_TEST_CASE(tcs, fork);
492 
493     ATF_ADD_TEST_CASE(tcs, grep_collection__set);
494     ATF_ADD_TEST_CASE(tcs, grep_collection__vector);
495     ATF_ADD_TEST_CASE(tcs, grep_file);
496     ATF_ADD_TEST_CASE(tcs, grep_string);
497 
498     ATF_ADD_TEST_CASE(tcs, redirect__stdout);
499     ATF_ADD_TEST_CASE(tcs, redirect__stderr);
500     ATF_ADD_TEST_CASE(tcs, redirect__other);
501 
502     ATF_ADD_TEST_CASE(tcs, wait__ok);
503     ATF_ADD_TEST_CASE(tcs, wait__ok_nested);
504     ATF_ADD_TEST_CASE(tcs, wait__invalid_exitstatus);
505     ATF_ADD_TEST_CASE(tcs, wait__invalid_stdout);
506     ATF_ADD_TEST_CASE(tcs, wait__invalid_stderr);
507     ATF_ADD_TEST_CASE(tcs, wait__save_stdout);
508     ATF_ADD_TEST_CASE(tcs, wait__save_stderr);
509 }
510