]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/filesystem/test/operations_test.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / filesystem / test / operations_test.cpp
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
13 #ifndef BOOST_FILESYSTEM_NO_DEPRECATED
14 # define BOOST_FILESYSTEM_NO_DEPRECATED
15 #endif
16 #ifndef BOOST_SYSTEM_NO_DEPRECATED
17 # define BOOST_SYSTEM_NO_DEPRECATED
18 #endif
19
20 #include <boost/filesystem/operations.hpp>
21 #include <boost/filesystem/directory.hpp>
22 #include <boost/filesystem/exception.hpp>
23 #include <boost/filesystem/file_status.hpp>
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>
31 #include <boost/detail/lightweight_test.hpp>
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);
58
59 return std::wstring(s.begin(), s.end());
60 }
61
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
68 inline void setenv_(const char* name, const fs::path::value_type* val, int)
69 {
70 SetEnvironmentVariableW(convert(name).c_str(), val);
71 }
72
73 inline void setenv_(const char* name, const char* val, int)
74 {
75 SetEnvironmentVariableW(convert(name).c_str(), convert(val).c_str());
76 }
77
78 inline void unsetenv_(const char* name)
79 {
80 SetEnvironmentVariableW(convert(name).c_str(), 0);
81 }
82
83 #else
84
85 #include <stdlib.h> // allow unqualifed calls to env funcs on SunOS
86
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
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
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 }
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 }
219
220 void bad_directory_size()
221 {
222 fs::file_size(fs::current_path());
223 }
224
225 fs::path bad_create_directory_path;
226 void bad_create_directory()
227 {
228 fs::create_directory(bad_create_directory_path);
229 }
230
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;
278 // for (fs::recursive_directory_iterator it (root, fs::directory_options::follow_directory_symlink);
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
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
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
322 // to what(), so check only the initial portion:
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 }
380 catch (const fs::filesystem_error& x)
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
407 try
408 {
409 fs::file_size(ng); // will throw
410 }
411 catch (fs::filesystem_error& ex)
412 {
413 BOOST_TEST(ex.path1().string() == " no-way, Jose");
414 }
415
416 cout << " exception_tests complete" << endl;
417 }
418
419 #if defined(BOOST_GCC) && BOOST_GCC >= 80000
420 #pragma GCC diagnostic pop
421 #endif
422
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"
430
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);
511
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]
593 // augmented to test single pass semantics of a copied iterator [#12578]
594 fs::directory_iterator itx(dir);
595 fs::directory_iterator itx2(itx);
596 BOOST_TEST(itx == itx2);
597 const fs::path p1 = (*itx++).path();
598 BOOST_TEST(itx == itx2);
599 BOOST_TEST(itx != fs::directory_iterator());
600 const fs::path p2 = (*itx++).path();
601 BOOST_TEST(itx == itx2);
602 BOOST_TEST(p1 != p2);
603 ++itx;
604 BOOST_TEST(itx == itx2);
605 ++itx;
606 BOOST_TEST(itx == itx2);
607 BOOST_TEST(itx == fs::directory_iterator());
608 BOOST_TEST(itx2 == fs::directory_iterator());
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;
635 {
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 {
648 //cout << " walk_tree" << endl;
649 error_code ec;
650 int d1f1_count = 0;
651 for (fs::recursive_directory_iterator it (dir,
652 recursive ? (fs::directory_options::follow_directory_symlink | fs::directory_options::skip_dangling_symlinks) : fs::directory_options::none);
653 it != fs::recursive_directory_iterator();
654 it.increment(ec))
655 {
656 //cout << " " << it->path() << " : " << ec << endl;
657 if (it->path().filename() == "d1f1")
658 ++d1f1_count;
659 }
660 //cout << " last error : " << ec << endl;
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;
675 fs::recursive_directory_iterator it(dir, fs::directory_options::none);
676 fs::recursive_directory_iterator it2(it); // test single pass shallow copy semantics
677 for (;
678 it != fs::recursive_directory_iterator();
679 it.increment(ec))
680 {
681 if (it->path().filename() == "d1f1")
682 ++d1f1_count;
683 BOOST_TEST(it == it2); // verify single pass shallow copy semantics
684 }
685 BOOST_TEST(!ec);
686 BOOST_TEST_EQ(d1f1_count, 1);
687 BOOST_TEST(it == it2); // verify single pass shallow copy semantics
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 }
755
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 }
769
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 }
815
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;
830 cout
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));
861
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);
913 cout << std::oct;
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);
917 cout << " status(p).permissions(): " << fs::status(p).permissions() << endl;
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 }
932
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 }
1037
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 }
1067
1068 // create_directory_tests ----------------------------------------------------------//
1069
1070 void create_directory_tests()
1071 {
1072 cout << "create_directory_tests..." << endl;
1073
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);
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 }
1138
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
1170 error_code ec;
1171 BOOST_TEST(!fs::create_directories("", ec));
1172 BOOST_TEST(ec);
1173
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
1199
1200 fs::path p = dir / "level1/." / "level2/./.." / "level3/";
1201 // trailing "/.", "/./..", and "/" in the above elements test ticket #7258 and
1202 // related issues
1203
1204 cout << " p is " << p << endl;
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 {
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));
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;
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);
1286 BOOST_TEST(&ec.category() == &poison_category());
1287 fs::file_status s = fs::status(".",ec);
1288 BOOST_TEST(ec.value() == 0);
1289 BOOST_TEST(ec.category() == system_category());
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);
1298 BOOST_TEST(ec.category() == system_category());
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);
1312 BOOST_TEST(ec.category() == system_category());
1313 ec.assign(-1,poison_category());
1314 BOOST_TEST(!fs::is_regular_file(".", ec));
1315 BOOST_TEST(ec.value() == 0);
1316 BOOST_TEST(ec.category() == system_category());
1317 ec.assign(-1,poison_category());
1318 BOOST_TEST(fs::is_directory(".", ec));
1319 BOOST_TEST(ec.value() == 0);
1320 BOOST_TEST(ec.category() == system_category());
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);
1326 BOOST_TEST(ec.category() == system_category());
1327 ec.assign(-1,poison_category());
1328 BOOST_TEST(!fs::is_regular_file(p, ec));
1329 BOOST_TEST(ec.value() != 0);
1330 BOOST_TEST(ec.category() == system_category());
1331 ec.assign(-1,poison_category());
1332 BOOST_TEST(!fs::is_directory(p, ec));
1333 BOOST_TEST(ec.value() != 0);
1334 BOOST_TEST(ec.category() == system_category());
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 ------------------------------------------------------------//
1368
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)
1719 {
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
1732 // if time_t is local or UTC.
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));
1751 cout
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;
1830 BOOST_TEST(std::system("mklink /j junc d1") == 0);
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
1912 // it is convenient to display space, but older VC++ versions choke
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
1940
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;
1948
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 {
1965 m_empty? unsetenv_(m_name.c_str())
1966 : setenv_(m_name.c_str(), m_string.c_str(), 1);
1967 }
1968 };
1969
1970 previous_value m_previous_value;
1971
1972 guarded_env_var(const char* name, const char* value)
1973 : m_previous_value(name)
1974 {
1975 // std::cout << name << " old value is \"" << getenv(name) << "\"" << std::endl;
1976 value ? setenv_(name, value, 1) : unsetenv_(name);
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;
1985 cout << " temp_directory_path() is " << fs::temp_directory_path() << endl;
1986
1987 #if defined(BOOST_WINDOWS_API)
1988
1989 //**************************************************************************************//
1990 // Bug in GCC 4.9 getenv() when !defined(__GXX_EXPERIMENTAL_CXX0X__) makes these
1991 // tests meaningless, so skip them
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.
2000 // (This test failed prior to the fix being applied.)
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);
2025 BOOST_TEST_EQ(tmp_path, fs::initial_path());
2026 }
2027
2028 #endif
2029 BOOST_TEST(!fs::temp_directory_path().empty());
2030 BOOST_TEST(exists(fs::temp_directory_path()));
2031 fs::path ph = fs::temp_directory_path() / fs::unique_path("temp_directory_path_test_%%%%_%%%%.txt");
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 }
2047
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
2060 ( const fs::path::value_type* tmpdir
2061 , const fs::path::value_type* tmp
2062 , const fs::path::value_type* temp
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)
2069 {}
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
2105 ( const char* tmp
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 )
2114 {}
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 }
2150 #endif
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 //}
2181
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";
2217 language_id = ::GetUserDefaultUILanguage();
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));
2278
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
2307
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
2316 // a bug (failure to close an internal search handle).
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