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