]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost operations_test.cpp ---------------------------------------------------------// |
2 | ||
3 | // Copyright Beman Dawes 2002, 2009. | |
4 | ||
5 | // Distributed under the Boost Software License, Version 1.0. | |
6 | // See http://www.boost.org/LICENSE_1_0.txt | |
7 | ||
8 | // Library home page: http://www.boost.org/libs/filesystem | |
9 | ||
10 | #include <boost/config/warning_disable.hpp> | |
11 | ||
12 | // See deprecated_test for tests of deprecated features | |
92f5a8d4 | 13 | #ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
7c673cae FG |
14 | # define BOOST_FILESYSTEM_NO_DEPRECATED |
15 | #endif | |
92f5a8d4 | 16 | #ifndef BOOST_SYSTEM_NO_DEPRECATED |
7c673cae FG |
17 | # define BOOST_SYSTEM_NO_DEPRECATED |
18 | #endif | |
19 | ||
20 | #include <boost/filesystem/operations.hpp> | |
92f5a8d4 TL |
21 | #include <boost/filesystem/directory.hpp> |
22 | #include <boost/filesystem/exception.hpp> | |
23 | #include <boost/filesystem/file_status.hpp> | |
7c673cae FG |
24 | |
25 | #include <boost/config.hpp> | |
26 | # if defined( BOOST_NO_STD_WSTRING ) | |
27 | # error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support | |
28 | # endif | |
29 | ||
30 | #include <boost/cerrno.hpp> | |
f67539c2 | 31 | #include <boost/core/lightweight_test.hpp> |
7c673cae FG |
32 | #include <boost/detail/lightweight_main.hpp> |
33 | ||
34 | namespace fs = boost::filesystem; | |
35 | using boost::system::error_code; | |
36 | using boost::system::system_category; | |
37 | using boost::system::system_error; | |
38 | ||
39 | #include <fstream> | |
40 | #include <iostream> | |
41 | ||
42 | using std::cout; | |
43 | using std::endl; | |
44 | ||
45 | #include <string> | |
46 | #include <vector> | |
47 | #include <algorithm> | |
48 | #include <cstring> // for strncmp, etc. | |
49 | #include <ctime> | |
50 | #include <cstdlib> // for system(), getenv(), etc. | |
51 | ||
52 | #ifdef BOOST_WINDOWS_API | |
53 | # include <windows.h> | |
54 | ||
55 | inline std::wstring convert(const char* c) | |
56 | { | |
57 | std::string s(c); | |
92f5a8d4 | 58 | |
7c673cae FG |
59 | return std::wstring(s.begin(), s.end()); |
60 | } | |
61 | ||
7c673cae FG |
62 | // Note: these three setenv* functions are not general solutions for the missing |
63 | // setenv* problem on VC++. See Microsoft's _putenv for that need, and ticker #7018 | |
64 | // for discussion and rationale for returning void for this test program, which needs | |
65 | // to work for both the MSVC Runtime and the Windows Runtime (which does not support | |
66 | // _putenv). | |
67 | ||
11fdf7f2 | 68 | inline void setenv_(const char* name, const fs::path::value_type* val, int) |
7c673cae | 69 | { |
11fdf7f2 | 70 | SetEnvironmentVariableW(convert(name).c_str(), val); |
7c673cae FG |
71 | } |
72 | ||
11fdf7f2 | 73 | inline void setenv_(const char* name, const char* val, int) |
7c673cae | 74 | { |
11fdf7f2 | 75 | SetEnvironmentVariableW(convert(name).c_str(), convert(val).c_str()); |
7c673cae FG |
76 | } |
77 | ||
11fdf7f2 | 78 | inline void unsetenv_(const char* name) |
92f5a8d4 | 79 | { |
11fdf7f2 | 80 | SetEnvironmentVariableW(convert(name).c_str(), 0); |
7c673cae | 81 | } |
7c673cae FG |
82 | |
83 | #else | |
84 | ||
85 | #include <stdlib.h> // allow unqualifed calls to env funcs on SunOS | |
86 | ||
11fdf7f2 TL |
87 | inline void setenv_(const char* name, const char* val, int ovw) |
88 | { | |
89 | setenv(name, val, ovw); | |
90 | } | |
91 | ||
92 | inline void unsetenv_(const char* name) | |
93 | { | |
94 | unsetenv(name); | |
95 | } | |
96 | ||
7c673cae FG |
97 | #endif |
98 | ||
99 | // on Windows, except for standard libaries known to have wchar_t overloads for | |
100 | // file stream I/O, use path::string() to get a narrow character c_str() | |
101 | #if defined(BOOST_WINDOWS_API) \ | |
102 | && (!defined(_CPPLIB_VER) || _CPPLIB_VER < 405) // not Dinkumware || no wide overloads | |
103 | # define BOOST_FILESYSTEM_C_STR string().c_str() // use narrow, since wide not available | |
104 | #else // use the native c_str, which will be narrow on POSIX, wide on Windows | |
105 | # define BOOST_FILESYSTEM_C_STR c_str() | |
106 | #endif | |
107 | ||
108 | #define CHECK_EXCEPTION(Functor,Expect) throws_fs_error(Functor,Expect,__LINE__) | |
109 | ||
110 | namespace | |
111 | { | |
112 | typedef int errno_t; | |
113 | std::string platform(BOOST_PLATFORM); | |
114 | bool report_throws = false; | |
115 | bool cleanup = true; | |
116 | bool skip_long_windows_tests = false; | |
117 | ||
118 | fs::directory_iterator end_itr; | |
119 | fs::path dir; | |
120 | fs::path d1; | |
121 | fs::path d2; | |
122 | fs::path f0; | |
123 | fs::path f1; | |
124 | fs::path d1f1; | |
125 | ||
126 | bool create_symlink_ok(true); | |
127 | ||
128 | fs::path ng(" no-way, Jose"); | |
129 | ||
130 | unsigned short language_id; // 0 except for Windows | |
131 | ||
132 | const fs::path temp_dir(fs::unique_path("op-test-%%%%-%%%%")); | |
133 | ||
134 | void create_file(const fs::path & ph, const std::string & contents = std::string()) | |
135 | { | |
136 | std::ofstream f(ph.BOOST_FILESYSTEM_C_STR); | |
137 | if (!f) | |
138 | throw fs::filesystem_error("operations_test create_file", | |
139 | ph, error_code(errno, system_category())); | |
140 | if (!contents.empty()) f << contents; | |
141 | } | |
142 | ||
143 | void verify_file(const fs::path & ph, const std::string & expected) | |
144 | { | |
145 | std::ifstream f(ph.BOOST_FILESYSTEM_C_STR); | |
146 | if (!f) | |
147 | throw fs::filesystem_error("operations_test verify_file", | |
148 | ph, error_code(errno, system_category())); | |
149 | std::string contents; | |
150 | f >> contents; | |
151 | if (contents != expected) | |
152 | throw fs::filesystem_error("operations_test verify_file contents \"" | |
153 | + contents + "\" != \"" + expected + "\"", ph, error_code()); | |
154 | } | |
155 | ||
156 | template< typename F > | |
157 | bool throws_fs_error(F func, errno_t en, int line) | |
158 | { | |
159 | try { func(); } | |
160 | ||
161 | catch (const fs::filesystem_error & ex) | |
162 | { | |
163 | if (report_throws) | |
164 | { | |
165 | // use the what() convenience function to display exceptions | |
166 | cout << "\n" << ex.what() << "\n"; | |
167 | } | |
168 | if (en == 0 | |
169 | || en == ex.code().default_error_condition().value()) return true; | |
170 | cout | |
171 | << "\nWarning: line " << line | |
172 | << " exception reports default_error_condition().value() " | |
173 | << ex.code().default_error_condition().value() | |
174 | << ", should be " << en | |
175 | << "\n value() is " << ex.code().value() | |
176 | << endl; | |
177 | return true; | |
178 | } | |
179 | return false; | |
180 | } | |
181 | ||
92f5a8d4 TL |
182 | struct poison_category_impl: public boost::system::error_category |
183 | { | |
184 | char const * name() const BOOST_NOEXCEPT { return "poison"; } | |
185 | std::string message( int ) const { return "poison_category::message"; } | |
186 | }; | |
187 | ||
188 | boost::system::error_category& poison_category() | |
189 | { | |
190 | static poison_category_impl instance; | |
191 | return instance; | |
192 | } | |
7c673cae FG |
193 | |
194 | // compile-only two argument "do-the-right-thing" tests | |
195 | // verifies that all overload combinations compile without error | |
196 | void do_the_right_thing_tests(bool call_ = false) | |
197 | { | |
198 | if (call_) | |
199 | { | |
200 | fs::path p; | |
201 | std::string s; | |
202 | const char* a = 0; | |
203 | fs::copy_file(p, p); | |
204 | fs::copy_file(s, p); | |
205 | fs::copy_file(a, p); | |
206 | fs::copy_file(p, s); | |
207 | fs::copy_file(p, a); | |
208 | fs::copy_file(s, s); | |
209 | fs::copy_file(a, s); | |
210 | fs::copy_file(s, a); | |
211 | fs::copy_file(a, a); | |
212 | } | |
213 | } | |
214 | ||
215 | void bad_file_size() | |
216 | { | |
217 | fs::file_size(" No way, Jose"); | |
218 | } | |
92f5a8d4 | 219 | |
7c673cae FG |
220 | void bad_directory_size() |
221 | { | |
222 | fs::file_size(fs::current_path()); | |
223 | } | |
92f5a8d4 | 224 | |
7c673cae FG |
225 | fs::path bad_create_directory_path; |
226 | void bad_create_directory() | |
227 | { | |
228 | fs::create_directory(bad_create_directory_path); | |
229 | } | |
92f5a8d4 | 230 | |
7c673cae FG |
231 | void bad_equivalent() |
232 | { | |
233 | fs::equivalent("no-such-path", "another-not-present-path"); | |
234 | } | |
235 | ||
236 | fs::path bad_remove_dir; | |
237 | void bad_remove() | |
238 | { | |
239 | fs::remove(bad_remove_dir); | |
240 | } | |
241 | ||
242 | class renamer | |
243 | { | |
244 | public: | |
245 | renamer(const fs::path & p1, const fs::path & p2) | |
246 | : from(p1), to(p2) {} | |
247 | void operator()() | |
248 | { | |
249 | fs::rename(from, to); | |
250 | } | |
251 | private: | |
252 | fs::path from; | |
253 | fs::path to; | |
254 | }; | |
255 | ||
256 | //------------------------------ debugging aids --------------------------------------// | |
257 | ||
258 | //std::ostream& operator<<(std::ostream& os, const fs::file_status& s) | |
259 | //{ | |
260 | // if (s.type() == fs::status_error) { os << "status_error"; } | |
261 | // else if (s.type() == fs::file_not_found) { os << "file_not_found"; } | |
262 | // else if (s.type() == fs::regular_file) { os << "regular_file"; } | |
263 | // else if (s.type() == fs::directory_file) { os << "directory_file"; } | |
264 | // else if (s.type() == fs::symlink_file) { os << "symlink_file"; } | |
265 | // else if (s.type() == fs::block_file) { os << "block_file"; } | |
266 | // else if (s.type() == fs::character_file) { os << "character_file"; } | |
267 | // else if (s.type() == fs::fifo_file) { os << "fifo_file"; } | |
268 | // else if (s.type() == fs::socket_file) { os << "socket_file"; } | |
269 | // else if (s.type() == fs::reparse_file) { os << "reparse_file"; } | |
270 | // else if (s.type() == fs::type_unknown) { os << "type_unknown"; } | |
271 | // else { os << "_detail_directory_symlink"; } | |
272 | // return os; | |
273 | //} | |
274 | ||
275 | //void dump_tree(const fs::path & root) | |
276 | //{ | |
277 | // cout << "dumping tree rooted at " << root << endl; | |
92f5a8d4 | 278 | // for (fs::recursive_directory_iterator it (root, fs::directory_options::follow_directory_symlink); |
7c673cae FG |
279 | // it != fs::recursive_directory_iterator(); |
280 | // ++it) | |
281 | // { | |
282 | // for (int i = 0; i <= it.level(); ++i) | |
283 | // cout << " "; | |
284 | ||
285 | // cout << it->path(); | |
286 | // if (fs::is_symlink(it->path())) | |
287 | // { | |
288 | // cout << " [symlink]" << endl; | |
289 | // } | |
290 | // else | |
291 | // cout << endl; | |
292 | // } | |
293 | //} | |
294 | ||
295 | // exception_tests() ---------------------------------------------------------------// | |
296 | ||
92f5a8d4 TL |
297 | #if defined(BOOST_GCC) && BOOST_GCC >= 80000 |
298 | #pragma GCC diagnostic push | |
299 | // catching polymorphic type "X" by value - that's the intention of the test | |
300 | #pragma GCC diagnostic ignored "-Wcatch-value" | |
301 | #endif | |
302 | ||
7c673cae FG |
303 | void exception_tests() |
304 | { | |
305 | cout << "exception_tests..." << endl; | |
306 | bool exception_thrown; | |
307 | ||
308 | // catch runtime_error by value | |
309 | ||
310 | cout << " catch runtime_error by value" << endl; | |
311 | exception_thrown = false; | |
312 | try | |
313 | { | |
314 | fs::create_directory("no-such-dir/foo/bar"); | |
315 | } | |
316 | catch (std::runtime_error x) | |
317 | { | |
318 | exception_thrown = true; | |
319 | if (report_throws) cout << x.what() << endl; | |
320 | if (platform == "Windows" && language_id == 0x0409) // English (United States) | |
321 | // the stdcxx standard library apparently appends additional info | |
92f5a8d4 | 322 | // to what(), so check only the initial portion: |
7c673cae FG |
323 | BOOST_TEST(std::strncmp(x.what(), |
324 | "boost::filesystem::create_directory", | |
325 | sizeof("boost::filesystem::create_directory")-1) == 0); | |
326 | } | |
327 | BOOST_TEST(exception_thrown); | |
328 | ||
329 | // catch system_error by value | |
330 | ||
331 | cout << " catch system_error by value" << endl; | |
332 | exception_thrown = false; | |
333 | try | |
334 | { | |
335 | fs::create_directory("no-such-dir/foo/bar"); | |
336 | } | |
337 | catch (system_error x) | |
338 | { | |
339 | exception_thrown = true; | |
340 | if (report_throws) cout << x.what() << endl; | |
341 | if (platform == "Windows" && language_id == 0x0409) // English (United States) | |
342 | BOOST_TEST(std::strcmp(x.what(), | |
343 | "boost::filesystem::create_directory: The system cannot find the path specified") == 0); | |
344 | } | |
345 | BOOST_TEST(exception_thrown); | |
346 | ||
347 | // catch filesystem_error by value | |
348 | ||
349 | cout << " catch filesystem_error by value" << endl; | |
350 | exception_thrown = false; | |
351 | try | |
352 | { | |
353 | fs::create_directory("no-such-dir/foo/bar"); | |
354 | } | |
355 | catch (fs::filesystem_error x) | |
356 | { | |
357 | exception_thrown = true; | |
358 | if (report_throws) cout << x.what() << endl; | |
359 | if (platform == "Windows" && language_id == 0x0409) // English (United States) | |
360 | { | |
361 | bool ok (std::strcmp(x.what(), | |
362 | "boost::filesystem::create_directory: The system cannot find the path specified: \"no-such-dir/foo/bar\"") == 0); | |
363 | BOOST_TEST(ok); | |
364 | if (!ok) | |
365 | { | |
366 | cout << "what returns \"" << x.what() << "\"" << endl; | |
367 | } | |
368 | } | |
369 | } | |
370 | BOOST_TEST(exception_thrown); | |
371 | ||
372 | // catch filesystem_error by const reference | |
373 | ||
374 | cout << " catch filesystem_error by const reference" << endl; | |
375 | exception_thrown = false; | |
376 | try | |
377 | { | |
378 | fs::create_directory("no-such-dir/foo/bar"); | |
379 | } | |
92f5a8d4 | 380 | catch (const fs::filesystem_error& x) |
7c673cae FG |
381 | { |
382 | exception_thrown = true; | |
383 | if (report_throws) cout << x.what() << endl; | |
384 | if (platform == "Windows" && language_id == 0x0409) // English (United States) | |
385 | { | |
386 | bool ok (std::strcmp(x.what(), | |
387 | "boost::filesystem::create_directory: The system cannot find the path specified: \"no-such-dir/foo/bar\"") == 0); | |
388 | BOOST_TEST(ok); | |
389 | if (!ok) | |
390 | { | |
391 | cout << "what returns \"" << x.what() << "\"" << endl; | |
392 | } | |
393 | } | |
394 | } | |
395 | BOOST_TEST(exception_thrown); | |
396 | ||
397 | // the bound functions should throw, so CHECK_EXCEPTION() should return true | |
398 | ||
399 | BOOST_TEST(CHECK_EXCEPTION(bad_file_size, ENOENT)); | |
400 | ||
401 | if (platform == "Windows") | |
402 | BOOST_TEST(CHECK_EXCEPTION(bad_directory_size, ENOENT)); | |
403 | else | |
404 | BOOST_TEST(CHECK_EXCEPTION(bad_directory_size, 0)); | |
405 | ||
406 | // test path::exception members | |
92f5a8d4 TL |
407 | try |
408 | { | |
409 | fs::file_size(ng); // will throw | |
410 | } | |
411 | catch (fs::filesystem_error& ex) | |
7c673cae FG |
412 | { |
413 | BOOST_TEST(ex.path1().string() == " no-way, Jose"); | |
414 | } | |
415 | ||
416 | cout << " exception_tests complete" << endl; | |
417 | } | |
418 | ||
92f5a8d4 TL |
419 | #if defined(BOOST_GCC) && BOOST_GCC >= 80000 |
420 | #pragma GCC diagnostic pop | |
421 | #endif | |
422 | ||
7c673cae FG |
423 | // create a directory tree that can be used by subsequent tests ---------------------// |
424 | // | |
425 | // dir | |
426 | // d1 | |
427 | // d1f1 // an empty file | |
428 | // f0 // an empty file | |
429 | // f1 // a file containing "file-f1" | |
92f5a8d4 | 430 | |
7c673cae FG |
431 | void create_tree() |
432 | { | |
433 | cout << "creating test directories and files in " << dir << endl; | |
434 | ||
435 | // create directory d1 | |
436 | BOOST_TEST(!fs::create_directory(dir)); | |
437 | BOOST_TEST(!fs::is_symlink(dir)); | |
438 | BOOST_TEST(!fs::is_symlink("nosuchfileordirectory")); | |
439 | d1 = dir / "d1"; | |
440 | BOOST_TEST(fs::create_directory(d1)); | |
441 | BOOST_TEST(fs::exists(d1)); | |
442 | BOOST_TEST(fs::is_directory(d1)); | |
443 | BOOST_TEST(fs::is_empty(d1)); | |
444 | ||
445 | // create an empty file named "d1f1" | |
446 | d1f1 = d1 / "d1f1"; | |
447 | create_file(d1f1, ""); | |
448 | BOOST_TEST(fs::exists(d1f1)); | |
449 | BOOST_TEST(!fs::is_directory(d1f1)); | |
450 | BOOST_TEST(fs::is_regular_file(d1f1)); | |
451 | BOOST_TEST(fs::is_empty(d1f1)); | |
452 | BOOST_TEST(fs::file_size(d1f1) == 0); | |
453 | BOOST_TEST(fs::hard_link_count(d1f1) == 1); | |
454 | ||
455 | // create an empty file named "f0" | |
456 | f0 = dir / "f0"; | |
457 | create_file(f0, ""); | |
458 | BOOST_TEST(fs::exists(f0)); | |
459 | BOOST_TEST(!fs::is_directory(f0)); | |
460 | BOOST_TEST(fs::is_regular_file(f0)); | |
461 | BOOST_TEST(fs::is_empty(f0)); | |
462 | BOOST_TEST(fs::file_size(f0) == 0); | |
463 | BOOST_TEST(fs::hard_link_count(f0) == 1); | |
464 | ||
465 | // create a file named "f1" | |
466 | f1 = dir / "f1"; | |
467 | create_file(f1, "file-f1"); | |
468 | BOOST_TEST(fs::exists(f1)); | |
469 | BOOST_TEST(!fs::is_directory(f1)); | |
470 | BOOST_TEST(fs::is_regular_file(f1)); | |
471 | BOOST_TEST(fs::file_size(f1) == 7); | |
472 | verify_file(f1, "file-f1"); | |
473 | } | |
474 | ||
475 | // directory_iterator_tests --------------------------------------------------------// | |
476 | ||
477 | void directory_iterator_tests() | |
478 | { | |
479 | cout << "directory_iterator_tests..." << endl; | |
480 | ||
481 | bool dir_itr_exception(false); | |
482 | try { fs::directory_iterator it(""); } | |
483 | catch (const fs::filesystem_error &) { dir_itr_exception = true; } | |
484 | BOOST_TEST(dir_itr_exception); | |
485 | ||
486 | error_code ec; | |
487 | ||
488 | BOOST_TEST(!ec); | |
489 | fs::directory_iterator it("", ec); | |
490 | BOOST_TEST(ec); | |
491 | ||
492 | dir_itr_exception = false; | |
493 | try { fs::directory_iterator itx("nosuchdirectory"); } | |
494 | catch (const fs::filesystem_error &) { dir_itr_exception = true; } | |
495 | BOOST_TEST(dir_itr_exception); | |
496 | ||
497 | ec.clear(); | |
498 | fs::directory_iterator it2x("nosuchdirectory", ec); | |
499 | BOOST_TEST(ec); | |
500 | ||
501 | dir_itr_exception = false; | |
502 | try | |
503 | { | |
504 | error_code ecx; | |
505 | fs::directory_iterator itx("nosuchdirectory", ecx); | |
506 | BOOST_TEST(ecx); | |
507 | BOOST_TEST(ecx == boost::system::errc::no_such_file_or_directory); | |
508 | } | |
509 | catch (const fs::filesystem_error &) { dir_itr_exception = true; } | |
510 | BOOST_TEST(!dir_itr_exception); | |
92f5a8d4 | 511 | |
7c673cae FG |
512 | // create a second directory named d2 |
513 | d2 = dir / "d2"; | |
514 | fs::create_directory(d2); | |
515 | BOOST_TEST(fs::exists(d2)); | |
516 | BOOST_TEST(fs::is_directory(d2)); | |
517 | ||
518 | // test the basic operation of directory_iterators, and test that | |
519 | // stepping one iterator doesn't affect a different iterator. | |
520 | { | |
521 | typedef std::vector<fs::directory_entry> vec_type; | |
522 | vec_type vec; | |
523 | ||
524 | fs::directory_iterator it1(dir); | |
525 | BOOST_TEST(it1 != fs::directory_iterator()); | |
526 | BOOST_TEST(fs::exists(it1->status())); | |
527 | vec.push_back(*it1); | |
528 | BOOST_TEST(*it1 == vec[0]); | |
529 | ||
530 | fs::directory_iterator it2(dir); | |
531 | BOOST_TEST(it2 != fs::directory_iterator()); | |
532 | BOOST_TEST(*it1 == *it2); | |
533 | ||
534 | ++it1; | |
535 | BOOST_TEST(it1 != fs::directory_iterator()); | |
536 | BOOST_TEST(fs::exists(it1->status())); | |
537 | BOOST_TEST(it1 != it2); | |
538 | BOOST_TEST(*it1 != vec[0]); | |
539 | BOOST_TEST(*it2 == vec[0]); | |
540 | vec.push_back(*it1); | |
541 | ||
542 | ++it1; | |
543 | BOOST_TEST(it1 != fs::directory_iterator()); | |
544 | BOOST_TEST(fs::exists(it1->status())); | |
545 | BOOST_TEST(it1 != it2); | |
546 | BOOST_TEST(*it2 == vec[0]); | |
547 | vec.push_back(*it1); | |
548 | ||
549 | ++it1; | |
550 | BOOST_TEST(it1 != fs::directory_iterator()); | |
551 | BOOST_TEST(fs::exists(it1->status())); | |
552 | BOOST_TEST(it1 != it2); | |
553 | BOOST_TEST(*it2 == vec[0]); | |
554 | vec.push_back(*it1); | |
555 | ||
556 | ++it1; | |
557 | BOOST_TEST(it1 == fs::directory_iterator()); | |
558 | ||
559 | BOOST_TEST(*it2 == vec[0]); | |
560 | ec.clear(); | |
561 | it2.increment(ec); | |
562 | BOOST_TEST(!ec); | |
563 | BOOST_TEST(it2 != fs::directory_iterator()); | |
564 | BOOST_TEST(it1 == fs::directory_iterator()); | |
565 | BOOST_TEST(*it2 == vec[1]); | |
566 | ++it2; | |
567 | BOOST_TEST(*it2 == vec[2]); | |
568 | BOOST_TEST(it1 == fs::directory_iterator()); | |
569 | ++it2; | |
570 | BOOST_TEST(*it2 == vec[3]); | |
571 | ++it2; | |
572 | BOOST_TEST(it1 == fs::directory_iterator()); | |
573 | BOOST_TEST(it2 == fs::directory_iterator()); | |
574 | ||
575 | // sort vec and check that the right directory entries were found | |
576 | std::sort(vec.begin(), vec.end()); | |
577 | ||
578 | BOOST_TEST_EQ(vec[0].path().filename().string(), std::string("d1")); | |
579 | BOOST_TEST_EQ(vec[1].path().filename().string(), std::string("d2")); | |
580 | BOOST_TEST_EQ(vec[2].path().filename().string(), std::string("f0")); | |
581 | BOOST_TEST_EQ(vec[3].path().filename().string(), std::string("f1")); | |
582 | } | |
583 | ||
584 | { // *i++ must meet the standard's InputIterator requirements | |
585 | fs::directory_iterator dir_itr(dir); | |
586 | BOOST_TEST(dir_itr != fs::directory_iterator()); | |
587 | fs::path p = dir_itr->path(); | |
588 | BOOST_TEST((*dir_itr++).path() == p); | |
589 | BOOST_TEST(dir_itr != fs::directory_iterator()); | |
590 | BOOST_TEST(dir_itr->path() != p); | |
591 | ||
592 | // test case reported in comment to SourceForge bug tracker [937606] | |
b32b8144 | 593 | // augmented to test single pass semantics of a copied iterator [#12578] |
7c673cae | 594 | fs::directory_iterator itx(dir); |
b32b8144 FG |
595 | fs::directory_iterator itx2(itx); |
596 | BOOST_TEST(itx == itx2); | |
7c673cae | 597 | const fs::path p1 = (*itx++).path(); |
b32b8144 | 598 | BOOST_TEST(itx == itx2); |
7c673cae FG |
599 | BOOST_TEST(itx != fs::directory_iterator()); |
600 | const fs::path p2 = (*itx++).path(); | |
b32b8144 | 601 | BOOST_TEST(itx == itx2); |
7c673cae FG |
602 | BOOST_TEST(p1 != p2); |
603 | ++itx; | |
b32b8144 | 604 | BOOST_TEST(itx == itx2); |
7c673cae | 605 | ++itx; |
b32b8144 | 606 | BOOST_TEST(itx == itx2); |
7c673cae | 607 | BOOST_TEST(itx == fs::directory_iterator()); |
b32b8144 | 608 | BOOST_TEST(itx2 == fs::directory_iterator()); |
7c673cae FG |
609 | } |
610 | ||
611 | // Windows has a tricky special case when just the root-name is given, | |
612 | // causing the rest of the path to default to the current directory. | |
613 | // Reported as S/F bug [ 1259176 ] | |
614 | if (platform == "Windows") | |
615 | { | |
616 | fs::path root_name_path(fs::current_path().root_name()); | |
617 | fs::directory_iterator itx(root_name_path); | |
618 | BOOST_TEST(itx != fs::directory_iterator()); | |
619 | // BOOST_TEST(fs::exists((*itx).path())); | |
620 | BOOST_TEST(fs::exists(itx->path())); | |
621 | BOOST_TEST(itx->path().parent_path() == root_name_path); | |
622 | bool found(false); | |
623 | do | |
624 | { | |
625 | if (itx->path().filename() == temp_dir.filename()) | |
626 | found = true; | |
627 | } while (++itx != fs::directory_iterator()); | |
628 | BOOST_TEST(found); | |
629 | } | |
630 | ||
631 | // there was an inital bug in directory_iterator that caused premature | |
632 | // close of an OS handle. This block will detect regression. | |
633 | { | |
634 | fs::directory_iterator di; | |
92f5a8d4 | 635 | { |
7c673cae FG |
636 | di = fs::directory_iterator(dir); |
637 | } | |
638 | BOOST_TEST(++di != fs::directory_iterator()); | |
639 | } | |
640 | ||
641 | cout << " directory_iterator_tests complete" << endl; | |
642 | } | |
643 | ||
644 | // recursive_directory_iterator_tests ----------------------------------------------// | |
645 | ||
646 | int walk_tree(bool recursive) | |
647 | { | |
92f5a8d4 | 648 | //cout << " walk_tree" << endl; |
7c673cae FG |
649 | error_code ec; |
650 | int d1f1_count = 0; | |
651 | for (fs::recursive_directory_iterator it (dir, | |
92f5a8d4 | 652 | recursive ? (fs::directory_options::follow_directory_symlink | fs::directory_options::skip_dangling_symlinks) : fs::directory_options::none); |
7c673cae FG |
653 | it != fs::recursive_directory_iterator(); |
654 | it.increment(ec)) | |
655 | { | |
92f5a8d4 | 656 | //cout << " " << it->path() << " : " << ec << endl; |
7c673cae FG |
657 | if (it->path().filename() == "d1f1") |
658 | ++d1f1_count; | |
659 | } | |
92f5a8d4 | 660 | //cout << " last error : " << ec << endl; |
7c673cae FG |
661 | return d1f1_count; |
662 | } | |
663 | ||
664 | void recursive_directory_iterator_tests() | |
665 | { | |
666 | cout << "recursive_directory_iterator_tests..." << endl; | |
667 | BOOST_TEST_EQ(walk_tree(false), 1); | |
668 | if (create_symlink_ok) | |
669 | BOOST_TEST(walk_tree(true) > 1); | |
670 | ||
671 | // test iterator increment with error_code argument | |
672 | cout << " with error_code argument" << endl; | |
673 | boost::system::error_code ec; | |
674 | int d1f1_count = 0; | |
92f5a8d4 | 675 | fs::recursive_directory_iterator it(dir, fs::directory_options::none); |
b32b8144 FG |
676 | fs::recursive_directory_iterator it2(it); // test single pass shallow copy semantics |
677 | for (; | |
7c673cae FG |
678 | it != fs::recursive_directory_iterator(); |
679 | it.increment(ec)) | |
680 | { | |
681 | if (it->path().filename() == "d1f1") | |
682 | ++d1f1_count; | |
b32b8144 | 683 | BOOST_TEST(it == it2); // verify single pass shallow copy semantics |
7c673cae FG |
684 | } |
685 | BOOST_TEST(!ec); | |
686 | BOOST_TEST_EQ(d1f1_count, 1); | |
b32b8144 | 687 | BOOST_TEST(it == it2); // verify single pass shallow copy semantics |
7c673cae FG |
688 | |
689 | cout << " recursive_directory_iterator_tests complete" << endl; | |
690 | } | |
691 | ||
692 | // iterator_status_tests -----------------------------------------------------------// | |
693 | ||
694 | void iterator_status_tests() | |
695 | { | |
696 | cout << "iterator_status_tests..." << endl; | |
697 | ||
698 | error_code ec; | |
699 | // harmless if these fail: | |
700 | fs::create_symlink(dir/"f0", dir/"f0_symlink", ec); | |
701 | fs::create_symlink(dir/"no such file", dir/"dangling_symlink", ec); | |
702 | fs::create_directory_symlink(dir/"d1", dir/"d1_symlink", ec); | |
703 | fs::create_directory_symlink(dir/"no such directory", | |
704 | dir/"dangling_directory_symlink", ec); | |
705 | ||
706 | for (fs::directory_iterator it(dir); | |
707 | it != fs::directory_iterator(); ++it) | |
708 | { | |
709 | BOOST_TEST(fs::status(it->path()).type() == it->status().type()); | |
710 | BOOST_TEST(fs::symlink_status(it->path()).type() == it->symlink_status().type()); | |
711 | if (it->path().filename() == "d1") | |
712 | { | |
713 | BOOST_TEST(fs::is_directory(it->status())); | |
714 | BOOST_TEST(fs::is_directory(it->symlink_status())); | |
715 | } | |
716 | else if (it->path().filename() == "d2") | |
717 | { | |
718 | BOOST_TEST(fs::is_directory(it->status())); | |
719 | BOOST_TEST(fs::is_directory(it->symlink_status())); | |
720 | } | |
721 | else if (it->path().filename() == "f0") | |
722 | { | |
723 | BOOST_TEST(fs::is_regular_file(it->status())); | |
724 | BOOST_TEST(fs::is_regular_file(it->symlink_status())); | |
725 | } | |
726 | else if (it->path().filename() == "f1") | |
727 | { | |
728 | BOOST_TEST(fs::is_regular_file(it->status())); | |
729 | BOOST_TEST(fs::is_regular_file(it->symlink_status())); | |
730 | } | |
731 | else if (it->path().filename() == "f0_symlink") | |
732 | { | |
733 | BOOST_TEST(fs::is_regular_file(it->status())); | |
734 | BOOST_TEST(fs::is_symlink(it->symlink_status())); | |
735 | } | |
736 | else if (it->path().filename() == "dangling_symlink") | |
737 | { | |
738 | BOOST_TEST(it->status().type() == fs::file_not_found); | |
739 | BOOST_TEST(fs::is_symlink(it->symlink_status())); | |
740 | } | |
741 | else if (it->path().filename() == "d1_symlink") | |
742 | { | |
743 | BOOST_TEST(fs::is_directory(it->status())); | |
744 | BOOST_TEST(fs::is_symlink(it->symlink_status())); | |
745 | } | |
746 | else if (it->path().filename() == "dangling_directory_symlink") | |
747 | { | |
748 | BOOST_TEST(it->status().type() == fs::file_not_found); | |
749 | BOOST_TEST(fs::is_symlink(it->symlink_status())); | |
750 | } | |
751 | //else | |
752 | // cout << " Note: unexpected directory entry " << it->path().filename() << endl; | |
753 | } | |
754 | } | |
92f5a8d4 | 755 | |
7c673cae FG |
756 | // recursive_iterator_status_tests -------------------------------------------------// |
757 | ||
758 | void recursive_iterator_status_tests() | |
759 | { | |
760 | cout << "recursive_iterator_status_tests..." << endl; | |
761 | for (fs::recursive_directory_iterator it (dir); | |
762 | it != fs::recursive_directory_iterator(); | |
763 | ++it) | |
764 | { | |
765 | BOOST_TEST(fs::status(it->path()).type() == it->status().type()); | |
766 | BOOST_TEST(fs::symlink_status(it->path()).type() == it->symlink_status().type()); | |
767 | } | |
768 | } | |
92f5a8d4 | 769 | |
7c673cae FG |
770 | // create_hard_link_tests ----------------------------------------------------------// |
771 | ||
772 | void create_hard_link_tests() | |
773 | { | |
774 | cout << "create_hard_link_tests..." << endl; | |
775 | ||
776 | fs::path from_ph(dir / "f3"); | |
777 | fs::path f1x(dir / "f1"); | |
778 | ||
779 | BOOST_TEST(!fs::exists(from_ph)); | |
780 | BOOST_TEST(fs::exists(f1x)); | |
781 | bool create_hard_link_ok(true); | |
782 | try { fs::create_hard_link(f1x, from_ph); } | |
783 | catch (const fs::filesystem_error & ex) | |
784 | { | |
785 | create_hard_link_ok = false; | |
786 | cout | |
787 | << " *** For information only ***\n" | |
788 | " create_hard_link() attempt failed\n" | |
789 | " filesystem_error.what() reports: " << ex.what() << "\n" | |
790 | " create_hard_link() may not be supported on this file system\n"; | |
791 | } | |
792 | ||
793 | if (create_hard_link_ok) | |
794 | { | |
795 | cout | |
796 | << " *** For information only ***\n" | |
797 | " create_hard_link() succeeded\n"; | |
798 | BOOST_TEST(fs::exists(from_ph)); | |
799 | BOOST_TEST(fs::exists(f1x)); | |
800 | BOOST_TEST(fs::equivalent(from_ph, f1x)); | |
801 | BOOST_TEST(fs::hard_link_count(from_ph) == 2); | |
802 | BOOST_TEST(fs::hard_link_count(f1x) == 2); | |
803 | } | |
804 | ||
805 | // Although tests may be running on a FAT or other file system that does | |
806 | // not support hard links, that is unusual enough that it is considered | |
807 | // a test failure. | |
808 | BOOST_TEST(create_hard_link_ok); | |
809 | ||
810 | error_code ec; | |
811 | fs::create_hard_link(fs::path("doesnotexist"), | |
812 | fs::path("shouldnotwork"), ec); | |
813 | BOOST_TEST(ec); | |
814 | } | |
92f5a8d4 | 815 | |
7c673cae FG |
816 | // create_symlink_tests ------------------------------------------------------------// |
817 | ||
818 | void create_symlink_tests() | |
819 | { | |
820 | cout << "create_symlink_tests..." << endl; | |
821 | ||
822 | fs::path from_ph(dir / "f4"); | |
823 | fs::path f1x(dir / "f1"); | |
824 | BOOST_TEST(!fs::exists(from_ph)); | |
825 | BOOST_TEST(fs::exists(f1x)); | |
826 | try { fs::create_symlink(f1x, from_ph); } | |
827 | catch (const fs::filesystem_error & ex) | |
828 | { | |
829 | create_symlink_ok = false; | |
92f5a8d4 | 830 | cout |
7c673cae FG |
831 | << " *** For information only ***\n" |
832 | " create_symlink() attempt failed\n" | |
833 | " filesystem_error.what() reports: " << ex.what() << "\n" | |
834 | " create_symlink() may not be supported on this operating system or file system\n"; | |
835 | } | |
836 | ||
837 | if (create_symlink_ok) | |
838 | { | |
839 | cout | |
840 | << " *** For information only ***\n" | |
841 | " create_symlink() succeeded\n"; | |
842 | BOOST_TEST(fs::exists(from_ph)); | |
843 | BOOST_TEST(fs::is_symlink(from_ph)); | |
844 | BOOST_TEST(fs::exists(f1x)); | |
845 | BOOST_TEST(fs::equivalent(from_ph, f1x)); | |
846 | BOOST_TEST(fs::read_symlink(from_ph) == f1x); | |
847 | ||
848 | fs::file_status stat = fs::symlink_status(from_ph); | |
849 | BOOST_TEST(fs::exists(stat)); | |
850 | BOOST_TEST(!fs::is_directory(stat)); | |
851 | BOOST_TEST(!fs::is_regular_file(stat)); | |
852 | BOOST_TEST(!fs::is_other(stat)); | |
853 | BOOST_TEST(fs::is_symlink(stat)); | |
854 | ||
855 | stat = fs::status(from_ph); | |
856 | BOOST_TEST(fs::exists(stat)); | |
857 | BOOST_TEST(!fs::is_directory(stat)); | |
858 | BOOST_TEST(fs::is_regular_file(stat)); | |
859 | BOOST_TEST(!fs::is_other(stat)); | |
860 | BOOST_TEST(!fs::is_symlink(stat)); | |
92f5a8d4 | 861 | |
7c673cae FG |
862 | // since create_symlink worked, copy_symlink should also work |
863 | fs::path symlink2_ph(dir / "symlink2"); | |
864 | fs::copy_symlink(from_ph, symlink2_ph); | |
865 | stat = fs::symlink_status(symlink2_ph); | |
866 | BOOST_TEST(fs::is_symlink(stat)); | |
867 | BOOST_TEST(fs::exists(stat)); | |
868 | BOOST_TEST(!fs::is_directory(stat)); | |
869 | BOOST_TEST(!fs::is_regular_file(stat)); | |
870 | BOOST_TEST(!fs::is_other(stat)); | |
871 | } | |
872 | ||
873 | error_code ec = error_code(); | |
874 | fs::create_symlink("doesnotexist", "", ec); | |
875 | BOOST_TEST(ec); | |
876 | } | |
877 | ||
878 | // permissions_tests ---------------------------------------------------------------// | |
879 | ||
880 | void permissions_tests() | |
881 | { | |
882 | cout << "permissions_tests..." << endl; | |
883 | ||
884 | fs::path p(dir / "permissions.txt"); | |
885 | create_file(p); | |
886 | ||
887 | if (platform == "POSIX") | |
888 | { | |
889 | cout << " fs::status(p).permissions() " << std::oct << fs::status(p).permissions() | |
890 | << std::dec << endl; | |
891 | BOOST_TEST((fs::status(p).permissions() & 0600) == 0600); // 0644, 0664 sometimes returned | |
892 | ||
893 | fs::permissions(p, fs::owner_all); | |
894 | BOOST_TEST(fs::status(p).permissions() == fs::owner_all); | |
895 | ||
896 | fs::permissions(p, fs::add_perms | fs::group_all); | |
897 | BOOST_TEST(fs::status(p).permissions() == (fs::owner_all | fs::group_all)); | |
898 | ||
899 | fs::permissions(p, fs::remove_perms | fs::group_all); | |
900 | BOOST_TEST(fs::status(p).permissions() == fs::owner_all); | |
901 | ||
902 | // some POSIX platforms cache permissions during directory iteration, some don't | |
903 | // so test that iteration finds the correct permissions | |
904 | for (fs::directory_iterator itr(dir); itr != fs::directory_iterator(); ++itr) | |
905 | if (itr->path().filename() == fs::path("permissions.txt")) | |
906 | BOOST_TEST(itr->status().permissions() == fs::owner_all); | |
907 | ||
908 | if (create_symlink_ok) // only if symlinks supported | |
909 | { | |
910 | BOOST_TEST(fs::status(p).permissions() == fs::owner_all); | |
911 | fs::path p2(dir / "permissions-symlink.txt"); | |
912 | fs::create_symlink(p, p2); | |
92f5a8d4 | 913 | cout << std::oct; |
7c673cae FG |
914 | cout << " status(p).permissions() " << fs::status(p).permissions() << endl; |
915 | cout << " status(p2).permissions() " << fs::status(p).permissions() << endl; | |
916 | fs::permissions(p2, fs::add_perms | fs::others_read); | |
92f5a8d4 | 917 | cout << " status(p).permissions(): " << fs::status(p).permissions() << endl; |
7c673cae FG |
918 | cout << " status(p2).permissions(): " << fs::status(p2).permissions() << endl; |
919 | cout << std::dec; | |
920 | } | |
921 | ||
922 | } | |
923 | else // Windows | |
924 | { | |
925 | BOOST_TEST(fs::status(p).permissions() == 0666); | |
926 | fs::permissions(p, fs::remove_perms | fs::group_write); | |
927 | BOOST_TEST(fs::status(p).permissions() == 0444); | |
928 | fs::permissions(p, fs::add_perms | fs::group_write); | |
929 | BOOST_TEST(fs::status(p).permissions() == 0666); | |
930 | } | |
931 | } | |
92f5a8d4 | 932 | |
7c673cae FG |
933 | // rename_tests --------------------------------------------------------------------// |
934 | ||
935 | void rename_tests() | |
936 | { | |
937 | cout << "rename_tests..." << endl; | |
938 | ||
939 | fs::path f1x(dir / "f1"); | |
940 | BOOST_TEST(fs::exists(f1x)); | |
941 | ||
942 | // error: rename a non-existent old file | |
943 | BOOST_TEST(!fs::exists(d1 / "f99")); | |
944 | BOOST_TEST(!fs::exists(d1 / "f98")); | |
945 | renamer n1a(d1 / "f99", d1 / "f98"); | |
946 | BOOST_TEST(CHECK_EXCEPTION(n1a, ENOENT)); | |
947 | renamer n1b(fs::path(""), d1 / "f98"); | |
948 | BOOST_TEST(CHECK_EXCEPTION(n1b, ENOENT)); | |
949 | ||
950 | // error: rename an existing file to "" | |
951 | renamer n2(f1x, ""); | |
952 | BOOST_TEST(CHECK_EXCEPTION(n2, ENOENT)); | |
953 | ||
954 | // rename an existing file to an existent file | |
955 | create_file(dir / "ff1", "ff1"); | |
956 | create_file(dir / "ff2", "ff2"); | |
957 | fs::rename(dir / "ff2", dir / "ff1"); | |
958 | BOOST_TEST(fs::exists(dir / "ff1")); | |
959 | verify_file(dir / "ff1", "ff2"); | |
960 | BOOST_TEST(!fs::exists(dir / "ff2")); | |
961 | ||
962 | // rename an existing file to itself | |
963 | BOOST_TEST(fs::exists(dir / "f1")); | |
964 | fs::rename(dir / "f1", dir / "f1"); | |
965 | BOOST_TEST(fs::exists(dir / "f1")); | |
966 | ||
967 | // error: rename an existing directory to an existing non-empty directory | |
968 | BOOST_TEST(fs::exists(dir / "f1")); | |
969 | BOOST_TEST(fs::exists(d1 / "f2")); | |
970 | // several POSIX implementations (cygwin, openBSD) report ENOENT instead of EEXIST, | |
971 | // so we don't verify error type on the following test. | |
972 | renamer n3b(dir, d1); | |
973 | BOOST_TEST(CHECK_EXCEPTION(n3b, 0)); | |
974 | ||
975 | // error: move existing file to a nonexistent parent directory | |
976 | BOOST_TEST(!fs::is_directory(dir / "f1")); | |
977 | BOOST_TEST(!fs::exists(dir / "d3/f3")); | |
978 | renamer n4a(dir / "f1", dir / "d3/f3"); | |
979 | BOOST_TEST(CHECK_EXCEPTION(n4a, ENOENT)); | |
980 | ||
981 | // rename existing file in same directory | |
982 | BOOST_TEST(fs::exists(d1 / "f2")); | |
983 | BOOST_TEST(!fs::exists(d1 / "f50")); | |
984 | fs::rename(d1 / "f2", d1 / "f50"); | |
985 | BOOST_TEST(!fs::exists(d1 / "f2")); | |
986 | BOOST_TEST(fs::exists(d1 / "f50")); | |
987 | fs::rename(d1 / "f50", d1 / "f2"); | |
988 | BOOST_TEST(fs::exists(d1 / "f2")); | |
989 | BOOST_TEST(!fs::exists(d1 / "f50")); | |
990 | ||
991 | // move and rename an existing file to a different directory | |
992 | fs::rename(d1 / "f2", d2 / "f3"); | |
993 | BOOST_TEST(!fs::exists(d1 / "f2")); | |
994 | BOOST_TEST(!fs::exists(d2 / "f2")); | |
995 | BOOST_TEST(fs::exists(d2 / "f3")); | |
996 | BOOST_TEST(!fs::is_directory(d2 / "f3")); | |
997 | verify_file(d2 / "f3", "file-f1"); | |
998 | fs::rename(d2 / "f3", d1 / "f2"); | |
999 | BOOST_TEST(fs::exists(d1 / "f2")); | |
1000 | ||
1001 | // error: move existing directory to nonexistent parent directory | |
1002 | BOOST_TEST(fs::exists(d1)); | |
1003 | BOOST_TEST(!fs::exists(dir / "d3/d5")); | |
1004 | BOOST_TEST(!fs::exists(dir / "d3")); | |
1005 | renamer n5a(d1, dir / "d3/d5"); | |
1006 | BOOST_TEST(CHECK_EXCEPTION(n5a, ENOENT)); | |
1007 | ||
1008 | // rename existing directory | |
1009 | fs::path d3(dir / "d3"); | |
1010 | BOOST_TEST(fs::exists(d1)); | |
1011 | BOOST_TEST(fs::exists(d1 / "f2")); | |
1012 | BOOST_TEST(!fs::exists(d3)); | |
1013 | fs::rename(d1, d3); | |
1014 | BOOST_TEST(!fs::exists(d1)); | |
1015 | BOOST_TEST(fs::exists(d3)); | |
1016 | BOOST_TEST(fs::is_directory(d3)); | |
1017 | BOOST_TEST(!fs::exists(d1 / "f2")); | |
1018 | BOOST_TEST(fs::exists(d3 / "f2")); | |
1019 | fs::rename(d3, d1); | |
1020 | BOOST_TEST(fs::exists(d1)); | |
1021 | BOOST_TEST(fs::exists(d1 / "f2")); | |
1022 | BOOST_TEST(!fs::exists(d3)); | |
1023 | ||
1024 | // rename and move d1 to d2 / "d20" | |
1025 | BOOST_TEST(fs::exists(d1)); | |
1026 | BOOST_TEST(!fs::exists(d2 / "d20")); | |
1027 | BOOST_TEST(fs::exists(d1 / "f2")); | |
1028 | fs::rename(d1, d2 / "d20"); | |
1029 | BOOST_TEST(!fs::exists(d1)); | |
1030 | BOOST_TEST(fs::exists(d2 / "d20")); | |
1031 | BOOST_TEST(fs::exists(d2 / "d20" / "f2")); | |
1032 | fs::rename(d2 / "d20", d1); | |
1033 | BOOST_TEST(fs::exists(d1)); | |
1034 | BOOST_TEST(!fs::exists(d2 / "d20")); | |
1035 | BOOST_TEST(fs::exists(d1 / "f2")); | |
1036 | } | |
92f5a8d4 | 1037 | |
7c673cae FG |
1038 | // predicate_and_status_tests ------------------------------------------------------// |
1039 | ||
1040 | void predicate_and_status_tests() | |
1041 | { | |
1042 | cout << "predicate_and_status_tests..." << endl; | |
1043 | ||
1044 | BOOST_TEST(!fs::exists(ng)); | |
1045 | BOOST_TEST(!fs::is_directory(ng)); | |
1046 | BOOST_TEST(!fs::is_regular_file(ng)); | |
1047 | BOOST_TEST(!fs::is_symlink(ng)); | |
1048 | fs::file_status stat(fs::status(ng)); | |
1049 | BOOST_TEST(fs::type_present(stat)); | |
1050 | BOOST_TEST(fs::permissions_present(stat)); | |
1051 | BOOST_TEST(fs::status_known(stat)); | |
1052 | BOOST_TEST(!fs::exists(stat)); | |
1053 | BOOST_TEST(!fs::is_directory(stat)); | |
1054 | BOOST_TEST(!fs::is_regular_file(stat)); | |
1055 | BOOST_TEST(!fs::is_other(stat)); | |
1056 | BOOST_TEST(!fs::is_symlink(stat)); | |
1057 | stat = fs::status(""); | |
1058 | BOOST_TEST(fs::type_present(stat)); | |
1059 | BOOST_TEST(fs::permissions_present(stat)); | |
1060 | BOOST_TEST(fs::status_known(stat)); | |
1061 | BOOST_TEST(!fs::exists(stat)); | |
1062 | BOOST_TEST(!fs::is_directory(stat)); | |
1063 | BOOST_TEST(!fs::is_regular_file(stat)); | |
1064 | BOOST_TEST(!fs::is_other(stat)); | |
1065 | BOOST_TEST(!fs::is_symlink(stat)); | |
1066 | } | |
92f5a8d4 | 1067 | |
7c673cae FG |
1068 | // create_directory_tests ----------------------------------------------------------// |
1069 | ||
1070 | void create_directory_tests() | |
1071 | { | |
1072 | cout << "create_directory_tests..." << endl; | |
1073 | ||
b32b8144 FG |
1074 | error_code ec; |
1075 | BOOST_TEST(!fs::create_directory("", ec)); | |
1076 | BOOST_TEST(ec); | |
1077 | ||
1078 | #ifdef BOOST_WINDOWS_API | |
1079 | ec.clear(); | |
1080 | BOOST_TEST(!fs::create_directory(" ", ec)); // OK on Linux | |
1081 | BOOST_TEST(ec); | |
1082 | #endif | |
1083 | ||
1084 | ec.clear(); | |
1085 | BOOST_TEST(!fs::create_directory("/", ec)); | |
1086 | BOOST_TEST(!ec); | |
1087 | BOOST_TEST(fs::is_directory("/")); // this is a post-condition | |
1088 | ||
1089 | ec.clear(); | |
1090 | BOOST_TEST(!fs::create_directory(".", ec)); | |
1091 | BOOST_TEST(!ec); | |
1092 | ||
1093 | ec.clear(); | |
1094 | BOOST_TEST(!fs::create_directory("..", ec)); | |
1095 | BOOST_TEST(!ec); | |
7c673cae FG |
1096 | |
1097 | // create a directory, then check it for consistency | |
1098 | // take extra care to report problems, since if this fails | |
1099 | // many subsequent tests will fail | |
1100 | try | |
1101 | { | |
1102 | fs::create_directory(dir); | |
1103 | } | |
1104 | ||
1105 | catch (const fs::filesystem_error & x) | |
1106 | { | |
1107 | cout << x.what() << "\n\n" | |
1108 | "***** Creating directory " << dir << " failed. *****\n" | |
1109 | "***** This is a serious error that will prevent further tests *****\n" | |
1110 | "***** from returning useful results. Further testing is aborted. *****\n\n"; | |
1111 | std::exit(1); | |
1112 | } | |
1113 | ||
1114 | catch (...) | |
1115 | { | |
1116 | cout << "\n\n" | |
1117 | "***** Creating directory " << dir << " failed. *****\n" | |
1118 | "***** This is a serious error that will prevent further tests *****\n" | |
1119 | "***** from returning useful results. Further testing is aborted. *****\n\n"; | |
1120 | std::exit(1); | |
1121 | } | |
1122 | ||
1123 | BOOST_TEST(fs::exists(dir)); | |
1124 | BOOST_TEST(fs::is_empty(dir)); | |
1125 | BOOST_TEST(fs::is_directory(dir)); | |
1126 | BOOST_TEST(!fs::is_regular_file(dir)); | |
1127 | BOOST_TEST(!fs::is_other(dir)); | |
1128 | BOOST_TEST(!fs::is_symlink(dir)); | |
1129 | fs::file_status stat = fs::status(dir); | |
1130 | BOOST_TEST(fs::exists(stat)); | |
1131 | BOOST_TEST(fs::is_directory(stat)); | |
1132 | BOOST_TEST(!fs::is_regular_file(stat)); | |
1133 | BOOST_TEST(!fs::is_other(stat)); | |
1134 | BOOST_TEST(!fs::is_symlink(stat)); | |
1135 | ||
1136 | cout << " create_directory_tests complete" << endl; | |
1137 | } | |
92f5a8d4 | 1138 | |
7c673cae FG |
1139 | // current_directory_tests ---------------------------------------------------------// |
1140 | ||
1141 | void current_directory_tests() | |
1142 | { | |
1143 | cout << "current_directory_tests..." << endl; | |
1144 | ||
1145 | // set the current directory, then check it for consistency | |
1146 | fs::path original_dir = fs::current_path(); | |
1147 | BOOST_TEST(dir != original_dir); | |
1148 | fs::current_path(dir); | |
1149 | BOOST_TEST(fs::current_path() == dir); | |
1150 | BOOST_TEST(fs::current_path() != original_dir); | |
1151 | fs::current_path(original_dir); | |
1152 | BOOST_TEST(fs::current_path() == original_dir); | |
1153 | BOOST_TEST(fs::current_path() != dir); | |
1154 | ||
1155 | // make sure the overloads work | |
1156 | fs::current_path(dir.c_str()); | |
1157 | BOOST_TEST(fs::current_path() == dir); | |
1158 | BOOST_TEST(fs::current_path() != original_dir); | |
1159 | fs::current_path(original_dir.string()); | |
1160 | BOOST_TEST(fs::current_path() == original_dir); | |
1161 | BOOST_TEST(fs::current_path() != dir); | |
1162 | } | |
1163 | ||
1164 | // create_directories_tests --------------------------------------------------------// | |
1165 | ||
1166 | void create_directories_tests() | |
1167 | { | |
1168 | cout << "create_directories_tests..." << endl; | |
1169 | ||
b32b8144 FG |
1170 | error_code ec; |
1171 | BOOST_TEST(!fs::create_directories("", ec)); | |
1172 | BOOST_TEST(ec); | |
7c673cae | 1173 | |
b32b8144 FG |
1174 | #ifdef BOOST_WINDOWS_API |
1175 | // Windows only test, since " " is OK on Linux as a directory name | |
1176 | ec.clear(); | |
1177 | BOOST_TEST(!fs::create_directories(" ", ec)); | |
1178 | BOOST_TEST(ec); | |
1179 | #endif | |
1180 | ||
1181 | ec.clear(); | |
1182 | BOOST_TEST(!fs::create_directories("/", ec)); | |
1183 | BOOST_TEST(!ec); | |
1184 | ||
1185 | ec.clear(); | |
1186 | BOOST_TEST(!fs::create_directories(".", ec)); | |
1187 | BOOST_TEST(ec); | |
1188 | ||
1189 | ec.clear(); | |
1190 | BOOST_TEST(!fs::create_directories("..", ec)); | |
1191 | BOOST_TEST(ec); | |
1192 | ||
1193 | #ifdef BOOST_POSIX_API | |
1194 | ec.clear(); | |
1195 | BOOST_TEST(!fs::create_directories("/foo", ec)); // may be OK on Windows | |
1196 | // but unlikely to be OK on POSIX | |
1197 | BOOST_TEST(ec); | |
1198 | #endif | |
92f5a8d4 | 1199 | |
7c673cae FG |
1200 | fs::path p = dir / "level1/." / "level2/./.." / "level3/"; |
1201 | // trailing "/.", "/./..", and "/" in the above elements test ticket #7258 and | |
1202 | // related issues | |
1203 | ||
b32b8144 | 1204 | cout << " p is " << p << endl; |
7c673cae FG |
1205 | BOOST_TEST(!fs::exists(p)); |
1206 | BOOST_TEST(fs::create_directories(p)); | |
1207 | BOOST_TEST(fs::exists(p)); | |
1208 | BOOST_TEST(fs::is_directory(p)); | |
1209 | ||
1210 | if (fs::exists("/permissions_test")) | |
1211 | { | |
7c673cae FG |
1212 | BOOST_TEST(!fs::create_directories("/permissions_test", ec)); |
1213 | BOOST_TEST(!fs::create_directories("/permissions_test/another_directory", ec)); | |
1214 | BOOST_TEST(ec); | |
1215 | } | |
1216 | } | |
1217 | ||
1218 | // resize_file_tests ---------------------------------------------------------------// | |
1219 | ||
1220 | void resize_file_tests() | |
1221 | { | |
1222 | cout << "resize_file_tests..." << endl; | |
1223 | ||
1224 | fs::path p(dir / "resize_file_test.txt"); | |
1225 | ||
1226 | fs::remove(p); | |
1227 | create_file(p, "1234567890"); | |
1228 | ||
1229 | BOOST_TEST(fs::exists(p)); | |
1230 | BOOST_TEST_EQ(fs::file_size(p), 10U); | |
1231 | fs::resize_file(p, 5); | |
1232 | BOOST_TEST(fs::exists(p)); | |
1233 | BOOST_TEST_EQ(fs::file_size(p), 5U); | |
1234 | fs::resize_file(p, 15); | |
1235 | BOOST_TEST(fs::exists(p)); | |
1236 | BOOST_TEST_EQ(fs::file_size(p), 15U); | |
1237 | ||
1238 | error_code ec; | |
1239 | fs::resize_file("no such file", 15, ec); | |
1240 | BOOST_TEST(ec); | |
1241 | } | |
1242 | ||
1243 | // status_of_nonexistent_tests -----------------------------------------------------// | |
1244 | ||
1245 | void status_of_nonexistent_tests() | |
1246 | { | |
1247 | cout << "status_of_nonexistent_tests..." << endl; | |
1248 | fs::path p ("nosuch"); | |
1249 | BOOST_TEST(!fs::exists(p)); | |
1250 | BOOST_TEST(!fs::is_regular_file(p)); | |
1251 | BOOST_TEST(!fs::is_directory(p)); | |
1252 | BOOST_TEST(!fs::is_symlink(p)); | |
1253 | BOOST_TEST(!fs::is_other(p)); | |
1254 | ||
1255 | fs::file_status s = fs::status(p); | |
1256 | BOOST_TEST(!fs::exists(s)); | |
1257 | BOOST_TEST_EQ(s.type(), fs::file_not_found); | |
1258 | BOOST_TEST(fs::type_present(s)); | |
1259 | BOOST_TEST(!fs::is_regular_file(s)); | |
1260 | BOOST_TEST(!fs::is_directory(s)); | |
1261 | BOOST_TEST(!fs::is_symlink(s)); | |
1262 | BOOST_TEST(!fs::is_other(s)); | |
b32b8144 FG |
1263 | |
1264 | // ticket #12574 was just user confusion, but are the tests are worth keeping | |
1265 | error_code ec; | |
1266 | BOOST_TEST(!fs::is_directory(dir / "no-such-directory", ec)); | |
1267 | BOOST_TEST(ec); | |
1268 | //cout << "error_code value: " << ec.value() << endl; | |
1269 | ec.clear(); | |
1270 | BOOST_TEST(!fs::is_directory(dir / "no-such-directory" / "bar", ec)); | |
1271 | BOOST_TEST(ec); | |
1272 | //cout << "error_code value: " << ec.value() << endl; | |
7c673cae FG |
1273 | } |
1274 | ||
1275 | // status_error_reporting_tests ----------------------------------------------------// | |
1276 | ||
1277 | void status_error_reporting_tests() | |
1278 | { | |
1279 | cout << "status_error_reporting_tests..." << endl; | |
1280 | ||
1281 | error_code ec; | |
1282 | ||
1283 | // test status, ec, for existing file | |
1284 | ec.assign(-1,poison_category()); | |
1285 | BOOST_TEST(ec.value() == -1); | |
92f5a8d4 | 1286 | BOOST_TEST(&ec.category() == &poison_category()); |
7c673cae FG |
1287 | fs::file_status s = fs::status(".",ec); |
1288 | BOOST_TEST(ec.value() == 0); | |
92f5a8d4 | 1289 | BOOST_TEST(ec.category() == system_category()); |
7c673cae FG |
1290 | BOOST_TEST(fs::exists(s)); |
1291 | BOOST_TEST(fs::is_directory(s)); | |
1292 | ||
1293 | // test status, ec, for non-existing file | |
1294 | fs::path p ("nosuch"); | |
1295 | ec.assign(-1,poison_category()); | |
1296 | s = fs::status(p,ec); | |
1297 | BOOST_TEST(ec.value() != 0); | |
92f5a8d4 | 1298 | BOOST_TEST(ec.category() == system_category()); |
7c673cae FG |
1299 | |
1300 | BOOST_TEST(!fs::exists(s)); | |
1301 | BOOST_TEST_EQ(s.type(), fs::file_not_found); | |
1302 | BOOST_TEST(fs::type_present(s)); | |
1303 | BOOST_TEST(!fs::is_regular_file(s)); | |
1304 | BOOST_TEST(!fs::is_directory(s)); | |
1305 | BOOST_TEST(!fs::is_symlink(s)); | |
1306 | BOOST_TEST(!fs::is_other(s)); | |
1307 | ||
1308 | // test queries, ec, for existing file | |
1309 | ec.assign(-1,poison_category()); | |
1310 | BOOST_TEST(fs::exists(".", ec)); | |
1311 | BOOST_TEST(ec.value() == 0); | |
92f5a8d4 | 1312 | BOOST_TEST(ec.category() == system_category()); |
7c673cae FG |
1313 | ec.assign(-1,poison_category()); |
1314 | BOOST_TEST(!fs::is_regular_file(".", ec)); | |
1315 | BOOST_TEST(ec.value() == 0); | |
92f5a8d4 | 1316 | BOOST_TEST(ec.category() == system_category()); |
7c673cae FG |
1317 | ec.assign(-1,poison_category()); |
1318 | BOOST_TEST(fs::is_directory(".", ec)); | |
1319 | BOOST_TEST(ec.value() == 0); | |
92f5a8d4 | 1320 | BOOST_TEST(ec.category() == system_category()); |
7c673cae FG |
1321 | |
1322 | // test queries, ec, for non-existing file | |
1323 | ec.assign(-1,poison_category()); | |
1324 | BOOST_TEST(!fs::exists(p, ec)); | |
1325 | BOOST_TEST(ec.value() != 0); | |
92f5a8d4 | 1326 | BOOST_TEST(ec.category() == system_category()); |
7c673cae FG |
1327 | ec.assign(-1,poison_category()); |
1328 | BOOST_TEST(!fs::is_regular_file(p, ec)); | |
1329 | BOOST_TEST(ec.value() != 0); | |
92f5a8d4 | 1330 | BOOST_TEST(ec.category() == system_category()); |
7c673cae FG |
1331 | ec.assign(-1,poison_category()); |
1332 | BOOST_TEST(!fs::is_directory(p, ec)); | |
1333 | BOOST_TEST(ec.value() != 0); | |
92f5a8d4 | 1334 | BOOST_TEST(ec.category() == system_category()); |
7c673cae FG |
1335 | } |
1336 | ||
1337 | // remove_tests --------------------------------------------------------------------// | |
1338 | ||
1339 | void remove_tests(const fs::path& dirx) | |
1340 | { | |
1341 | cout << "remove_tests..." << endl; | |
1342 | ||
1343 | // remove() file | |
1344 | fs::path f1x = dirx / "shortlife"; | |
1345 | BOOST_TEST(!fs::exists(f1x)); | |
1346 | create_file(f1x, ""); | |
1347 | BOOST_TEST(fs::exists(f1x)); | |
1348 | BOOST_TEST(!fs::is_directory(f1x)); | |
1349 | BOOST_TEST(fs::remove(f1x)); | |
1350 | BOOST_TEST(!fs::exists(f1x)); | |
1351 | BOOST_TEST(!fs::remove("no-such-file")); | |
1352 | BOOST_TEST(!fs::remove("no-such-directory/no-such-file")); | |
1353 | ||
1354 | // remove() directory | |
1355 | fs::path d1x = dirx / "shortlife_dir"; | |
1356 | BOOST_TEST(!fs::exists(d1x)); | |
1357 | fs::create_directory(d1x); | |
1358 | BOOST_TEST(fs::exists(d1x)); | |
1359 | BOOST_TEST(fs::is_directory(d1x)); | |
1360 | BOOST_TEST(fs::is_empty(d1x)); | |
1361 | bad_remove_dir = dirx; | |
1362 | BOOST_TEST(CHECK_EXCEPTION(bad_remove, ENOTEMPTY)); | |
1363 | BOOST_TEST(fs::remove(d1x)); | |
1364 | BOOST_TEST(!fs::exists(d1x)); | |
1365 | } | |
1366 | ||
1367 | // remove_symlink_tests ------------------------------------------------------------// | |
92f5a8d4 | 1368 | |
7c673cae FG |
1369 | void remove_symlink_tests() |
1370 | { | |
1371 | cout << "remove_symlink_tests..." << endl; | |
1372 | ||
1373 | // remove() dangling symbolic link | |
1374 | fs::path link("dangling_link"); | |
1375 | fs::remove(link); // remove any residue from past tests | |
1376 | BOOST_TEST(!fs::is_symlink(link)); | |
1377 | BOOST_TEST(!fs::exists(link)); | |
1378 | fs::create_symlink("nowhere", link); | |
1379 | BOOST_TEST(!fs::exists(link)); | |
1380 | BOOST_TEST(fs::is_symlink(link)); | |
1381 | BOOST_TEST(fs::remove(link)); | |
1382 | BOOST_TEST(!fs::is_symlink(link)); | |
1383 | ||
1384 | // remove() self-refering symbolic link | |
1385 | link = "link_to_self"; | |
1386 | fs::remove(link); // remove any residue from past tests | |
1387 | BOOST_TEST(!fs::is_symlink(link)); | |
1388 | BOOST_TEST(!fs::exists(link)); | |
1389 | fs::create_symlink(link, link); | |
1390 | BOOST_TEST(fs::remove(link)); | |
1391 | BOOST_TEST(!fs::exists(link)); | |
1392 | BOOST_TEST(!fs::is_symlink(link)); | |
1393 | ||
1394 | // remove() cyclic symbolic link | |
1395 | link = "link_to_a"; | |
1396 | fs::path link2("link_to_b"); | |
1397 | fs::remove(link); // remove any residue from past tests | |
1398 | fs::remove(link2); // remove any residue from past tests | |
1399 | BOOST_TEST(!fs::is_symlink(link)); | |
1400 | BOOST_TEST(!fs::exists(link)); | |
1401 | fs::create_symlink(link, link2); | |
1402 | fs::create_symlink(link2, link); | |
1403 | BOOST_TEST(fs::remove(link)); | |
1404 | BOOST_TEST(fs::remove(link2)); | |
1405 | BOOST_TEST(!fs::exists(link)); | |
1406 | BOOST_TEST(!fs::exists(link2)); | |
1407 | BOOST_TEST(!fs::is_symlink(link)); | |
1408 | ||
1409 | // remove() symbolic link to file | |
1410 | fs::path f1x = "link_target"; | |
1411 | fs::remove(f1x); // remove any residue from past tests | |
1412 | BOOST_TEST(!fs::exists(f1x)); | |
1413 | create_file(f1x, ""); | |
1414 | BOOST_TEST(fs::exists(f1x)); | |
1415 | BOOST_TEST(!fs::is_directory(f1x)); | |
1416 | BOOST_TEST(fs::is_regular_file(f1x)); | |
1417 | link = "non_dangling_link"; | |
1418 | fs::create_symlink(f1x, link); | |
1419 | BOOST_TEST(fs::exists(link)); | |
1420 | BOOST_TEST(!fs::is_directory(link)); | |
1421 | BOOST_TEST(fs::is_regular_file(link)); | |
1422 | BOOST_TEST(fs::is_symlink(link)); | |
1423 | BOOST_TEST(fs::remove(link)); | |
1424 | BOOST_TEST(fs::exists(f1x)); | |
1425 | BOOST_TEST(!fs::exists(link)); | |
1426 | BOOST_TEST(!fs::is_symlink(link)); | |
1427 | BOOST_TEST(fs::remove(f1x)); | |
1428 | BOOST_TEST(!fs::exists(f1x)); | |
1429 | } | |
1430 | ||
1431 | // absolute_tests -----------------------------------------------------------------// | |
1432 | ||
1433 | void absolute_tests() | |
1434 | { | |
1435 | cout << "absolute_tests..." << endl; | |
1436 | ||
1437 | BOOST_TEST_EQ(fs::absolute(""), fs::current_path() ); | |
1438 | BOOST_TEST_EQ(fs::absolute("", ""), fs::current_path() ); | |
1439 | BOOST_TEST_EQ(fs::absolute(fs::current_path() / "foo/bar"), fs::current_path() / "foo/bar"); | |
1440 | BOOST_TEST_EQ(fs::absolute("foo"), fs::current_path() / "foo"); | |
1441 | BOOST_TEST_EQ(fs::absolute("foo", fs::current_path()), fs::current_path() / "foo"); | |
1442 | BOOST_TEST_EQ(fs::absolute("bar", "foo"), fs::current_path() / "foo" / "bar"); | |
1443 | BOOST_TEST_EQ(fs::absolute("/foo"), fs::current_path().root_path().string() + "foo"); | |
1444 | ||
1445 | # ifdef BOOST_WINDOWS_API | |
1446 | BOOST_TEST_EQ(fs::absolute("a:foo", "b:/bar"), "a:/bar/foo"); | |
1447 | # endif | |
1448 | ||
1449 | // these tests were moved from elsewhere, so may duplicate some of the above tests | |
1450 | ||
1451 | // p.empty() | |
1452 | BOOST_TEST_EQ(fs::absolute(fs::path(), "//foo/bar"), "//foo/bar"); | |
1453 | if (platform == "Windows") | |
1454 | { | |
1455 | BOOST_TEST_EQ(fs::absolute(fs::path(), "a:/bar"), "a:/bar"); | |
1456 | } | |
1457 | ||
1458 | // p.has_root_name() | |
1459 | // p.has_root_directory() | |
1460 | BOOST_TEST_EQ(fs::absolute(fs::path("//foo/bar"), "//uvw/xyz"), "//foo/bar"); | |
1461 | if (platform == "Windows") | |
1462 | { | |
1463 | BOOST_TEST_EQ(fs::absolute(fs::path("a:/bar"), "b:/xyz"), "a:/bar"); | |
1464 | } | |
1465 | // !p.has_root_directory() | |
1466 | BOOST_TEST_EQ(fs::absolute(fs::path("//net"), "//xyz/"), "//net/"); | |
1467 | BOOST_TEST_EQ(fs::absolute(fs::path("//net"), "//xyz/abc"), "//net/abc"); | |
1468 | BOOST_TEST_EQ(fs::absolute(fs::path("//net"), "//xyz/abc/def"), "//net/abc/def"); | |
1469 | if (platform == "Windows") | |
1470 | { | |
1471 | BOOST_TEST_EQ(fs::absolute(fs::path("a:"), "b:/"), "a:/"); | |
1472 | BOOST_TEST_EQ(fs::absolute(fs::path("a:"),"b:/abc"), "a:/abc"); | |
1473 | BOOST_TEST_EQ(fs::absolute(fs::path("a:"),"b:/abc/def"), "a:/abc/def"); | |
1474 | BOOST_TEST_EQ(fs::absolute(fs::path("a:foo"), "b:/"), "a:/foo"); | |
1475 | BOOST_TEST_EQ(fs::absolute(fs::path("a:foo"), "b:/abc"), "a:/abc/foo"); | |
1476 | BOOST_TEST_EQ(fs::absolute(fs::path("a:foo"), "b:/abc/def"), "a:/abc/def/foo"); | |
1477 | BOOST_TEST_EQ(fs::absolute(fs::path("a:foo/bar"), "b:/"), "a:/foo/bar"); | |
1478 | BOOST_TEST_EQ(fs::absolute(fs::path("a:foo/bar"), "b:/abc"), "a:/abc/foo/bar"); | |
1479 | BOOST_TEST_EQ(fs::absolute(fs::path("a:foo/bar"), "b:/abc/def"), "a:/abc/def/foo/bar"); | |
1480 | } | |
1481 | // !p.has_root_name() | |
1482 | // p.has_root_directory() | |
1483 | BOOST_TEST_EQ(fs::absolute(fs::path("/"), "//xyz/"), "//xyz/"); | |
1484 | BOOST_TEST_EQ(fs::absolute(fs::path("/"), "//xyz/abc"), "//xyz/"); | |
1485 | BOOST_TEST_EQ(fs::absolute(fs::path("/foo"), "//xyz/"), "//xyz/foo"); | |
1486 | BOOST_TEST_EQ(fs::absolute(fs::path("/foo"), "//xyz/abc"), "//xyz/foo"); | |
1487 | // !p.has_root_directory() | |
1488 | BOOST_TEST_EQ(fs::absolute(fs::path("foo"), "//xyz/abc"), "//xyz/abc/foo"); | |
1489 | BOOST_TEST_EQ(fs::absolute(fs::path("foo/bar"), "//xyz/abc"), "//xyz/abc/foo/bar"); | |
1490 | BOOST_TEST_EQ(fs::absolute(fs::path("."), "//xyz/abc"), "//xyz/abc/."); | |
1491 | BOOST_TEST_EQ(fs::absolute(fs::path(".."), "//xyz/abc"), "//xyz/abc/.."); | |
1492 | BOOST_TEST_EQ(fs::absolute(fs::path("./foo"), "//xyz/abc"), "//xyz/abc/./foo"); | |
1493 | BOOST_TEST_EQ(fs::absolute(fs::path("../foo"), "//xyz/abc"), "//xyz/abc/../foo"); | |
1494 | if (platform == "POSIX") | |
1495 | { | |
1496 | BOOST_TEST_EQ(fs::absolute(fs::path("foo"), "/abc"), "/abc/foo"); | |
1497 | BOOST_TEST_EQ(fs::absolute(fs::path("foo/bar"), "/abc"), "/abc/foo/bar"); | |
1498 | BOOST_TEST_EQ(fs::absolute(fs::path("."), "/abc"), "/abc/."); | |
1499 | BOOST_TEST_EQ(fs::absolute(fs::path(".."), "/abc"), "/abc/.."); | |
1500 | BOOST_TEST_EQ(fs::absolute(fs::path("./foo"), "/abc"), "/abc/./foo"); | |
1501 | BOOST_TEST_EQ(fs::absolute(fs::path("../foo"), "/abc"), "/abc/../foo"); | |
1502 | } | |
1503 | ||
1504 | } | |
1505 | ||
1506 | // canonical_basic_tests -----------------------------------------------------------// | |
1507 | ||
1508 | void canonical_basic_tests() | |
1509 | { | |
1510 | cout << "canonical_basic_tests..." << endl; | |
1511 | ||
1512 | // error handling | |
1513 | error_code ec; | |
1514 | ec.clear(); | |
1515 | fs::canonical("no-such-file", ec); | |
1516 | BOOST_TEST(ec); | |
1517 | ec.clear(); | |
1518 | fs::canonical("no-such-file", "x", ec); | |
1519 | BOOST_TEST(ec); | |
1520 | bool ok(false); | |
1521 | try { fs::canonical("no-such-file"); } | |
1522 | catch (const fs::filesystem_error&) { ok = true; } | |
1523 | BOOST_TEST(ok); | |
1524 | ||
1525 | // non-symlink tests; also see canonical_symlink_tests() | |
1526 | BOOST_TEST_EQ(fs::canonical(""), fs::current_path()); | |
1527 | BOOST_TEST_EQ(fs::canonical("", fs::current_path()), fs::current_path()); | |
1528 | BOOST_TEST_EQ(fs::canonical("", ""), fs::current_path()); | |
1529 | BOOST_TEST_EQ(fs::canonical(fs::current_path()), fs::current_path()); | |
1530 | BOOST_TEST_EQ(fs::canonical(fs::current_path(), ""), fs::current_path()); | |
1531 | BOOST_TEST_EQ(fs::canonical(fs::current_path(), "no-such-file"), fs::current_path()); | |
1532 | ||
1533 | BOOST_TEST_EQ(fs::canonical("."), fs::current_path()); | |
1534 | BOOST_TEST_EQ(fs::canonical(".."), fs::current_path().parent_path()); | |
1535 | BOOST_TEST_EQ(fs::canonical("/"), fs::current_path().root_path()); | |
1536 | ||
1537 | fs::path relative_dir(dir.filename()); | |
1538 | BOOST_TEST_EQ(fs::canonical(dir), dir); | |
1539 | BOOST_TEST_EQ(fs::canonical(relative_dir), dir); | |
1540 | BOOST_TEST_EQ(fs::canonical(dir / "f0"), dir / "f0"); | |
1541 | BOOST_TEST_EQ(fs::canonical(relative_dir / "f0"), dir / "f0"); | |
1542 | BOOST_TEST_EQ(fs::canonical(relative_dir / "./f0"), dir / "f0"); | |
1543 | BOOST_TEST_EQ(fs::canonical(relative_dir / "d1/../f0"), dir / "f0"); | |
1544 | ||
1545 | // treat parent of root as itself on both POSIX and Windows | |
1546 | fs::path init(fs::initial_path()); | |
1547 | fs::path root(init.root_path()); | |
1548 | fs::path::const_iterator it(init.begin()); | |
1549 | fs::path first; // relative first non-root directory | |
1550 | # ifdef BOOST_WINDOWS_API | |
1551 | if (!init.empty()) | |
1552 | ++it; | |
1553 | # endif | |
1554 | if (++it != init.end()) | |
1555 | first = *it; | |
1556 | fs::path expected(root/first); | |
1557 | ||
1558 | cout << " init: " << init << endl; | |
1559 | cout << " root: " << root << endl; | |
1560 | cout << " first: " << first << endl; | |
1561 | cout << " expected: " << expected << endl; | |
1562 | ||
1563 | // ticket 10187 tests | |
1564 | BOOST_TEST_EQ(fs::canonical(root / "../.." / first), expected); | |
1565 | BOOST_TEST_EQ(fs::canonical(fs::path("../..") / first, root), expected); | |
1566 | BOOST_TEST_EQ(fs::canonical(fs::path("/../..") / first, fs::current_path().root_name()), expected); | |
1567 | ||
1568 | // ticket 9683 test | |
1569 | BOOST_TEST_EQ(fs::canonical(root / first / "../../../../.."), root); | |
1570 | } | |
1571 | ||
1572 | // canonical_symlink_tests -----------------------------------------------------------// | |
1573 | ||
1574 | void canonical_symlink_tests() | |
1575 | { | |
1576 | cout << "canonical_symlink_tests..." << endl; | |
1577 | ||
1578 | fs::path relative_dir(dir.filename()); | |
1579 | BOOST_TEST_EQ(fs::canonical(dir / "sym-d1/f2"), d1 / "f2"); | |
1580 | BOOST_TEST_EQ(fs::canonical(relative_dir / "sym-d1/f2"), d1 / "f2"); | |
1581 | } | |
1582 | ||
1583 | // copy_file_tests ------------------------------------------------------------------// | |
1584 | ||
1585 | void copy_file_tests(const fs::path& f1x, const fs::path& d1x) | |
1586 | { | |
1587 | cout << "copy_file_tests..." << endl; | |
1588 | ||
1589 | BOOST_TEST(fs::exists(f1x)); | |
1590 | fs::remove(d1x / "f2"); // remove possible residue from prior testing | |
1591 | BOOST_TEST(fs::exists(d1x)); | |
1592 | BOOST_TEST(!fs::exists(d1x / "f2")); | |
1593 | cout << " copy " << f1x << " to " << d1x / "f2" << endl; | |
1594 | fs::copy_file(f1x, d1x / "f2"); | |
1595 | cout << " copy complete" << endl; | |
1596 | BOOST_TEST(fs::exists(f1x)); | |
1597 | BOOST_TEST(fs::exists(d1x / "f2")); | |
1598 | BOOST_TEST(!fs::is_directory(d1x / "f2")); | |
1599 | verify_file(d1x / "f2", "file-f1"); | |
1600 | ||
1601 | bool copy_ex_ok = false; | |
1602 | try { fs::copy_file(f1x, d1x / "f2"); } | |
1603 | catch (const fs::filesystem_error &) { copy_ex_ok = true; } | |
1604 | BOOST_TEST(copy_ex_ok); | |
1605 | ||
1606 | copy_ex_ok = false; | |
1607 | try { fs::copy_file(f1x, d1x / "f2", fs::copy_option::fail_if_exists); } | |
1608 | catch (const fs::filesystem_error &) { copy_ex_ok = true; } | |
1609 | BOOST_TEST(copy_ex_ok); | |
1610 | ||
1611 | create_file(d1x / "f2", "1234567890"); | |
1612 | BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 10U); | |
1613 | copy_ex_ok = true; | |
1614 | try { fs::copy_file(f1x, d1x / "f2", fs::copy_option::overwrite_if_exists); } | |
1615 | catch (const fs::filesystem_error &) { copy_ex_ok = false; } | |
1616 | BOOST_TEST(copy_ex_ok); | |
1617 | BOOST_TEST_EQ(fs::file_size(d1x / "f2"), 7U); | |
1618 | verify_file(d1x / "f2", "file-f1"); | |
1619 | } | |
1620 | ||
1621 | // symlink_status_tests -------------------------------------------------------------// | |
1622 | ||
1623 | void symlink_status_tests() | |
1624 | { | |
1625 | cout << "symlink_status_tests..." << endl; | |
1626 | ||
1627 | boost::system::error_code ec; | |
1628 | ||
1629 | fs::path dangling_sym(dir / "dangling-sym"); | |
1630 | fs::path dangling_directory_sym(dir / "dangling-directory-sym"); | |
1631 | fs::path sym_d1(dir / "sym-d1"); | |
1632 | fs::path symsym_d1(dir / "symsym-d1"); | |
1633 | fs::path sym_f1(dir / "sym-f1"); | |
1634 | fs::path symsym_f1(dir / "symsym-f1"); | |
1635 | fs::create_symlink("does not exist", dangling_sym); | |
1636 | fs::create_directory_symlink("does not exist", dangling_directory_sym); | |
1637 | fs::create_directory_symlink(d1, sym_d1); | |
1638 | fs::create_directory_symlink(sym_d1, symsym_d1); | |
1639 | fs::create_symlink(f1, sym_f1); | |
1640 | fs::create_symlink(sym_f1, symsym_f1); | |
1641 | ||
1642 | // verify all cases detected as symlinks | |
1643 | BOOST_TEST_EQ(fs::symlink_status(dangling_sym, ec).type(), fs::symlink_file); | |
1644 | BOOST_TEST_EQ(fs::symlink_status(dangling_directory_sym, ec).type(), fs::symlink_file); | |
1645 | BOOST_TEST_EQ(fs::symlink_status(sym_d1, ec).type(), fs::symlink_file); | |
1646 | BOOST_TEST_EQ(fs::symlink_status(symsym_d1, ec).type(), fs::symlink_file); | |
1647 | BOOST_TEST_EQ(fs::symlink_status(sym_f1, ec).type(), fs::symlink_file); | |
1648 | BOOST_TEST_EQ(fs::symlink_status(symsym_f1, ec).type(), fs::symlink_file); | |
1649 | ||
1650 | // verify all cases resolve to the (possibly recursive) symlink target | |
1651 | BOOST_TEST_EQ(fs::status(dangling_sym, ec).type(), fs::file_not_found); | |
1652 | BOOST_TEST_EQ(fs::status(dangling_directory_sym, ec).type(), fs::file_not_found); | |
1653 | ||
1654 | BOOST_TEST_EQ(fs::status(sym_d1, ec).type(), fs::directory_file); | |
1655 | BOOST_TEST_EQ(fs::status(sym_d1 / "d1f1", ec).type(), fs::regular_file); | |
1656 | BOOST_TEST_EQ(fs::status(symsym_d1, ec).type(), fs::directory_file); | |
1657 | BOOST_TEST_EQ(fs::status(symsym_d1 / "d1f1", ec).type(), fs::regular_file); | |
1658 | BOOST_TEST_EQ(fs::status(sym_f1, ec).type(), fs::regular_file); | |
1659 | BOOST_TEST_EQ(fs::status(symsym_f1, ec).type(), fs::regular_file); | |
1660 | ||
1661 | #ifdef BOOST_WINDOWS_API | |
1662 | ||
1663 | // On Windows, telling if a filesystem entry is a symlink (or junction which is | |
1664 | // treated as a symlink), rather than some other kind of reparse point, requires some | |
1665 | // baroque code. See ticket #4663, filesystem objects falsely identified as symlinks. | |
1666 | // This test checks two directory entries created by Windows itself to verify | |
1667 | // is_symlink() works correctly. Try "dir /A %HOMEPATH%\.." from the command line to | |
1668 | // verify this test is valid on your version of Windows. It only works on Vista and | |
1669 | // later. | |
1670 | ||
1671 | fs::path users(getenv("HOMEDRIVE")); | |
1672 | BOOST_TEST(!users.empty()); | |
1673 | users /= "\\Users"; | |
1674 | BOOST_TEST(fs::exists(users)); | |
1675 | BOOST_TEST(fs::exists(users/"All Users")); | |
1676 | BOOST_TEST(fs::exists(users/"Default User")); | |
1677 | BOOST_TEST(fs::is_symlink(users/"All Users")); // dir /A reports <SYMLINKD> | |
1678 | BOOST_TEST(fs::is_symlink(users/"Default User")); // dir /A reports <JUNCTION> | |
1679 | ||
1680 | #endif | |
1681 | } | |
1682 | ||
1683 | // copy_symlink_tests ---------------------------------------------------------------// | |
1684 | ||
1685 | void copy_symlink_tests(const fs::path& f1x, const fs::path& d1x) | |
1686 | { | |
1687 | cout << "copy_symlink_tests..." << endl; | |
1688 | ||
1689 | BOOST_TEST(fs::exists(f1x)); | |
1690 | BOOST_TEST(fs::exists(d1x)); | |
1691 | fs::path sym1(d1x / "symlink1"); | |
1692 | fs::remove(sym1); // remove possible residue from prior testing | |
1693 | fs::create_symlink(f1x, sym1); | |
1694 | BOOST_TEST(fs::exists(sym1)); | |
1695 | BOOST_TEST(fs::is_symlink(sym1)); | |
1696 | fs::path sym2(d1x / "symlink2"); | |
1697 | fs::copy_symlink(sym1, sym2); | |
1698 | BOOST_TEST(fs::exists(sym2)); | |
1699 | BOOST_TEST(fs::is_symlink(sym2)); | |
1700 | //fs::path sym3(d1x / "symlink3"); | |
1701 | //fs::copy(sym1, sym3); | |
1702 | //BOOST_TEST(fs::exists(sym3)); | |
1703 | //BOOST_TEST(fs::is_symlink(sym3)); | |
1704 | ||
1705 | bool copy_ex_ok = false; | |
1706 | try { fs::copy_symlink("no-such-file", "new-symlink1"); } | |
1707 | catch (const fs::filesystem_error &) { copy_ex_ok = true; } | |
1708 | BOOST_TEST(copy_ex_ok); | |
1709 | ||
1710 | copy_ex_ok = false; | |
1711 | try { fs::copy_symlink(f1x, "new-symlink2"); } // should fail; f1x not symlink | |
1712 | catch (const fs::filesystem_error &) { copy_ex_ok = true; } | |
1713 | BOOST_TEST(copy_ex_ok); | |
1714 | } | |
1715 | ||
1716 | // write_time_tests ----------------------------------------------------------------// | |
1717 | ||
1718 | void write_time_tests(const fs::path& dirx) | |
92f5a8d4 | 1719 | { |
7c673cae FG |
1720 | cout << "write_time_tests..." << endl; |
1721 | ||
1722 | fs::path f1x = dirx / "foobar2"; | |
1723 | create_file(f1x, "foobar2"); | |
1724 | BOOST_TEST(fs::exists(f1x)); | |
1725 | BOOST_TEST(!fs::is_directory(f1x)); | |
1726 | BOOST_TEST(fs::is_regular_file(f1x)); | |
1727 | BOOST_TEST(fs::file_size(f1x) == 7); | |
1728 | verify_file(f1x, "foobar2"); | |
1729 | ||
1730 | // Some file system report last write time as local (FAT), while | |
1731 | // others (NTFS) report it as UTC. The C standard does not specify | |
92f5a8d4 | 1732 | // if time_t is local or UTC. |
7c673cae FG |
1733 | |
1734 | std::time_t ft = fs::last_write_time(f1x); | |
1735 | cout << "\n UTC last_write_time() for a file just created is " | |
1736 | << std::asctime(std::gmtime(&ft)) << endl; | |
1737 | ||
1738 | std::tm * tmp = std::localtime(&ft); | |
1739 | cout << "\n Year is " << tmp->tm_year << endl; | |
1740 | --tmp->tm_year; | |
1741 | cout << " Change year to " << tmp->tm_year << endl; | |
1742 | fs::last_write_time(f1x, std::mktime(tmp)); | |
1743 | std::time_t ft2 = fs::last_write_time(f1x); | |
1744 | cout << " last_write_time() for the file is now " | |
1745 | << std::asctime(std::gmtime(&ft2)) << endl; | |
1746 | BOOST_TEST(ft != fs::last_write_time(f1x)); | |
1747 | ||
1748 | cout << "\n Reset to current time" << endl; | |
1749 | fs::last_write_time(f1x, ft); | |
1750 | double time_diff = std::difftime(ft, fs::last_write_time(f1x)); | |
92f5a8d4 | 1751 | cout |
7c673cae FG |
1752 | << " original last_write_time() - current last_write_time() is " |
1753 | << time_diff << " seconds" << endl; | |
1754 | BOOST_TEST(time_diff >= -60.0 && time_diff <= 60.0); | |
1755 | } | |
1756 | ||
1757 | // platform_specific_tests ---------------------------------------------------------// | |
1758 | ||
1759 | void platform_specific_tests() | |
1760 | { | |
1761 | // Windows only tests | |
1762 | if (platform == "Windows") | |
1763 | { | |
1764 | cout << "Windows specific tests..." << endl; | |
1765 | if (!skip_long_windows_tests) | |
1766 | { | |
1767 | cout << " (may take several seconds)"<< endl; | |
1768 | ||
1769 | BOOST_TEST(!fs::exists(fs::path("//share-not"))); | |
1770 | BOOST_TEST(!fs::exists(fs::path("//share-not/"))); | |
1771 | BOOST_TEST(!fs::exists(fs::path("//share-not/foo"))); | |
1772 | } | |
1773 | cout << endl; | |
1774 | ||
1775 | BOOST_TEST(!fs::exists("tools/jam/src/:sys:stat.h")); // !exists() if ERROR_INVALID_NAME | |
1776 | BOOST_TEST(!fs::exists(":sys:stat.h")); // !exists() if ERROR_INVALID_PARAMETER | |
1777 | BOOST_TEST(dir.string().size() > 1 | |
1778 | && dir.string()[1] == ':'); // verify path includes drive | |
1779 | ||
1780 | BOOST_TEST(fs::system_complete("").empty()); | |
1781 | BOOST_TEST(fs::system_complete("/") == fs::initial_path().root_path()); | |
1782 | BOOST_TEST(fs::system_complete("foo") | |
1783 | == fs::initial_path() / "foo"); | |
1784 | ||
1785 | fs::path p1(fs::system_complete("/foo")); | |
1786 | BOOST_TEST_EQ(p1.string().size(), 6U); // this failed during v3 development due to bug | |
1787 | std::string s1(p1.string() ); | |
1788 | std::string s2(fs::initial_path().root_path().string()+"foo"); | |
1789 | BOOST_TEST_EQ(s1, s2); | |
1790 | ||
1791 | BOOST_TEST(fs::system_complete(fs::path(fs::initial_path().root_name())) | |
1792 | == fs::initial_path()); | |
1793 | BOOST_TEST(fs::system_complete(fs::path(fs::initial_path().root_name().string() | |
1794 | + "foo")).string() == fs::initial_path() / "foo"); | |
1795 | BOOST_TEST(fs::system_complete(fs::path("c:/")).generic_string() | |
1796 | == "c:/"); | |
1797 | BOOST_TEST(fs::system_complete(fs::path("c:/foo")).generic_string() | |
1798 | == "c:/foo"); | |
1799 | BOOST_TEST(fs::system_complete(fs::path("//share")).generic_string() | |
1800 | == "//share"); | |
1801 | ||
1802 | // Issue 9016 asked that NTFS directory junctions be recognized as directories. | |
1803 | // That is equivalent to recognizing them as symlinks, and then the normal symlink | |
1804 | // mechanism takes care of recognizing them as directories. | |
1805 | // | |
1806 | // Directory junctions are very similar to symlinks, but have some performance | |
1807 | // and other advantages over symlinks. They can be created from the command line | |
1808 | // with "mklink /j junction-name target-path". | |
1809 | ||
1810 | if (create_symlink_ok) // only if symlinks supported | |
1811 | { | |
1812 | cout << " directory junction tests..." << endl; | |
1813 | BOOST_TEST(fs::exists(dir)); | |
1814 | BOOST_TEST(fs::exists(dir / "d1/d1f1")); | |
1815 | fs::path junc(dir / "junc"); | |
1816 | if (fs::exists(junc)) | |
1817 | fs::remove(junc); | |
1818 | fs::path new_junc(dir / "new-junc"); | |
1819 | if (fs::exists(new_junc)) | |
1820 | fs::remove(new_junc); | |
1821 | ||
1822 | //cout << " dir is " << dir << endl; | |
1823 | //cout << " junc is " << junc << endl; | |
1824 | //cout << " new_junc is " << new_junc << endl; | |
1825 | //cout << " current_path() is " << fs::current_path() << endl; | |
1826 | ||
1827 | fs::path cur_path(fs::current_path()); | |
1828 | fs::current_path(dir); | |
1829 | //cout << " current_path() is " << fs::current_path() << endl; | |
92f5a8d4 | 1830 | BOOST_TEST(std::system("mklink /j junc d1") == 0); |
7c673cae FG |
1831 | //std::system("dir"); |
1832 | fs::current_path(cur_path); | |
1833 | //cout << " current_path() is " << fs::current_path() << endl; | |
1834 | ||
1835 | BOOST_TEST(fs::exists(junc)); | |
1836 | BOOST_TEST(fs::is_symlink(junc)); | |
1837 | BOOST_TEST(fs::is_directory(junc)); | |
1838 | BOOST_TEST(!fs::is_regular_file(junc)); | |
1839 | BOOST_TEST(fs::exists(junc / "d1f1")); | |
1840 | BOOST_TEST(fs::is_regular_file(junc / "d1f1")); | |
1841 | ||
1842 | int count = 0; | |
1843 | for (fs::directory_iterator itr(junc); | |
1844 | itr != fs::directory_iterator(); ++itr) | |
1845 | { | |
1846 | //cout << itr->path() << endl; | |
1847 | ++count; | |
1848 | } | |
1849 | cout << " iteration count is " << count << endl; | |
1850 | BOOST_TEST(count > 0); | |
1851 | ||
1852 | fs::rename(junc, new_junc); | |
1853 | BOOST_TEST(!fs::exists(junc)); | |
1854 | BOOST_TEST(fs::exists(new_junc)); | |
1855 | BOOST_TEST(fs::is_symlink(new_junc)); | |
1856 | BOOST_TEST(fs::is_directory(new_junc)); | |
1857 | BOOST_TEST(!fs::is_regular_file(new_junc)); | |
1858 | BOOST_TEST(fs::exists(new_junc / "d1f1")); | |
1859 | BOOST_TEST(fs::is_regular_file(new_junc / "d1f1")); | |
1860 | ||
1861 | fs::remove(new_junc); | |
1862 | BOOST_TEST(!fs::exists(new_junc / "d1f1")); | |
1863 | BOOST_TEST(!fs::exists(new_junc)); | |
1864 | BOOST_TEST(fs::exists(dir)); | |
1865 | BOOST_TEST(fs::exists(dir / "d1/d1f1")); | |
1866 | } | |
1867 | ||
1868 | } // Windows | |
1869 | ||
1870 | else if (platform == "POSIX") | |
1871 | { | |
1872 | cout << "POSIX specific tests..." << endl; | |
1873 | BOOST_TEST(fs::system_complete("").empty()); | |
1874 | BOOST_TEST(fs::initial_path().root_path().string() == "/"); | |
1875 | BOOST_TEST(fs::system_complete("/").string() == "/"); | |
1876 | BOOST_TEST(fs::system_complete("foo").string() | |
1877 | == fs::initial_path().string()+"/foo"); | |
1878 | BOOST_TEST(fs::system_complete("/foo").string() | |
1879 | == fs::initial_path().root_path().string()+"foo"); | |
1880 | } // POSIX | |
1881 | } | |
1882 | ||
1883 | // initial_tests -------------------------------------------------------------------// | |
1884 | ||
1885 | void initial_tests() | |
1886 | { | |
1887 | cout << "initial_tests..." << endl; | |
1888 | ||
1889 | cout << " current_path().string() is\n \"" | |
1890 | << fs::initial_path().string() | |
1891 | << "\"\n\n"; | |
1892 | BOOST_TEST(fs::initial_path() == fs::current_path()); | |
1893 | BOOST_TEST(fs::initial_path().is_absolute()); | |
1894 | BOOST_TEST(fs::current_path().is_absolute()); | |
1895 | BOOST_TEST(fs::initial_path().string() | |
1896 | == fs::current_path().string()); | |
1897 | } | |
1898 | ||
1899 | // space_tests ---------------------------------------------------------------------// | |
1900 | ||
1901 | void space_tests() | |
1902 | { | |
1903 | cout << "space_tests..." << endl; | |
1904 | ||
1905 | // make some reasonable assuptions for testing purposes | |
1906 | fs::space_info spi(fs::space(dir)); | |
1907 | BOOST_TEST(spi.capacity > 1000000); | |
1908 | BOOST_TEST(spi.free > 1000); | |
1909 | BOOST_TEST(spi.capacity > spi.free); | |
1910 | BOOST_TEST(spi.free >= spi.available); | |
1911 | ||
92f5a8d4 | 1912 | // it is convenient to display space, but older VC++ versions choke |
7c673cae FG |
1913 | # if !defined(BOOST_MSVC) || _MSC_VER >= 1300 // 1300 == VC++ 7.0 |
1914 | cout << " capacity = " << spi.capacity << '\n'; | |
1915 | cout << " free = " << spi.free << '\n'; | |
1916 | cout << " available = " << spi.available << '\n'; | |
1917 | # endif | |
1918 | } | |
1919 | ||
1920 | // equivalent_tests ----------------------------------------------------------------// | |
1921 | ||
1922 | void equivalent_tests(const fs::path& f1x) | |
1923 | { | |
1924 | cout << "equivalent_tests..." << endl; | |
1925 | ||
1926 | BOOST_TEST(CHECK_EXCEPTION(bad_equivalent, ENOENT)); | |
1927 | BOOST_TEST(fs::equivalent(f1x, dir / "f1")); | |
1928 | BOOST_TEST(fs::equivalent(dir, d1 / "..")); | |
1929 | BOOST_TEST(!fs::equivalent(f1x, dir)); | |
1930 | BOOST_TEST(!fs::equivalent(dir, f1x)); | |
1931 | BOOST_TEST(!fs::equivalent(d1, d2)); | |
1932 | BOOST_TEST(!fs::equivalent(dir, ng)); | |
1933 | BOOST_TEST(!fs::equivalent(ng, dir)); | |
1934 | BOOST_TEST(!fs::equivalent(f1x, ng)); | |
1935 | BOOST_TEST(!fs::equivalent(ng, f1x)); | |
1936 | } | |
1937 | ||
1938 | // temp_directory_path_tests -------------------------------------------------------// | |
1939 | // contributed by Jeff Flinn | |
92f5a8d4 | 1940 | |
7c673cae FG |
1941 | struct guarded_env_var |
1942 | { | |
1943 | struct previous_value | |
1944 | { | |
1945 | std::string m_name; | |
1946 | std::string m_string; | |
1947 | bool m_empty; | |
92f5a8d4 | 1948 | |
7c673cae FG |
1949 | previous_value(const char* name) |
1950 | : m_name(name) | |
1951 | , m_empty (true) | |
1952 | { | |
1953 | if(const char* value = getenv(name)) | |
1954 | { | |
1955 | m_string.assign(value); | |
1956 | m_empty = false; | |
1957 | } | |
1958 | else | |
1959 | { | |
1960 | m_empty = true; | |
1961 | } | |
1962 | } | |
1963 | ~previous_value() | |
1964 | { | |
11fdf7f2 TL |
1965 | m_empty? unsetenv_(m_name.c_str()) |
1966 | : setenv_(m_name.c_str(), m_string.c_str(), 1); | |
7c673cae FG |
1967 | } |
1968 | }; | |
92f5a8d4 | 1969 | |
7c673cae | 1970 | previous_value m_previous_value; |
92f5a8d4 TL |
1971 | |
1972 | guarded_env_var(const char* name, const char* value) | |
1973 | : m_previous_value(name) | |
7c673cae FG |
1974 | { |
1975 | // std::cout << name << " old value is \"" << getenv(name) << "\"" << std::endl; | |
11fdf7f2 | 1976 | value ? setenv_(name, value, 1) : unsetenv_(name); |
7c673cae FG |
1977 | // std::cout << name << " new value is \"" << getenv(name) << "\"" << std::endl; |
1978 | } | |
1979 | }; | |
1980 | ||
1981 | void temp_directory_path_tests() | |
1982 | { | |
1983 | { | |
1984 | cout << "temp_directory_path_tests..." << endl; | |
11fdf7f2 | 1985 | cout << " temp_directory_path() is " << fs::temp_directory_path() << endl; |
7c673cae FG |
1986 | |
1987 | #if defined(BOOST_WINDOWS_API) | |
1988 | ||
1989 | //**************************************************************************************// | |
1990 | // Bug in GCC 4.9 getenv() when !defined(__GXX_EXPERIMENTAL_CXX0X__) makes these | |
92f5a8d4 | 1991 | // tests meaningless, so skip them |
7c673cae FG |
1992 | //**************************************************************************************// |
1993 | ||
1994 | #if defined(__CYGWIN__) && !defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ == 4 | |
1995 | cout << "Bug in GCC 4.9 getenv() when !defined(__GXX_EXPERIMENTAL_CXX0X__) makes these" | |
1996 | "tests meaningless, so skip them" << endl; | |
1997 | return; | |
1998 | #endif | |
1999 | // Test ticket #5300, temp_directory_path failure on Windows with path length > 130. | |
92f5a8d4 | 2000 | // (This test failed prior to the fix being applied.) |
7c673cae FG |
2001 | { |
2002 | const wchar_t long_name[] = | |
2003 | L"12345678901234567890123456789012345678901234567890" | |
2004 | L"12345678901234567890123456789012345678901234567890" | |
2005 | L"12345678901234567890123456789012345678901234567890#" // total 151 chars | |
2006 | ; | |
2007 | fs::path p (temp_dir); | |
2008 | p /= long_name; | |
2009 | fs::create_directory(p); | |
2010 | ||
2011 | guarded_env_var tmp_guard("TMP", p.string().c_str()); | |
2012 | error_code ec; | |
2013 | fs::path tmp_path = fs::temp_directory_path(ec); | |
2014 | BOOST_TEST(!ec); | |
2015 | BOOST_TEST_EQ(p, tmp_path); | |
2016 | fs::remove(p); | |
2017 | } | |
2018 | ||
2019 | // Test ticket #10388, null character at end of filesystem::temp_directory_path path | |
2020 | { | |
2021 | guarded_env_var tmp_guard("TMP", fs::initial_path().string().c_str()); | |
2022 | ||
2023 | error_code ec; | |
2024 | fs::path tmp_path = fs::temp_directory_path(ec); | |
92f5a8d4 | 2025 | BOOST_TEST_EQ(tmp_path, fs::initial_path()); |
7c673cae FG |
2026 | } |
2027 | ||
2028 | #endif | |
2029 | BOOST_TEST(!fs::temp_directory_path().empty()); | |
2030 | BOOST_TEST(exists(fs::temp_directory_path())); | |
11fdf7f2 | 2031 | fs::path ph = fs::temp_directory_path() / fs::unique_path("temp_directory_path_test_%%%%_%%%%.txt"); |
7c673cae FG |
2032 | { |
2033 | if(exists(ph)) remove(ph); | |
2034 | std::ofstream f(ph.BOOST_FILESYSTEM_C_STR); | |
2035 | f << "passed"; | |
2036 | } | |
2037 | BOOST_TEST(exists(ph)); | |
2038 | { | |
2039 | std::ifstream f(ph.BOOST_FILESYSTEM_C_STR); | |
2040 | std::string s; | |
2041 | f >> s; | |
2042 | BOOST_TEST(s == "passed"); | |
2043 | } | |
2044 | remove(ph); | |
2045 | BOOST_TEST(!exists(ph)); | |
2046 | } | |
92f5a8d4 | 2047 | |
7c673cae FG |
2048 | fs::path test_temp_dir = temp_dir; |
2049 | ||
2050 | #if defined(BOOST_POSIX_API) | |
2051 | { | |
2052 | struct guarded_tmp_vars | |
2053 | { | |
2054 | guarded_env_var m_tmpdir ; | |
2055 | guarded_env_var m_tmp ; | |
2056 | guarded_env_var m_temp ; | |
2057 | guarded_env_var m_tempdir; | |
2058 | ||
2059 | guarded_tmp_vars | |
92f5a8d4 TL |
2060 | ( const fs::path::value_type* tmpdir |
2061 | , const fs::path::value_type* tmp | |
2062 | , const fs::path::value_type* temp | |
7c673cae FG |
2063 | , const fs::path::value_type* tempdir |
2064 | ) | |
2065 | : m_tmpdir ("TMPDIR" , tmpdir ) | |
2066 | , m_tmp ("TMP" , tmp ) | |
2067 | , m_temp ("TEMP" , temp ) | |
2068 | , m_tempdir("TEMPDIR", tempdir) | |
92f5a8d4 | 2069 | {} |
7c673cae FG |
2070 | }; |
2071 | ||
2072 | { | |
2073 | guarded_tmp_vars vars(test_temp_dir.c_str(), 0, 0, 0); | |
2074 | fs::path ph = fs::temp_directory_path(); | |
2075 | BOOST_TEST(equivalent(test_temp_dir, ph)); | |
2076 | } | |
2077 | { | |
2078 | guarded_tmp_vars vars(0, test_temp_dir.c_str(), 0, 0); | |
2079 | fs::path ph = fs::temp_directory_path(); | |
2080 | BOOST_TEST(equivalent(test_temp_dir, ph)); | |
2081 | } | |
2082 | { | |
2083 | guarded_tmp_vars vars(0, 0, test_temp_dir.c_str(), 0); | |
2084 | fs::path ph = fs::temp_directory_path(); | |
2085 | BOOST_TEST(equivalent(test_temp_dir, ph)); | |
2086 | } | |
2087 | { | |
2088 | guarded_tmp_vars vars(0, 0, 0, test_temp_dir.c_str()); | |
2089 | fs::path ph = fs::temp_directory_path(); | |
2090 | BOOST_TEST(equivalent(test_temp_dir, ph)); | |
2091 | } | |
2092 | } | |
2093 | #endif | |
2094 | ||
2095 | #if defined(BOOST_WINDOWS_API) | |
2096 | ||
2097 | struct guarded_tmp_vars | |
2098 | { | |
2099 | guarded_env_var m_tmp ; | |
2100 | guarded_env_var m_temp ; | |
2101 | guarded_env_var m_localappdata; | |
2102 | guarded_env_var m_userprofile; | |
2103 | ||
2104 | guarded_tmp_vars | |
92f5a8d4 | 2105 | ( const char* tmp |
7c673cae FG |
2106 | , const char* temp |
2107 | , const char* localappdata | |
2108 | , const char* userprofile | |
2109 | ) | |
2110 | : m_tmp ("TMP" , tmp ) | |
2111 | , m_temp ("TEMP" , temp ) | |
2112 | , m_localappdata ("LOCALAPPDATA" , localappdata) | |
2113 | , m_userprofile ("USERPROFILE" , userprofile ) | |
92f5a8d4 | 2114 | {} |
7c673cae FG |
2115 | }; |
2116 | ||
2117 | // test the GetWindowsDirectoryW()/Temp fallback | |
2118 | { | |
2119 | guarded_tmp_vars vars(0, 0, 0, 0); | |
2120 | error_code ec; | |
2121 | fs::path ph = fs::temp_directory_path(ec); | |
2122 | BOOST_TEST(!ec); | |
2123 | cout << "Fallback test, temp_directory_path() returned " << ph << endl; | |
2124 | } | |
2125 | ||
2126 | { | |
2127 | guarded_tmp_vars vars(test_temp_dir.string().c_str(), 0, 0, 0); | |
2128 | fs::path ph = fs::temp_directory_path(); | |
2129 | BOOST_TEST(equivalent(test_temp_dir, ph)); | |
2130 | } | |
2131 | { | |
2132 | guarded_tmp_vars vars(0, test_temp_dir.string().c_str(), 0, 0); | |
2133 | fs::path ph = fs::temp_directory_path(); | |
2134 | BOOST_TEST(equivalent(test_temp_dir, ph)); | |
2135 | } | |
2136 | ||
2137 | fs::create_directory(test_temp_dir / L"Temp"); | |
2138 | { | |
2139 | guarded_tmp_vars vars(0, 0, test_temp_dir.string().c_str(), 0); | |
2140 | fs::path ph = fs::temp_directory_path(); | |
2141 | BOOST_TEST(equivalent(test_temp_dir/L"Temp", ph)); | |
2142 | cout << "temp_directory_path() returned " << ph << endl; | |
2143 | } | |
2144 | { | |
2145 | guarded_tmp_vars vars(0, 0, 0, test_temp_dir.string().c_str()); | |
2146 | fs::path ph = fs::temp_directory_path(); | |
2147 | BOOST_TEST(equivalent(test_temp_dir/L"Temp", ph)); | |
2148 | cout << "temp_directory_path() returned " << ph << endl; | |
2149 | } | |
92f5a8d4 | 2150 | #endif |
7c673cae FG |
2151 | } |
2152 | ||
2153 | // weakly_canonical_tests ----------------------------------------------------------// | |
2154 | ||
2155 | void weakly_canonical_tests() | |
2156 | { | |
2157 | cout << "weakly_canonical_tests..." << endl; | |
2158 | cout << " dir is " << dir << endl; | |
2159 | ||
2160 | BOOST_TEST_EQ(fs::weakly_canonical("no-such/foo/bar"), "no-such/foo/bar"); | |
2161 | BOOST_TEST_EQ(fs::weakly_canonical("no-such/foo/../bar"), "no-such/bar"); | |
2162 | BOOST_TEST_EQ(fs::weakly_canonical(dir), dir); | |
2163 | BOOST_TEST_EQ(fs::weakly_canonical(dir/"no-such/foo/bar"), dir/"no-such/foo/bar"); | |
2164 | BOOST_TEST_EQ(fs::weakly_canonical(dir/"no-such/foo/../bar"), dir/"no-such/bar"); | |
2165 | BOOST_TEST_EQ(fs::weakly_canonical(dir/"../no-such/foo/../bar"), | |
2166 | dir.parent_path()/"no-such/bar"); | |
2167 | BOOST_TEST_EQ(fs::weakly_canonical("c:/no-such/foo/bar"), "c:/no-such/foo/bar"); | |
2168 | ||
2169 | fs::create_directory_symlink(dir / "d1", dir / "sld1"); | |
2170 | BOOST_TEST_EQ(fs::weakly_canonical(dir / "sld1/foo/bar"), dir / "d1/foo/bar"); | |
2171 | ||
2172 | BOOST_TEST_EQ(relative(dir / "sld1/foo/bar/baz", dir / "d1/foo"), "bar/baz"); | |
2173 | } | |
2174 | ||
2175 | // _tests --------------------------------------------------------------------------// | |
2176 | ||
2177 | //void _tests() | |
2178 | //{ | |
2179 | // cout << "_tests..." << endl; | |
2180 | //} | |
92f5a8d4 | 2181 | |
7c673cae FG |
2182 | } // unnamed namespace |
2183 | ||
2184 | //------------------------------------------------------------------------------------// | |
2185 | // // | |
2186 | // main // | |
2187 | // // | |
2188 | //------------------------------------------------------------------------------------// | |
2189 | ||
2190 | int cpp_main(int argc, char* argv[]) | |
2191 | { | |
2192 | // document state of critical macros | |
2193 | #ifdef BOOST_POSIX_API | |
2194 | cout << "BOOST_POSIX_API is defined\n"; | |
2195 | #endif | |
2196 | #ifdef BOOST_WINDOWS_API | |
2197 | cout << "BOOST_WINDOWS_API is defined\n"; | |
2198 | #endif | |
2199 | ||
2200 | for (; argc > 1; --argc, ++argv) | |
2201 | { | |
2202 | if (*argv[1]=='-' && *(argv[1]+1)=='t') | |
2203 | report_throws = true; | |
2204 | else if (*argv[1]=='-' && *(argv[1]+1)=='x') | |
2205 | cleanup = false; | |
2206 | else if (*argv[1]=='-' && *(argv[1]+1)=='w') | |
2207 | skip_long_windows_tests = true; | |
2208 | } | |
2209 | ||
2210 | // The choice of platform to test is made at runtime rather than compile-time | |
2211 | // so that compile errors for all platforms will be detected even though | |
2212 | // only the current platform is runtime tested. | |
2213 | # if defined(BOOST_POSIX_API) | |
2214 | platform = "POSIX"; | |
2215 | # elif defined(BOOST_WINDOWS_API) | |
2216 | platform = "Windows"; | |
92f5a8d4 | 2217 | language_id = ::GetUserDefaultUILanguage(); |
7c673cae FG |
2218 | # else |
2219 | # error neither BOOST_POSIX_API nor BOOST_WINDOWS_API is defined. See boost/system/api_config.hpp | |
2220 | # endif | |
2221 | cout << "API is " << platform << endl; | |
2222 | cout << "initial_path() is " << fs::initial_path() << endl; | |
2223 | fs::path ip = fs::initial_path(); | |
2224 | do_the_right_thing_tests(); // compile-only tests, but call anyhow to suppress warnings | |
2225 | ||
2226 | for (fs::path::const_iterator it = ip.begin(); it != ip.end(); ++it) | |
2227 | { | |
2228 | if (it != ip.begin()) | |
2229 | cout << ", "; | |
2230 | cout << *it; | |
2231 | } | |
2232 | cout << endl; | |
2233 | ||
2234 | dir = fs::initial_path() / temp_dir; | |
2235 | ||
2236 | if (fs::exists(dir)) | |
2237 | { | |
2238 | cout << "remove residue from prior failed tests..." << endl; | |
2239 | fs::remove_all(dir); | |
2240 | } | |
2241 | BOOST_TEST(!fs::exists(dir)); | |
2242 | ||
2243 | // several functions give unreasonable results if uintmax_t isn't 64-bits | |
2244 | cout << "sizeof(boost::uintmax_t) = " << sizeof(boost::uintmax_t) << '\n'; | |
2245 | BOOST_TEST(sizeof(boost::uintmax_t) >= 8); | |
2246 | ||
2247 | initial_tests(); | |
2248 | predicate_and_status_tests(); | |
2249 | exception_tests(); | |
2250 | create_directory_tests(); | |
2251 | current_directory_tests(); | |
2252 | space_tests(); | |
2253 | ||
2254 | // create a directory tree that can be used by subsequent tests | |
2255 | // | |
2256 | // dir | |
2257 | // d1 | |
2258 | // d1f1 // an empty file | |
2259 | // f0 // an empty file | |
2260 | // f1 // a file containing "file f1" | |
2261 | // | |
2262 | create_tree(); | |
2263 | ||
2264 | status_of_nonexistent_tests(); | |
2265 | status_error_reporting_tests(); | |
2266 | directory_iterator_tests(); | |
2267 | create_directories_tests(); // must run AFTER directory_iterator_tests | |
2268 | ||
2269 | bad_create_directory_path = f1; | |
2270 | BOOST_TEST(CHECK_EXCEPTION(bad_create_directory, EEXIST)); | |
2271 | fs::file_status stat = fs::status(f1); | |
2272 | BOOST_TEST(fs::status_known(stat)); | |
2273 | BOOST_TEST(fs::exists(stat)); | |
2274 | BOOST_TEST(!fs::is_directory(stat)); | |
2275 | BOOST_TEST(fs::is_regular_file(stat)); | |
2276 | BOOST_TEST(!fs::is_other(stat)); | |
2277 | BOOST_TEST(!fs::is_symlink(stat)); | |
92f5a8d4 | 2278 | |
7c673cae FG |
2279 | equivalent_tests(f1); |
2280 | create_hard_link_tests(); | |
2281 | create_symlink_tests(); | |
2282 | resize_file_tests(); | |
2283 | absolute_tests(); | |
2284 | canonical_basic_tests(); | |
2285 | permissions_tests(); | |
2286 | copy_file_tests(f1, d1); | |
2287 | if (create_symlink_ok) // only if symlinks supported | |
2288 | { | |
2289 | symlink_status_tests(); | |
2290 | copy_symlink_tests(f1, d1); | |
2291 | canonical_symlink_tests(); | |
2292 | weakly_canonical_tests(); | |
2293 | } | |
2294 | iterator_status_tests(); // lots of cases by now, so a good time to test | |
2295 | // dump_tree(dir); | |
2296 | recursive_directory_iterator_tests(); | |
2297 | recursive_iterator_status_tests(); // lots of cases by now, so a good time to test | |
2298 | rename_tests(); | |
2299 | remove_tests(dir); | |
2300 | if (create_symlink_ok) // only if symlinks supported | |
2301 | remove_symlink_tests(); | |
2302 | write_time_tests(dir); | |
2303 | temp_directory_path_tests(); | |
2304 | ||
2305 | platform_specific_tests(); // do these last since they take a lot of time on Windows, | |
2306 | // and that's a pain during manual testing | |
92f5a8d4 | 2307 | |
7c673cae FG |
2308 | cout << "testing complete" << endl; |
2309 | ||
2310 | // post-test cleanup | |
2311 | if (cleanup) | |
2312 | { | |
2313 | cout << "post-test removal of " << dir << endl; | |
2314 | BOOST_TEST(fs::remove_all(dir) != 0); | |
2315 | // above was added just to simplify testing, but it ended up detecting | |
92f5a8d4 | 2316 | // a bug (failure to close an internal search handle). |
7c673cae FG |
2317 | cout << "post-test removal complete" << endl; |
2318 | // BOOST_TEST(!fs::exists(dir)); // nice test, but doesn't play well with TortoiseGit cache | |
2319 | } | |
2320 | ||
2321 | cout << "returning from main()" << endl; | |
2322 | return ::boost::report_errors(); | |
2323 | } // main |