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 <sys/types.h>
32#include <sys/stat.h>
33}
34
35#include <cerrno>
36#include <fstream>
37
38#include "atf-c++/macros.hpp"
39
40#include "atf-c++/detail/exceptions.hpp"
41#include "atf-c++/detail/fs.hpp"
42
43#include "fs.hpp"
44#include "user.hpp"
45
46// ------------------------------------------------------------------------
47// Auxiliary functions.
48// ------------------------------------------------------------------------
49
50static
51void
52create_file(const char *name)
53{
54    std::ofstream os(name);
55    os.close();
56}
57
58// ------------------------------------------------------------------------
59// Test cases for the "temp_dir" class.
60// ------------------------------------------------------------------------
61
62ATF_TEST_CASE(temp_dir_raii);
63ATF_TEST_CASE_HEAD(temp_dir_raii)
64{
65    set_md_var("descr", "Tests the RAII behavior of the temp_dir class");
66}
67ATF_TEST_CASE_BODY(temp_dir_raii)
68{
69    using atf::atf_run::temp_dir;
70
71    atf::fs::path t1("non-existent");
72    atf::fs::path t2("non-existent");
73
74    {
75        atf::fs::path tmpl("testdir.XXXXXX");
76        temp_dir td1(tmpl);
77        temp_dir td2(tmpl);
78        t1 = td1.get_path();
79        t2 = td2.get_path();
80        ATF_REQUIRE(t1.str().find("XXXXXX") == std::string::npos);
81        ATF_REQUIRE(t2.str().find("XXXXXX") == std::string::npos);
82        ATF_REQUIRE(t1 != t2);
83        ATF_REQUIRE(!atf::fs::exists(tmpl));
84        ATF_REQUIRE( atf::fs::exists(t1));
85        ATF_REQUIRE( atf::fs::exists(t2));
86
87        atf::fs::file_info fi1(t1);
88        ATF_REQUIRE( fi1.is_owner_readable());
89        ATF_REQUIRE( fi1.is_owner_writable());
90        ATF_REQUIRE( fi1.is_owner_executable());
91        ATF_REQUIRE(!fi1.is_group_readable());
92        ATF_REQUIRE(!fi1.is_group_writable());
93        ATF_REQUIRE(!fi1.is_group_executable());
94        ATF_REQUIRE(!fi1.is_other_readable());
95        ATF_REQUIRE(!fi1.is_other_writable());
96        ATF_REQUIRE(!fi1.is_other_executable());
97
98        atf::fs::file_info fi2(t2);
99        ATF_REQUIRE( fi2.is_owner_readable());
100        ATF_REQUIRE( fi2.is_owner_writable());
101        ATF_REQUIRE( fi2.is_owner_executable());
102        ATF_REQUIRE(!fi2.is_group_readable());
103        ATF_REQUIRE(!fi2.is_group_writable());
104        ATF_REQUIRE(!fi2.is_group_executable());
105        ATF_REQUIRE(!fi2.is_other_readable());
106        ATF_REQUIRE(!fi2.is_other_writable());
107        ATF_REQUIRE(!fi2.is_other_executable());
108    }
109
110    ATF_REQUIRE(t1.str() != "non-existent");
111    ATF_REQUIRE(!atf::fs::exists(t1));
112    ATF_REQUIRE(t2.str() != "non-existent");
113    ATF_REQUIRE(!atf::fs::exists(t2));
114}
115
116
117// ------------------------------------------------------------------------
118// Test cases for the free functions.
119// ------------------------------------------------------------------------
120
121ATF_TEST_CASE(cleanup);
122ATF_TEST_CASE_HEAD(cleanup)
123{
124    set_md_var("descr", "Tests the cleanup function");
125}
126ATF_TEST_CASE_BODY(cleanup)
127{
128    using atf::atf_run::cleanup;
129
130    ::mkdir("root", 0755);
131    ::mkdir("root/dir", 0755);
132    ::mkdir("root/dir/1", 0100);
133    ::mkdir("root/dir/2", 0644);
134    create_file("root/reg");
135
136    atf::fs::path p("root");
137    ATF_REQUIRE(atf::fs::exists(p));
138    ATF_REQUIRE(atf::fs::exists(p / "dir"));
139    ATF_REQUIRE(atf::fs::exists(p / "dir/1"));
140    ATF_REQUIRE(atf::fs::exists(p / "dir/2"));
141    ATF_REQUIRE(atf::fs::exists(p / "reg"));
142    cleanup(p);
143    ATF_REQUIRE(!atf::fs::exists(p));
144}
145
146ATF_TEST_CASE(cleanup_eacces_on_root);
147ATF_TEST_CASE_HEAD(cleanup_eacces_on_root)
148{
149    set_md_var("descr", "Tests the cleanup function");
150}
151ATF_TEST_CASE_BODY(cleanup_eacces_on_root)
152{
153    using atf::atf_run::cleanup;
154
155    ::mkdir("aux", 0755);
156    ::mkdir("aux/root", 0755);
157    ATF_REQUIRE(::chmod("aux", 0555) != -1);
158
159    try {
160        cleanup(atf::fs::path("aux/root"));
161        ATF_REQUIRE(atf::atf_run::is_root());
162    } catch (const atf::system_error& e) {
163        ATF_REQUIRE(!atf::atf_run::is_root());
164        ATF_REQUIRE_EQ(EACCES, e.code());
165    }
166}
167
168ATF_TEST_CASE(cleanup_eacces_on_subdir);
169ATF_TEST_CASE_HEAD(cleanup_eacces_on_subdir)
170{
171    set_md_var("descr", "Tests the cleanup function");
172}
173ATF_TEST_CASE_BODY(cleanup_eacces_on_subdir)
174{
175    using atf::atf_run::cleanup;
176
177    ::mkdir("root", 0755);
178    ::mkdir("root/1", 0755);
179    ::mkdir("root/1/2", 0755);
180    ::mkdir("root/1/2/3", 0755);
181    ATF_REQUIRE(::chmod("root/1/2", 0555) != -1);
182    ATF_REQUIRE(::chmod("root/1", 0555) != -1);
183
184    const atf::fs::path p("root");
185    cleanup(p);
186    ATF_REQUIRE(!atf::fs::exists(p));
187}
188
189ATF_TEST_CASE(change_directory);
190ATF_TEST_CASE_HEAD(change_directory)
191{
192    set_md_var("descr", "Tests the change_directory function");
193}
194ATF_TEST_CASE_BODY(change_directory)
195{
196    using atf::atf_run::change_directory;
197    using atf::atf_run::get_current_dir;
198
199    ::mkdir("files", 0755);
200    ::mkdir("files/dir", 0755);
201    create_file("files/reg");
202
203    const atf::fs::path old = get_current_dir();
204
205    ATF_REQUIRE_THROW(atf::system_error,
206                    change_directory(atf::fs::path("files/reg")));
207    ATF_REQUIRE(get_current_dir() == old);
208
209    atf::fs::path old2 = change_directory(atf::fs::path("files"));
210    ATF_REQUIRE(old2 == old);
211    atf::fs::path old3 = change_directory(atf::fs::path("dir"));
212    ATF_REQUIRE(old3 == old2 / "files");
213    atf::fs::path old4 = change_directory(atf::fs::path("../.."));
214    ATF_REQUIRE(old4 == old3 / "dir");
215    ATF_REQUIRE(get_current_dir() == old);
216}
217
218ATF_TEST_CASE(get_current_dir);
219ATF_TEST_CASE_HEAD(get_current_dir)
220{
221    set_md_var("descr", "Tests the get_current_dir function");
222}
223ATF_TEST_CASE_BODY(get_current_dir)
224{
225    using atf::atf_run::change_directory;
226    using atf::atf_run::get_current_dir;
227
228    ::mkdir("files", 0755);
229    ::mkdir("files/dir", 0755);
230    create_file("files/reg");
231
232    atf::fs::path curdir = get_current_dir();
233    change_directory(atf::fs::path("."));
234    ATF_REQUIRE(get_current_dir() == curdir);
235    change_directory(atf::fs::path("files"));
236    ATF_REQUIRE(get_current_dir() == curdir / "files");
237    change_directory(atf::fs::path("dir"));
238    ATF_REQUIRE(get_current_dir() == curdir / "files/dir");
239    change_directory(atf::fs::path(".."));
240    ATF_REQUIRE(get_current_dir() == curdir / "files");
241    change_directory(atf::fs::path(".."));
242    ATF_REQUIRE(get_current_dir() == curdir);
243}
244
245// ------------------------------------------------------------------------
246// Main.
247// ------------------------------------------------------------------------
248
249ATF_INIT_TEST_CASES(tcs)
250{
251    // Add the tests for the "temp_dir" class.
252    ATF_ADD_TEST_CASE(tcs, temp_dir_raii);
253
254    // Add the tests for the free functions.
255    ATF_ADD_TEST_CASE(tcs, cleanup);
256    ATF_ADD_TEST_CASE(tcs, cleanup_eacces_on_root);
257    ATF_ADD_TEST_CASE(tcs, cleanup_eacces_on_subdir);
258    ATF_ADD_TEST_CASE(tcs, change_directory);
259    ATF_ADD_TEST_CASE(tcs, get_current_dir);
260}
261