|
| 1 | +#include <chrono> |
| 2 | +#include <cstdio> |
| 3 | +#include <filesystem> |
| 4 | +#include <fstream> |
| 5 | +#include <random> |
| 6 | +#include <string> |
| 7 | +#include <thread> |
| 8 | + |
| 9 | +#define ASSERT(condition) \ |
| 10 | + if (!(condition)) { \ |
| 11 | + fprintf(stderr, "%s:%d: test failed: %s\n", __FILE__, __LINE__, \ |
| 12 | + #condition); \ |
| 13 | + return 1; \ |
| 14 | + } |
| 15 | + |
| 16 | +namespace fs = std::filesystem; |
| 17 | + |
| 18 | +fs::path g_temp_path; |
| 19 | +fs::path g_orig_path; |
| 20 | +std::string g_tmpdir; |
| 21 | + |
| 22 | +void setup() { |
| 23 | + g_orig_path = fs::current_path(); |
| 24 | + fs::path temp_path = fs::temp_directory_path(); |
| 25 | + auto now = std::chrono::system_clock::now(); |
| 26 | + auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now); |
| 27 | + auto value = now_ms.time_since_epoch(); |
| 28 | + long duration = value.count(); |
| 29 | + std::random_device rd; |
| 30 | + std::mt19937 gen(rd()); |
| 31 | + std::uniform_int_distribution<> dis(0, 999999); |
| 32 | + int random_number = dis(gen); |
| 33 | + std::string dir_name = |
| 34 | + "temp_" + std::to_string(duration) + "_" + std::to_string(random_number); |
| 35 | + g_temp_path = temp_path / dir_name; |
| 36 | + fs::create_directory(g_temp_path); |
| 37 | + fs::current_path(g_temp_path); |
| 38 | + fs::create_directory("tmp"); |
| 39 | + g_tmpdir = fs::absolute("tmp"); |
| 40 | + setenv("TMPDIR", g_tmpdir.c_str(), true); |
| 41 | +} |
| 42 | + |
| 43 | +void teardown() { |
| 44 | + fs::current_path(g_orig_path); |
| 45 | + fs::remove_all(g_temp_path); |
| 46 | +} |
| 47 | + |
| 48 | +int test_create_directory() { |
| 49 | + fs::path dir = "test_dir"; |
| 50 | + ASSERT(fs::create_directory(dir)); |
| 51 | + ASSERT(fs::is_directory(dir)); |
| 52 | + ASSERT(!fs::create_directory(dir)); |
| 53 | + fs::remove(dir); |
| 54 | + return 0; |
| 55 | +} |
| 56 | + |
| 57 | +int test_create_directories() { |
| 58 | + fs::path dirs = "test_dir/nested/deep"; |
| 59 | + ASSERT(fs::create_directories(dirs)); |
| 60 | + ASSERT(fs::is_directory(dirs)); |
| 61 | + ASSERT(!fs::create_directories(dirs)); |
| 62 | + fs::remove_all("test_dir"); |
| 63 | + return 0; |
| 64 | +} |
| 65 | + |
| 66 | +int test_remove() { |
| 67 | + fs::path file = "test_file.txt"; |
| 68 | + std::ofstream(file).put('a'); |
| 69 | + ASSERT(fs::remove(file)); |
| 70 | + ASSERT(!fs::remove(file)); |
| 71 | + return 0; |
| 72 | +} |
| 73 | + |
| 74 | +int test_remove_all() { |
| 75 | + fs::path dir = "test_dir/nested/deep"; |
| 76 | + fs::create_directories(dir); |
| 77 | + ASSERT(fs::remove_all("test_dir") > 0); |
| 78 | + ASSERT(fs::remove_all("test_dir") == 0); |
| 79 | + return 0; |
| 80 | +} |
| 81 | + |
| 82 | +int test_rename() { |
| 83 | + fs::path old_name = "old.txt"; |
| 84 | + fs::path new_name = "new.txt"; |
| 85 | + std::ofstream(old_name).put('a'); |
| 86 | + fs::rename(old_name, new_name); |
| 87 | + ASSERT(!fs::exists(old_name)); |
| 88 | + ASSERT(fs::exists(new_name)); |
| 89 | + fs::remove(new_name); |
| 90 | + return 0; |
| 91 | +} |
| 92 | + |
| 93 | +int test_copy() { |
| 94 | + fs::path src = "src.txt"; |
| 95 | + fs::path dst = "dst.txt"; |
| 96 | + std::ofstream(src) << "test"; |
| 97 | + fs::copy(src, dst); |
| 98 | + ASSERT(fs::exists(dst)); |
| 99 | + ASSERT(fs::file_size(src) == fs::file_size(dst)); |
| 100 | + fs::remove(src); |
| 101 | + fs::remove(dst); |
| 102 | + return 0; |
| 103 | +} |
| 104 | + |
| 105 | +int test_copy_file() { |
| 106 | + fs::path src = "src.txt"; |
| 107 | + fs::path dst = "dst.txt"; |
| 108 | + std::ofstream(src) << "test"; |
| 109 | + ASSERT(fs::copy_file(src, dst)); |
| 110 | + ASSERT(!fs::copy_file(src, dst, fs::copy_options::skip_existing)); |
| 111 | + fs::remove(src); |
| 112 | + fs::remove(dst); |
| 113 | + return 0; |
| 114 | +} |
| 115 | + |
| 116 | +int test_exists() { |
| 117 | + fs::path file = "test.txt"; |
| 118 | + ASSERT(!fs::exists(file)); |
| 119 | + std::ofstream(file).put('a'); |
| 120 | + ASSERT(fs::exists(file)); |
| 121 | + fs::remove(file); |
| 122 | + return 0; |
| 123 | +} |
| 124 | + |
| 125 | +int test_is_regular_file() { |
| 126 | + fs::path file = "test.txt"; |
| 127 | + fs::path dir = "test_dir"; |
| 128 | + std::ofstream(file).put('a'); |
| 129 | + fs::create_directory(dir); |
| 130 | + ASSERT(fs::is_regular_file(file)); |
| 131 | + ASSERT(!fs::is_regular_file(dir)); |
| 132 | + fs::remove(file); |
| 133 | + fs::remove(dir); |
| 134 | + return 0; |
| 135 | +} |
| 136 | + |
| 137 | +int test_is_directory() { |
| 138 | + fs::path file = "test.txt"; |
| 139 | + fs::path dir = "test_dir"; |
| 140 | + std::ofstream(file).put('a'); |
| 141 | + fs::create_directory(dir); |
| 142 | + ASSERT(!fs::is_directory(file)); |
| 143 | + ASSERT(fs::is_directory(dir)); |
| 144 | + fs::remove(file); |
| 145 | + fs::remove(dir); |
| 146 | + return 0; |
| 147 | +} |
| 148 | + |
| 149 | +int test_is_symlink() { |
| 150 | + fs::path file = "test.txt"; |
| 151 | + fs::path link = "test_link"; |
| 152 | + std::ofstream(file).put('a'); |
| 153 | + fs::create_symlink(file, link); |
| 154 | + ASSERT(!fs::is_symlink(file)); |
| 155 | + ASSERT(fs::is_symlink(link)); |
| 156 | + fs::remove(file); |
| 157 | + fs::remove(link); |
| 158 | + return 0; |
| 159 | +} |
| 160 | + |
| 161 | +int test_file_size() { |
| 162 | + fs::path file = "test.txt"; |
| 163 | + std::ofstream(file) << "test"; |
| 164 | + ASSERT(fs::file_size(file) == 4); |
| 165 | + fs::remove(file); |
| 166 | + return 0; |
| 167 | +} |
| 168 | + |
| 169 | +int test_last_write_time() { |
| 170 | + fs::path file = "test.txt"; |
| 171 | + auto now = fs::file_time_type::clock::now(); |
| 172 | + std::ofstream(file).put('a'); |
| 173 | + fs::last_write_time(file, now); |
| 174 | + ASSERT(fs::last_write_time(file) == now); |
| 175 | + fs::remove(file); |
| 176 | + return 0; |
| 177 | +} |
| 178 | + |
| 179 | +int test_permissions() { |
| 180 | + fs::path file = "test.txt"; |
| 181 | + std::ofstream(file).put('a'); |
| 182 | + fs::permissions(file, fs::perms::owner_read | fs::perms::owner_write); |
| 183 | + auto perms = fs::status(file).permissions(); |
| 184 | + ASSERT((perms & fs::perms::owner_read) != fs::perms::none); |
| 185 | + ASSERT((perms & fs::perms::owner_write) != fs::perms::none); |
| 186 | + ASSERT((perms & fs::perms::owner_exec) == fs::perms::none); |
| 187 | + fs::remove(file); |
| 188 | + return 0; |
| 189 | +} |
| 190 | + |
| 191 | +int test_current_path() { |
| 192 | + auto original_path = fs::current_path(); |
| 193 | + fs::path new_path = fs::temp_directory_path(); |
| 194 | + fs::current_path(new_path); |
| 195 | + ASSERT(fs::current_path() == new_path); |
| 196 | + fs::current_path(original_path); |
| 197 | + return 0; |
| 198 | +} |
| 199 | + |
| 200 | +int test_absolute() { |
| 201 | + fs::path relative = "test.txt"; |
| 202 | + auto abs_path = fs::absolute(relative); |
| 203 | + ASSERT(abs_path.is_absolute()); |
| 204 | + return 0; |
| 205 | +} |
| 206 | + |
| 207 | +int test_canonical() { |
| 208 | + fs::path dir = "test_dir"; |
| 209 | + fs::path file = dir / "test.txt"; |
| 210 | + fs::create_directories(dir); |
| 211 | + std::ofstream(file).put('a'); |
| 212 | + auto can_path = fs::canonical(file); |
| 213 | + ASSERT(can_path.is_absolute()); |
| 214 | + ASSERT(!can_path.lexically_normal().string().empty()); |
| 215 | + fs::remove_all(dir); |
| 216 | + return 0; |
| 217 | +} |
| 218 | + |
| 219 | +int test_read_symlink() { |
| 220 | + fs::path file = "test.txt"; |
| 221 | + fs::path link = "test_link"; |
| 222 | + std::ofstream(file).put('a'); |
| 223 | + fs::create_symlink(file, link); |
| 224 | + ASSERT(fs::read_symlink(link) == file); |
| 225 | + fs::remove(file); |
| 226 | + fs::remove(link); |
| 227 | + return 0; |
| 228 | +} |
| 229 | + |
| 230 | +int test_create_symlink_and_hard_link() { |
| 231 | + fs::path file = "test.txt"; |
| 232 | + fs::path symlink = "test_symlink"; |
| 233 | + fs::path hardlink = "test_hardlink"; |
| 234 | + std::ofstream(file).put('a'); |
| 235 | + fs::create_symlink(file, symlink); |
| 236 | + fs::create_hard_link(file, hardlink); |
| 237 | + ASSERT(fs::exists(symlink)); |
| 238 | + ASSERT(fs::exists(hardlink)); |
| 239 | + ASSERT(fs::is_symlink(symlink)); |
| 240 | + ASSERT(!fs::is_symlink(hardlink)); |
| 241 | + fs::remove(file); |
| 242 | + fs::remove(symlink); |
| 243 | + fs::remove(hardlink); |
| 244 | + return 0; |
| 245 | +} |
| 246 | + |
| 247 | +int test_space() { |
| 248 | + auto space_info = fs::space("."); |
| 249 | + ASSERT(space_info.capacity > 0); |
| 250 | + ASSERT(space_info.free > 0); |
| 251 | + ASSERT(space_info.available > 0); |
| 252 | + return 0; |
| 253 | +} |
| 254 | + |
| 255 | +int test_equivalent() { |
| 256 | + fs::path file1 = "test1.txt"; |
| 257 | + fs::path file2 = "test2.txt"; |
| 258 | + std::ofstream(file1).put('a'); |
| 259 | + fs::create_hard_link(file1, file2); |
| 260 | + ASSERT(fs::equivalent(file1, file2)); |
| 261 | + fs::remove(file1); |
| 262 | + fs::remove(file2); |
| 263 | + return 0; |
| 264 | +} |
| 265 | + |
| 266 | +int test_resize_file() { |
| 267 | + fs::path file = "test.txt"; |
| 268 | + std::ofstream(file) << "test"; |
| 269 | + fs::resize_file(file, 10); |
| 270 | + ASSERT(fs::file_size(file) == 10); |
| 271 | + fs::remove(file); |
| 272 | + return 0; |
| 273 | +} |
| 274 | + |
| 275 | +int test_status() { |
| 276 | + fs::path file = "test.txt"; |
| 277 | + std::ofstream(file).put('a'); |
| 278 | + auto status = fs::status(file); |
| 279 | + ASSERT(status.type() == fs::file_type::regular); |
| 280 | + fs::remove(file); |
| 281 | + return 0; |
| 282 | +} |
| 283 | + |
| 284 | +int test_copy_enoent() { |
| 285 | + fs::path src = "non_existent_file.txt"; |
| 286 | + fs::path dst = "destination.txt"; |
| 287 | + try { |
| 288 | + fs::copy(src, dst); |
| 289 | + ASSERT(false); |
| 290 | + } catch (const fs::filesystem_error& e) { |
| 291 | + if (e.code() == std::errc::no_such_file_or_directory) { |
| 292 | + return 0; |
| 293 | + } else { |
| 294 | + ASSERT(false); |
| 295 | + } |
| 296 | + } catch (const std::exception& e) { |
| 297 | + ASSERT(false); |
| 298 | + } |
| 299 | +} |
| 300 | + |
| 301 | +#define RUN(func) \ |
| 302 | + result = func(); \ |
| 303 | + if (result) \ |
| 304 | + return result |
| 305 | + |
| 306 | +int test() { |
| 307 | + int result = 0; |
| 308 | + RUN(test_copy_enoent); |
| 309 | + RUN(test_create_directory); |
| 310 | + RUN(test_create_directories); |
| 311 | + RUN(test_remove); |
| 312 | + RUN(test_remove_all); |
| 313 | + RUN(test_rename); |
| 314 | + RUN(test_copy); |
| 315 | + RUN(test_copy_file); |
| 316 | + RUN(test_exists); |
| 317 | + RUN(test_is_regular_file); |
| 318 | + RUN(test_is_directory); |
| 319 | + RUN(test_is_symlink); |
| 320 | + RUN(test_file_size); |
| 321 | + RUN(test_last_write_time); |
| 322 | + RUN(test_permissions); |
| 323 | + RUN(test_current_path); |
| 324 | + RUN(test_absolute); |
| 325 | + RUN(test_canonical); |
| 326 | + RUN(test_read_symlink); |
| 327 | + RUN(test_create_symlink_and_hard_link); |
| 328 | + RUN(test_space); |
| 329 | + RUN(test_equivalent); |
| 330 | + RUN(test_resize_file); |
| 331 | + RUN(test_status); |
| 332 | + return 0; |
| 333 | +} |
| 334 | + |
| 335 | +int main() { |
| 336 | + int rc; |
| 337 | + setup(); |
| 338 | + rc = test(); |
| 339 | + teardown(); |
| 340 | + return rc; |
| 341 | +} |
0 commit comments