]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/testsuite/util/testsuite_fs.h
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / testsuite / util / testsuite_fs.h
CommitLineData
0ca7ba9a
JW
1// -*- C++ -*-
2// Filesystem utils for the C++ library testsuite.
3//
a945c346 4// Copyright (C) 2014-2024 Free Software Foundation, Inc.
0ca7ba9a
JW
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
641cb5a6
JW
25// Assume we want std::filesystem in C++17, unless USE_FILESYSTEM_TS defined:
26#if __cplusplus >= 201703L && ! defined USE_FILESYSTEM_TS
27#include <filesystem>
28namespace test_fs = std::filesystem;
29#else
0ca7ba9a 30#include <experimental/filesystem>
641cb5a6
JW
31namespace test_fs = std::experimental::filesystem;
32#endif
f9b22a0c 33#include <algorithm>
fd5effb1 34#include <fstream>
30a8f672 35#include <random> // std::random_device
0ca7ba9a 36#include <string>
30a8f672 37#include <system_error>
9caf7b27 38#include <cstdio>
29b2fd37 39#include <unistd.h> // unlink, close, getpid, geteuid
4179ec10
JW
40
41#if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
42#include <stdlib.h> // mkstemp
4179ec10 43#endif
0ca7ba9a 44
9f7f25bb
AO
45#ifndef _GLIBCXX_HAVE_SYMLINK
46#define NO_SYMLINKS
47#endif
48
b931c687
AO
49#if !defined (_GLIBCXX_HAVE_SYS_STATVFS_H) \
50 && !defined (_GLIBCXX_FILESYSTEM_IS_WINDOWS)
51#define NO_SPACE
52#endif
53
f01cf5ea
AO
54#if !(_GLIBCXX_HAVE_SYS_STAT_H \
55 && (_GLIBCXX_USE_UTIMENSAT || _GLIBCXX_USE_UTIME))
56#define NO_LAST_WRITE_TIME 1
57#endif
58
0ca7ba9a
JW
59namespace __gnu_test
60{
61#define PATH_CHK(p1, p2, fn) \
62 if ( p1.fn() != p2.fn() ) \
50e248f0 63 throw test_fs::filesystem_error("comparing '" #fn "' failed", p1, p2, \
0ca7ba9a
JW
64 std::make_error_code(std::errc::invalid_argument) )
65
66 void
641cb5a6
JW
67 compare_paths(const test_fs::path& p1,
68 const test_fs::path& p2)
0ca7ba9a 69 {
eeb517d3 70 PATH_CHK( p1, p2, native );
0ca7ba9a
JW
71 PATH_CHK( p1, p2, string );
72 PATH_CHK( p1, p2, empty );
73 PATH_CHK( p1, p2, has_root_path );
74 PATH_CHK( p1, p2, has_root_name );
75 PATH_CHK( p1, p2, has_root_directory );
76 PATH_CHK( p1, p2, has_relative_path );
77 PATH_CHK( p1, p2, has_parent_path );
78 PATH_CHK( p1, p2, has_filename );
79 PATH_CHK( p1, p2, has_stem );
80 PATH_CHK( p1, p2, has_extension );
81 PATH_CHK( p1, p2, is_absolute );
82 PATH_CHK( p1, p2, is_relative );
83 auto d1 = std::distance(p1.begin(), p1.end());
84 auto d2 = std::distance(p2.begin(), p2.end());
f9b22a0c 85 if (d1 != d2)
641cb5a6 86 throw test_fs::filesystem_error(
f9b22a0c 87 "distance(begin1, end1) != distance(begin2, end2)", p1, p2,
0ca7ba9a 88 std::make_error_code(std::errc::invalid_argument) );
d9b401df 89 if (!std::equal(p1.begin(), p1.end(), p2.begin()))
f9b22a0c 90 throw test_fs::filesystem_error(
d9b401df 91 "!equal(begin1, end1, begin2)", p1, p2,
f9b22a0c
JW
92 std::make_error_code(std::errc::invalid_argument) );
93
0ca7ba9a
JW
94 }
95
96 const std::string test_paths[] = {
97 "", "/", "//", "/.", "/./", "/a", "/a/", "/a//", "/a/b/c/d", "/a//b",
98 "a", "a/b", "a/b/", "a/b/c", "a/b/c.d", "a/b/..", "a/b/c.", "a/b/.c"
99 };
100
9534a5e6
JW
101 test_fs::path
102 root_path()
103 {
6a6f74be 104#if defined(__MINGW32__) || defined(__MINGW64__)
9534a5e6
JW
105 return L"c:/";
106#else
107 return "/";
108#endif
109 }
110
9caf7b27
JW
111 // This is NOT supposed to be a secure way to get a unique name!
112 // We just need a path that doesn't exist for testing purposes.
641cb5a6 113 test_fs::path
7c4979b2 114 nonexistent_path(std::string file = __builtin_FILE())
9caf7b27 115 {
7c4979b2
JW
116 // Include the caller's filename to help identify tests that fail to
117 // clean up the files they create.
118 // Remove .cc extension:
119 if (file.length() > 3 && file.compare(file.length() - 3, 3, ".cc") == 0)
120 file.resize(file.length() - 3);
121 // And directory:
122 auto pos = file.find_last_of("/\\");
123 if (pos != file.npos)
124 file.erase(0, pos+1);
125
30a8f672
JB
126 file.reserve(file.size() + 40);
127 file.insert(0, "filesystem-test.");
128
129 // A counter, starting from a random value, to be included as part
130 // of the filename being returned, and incremented each time
131 // this function is used. It allows us to ensure that two calls
132 // to this function can never return the same filename, something
133 // testcases do when they need multiple non-existent filenames
134 // for their purposes.
135 static unsigned counter = std::random_device{}();
136 file += '.';
137 file += std::to_string(counter++);
138 file += '.';
139
641cb5a6 140 test_fs::path p;
9caf7b27 141#if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
30a8f672
JB
142
143 // Use mkstemp to determine the name of a file which does not exist yet.
144 //
145 // Note that we have seen on some systems (such as RTEMS, for instance)
146 // that mkstemp behaves very predictably, causing it to always try
147 // the same sequence of file names. In other words, if we call mkstemp
148 // with a pattern, delete the file it created (which is what we do, here),
149 // and call mkstemp with the same pattern again, it returns the same
150 // filename once more. While most implementations introduce a degree
151 // of randomness, it is not mandated by the standard, and this is why
152 // we also include a counter in the template passed to mkstemp.
153 file += "XXXXXX";
154 int fd = ::mkstemp(&file[0]);
9caf7b27 155 if (fd == -1)
641cb5a6 156 throw test_fs::filesystem_error("mkstemp failed",
9caf7b27 157 std::error_code(errno, std::generic_category()));
30a8f672 158 ::unlink(file.c_str());
9caf7b27 159 ::close(fd);
30a8f672 160 p = std::move(file);
9caf7b27 161#else
7c4979b2
JW
162 if (file.length() > 64)
163 file.resize(64);
30a8f672 164 // The combination of random counter and PID should be unique for a given
bd2d0aab
AO
165 // run of the testsuite. N.B. getpid() returns a pointer type on vxworks
166 // in kernel mode.
b44cba35 167 file += std::to_string((unsigned long) ::getpid());
30a8f672
JB
168 p = std::move(file);
169 if (test_fs::exists(p))
170 throw test_fs::filesystem_error("Failed to generate unique pathname", p,
171 std::make_error_code(std::errc::file_exists));
9caf7b27
JW
172#endif
173 return p;
174 }
175
fd5effb1
JW
176 // RAII helper to remove a file on scope exit.
177 struct scoped_file
178 {
641cb5a6 179 using path_type = test_fs::path;
fd5effb1
JW
180
181 enum adopt_file_t { adopt_file };
182
183 explicit
184 scoped_file(const path_type& p = nonexistent_path()) : path(p)
9534a5e6 185 { std::ofstream{p.c_str()}; }
fd5effb1
JW
186
187 scoped_file(path_type p, adopt_file_t) : path(p) { }
188
ec04aad7 189 ~scoped_file() { if (!path.empty()) remove(path); }
fd5effb1 190
c7dde4a9
JW
191 scoped_file(scoped_file&&) = default;
192 scoped_file& operator=(scoped_file&&) = default;
193
fd5effb1
JW
194 path_type path;
195 };
196
bc97e736 197 inline bool
29b2fd37
JW
198 permissions_are_testable(bool print_msg = true)
199 {
200 bool testable = false;
201#if !(defined __MINGW32__ || defined __MINGW64__)
202 if (geteuid() != 0)
203 testable = true;
204 // XXX on Linux the CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH capabilities
205 // can give normal users extra permissions for files and directories.
206 // We ignore that possibility here.
207#endif
208 if (print_msg && !testable)
209 std::puts("Skipping tests that depend on filesystem permissions");
210 return testable;
211 }
212
0ca7ba9a
JW
213} // namespace __gnu_test
214#endif