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