xref: /freebsd/contrib/atf/atf-c++/detail/fs_test.cpp (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
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++/detail/fs.hpp"
27 
28 extern "C" {
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 }
32 
33 #include <fstream>
34 #include <cerrno>
35 #include <cstdio>
36 
37 #include <atf-c++.hpp>
38 
39 #include "atf-c++/detail/exceptions.hpp"
40 
41 // ------------------------------------------------------------------------
42 // Auxiliary functions.
43 // ------------------------------------------------------------------------
44 
45 static
46 void
47 create_files(void)
48 {
49     ::mkdir("files", 0755);
50     ::mkdir("files/dir", 0755);
51 
52     std::ofstream os("files/reg");
53     os.close();
54 
55     // TODO: Should create all other file types (blk, chr, fifo, lnk, sock)
56     // and test for them... but the underlying file system may not support
57     // most of these.  Specially as we are working on /tmp, which can be
58     // mounted with flags such as "nodev".  See how to deal with this
59     // situation.
60 }
61 
62 // ------------------------------------------------------------------------
63 // Test cases for the "path" class.
64 // ------------------------------------------------------------------------
65 
66 ATF_TEST_CASE(path_normalize);
67 ATF_TEST_CASE_HEAD(path_normalize)
68 {
69     set_md_var("descr", "Tests the path's normalization");
70 }
71 ATF_TEST_CASE_BODY(path_normalize)
72 {
73     using atf::fs::path;
74 
75     ATF_REQUIRE_EQ(path(".").str(), ".");
76     ATF_REQUIRE_EQ(path("..").str(), "..");
77 
78     ATF_REQUIRE_EQ(path("foo").str(), "foo");
79     ATF_REQUIRE_EQ(path("foo/bar").str(), "foo/bar");
80     ATF_REQUIRE_EQ(path("foo/bar/").str(), "foo/bar");
81 
82     ATF_REQUIRE_EQ(path("/foo").str(), "/foo");
83     ATF_REQUIRE_EQ(path("/foo/bar").str(), "/foo/bar");
84     ATF_REQUIRE_EQ(path("/foo/bar/").str(), "/foo/bar");
85 
86     ATF_REQUIRE_EQ(path("///foo").str(), "/foo");
87     ATF_REQUIRE_EQ(path("///foo///bar").str(), "/foo/bar");
88     ATF_REQUIRE_EQ(path("///foo///bar///").str(), "/foo/bar");
89 }
90 
91 ATF_TEST_CASE(path_is_absolute);
92 ATF_TEST_CASE_HEAD(path_is_absolute)
93 {
94     set_md_var("descr", "Tests the path::is_absolute function");
95 }
96 ATF_TEST_CASE_BODY(path_is_absolute)
97 {
98     using atf::fs::path;
99 
100     ATF_REQUIRE( path("/").is_absolute());
101     ATF_REQUIRE( path("////").is_absolute());
102     ATF_REQUIRE( path("////a").is_absolute());
103     ATF_REQUIRE( path("//a//").is_absolute());
104     ATF_REQUIRE(!path("a////").is_absolute());
105     ATF_REQUIRE(!path("../foo").is_absolute());
106 }
107 
108 ATF_TEST_CASE(path_is_root);
109 ATF_TEST_CASE_HEAD(path_is_root)
110 {
111     set_md_var("descr", "Tests the path::is_root function");
112 }
113 ATF_TEST_CASE_BODY(path_is_root)
114 {
115     using atf::fs::path;
116 
117     ATF_REQUIRE( path("/").is_root());
118     ATF_REQUIRE( path("////").is_root());
119     ATF_REQUIRE(!path("////a").is_root());
120     ATF_REQUIRE(!path("//a//").is_root());
121     ATF_REQUIRE(!path("a////").is_root());
122     ATF_REQUIRE(!path("../foo").is_root());
123 }
124 
125 ATF_TEST_CASE(path_branch_path);
126 ATF_TEST_CASE_HEAD(path_branch_path)
127 {
128     set_md_var("descr", "Tests the path::branch_path function");
129 }
130 ATF_TEST_CASE_BODY(path_branch_path)
131 {
132     using atf::fs::path;
133 
134     ATF_REQUIRE_EQ(path(".").branch_path().str(), ".");
135     ATF_REQUIRE_EQ(path("foo").branch_path().str(), ".");
136     ATF_REQUIRE_EQ(path("foo/bar").branch_path().str(), "foo");
137     ATF_REQUIRE_EQ(path("/foo").branch_path().str(), "/");
138     ATF_REQUIRE_EQ(path("/foo/bar").branch_path().str(), "/foo");
139 }
140 
141 ATF_TEST_CASE(path_leaf_name);
142 ATF_TEST_CASE_HEAD(path_leaf_name)
143 {
144     set_md_var("descr", "Tests the path::leaf_name function");
145 }
146 ATF_TEST_CASE_BODY(path_leaf_name)
147 {
148     using atf::fs::path;
149 
150     ATF_REQUIRE_EQ(path(".").leaf_name(), ".");
151     ATF_REQUIRE_EQ(path("foo").leaf_name(), "foo");
152     ATF_REQUIRE_EQ(path("foo/bar").leaf_name(), "bar");
153     ATF_REQUIRE_EQ(path("/foo").leaf_name(), "foo");
154     ATF_REQUIRE_EQ(path("/foo/bar").leaf_name(), "bar");
155 }
156 
157 ATF_TEST_CASE(path_compare_equal);
158 ATF_TEST_CASE_HEAD(path_compare_equal)
159 {
160     set_md_var("descr", "Tests the comparison for equality between paths");
161 }
162 ATF_TEST_CASE_BODY(path_compare_equal)
163 {
164     using atf::fs::path;
165 
166     ATF_REQUIRE(path("/") == path("///"));
167     ATF_REQUIRE(path("/a") == path("///a"));
168     ATF_REQUIRE(path("/a") == path("///a///"));
169 
170     ATF_REQUIRE(path("a/b/c") == path("a//b//c"));
171     ATF_REQUIRE(path("a/b/c") == path("a//b//c///"));
172 }
173 
174 ATF_TEST_CASE(path_compare_different);
175 ATF_TEST_CASE_HEAD(path_compare_different)
176 {
177     set_md_var("descr", "Tests the comparison for difference between paths");
178 }
179 ATF_TEST_CASE_BODY(path_compare_different)
180 {
181     using atf::fs::path;
182 
183     ATF_REQUIRE(path("/") != path("//a/"));
184     ATF_REQUIRE(path("/a") != path("a///"));
185 
186     ATF_REQUIRE(path("a/b/c") != path("a/b"));
187     ATF_REQUIRE(path("a/b/c") != path("a//b"));
188     ATF_REQUIRE(path("a/b/c") != path("/a/b/c"));
189     ATF_REQUIRE(path("a/b/c") != path("/a//b//c"));
190 }
191 
192 ATF_TEST_CASE(path_concat);
193 ATF_TEST_CASE_HEAD(path_concat)
194 {
195     set_md_var("descr", "Tests the concatenation of multiple paths");
196 }
197 ATF_TEST_CASE_BODY(path_concat)
198 {
199     using atf::fs::path;
200 
201     ATF_REQUIRE_EQ((path("foo") / "bar").str(), "foo/bar");
202     ATF_REQUIRE_EQ((path("foo/") / "/bar").str(), "foo/bar");
203     ATF_REQUIRE_EQ((path("foo/") / "/bar/baz").str(), "foo/bar/baz");
204     ATF_REQUIRE_EQ((path("foo/") / "///bar///baz").str(), "foo/bar/baz");
205 }
206 
207 ATF_TEST_CASE(path_to_absolute);
208 ATF_TEST_CASE_HEAD(path_to_absolute)
209 {
210     set_md_var("descr", "Tests the conversion of a relative path to an "
211                "absolute one");
212 }
213 ATF_TEST_CASE_BODY(path_to_absolute)
214 {
215     using atf::fs::file_info;
216     using atf::fs::path;
217 
218     create_files();
219 
220     {
221         const path p(".");
222         path pa = p.to_absolute();
223         ATF_REQUIRE(pa.is_absolute());
224 
225         file_info fi(p);
226         file_info fia(pa);
227         ATF_REQUIRE_EQ(fi.get_device(), fia.get_device());
228         ATF_REQUIRE_EQ(fi.get_inode(), fia.get_inode());
229     }
230 
231     {
232         const path p("files/reg");
233         path pa = p.to_absolute();
234         ATF_REQUIRE(pa.is_absolute());
235 
236         file_info fi(p);
237         file_info fia(pa);
238         ATF_REQUIRE_EQ(fi.get_device(), fia.get_device());
239         ATF_REQUIRE_EQ(fi.get_inode(), fia.get_inode());
240     }
241 }
242 
243 ATF_TEST_CASE(path_op_less);
244 ATF_TEST_CASE_HEAD(path_op_less)
245 {
246     set_md_var("descr", "Tests that the path's less-than operator works");
247 }
248 ATF_TEST_CASE_BODY(path_op_less)
249 {
250     using atf::fs::path;
251 
252     create_files();
253 
254     ATF_REQUIRE(!(path("aaa") < path("aaa")));
255 
256     ATF_REQUIRE(  path("aab") < path("abc"));
257     ATF_REQUIRE(!(path("abc") < path("aab")));
258 }
259 
260 // ------------------------------------------------------------------------
261 // Test cases for the "directory" class.
262 // ------------------------------------------------------------------------
263 
264 ATF_TEST_CASE(directory_read);
265 ATF_TEST_CASE_HEAD(directory_read)
266 {
267     set_md_var("descr", "Tests the directory class creation, which reads "
268                "the contents of a directory");
269 }
270 ATF_TEST_CASE_BODY(directory_read)
271 {
272     using atf::fs::directory;
273     using atf::fs::path;
274 
275     create_files();
276 
277     directory d(path("files"));
278     ATF_REQUIRE_EQ(d.size(), 4);
279     ATF_REQUIRE(d.find(".") != d.end());
280     ATF_REQUIRE(d.find("..") != d.end());
281     ATF_REQUIRE(d.find("dir") != d.end());
282     ATF_REQUIRE(d.find("reg") != d.end());
283 }
284 
285 ATF_TEST_CASE(directory_file_info);
286 ATF_TEST_CASE_HEAD(directory_file_info)
287 {
288     set_md_var("descr", "Tests that the file_info objects attached to the "
289                "directory are valid");
290 }
291 ATF_TEST_CASE_BODY(directory_file_info)
292 {
293     using atf::fs::directory;
294     using atf::fs::file_info;
295     using atf::fs::path;
296 
297     create_files();
298 
299     directory d(path("files"));
300 
301     {
302         directory::const_iterator iter = d.find("dir");
303         ATF_REQUIRE(iter != d.end());
304         const file_info& fi = (*iter).second;
305         ATF_REQUIRE(fi.get_type() == file_info::dir_type);
306     }
307 
308     {
309         directory::const_iterator iter = d.find("reg");
310         ATF_REQUIRE(iter != d.end());
311         const file_info& fi = (*iter).second;
312         ATF_REQUIRE(fi.get_type() == file_info::reg_type);
313     }
314 }
315 
316 ATF_TEST_CASE(directory_names);
317 ATF_TEST_CASE_HEAD(directory_names)
318 {
319     set_md_var("descr", "Tests the directory's names method");
320 }
321 ATF_TEST_CASE_BODY(directory_names)
322 {
323     using atf::fs::directory;
324     using atf::fs::path;
325 
326     create_files();
327 
328     directory d(path("files"));
329     std::set< std::string > ns = d.names();
330     ATF_REQUIRE_EQ(ns.size(), 4);
331     ATF_REQUIRE(ns.find(".") != ns.end());
332     ATF_REQUIRE(ns.find("..") != ns.end());
333     ATF_REQUIRE(ns.find("dir") != ns.end());
334     ATF_REQUIRE(ns.find("reg") != ns.end());
335 }
336 
337 // ------------------------------------------------------------------------
338 // Test cases for the "file_info" class.
339 // ------------------------------------------------------------------------
340 
341 ATF_TEST_CASE(file_info_stat);
342 ATF_TEST_CASE_HEAD(file_info_stat)
343 {
344     set_md_var("descr", "Tests the file_info creation and its basic contents");
345 }
346 ATF_TEST_CASE_BODY(file_info_stat)
347 {
348     using atf::fs::file_info;
349     using atf::fs::path;
350 
351     create_files();
352 
353     {
354         path p("files/dir");
355         file_info fi(p);
356         ATF_REQUIRE(fi.get_type() == file_info::dir_type);
357     }
358 
359     {
360         path p("files/reg");
361         file_info fi(p);
362         ATF_REQUIRE(fi.get_type() == file_info::reg_type);
363     }
364 }
365 
366 ATF_TEST_CASE(file_info_perms);
367 ATF_TEST_CASE_HEAD(file_info_perms)
368 {
369     set_md_var("descr", "Tests the file_info methods to get the file's "
370                "permissions");
371 }
372 ATF_TEST_CASE_BODY(file_info_perms)
373 {
374     using atf::fs::file_info;
375     using atf::fs::path;
376 
377     path p("file");
378 
379     std::ofstream os(p.c_str());
380     os.close();
381 
382 #define perms(ur, uw, ux, gr, gw, gx, othr, othw, othx) \
383     { \
384         file_info fi(p); \
385         ATF_REQUIRE(fi.is_owner_readable() == ur); \
386         ATF_REQUIRE(fi.is_owner_writable() == uw); \
387         ATF_REQUIRE(fi.is_owner_executable() == ux); \
388         ATF_REQUIRE(fi.is_group_readable() == gr); \
389         ATF_REQUIRE(fi.is_group_writable() == gw); \
390         ATF_REQUIRE(fi.is_group_executable() == gx); \
391         ATF_REQUIRE(fi.is_other_readable() == othr); \
392         ATF_REQUIRE(fi.is_other_writable() == othw); \
393         ATF_REQUIRE(fi.is_other_executable() == othx); \
394     }
395 
396     ::chmod(p.c_str(), 0000);
397     perms(false, false, false, false, false, false, false, false, false);
398 
399     ::chmod(p.c_str(), 0001);
400     perms(false, false, false, false, false, false, false, false, true);
401 
402     ::chmod(p.c_str(), 0010);
403     perms(false, false, false, false, false, true, false, false, false);
404 
405     ::chmod(p.c_str(), 0100);
406     perms(false, false, true, false, false, false, false, false, false);
407 
408     ::chmod(p.c_str(), 0002);
409     perms(false, false, false, false, false, false, false, true, false);
410 
411     ::chmod(p.c_str(), 0020);
412     perms(false, false, false, false, true, false, false, false, false);
413 
414     ::chmod(p.c_str(), 0200);
415     perms(false, true, false, false, false, false, false, false, false);
416 
417     ::chmod(p.c_str(), 0004);
418     perms(false, false, false, false, false, false, true, false, false);
419 
420     ::chmod(p.c_str(), 0040);
421     perms(false, false, false, true, false, false, false, false, false);
422 
423     ::chmod(p.c_str(), 0400);
424     perms(true, false, false, false, false, false, false, false, false);
425 
426     ::chmod(p.c_str(), 0644);
427     perms(true, true, false, true, false, false, true, false, false);
428 
429     ::chmod(p.c_str(), 0755);
430     perms(true, true, true, true, false, true, true, false, true);
431 
432     ::chmod(p.c_str(), 0777);
433     perms(true, true, true, true, true, true, true, true, true);
434 
435 #undef perms
436 }
437 
438 // ------------------------------------------------------------------------
439 // Test cases for the free functions.
440 // ------------------------------------------------------------------------
441 
442 ATF_TEST_CASE(exists);
443 ATF_TEST_CASE_HEAD(exists)
444 {
445     set_md_var("descr", "Tests the exists function");
446 }
447 ATF_TEST_CASE_BODY(exists)
448 {
449     using atf::fs::exists;
450     using atf::fs::path;
451 
452     create_files();
453 
454     ATF_REQUIRE( exists(path("files")));
455     ATF_REQUIRE(!exists(path("file")));
456     ATF_REQUIRE(!exists(path("files2")));
457 
458     ATF_REQUIRE( exists(path("files/.")));
459     ATF_REQUIRE( exists(path("files/..")));
460     ATF_REQUIRE( exists(path("files/dir")));
461     ATF_REQUIRE( exists(path("files/reg")));
462     ATF_REQUIRE(!exists(path("files/foo")));
463 }
464 
465 ATF_TEST_CASE(is_executable);
466 ATF_TEST_CASE_HEAD(is_executable)
467 {
468     set_md_var("descr", "Tests the is_executable function");
469 }
470 ATF_TEST_CASE_BODY(is_executable)
471 {
472     using atf::fs::is_executable;
473     using atf::fs::path;
474 
475     create_files();
476 
477     ATF_REQUIRE( is_executable(path("files")));
478     ATF_REQUIRE( is_executable(path("files/.")));
479     ATF_REQUIRE( is_executable(path("files/..")));
480     ATF_REQUIRE( is_executable(path("files/dir")));
481 
482     ATF_REQUIRE(!is_executable(path("non-existent")));
483 
484     ATF_REQUIRE(!is_executable(path("files/reg")));
485     ATF_REQUIRE(::chmod("files/reg", 0755) != -1);
486     ATF_REQUIRE( is_executable(path("files/reg")));
487 }
488 
489 ATF_TEST_CASE(remove);
490 ATF_TEST_CASE_HEAD(remove)
491 {
492     set_md_var("descr", "Tests the remove function");
493 }
494 ATF_TEST_CASE_BODY(remove)
495 {
496     using atf::fs::exists;
497     using atf::fs::path;
498     using atf::fs::remove;
499 
500     create_files();
501 
502     ATF_REQUIRE( exists(path("files/reg")));
503     remove(path("files/reg"));
504     ATF_REQUIRE(!exists(path("files/reg")));
505 
506     ATF_REQUIRE( exists(path("files/dir")));
507     ATF_REQUIRE_THROW(atf::system_error, remove(path("files/dir")));
508     ATF_REQUIRE( exists(path("files/dir")));
509 }
510 
511 // ------------------------------------------------------------------------
512 // Main.
513 // ------------------------------------------------------------------------
514 
515 ATF_INIT_TEST_CASES(tcs)
516 {
517     // Add the tests for the "path" class.
518     ATF_ADD_TEST_CASE(tcs, path_normalize);
519     ATF_ADD_TEST_CASE(tcs, path_is_absolute);
520     ATF_ADD_TEST_CASE(tcs, path_is_root);
521     ATF_ADD_TEST_CASE(tcs, path_branch_path);
522     ATF_ADD_TEST_CASE(tcs, path_leaf_name);
523     ATF_ADD_TEST_CASE(tcs, path_compare_equal);
524     ATF_ADD_TEST_CASE(tcs, path_compare_different);
525     ATF_ADD_TEST_CASE(tcs, path_concat);
526     ATF_ADD_TEST_CASE(tcs, path_to_absolute);
527     ATF_ADD_TEST_CASE(tcs, path_op_less);
528 
529     // Add the tests for the "file_info" class.
530     ATF_ADD_TEST_CASE(tcs, file_info_stat);
531     ATF_ADD_TEST_CASE(tcs, file_info_perms);
532 
533     // Add the tests for the "directory" class.
534     ATF_ADD_TEST_CASE(tcs, directory_read);
535     ATF_ADD_TEST_CASE(tcs, directory_names);
536     ATF_ADD_TEST_CASE(tcs, directory_file_info);
537 
538     // Add the tests for the free functions.
539     ATF_ADD_TEST_CASE(tcs, exists);
540     ATF_ADD_TEST_CASE(tcs, is_executable);
541     ATF_ADD_TEST_CASE(tcs, remove);
542 }
543