From 235a594240669e55028d846a43c727e0376f21e2 Mon Sep 17 00:00:00 2001 From: Steffen Schuemann Date: Fri, 31 May 2019 00:46:29 +0200 Subject: [PATCH] Squashed commit of the following: commit 9cc8cbf731375fbedac9e76f883664a27814bff0 Author: Steffen Schuemann Date: Mon May 27 09:36:09 2019 +0200 Workaround for bug in clangs libc++ std::filesystem::path::format. commit 72285d01f2a269247084dddb8fe8d9da66f082a1 Author: Steffen Schuemann Date: Mon May 27 09:17:49 2019 +0200 Test coverage. commit f3ab2af99fda2dad26334d2a4884faa7463f7edb Author: Steffen Schuemann Date: Sun May 26 12:35:39 2019 +0200 Fixed std builds, removed non-standard conforming swap in directory_iterator/recursive_directory_iterator. commit 3ae76b29a0745319d2a64e34bdbcb35264ad3e99 Author: gulrak Date: Sun May 26 11:08:52 2019 +0200 Additional tests. commit af4bbe14e192b464d3fece68c5dbcf3bf1c4e214 Author: gulrak Date: Fri May 24 21:52:15 2019 +0200 Added more tests. --- include/ghc/filesystem.hpp | 28 +++----- test/filesystem_test.cpp | 133 +++++++++++++++++++++++++++++++++++-- 2 files changed, 138 insertions(+), 23 deletions(-) diff --git a/include/ghc/filesystem.hpp b/include/ghc/filesystem.hpp index 58cc8a0..3020a3b 100644 --- a/include/ghc/filesystem.hpp +++ b/include/ghc/filesystem.hpp @@ -681,7 +681,6 @@ public: } bool operator==(const directory_iterator& rhs) const; bool operator!=(const directory_iterator& rhs) const; - void swap(directory_iterator& rhs); private: friend class recursive_directory_iterator; @@ -740,7 +739,6 @@ public: } bool operator==(const recursive_directory_iterator& rhs) const; bool operator!=(const recursive_directory_iterator& rhs) const; - void swap(recursive_directory_iterator& rhs); private: struct recursive_directory_iterator_impl @@ -2515,17 +2513,19 @@ GHC_INLINE path::iterator::iterator(const path::string_type::const_iterator& fir } else #endif + { if (_first != _last && *_first == '/') { - if (_last - _first >= 2 && *(_first + 1) == '/' && !(_last - _first >= 3 && *(_first + 2) == '/')) { - _root = increment(_first); + if (_last - _first >= 2 && *(_first + 1) == '/' && !(_last - _first >= 3 && *(_first + 2) == '/')) { + _root = increment(_first); + } + else { + _root = _first; + } } else { - _root = _first; + _root = _last; } } - else { - _root = _last; - } } GHC_INLINE path::string_type::const_iterator path::iterator::increment(const path::string_type::const_iterator& pos) const @@ -2631,7 +2631,7 @@ GHC_INLINE path::iterator& path::iterator::operator--() GHC_INLINE path::iterator path::iterator::operator--(int) { - path::iterator i{*this}; + auto i = *this; --(*this); return i; } @@ -4778,11 +4778,6 @@ GHC_INLINE bool directory_iterator::operator!=(const directory_iterator& rhs) co return _impl->_current != rhs._impl->_current; } -GHC_INLINE void directory_iterator::swap(directory_iterator& rhs) -{ - std::swap(_impl, rhs._impl); -} - // 30.10.13.2 directory_iterator non-member functions GHC_INLINE directory_iterator begin(directory_iterator iter) noexcept @@ -4948,11 +4943,6 @@ GHC_INLINE bool recursive_directory_iterator::operator!=(const recursive_directo return _impl->_dir_iter_stack.top() != rhs._impl->_dir_iter_stack.top(); } -GHC_INLINE void recursive_directory_iterator::swap(recursive_directory_iterator& rhs) -{ - std::swap(_impl, rhs._impl); -} - // 30.10.14.2 directory_iterator non-member functions GHC_INLINE recursive_directory_iterator begin(recursive_directory_iterator iter) noexcept { diff --git a/test/filesystem_test.cpp b/test/filesystem_test.cpp index a4cddb8..83e3962 100644 --- a/test/filesystem_test.cpp +++ b/test/filesystem_test.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -308,7 +309,7 @@ TEST_CASE("Temporary Directory", "[fs.test.tempdir]") } #ifdef GHC_FILESYSTEM_VERSION -TEST_CASE("fs::detail::fromUf88", "[filesystem][fs.detail.utf8]") +TEST_CASE("fs::detail::fromUtf8", "[filesystem][fs.detail.utf8]") { CHECK(fs::detail::fromUtf8("foobar").length() == 6); CHECK(fs::detail::fromUtf8("foobar") == L"foobar"); @@ -321,6 +322,7 @@ TEST_CASE("fs::detail::fromUf88", "[filesystem][fs.detail.utf8]") CHECK(fs::detail::toUtf8(std::wstring(L"föobar")) == u8"föobar"); CHECK(std::u16string(2,0xfffd) == fs::detail::fromUtf8(std::string("\xed\xa0\x80"))); + CHECK(std::u16string(1,0xfffd) == fs::detail::fromUtf8(std::string("\xc3"))); } TEST_CASE("fs::detail::toUtf8", "[filesystem][fs.detail.utf8]") @@ -348,10 +350,15 @@ TEST_CASE("30.10.8.4.1 path constructors and destructor", "[filesystem][path][fs std::string str = "/usr/local/bin"; std::u16string u16str = u"/usr/local/bin"; std::u32string u32str = U"/usr/local/bin"; + CHECK(str == fs::path(str, fs::path::format::generic_format)); CHECK(str == fs::path(str.begin(), str.end())); CHECK(fs::path(std::wstring(3, 67)) == "CCC"); CHECK(str == fs::path(u16str.begin(), u16str.end())); CHECK(str == fs::path(u32str.begin(), u32str.end())); +#ifdef GHC_FILESYSTEM_VERSION + CHECK(fs::path("///foo/bar") == "/foo/bar"); + CHECK(fs::path("//foo//bar") == "//foo/bar"); +#endif #ifdef GHC_OS_WINDOWS CHECK("\\usr\\local\\bin" == fs::path("/usr/local/bin")); CHECK("C:\\usr\\local\\bin" == fs::path("C:\\usr\\local\\bin")); @@ -963,13 +970,19 @@ TEST_CASE("30.10.8.5 path iterators", "[filesystem][path][fs.path.itr]") p2 /= pe; } CHECK(p1 == p2); + CHECK("bar" == *(--fs::path("/foo/bar").end())); + auto p = fs::path("/foo/bar"); + auto pi = p.end(); + pi--; + CHECK("bar" == *pi); } if (has_host_root_name_support()) { CHECK("foo" == *(--fs::path("//host/foo").end())); - /*auto pi = fs::path("//host/foo").end(); + auto p = fs::path("//host/foo"); + auto pi = p.end(); pi--; - CHECK("foo" == *pi);*/ + CHECK("foo" == *pi); CHECK("//host" == iterateResult(fs::path("//host"))); CHECK("//host,/,foo" == iterateResult(fs::path("//host/foo"))); CHECK("//host" == reverseIterateResult(fs::path("//host"))); @@ -1068,7 +1081,8 @@ TEST_CASE("30.10.8.6.2 path factory functions", "[filesystem][path][fs.path.fact TEST_CASE("30.10.9 class filesystem_error", "[filesystem][filesystem_error][fs.class.filesystem_error]") { std::error_code ec(1, std::system_category()); - auto fse = fs::filesystem_error("Some error", ec); + fs::filesystem_error fse("None", std::error_code()); + fse = fs::filesystem_error("Some error", ec); CHECK(fse.code().value() == 1); CHECK(!std::string(fse.what()).empty()); CHECK(fse.path1().empty()); @@ -1132,8 +1146,10 @@ TEST_CASE("30.10.11 class file_status", "[filesystem][file_status][fs.class.file TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.dir.entry]") { TemporaryDirectory t; + std::error_code ec; auto de = fs::directory_entry(t.path()); CHECK(de.path() == t.path()); + CHECK((fs::path)de == t.path()); CHECK(de.exists()); CHECK(!de.is_block_file()); CHECK(!de.is_character_file()); @@ -1143,21 +1159,98 @@ TEST_CASE("30.10.12 class directory_entry", "[filesystem][directory_entry][fs.di CHECK(!de.is_regular_file()); CHECK(!de.is_socket()); CHECK(!de.is_symlink()); + CHECK(de.status().type() == fs::file_type::directory); + ec.clear(); + CHECK(de.status(ec).type() == fs::file_type::directory); + CHECK(!ec); CHECK_NOTHROW(de.refresh()); + fs::directory_entry none; + CHECK_THROWS_AS(none.refresh(), fs::filesystem_error); + CHECK_THROWS_AS(de.assign(""), fs::filesystem_error); + ec.clear(); + CHECK_NOTHROW(de.assign("", ec)); + CHECK(ec); generateFile(t.path() / "foo", 1234); + auto now = fs::file_time_type::clock::now(); + CHECK_NOTHROW(de.assign(t.path() / "foo")); + CHECK_NOTHROW(de.assign(t.path() / "foo", ec)); + CHECK(!ec); de = fs::directory_entry(t.path() / "foo"); CHECK(de.path() == t.path() / "foo"); CHECK(de.exists()); + CHECK(de.exists(ec)); + CHECK(!ec); CHECK(!de.is_block_file()); + CHECK(!de.is_block_file(ec)); + CHECK(!ec); CHECK(!de.is_character_file()); + CHECK(!de.is_character_file(ec)); + CHECK(!ec); CHECK(!de.is_directory()); + CHECK(!de.is_directory(ec)); + CHECK(!ec); CHECK(!de.is_fifo()); + CHECK(!de.is_fifo(ec)); + CHECK(!ec); CHECK(!de.is_other()); + CHECK(!de.is_other(ec)); + CHECK(!ec); CHECK(de.is_regular_file()); + CHECK(de.is_regular_file(ec)); + CHECK(!ec); CHECK(!de.is_socket()); + CHECK(!de.is_socket(ec)); + CHECK(!ec); CHECK(!de.is_symlink()); + CHECK(!de.is_symlink(ec)); + CHECK(!ec); CHECK(de.file_size() == 1234); + CHECK(de.file_size(ec) == 1234); + CHECK(std::abs(std::chrono::duration_cast(de.last_write_time() - now).count()) < 3); + ec.clear(); + CHECK(std::abs(std::chrono::duration_cast(de.last_write_time(ec) - now).count()) < 3); + CHECK(!ec); CHECK(de.hard_link_count() == 1); + CHECK(de.hard_link_count(ec) == 1); + CHECK(!ec); + CHECK_THROWS_AS(de.replace_filename("bar"), fs::filesystem_error); + CHECK_NOTHROW(de.replace_filename("foo")); + ec.clear(); + CHECK_NOTHROW(de.replace_filename("bar", ec)); + CHECK(ec); + auto de2none = fs::directory_entry(); + ec.clear(); + CHECK(de2none.hard_link_count(ec) == static_cast(-1)); + CHECK_THROWS_AS(de2none.hard_link_count(), fs::filesystem_error); + CHECK(ec); + ec.clear(); + CHECK_NOTHROW(de2none.last_write_time(ec)); + CHECK_THROWS_AS(de2none.last_write_time(), fs::filesystem_error); + CHECK(ec); + ec.clear(); + CHECK_THROWS_AS(de2none.file_size(), fs::filesystem_error); + CHECK(de2none.file_size(ec) == static_cast(-1)); + CHECK(ec); + ec.clear(); + CHECK(de2none.status().type() == fs::file_type::not_found); + CHECK(de2none.status(ec).type() == fs::file_type::not_found); + CHECK(ec); + generateFile(t.path() / "a"); + generateFile(t.path() / "b"); + auto d1 = fs::directory_entry(t.path() / "a"); + auto d2 = fs::directory_entry(t.path() / "b"); + CHECK(d1 < d2); + CHECK(!(d2 < d1)); + CHECK(d1 <= d2); + CHECK(!(d2 <= d1)); + CHECK(d2 > d1); + CHECK(!(d1 > d2)); + CHECK(d2 >= d1); + CHECK(!(d1 >= d2)); + CHECK(d1 != d2); + CHECK(!(d2 != d2)); + CHECK(d1 == d1); + CHECK(!(d1 == d2)); } TEST_CASE("30.10.13 class directory_iterator", "[filesystem][directory_iterator][fs.class.directory_iterator]") @@ -1183,6 +1276,11 @@ TEST_CASE("30.10.13 class directory_iterator", "[filesystem][directory_iterator] CHECK(iter->file_size() == 1234); CHECK(++iter == fs::directory_iterator()); CHECK_THROWS_AS(fs::directory_iterator(t.path() / "non-existing"), fs::filesystem_error); + int cnt = 0; + for(auto de : fs::directory_iterator(t.path())) { + ++cnt; + } + CHECK(cnt == 1); } if (is_symlink_creation_supported()) { TemporaryDirectory t; @@ -1218,6 +1316,11 @@ TEST_CASE("30.10.13 class directory_iterator", "[filesystem][directory_iterator] TEST_CASE("30.10.14 class recursive_directory_iterator", "[filesystem][recursive_directory_iterator][fs.class.rec.dir.itr]") { + { + auto iter = fs::recursive_directory_iterator("."); + iter.pop(); + CHECK(iter == fs::recursive_directory_iterator()); + } { TemporaryDirectory t; CHECK(fs::recursive_directory_iterator(t.path()) == fs::recursive_directory_iterator()); @@ -1302,6 +1405,25 @@ TEST_CASE("30.10.14 class recursive_directory_iterator", "[filesystem][recursive } CHECK(os.str() == "[./a,0],[./d1,0],[./d1/b,1],[./d1/c,1],[./d1/d2,1],[./d1/d2/d,2],[./e,0],"); } + { + TemporaryDirectory t(TempOpt::change_path); + generateFile("a"); + fs::create_directory("d1"); + fs::create_directory("d1/d2"); + generateFile("d1/b"); + generateFile("d1/c"); + generateFile("d1/d2/d"); + generateFile("e"); + std::multiset result; + for(auto de : fs::recursive_directory_iterator(".")) { + result.insert(de.path().generic_string()); + } + std::stringstream os; + for(auto p : result) { + os << p << ","; + } + CHECK(os.str() == "./a,./d1,./d1/b,./d1/c,./d1/d2,./d1/d2/d,./e,"); + } { TemporaryDirectory t(TempOpt::change_path); generateFile("a"); @@ -2243,6 +2365,9 @@ TEST_CASE("30.10.15.29 relative", "[filesystem][operations][fs.op.relative]") CHECK(fs::relative("a/b/c", "a/b/c/x/y") == "../.."); CHECK(fs::relative("a/b/c", "a/b/c") == "."); CHECK(fs::relative("a/b", "c/d") == "../../a/b"); + std::error_code ec; + CHECK(fs::relative(fs::current_path() / "foo", ec) == "foo"); + CHECK(!ec); } TEST_CASE("30.10.15.30 remove", "[filesystem][operations][fs.op.remove]")