// 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 // 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 #include // for imbue tests #include "test_codecvt.hpp" // for codecvt arg tests #include #include // used constructor tests #include #include #include #include #include #include #include #include #include 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 l; // see main() for initialization to s, t, r, i, n, g std::list wl; // see main() for initialization to w, s, t, r, i, n, g std::vector v; // see main() for initialization to f, u, z std::vector 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 PATH_IS(x4v, L"fuz"); BOOST_TEST_EQ(x4v.native().size(), 3U); path x5v(wv); // std::vector 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(s.c_str())); // char* null terminated PATH_IS(x8nc, L"string"); BOOST_TEST_EQ(x8nc.native().size(), 6U); path x9nc(const_cast(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 PATH_IS(x10, L"string"); BOOST_TEST_EQ(x10.native().size(), 6U); path xll(wl); // std::list 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() == "abc/def/ghi"); CHECK(p.generic_string() == L"abc/def/ghi"); CHECK(p.generic_string() == 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() == "abc\\def/ghi"); CHECK(p.generic_string() == L"abc\\def/ghi"); CHECK(p.generic_string() == "abc\\def/ghi"); # endif } // test_relationals ----------------------------------------------------------------// void test_relationals() { std::cout << "testing relationals..." << std::endl; boost::hash 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(cvt) == s1); std::cout << " test " << ++t << std::endl; CHECK(p.string(cvt) == s1); std::cout << " test " << ++t << std::endl; CHECK(p.string(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(cvt) == s1); std::cout << " test " << ++t << std::endl; CHECK(p.generic_string(cvt) == s1); std::cout << " test " << ++t << std::endl; CHECK(p.generic_string(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() {} 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 user_string; } // unnamed namespace namespace boost { namespace filesystem { namespace path_traits { template<> struct is_iterator { static const bool value = true; }; template<> struct is_iterator { static const bool value = true; }; template<> struct is_iterator { static const bool value = true; }; template<> struct is_iterator { static const bool value = true; }; template<> struct is_container { static const bool value = true; }; template<> void append(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(const user_string::value_type * begin, string_type & target, system::error_code & ec) { path_traits::append(begin, static_cast(0), target, ec); } # endif template<> user_string convert(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()); 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(); }