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