Imported Upstream version 1.64.0
[platform/upstream/boost.git] / libs / filesystem / test / path_unit_test.cpp
1 //  filesystem path_unit_test.cpp  ---------------------------------------------------  //
2
3 //  Copyright Beman Dawes 2008, 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 //  ----------------------------------------------------------------------------------  //
11 //
12 //  The purpose of this test is to ensure that each function in the public
13 //  interface can be called with arguments of the appropriate types. It does
14 //  not attempt to verify that the full range of values for each argument
15 //  are processed correctly.
16 //
17 //  For full functionality tests, including probes with many different argument
18 //  values, see path_test.cpp and other test programs.
19 //
20 //  ----------------------------------------------------------------------------------  //
21
22 #include <boost/config/warning_disable.hpp>
23
24 //  See deprecated_test for tests of deprecated features
25 #ifndef BOOST_FILESYSTEM_NO_DEPRECATED 
26 # define BOOST_FILESYSTEM_NO_DEPRECATED
27 #endif
28 #ifndef BOOST_SYSTEM_NO_DEPRECATED 
29 # define BOOST_SYSTEM_NO_DEPRECATED
30 #endif
31
32 #include <boost/filesystem/path.hpp>
33
34 #include <boost/filesystem/detail/utf8_codecvt_facet.hpp>  // for imbue tests
35 #include "test_codecvt.hpp"                                // for codecvt arg tests
36 #include <boost/detail/lightweight_test_report.hpp>
37 #include <boost/smart_ptr.hpp>  // used constructor tests
38 #include <boost/functional/hash.hpp>
39
40 #include <iostream>
41 #include <iomanip>
42 #include <sstream>
43 #include <string>
44 #include <cstring>
45 #include <cwchar>
46 #include <locale>
47 #include <list>
48
49 namespace fs = boost::filesystem;
50 namespace bs = boost::system;
51 using boost::filesystem::path;
52 using std::cout;
53 using std::endl;
54 using std::string;
55 using std::wstring;
56
57 #define CHECK(x) check(x, __FILE__, __LINE__)
58 #define PATH_IS(a, b) check_path(a, b, __FILE__, __LINE__)
59 #define NATIVE_IS(p, s, ws) check_native(p, s, ws, __FILE__, __LINE__)
60 #define IS(a,b) check_equal(a, b, __FILE__, __LINE__)
61
62 #if defined(_MSC_VER)
63 # pragma warning(push) // Save warning settings.
64 # pragma warning(disable : 4428) // Disable universal-character-name encountered in source warning.
65 #endif
66
67 namespace
68 {
69
70   boost::system::error_code ec;
71   const boost::system::error_code ok;
72   const boost::system::error_code ng(-1, boost::system::system_category());
73
74   std::string platform(BOOST_PLATFORM);
75
76   void check_path(const path& source,
77               const wstring& expected, const char* file, int line)
78   {
79     if (source == expected) return;
80
81     ++::boost::detail::test_errors();
82
83     std::cout << file;
84     std::wcout << L'(' << line << L"): source.wstring(): \""
85                << source.wstring()
86                << L"\" != expected: \"" << expected
87                << L"\"\n" ;
88   }
89
90 # ifdef BOOST_WINDOWS_API
91   void check_native(const path& p,
92     const string&, const wstring& expected, const char* file, int line)
93 # else
94   void check_native(const path& p,
95     const string& expected, const wstring&, const char* file, int line)
96 # endif
97   {
98     if (p.native() == expected) return;
99
100     ++::boost::detail::test_errors();
101
102     std::cout << file  << '(' << line << "): native() is not equal expected\n"
103       "  native---: " << std::hex;
104     path::string_type nat(p.native());
105     for (path::string_type::const_iterator it = nat.begin(); it != nat.end(); ++it)
106       std::cout << long(*it) << ' ';
107     std::cout << "\n  expected-: ";
108     for (path::string_type::const_iterator it = expected.begin(); it != expected.end(); ++it)
109       std::cout << long(*it) << ' ';
110     std::cout << std::dec << std::endl;
111   }
112
113   template< class T1, class T2 >
114   void check_equal(const T1& value,
115                     const T2& expected, const char* file, int line)
116   {
117     if (value == expected) return;
118
119     ++::boost::detail::test_errors();
120
121     std::cout << file;
122
123     std::wcout << L'(' << line << L"): value: \"" << value
124                << L"\" != expected: \"" << expected
125                << L"\"\n" ;
126   }
127
128   void check(bool ok_, const char* file, int line)
129   {
130     if (ok_) return;
131
132     ++::boost::detail::test_errors();
133
134     std::cout << file << '(' << line << "): test failed\n";
135   }
136
137   string s("string");
138   wstring ws(L"wstring");
139   std::list<char> l;      // see main() for initialization to s, t, r, i, n, g
140   std::list<wchar_t> wl;  // see main() for initialization to w, s, t, r, i, n, g
141   std::vector<char> v;      // see main() for initialization to f, u, z
142   std::vector<wchar_t> wv;  // see main() for initialization to w, f, u, z
143
144   class Base {};
145   class Derived : public Base {};
146   void fun(const boost::shared_ptr< Base >&) {}
147
148   //  test_constructors  ---------------------------------------------------------------//
149
150   void test_constructors()
151   {
152     std::cout << "testing constructors..." << std::endl;
153
154     path x0;                                           // default constructor
155     PATH_IS(x0, L"");
156     BOOST_TEST_EQ(x0.native().size(), 0U);
157
158     path x1(l.begin(), l.end());                       // iterator range char
159     PATH_IS(x1, L"string");
160     BOOST_TEST_EQ(x1.native().size(), 6U);
161
162     path x2(x1);                                       // copy constructor
163     PATH_IS(x2, L"string");
164     BOOST_TEST_EQ(x2.native().size(), 6U);
165
166     path x3(wl.begin(), wl.end());                     // iterator range wchar_t
167     PATH_IS(x3, L"wstring");
168     BOOST_TEST_EQ(x3.native().size(), 7U);
169
170     // contiguous containers
171     path x4(string("std::string"));                    // std::string
172     PATH_IS(x4, L"std::string");
173     BOOST_TEST_EQ(x4.native().size(), 11U);
174
175     path x5(wstring(L"std::wstring"));                 // std::wstring
176     PATH_IS(x5, L"std::wstring");
177     BOOST_TEST_EQ(x5.native().size(), 12U);
178
179     path x4v(v);                                       // std::vector<char>
180     PATH_IS(x4v, L"fuz");
181     BOOST_TEST_EQ(x4v.native().size(), 3U);
182
183     path x5v(wv);                                      // std::vector<wchar_t>
184     PATH_IS(x5v, L"wfuz");
185     BOOST_TEST_EQ(x5v.native().size(), 4U);
186
187     path x6("array char");                             // array char
188     PATH_IS(x6, L"array char");
189     BOOST_TEST_EQ(x6.native().size(), 10U);
190
191     path x7(L"array wchar_t");                         // array wchar_t
192     PATH_IS(x7, L"array wchar_t");
193     BOOST_TEST_EQ(x7.native().size(), 13U);
194
195     char char_array[100];
196     std::strcpy(char_array, "big array char");
197     path x6o(char_array);                              // array char, only partially full
198     PATH_IS(x6o, L"big array char");
199     BOOST_TEST_EQ(x6o.native().size(), 14U);
200
201     wchar_t wchar_array[100];
202     std::wcscpy(wchar_array, L"big array wchar_t");
203     path x7o(wchar_array);                             // array char, only partially full
204     PATH_IS(x7o, L"big array wchar_t");
205     BOOST_TEST_EQ(x7o.native().size(), 17U);
206
207     path x8(s.c_str());                                // const char* null terminated
208     PATH_IS(x8, L"string");
209     BOOST_TEST_EQ(x8.native().size(), 6U);
210
211     path x9(ws.c_str());                               // const wchar_t* null terminated
212     PATH_IS(x9, L"wstring");
213     BOOST_TEST_EQ(x9.native().size(), 7U);
214
215     path x8nc(const_cast<char*>(s.c_str()));           // char* null terminated
216     PATH_IS(x8nc, L"string");
217     BOOST_TEST_EQ(x8nc.native().size(), 6U);
218
219     path x9nc(const_cast<wchar_t*>(ws.c_str()));       // wchar_t* null terminated
220     PATH_IS(x9nc, L"wstring");
221     BOOST_TEST_EQ(x9nc.native().size(), 7U);
222
223     // non-contiguous containers
224     path x10(l);                                       // std::list<char>
225     PATH_IS(x10, L"string");
226     BOOST_TEST_EQ(x10.native().size(), 6U);
227
228     path xll(wl);                                      // std::list<wchar_t>
229     PATH_IS(xll, L"wstring");
230     BOOST_TEST_EQ(xll.native().size(), 7U);
231
232     // easy-to-make coding errors
233     // path e1(x0, path::codecvt());  // fails to compile, and that is OK
234
235     boost::shared_ptr< Derived > pDerived( new Derived() ); 
236     fun( pDerived );  // tests constructor member template enable_if working correctly;
237                       // will fail to compile if enable_if not taking path off the table
238   }
239
240   path x;
241   path y;
242
243   //  test_assignments  ----------------------------------------------------------------//
244
245   void test_assignments()
246   {
247     std::cout << "testing assignments..." << std::endl;
248
249     x = path("yet another path");                      // another path
250     PATH_IS(x, L"yet another path");
251     BOOST_TEST_EQ(x.native().size(), 16U);
252
253     x = x;                                             // self-assignment
254     PATH_IS(x, L"yet another path");
255     BOOST_TEST_EQ(x.native().size(), 16U);
256
257     x.assign(l.begin(), l.end());                      // iterator range char
258     PATH_IS(x, L"string");
259
260     x.assign(wl.begin(), wl.end());                    // iterator range wchar_t
261     PATH_IS(x, L"wstring");
262
263     x = string("std::string");                         // container char
264     PATH_IS(x, L"std::string");
265
266     x = wstring(L"std::wstring");                      // container wchar_t
267     PATH_IS(x, L"std::wstring");
268
269     x = "array char";                                  // array char
270     PATH_IS(x, L"array char");
271
272     x = L"array wchar";                                // array wchar_t
273     PATH_IS(x, L"array wchar");
274
275     x = s.c_str();                                     // const char* null terminated
276     PATH_IS(x, L"string");
277
278     x = ws.c_str();                                    // const wchar_t* null terminated
279     PATH_IS(x, L"wstring");
280    }
281
282   //  test_move_construction_and_assignment  -------------------------------------------//
283
284   void test_move_construction_and_assignment()
285   {
286     std::cout << "testing move_construction_and_assignment..." << std::endl;
287
288 # if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
289     path from("long enough to avoid small object optimization");
290     path to(std::move(from));
291     BOOST_TEST(to == "long enough to avoid small object optimization");
292     if (!from.empty())
293       cout << "Note: move construction did not result in empty source path" << endl;
294
295     path from2("long enough to avoid small object optimization");
296     path to2;
297     to2 = std::move(from2);
298     BOOST_TEST(to2 == "long enough to avoid small object optimization");
299     if (!from2.empty())
300       cout << "Note: move assignment did not result in empty rhs path" << endl;
301 # else
302     std::cout << 
303       "Test skipped because compiler does not support move semantics" << std::endl;
304 # endif
305
306   }
307
308   //  test_appends  --------------------------------------------------------------------//
309
310   void test_appends()
311   {
312     std::cout << "testing appends..." << std::endl;
313
314 # ifdef BOOST_WINDOWS_API
315 #   define BOOST_FS_FOO L"/foo\\"
316 # else   // POSIX paths
317 #   define BOOST_FS_FOO L"/foo/"
318 # endif
319
320     x = "/foo";
321     x /= path("");                                      // empty path
322     PATH_IS(x, L"/foo");
323
324     x = "/foo";
325     x /= path("/");                                     // slash path
326     PATH_IS(x, L"/foo/");
327
328     x = "/foo";
329     x /= path("/boo");                                  // slash path
330     PATH_IS(x, L"/foo/boo");
331
332     x = "/foo";
333     x /= x;                                             // self-append
334     PATH_IS(x, L"/foo/foo");
335
336     x = "/foo";
337     x /= path("yet another path");                      // another path
338     PATH_IS(x, BOOST_FS_FOO L"yet another path");
339
340     x = "/foo";
341     x.append(l.begin(), l.end());                      // iterator range char
342     PATH_IS(x, BOOST_FS_FOO L"string");
343
344     x = "/foo";
345     x.append(wl.begin(), wl.end());                    // iterator range wchar_t
346     PATH_IS(x, BOOST_FS_FOO L"wstring");
347
348     x = "/foo";
349     x /= string("std::string");                         // container char
350     PATH_IS(x, BOOST_FS_FOO L"std::string");
351
352     x = "/foo";
353     x /= wstring(L"std::wstring");                      // container wchar_t
354     PATH_IS(x, BOOST_FS_FOO L"std::wstring");
355
356     x = "/foo";
357     x /= "array char";                                  // array char
358     PATH_IS(x, BOOST_FS_FOO L"array char");
359
360     x = "/foo";
361     x /= L"array wchar";                                // array wchar_t
362     PATH_IS(x, BOOST_FS_FOO L"array wchar");
363
364     x = "/foo";
365     x /= s.c_str();                                     // const char* null terminated
366     PATH_IS(x, BOOST_FS_FOO L"string");
367
368     x = "/foo";
369     x /= ws.c_str();                                    // const wchar_t* null terminated
370     PATH_IS(x, BOOST_FS_FOO L"wstring");
371    }
372
373   //  test_concats  --------------------------------------------------------------------//
374
375   void test_concats()
376   {
377     std::cout << "testing concats..." << std::endl;
378
379     x = "/foo";
380     x += path("");                                      // empty path
381     PATH_IS(x, L"/foo");
382
383     x = "/foo";
384     x += path("/");                                     // slash path
385     PATH_IS(x, L"/foo/");
386
387     x = "/foo";
388     x += path("boo");                                  // slash path
389     PATH_IS(x, L"/fooboo");
390
391     x = "foo";
392     x += x;                                             // self-append
393     PATH_IS(x, L"foofoo");
394
395     x = "foo-";
396     x += path("yet another path");                      // another path
397     PATH_IS(x, L"foo-yet another path");
398
399     x = "foo-";
400     x.concat(l.begin(), l.end());                      // iterator range char
401     PATH_IS(x, L"foo-string");
402
403     x = "foo-";
404     x.concat(wl.begin(), wl.end());                    // iterator range wchar_t
405     PATH_IS(x, L"foo-wstring");
406
407     x = "foo-";
408     x += string("std::string");                         // container char
409     PATH_IS(x, L"foo-std::string");
410
411     x = "foo-";
412     x += wstring(L"std::wstring");                      // container wchar_t
413     PATH_IS(x, L"foo-std::wstring");
414
415     x = "foo-";
416     x += "array char";                                  // array char
417     PATH_IS(x, L"foo-array char");
418
419     x = "foo-";
420     x += L"array wchar";                                // array wchar_t
421     PATH_IS(x, L"foo-array wchar");
422
423     x = "foo-";
424     x += s.c_str();                                     // const char* null terminated
425     PATH_IS(x, L"foo-string");
426
427     x = "foo-";
428     x += ws.c_str();                                    // const wchar_t* null terminated
429     PATH_IS(x, L"foo-wstring");
430
431     x = "foo-";
432     x += 'x';                                           // char
433     PATH_IS(x, L"foo-x");
434
435     x = "foo-";
436     x += L'x';                                          // wchar
437     PATH_IS(x, L"foo-x");
438    }
439
440   //  test_observers  ------------------------------------------------------------------//
441
442   void test_observers()
443   {
444     std::cout << "testing observers..." << std::endl;
445
446     path p0("abc");
447
448     CHECK(p0.native().size() == 3);
449     CHECK(p0.size() == 3);
450     CHECK(p0.string() == "abc");
451     CHECK(p0.string().size() == 3);
452     CHECK(p0.wstring() == L"abc");
453     CHECK(p0.wstring().size() == 3);
454
455     p0 = "";
456     CHECK(p0.native().size() == 0);
457     CHECK(p0.size() == 0);
458
459 # ifdef BOOST_WINDOWS_API
460
461     path p("abc\\def/ghi");
462
463     CHECK(std::wstring(p.c_str()) == L"abc\\def/ghi");
464
465     CHECK(p.string() == "abc\\def/ghi");
466     CHECK(p.wstring() == L"abc\\def/ghi");
467
468     CHECK(p.generic_path().string() == "abc/def/ghi");
469     CHECK(p.generic_string() == "abc/def/ghi");
470     CHECK(p.generic_wstring() == L"abc/def/ghi");
471
472     CHECK(p.generic_string<string>() == "abc/def/ghi");
473     CHECK(p.generic_string<wstring>() == L"abc/def/ghi");
474     CHECK(p.generic_string<path::string_type>() == L"abc/def/ghi");
475
476 # else  // BOOST_POSIX_API
477
478     path p("abc\\def/ghi");
479
480     CHECK(string(p.c_str()) == "abc\\def/ghi");
481
482     CHECK(p.string() == "abc\\def/ghi");
483     CHECK(p.wstring() == L"abc\\def/ghi");
484
485     CHECK(p.generic_path().string() == "abc\\def/ghi");
486     CHECK(p.generic_string() == "abc\\def/ghi");
487     CHECK(p.generic_wstring() == L"abc\\def/ghi");
488
489     CHECK(p.generic_string<string>() == "abc\\def/ghi");
490     CHECK(p.generic_string<wstring>() == L"abc\\def/ghi");
491     CHECK(p.generic_string<path::string_type>() == "abc\\def/ghi");
492
493 # endif
494   }
495
496   //  test_relationals  ----------------------------------------------------------------//
497
498   void test_relationals()
499   {
500     std::cout << "testing relationals..." << std::endl;
501
502     boost::hash<path> hash;
503
504 # ifdef BOOST_WINDOWS_API
505     // this is a critical use case to meet user expectations
506     CHECK(path("c:\\abc") == path("c:/abc"));
507     CHECK(hash(path("c:\\abc")) == hash(path("c:/abc")));
508 # endif
509
510     const path p("bar");
511     const path p2("baz");
512
513     CHECK(!(p < p));
514     CHECK(p < p2);
515     CHECK(!(p2 < p));
516     CHECK(p < "baz");
517     CHECK(p < string("baz"));
518     CHECK(p < L"baz");
519     CHECK(p < wstring(L"baz"));
520     CHECK(!("baz" < p));
521     CHECK(!(string("baz") < p));
522     CHECK(!(L"baz" < p));
523     CHECK(!(wstring(L"baz") < p));
524
525     CHECK(p == p);
526     CHECK(!(p == p2));
527     CHECK(!(p2 == p));
528     CHECK(p2 == "baz");
529     CHECK(p2 == string("baz"));
530     CHECK(p2 == L"baz");
531     CHECK(p2 == wstring(L"baz"));
532     CHECK("baz" == p2);
533     CHECK(string("baz") == p2);
534     CHECK(L"baz" == p2);
535     CHECK(wstring(L"baz") == p2);
536
537     CHECK(hash(p) == hash(p));
538     CHECK(hash(p) != hash(p2)); // Not strictly required, but desirable
539
540     CHECK(!(p != p));
541     CHECK(p != p2);
542     CHECK(p2 != p);
543
544     CHECK(p <= p);
545     CHECK(p <= p2);
546     CHECK(!(p2 <= p));
547
548     CHECK(!(p > p));
549     CHECK(!(p > p2));
550     CHECK(p2 > p);
551
552     CHECK(p >= p);
553     CHECK(!(p >= p2));
554     CHECK(p2 >= p);
555 }
556
557   //  test_inserter_and_extractor  -----------------------------------------------------//
558
559   void test_inserter_and_extractor()
560   {
561     std::cout << "testing inserter and extractor..." << std::endl;
562
563     path p1("foo bar");  // verify space in path roundtrips per ticket #3863
564     path p2;
565
566     std::stringstream ss;
567
568     CHECK(p1 != p2);
569     ss << p1;
570     ss >> p2;
571     CHECK(p1 == p2);
572
573     path wp1(L"foo bar");
574     path wp2;
575
576     std::wstringstream wss;
577
578     CHECK(wp1 != wp2);
579     wss << wp1;
580     wss >> wp2;
581     CHECK(wp1 == wp2);
582   }
583
584   //  test_other_non_members  ----------------------------------------------------------//
585
586   void test_other_non_members()
587   {
588     std::cout << "testing other_non_members..." << std::endl;
589
590     path p1("foo");
591     path p2("bar");
592
593     //  operator /
594
595     CHECK(p1 / p2 == path("foo/bar").make_preferred());
596     CHECK("foo" / p2 == path("foo/bar").make_preferred());
597     CHECK(L"foo" / p2 == path("foo/bar").make_preferred());
598     CHECK(string("foo") / p2 == path("foo/bar").make_preferred());
599     CHECK(wstring(L"foo") / p2 == path("foo/bar").make_preferred());
600     CHECK(p1 / "bar" == path("foo/bar").make_preferred());
601     CHECK(p1 / L"bar" == path("foo/bar").make_preferred());
602     CHECK(p1 / string("bar") == path("foo/bar").make_preferred());
603     CHECK(p1 / wstring(L"bar") == path("foo/bar").make_preferred());
604
605     swap(p1, p2);
606
607     CHECK(p1 == "bar");
608     CHECK(p2 == "foo");
609
610     CHECK(!path("").filename_is_dot());
611     CHECK(!path("").filename_is_dot_dot());
612     CHECK(!path("..").filename_is_dot());
613     CHECK(!path(".").filename_is_dot_dot());
614     CHECK(!path("...").filename_is_dot_dot());
615     CHECK(path(".").filename_is_dot());
616     CHECK(path("..").filename_is_dot_dot());
617     CHECK(path("/.").filename_is_dot());
618     CHECK(path("/..").filename_is_dot_dot());
619     CHECK(!path("a.").filename_is_dot());
620     CHECK(!path("a..").filename_is_dot_dot());
621
622     // edge cases
623     CHECK(path("foo/").filename() == path("."));
624     CHECK(path("foo/").filename_is_dot());
625     CHECK(path("/").filename() == path("/"));
626     CHECK(!path("/").filename_is_dot());
627 # ifdef BOOST_WINDOWS_API
628     CHECK(path("c:.").filename() == path("."));
629     CHECK(path("c:.").filename_is_dot());
630     CHECK(path("c:/").filename() == path("/"));
631     CHECK(!path("c:\\").filename_is_dot());
632 # else
633     CHECK(path("c:.").filename() == path("c:."));
634     CHECK(!path("c:.").filename_is_dot());
635     CHECK(path("c:/").filename() == path("."));
636     CHECK(path("c:/").filename_is_dot());
637 # endif
638
639     // check that the implementation code to make the edge cases above work right
640     // doesn't cause some non-edge cases to fail
641     CHECK(path("c:").filename() != path("."));
642     CHECK(!path("c:").filename_is_dot());
643
644     // examples from reference.html
645     std::cout << path(".").filename_is_dot();            // outputs 1
646     std::cout << path("/.").filename_is_dot();           // outputs 1
647     std::cout << path("foo/.").filename_is_dot();        // outputs 1
648     std::cout << path("foo/").filename_is_dot();         // outputs 1
649     std::cout << path("/").filename_is_dot();            // outputs 0
650     std::cout << path("/foo").filename_is_dot();         // outputs 0
651     std::cout << path("/foo.").filename_is_dot();        // outputs 0
652     std::cout << path("..").filename_is_dot();           // outputs 0
653     cout << std::endl;
654   }
655
656 //  //  test_modifiers  ------------------------------------------------------------------//
657 //
658 //  void test_modifiers()
659 //  {
660 //    std::cout << "testing modifiers..." << std::endl;
661 //
662 //  }
663
664   //  test_iterators  ------------------------------------------------------------------//
665
666   void test_iterators()
667   {
668     std::cout << "testing iterators..." << std::endl;
669
670     path p1;
671     CHECK(p1.begin() == p1.end());
672
673     path p2("/");
674     CHECK(p2.begin() != p2.end());
675     CHECK(*p2.begin() == "/");
676     CHECK(++p2.begin() == p2.end());
677
678     path p3("foo/bar/baz");
679
680     path::iterator it(p3.begin());
681     CHECK(p3.begin() != p3.end());
682     CHECK(*it == "foo");
683     CHECK(*++it == "bar");
684     CHECK(*++it == "baz");
685     CHECK(*--it == "bar");
686     CHECK(*--it == "foo");
687     CHECK(*++it == "bar");
688     CHECK(*++it == "baz");
689     CHECK(++it == p3.end());
690   }
691
692   //  test_reverse_iterators  ----------------------------------------------------------//
693
694   void test_reverse_iterators()
695   {
696     std::cout << "testing reverse_iterators..." << std::endl;
697
698     path p1;
699     CHECK(p1.rbegin() == p1.rend());
700
701     path p2("/");
702     CHECK(p2.rbegin() != p2.rend());
703     CHECK(*p2.rbegin() == "/");
704     CHECK(++p2.rbegin() == p2.rend());
705
706     path p3("foo/bar/baz");
707
708     path::reverse_iterator it(p3.rbegin());
709     CHECK(p3.rbegin() != p3.rend());
710     CHECK(*it == "baz");
711     CHECK(*++it == "bar");
712     CHECK(*++it == "foo");
713     CHECK(*--it == "bar");
714     CHECK(*--it == "baz");
715     CHECK(*++it == "bar");
716     CHECK(*++it == "foo");
717     CHECK(++it == p3.rend());
718   }
719
720   //  test_modifiers  ------------------------------------------------------------------//
721
722   void test_modifiers()
723   {
724     std::cout << "testing modifiers..." << std::endl;
725
726     CHECK(path("").remove_filename() == "");
727     CHECK(path("foo").remove_filename() == "");
728     CHECK(path("/foo").remove_filename() == "/");
729     CHECK(path("foo/bar").remove_filename() == "foo");
730     BOOST_TEST_EQ(path("foo/bar/").remove_filename(), path("foo/bar"));
731     BOOST_TEST_EQ(path(".").remove_filename(), path(""));
732     BOOST_TEST_EQ(path("./.").remove_filename(), path("."));
733     BOOST_TEST_EQ(path("/.").remove_filename(), path("/"));
734     BOOST_TEST_EQ(path("..").remove_filename(), path(""));
735     BOOST_TEST_EQ(path("../..").remove_filename(), path(".."));
736     BOOST_TEST_EQ(path("/..").remove_filename(), path("/"));
737
738   }
739
740   //  test_decompositions  -------------------------------------------------------------//
741
742   void test_decompositions()
743   {
744     std::cout << "testing decompositions..." << std::endl;
745
746     CHECK(path("").root_name().string() == "");
747     CHECK(path("foo").root_name().string() == "");
748     CHECK(path("/").root_name().string() == "");
749     CHECK(path("/foo").root_name().string() == "");
750     CHECK(path("//netname").root_name().string() == "//netname");
751     CHECK(path("//netname/foo").root_name().string() == "//netname");
752
753     CHECK(path("").root_directory().string() == "");
754     CHECK(path("foo").root_directory().string() == "");
755     CHECK(path("/").root_directory().string() == "/");
756     CHECK(path("/foo").root_directory().string() == "/");
757     CHECK(path("//netname").root_directory().string() == "");
758     CHECK(path("//netname/foo").root_directory().string() == "/");
759
760     CHECK(path("").root_path().string() == "");
761     CHECK(path("/").root_path().string() == "/");
762     CHECK(path("/foo").root_path().string() == "/");
763     CHECK(path("//netname").root_path().string() == "//netname");
764     CHECK(path("//netname/foo").root_path().string() == "//netname/");
765
766 #   ifdef BOOST_WINDOWS_API
767     CHECK(path("c:/foo").root_path().string() == "c:/");
768 #   endif
769
770     CHECK(path("").relative_path().string() == "");
771     CHECK(path("/").relative_path().string() == "");
772     CHECK(path("/foo").relative_path().string() == "foo");
773
774     CHECK(path("").parent_path().string() == "");
775     CHECK(path("/").parent_path().string() == "");
776     CHECK(path("/foo").parent_path().string() == "/");
777     CHECK(path("/foo/bar").parent_path().string() == "/foo");
778
779     CHECK(path("/foo/bar/baz.zoo").filename().string() == "baz.zoo");
780
781     CHECK(path("/foo/bar/baz.zoo").stem().string() == "baz");
782     CHECK(path("/foo/bar.woo/baz").stem().string() == "baz");
783
784     CHECK(path("foo.bar.baz.tar.bz2").extension().string() == ".bz2");
785     CHECK(path("/foo/bar/baz.zoo").extension().string() == ".zoo");
786     CHECK(path("/foo/bar.woo/baz").extension().string() == "");
787   }
788
789   //  test_queries  --------------------------------------------------------------------//
790
791   void test_queries()
792   {
793     std::cout << "testing queries..." << std::endl;
794
795     path p1("");
796     path p2("//netname/foo.doo");
797
798     CHECK(p1.empty());
799     CHECK(!p1.has_root_path());
800     CHECK(!p1.has_root_name());
801     CHECK(!p1.has_root_directory());
802     CHECK(!p1.has_relative_path());
803     CHECK(!p1.has_parent_path());
804     CHECK(!p1.has_filename());
805     CHECK(!p1.has_stem());
806     CHECK(!p1.has_extension());
807     CHECK(!p1.is_absolute());
808     CHECK(p1.is_relative());
809
810     CHECK(!p2.empty());
811     CHECK(p2.has_root_path());
812     CHECK(p2.has_root_name());
813     CHECK(p2.has_root_directory());
814     CHECK(p2.has_relative_path());
815     CHECK(p2.has_parent_path());
816     CHECK(p2.has_filename());
817     CHECK(p2.has_stem());
818     CHECK(p2.has_extension());
819     CHECK(p2.is_absolute());
820     CHECK(!p2.is_relative());
821
822   }
823
824   //  test_imbue_locale  ---------------------------------------------------------------//
825
826   void test_imbue_locale()
827   {
828     std::cout << "testing imbue locale..." << std::endl;
829
830     //  weak test case for before/after states since we don't know what characters the
831     //  default locale accepts. 
832     path before("abc");
833
834     //  So that tests are run with known encoding, use Boost UTF-8 codecvt
835     //  \u2722 and \xE2\x9C\xA2 are UTF-16 and UTF-8 FOUR TEARDROP-SPOKED ASTERISK
836
837     std::locale global_loc = std::locale();
838     std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet);
839     std::cout << "  imbuing locale ..." << std::endl;
840     std::locale old_loc = path::imbue(loc);
841
842     std::cout << "  testing with the imbued locale ..." << std::endl;
843     path p2("\xE2\x9C\xA2");
844     CHECK(p2.wstring().size() == 1);
845     CHECK(p2.wstring()[0] == 0x2722);
846
847     std::cout << "  imbuing the original locale ..." << std::endl;
848     path::imbue(old_loc);
849
850     std::cout << "  testing with the original locale ..." << std::endl;
851     path after("abc");
852     CHECK(before == after);
853
854     std::cout << "  locale testing complete" << std::endl;
855   }
856
857   //  test_codecvt_argument  -----------------------------------------------------------//
858
859   void test_codecvt_argument()
860   {
861     std::cout << "testing codecvt arguments..." << std::endl;
862
863     const char * c1 = "a1";
864     const std::string s1(c1);
865     const std::wstring ws1(L"b2");  // off-by-one mimics test_codecvt
866     const std::string s2("y8");
867     const std::wstring ws2(L"z9");
868
869     test_codecvt cvt;  // produces off-by-one values that will always differ from
870                        // the system's default locale codecvt facet
871
872     int t = 0;
873
874     //  constructors
875     std::cout << "  constructors test " << ++t << std::endl;
876     path p(c1, cvt);
877     NATIVE_IS(p, s1, ws1);
878
879     std::cout << "  test " << ++t << std::endl;
880     path p1(s1.begin(), s1.end(), cvt);
881     NATIVE_IS(p1, s1, ws1);
882
883     std::cout << "  test " << ++t << std::endl;
884     path p2(ws2, cvt);
885     NATIVE_IS(p2, s2, ws2);
886
887     std::cout << "  test " << ++t << std::endl;
888     path p3(ws2.begin(), ws2.end(), cvt);
889     NATIVE_IS(p3, s2, ws2);
890
891     // path p2(p1, cvt);  // fails to compile, and that is OK
892
893     //  assigns
894     p1.clear();
895     std::cout << "  assigns test " << ++t << std::endl;
896     p1.assign(s1,cvt);
897     NATIVE_IS(p1, s1, ws1);
898     p1.clear();
899     std::cout << "  test " << ++t << std::endl;
900     p1.assign(s1.begin(), s1.end(), cvt);
901     NATIVE_IS(p1, s1, ws1);
902     // p1.assign(p, cvt);  // fails to compile, and that is OK
903
904     //  appends
905     p1.clear();
906     std::cout << "  appends test " << ++t << std::endl;
907     p1.append(s1,cvt);
908     NATIVE_IS(p1, s1, ws1);
909     p1.clear();
910     std::cout << "  test " << ++t << std::endl;
911     p1.append(s1.begin(), s1.end(), cvt);
912     NATIVE_IS(p1, s1, ws1);
913     // p1.append(p, cvt);  // fails to compile, and that is OK
914
915     //  native observers
916     std::cout << "  native observers test " << ++t << std::endl;
917     CHECK(p.string<std::string>(cvt) == s1);
918     std::cout << "  test " << ++t << std::endl;
919     CHECK(p.string(cvt) == s1);
920     std::cout << "  test " << ++t << std::endl;
921     CHECK(p.string<std::wstring>(cvt) == ws1);
922     std::cout << "  test " << ++t << std::endl;
923     CHECK(p.wstring(cvt) == ws1);
924
925     //  generic observers
926     std::cout << "  generic observers test " << ++t << std::endl;
927     CHECK(p.generic_string<std::string>(cvt) == s1);
928     std::cout << "  test " << ++t << std::endl;
929     CHECK(p.generic_string(cvt) == s1);
930     std::cout << "  test " << ++t << std::endl;
931     CHECK(p.generic_string<std::wstring>(cvt) == ws1);
932     std::cout << "  test " << ++t << std::endl;
933     CHECK(p.generic_wstring(cvt) == ws1);
934
935     std::cout << "  codecvt arguments testing complete" << std::endl;
936   }
937
938   //  test_overloads  ------------------------------------------------------------------//
939
940   void test_overloads()
941   {
942     std::cout << "testing overloads..." << std::endl;
943     std::string sto("hello");
944     const char a[] = "goodbye";
945     path p1(sto);
946     path p2(sto.c_str());
947     path p3(a);
948     path p4("foo");
949
950     std::wstring wsto(L"hello");
951     const wchar_t wa[] = L"goodbye";
952     path wp1(wsto);
953     path wp2(wsto.c_str());
954     path wp3(wa);
955     path wp4(L"foo");
956   }
957
958   //  test_error_handling  -------------------------------------------------------------//
959
960   class error_codecvt
961     : public std::codecvt< wchar_t, char, std::mbstate_t >
962   {
963   public:
964     explicit error_codecvt()
965         : std::codecvt<wchar_t, char, std::mbstate_t>() {}
966   protected:
967
968     virtual bool do_always_noconv() const throw() { return false; }
969     virtual int do_encoding() const throw() { return 0; }
970
971     virtual std::codecvt_base::result do_in(std::mbstate_t&,
972       const char*, const char*, const char*&,
973       wchar_t*, wchar_t*, wchar_t*&) const
974     {
975       static std::codecvt_base::result r = std::codecvt_base::noconv;
976       if (r == std::codecvt_base::partial) r = std::codecvt_base::error;
977       else if (r == std::codecvt_base::error) r = std::codecvt_base::noconv;
978       else r = std::codecvt_base::partial;
979       return r;
980     }
981
982     virtual std::codecvt_base::result do_out(std::mbstate_t &,
983       const wchar_t*, const wchar_t*, const wchar_t*&,
984       char*, char*, char*&) const
985     {
986       static std::codecvt_base::result r = std::codecvt_base::noconv;
987       if (r == std::codecvt_base::partial) r = std::codecvt_base::error;
988       else if (r == std::codecvt_base::error) r = std::codecvt_base::noconv;
989       else r = std::codecvt_base::partial;
990       return r;
991     }
992
993     virtual std::codecvt_base::result do_unshift(std::mbstate_t&,
994         char*, char*, char* &) const  { return ok; }
995     virtual int do_length(std::mbstate_t &,
996       const char*, const char*, std::size_t) const  { return 0; }
997     virtual int do_max_length() const throw () { return 0; }
998   };
999
1000   void test_error_handling()
1001   {
1002     std::cout << "testing error handling..." << std::endl;
1003
1004     std::locale global_loc = std::locale();
1005     std::locale loc(global_loc, new error_codecvt);
1006     std::cout << "  imbuing error locale ..." << std::endl;
1007     std::locale old_loc = path::imbue(loc);
1008
1009     //  These tests rely on a path constructor that fails in the locale conversion.
1010     //  Thus construction has to call codecvt. Force that by using a narrow string
1011     //  for Windows, and a wide string for POSIX.
1012 #   ifdef BOOST_WINDOWS_API
1013 #     define STRING_FOO_ "foo"
1014 #   else
1015 #     define STRING_FOO_ L"foo"
1016 #   endif
1017
1018     {
1019       std::cout << "    testing std::codecvt_base::partial error..." << std::endl;
1020       bool exception_thrown (false);
1021       try { path(STRING_FOO_); }
1022       catch (const bs::system_error & ex)
1023       {
1024         exception_thrown = true;
1025         BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::partial,
1026           fs::codecvt_error_category()));
1027       }
1028       catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
1029       BOOST_TEST(exception_thrown);
1030     }
1031
1032     {
1033       std::cout << "    testing std::codecvt_base::error error..." << std::endl;
1034       bool exception_thrown (false);
1035       try { path(STRING_FOO_); }
1036       catch (const bs::system_error & ex)
1037       {
1038         exception_thrown = true;
1039         BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::error,
1040           fs::codecvt_error_category()));
1041       }
1042       catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
1043       BOOST_TEST(exception_thrown);
1044     }
1045
1046     {
1047       std::cout << "    testing std::codecvt_base::noconv error..." << std::endl;
1048       bool exception_thrown (false);
1049       try { path(STRING_FOO_); }
1050       catch (const bs::system_error & ex)
1051       {
1052         exception_thrown = true;
1053         BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::noconv,
1054           fs::codecvt_error_category()));
1055       }
1056       catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
1057       BOOST_TEST(exception_thrown);
1058     }
1059
1060     std::cout << "  restoring original locale ..." << std::endl;
1061     path::imbue(old_loc);
1062     std::cout << "  testing error handling complete" << std::endl;
1063  }
1064
1065 # if 0
1066
1067 //  //  test_locales  --------------------------------------------------------------------//
1068 //
1069 //  void test_locales()
1070 //  {
1071 //    std::cout << "testing locales..." << std::endl;
1072 //
1073 //  }
1074
1075   //  test_user_supplied_type  ---------------------------------------------------------//
1076
1077   typedef std::basic_string<int> user_string;
1078
1079 }  // unnamed namespace
1080
1081 namespace boost
1082 {
1083 namespace filesystem
1084 {
1085   namespace path_traits
1086   {
1087     template<> struct is_iterator<const user_string::value_type *> { static const bool value = true; };
1088     template<> struct is_iterator<user_string::value_type *> { static const bool value = true; };
1089     template<> struct is_iterator<user_string::iterator> { static const bool value = true; };
1090     template<> struct is_iterator<user_string::const_iterator> { static const bool value = true; };
1091     template<> struct is_container<user_string> { static const bool value = true; };
1092
1093     template<>
1094     void append<user_string::value_type>(const user_string::value_type * begin,
1095       const user_string::value_type * end, string_type & target, system::error_code & ec)
1096     {
1097       for (; begin != end && *begin; ++begin)
1098         target += *begin + 1;  // change so that results distinguishable from char cvts
1099     }
1100
1101 #  ifdef __GNUC__
1102     //  This specialization shouldn't be needed, and VC++, Intel, and others work
1103     //  fine without it. But gcc 4.3.2, and presumably other versions, need it.
1104     template<>
1105     void append<user_string::value_type>(const user_string::value_type * begin,
1106       string_type & target, system::error_code & ec)
1107     {
1108       path_traits::append<user_string::value_type>(begin,
1109         static_cast<const user_string::value_type *>(0), target, ec);
1110     }
1111 #  endif
1112
1113     template<>
1114     user_string convert<user_string>(const string_type & source,
1115       system::error_code & ec)
1116     {
1117       user_string temp;
1118       for (string_type::const_iterator it = source.begin();
1119             it != source.end(); ++it)
1120         temp += *it - 1;
1121       return temp;
1122     }
1123   }  // namespace path_traits
1124 }  // namespace filesystem
1125 }  // namespace boost
1126
1127 namespace
1128 {
1129
1130   void test_user_supplied_type()
1131   {
1132     std::cout << "testing user supplied type..." << std::endl;
1133
1134     user_string::value_type usr_c_str[] = { 'a', 'b', 'c', 0 };
1135     user_string usr(usr_c_str);
1136
1137     path p1(usr.c_str());
1138     CHECK(p1 == path("bcd"));
1139     CHECK(p1 == "bcd");
1140     user_string s1(p1.string<user_string>());
1141     CHECK(s1 == usr);
1142   }
1143
1144 # endif
1145
1146   inline const char* macro_value(const char* name, const char* value)
1147   {
1148     static const char* no_value = "[no value]";
1149     static const char* not_defined = "[not defined]";
1150
1151     //if (0 != strcmp(name, value + 1))  // macro is defined
1152     //{
1153     //  if (value[1])
1154     //    return value;
1155     //  else
1156     //    return no_value;
1157     //}
1158     //return not_defined;
1159
1160     return 0 == strcmp(name, value + 1)
1161       ? not_defined 
1162       : (value[1] ? value : no_value);
1163   }
1164
1165 #define BOOST_MACRO_VALUE(X) macro_value(#X, BOOST_STRINGIZE(=X))
1166
1167 }  // unnamed namespace
1168
1169 //--------------------------------------------------------------------------------------//
1170 //                                                                                      //
1171 //                                     main                                             //
1172 //                                                                                      //
1173 //--------------------------------------------------------------------------------------//
1174
1175 int test_main(int, char*[])
1176 {
1177 // document state of critical macros
1178 #ifdef BOOST_POSIX_API
1179   cout << "BOOST_POSIX_API" << endl;
1180   BOOST_TEST(path::preferred_separator == '/');
1181 #endif
1182 #ifdef BOOST_WINDOWS_API
1183   cout << "BOOST_WINDOWS_API" << endl;
1184   BOOST_TEST(path::preferred_separator == '\\');
1185 #endif
1186
1187   cout << "BOOST_FILESYSTEM_DECL "
1188     << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_DECL) << endl;
1189
1190 //#ifdef BOOST_FILESYSTEM_DECL
1191 //  cout << "BOOST_FILESYSTEM_DECL is defined as "
1192 //    << BOOST_STRINGIZE(BOOST_FILESYSTEM_DECL) << endl;
1193 //#else
1194 //  cout << "BOOST_FILESYSTEM_DECL is not defined" << endl;
1195 //#endif
1196
1197   l.push_back('s');
1198   l.push_back('t');
1199   l.push_back('r');
1200   l.push_back('i');
1201   l.push_back('n');
1202   l.push_back('g');
1203
1204   wl.push_back(L'w');
1205   wl.push_back(L's');
1206   wl.push_back(L't');
1207   wl.push_back(L'r');
1208   wl.push_back(L'i');
1209   wl.push_back(L'n');
1210   wl.push_back(L'g');
1211
1212   v.push_back('f');
1213   v.push_back('u');
1214   v.push_back('z');
1215
1216   wv.push_back(L'w');
1217   wv.push_back(L'f');
1218   wv.push_back(L'u');
1219   wv.push_back(L'z');
1220
1221   test_overloads();
1222   test_constructors();
1223   test_assignments();
1224   test_move_construction_and_assignment();
1225   test_appends();
1226   test_concats();
1227   test_modifiers();
1228   test_observers();
1229   test_relationals();
1230   test_inserter_and_extractor();
1231   test_other_non_members();
1232   test_iterators();
1233   test_reverse_iterators();
1234   test_decompositions();
1235   test_queries();
1236   test_imbue_locale();
1237   test_codecvt_argument();
1238   test_error_handling();
1239
1240 #if 0
1241
1242   test_user_supplied_type();
1243
1244 #endif
1245
1246   std::string foo("\\abc");
1247   const char* bar = "/abc";
1248
1249   if (foo == bar)
1250     cout << "unintended consequence\n";
1251
1252   return ::boost::report_errors();
1253 }