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