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