1 // -*- C++ -*-
2 // Filesystem utils for the C++ library testsuite.
3 //
4 // Copyright (C) 2014-2016 Free Software Foundation, Inc.
5 //
6 // This file is part of the GNU ISO C++ Library.  This library is free
7 // software; you can redistribute it and/or modify it under the
8 // terms of the GNU General Public License as published by the
9 // Free Software Foundation; either version 3, or (at your option)
10 // any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this library; see the file COPYING3.  If not see
19 // <http://www.gnu.org/licenses/>.
20 //
21 
22 #ifndef _TESTSUITE_FS_H
23 #define _TESTSUITE_FS_H 1
24 
25 #include <experimental/filesystem>
26 #include <fstream>
27 #include <string>
28 #include <cstdio>
29 #include <stdlib.h>
30 #include <unistd.h>
31 
32 namespace __gnu_test
33 {
34 #define PATH_CHK(p1, p2, fn) \
35     if ( p1.fn() != p2.fn() ) \
36       throw std::experimental::filesystem::filesystem_error( #fn, p1, p2, \
37 	  std::make_error_code(std::errc::invalid_argument) )
38 
39   void
compare_paths(const std::experimental::filesystem::path & p1,const std::experimental::filesystem::path & p2)40   compare_paths(const std::experimental::filesystem::path& p1,
41 		const std::experimental::filesystem::path& p2)
42   {
43     PATH_CHK( p1, p2, string );
44     PATH_CHK( p1, p2, empty );
45     PATH_CHK( p1, p2, has_root_path );
46     PATH_CHK( p1, p2, has_root_name );
47     PATH_CHK( p1, p2, has_root_directory );
48     PATH_CHK( p1, p2, has_relative_path );
49     PATH_CHK( p1, p2, has_parent_path );
50     PATH_CHK( p1, p2, has_filename );
51     PATH_CHK( p1, p2, has_stem );
52     PATH_CHK( p1, p2, has_extension );
53     PATH_CHK( p1, p2, is_absolute );
54     PATH_CHK( p1, p2, is_relative );
55     auto d1 = std::distance(p1.begin(), p1.end());
56     auto d2 = std::distance(p2.begin(), p2.end());
57     if( d1 != d2 )
58       throw std::experimental::filesystem::filesystem_error(
59 	  "distance(begin, end)", p1, p2,
60 	  std::make_error_code(std::errc::invalid_argument) );
61   }
62 
63   const std::string test_paths[] = {
64     "", "/", "//", "/.", "/./", "/a", "/a/", "/a//", "/a/b/c/d", "/a//b",
65     "a", "a/b", "a/b/", "a/b/c", "a/b/c.d", "a/b/..", "a/b/c.", "a/b/.c"
66   };
67 
68   // This is NOT supposed to be a secure way to get a unique name!
69   // We just need a path that doesn't exist for testing purposes.
70   std::experimental::filesystem::path
nonexistent_path()71   nonexistent_path()
72   {
73     std::experimental::filesystem::path p;
74 #if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
75     char tmp[] = "filesystem-ts-test.XXXXXX";
76     int fd = ::mkstemp(tmp);
77     if (fd == -1)
78       throw std::experimental::filesystem::filesystem_error("mkstemp failed",
79 	  std::error_code(errno, std::generic_category()));
80     ::unlink(tmp);
81     ::close(fd);
82     p = tmp;
83 #else
84     char buf[64];
85     static int counter;
86 #if _GLIBCXX_USE_C99_STDIO
87     std::snprintf(buf, 64,
88 #else
89     std::sprintf(buf,
90 #endif
91       "filesystem-ts-test.%d.%lu", counter++, (unsigned long) ::getpid());
92     p = buf;
93 #endif
94     return p;
95   }
96 
97   // RAII helper to remove a file on scope exit.
98   struct scoped_file
99   {
100     using path_type = std::experimental::filesystem::path;
101 
102     enum adopt_file_t { adopt_file };
103 
104     explicit
pathscoped_file105     scoped_file(const path_type& p = nonexistent_path()) : path(p)
106     { std::ofstream{p.native()}; }
107 
scoped_filescoped_file108     scoped_file(path_type p, adopt_file_t) : path(p) { }
109 
~scoped_filescoped_file110     ~scoped_file() { if (!path.empty()) remove(path); }
111 
112     path_type path;
113   };
114 
115 } // namespace __gnu_test
116 #endif
117