]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/filesystem/test/path_unit_test.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / 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 }