diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4cc9485..c995e9e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -8,6 +8,7 @@ project : requirements /boost/filesystem//boost_filesystem /boost/system//boost_system + /boost/chrono//boost_chrono /boost/test//boost_prg_exec_monitor msvc:on ; diff --git a/test/convenience_test.cpp b/test/convenience_test.cpp index 0083eb7..9a04ff3 100644 --- a/test/convenience_test.cpp +++ b/test/convenience_test.cpp @@ -125,19 +125,21 @@ int cpp_main(int, char*[]) it = fs::recursive_directory_iterator(unique_dir); BOOST_TEST(it->path() == unique_yy); - BOOST_TEST(it.level() == 0); + BOOST_TEST(it.depth() == 0); ++it; BOOST_TEST(it->path() == unique_yy_zz); - BOOST_TEST(it.level() == 1); + BOOST_TEST(it.depth() == 1); it.pop(); BOOST_TEST(it->path() == unique_yya); - BOOST_TEST(it.level() == 0); + BOOST_TEST(it.depth() == 0); it++; BOOST_TEST(it == fs::recursive_directory_iterator()); it = fs::recursive_directory_iterator(unique_dir); BOOST_TEST(it->path() == unique_yy); - it.no_push(); + BOOST_TEST(it.recursion_pending()); + it.disable_recursion_pending(); + BOOST_TEST(!it.recursion_pending()); ++it; BOOST_TEST(it->path() == unique_yya); ++it; @@ -151,16 +153,16 @@ int cpp_main(int, char*[]) it = fs::recursive_directory_iterator(unique_dir); BOOST_TEST(it->path() == unique_yy); - BOOST_TEST(it.level() == 0); + BOOST_TEST(it.depth() == 0); ++it; BOOST_TEST(it->path() == unique_yy_zz); - BOOST_TEST(it.level() == 1); + BOOST_TEST(it.depth() == 1); it++; BOOST_TEST(it == fs::recursive_directory_iterator()); it = fs::recursive_directory_iterator(unique_dir); BOOST_TEST(it->path() == unique_yy); - it.no_push(); + it.disable_recursion_pending(); ++it; BOOST_TEST(it == fs::recursive_directory_iterator()); diff --git a/test/deprecated_test.cpp b/test/deprecated_test.cpp index 60f8349..fd8d336 100644 --- a/test/deprecated_test.cpp +++ b/test/deprecated_test.cpp @@ -164,6 +164,8 @@ namespace fs::initial_path(); fs::initial_path(); + p = fs::initial_path(); + p.file_string(); p.directory_string(); } @@ -250,5 +252,24 @@ int cpp_main(int /*argc*/, char* /*argv*/[]) // see the rationale in html docs for explanation why this works BOOST_TEST(fs::change_extension("", ".png").string() == ".png"); +// recursive_directory_iterator tests --------------------------------------// + + fs::recursive_directory_iterator iter("."); + BOOST_TEST(iter.no_push_request() != iter.recursion_pending()); + BOOST_TEST(iter.no_push_pending() != iter.recursion_pending()); + iter.no_push(); + +// symlink_option + + BOOST_TEST(fs::directory_options::none == fs::symlink_option::none); + BOOST_TEST(fs::directory_options::follow_directory_symlink + == fs::symlink_option::recurse); + +// copy_option + + BOOST_TEST(fs::copy_options::none == fs::copy_option::none); + BOOST_TEST(fs::copy_options::overwrite_if_exists + == fs::copy_option::overwrite_if_exists); + return ::boost::report_errors(); } diff --git a/test/locale_info.cpp b/test/locale_info.cpp index db57bb1..150e21d 100644 --- a/test/locale_info.cpp +++ b/test/locale_info.cpp @@ -7,8 +7,14 @@ #include #include -#include +#include #include +#include + +#ifndef BOOST_NO_CXX11_HDR_CODECVT +# include +#endif + using namespace std; #ifdef _MSC_VER @@ -20,11 +26,30 @@ namespace { void facet_info(const locale& loc, const char* msg) { + cout << "has_facet >(" + << msg << ") is " + << (has_facet >(loc) + ? "true\n" + : "false\n"); cout << "has_facet >(" << msg << ") is " << (has_facet >(loc) ? "true\n" : "false\n"); +#ifndef BOOST_NO_CXX11_HDR_CODECVT + cout << "has_facet >(" + << msg << ") is " + << (has_facet >(loc) + ? "true\n" + : "false\n"); +#endif +#ifndef BOOST_NO_CXX11_HDR_CODECVT + cout << "has_facet >(" + << msg << ") is " + << (has_facet >(loc) + ? "true\n" + : "false\n"); +#endif } void default_info() @@ -32,7 +57,7 @@ namespace try { locale loc; - cout << "\nlocale default construction OK" << endl; + cout << "\nlocale default construction OK, name is " << loc.name() << endl; facet_info(loc, "locale()"); } catch (const exception& ex) @@ -46,7 +71,7 @@ namespace try { locale loc(""); - cout << "\nlocale(\"\") construction OK" << endl; + cout << "\nlocale(\"\") construction OK, name is " << loc.name() << endl; facet_info(loc, "locale(\"\")"); } catch (const exception& ex) @@ -60,7 +85,7 @@ namespace try { locale loc(locale::classic()); - cout << "\nlocale(locale::classic()) copy construction OK" << endl; + cout << "\nlocale(locale::classic()) copy construction OK, name is " << loc.name() << endl; facet_info(loc, "locale::classic()"); } catch (const exception& ex) @@ -68,6 +93,52 @@ namespace cout << "\nlocale(locale::clasic()) copy construction threw: " << ex.what() << endl; } } + + void codecvt_info(const locale& loc) + { + cout << "\ncodecvt conversion for locale " << loc.name() << endl; + + char s[128]; + wchar_t ws[128]; + + for (int i = 0; i < 128; ++i) + { + s[i] = char(128 + i); + ws[i] = L'\0'; + } + + mbstate_t state = mbstate_t(); // VC++ needs initialization + const char* from_next; + wchar_t* to_next; + codecvt::result result; + + try + { + result = use_facet >(loc).in(state, s, s+128, from_next, ws, ws+128, to_next); + } + catch (const runtime_error& x) + { + cout << "exception: " << x.what() << endl; + return; + } + + if (result != codecvt::ok) + { + cout << "Oops! conversion returned " << result << endl; + return; + } + + cout << hex; + for (int i = 0; i < 128; ++i) + { + cout << s[i] << ':' << (unsigned short)(ws[i]); + if (i % 8) + cout << ','; + else + cout << endl; + } + cout << endl; + } } int main() @@ -76,10 +147,31 @@ int main() cout << "\nLANG environmental variable is " << (lang ? lang : "not present") << endl; +#ifndef BOOST_NO_CXX11_HDR_CODECVT + cout << "BOOST_NO_CXX11_HDR_CODECVT is not defined" << endl; +#else + cout << "BOOST_NO_CXX11_HDR_CODECVT is defined" << endl; +#endif + +#ifndef BOOST_NO_CXX11_CHAR16_T + cout << "BOOST_NO_CXX11_CHAR16_T is not defined" << endl; +#else + cout << "BOOST_NO_CXX11_CHAR16_T is defined" << endl; +#endif + +#ifndef BOOST_NO_CXX11_CHAR32_T + cout << "BOOST_NO_CXX11_CHAR32_T is not defined" << endl; +#else + cout << "BOOST_NO_CXX11_CHAR32_T is defined" << endl; +#endif + default_info(); null_string_info(); classic_info(); + codecvt_info(locale()); + codecvt_info(locale("")); + return 0; } diff --git a/test/operations_test.cpp b/test/operations_test.cpp index dccd765..8f16b69 100644 --- a/test/operations_test.cpp +++ b/test/operations_test.cpp @@ -17,6 +17,7 @@ # define BOOST_SYSTEM_NO_DEPRECATED #endif +#define BOOST_CHRONO_HEADER_ONLY #include #include @@ -95,6 +96,7 @@ inline int unsetenv(const char* name) namespace { + fs::path initial_path = fs::current_path(); typedef int errno_t; std::string platform(BOOST_PLATFORM); bool report_throws = false; @@ -117,6 +119,20 @@ namespace const fs::path temp_dir(fs::unique_path("operations-test-%%%%-%%%%-%%%%-%%%%")); + std::time_t to_time_t(fs::file_time_type ft) +# ifdef BOOST_FILESYSTEM_USE_TIME_T + {return ft;} +# else + {return boost::chrono::system_clock::to_time_t(ft);} +# endif + + fs::file_time_type from_time_t(std::time_t ft) +# ifdef BOOST_FILESYSTEM_USE_TIME_T + {return ft;} +# else + {return boost::chrono::system_clock::from_time_t(ft);} +# endif + void create_file(const fs::path & ph, const std::string & contents = std::string()) { std::ofstream f(ph.BOOST_FILESYSTEM_C_STR); @@ -165,6 +181,14 @@ namespace return false; } + void delay(std::time_t amt) + { + std::time_t start = std::time(0); + cout << " start delay" << endl; + while (start + amt >= std::time(0)) {} + cout << " end delay" << endl; + } + boost::system::error_category* poison_category_aux() { return 0; } boost::system::error_category& poison_category() { return *poison_category_aux(); } @@ -231,17 +255,17 @@ namespace std::ostream& operator<<(std::ostream& os, const fs::file_status& s) { - if (s.type() == fs::status_error) { os << "status_error"; } - else if (s.type() == fs::file_not_found) { os << "file_not_found"; } - else if (s.type() == fs::regular_file) { os << "regular_file"; } - else if (s.type() == fs::directory_file) { os << "directory_file"; } - else if (s.type() == fs::symlink_file) { os << "symlink_file"; } - else if (s.type() == fs::block_file) { os << "block_file"; } - else if (s.type() == fs::character_file) { os << "character_file"; } - else if (s.type() == fs::fifo_file) { os << "fifo_file"; } - else if (s.type() == fs::socket_file) { os << "socket_file"; } - else if (s.type() == fs::reparse_file) { os << "reparse_file"; } - else if (s.type() == fs::type_unknown) { os << "type_unknown"; } + if (s.type() == fs::file_type::none) { os << "file_type::none"; } + else if (s.type() == fs::file_type::not_found) { os << "file_type::not_found"; } + else if (s.type() == fs::file_type::regular) { os << "file_type::regular"; } + else if (s.type() == fs::file_type::directory) { os << "file_type::directory"; } + else if (s.type() == fs::file_type::symlink) { os << "file_type::symlink"; } + else if (s.type() == fs::file_type::block) { os << "file_type::block"; } + else if (s.type() == fs::file_type::character) { os << "file_type::character"; } + else if (s.type() == fs::file_type::fifo) { os << "file_type::fifo"; } + else if (s.type() == fs::file_type::socket) { os << "file_type::socket"; } + else if (s.type() == fs::file_type::reparse_point) { os << "file_type::reparse_point"; } + else if (s.type() == fs::file_type::unknown) { os << "file_type::unknown"; } else { os << "_detail_directory_symlink"; } return os; } @@ -249,11 +273,11 @@ namespace void dump_tree(const fs::path & root) { cout << "dumping tree rooted at " << root << endl; - for (fs::recursive_directory_iterator it (root, fs::symlink_option::recurse); + for (fs::recursive_directory_iterator it (root, fs::directory_options::follow_directory_symlink); it != fs::recursive_directory_iterator(); ++it) { - for (int i = 0; i <= it.level(); ++i) + for (int i = 0; i <= it.depth(); ++i) cout << " "; cout << it->path(); @@ -600,11 +624,16 @@ namespace int walk_tree(bool recursive) { int d1f1_count = 0; - for (fs::recursive_directory_iterator it (dir, - recursive ? fs::symlink_option::recurse : fs::symlink_option::no_recurse); +// for (fs::recursive_directory_iterator it (dir, fs::directory_options::none); + for (fs::recursive_directory_iterator it (dir, + recursive ? fs::directory_options::follow_directory_symlink + : fs::directory_options::none); it != fs::recursive_directory_iterator(); ++it) { + BOOST_TEST(it.options() == + (recursive ? fs::directory_options::follow_directory_symlink + : fs::directory_options::none)); if (it->path().filename() == "d1f1") ++d1f1_count; } @@ -621,7 +650,7 @@ namespace // test iterator increment with error_code argument boost::system::error_code ec; int d1f1_count = 0; - for (fs::recursive_directory_iterator it (dir, fs::symlink_option::no_recurse); + for (fs::recursive_directory_iterator it (dir); it != fs::recursive_directory_iterator(); it.increment(ec)) { @@ -680,7 +709,7 @@ namespace } else if (it->path().filename() == "dangling_symlink") { - BOOST_TEST(it->status().type() == fs::file_not_found); + BOOST_TEST(it->status().type() == fs::file_type::not_found); BOOST_TEST(fs::is_symlink(it->symlink_status())); } else if (it->path().filename() == "d1_symlink") @@ -690,7 +719,7 @@ namespace } else if (it->path().filename() == "dangling_directory_symlink") { - BOOST_TEST(it->status().type() == fs::file_not_found); + BOOST_TEST(it->status().type() == fs::file_type::not_found); BOOST_TEST(fs::is_symlink(it->symlink_status())); } //else @@ -1146,7 +1175,7 @@ namespace fs::file_status s = fs::status(p); BOOST_TEST(!fs::exists(s)); - BOOST_TEST_EQ(s.type(), fs::file_not_found); + BOOST_TEST(s.type() == fs::file_type::not_found); BOOST_TEST(fs::type_present(s)); BOOST_TEST(!fs::is_regular_file(s)); BOOST_TEST(!fs::is_directory(s)); @@ -1180,7 +1209,7 @@ namespace BOOST_TEST(ec.category() == system_category()); BOOST_TEST(!fs::exists(s)); - BOOST_TEST_EQ(s.type(), fs::file_not_found); + BOOST_TEST(s.type() == fs::file_type::not_found); BOOST_TEST(fs::type_present(s)); BOOST_TEST(!fs::is_regular_file(s)); BOOST_TEST(!fs::is_directory(s)); @@ -1435,7 +1464,7 @@ namespace BOOST_TEST_EQ(fs::canonical(dir / "sym-d1/f2"), d1 / "f2"); BOOST_TEST_EQ(fs::canonical(relative_dir / "sym-d1/f2"), d1 / "f2"); } - + // copy_file_tests ------------------------------------------------------------------// void copy_file_tests(const fs::path& f1, const fs::path& d1) @@ -1446,32 +1475,125 @@ namespace fs::remove(d1 / "f2"); // remove possible residue from prior testing BOOST_TEST(fs::exists(d1)); BOOST_TEST(!fs::exists(d1 / "f2")); - cout << " copy " << f1 << " to " << d1 / "f2" << endl; - fs::copy_file(f1, d1 / "f2"); - cout << " copy complete" << endl; +// cout << " copy_file " << f1 << " to " << d1 / "f2" << endl; + BOOST_TEST(fs::copy_file(f1, d1 / "f2")); +// cout << " copy_file complete" << endl; BOOST_TEST(fs::exists(f1)); BOOST_TEST(fs::exists(d1 / "f2")); + BOOST_TEST_EQ(fs::file_size(d1 / "f2"), 7U); BOOST_TEST(!fs::is_directory(d1 / "f2")); verify_file(d1 / "f2", "file-f1"); + // default copy_options::none bool copy_ex_ok = false; - try { fs::copy_file(f1, d1 / "f2"); } - catch (const fs::filesystem_error &) { copy_ex_ok = true; } + try + { + BOOST_TEST(!fs::copy_file(f1, d1 / "f2")); + } + catch (const fs::filesystem_error&) { copy_ex_ok = true; } BOOST_TEST(copy_ex_ok); + // copy_options::none copy_ex_ok = false; - try { fs::copy_file(f1, d1 / "f2", fs::copy_option::fail_if_exists); } - catch (const fs::filesystem_error &) { copy_ex_ok = true; } + try + { + BOOST_TEST(!fs::copy_file(f1, d1 / "f2", fs::copy_options::none)); + } + catch (const fs::filesystem_error&) { copy_ex_ok = true; } BOOST_TEST(copy_ex_ok); - + create_file(d1 / "f2", "1234567890"); BOOST_TEST_EQ(fs::file_size(d1 / "f2"), 10U); + + // copy_options::skip_existing and exists(to) + BOOST_TEST(!fs::copy_file(f1, d1 / "f2", fs::copy_options::skip_existing)); + BOOST_TEST_EQ(fs::file_size(d1 / "f2"), 10U); + + // copy_options::skip_existing and !exists(to) + BOOST_TEST(!fs::exists(d1 / "f3")); + BOOST_TEST(fs::copy_file(f1, d1 / "f3", fs::copy_options::skip_existing)); + BOOST_TEST(fs::exists(d1 / "f3")); + BOOST_TEST_EQ(fs::file_size(d1 / "f3"), 7U); + + // copy_options::overwrite_existing and exists(to) copy_ex_ok = true; - try { fs::copy_file(f1, d1 / "f2", fs::copy_option::overwrite_if_exists); } - catch (const fs::filesystem_error &) { copy_ex_ok = false; } + try + { + BOOST_TEST(fs::copy_file(f1, d1 / "f2", fs::copy_options::overwrite_existing)); + } + catch (const fs::filesystem_error&) { copy_ex_ok = false; } BOOST_TEST(copy_ex_ok); BOOST_TEST_EQ(fs::file_size(d1 / "f2"), 7U); verify_file(d1 / "f2", "file-f1"); + + // copy_options::overwrite_existing and !exists(to) + BOOST_TEST(!fs::exists(d1 / "f4")); + BOOST_TEST(fs::copy_file(f1, d1 / "f4", fs::copy_options::overwrite_existing)); + BOOST_TEST(fs::exists(d1 / "f4")); + BOOST_TEST_EQ(fs::file_size(d1 / "f4"), 7U); + + // copy_options::update_existing and !exists(to) + BOOST_TEST(!fs::exists(d1 / "f5")); + BOOST_TEST(fs::copy_file(f1, d1 / "f5", fs::copy_options::update_existing)); + BOOST_TEST(fs::exists(d1 / "f5")); + BOOST_TEST_EQ(fs::file_size(d1 / "f5"), 7U); + + // copy_options::update_existing and exists(to) and from is older + BOOST_TEST(!fs::copy_file(f1, d1 / "f5", fs::copy_options::update_existing)); + BOOST_TEST_EQ(fs::file_size(d1 / "f5"), 7U); + + // copy_options::update_existing and exists(to) and from is newer + delay(1); + create_file(d1 / "f5a", "12345"); + BOOST_TEST(fs::copy_file(d1 / "f5a", d1 / "f5", fs::copy_options::update_existing)); + BOOST_TEST_EQ(fs::file_size(d1 / "f5"), 5U); + } + + // copy_tests ------------------------------------------------------------------// + + void copy_tests() + { + cout << "copy_tests..." << endl; + + //int regular_file_count = 0; + //int directory_count = 0; + //int logic_error_count = 0; + //for (fs::recursive_directory_iterator it (dir); + // it != fs::recursive_directory_iterator(); + // ++it) + //{ + // if (fs::is_regular_file(it->status())) + // ++regular_file_count; + // else if (fs::is_directory(it->status())) + // ++directory_count; + // else + // ++logic_error_count; + //} + //cout << regular_file_count << " regular_file_count \n"; + //cout << directory_count << " directory_count \n"; + //cout << logic_error_count << " logic_error_count \n"; + + fs::create_directories(dir/"dir1/dir2"); + create_file(dir/"dir1/file1", "file1"); + create_file(dir/"dir1/file2", "file2"); + create_file(dir/"dir1/dir2/file3", "file3"); + BOOST_TEST(exists(dir/"dir1/file1")); + BOOST_TEST(exists(dir/"dir1/file2")); + BOOST_TEST(exists(dir/"dir1/dir2/file3")); + + fs::copy(dir/"dir1", dir/"dir3"); + BOOST_TEST(exists(dir/"dir3/file1")); + BOOST_TEST(exists(dir/"dir3/file2")); + BOOST_TEST(!exists(dir/"dir3/dir2")); + BOOST_TEST(!exists(dir/"dir3/dir2/file3")); + + fs::copy(dir/"dir1", dir/"dir3", + fs::copy_options::recursive | fs::copy_options::skip_existing); + BOOST_TEST(exists(dir/"dir3/file1")); + BOOST_TEST(exists(dir/"dir3/file2")); + BOOST_TEST(exists(dir/"dir3/dir2")); + BOOST_TEST(exists(dir/"dir3/dir2/file3")); + } // symlink_status_tests -------------------------------------------------------------// @@ -1496,23 +1618,23 @@ namespace fs::create_symlink(sym_f1, symsym_f1); // verify all cases detected as symlinks - BOOST_TEST_EQ(fs::symlink_status(dangling_sym, ec).type(), fs::symlink_file); - BOOST_TEST_EQ(fs::symlink_status(dangling_directory_sym, ec).type(), fs::symlink_file); - BOOST_TEST_EQ(fs::symlink_status(sym_d1, ec).type(), fs::symlink_file); - BOOST_TEST_EQ(fs::symlink_status(symsym_d1, ec).type(), fs::symlink_file); - BOOST_TEST_EQ(fs::symlink_status(sym_f1, ec).type(), fs::symlink_file); - BOOST_TEST_EQ(fs::symlink_status(symsym_f1, ec).type(), fs::symlink_file); + BOOST_TEST(fs::symlink_status(dangling_sym, ec).type() == fs::file_type::symlink); + BOOST_TEST(fs::symlink_status(dangling_directory_sym, ec).type() == fs::file_type::symlink); + BOOST_TEST(fs::symlink_status(sym_d1, ec).type() == fs::file_type::symlink); + BOOST_TEST(fs::symlink_status(symsym_d1, ec).type() == fs::file_type::symlink); + BOOST_TEST(fs::symlink_status(sym_f1, ec).type() == fs::file_type::symlink); + BOOST_TEST(fs::symlink_status(symsym_f1, ec).type() == fs::file_type::symlink); // verify all cases resolve to the (possibly recursive) symlink target - BOOST_TEST_EQ(fs::status(dangling_sym, ec).type(), fs::file_not_found); - BOOST_TEST_EQ(fs::status(dangling_directory_sym, ec).type(), fs::file_not_found); + BOOST_TEST(fs::status(dangling_sym, ec).type() == fs::file_type::not_found); + BOOST_TEST(fs::status(dangling_directory_sym, ec).type() == fs::file_type::not_found); - BOOST_TEST_EQ(fs::status(sym_d1, ec).type(), fs::directory_file); - BOOST_TEST_EQ(fs::status(sym_d1 / "d1f1", ec).type(), fs::regular_file); - BOOST_TEST_EQ(fs::status(symsym_d1, ec).type(), fs::directory_file); - BOOST_TEST_EQ(fs::status(symsym_d1 / "d1f1", ec).type(), fs::regular_file); - BOOST_TEST_EQ(fs::status(sym_f1, ec).type(), fs::regular_file); - BOOST_TEST_EQ(fs::status(symsym_f1, ec).type(), fs::regular_file); + BOOST_TEST(fs::status(sym_d1, ec).type() == fs::file_type::directory); + BOOST_TEST(fs::status(sym_d1 / "d1f1", ec).type() == fs::file_type::regular); + BOOST_TEST(fs::status(symsym_d1, ec).type() == fs::file_type::directory); + BOOST_TEST(fs::status(symsym_d1 / "d1f1", ec).type() == fs::file_type::regular); + BOOST_TEST(fs::status(sym_f1, ec).type() == fs::file_type::regular); + BOOST_TEST(fs::status(symsym_f1, ec).type() == fs::file_type::regular); #ifdef BOOST_WINDOWS_API @@ -1587,7 +1709,7 @@ namespace // others (NTFS) report it as UTC. The C standard does not specify // if time_t is local or UTC. - std::time_t ft = fs::last_write_time(f1); + std::time_t ft = to_time_t(fs::last_write_time(f1)); cout << "\n UTC last_write_time() for a file just created is " << std::asctime(std::gmtime(&ft)) << endl; @@ -1595,15 +1717,15 @@ namespace cout << "\n Year is " << tmp->tm_year << endl; --tmp->tm_year; cout << " Change year to " << tmp->tm_year << endl; - fs::last_write_time(f1, std::mktime(tmp)); - std::time_t ft2 = fs::last_write_time(f1); + fs::last_write_time(f1, from_time_t(std::mktime(tmp))); + std::time_t ft2 = to_time_t(fs::last_write_time(f1)); cout << " last_write_time() for the file is now " << std::asctime(std::gmtime(&ft2)) << endl; - BOOST_TEST(ft != fs::last_write_time(f1)); + BOOST_TEST(ft != to_time_t(fs::last_write_time(f1))); cout << "\n Reset to current time" << endl; - fs::last_write_time(f1, ft); - double time_diff = std::difftime(ft, fs::last_write_time(f1)); + fs::last_write_time(f1, from_time_t(ft)); + double time_diff = std::difftime(ft, to_time_t(fs::last_write_time(f1))); cout << " original last_write_time() - current last_write_time() is " << time_diff << " seconds" << endl; @@ -1634,20 +1756,20 @@ namespace && dir.string()[1] == ':'); // verify path includes drive BOOST_TEST(fs::system_complete("").empty()); - BOOST_TEST(fs::system_complete("/") == fs::initial_path().root_path()); + BOOST_TEST(fs::system_complete("/") == initial_path.root_path()); BOOST_TEST(fs::system_complete("foo") - == fs::initial_path() / "foo"); + == initial_path / "foo"); fs::path p1(fs::system_complete("/foo")); BOOST_TEST_EQ(p1.string().size(), 6U); // this failed during v3 development due to bug std::string s1(p1.string() ); - std::string s2(fs::initial_path().root_path().string()+"foo"); + std::string s2(initial_path.root_path().string()+"foo"); BOOST_TEST_EQ(s1, s2); - BOOST_TEST(fs::system_complete(fs::path(fs::initial_path().root_name())) - == fs::initial_path()); - BOOST_TEST(fs::system_complete(fs::path(fs::initial_path().root_name().string() - + "foo")).string() == fs::initial_path() / "foo"); + BOOST_TEST(fs::system_complete(fs::path(initial_path.root_name())) + == initial_path); + BOOST_TEST(fs::system_complete(fs::path(initial_path.root_name().string() + + "foo")).string() == initial_path / "foo"); BOOST_TEST(fs::system_complete(fs::path("c:/")).generic_string() == "c:/"); BOOST_TEST(fs::system_complete(fs::path("c:/foo")).generic_string() @@ -1660,12 +1782,12 @@ namespace { cout << "POSIX specific tests..." << endl; BOOST_TEST(fs::system_complete("").empty()); - BOOST_TEST(fs::initial_path().root_path().string() == "/"); + BOOST_TEST(initial_path.root_path().string() == "/"); BOOST_TEST(fs::system_complete("/").string() == "/"); BOOST_TEST(fs::system_complete("foo").string() - == fs::initial_path().string()+"/foo"); + == initial_path.string()+"/foo"); BOOST_TEST(fs::system_complete("/foo").string() - == fs::initial_path().root_path().string()+"foo"); + == initial_path.root_path().string()+"foo"); } // POSIX } @@ -1676,12 +1798,12 @@ namespace cout << "initial_tests..." << endl; cout << " current_path().string() is\n \"" - << fs::initial_path().string() + << fs::current_path().string() << "\"\n\n"; - BOOST_TEST(fs::initial_path() == fs::current_path()); - BOOST_TEST(fs::initial_path().is_absolute()); + BOOST_TEST(initial_path == fs::current_path()); + BOOST_TEST(initial_path.is_absolute()); BOOST_TEST(fs::current_path().is_absolute()); - BOOST_TEST(fs::initial_path().string() + BOOST_TEST(initial_path.string() == fs::current_path().string()); } @@ -1789,7 +1911,7 @@ namespace BOOST_TEST(!exists(ph)); } - fs::path test_temp_dir = fs::initial_path(); + fs::path test_temp_dir = initial_path; #if defined BOOST_POSIX_API { @@ -1942,7 +2064,7 @@ int cpp_main(int argc, char* argv[]) # endif cout << "API is " << platform << endl; - dir = fs::initial_path() / temp_dir; + dir = initial_path / temp_dir; if (fs::exists(dir)) { @@ -2001,6 +2123,7 @@ int cpp_main(int argc, char* argv[]) copy_symlink_tests(f1, d1); canonical_symlink_tests(); } + copy_tests(); iterator_status_tests(); // lots of cases by now, so a good time to test // dump_tree(dir); recursive_directory_iterator_tests(); @@ -2021,12 +2144,18 @@ int cpp_main(int argc, char* argv[]) if (cleanup) { cout << "post-test removal of " << dir << endl; - BOOST_TEST(fs::remove_all(dir) != 0); + boost::uintmax_t removed = fs::remove_all(dir); + cout << " removed " << removed << " files, including directories" << endl; + BOOST_TEST(removed != 0); // above was added just to simplify testing, but it ended up detecting - // a bug (failure to close an internal search handle). - cout << "post-test removal complete" << endl; + // a bug (failure to close an internal search handle). + + // The following is failing itermittently with a permissions error. The error + // goes away if recursive_directory_iterator_tests() is not run, but directory + // search handles seem to be closed properly. Very perplexing. 8/8/2012. BOOST_TEST(!fs::exists(dir)); BOOST_TEST(fs::remove_all(dir) == 0); + cout << "post-test removal complete" << endl; } cout << "returning from main()" << endl; diff --git a/test/operations_unit_test.cpp b/test/operations_unit_test.cpp index f82bc9f..155c0ac 100644 --- a/test/operations_unit_test.cpp +++ b/test/operations_unit_test.cpp @@ -24,6 +24,7 @@ # define BOOST_SYSTEM_NO_DEPRECATED #endif +#define BOOST_CHRONO_HEADER_ONLY #include // make sure filesystem.hpp works #include @@ -93,7 +94,7 @@ namespace CHECK(file_size("no-such-file", ec) == static_cast(-1)); CHECK(ec == errc::no_such_file_or_directory); - CHECK(status("no-such-file") == file_status(file_not_found, no_perms)); + CHECK(status("no-such-file") == file_status(file_type::not_found, no_perms)); CHECK(exists("/")); CHECK(is_directory("/")); @@ -112,6 +113,10 @@ namespace CHECK(!is_regular_file("/")); CHECK(!boost::filesystem::is_empty("/")); CHECK(!is_other("/")); + CHECK(!is_block_file("/")); + CHECK(!is_character_file("/")); + CHECK(!is_fifo("/")); + CHECK(!is_socket("/")); } // directory_iterator_test -----------------------------------------------// @@ -256,8 +261,8 @@ namespace CHECK(equivalent("/", "/")); CHECK(!equivalent("/", ".")); - std::time_t ft = last_write_time("."); - ft = -1; + file_time_type ft = last_write_time("."); +// ft = -1; last_write_time(".", ft, ec); } @@ -268,11 +273,11 @@ namespace cout << "directory_entry test..." << endl; directory_entry de("foo.bar", - file_status(regular_file, owner_all), file_status(directory_file, group_all)); + file_status(file_type::regular, owner_all), file_status(file_type::directory, group_all)); CHECK(de.path() == "foo.bar"); - CHECK(de.status() == file_status(regular_file, owner_all)); - CHECK(de.symlink_status() == file_status(directory_file, group_all)); + CHECK(de.status() == file_status(file_type::regular, owner_all)); + CHECK(de.symlink_status() == file_status(file_type::directory, group_all)); CHECK(de < directory_entry("goo.bar")); CHECK(de == directory_entry("foo.bar")); CHECK(de != directory_entry("goo.bar")); diff --git a/test/path_test.cpp b/test/path_test.cpp index 620aa0a..364a8c0 100644 --- a/test/path_test.cpp +++ b/test/path_test.cpp @@ -597,10 +597,47 @@ namespace BOOST_TEST(!(as < acs)); BOOST_TEST(!(acs < as)); + // verify compare is actually lexicographical + // character set reality check before lexicographical tests BOOST_TEST(std::string("a.b") < std::string("a/b")); - // verify compare is actually lexicographical - BOOST_TEST(path("a/b") < path("a.b")); + + path lex_lo("a/b"), lex_hi("a.b"); + const char* plex_lo = "a/b"; + const char* plex_hi = "a.b"; + const std::string slex_lo("a/b"), slex_hi("a.b"); + + BOOST_TEST(lex_lo < lex_hi); + BOOST_TEST(lex_lo < "a.b"); + BOOST_TEST(lex_lo < plex_hi); + BOOST_TEST(lex_lo < slex_hi); + BOOST_TEST("a/b" < lex_hi); + BOOST_TEST(plex_lo < lex_hi); + BOOST_TEST(slex_lo < lex_hi); + + BOOST_TEST(!(lex_lo == lex_hi)); + BOOST_TEST(!(lex_lo == "a.b")); + BOOST_TEST(!(lex_lo == plex_hi)); + BOOST_TEST(!(lex_lo == slex_hi)); + BOOST_TEST(!("a/b" == lex_hi)); + BOOST_TEST(!(plex_lo == lex_hi)); + BOOST_TEST(!(slex_lo == lex_hi)); + + // verify path overloads aren't knocking out string overloads + + BOOST_TEST(!(slex_lo < slex_hi)); + BOOST_TEST(!(slex_lo < "a.b")); + BOOST_TEST(!(slex_lo < plex_hi)); + BOOST_TEST(!("a/b" < slex_hi)); + BOOST_TEST(!(plex_lo < slex_hi)); + BOOST_TEST(!(slex_lo == slex_hi)); + BOOST_TEST(!(slex_lo == "a.b")); + BOOST_TEST(!(slex_lo == plex_hi)); + BOOST_TEST(!("a/b" == slex_hi)); + BOOST_TEST(!(plex_lo == slex_hi)); + + // misc test cases + BOOST_TEST(path("a/b") == path("a///b")); BOOST_TEST(path("a/b/") == path("a/b/.")); BOOST_TEST(path("a/b") != path("a/b/")); @@ -1729,6 +1766,27 @@ namespace BOOST_TEST(!fs::portable_file_name(std::string("foo."))); } + // replace_filename_tests ---------------------------------------------------------// + + void replace_filename_tests() + { + std::cout << "replace_filename_tests..." << std::endl; + + BOOST_TEST(path().replace_filename("").empty()); + BOOST_TEST(path().replace_filename("a") == "a"); + BOOST_TEST(path().replace_filename("a.txt") == "a.txt"); + + BOOST_TEST(path("foo").replace_filename("bar") == "bar"); + BOOST_TEST_EQ(path("/").replace_filename("bar"), path("bar")); + BOOST_TEST_EQ(path(".").replace_filename("bar"), path("bar")); + BOOST_TEST_EQ(path("..").replace_filename("bar"), path("bar")); + BOOST_TEST(path("/foo").replace_filename("bar") == "/bar"); + BOOST_TEST(path("my/foo").replace_filename("bar") == "my/bar"); + BOOST_TEST(path("my//foo").replace_filename("bar") == "my/bar"); + BOOST_TEST(path("./foo").replace_filename("bar") == "./bar"); + BOOST_TEST(path("../foo").replace_filename("bar") == "../bar"); + } + // replace_extension_tests ---------------------------------------------------------// void replace_extension_tests() @@ -1820,6 +1878,7 @@ int cpp_main(int, char*[]) non_member_tests(); exception_tests(); name_function_tests(); + replace_filename_tests(); replace_extension_tests(); make_preferred_tests(); diff --git a/test/path_unit_test.cpp b/test/path_unit_test.cpp index 0ae4519..bd5b661 100644 --- a/test/path_unit_test.cpp +++ b/test/path_unit_test.cpp @@ -60,6 +60,15 @@ using std::cout; using std::endl; using std::string; using std::wstring; +using boost::char16; +using boost::char32; +using boost::u16string; +using boost::u32string; +using boost::interop::make_string; +using boost::interop::narrow; +using boost::interop::wide; +using boost::interop::utf16; +using boost::interop::utf32; #define CHECK(x) check(x, __FILE__, __LINE__) #define PATH_IS(a, b) check_path(a, b, __FILE__, __LINE__) @@ -143,8 +152,26 @@ namespace string s("string"); wstring ws(L"wstring"); + + // Test with cases that require UTF-16 surrogate pairs + // U+1F60A SMILING FACE WITH SMILING EYES + // U+1F60E SMILING FACE WITH SUNGLASSES + + // build test strings character by character so they work with C++03 compilers + const char32 u32c[] = {0x1F60A, 0x1F60E, 0}; + const char16 u16c[] = {0xD83D, 0xDE0A, 0xD83D, 0xDE0E, 0}; + + const u32string u32s(u32c); + const u16string u16s(u16c); + const string u8s("\xF0\x9F\x98\x8A\xF0\x9F\x98\x8E"); + const string chars("\xF0\x9F\x98\x8A\xF0\x9F\x98\x8E"); + const wstring wchars(L"\xF0\x9F\x98\x8A\xF0\x9F\x98\x8E"); + + 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::list u16l; // see main() for initialization to u, 1, 6, s, t, r, i, n, g + std::list u32l; // see main() for initialization to u, 3, 2, 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 @@ -170,10 +197,27 @@ namespace PATH_IS(x2, L"string"); BOOST_TEST_EQ(x2.native().size(), 6U); +# ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + std::cout << " with rvalue references..." << std::endl; + path x2source("source------------------------32"); + path x2m(std::move(x2source)); // move constructor + BOOST_TEST(x2m == "source------------------------32"); + BOOST_TEST(x2source.empty()); + std::cout << " with rvalue references complete" << std::endl; +# endif + path x3(wl.begin(), wl.end()); // iterator range wchar_t PATH_IS(x3, L"wstring"); BOOST_TEST_EQ(x3.native().size(), 7U); + path x3_16(u16l.begin(), u16l.end()); // iterator range char16 + PATH_IS(x3_16, L"u16string"); + BOOST_TEST_EQ(x3_16.native().size(), 9U); + + path x3_32(u32l.begin(), u32l.end()); // iterator range char32 + PATH_IS(x3_32, L"u32string"); + BOOST_TEST_EQ(x3_32.native().size(), 9U); + // contiguous containers path x4(string("std::string")); // std::string PATH_IS(x4, L"std::string"); @@ -183,6 +227,14 @@ namespace PATH_IS(x5, L"std::wstring"); BOOST_TEST_EQ(x5.native().size(), 12U); + path x4_16(make_string("u16string")); // u16string + PATH_IS(x4_16, L"u16string"); + BOOST_TEST_EQ(x4_16.native().size(), 9U); + + path x4_32(make_string("u32string")); // u32string + PATH_IS(x4_32, L"u32string"); + BOOST_TEST_EQ(x4_32.native().size(), 9U); + path x4v(v); // std::vector PATH_IS(x4v, L"fuz"); BOOST_TEST_EQ(x4v.native().size(), 3U); @@ -219,6 +271,14 @@ namespace PATH_IS(x9, L"wstring"); BOOST_TEST_EQ(x9.native().size(), 7U); + path x9_16(make_string("cvt-u16string").c_str()); // const char16* null terminated + PATH_IS(x9_16, L"cvt-u16string"); + BOOST_TEST_EQ(x9_16.native().size(), 13U); + + path x9_32(make_string("cvt-u32string").c_str()); // const char32* null terminated + PATH_IS(x9_32, L"cvt-u32string"); + BOOST_TEST_EQ(x9_32.native().size(), 13U); + // non-contiguous containers path x10(l); // std::list PATH_IS(x10, L"string"); @@ -245,9 +305,18 @@ namespace { std::cout << "testing assignments..." << std::endl; - x = path("yet another path"); // another path + x = path("yet another path"); // copy assignment PATH_IS(x, L"yet another path"); BOOST_TEST_EQ(x.native().size(), 16U); + +# ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + std::cout << " with rvalue references" << std::endl; + path x2source("source------------------------32"); + path x2; + x2 = std::move(x2source); // move assignment + BOOST_TEST(x2 == "source------------------------32"); + BOOST_TEST(x2source.empty()); +# endif x = x; // self-assignment PATH_IS(x, L"yet another path"); @@ -423,6 +492,15 @@ namespace CHECK(p0.string().size() == 3); CHECK(p0.wstring() == L"abc"); CHECK(p0.wstring().size() == 3); + CHECK(p0.u16string() == (make_string("abc"))); + CHECK(p0.u16string().size() == 3); + CHECK(p0.u32string() == (make_string("abc"))); + CHECK(p0.u32string().size() == 3); + + CHECK(p0.string() == p0.string()); + CHECK(p0.string() == (p0.basic_string, std::allocator >())); + # ifdef BOOST_WINDOWS_API @@ -435,6 +513,8 @@ namespace CHECK(p.generic_string() == "abc/def/ghi"); CHECK(p.generic_wstring() == L"abc/def/ghi"); + CHECK(p.generic_u16string() == (make_string("abc/def/ghi"))); + CHECK(p.generic_u32string() == (make_string("abc/def/ghi"))); CHECK(p.generic_string() == "abc/def/ghi"); CHECK(p.generic_string() == L"abc/def/ghi"); @@ -451,6 +531,8 @@ namespace CHECK(p.generic_string() == "abc\\def/ghi"); CHECK(p.generic_wstring() == L"abc\\def/ghi"); + CHECK(p.generic_u16string() == (make_string("abc\\def/ghi"))); + CHECK(p.generic_u32string() == (make_string("abc\\def/ghi"))); CHECK(p.generic_string() == "abc\\def/ghi"); CHECK(p.generic_string() == L"abc\\def/ghi"); @@ -473,32 +555,35 @@ namespace CHECK(hash(path("c:\\abc")) == hash(path("c:/abc"))); # endif - const path p("bar"); - const path p2("baz"); + const path p("a/b"); + const path p2("a.b"); + + // verify "a.c" < "a/c", so tests will detect failure to do lexicographic compare + CHECK(string("a.b") < string("a/b")); 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 < "a.b"); + CHECK(p < string("a.b")); + CHECK(p < L"a.b"); + CHECK(p < wstring(L"a.b")); + CHECK(!("a.b" < p)); + CHECK(!(string("a.b") < p)); + CHECK(!(L"a.b" < p)); + CHECK(!(wstring(L"a.b") < 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(p2 == "a.b"); + CHECK(p2 == string("a.b")); + CHECK(p2 == L"a.b"); + CHECK(p2 == wstring(L"a.b")); + CHECK("a.b" == p2); + CHECK(string("a.b") == p2); + CHECK(L"a.b" == p2); + CHECK(wstring(L"a.b") == p2); CHECK(hash(p) == hash(p)); CHECK(hash(p) != hash(p2)); // Not strictly required, but desirable @@ -620,6 +705,11 @@ namespace { std::cout << "testing modifiers..." << std::endl; + path p("foo/bar"); + std::cout << p << std::endl; // outputs: "foo/bar" + p.make_preferred(); + std::cout << p << std::endl; // outputs: "foo\bar" on Windows, otherwise "foo/bar" + } // test_decompositions -------------------------------------------------------------// @@ -1063,6 +1153,26 @@ int cpp_main(int, char*[]) wl.push_back(L'n'); wl.push_back(L'g'); + u16l.push_back('u'); + u16l.push_back('1'); + u16l.push_back('6'); + u16l.push_back('s'); + u16l.push_back('t'); + u16l.push_back('r'); + u16l.push_back('i'); + u16l.push_back('n'); + u16l.push_back('g'); + + u32l.push_back('u'); + u32l.push_back('3'); + u32l.push_back('2'); + u32l.push_back('s'); + u32l.push_back('t'); + u32l.push_back('r'); + u32l.push_back('i'); + u32l.push_back('n'); + u32l.push_back('g'); + v.push_back('f'); v.push_back('u'); v.push_back('z');