12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253 |
- // filesystem path_unit_test.cpp --------------------------------------------------- //
- // Copyright Beman Dawes 2008, 2009
- // Distributed under the Boost Software License, Version 1.0.
- // See http://www.boost.org/LICENSE_1_0.txt
- // Library home page: http://www.boost.org/libs/filesystem
- // ---------------------------------------------------------------------------------- //
- //
- // The purpose of this test is to ensure that each function in the public
- // interface can be called with arguments of the appropriate types. It does
- // not attempt to verify that the full range of values for each argument
- // are processed correctly.
- //
- // For full functionality tests, including probes with many different argument
- // values, see path_test.cpp and other test programs.
- //
- // ---------------------------------------------------------------------------------- //
- #include <boost/config/warning_disable.hpp>
- // See deprecated_test for tests of deprecated features
- #ifndef BOOST_FILESYSTEM_NO_DEPRECATED
- # define BOOST_FILESYSTEM_NO_DEPRECATED
- #endif
- #ifndef BOOST_SYSTEM_NO_DEPRECATED
- # define BOOST_SYSTEM_NO_DEPRECATED
- #endif
- #include <boost/filesystem/path.hpp>
- #include <boost/filesystem/detail/utf8_codecvt_facet.hpp> // for imbue tests
- #include "test_codecvt.hpp" // for codecvt arg tests
- #include <boost/detail/lightweight_test_report.hpp>
- #include <boost/smart_ptr.hpp> // used constructor tests
- #include <boost/functional/hash.hpp>
- #include <iostream>
- #include <iomanip>
- #include <sstream>
- #include <string>
- #include <cstring>
- #include <cwchar>
- #include <locale>
- #include <list>
- namespace fs = boost::filesystem;
- namespace bs = boost::system;
- using boost::filesystem::path;
- using std::cout;
- using std::endl;
- using std::string;
- using std::wstring;
- #define CHECK(x) check(x, __FILE__, __LINE__)
- #define PATH_IS(a, b) check_path(a, b, __FILE__, __LINE__)
- #define NATIVE_IS(p, s, ws) check_native(p, s, ws, __FILE__, __LINE__)
- #define IS(a,b) check_equal(a, b, __FILE__, __LINE__)
- #if defined(_MSC_VER)
- # pragma warning(push) // Save warning settings.
- # pragma warning(disable : 4428) // Disable universal-character-name encountered in source warning.
- #endif
- namespace
- {
- boost::system::error_code ec;
- const boost::system::error_code ok;
- const boost::system::error_code ng(-1, boost::system::system_category());
- std::string platform(BOOST_PLATFORM);
- void check_path(const path& source,
- const wstring& expected, const char* file, int line)
- {
- if (source == expected) return;
- ++::boost::detail::test_errors();
- std::cout << file;
- std::wcout << L'(' << line << L"): source.wstring(): \""
- << source.wstring()
- << L"\" != expected: \"" << expected
- << L"\"\n" ;
- }
- # ifdef BOOST_WINDOWS_API
- void check_native(const path& p,
- const string&, const wstring& expected, const char* file, int line)
- # else
- void check_native(const path& p,
- const string& expected, const wstring&, const char* file, int line)
- # endif
- {
- if (p.native() == expected) return;
- ++::boost::detail::test_errors();
- std::cout << file << '(' << line << "): native() is not equal expected\n"
- " native---: " << std::hex;
- path::string_type nat(p.native());
- for (path::string_type::const_iterator it = nat.begin(); it != nat.end(); ++it)
- std::cout << long(*it) << ' ';
- std::cout << "\n expected-: ";
- for (path::string_type::const_iterator it = expected.begin(); it != expected.end(); ++it)
- std::cout << long(*it) << ' ';
- std::cout << std::dec << std::endl;
- }
- template< class T1, class T2 >
- void check_equal(const T1& value,
- const T2& expected, const char* file, int line)
- {
- if (value == expected) return;
- ++::boost::detail::test_errors();
- std::cout << file;
- std::wcout << L'(' << line << L"): value: \"" << value
- << L"\" != expected: \"" << expected
- << L"\"\n" ;
- }
- void check(bool ok_, const char* file, int line)
- {
- if (ok_) return;
- ++::boost::detail::test_errors();
- std::cout << file << '(' << line << "): test failed\n";
- }
- string s("string");
- wstring ws(L"wstring");
- std::list<char> l; // see main() for initialization to s, t, r, i, n, g
- std::list<wchar_t> wl; // see main() for initialization to w, s, t, r, i, n, g
- std::vector<char> v; // see main() for initialization to f, u, z
- std::vector<wchar_t> wv; // see main() for initialization to w, f, u, z
- class Base {};
- class Derived : public Base {};
- void fun(const boost::shared_ptr< Base >&) {}
- // test_constructors ---------------------------------------------------------------//
- void test_constructors()
- {
- std::cout << "testing constructors..." << std::endl;
- path x0; // default constructor
- PATH_IS(x0, L"");
- BOOST_TEST_EQ(x0.native().size(), 0U);
- path x1(l.begin(), l.end()); // iterator range char
- PATH_IS(x1, L"string");
- BOOST_TEST_EQ(x1.native().size(), 6U);
- path x2(x1); // copy constructor
- PATH_IS(x2, L"string");
- BOOST_TEST_EQ(x2.native().size(), 6U);
- path x3(wl.begin(), wl.end()); // iterator range wchar_t
- PATH_IS(x3, L"wstring");
- BOOST_TEST_EQ(x3.native().size(), 7U);
- // contiguous containers
- path x4(string("std::string")); // std::string
- PATH_IS(x4, L"std::string");
- BOOST_TEST_EQ(x4.native().size(), 11U);
- path x5(wstring(L"std::wstring")); // std::wstring
- PATH_IS(x5, L"std::wstring");
- BOOST_TEST_EQ(x5.native().size(), 12U);
- path x4v(v); // std::vector<char>
- PATH_IS(x4v, L"fuz");
- BOOST_TEST_EQ(x4v.native().size(), 3U);
- path x5v(wv); // std::vector<wchar_t>
- PATH_IS(x5v, L"wfuz");
- BOOST_TEST_EQ(x5v.native().size(), 4U);
- path x6("array char"); // array char
- PATH_IS(x6, L"array char");
- BOOST_TEST_EQ(x6.native().size(), 10U);
- path x7(L"array wchar_t"); // array wchar_t
- PATH_IS(x7, L"array wchar_t");
- BOOST_TEST_EQ(x7.native().size(), 13U);
- char char_array[100];
- std::strcpy(char_array, "big array char");
- path x6o(char_array); // array char, only partially full
- PATH_IS(x6o, L"big array char");
- BOOST_TEST_EQ(x6o.native().size(), 14U);
- wchar_t wchar_array[100];
- std::wcscpy(wchar_array, L"big array wchar_t");
- path x7o(wchar_array); // array char, only partially full
- PATH_IS(x7o, L"big array wchar_t");
- BOOST_TEST_EQ(x7o.native().size(), 17U);
- path x8(s.c_str()); // const char* null terminated
- PATH_IS(x8, L"string");
- BOOST_TEST_EQ(x8.native().size(), 6U);
- path x9(ws.c_str()); // const wchar_t* null terminated
- PATH_IS(x9, L"wstring");
- BOOST_TEST_EQ(x9.native().size(), 7U);
- path x8nc(const_cast<char*>(s.c_str())); // char* null terminated
- PATH_IS(x8nc, L"string");
- BOOST_TEST_EQ(x8nc.native().size(), 6U);
- path x9nc(const_cast<wchar_t*>(ws.c_str())); // wchar_t* null terminated
- PATH_IS(x9nc, L"wstring");
- BOOST_TEST_EQ(x9nc.native().size(), 7U);
- // non-contiguous containers
- path x10(l); // std::list<char>
- PATH_IS(x10, L"string");
- BOOST_TEST_EQ(x10.native().size(), 6U);
- path xll(wl); // std::list<wchar_t>
- PATH_IS(xll, L"wstring");
- BOOST_TEST_EQ(xll.native().size(), 7U);
- // easy-to-make coding errors
- // path e1(x0, path::codecvt()); // fails to compile, and that is OK
- boost::shared_ptr< Derived > pDerived( new Derived() );
- fun( pDerived ); // tests constructor member template enable_if working correctly;
- // will fail to compile if enable_if not taking path off the table
- }
- path x;
- path y;
- // test_assignments ----------------------------------------------------------------//
- void test_assignments()
- {
- std::cout << "testing assignments..." << std::endl;
- x = path("yet another path"); // another path
- PATH_IS(x, L"yet another path");
- BOOST_TEST_EQ(x.native().size(), 16U);
- x = x; // self-assignment
- PATH_IS(x, L"yet another path");
- BOOST_TEST_EQ(x.native().size(), 16U);
- x.assign(l.begin(), l.end()); // iterator range char
- PATH_IS(x, L"string");
- x.assign(wl.begin(), wl.end()); // iterator range wchar_t
- PATH_IS(x, L"wstring");
- x = string("std::string"); // container char
- PATH_IS(x, L"std::string");
- x = wstring(L"std::wstring"); // container wchar_t
- PATH_IS(x, L"std::wstring");
- x = "array char"; // array char
- PATH_IS(x, L"array char");
- x = L"array wchar"; // array wchar_t
- PATH_IS(x, L"array wchar");
- x = s.c_str(); // const char* null terminated
- PATH_IS(x, L"string");
- x = ws.c_str(); // const wchar_t* null terminated
- PATH_IS(x, L"wstring");
- }
- // test_move_construction_and_assignment -------------------------------------------//
- void test_move_construction_and_assignment()
- {
- std::cout << "testing move_construction_and_assignment..." << std::endl;
- # if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
- path from("long enough to avoid small object optimization");
- path to(std::move(from));
- BOOST_TEST(to == "long enough to avoid small object optimization");
- if (!from.empty())
- cout << "Note: move construction did not result in empty source path" << endl;
- path from2("long enough to avoid small object optimization");
- path to2;
- to2 = std::move(from2);
- BOOST_TEST(to2 == "long enough to avoid small object optimization");
- if (!from2.empty())
- cout << "Note: move assignment did not result in empty rhs path" << endl;
- # else
- std::cout <<
- "Test skipped because compiler does not support move semantics" << std::endl;
- # endif
- }
- // test_appends --------------------------------------------------------------------//
- void test_appends()
- {
- std::cout << "testing appends..." << std::endl;
- # ifdef BOOST_WINDOWS_API
- # define BOOST_FS_FOO L"/foo\\"
- # else // POSIX paths
- # define BOOST_FS_FOO L"/foo/"
- # endif
- x = "/foo";
- x /= path(""); // empty path
- PATH_IS(x, L"/foo");
- x = "/foo";
- x /= path("/"); // slash path
- PATH_IS(x, L"/foo/");
- x = "/foo";
- x /= path("/boo"); // slash path
- PATH_IS(x, L"/foo/boo");
- x = "/foo";
- x /= x; // self-append
- PATH_IS(x, L"/foo/foo");
- x = "/foo";
- x /= path("yet another path"); // another path
- PATH_IS(x, BOOST_FS_FOO L"yet another path");
- x = "/foo";
- x.append(l.begin(), l.end()); // iterator range char
- PATH_IS(x, BOOST_FS_FOO L"string");
- x = "/foo";
- x.append(wl.begin(), wl.end()); // iterator range wchar_t
- PATH_IS(x, BOOST_FS_FOO L"wstring");
- x = "/foo";
- x /= string("std::string"); // container char
- PATH_IS(x, BOOST_FS_FOO L"std::string");
- x = "/foo";
- x /= wstring(L"std::wstring"); // container wchar_t
- PATH_IS(x, BOOST_FS_FOO L"std::wstring");
- x = "/foo";
- x /= "array char"; // array char
- PATH_IS(x, BOOST_FS_FOO L"array char");
- x = "/foo";
- x /= L"array wchar"; // array wchar_t
- PATH_IS(x, BOOST_FS_FOO L"array wchar");
- x = "/foo";
- x /= s.c_str(); // const char* null terminated
- PATH_IS(x, BOOST_FS_FOO L"string");
- x = "/foo";
- x /= ws.c_str(); // const wchar_t* null terminated
- PATH_IS(x, BOOST_FS_FOO L"wstring");
- }
- // test_concats --------------------------------------------------------------------//
- void test_concats()
- {
- std::cout << "testing concats..." << std::endl;
- x = "/foo";
- x += path(""); // empty path
- PATH_IS(x, L"/foo");
- x = "/foo";
- x += path("/"); // slash path
- PATH_IS(x, L"/foo/");
- x = "/foo";
- x += path("boo"); // slash path
- PATH_IS(x, L"/fooboo");
- x = "foo";
- x += x; // self-append
- PATH_IS(x, L"foofoo");
- x = "foo-";
- x += path("yet another path"); // another path
- PATH_IS(x, L"foo-yet another path");
- x = "foo-";
- x.concat(l.begin(), l.end()); // iterator range char
- PATH_IS(x, L"foo-string");
- x = "foo-";
- x.concat(wl.begin(), wl.end()); // iterator range wchar_t
- PATH_IS(x, L"foo-wstring");
- x = "foo-";
- x += string("std::string"); // container char
- PATH_IS(x, L"foo-std::string");
- x = "foo-";
- x += wstring(L"std::wstring"); // container wchar_t
- PATH_IS(x, L"foo-std::wstring");
- x = "foo-";
- x += "array char"; // array char
- PATH_IS(x, L"foo-array char");
- x = "foo-";
- x += L"array wchar"; // array wchar_t
- PATH_IS(x, L"foo-array wchar");
- x = "foo-";
- x += s.c_str(); // const char* null terminated
- PATH_IS(x, L"foo-string");
- x = "foo-";
- x += ws.c_str(); // const wchar_t* null terminated
- PATH_IS(x, L"foo-wstring");
- x = "foo-";
- x += 'x'; // char
- PATH_IS(x, L"foo-x");
- x = "foo-";
- x += L'x'; // wchar
- PATH_IS(x, L"foo-x");
- }
- // test_observers ------------------------------------------------------------------//
- void test_observers()
- {
- std::cout << "testing observers..." << std::endl;
- path p0("abc");
- CHECK(p0.native().size() == 3);
- CHECK(p0.size() == 3);
- CHECK(p0.string() == "abc");
- CHECK(p0.string().size() == 3);
- CHECK(p0.wstring() == L"abc");
- CHECK(p0.wstring().size() == 3);
- p0 = "";
- CHECK(p0.native().size() == 0);
- CHECK(p0.size() == 0);
- # ifdef BOOST_WINDOWS_API
- path p("abc\\def/ghi");
- CHECK(std::wstring(p.c_str()) == L"abc\\def/ghi");
- CHECK(p.string() == "abc\\def/ghi");
- CHECK(p.wstring() == L"abc\\def/ghi");
- CHECK(p.generic_path().string() == "abc/def/ghi");
- CHECK(p.generic_string() == "abc/def/ghi");
- CHECK(p.generic_wstring() == L"abc/def/ghi");
- CHECK(p.generic_string<string>() == "abc/def/ghi");
- CHECK(p.generic_string<wstring>() == L"abc/def/ghi");
- CHECK(p.generic_string<path::string_type>() == L"abc/def/ghi");
- # else // BOOST_POSIX_API
- path p("abc\\def/ghi");
- CHECK(string(p.c_str()) == "abc\\def/ghi");
- CHECK(p.string() == "abc\\def/ghi");
- CHECK(p.wstring() == L"abc\\def/ghi");
- CHECK(p.generic_path().string() == "abc\\def/ghi");
- CHECK(p.generic_string() == "abc\\def/ghi");
- CHECK(p.generic_wstring() == L"abc\\def/ghi");
- CHECK(p.generic_string<string>() == "abc\\def/ghi");
- CHECK(p.generic_string<wstring>() == L"abc\\def/ghi");
- CHECK(p.generic_string<path::string_type>() == "abc\\def/ghi");
- # endif
- }
- // test_relationals ----------------------------------------------------------------//
- void test_relationals()
- {
- std::cout << "testing relationals..." << std::endl;
- boost::hash<path> hash;
- # ifdef BOOST_WINDOWS_API
- // this is a critical use case to meet user expectations
- CHECK(path("c:\\abc") == path("c:/abc"));
- CHECK(hash(path("c:\\abc")) == hash(path("c:/abc")));
- # endif
- const path p("bar");
- const path p2("baz");
- CHECK(!(p < p));
- CHECK(p < p2);
- CHECK(!(p2 < p));
- CHECK(p < "baz");
- CHECK(p < string("baz"));
- CHECK(p < L"baz");
- CHECK(p < wstring(L"baz"));
- CHECK(!("baz" < p));
- CHECK(!(string("baz") < p));
- CHECK(!(L"baz" < p));
- CHECK(!(wstring(L"baz") < p));
- CHECK(p == p);
- CHECK(!(p == p2));
- CHECK(!(p2 == p));
- CHECK(p2 == "baz");
- CHECK(p2 == string("baz"));
- CHECK(p2 == L"baz");
- CHECK(p2 == wstring(L"baz"));
- CHECK("baz" == p2);
- CHECK(string("baz") == p2);
- CHECK(L"baz" == p2);
- CHECK(wstring(L"baz") == p2);
- CHECK(hash(p) == hash(p));
- CHECK(hash(p) != hash(p2)); // Not strictly required, but desirable
- CHECK(!(p != p));
- CHECK(p != p2);
- CHECK(p2 != p);
- CHECK(p <= p);
- CHECK(p <= p2);
- CHECK(!(p2 <= p));
- CHECK(!(p > p));
- CHECK(!(p > p2));
- CHECK(p2 > p);
- CHECK(p >= p);
- CHECK(!(p >= p2));
- CHECK(p2 >= p);
- }
- // test_inserter_and_extractor -----------------------------------------------------//
- void test_inserter_and_extractor()
- {
- std::cout << "testing inserter and extractor..." << std::endl;
- path p1("foo bar"); // verify space in path roundtrips per ticket #3863
- path p2;
- std::stringstream ss;
- CHECK(p1 != p2);
- ss << p1;
- ss >> p2;
- CHECK(p1 == p2);
- path wp1(L"foo bar");
- path wp2;
- std::wstringstream wss;
- CHECK(wp1 != wp2);
- wss << wp1;
- wss >> wp2;
- CHECK(wp1 == wp2);
- }
- // test_other_non_members ----------------------------------------------------------//
- void test_other_non_members()
- {
- std::cout << "testing other_non_members..." << std::endl;
- path p1("foo");
- path p2("bar");
- // operator /
- CHECK(p1 / p2 == path("foo/bar").make_preferred());
- CHECK("foo" / p2 == path("foo/bar").make_preferred());
- CHECK(L"foo" / p2 == path("foo/bar").make_preferred());
- CHECK(string("foo") / p2 == path("foo/bar").make_preferred());
- CHECK(wstring(L"foo") / p2 == path("foo/bar").make_preferred());
- CHECK(p1 / "bar" == path("foo/bar").make_preferred());
- CHECK(p1 / L"bar" == path("foo/bar").make_preferred());
- CHECK(p1 / string("bar") == path("foo/bar").make_preferred());
- CHECK(p1 / wstring(L"bar") == path("foo/bar").make_preferred());
- swap(p1, p2);
- CHECK(p1 == "bar");
- CHECK(p2 == "foo");
- CHECK(!path("").filename_is_dot());
- CHECK(!path("").filename_is_dot_dot());
- CHECK(!path("..").filename_is_dot());
- CHECK(!path(".").filename_is_dot_dot());
- CHECK(!path("...").filename_is_dot_dot());
- CHECK(path(".").filename_is_dot());
- CHECK(path("..").filename_is_dot_dot());
- CHECK(path("/.").filename_is_dot());
- CHECK(path("/..").filename_is_dot_dot());
- CHECK(!path("a.").filename_is_dot());
- CHECK(!path("a..").filename_is_dot_dot());
- // edge cases
- CHECK(path("foo/").filename() == path("."));
- CHECK(path("foo/").filename_is_dot());
- CHECK(path("/").filename() == path("/"));
- CHECK(!path("/").filename_is_dot());
- # ifdef BOOST_WINDOWS_API
- CHECK(path("c:.").filename() == path("."));
- CHECK(path("c:.").filename_is_dot());
- CHECK(path("c:/").filename() == path("/"));
- CHECK(!path("c:\\").filename_is_dot());
- # else
- CHECK(path("c:.").filename() == path("c:."));
- CHECK(!path("c:.").filename_is_dot());
- CHECK(path("c:/").filename() == path("."));
- CHECK(path("c:/").filename_is_dot());
- # endif
- // check that the implementation code to make the edge cases above work right
- // doesn't cause some non-edge cases to fail
- CHECK(path("c:").filename() != path("."));
- CHECK(!path("c:").filename_is_dot());
- // examples from reference.html
- std::cout << path(".").filename_is_dot(); // outputs 1
- std::cout << path("/.").filename_is_dot(); // outputs 1
- std::cout << path("foo/.").filename_is_dot(); // outputs 1
- std::cout << path("foo/").filename_is_dot(); // outputs 1
- std::cout << path("/").filename_is_dot(); // outputs 0
- std::cout << path("/foo").filename_is_dot(); // outputs 0
- std::cout << path("/foo.").filename_is_dot(); // outputs 0
- std::cout << path("..").filename_is_dot(); // outputs 0
- cout << std::endl;
- }
- // // test_modifiers ------------------------------------------------------------------//
- //
- // void test_modifiers()
- // {
- // std::cout << "testing modifiers..." << std::endl;
- //
- // }
- // test_iterators ------------------------------------------------------------------//
- void test_iterators()
- {
- std::cout << "testing iterators..." << std::endl;
- path p1;
- CHECK(p1.begin() == p1.end());
- path p2("/");
- CHECK(p2.begin() != p2.end());
- CHECK(*p2.begin() == "/");
- CHECK(++p2.begin() == p2.end());
- path p3("foo/bar/baz");
- path::iterator it(p3.begin());
- CHECK(p3.begin() != p3.end());
- CHECK(*it == "foo");
- CHECK(*++it == "bar");
- CHECK(*++it == "baz");
- CHECK(*--it == "bar");
- CHECK(*--it == "foo");
- CHECK(*++it == "bar");
- CHECK(*++it == "baz");
- CHECK(++it == p3.end());
- }
- // test_reverse_iterators ----------------------------------------------------------//
- void test_reverse_iterators()
- {
- std::cout << "testing reverse_iterators..." << std::endl;
- path p1;
- CHECK(p1.rbegin() == p1.rend());
- path p2("/");
- CHECK(p2.rbegin() != p2.rend());
- CHECK(*p2.rbegin() == "/");
- CHECK(++p2.rbegin() == p2.rend());
- path p3("foo/bar/baz");
- path::reverse_iterator it(p3.rbegin());
- CHECK(p3.rbegin() != p3.rend());
- CHECK(*it == "baz");
- CHECK(*++it == "bar");
- CHECK(*++it == "foo");
- CHECK(*--it == "bar");
- CHECK(*--it == "baz");
- CHECK(*++it == "bar");
- CHECK(*++it == "foo");
- CHECK(++it == p3.rend());
- }
- // test_modifiers ------------------------------------------------------------------//
- void test_modifiers()
- {
- std::cout << "testing modifiers..." << std::endl;
- CHECK(path("").remove_filename() == "");
- CHECK(path("foo").remove_filename() == "");
- CHECK(path("/foo").remove_filename() == "/");
- CHECK(path("foo/bar").remove_filename() == "foo");
- BOOST_TEST_EQ(path("foo/bar/").remove_filename(), path("foo/bar"));
- BOOST_TEST_EQ(path(".").remove_filename(), path(""));
- BOOST_TEST_EQ(path("./.").remove_filename(), path("."));
- BOOST_TEST_EQ(path("/.").remove_filename(), path("/"));
- BOOST_TEST_EQ(path("..").remove_filename(), path(""));
- BOOST_TEST_EQ(path("../..").remove_filename(), path(".."));
- BOOST_TEST_EQ(path("/..").remove_filename(), path("/"));
- }
- // test_decompositions -------------------------------------------------------------//
- void test_decompositions()
- {
- std::cout << "testing decompositions..." << std::endl;
- CHECK(path("").root_name().string() == "");
- CHECK(path("foo").root_name().string() == "");
- CHECK(path("/").root_name().string() == "");
- CHECK(path("/foo").root_name().string() == "");
- CHECK(path("//netname").root_name().string() == "//netname");
- CHECK(path("//netname/foo").root_name().string() == "//netname");
- CHECK(path("").root_directory().string() == "");
- CHECK(path("foo").root_directory().string() == "");
- CHECK(path("/").root_directory().string() == "/");
- CHECK(path("/foo").root_directory().string() == "/");
- CHECK(path("//netname").root_directory().string() == "");
- CHECK(path("//netname/foo").root_directory().string() == "/");
- CHECK(path("").root_path().string() == "");
- CHECK(path("/").root_path().string() == "/");
- CHECK(path("/foo").root_path().string() == "/");
- CHECK(path("//netname").root_path().string() == "//netname");
- CHECK(path("//netname/foo").root_path().string() == "//netname/");
- # ifdef BOOST_WINDOWS_API
- CHECK(path("c:/foo").root_path().string() == "c:/");
- # endif
- CHECK(path("").relative_path().string() == "");
- CHECK(path("/").relative_path().string() == "");
- CHECK(path("/foo").relative_path().string() == "foo");
- CHECK(path("").parent_path().string() == "");
- CHECK(path("/").parent_path().string() == "");
- CHECK(path("/foo").parent_path().string() == "/");
- CHECK(path("/foo/bar").parent_path().string() == "/foo");
- CHECK(path("/foo/bar/baz.zoo").filename().string() == "baz.zoo");
- CHECK(path("/foo/bar/baz.zoo").stem().string() == "baz");
- CHECK(path("/foo/bar.woo/baz").stem().string() == "baz");
- CHECK(path("foo.bar.baz.tar.bz2").extension().string() == ".bz2");
- CHECK(path("/foo/bar/baz.zoo").extension().string() == ".zoo");
- CHECK(path("/foo/bar.woo/baz").extension().string() == "");
- }
- // test_queries --------------------------------------------------------------------//
- void test_queries()
- {
- std::cout << "testing queries..." << std::endl;
- path p1("");
- path p2("//netname/foo.doo");
- CHECK(p1.empty());
- CHECK(!p1.has_root_path());
- CHECK(!p1.has_root_name());
- CHECK(!p1.has_root_directory());
- CHECK(!p1.has_relative_path());
- CHECK(!p1.has_parent_path());
- CHECK(!p1.has_filename());
- CHECK(!p1.has_stem());
- CHECK(!p1.has_extension());
- CHECK(!p1.is_absolute());
- CHECK(p1.is_relative());
- CHECK(!p2.empty());
- CHECK(p2.has_root_path());
- CHECK(p2.has_root_name());
- CHECK(p2.has_root_directory());
- CHECK(p2.has_relative_path());
- CHECK(p2.has_parent_path());
- CHECK(p2.has_filename());
- CHECK(p2.has_stem());
- CHECK(p2.has_extension());
- CHECK(p2.is_absolute());
- CHECK(!p2.is_relative());
- }
- // test_imbue_locale ---------------------------------------------------------------//
- void test_imbue_locale()
- {
- std::cout << "testing imbue locale..." << std::endl;
- // weak test case for before/after states since we don't know what characters the
- // default locale accepts.
- path before("abc");
- // So that tests are run with known encoding, use Boost UTF-8 codecvt
- // \u2722 and \xE2\x9C\xA2 are UTF-16 and UTF-8 FOUR TEARDROP-SPOKED ASTERISK
- std::locale global_loc = std::locale();
- std::locale loc(global_loc, new fs::detail::utf8_codecvt_facet);
- std::cout << " imbuing locale ..." << std::endl;
- std::locale old_loc = path::imbue(loc);
- std::cout << " testing with the imbued locale ..." << std::endl;
- path p2("\xE2\x9C\xA2");
- CHECK(p2.wstring().size() == 1);
- CHECK(p2.wstring()[0] == 0x2722);
- std::cout << " imbuing the original locale ..." << std::endl;
- path::imbue(old_loc);
- std::cout << " testing with the original locale ..." << std::endl;
- path after("abc");
- CHECK(before == after);
- std::cout << " locale testing complete" << std::endl;
- }
- // test_codecvt_argument -----------------------------------------------------------//
- void test_codecvt_argument()
- {
- std::cout << "testing codecvt arguments..." << std::endl;
- const char * c1 = "a1";
- const std::string s1(c1);
- const std::wstring ws1(L"b2"); // off-by-one mimics test_codecvt
- const std::string s2("y8");
- const std::wstring ws2(L"z9");
- test_codecvt cvt; // produces off-by-one values that will always differ from
- // the system's default locale codecvt facet
- int t = 0;
- // constructors
- std::cout << " constructors test " << ++t << std::endl;
- path p(c1, cvt);
- NATIVE_IS(p, s1, ws1);
- std::cout << " test " << ++t << std::endl;
- path p1(s1.begin(), s1.end(), cvt);
- NATIVE_IS(p1, s1, ws1);
- std::cout << " test " << ++t << std::endl;
- path p2(ws2, cvt);
- NATIVE_IS(p2, s2, ws2);
- std::cout << " test " << ++t << std::endl;
- path p3(ws2.begin(), ws2.end(), cvt);
- NATIVE_IS(p3, s2, ws2);
- // path p2(p1, cvt); // fails to compile, and that is OK
- // assigns
- p1.clear();
- std::cout << " assigns test " << ++t << std::endl;
- p1.assign(s1,cvt);
- NATIVE_IS(p1, s1, ws1);
- p1.clear();
- std::cout << " test " << ++t << std::endl;
- p1.assign(s1.begin(), s1.end(), cvt);
- NATIVE_IS(p1, s1, ws1);
- // p1.assign(p, cvt); // fails to compile, and that is OK
- // appends
- p1.clear();
- std::cout << " appends test " << ++t << std::endl;
- p1.append(s1,cvt);
- NATIVE_IS(p1, s1, ws1);
- p1.clear();
- std::cout << " test " << ++t << std::endl;
- p1.append(s1.begin(), s1.end(), cvt);
- NATIVE_IS(p1, s1, ws1);
- // p1.append(p, cvt); // fails to compile, and that is OK
- // native observers
- std::cout << " native observers test " << ++t << std::endl;
- CHECK(p.string<std::string>(cvt) == s1);
- std::cout << " test " << ++t << std::endl;
- CHECK(p.string(cvt) == s1);
- std::cout << " test " << ++t << std::endl;
- CHECK(p.string<std::wstring>(cvt) == ws1);
- std::cout << " test " << ++t << std::endl;
- CHECK(p.wstring(cvt) == ws1);
- // generic observers
- std::cout << " generic observers test " << ++t << std::endl;
- CHECK(p.generic_string<std::string>(cvt) == s1);
- std::cout << " test " << ++t << std::endl;
- CHECK(p.generic_string(cvt) == s1);
- std::cout << " test " << ++t << std::endl;
- CHECK(p.generic_string<std::wstring>(cvt) == ws1);
- std::cout << " test " << ++t << std::endl;
- CHECK(p.generic_wstring(cvt) == ws1);
- std::cout << " codecvt arguments testing complete" << std::endl;
- }
- // test_overloads ------------------------------------------------------------------//
- void test_overloads()
- {
- std::cout << "testing overloads..." << std::endl;
- std::string sto("hello");
- const char a[] = "goodbye";
- path p1(sto);
- path p2(sto.c_str());
- path p3(a);
- path p4("foo");
- std::wstring wsto(L"hello");
- const wchar_t wa[] = L"goodbye";
- path wp1(wsto);
- path wp2(wsto.c_str());
- path wp3(wa);
- path wp4(L"foo");
- }
- // test_error_handling -------------------------------------------------------------//
- class error_codecvt
- : public std::codecvt< wchar_t, char, std::mbstate_t >
- {
- public:
- explicit error_codecvt()
- : std::codecvt<wchar_t, char, std::mbstate_t>() {}
- protected:
- virtual bool do_always_noconv() const throw() { return false; }
- virtual int do_encoding() const throw() { return 0; }
- virtual std::codecvt_base::result do_in(std::mbstate_t&,
- const char*, const char*, const char*&,
- wchar_t*, wchar_t*, wchar_t*&) const
- {
- static std::codecvt_base::result r = std::codecvt_base::noconv;
- if (r == std::codecvt_base::partial) r = std::codecvt_base::error;
- else if (r == std::codecvt_base::error) r = std::codecvt_base::noconv;
- else r = std::codecvt_base::partial;
- return r;
- }
- virtual std::codecvt_base::result do_out(std::mbstate_t &,
- const wchar_t*, const wchar_t*, const wchar_t*&,
- char*, char*, char*&) const
- {
- static std::codecvt_base::result r = std::codecvt_base::noconv;
- if (r == std::codecvt_base::partial) r = std::codecvt_base::error;
- else if (r == std::codecvt_base::error) r = std::codecvt_base::noconv;
- else r = std::codecvt_base::partial;
- return r;
- }
- virtual std::codecvt_base::result do_unshift(std::mbstate_t&,
- char*, char*, char* &) const { return ok; }
- virtual int do_length(std::mbstate_t &,
- const char*, const char*, std::size_t) const { return 0; }
- virtual int do_max_length() const throw () { return 0; }
- };
- void test_error_handling()
- {
- std::cout << "testing error handling..." << std::endl;
- std::locale global_loc = std::locale();
- std::locale loc(global_loc, new error_codecvt);
- std::cout << " imbuing error locale ..." << std::endl;
- std::locale old_loc = path::imbue(loc);
- // These tests rely on a path constructor that fails in the locale conversion.
- // Thus construction has to call codecvt. Force that by using a narrow string
- // for Windows, and a wide string for POSIX.
- # ifdef BOOST_WINDOWS_API
- # define STRING_FOO_ "foo"
- # else
- # define STRING_FOO_ L"foo"
- # endif
- {
- std::cout << " testing std::codecvt_base::partial error..." << std::endl;
- bool exception_thrown (false);
- try { path(STRING_FOO_); }
- catch (const bs::system_error & ex)
- {
- exception_thrown = true;
- BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::partial,
- fs::codecvt_error_category()));
- }
- catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
- BOOST_TEST(exception_thrown);
- }
- {
- std::cout << " testing std::codecvt_base::error error..." << std::endl;
- bool exception_thrown (false);
- try { path(STRING_FOO_); }
- catch (const bs::system_error & ex)
- {
- exception_thrown = true;
- BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::error,
- fs::codecvt_error_category()));
- }
- catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
- BOOST_TEST(exception_thrown);
- }
- {
- std::cout << " testing std::codecvt_base::noconv error..." << std::endl;
- bool exception_thrown (false);
- try { path(STRING_FOO_); }
- catch (const bs::system_error & ex)
- {
- exception_thrown = true;
- BOOST_TEST_EQ(ex.code(), bs::error_code(std::codecvt_base::noconv,
- fs::codecvt_error_category()));
- }
- catch (...) { std::cout << "***** unexpected exception type *****" << std::endl; }
- BOOST_TEST(exception_thrown);
- }
- std::cout << " restoring original locale ..." << std::endl;
- path::imbue(old_loc);
- std::cout << " testing error handling complete" << std::endl;
- }
- # if 0
- // // test_locales --------------------------------------------------------------------//
- //
- // void test_locales()
- // {
- // std::cout << "testing locales..." << std::endl;
- //
- // }
- // test_user_supplied_type ---------------------------------------------------------//
- typedef std::basic_string<int> user_string;
- } // unnamed namespace
- namespace boost
- {
- namespace filesystem
- {
- namespace path_traits
- {
- template<> struct is_iterator<const user_string::value_type *> { static const bool value = true; };
- template<> struct is_iterator<user_string::value_type *> { static const bool value = true; };
- template<> struct is_iterator<user_string::iterator> { static const bool value = true; };
- template<> struct is_iterator<user_string::const_iterator> { static const bool value = true; };
- template<> struct is_container<user_string> { static const bool value = true; };
- template<>
- void append<user_string::value_type>(const user_string::value_type * begin,
- const user_string::value_type * end, string_type & target, system::error_code & ec)
- {
- for (; begin != end && *begin; ++begin)
- target += *begin + 1; // change so that results distinguishable from char cvts
- }
- # ifdef __GNUC__
- // This specialization shouldn't be needed, and VC++, Intel, and others work
- // fine without it. But gcc 4.3.2, and presumably other versions, need it.
- template<>
- void append<user_string::value_type>(const user_string::value_type * begin,
- string_type & target, system::error_code & ec)
- {
- path_traits::append<user_string::value_type>(begin,
- static_cast<const user_string::value_type *>(0), target, ec);
- }
- # endif
- template<>
- user_string convert<user_string>(const string_type & source,
- system::error_code & ec)
- {
- user_string temp;
- for (string_type::const_iterator it = source.begin();
- it != source.end(); ++it)
- temp += *it - 1;
- return temp;
- }
- } // namespace path_traits
- } // namespace filesystem
- } // namespace boost
- namespace
- {
- void test_user_supplied_type()
- {
- std::cout << "testing user supplied type..." << std::endl;
- user_string::value_type usr_c_str[] = { 'a', 'b', 'c', 0 };
- user_string usr(usr_c_str);
- path p1(usr.c_str());
- CHECK(p1 == path("bcd"));
- CHECK(p1 == "bcd");
- user_string s1(p1.string<user_string>());
- CHECK(s1 == usr);
- }
- # endif
- inline const char* macro_value(const char* name, const char* value)
- {
- static const char* no_value = "[no value]";
- static const char* not_defined = "[not defined]";
- //if (0 != strcmp(name, value + 1)) // macro is defined
- //{
- // if (value[1])
- // return value;
- // else
- // return no_value;
- //}
- //return not_defined;
- return 0 == strcmp(name, value + 1)
- ? not_defined
- : (value[1] ? value : no_value);
- }
- #define BOOST_MACRO_VALUE(X) macro_value(#X, BOOST_STRINGIZE(=X))
- } // unnamed namespace
- //--------------------------------------------------------------------------------------//
- // //
- // main //
- // //
- //--------------------------------------------------------------------------------------//
- int test_main(int, char*[])
- {
- // document state of critical macros
- #ifdef BOOST_POSIX_API
- cout << "BOOST_POSIX_API" << endl;
- BOOST_TEST(path::preferred_separator == '/');
- #endif
- #ifdef BOOST_WINDOWS_API
- cout << "BOOST_WINDOWS_API" << endl;
- BOOST_TEST(path::preferred_separator == '\\');
- #endif
- cout << "BOOST_FILESYSTEM_DECL "
- << BOOST_MACRO_VALUE(BOOST_FILESYSTEM_DECL) << endl;
- //#ifdef BOOST_FILESYSTEM_DECL
- // cout << "BOOST_FILESYSTEM_DECL is defined as "
- // << BOOST_STRINGIZE(BOOST_FILESYSTEM_DECL) << endl;
- //#else
- // cout << "BOOST_FILESYSTEM_DECL is not defined" << endl;
- //#endif
- l.push_back('s');
- l.push_back('t');
- l.push_back('r');
- l.push_back('i');
- l.push_back('n');
- l.push_back('g');
- wl.push_back(L'w');
- wl.push_back(L's');
- wl.push_back(L't');
- wl.push_back(L'r');
- wl.push_back(L'i');
- wl.push_back(L'n');
- wl.push_back(L'g');
- v.push_back('f');
- v.push_back('u');
- v.push_back('z');
- wv.push_back(L'w');
- wv.push_back(L'f');
- wv.push_back(L'u');
- wv.push_back(L'z');
- test_overloads();
- test_constructors();
- test_assignments();
- test_move_construction_and_assignment();
- test_appends();
- test_concats();
- test_modifiers();
- test_observers();
- test_relationals();
- test_inserter_and_extractor();
- test_other_non_members();
- test_iterators();
- test_reverse_iterators();
- test_decompositions();
- test_queries();
- test_imbue_locale();
- test_codecvt_argument();
- test_error_handling();
- #if 0
- test_user_supplied_type();
- #endif
- std::string foo("\\abc");
- const char* bar = "/abc";
- if (foo == bar)
- cout << "unintended consequence\n";
- return ::boost::report_errors();
- }
|