diff options
author | Sven Gothel <[email protected]> | 2022-06-16 06:09:37 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2022-06-16 06:09:37 +0200 |
commit | 2585ccd599b9f217a2a953e01c51e0e2c51dea40 (patch) | |
tree | a48cdb15f1f3a2247777c8cee374a6ea9b66a25a | |
parent | 961b256ef7a4a904113771e7f235751e2dab2d0a (diff) |
test_fileutils01: Test new functionality: file_stat, fmode_t and copy() [recursive, preserve_all, follow_symlink, ..]
-rw-r--r-- | test/test_fileutils01.cpp | 1014 | ||||
l--------- | test_data/README_slink08_relext.txt | 1 | ||||
l--------- | test_data/dir_01/dir_01_02/file_03_slink06.txt (renamed from test_data/dir_01/dir_01_02/file_03_slink.txt) | 0 | ||||
l--------- | test_data/dir_01/dir_01_02_slink05 (renamed from test_data/dir_01/dir_01_02_slink) | 0 | ||||
l--------- | test_data/dir_01/file_01_slink02.txt | 1 | ||||
l--------- | test_data/dir_01/file_02_slink03.txt (renamed from test_data/dir_01/file_02_slink.txt) | 0 | ||||
l--------- | test_data/dir_01/file_03_slink04.txt | 1 | ||||
l--------- | test_data/file_01_slink01.txt (renamed from test_data/file_01_slink.txt) | 0 | ||||
l--------- | test_data/fstab_slink07_absolute | 1 |
9 files changed, 866 insertions, 152 deletions
diff --git a/test/test_fileutils01.cpp b/test/test_fileutils01.cpp index 6a4b4bf..5f5b47b 100644 --- a/test/test_fileutils01.cpp +++ b/test/test_fileutils01.cpp @@ -39,6 +39,103 @@ using namespace jau::fractions_i64_literals; +static constexpr const bool _remove_target_test_dir = true; + +struct visitor_stats { + jau::fs::traverse_options topts; + int total_real; + int total_sym_links_existing; + int total_sym_links_not_existing; + int total_no_access; + int total_not_existing; + size_t total_file_bytes; + int files_real; + int files_sym_link; + int dirs_real; + int dirs_sym_link; + + visitor_stats(jau::fs::traverse_options topts_) + : topts(topts_), + total_real(0), + total_sym_links_existing(0), + total_sym_links_not_existing(0), + total_no_access(0), + total_not_existing(0), + total_file_bytes(0), + files_real(0), + files_sym_link(0), + dirs_real(0), + dirs_sym_link(0) + {} + + void add(const jau::fs::file_stats& element_stats) { + if( element_stats.is_link() ) { + if( element_stats.exists() ) { + total_sym_links_existing++; + } else { + total_sym_links_not_existing++; + } + } else { + total_real++; + } + if( !element_stats.has_access() ) { + total_no_access++; + } + if( !element_stats.exists() ) { + total_not_existing++; + } + if( element_stats.is_file() ) { + if( element_stats.is_link() ) { + files_sym_link++; + if( is_set(topts, jau::fs::traverse_options::follow_symlinks) ) { + total_file_bytes += element_stats.size(); + } + } else { + files_real++; + total_file_bytes += element_stats.size(); + } + } else if( element_stats.is_dir() ) { + if( element_stats.is_link() ) { + dirs_sym_link++; + } else { + dirs_real++; + } + } + } + + std::string to_string() const noexcept { + std::string res; + res += "- traverse_options "+jau::fs::to_string(topts)+"\n"; + res += "- total_real "+std::to_string(total_real)+"\n"; + res += "- total_sym_links_existing "+std::to_string(total_sym_links_existing)+"\n"; + res += "- total_sym_links_not_existing "+std::to_string(total_sym_links_not_existing)+"\n"; + res += "- total_no_access "+std::to_string(total_no_access)+"\n"; + res += "- total_not_existing "+std::to_string(total_not_existing)+"\n"; + res += "- total_file_bytes "+jau::to_decstring(total_file_bytes)+"\n"; + res += "- files_real "+std::to_string(files_real)+"\n"; + res += "- files_sym_link "+std::to_string(files_sym_link)+"\n"; + res += "- dirs_real "+std::to_string(dirs_real)+"\n"; + res += "- dirs_sym_link "+std::to_string(dirs_sym_link)+"\n"; + return res; + } +}; + +constexpr bool operator ==(const visitor_stats& lhs, const visitor_stats& rhs) noexcept { + return lhs.total_file_bytes == rhs.total_file_bytes && + lhs.total_real == rhs.total_real && + lhs.total_sym_links_existing == rhs.total_sym_links_existing && + lhs.total_sym_links_not_existing == rhs.total_sym_links_not_existing && + lhs.total_no_access == rhs.total_no_access && + lhs.total_not_existing == rhs.total_not_existing && + lhs.files_real == rhs.files_real && + lhs.files_sym_link == rhs.files_sym_link && + lhs.dirs_real == rhs.dirs_real && + lhs.dirs_sym_link == rhs.dirs_sym_link; +} +constexpr bool operator !=(const visitor_stats& lhs, const visitor_stats& rhs) noexcept { + return !( lhs == rhs ); +} + class TestFileUtil01 { public: const std::string root = "test_data"; @@ -46,14 +143,223 @@ class TestFileUtil01 { const std::string project_root1 = "../../test_data"; // submodule location with jaulib directly hosted below main project const std::string project_root2 = "../../../jaulib/test_data"; + // external filesystem to test ... + const std::string project_root_ext = "/mnt/ssd0/data/test_data"; + + /** + * + */ + void test01_cwd() { + const std::string cwd = jau::fs::get_cwd(); + INFO_STR("\n\ntest01_cwd: cwd "+cwd+"\n"); + REQUIRE( 0 < cwd.size() ); + const size_t idx = cwd.find("/jaulib/"); + REQUIRE( 0 < idx ); + REQUIRE( idx < cwd.size() ); + REQUIRE( idx != std::string::npos ); + } + + /** + * + */ + void test02_dirname() { + { + const std::string pathname0 = "/"; + const std::string pathname1 = jau::fs::dirname(pathname0); + INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "/" ); + } + { + { + const std::string pathname0 = "lala.txt"; + const std::string pathname1 = jau::fs::dirname(pathname0); + INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "." ); + } + { + const std::string pathname0 = "lala"; + const std::string pathname1 = jau::fs::dirname(pathname0); + INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "." ); + } + { + const std::string pathname0 = "lala/"; + const std::string pathname1 = jau::fs::dirname(pathname0); + INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "." ); + } + } + { + const std::string pathname0 = "blabla/jaulib/test/sub.txt"; + const std::string pathname1 = jau::fs::dirname(pathname0); + INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "blabla/jaulib/test" ); + } + { + const std::string pathname0 = "blabla/jaulib/test/sub"; + const std::string pathname1 = jau::fs::dirname(pathname0); + INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "blabla/jaulib/test" ); + } + { + const std::string pathname0 = "blabla/jaulib/test/"; + const std::string pathname1 = jau::fs::dirname(pathname0); + INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "blabla/jaulib" ); + } + { + const std::string pathname0 = "blabla/jaulib/test"; + const std::string pathname1 = jau::fs::dirname(pathname0); + INFO_STR("\n\ntest02_dirname: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "blabla/jaulib" ); + } + } + + void test03_basename() { + { + const std::string pathname0 = "/"; + const std::string pathname1 = jau::fs::basename(pathname0); + INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "/" ); + } + { + { + const std::string pathname0 = "lala.txt"; + const std::string pathname1 = jau::fs::basename(pathname0); + INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "lala.txt" ); + } + { + const std::string pathname0 = "lala"; + const std::string pathname1 = jau::fs::basename(pathname0); + INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "lala" ); + } + { + const std::string pathname0 = "lala/"; + const std::string pathname1 = jau::fs::basename(pathname0); + INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "lala" ); + } + } + { + const std::string pathname0 = "blabla/jaulib/test/sub.txt"; + const std::string pathname1 = jau::fs::basename(pathname0); + INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "sub.txt" ); + } + + { + const std::string pathname0 = "blabla/jaulib/test/"; + const std::string pathname1 = jau::fs::basename(pathname0); + INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "test" ); + } + + { + const std::string pathname0 = "blabla/jaulib/test"; + const std::string pathname1 = jau::fs::basename(pathname0); + INFO_STR("\n\ntest03_basename: cwd "+pathname0+" -> "+pathname1+"\n"); + REQUIRE( 0 < pathname1.size() ); + REQUIRE( pathname1 == "test" ); + } + } + + void test04_file_stat() { + INFO_STR("\n\ntest04_file_stat\n"); + + { + jau::fs::file_stats stats(project_root_ext+"/file_01.txt"); + jau::fprintf_td(stderr, "test04_file_stat: 01: %s\n", stats.to_string().c_str()); + jau::fprintf_td(stderr, "test04_file_stat: 01: fields %s\n", jau::fs::to_string( stats.fields() ).c_str()); + if( stats.exists() ) { + REQUIRE( stats.has_access() ); + REQUIRE( !stats.is_dir() ); + REQUIRE( stats.is_file() ); + REQUIRE( !stats.is_link() ); + REQUIRE( 15 == stats.size() ); + } + } + + jau::fs::file_stats proot_stats(project_root1); + if( !proot_stats.exists() ) { + proot_stats = jau::fs::file_stats(project_root2); + } + jau::fprintf_td(stderr, "test04_file_stat: 11: %s\n", proot_stats.to_string().c_str()); + jau::fprintf_td(stderr, "test04_file_stat: 11: fields %s\n", jau::fs::to_string( proot_stats.fields() ).c_str()); + REQUIRE( true == proot_stats.exists() ); + REQUIRE( true == proot_stats.is_dir() ); + + { + jau::fs::file_stats stats(proot_stats.path()+"/file_01.txt"); + jau::fprintf_td(stderr, "test04_file_stat: 12: %s\n", stats.to_string().c_str()); + jau::fprintf_td(stderr, "test04_file_stat: 12: fields %s\n", jau::fs::to_string( stats.fields() ).c_str()); + REQUIRE( stats.exists() ); + REQUIRE( stats.has_access() ); + REQUIRE( !stats.is_dir() ); + REQUIRE( stats.is_file() ); + REQUIRE( !stats.is_link() ); + REQUIRE( 15 == stats.size() ); + } + { + jau::fs::file_stats stats(proot_stats.path()+"/file_01_slink01.txt"); + jau::fprintf_td(stderr, "test04_file_stat: 13: %s\n", stats.to_string().c_str()); + jau::fprintf_td(stderr, "test04_file_stat: 13: fields %s\n", jau::fs::to_string( stats.fields() ).c_str()); + if( stats.is_link() ) { + jau::fprintf_td(stderr, "test04_file_stat: 13: link_target %s\n", stats.link_target()->to_string().c_str()); + } + REQUIRE( stats.exists() ); + REQUIRE( stats.has_access() ); + REQUIRE( !stats.is_dir() ); + REQUIRE( stats.is_file() ); + REQUIRE( stats.is_link() ); + REQUIRE( 15 == stats.size() ); + REQUIRE( nullptr != stats.link_target() ); + const jau::fs::file_stats* link_target = stats.link_target().get(); + REQUIRE( nullptr != link_target ); + REQUIRE( "file_01.txt" == link_target->path() ); + } + { + jau::fs::file_stats stats(proot_stats.path()+"/fstab_slink07_absolute"); + jau::fprintf_td(stderr, "test04_file_stat: 14: %s\n", stats.to_string().c_str()); + jau::fprintf_td(stderr, "test04_file_stat: 14: fields %s\n", jau::fs::to_string( stats.fields() ).c_str()); + if( stats.is_link() ) { + jau::fprintf_td(stderr, "test04_file_stat: 14: link_target %s\n", stats.link_target()->to_string().c_str()); + } + REQUIRE( stats.exists() ); + REQUIRE( stats.has_access() ); + REQUIRE( !stats.is_dir() ); + REQUIRE( stats.is_file() ); + REQUIRE( stats.is_link() ); + REQUIRE( 20 < stats.size() ); // greater than basename + REQUIRE( nullptr != stats.link_target() ); + const jau::fs::file_stats* link_target = stats.link_target().get(); + REQUIRE( nullptr != link_target ); + REQUIRE( "/etc/fstab" == link_target->path() ); + } + } /** * */ - void test01_mkdir() { - INFO_STR("\n\ntest01_mkdir\n"); + void test10_mkdir() { + INFO_STR("\n\ntest10_mkdir\n"); - jau::fs::remove(root, true); // start fresh + jau::fs::remove(root, jau::fs::traverse_options::recursive); // start fresh { jau::fs::file_stats root_stats(root); INFO_STR("root_stats.pre: "+root_stats.to_string(true)+"\n"); @@ -63,7 +369,7 @@ class TestFileUtil01 { REQUIRE( !root_stats.is_file() ); REQUIRE( !root_stats.is_link() ); } - REQUIRE( true == jau::fs::mkdir(root) ); + REQUIRE( true == jau::fs::mkdir(root, jau::fs::fmode_t::def_dir_prot) ); { jau::fs::file_stats root_stats(root); INFO_STR("root_stats.post: "+root_stats.to_string(true)+"\n"); @@ -73,15 +379,15 @@ class TestFileUtil01 { REQUIRE( !root_stats.is_file() ); REQUIRE( !root_stats.is_link() ); } - REQUIRE( false == jau::fs::remove(root, false) ); - REQUIRE( true == jau::fs::remove(root, true) ); + REQUIRE( false == jau::fs::remove(root, jau::fs::traverse_options::none) ); + REQUIRE( true == jau::fs::remove(root, jau::fs::traverse_options::recursive) ); } - void test02_touch() { - INFO_STR("\n\ntest02_touch\n"); + void test11_touch() { + INFO_STR("\n\ntest11_touch\n"); const std::string file_01 = root+"/data01.txt"; const std::string file_02 = root+"/data02.txt"; - REQUIRE( true == jau::fs::mkdir(root) ); + REQUIRE( true == jau::fs::mkdir(root, jau::fs::fmode_t::def_dir_prot) ); { jau::fs::file_stats root_stats(root); INFO_STR("root_stats1.post: "+root_stats.to_string(true)+"\n"); @@ -92,7 +398,7 @@ class TestFileUtil01 { REQUIRE( !root_stats.is_link() ); } - REQUIRE( true == jau::fs::touch(file_01) ); + REQUIRE( true == jau::fs::touch(file_01, jau::fs::fmode_t::def_file_prot) ); { jau::fs::file_stats file_stats(file_01); INFO_STR("file_stats2.post: "+file_stats.to_string(true)+"\n"); @@ -103,40 +409,61 @@ class TestFileUtil01 { REQUIRE( !file_stats.is_link() ); } - const jau::fraction_timespec atime = jau::getWallClockTime(); - const jau::fraction_timespec ts_20200101( 1577836800_s + 0_h); // 2020-01-01 00:00:00 - const jau::fraction_timespec mtime( ts_20200101 + 31_d + 10_h ); - INFO_STR("atime.pre: "+atime.to_iso8601_string(true)+", "+atime.to_string()+"\n"); - INFO_STR("mtime.pre: "+mtime.to_iso8601_string(true)+", "+mtime.to_string()+"\n"); - REQUIRE( true == jau::fs::touch(file_02, atime, mtime) ); { - jau::fs::file_stats file_stats(file_02); - INFO_STR("file_stats3.post: "+file_stats.to_string(true)+"\n"); - REQUIRE( file_stats.exists() ); - REQUIRE( file_stats.has_access() ); - REQUIRE( !file_stats.is_dir() ); - REQUIRE( file_stats.is_file() ); - REQUIRE( !file_stats.is_link() ); - REQUIRE( atime == file_stats.atime() ); - REQUIRE( mtime == file_stats.mtime() ); + REQUIRE( true == jau::fs::touch(file_02, jau::fs::fmode_t::def_file_prot) ); + jau::fs::file_stats file_stats_pre(file_02); + const jau::fraction_timespec btime_pre = file_stats_pre.btime(); + const jau::fraction_timespec atime_pre = file_stats_pre.atime(); + const jau::fraction_timespec mtime_pre = file_stats_pre.mtime(); + INFO_STR("btime.pre: "+btime_pre.to_iso8601_string(true)+", "+btime_pre.to_string()+"\n"); + INFO_STR("atime.pre: "+atime_pre.to_iso8601_string(true)+", "+atime_pre.to_string()+"\n"); + INFO_STR("mtime.pre: "+mtime_pre.to_iso8601_string(true)+", "+mtime_pre.to_string()+"\n"); + + const jau::fraction_timespec ts_20200101( 1577836800_s + 0_h); // 2020-01-01 00:00:00 + const jau::fraction_timespec atime_set( ts_20200101 + 1_d + 10_h ); + const jau::fraction_timespec mtime_set( ts_20200101 + 31_d + 10_h ); + INFO_STR("atime.set: "+atime_set.to_iso8601_string(true)+", "+atime_set.to_string()+"\n"); + INFO_STR("mtime.set: "+mtime_set.to_iso8601_string(true)+", "+mtime_set.to_string()+"\n"); + REQUIRE( true == jau::fs::touch(file_02, atime_set, mtime_set, jau::fs::fmode_t::def_file_prot) ); + + jau::fs::file_stats file_stats_post(file_02); + const jau::fraction_timespec atime_post = file_stats_post.atime(); + const jau::fraction_timespec mtime_post = file_stats_post.mtime(); + INFO_STR("atime.post: "+atime_post.to_iso8601_string(true)+", "+atime_post.to_string()+"\n"); + INFO_STR("mtime.post: "+mtime_post.to_iso8601_string(true)+", "+mtime_post.to_string()+"\n"); + jau::fprintf_td(stderr, "test11_touch: 03: %s\n", file_stats_post.to_string().c_str()); + { + REQUIRE( file_stats_post.exists() ); + REQUIRE( file_stats_post.has_access() ); + REQUIRE( !file_stats_post.is_dir() ); + REQUIRE( file_stats_post.is_file() ); + REQUIRE( !file_stats_post.is_link() ); + if( file_stats_post.has( jau::fs::file_stats::field_t::atime ) ) { + REQUIRE( atime_set == file_stats_post.atime() ); + } + if( file_stats_post.has( jau::fs::file_stats::field_t::mtime ) ) { + REQUIRE( mtime_set == file_stats_post.mtime() ); + } + } } - REQUIRE( true == jau::fs::remove(root, true) ); + REQUIRE( true == jau::fs::remove(root, jau::fs::traverse_options::recursive) ); } - void test03_visit() { - INFO_STR("\n\ntest03_visit\n"); + + void test20_visit() { + INFO_STR("\n\ntest20_visit\n"); std::string sub_dir1 = root+"/sub1"; std::string sub_dir2 = root+"/sub2"; std::string sub_dir3 = root+"/sub1/sub3"; - REQUIRE( true == jau::fs::mkdir(root) ); + REQUIRE( true == jau::fs::mkdir(root, jau::fs::fmode_t::def_dir_prot) ); REQUIRE( true == jau::fs::touch(root+"/data01.txt") ); REQUIRE( true == jau::fs::touch(root+"/data02.txt") ); - REQUIRE( true == jau::fs::mkdir(sub_dir1) ); - REQUIRE( true == jau::fs::mkdir(sub_dir2) ); - REQUIRE( true == jau::fs::mkdir(sub_dir3) ); + REQUIRE( true == jau::fs::mkdir(sub_dir1, jau::fs::fmode_t::def_dir_prot) ); + REQUIRE( true == jau::fs::mkdir(sub_dir2, jau::fs::fmode_t::def_dir_prot) ); + REQUIRE( true == jau::fs::mkdir(sub_dir3, jau::fs::fmode_t::def_dir_prot) ); REQUIRE( true == jau::fs::touch(sub_dir1+"/data03.txt") ); REQUIRE( true == jau::fs::touch(sub_dir1+"/data04.txt") ); REQUIRE( true == jau::fs::touch(sub_dir2+"/data05.txt") ); @@ -144,55 +471,53 @@ class TestFileUtil01 { REQUIRE( true == jau::fs::touch(sub_dir3+"/data07.txt") ); REQUIRE( true == jau::fs::touch(sub_dir3+"/data08.txt") ); - struct visitor_stats { - int total; - int files; - int dirs; - int sym_links; - }; - visitor_stats stats { 0, 0, 0, 0 }; - const jau::fs::path_visitor pv = jau::bindCaptureRefFunc(&stats, - ( bool(*)(visitor_stats*, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ - ( [](visitor_stats* stats_ptr, const jau::fs::file_stats& element_stats) -> bool { - stats_ptr->total++; - jau::fprintf_td(stderr, "test_03_visit: %d: %s\n", stats_ptr->total, element_stats.to_string(true).c_str()); - if( !element_stats.has_access() ) { - return false; - } - if( element_stats.is_link() ) { - stats_ptr->sym_links++; - } - if( element_stats.is_file() ) { - stats_ptr->files++; - } else if( element_stats.is_dir() ) { - stats_ptr->dirs++; - } - return true; - } ) ); - REQUIRE( true == jau::fs::visit(root, true /* follow_sym_link_dirs */, pv) ); - REQUIRE( 12 == stats.total ); - REQUIRE( 8 == stats.files ); - REQUIRE( 4 == stats.dirs ); - REQUIRE( 0 == stats.sym_links ); - - REQUIRE( true == jau::fs::remove(root, true) ); - } + const jau::fs::traverse_options topts_R_FSL_PDL = jau::fs::traverse_options::recursive | + jau::fs::traverse_options::follow_symlinks | + jau::fs::traverse_options::dir_exit; + visitor_stats stats_R_FSL_PDL(topts_R_FSL_PDL); + { + const jau::fs::path_visitor pv = jau::bindCaptureRefFunc(&stats_R_FSL_PDL, + ( bool(*)(visitor_stats*, jau::fs::traverse_event, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ + ( [](visitor_stats* stats_ptr, jau::fs::traverse_event tevt, const jau::fs::file_stats& element_stats) -> bool { + (void)tevt; + stats_ptr->add(element_stats); + return true; + } ) ); + REQUIRE( true == jau::fs::visit(root, topts_R_FSL_PDL, pv) ); + jau::fprintf_td(stderr, "test20_visit[R, FSL, PDL]: %s\n%s\n", to_string(topts_R_FSL_PDL).c_str(), stats_R_FSL_PDL.to_string().c_str()); + REQUIRE( 12 == stats_R_FSL_PDL.total_real ); + REQUIRE( 0 == stats_R_FSL_PDL.total_sym_links_existing ); + REQUIRE( 0 == stats_R_FSL_PDL.total_sym_links_not_existing ); + REQUIRE( 0 == stats_R_FSL_PDL.total_no_access ); + REQUIRE( 0 == stats_R_FSL_PDL.total_not_existing ); + REQUIRE( 0 == stats_R_FSL_PDL.total_file_bytes ); + REQUIRE( 8 == stats_R_FSL_PDL.files_real ); + REQUIRE( 0 == stats_R_FSL_PDL.files_sym_link ); + REQUIRE( 4 == stats_R_FSL_PDL.dirs_real ); + REQUIRE( 0 == stats_R_FSL_PDL.dirs_sym_link ); + } + const jau::fs::traverse_options topts_R_FSL = jau::fs::traverse_options::recursive | + jau::fs::traverse_options::follow_symlinks | + jau::fs::traverse_options::dir_entry; + visitor_stats stats_R_FSL(topts_R_FSL); + { + const jau::fs::path_visitor pv = jau::bindCaptureRefFunc(&stats_R_FSL, + ( bool(*)(visitor_stats*, jau::fs::traverse_event, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ + ( [](visitor_stats* stats_ptr, jau::fs::traverse_event tevt, const jau::fs::file_stats& element_stats) -> bool { + (void)tevt; + stats_ptr->add(element_stats); + return true; + } ) ); + REQUIRE( true == jau::fs::visit(root, topts_R_FSL, pv) ); + jau::fprintf_td(stderr, "test20_visit[R, FSL]: %s\n%s\n", to_string(topts_R_FSL).c_str(), stats_R_FSL.to_string().c_str()); + REQUIRE( stats_R_FSL_PDL == stats_R_FSL ); + } - /** - * - */ - void test04_cwd() { - const std::string cwd = jau::fs::get_cwd(); - INFO_STR("\n\ntest04_cwd: cwd "+cwd+"\n"); - REQUIRE( 0 < cwd.size() ); - const size_t idx = cwd.find("/jaulib/"); - REQUIRE( 0 < idx ); - REQUIRE( idx < cwd.size() ); - REQUIRE( idx != std::string::npos ); + REQUIRE( true == jau::fs::remove(root, jau::fs::traverse_options::recursive) ); } - void test04_symlink_file() { - INFO_STR("\n\ntest04_symlink_file\n"); + void test21_symlink_file() { + INFO_STR("\n\ntest21_symlink_file\n"); jau::fs::file_stats proot_stats(project_root1); if( !proot_stats.exists() ) { @@ -203,15 +528,15 @@ class TestFileUtil01 { INFO_STR("project_root "+proot_stats.to_string(true)+"\n"); REQUIRE( true == proot_stats.is_dir() ); - jau::fs::file_stats file_01_link_stats(proot_stats.path()+"/file_01_slink.txt"); + jau::fs::file_stats file_01_link_stats(proot_stats.path()+"/file_01_slink01.txt"); INFO_STR("project_root "+file_01_link_stats.to_string(true)+"\n"); REQUIRE( true == file_01_link_stats.is_link() ); REQUIRE( true == file_01_link_stats.is_file() ); REQUIRE( 15 == file_01_link_stats.size() ); } - void test05_visit_symlinks() { - INFO_STR("\n\ntest05_visit_symlinks\n"); + void test22_visit_symlinks() { + INFO_STR("\n\ntest22_visit_symlinks\n"); jau::fs::file_stats proot_stats(project_root1); if( !proot_stats.exists() ) { @@ -219,99 +544,484 @@ class TestFileUtil01 { } REQUIRE( true == proot_stats.exists() ); - struct visitor_stats { - int total_real; - int total_sym_link; - int files_real; - int files_sym_link; - int dirs_real; - int dirs_sym_link; - }; { - visitor_stats stats { 0, 0, 0, 0, 0, 0 }; + const jau::fs::traverse_options topts = jau::fs::traverse_options::recursive | + jau::fs::traverse_options::dir_entry; + visitor_stats stats(topts); const jau::fs::path_visitor pv = jau::bindCaptureRefFunc(&stats, - ( bool(*)(visitor_stats*, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ - ( [](visitor_stats* stats_ptr, const jau::fs::file_stats& element_stats) -> bool { - if( element_stats.is_link() ) { - stats_ptr->total_sym_link++; - } else { - stats_ptr->total_real++; - } - jau::fprintf_td(stderr, "test05_visit_symlinks: total[real %d, symlink %d]: %s\n", - stats_ptr->total_real, stats_ptr->total_sym_link, element_stats.to_string(true).c_str()); - if( !element_stats.has_access() ) { - return false; - } - if( element_stats.is_file() ) { - if( element_stats.is_link() ) { - stats_ptr->files_sym_link++; - } else { - stats_ptr->files_real++; - } - } else if( element_stats.is_dir() ) { - if( element_stats.is_link() ) { - stats_ptr->dirs_sym_link++; - } else { - stats_ptr->dirs_real++; - } - } + ( bool(*)(visitor_stats*, jau::fs::traverse_event, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ + ( [](visitor_stats* stats_ptr, jau::fs::traverse_event tevt, const jau::fs::file_stats& element_stats) -> bool { + (void)tevt; + stats_ptr->add(element_stats); return true; } ) ); - REQUIRE( true == jau::fs::visit(proot_stats, false /* follow_sym_link_dirs */, pv) ); + REQUIRE( true == jau::fs::visit(proot_stats, topts, pv) ); + jau::fprintf_td(stderr, "test22_visit[R]: %s\n%s\n", to_string(topts).c_str(), stats.to_string().c_str()); REQUIRE( 7 == stats.total_real ); - REQUIRE( 3 == stats.total_sym_link ); + REQUIRE( 8 == stats.total_sym_links_existing ); + REQUIRE( 0 == stats.total_sym_links_not_existing ); + REQUIRE( 0 == stats.total_no_access ); + REQUIRE( 0 == stats.total_not_existing ); + REQUIRE( 60 == stats.total_file_bytes ); REQUIRE( 4 == stats.files_real ); - REQUIRE( 3 == stats.files_sym_link ); + REQUIRE( 7 == stats.files_sym_link ); REQUIRE( 3 == stats.dirs_real ); - REQUIRE( 0 == stats.dirs_sym_link ); + REQUIRE( 1 == stats.dirs_sym_link ); } { - visitor_stats stats { 0, 0, 0, 0, 0, 0 }; + const jau::fs::traverse_options topts = jau::fs::traverse_options::recursive | + jau::fs::traverse_options::dir_entry | + jau::fs::traverse_options::follow_symlinks; + visitor_stats stats(topts); const jau::fs::path_visitor pv = jau::bindCaptureRefFunc(&stats, - ( bool(*)(visitor_stats*, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ - ( [](visitor_stats* stats_ptr, const jau::fs::file_stats& element_stats) -> bool { - if( element_stats.is_link() ) { - stats_ptr->total_sym_link++; + ( bool(*)(visitor_stats*, jau::fs::traverse_event, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ + ( [](visitor_stats* stats_ptr, jau::fs::traverse_event tevt, const jau::fs::file_stats& element_stats) -> bool { + (void)tevt; + stats_ptr->add(element_stats); + return true; + } ) ); + REQUIRE( true == jau::fs::visit(proot_stats, topts, pv) ); + jau::fprintf_td(stderr, "test22_visit[R, FSL]: %s\n%s\n", to_string(topts).c_str(), stats.to_string().c_str()); + REQUIRE( 9 == stats.total_real ); + REQUIRE( 9 == stats.total_sym_links_existing ); + REQUIRE( 0 == stats.total_sym_links_not_existing ); + REQUIRE( 0 == stats.total_no_access ); + REQUIRE( 0 == stats.total_not_existing ); + REQUIRE( 60 < stats.total_file_bytes ); // some followed symlink files are of unknown size, e.g. /etc/fstab + REQUIRE( 6 == stats.files_real ); + REQUIRE( 8 == stats.files_sym_link ); + REQUIRE( 3 == stats.dirs_real ); + REQUIRE( 1 == stats.dirs_sym_link ); + } + } + + void test30_copy_file2dir() { + INFO_STR("\n\ntest30_copy_file2dir\n"); + + jau::fs::file_stats root_orig_stats(project_root1); + if( !root_orig_stats.exists() ) { + root_orig_stats = jau::fs::file_stats(project_root2); + } + REQUIRE( true == root_orig_stats.exists() ); + + const std::string root_copy = root+"_copy_test30"; + { + // Fresh target folder + jau::fs::remove(root_copy, jau::fs::traverse_options::recursive); + + REQUIRE( true == jau::fs::mkdir(root_copy, jau::fs::fmode_t::def_dir_prot) ); + { + jau::fs::file_stats stats(root_copy); + REQUIRE( true == stats.exists() ); + REQUIRE( true == stats.ok() ); + REQUIRE( true == stats.is_dir() ); + } + } + jau::fs::file_stats source1_stats(root_orig_stats.path()+"/file_01.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: source1: %s\n", source1_stats.to_string().c_str()); + { + REQUIRE( true == source1_stats.exists() ); + REQUIRE( true == source1_stats.ok() ); + REQUIRE( true == source1_stats.is_file() ); + } + { + // Copy file to folder + const jau::fs::copy_options copts = jau::fs::copy_options::preserve_all | + jau::fs::copy_options::verbose; + { + jau::fs::file_stats dest_stats(root_copy+"/file_01.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: 01: dest.pre: %s\n", dest_stats.to_string().c_str()); + REQUIRE( false == dest_stats.exists() ); + } + REQUIRE( true == jau::fs::copy(source1_stats.path(), root_copy, copts) ); + { + jau::fs::file_stats dest_stats(root_copy+"/file_01.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: 01: dest.post: %s\n", dest_stats.to_string().c_str()); + REQUIRE( true == dest_stats.exists() ); + REQUIRE( true == dest_stats.ok() ); + REQUIRE( true == dest_stats.is_file() ); + REQUIRE( source1_stats.size() == dest_stats.size() ); + REQUIRE( source1_stats.mode() == dest_stats.mode() ); + } + } + { + // Error: already exists of 'Copy file to folder' + const jau::fs::copy_options copts = jau::fs::copy_options::preserve_all | + jau::fs::copy_options::verbose; + { + jau::fs::file_stats dest_stats(root_copy+"/file_01.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: 02: dest.pre: %s\n", dest_stats.to_string().c_str()); + REQUIRE( true == dest_stats.exists() ); + REQUIRE( true == dest_stats.ok() ); + REQUIRE( true == dest_stats.is_file() ); + } + REQUIRE( false == jau::fs::copy(source1_stats.path(), root_copy, copts) ); + } + { + // Overwrite copy file to folder + const jau::fs::copy_options copts = jau::fs::copy_options::preserve_all | + jau::fs::copy_options::overwrite | + jau::fs::copy_options::verbose; + + jau::fprintf_td(stderr, "test30_copy_file2dir: 03: source: %s\n", source1_stats.to_string().c_str()); + { + jau::fs::file_stats dest_stats(root_copy+"/file_01.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: 03: dest.pre: %s\n", dest_stats.to_string().c_str()); + REQUIRE( true == dest_stats.exists() ); + REQUIRE( true == dest_stats.ok() ); + REQUIRE( true == dest_stats.is_file() ); + REQUIRE( source1_stats.size() == dest_stats.size() ); + REQUIRE( source1_stats.mode() == dest_stats.mode() ); + } + REQUIRE( true == jau::fs::copy(source1_stats.path(), root_copy, copts) ); + { + jau::fs::file_stats dest_stats(root_copy+"/file_01.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: 03: dest.post: %s\n", dest_stats.to_string().c_str()); + REQUIRE( true == dest_stats.exists() ); + REQUIRE( true == dest_stats.ok() ); + REQUIRE( true == dest_stats.is_file() ); + REQUIRE( source1_stats.size() == dest_stats.size() ); + REQUIRE( source1_stats.mode() == dest_stats.mode() ); + } + } + if constexpr ( _remove_target_test_dir ) { + REQUIRE( true == jau::fs::remove(root_copy, jau::fs::traverse_options::recursive) ); + } + } + + void test31_copy_file2file() { + INFO_STR("\n\ntest31_copy_file2file\n"); + + jau::fs::file_stats root_orig_stats(project_root1); + if( !root_orig_stats.exists() ) { + root_orig_stats = jau::fs::file_stats(project_root2); + } + REQUIRE( true == root_orig_stats.exists() ); + + const std::string root_copy = root+"_copy_test31"; + { + // Fresh target folder + jau::fs::remove(root_copy, jau::fs::traverse_options::recursive); + + REQUIRE( true == jau::fs::mkdir(root_copy, jau::fs::fmode_t::def_dir_prot) ); + { + jau::fs::file_stats stats(root_copy); + REQUIRE( true == stats.exists() ); + REQUIRE( true == stats.ok() ); + REQUIRE( true == stats.is_dir() ); + } + } + jau::fs::file_stats source1_stats(root_orig_stats.path()+"/file_01.txt"); + jau::fprintf_td(stderr, "test31_copy_file2file: source1: %s\n", source1_stats.to_string().c_str()); + { + REQUIRE( true == source1_stats.exists() ); + REQUIRE( true == source1_stats.ok() ); + REQUIRE( true == source1_stats.is_file() ); + } + jau::fs::file_stats source2_stats(root_orig_stats.path()+"/README_slink08_relext.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: source2: %s\n", source2_stats.to_string().c_str()); + { + REQUIRE( true == source2_stats.exists() ); + REQUIRE( true == source2_stats.ok() ); + REQUIRE( true == source2_stats.is_file() ); + REQUIRE( true == source2_stats.is_link() ); + } + { + // Copy file to new file-name + const jau::fs::copy_options copts = jau::fs::copy_options::preserve_all | + jau::fs::copy_options::verbose; + { + jau::fs::file_stats dest_stats(root_copy+"/file_10.txt"); + jau::fprintf_td(stderr, "test31_copy_file2file: 10: dest.pre: %s\n", dest_stats.to_string().c_str()); + REQUIRE( false == dest_stats.exists() ); + } + REQUIRE( true == jau::fs::copy(source1_stats.path(), root_copy+"/file_10.txt", copts) ); + { + jau::fs::file_stats dest_stats(root_copy+"/file_10.txt"); + jau::fprintf_td(stderr, "test31_copy_file2file: 10: dest.post: %s\n", dest_stats.to_string().c_str()); + REQUIRE( true == dest_stats.exists() ); + REQUIRE( true == dest_stats.ok() ); + REQUIRE( true == dest_stats.is_file() ); + REQUIRE( source1_stats.size() == dest_stats.size() ); + REQUIRE( source1_stats.mode() == dest_stats.mode() ); + } + } + { + // Error: already exists of 'Copy file to file' + const jau::fs::copy_options copts = jau::fs::copy_options::preserve_all | + jau::fs::copy_options::verbose; + { + jau::fs::file_stats dest_stats(root_copy+"/file_10.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: 11: dest.pre: %s\n", dest_stats.to_string().c_str()); + REQUIRE( true == dest_stats.exists() ); + REQUIRE( true == dest_stats.ok() ); + REQUIRE( true == dest_stats.is_file() ); + } + REQUIRE( false == jau::fs::copy(source1_stats.path(), root_copy+"/file_10.txt", copts) ); + } + { + // Overwrite copy file to file + const jau::fs::copy_options copts = jau::fs::copy_options::preserve_all | + jau::fs::copy_options::overwrite | + jau::fs::copy_options::follow_symlinks | + jau::fs::copy_options::verbose; + + { + jau::fs::file_stats dest_stats(root_copy+"/file_10.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: 12: dest.pre: %s\n", dest_stats.to_string().c_str()); + REQUIRE( true == dest_stats.exists() ); + REQUIRE( true == dest_stats.ok() ); + REQUIRE( true == dest_stats.is_file() ); + REQUIRE( source1_stats.size() == dest_stats.size() ); + REQUIRE( source1_stats.mode() == dest_stats.mode() ); + } + REQUIRE( true == jau::fs::copy(source2_stats.path(), root_copy+"/file_10.txt", copts) ); + { + jau::fs::file_stats dest_stats(root_copy+"/file_10.txt"); + jau::fprintf_td(stderr, "test30_copy_file2dir: 12: dest.post: %s\n", dest_stats.to_string().c_str()); + REQUIRE( true == dest_stats.exists() ); + REQUIRE( true == dest_stats.ok() ); + REQUIRE( true == dest_stats.is_file() ); + REQUIRE( false == dest_stats.is_link() ); + REQUIRE( source2_stats.size() == dest_stats.size() ); + REQUIRE( source2_stats.link_target()->prot_mode() == dest_stats.prot_mode() ); + } + } + if constexpr ( _remove_target_test_dir ) { + REQUIRE( true == jau::fs::remove(root_copy, jau::fs::traverse_options::recursive) ); + } + } + + void test40_copy_ext_r_p() { + INFO_STR("\n\ntest40_copy_ext_r_p\n"); + + jau::fs::file_stats root_orig_stats(project_root1); + if( !root_orig_stats.exists() ) { + root_orig_stats = jau::fs::file_stats(project_root2); + } + REQUIRE( true == root_orig_stats.exists() ); + + const std::string root_copy = root+"_copy_test40"; + const jau::fs::copy_options copts = jau::fs::copy_options::recursive | + jau::fs::copy_options::preserve_all | + jau::fs::copy_options::sync | + jau::fs::copy_options::verbose; + { + jau::fs::remove(root_copy, jau::fs::traverse_options::recursive); + + REQUIRE( true == jau::fs::copy(root_orig_stats.path(), root_copy, copts) ); + } + jau::fs::file_stats root_copy_stats(root_copy); + REQUIRE( true == root_copy_stats.exists() ); + REQUIRE( true == root_copy_stats.ok() ); + REQUIRE( true == root_copy_stats.is_dir() ); + + bool(*pv_capture)(visitor_stats*, jau::fs::traverse_event, const jau::fs::file_stats&) = + ( [](visitor_stats* stats_ptr, jau::fs::traverse_event tevt, const jau::fs::file_stats& element_stats) -> bool { + (void)tevt; + stats_ptr->add(element_stats); + return true; + } ); + { + + const jau::fs::traverse_options topts = jau::fs::traverse_options::recursive | + jau::fs::traverse_options::dir_entry; + visitor_stats stats(topts); + visitor_stats stats_copy(topts); + const jau::fs::path_visitor pv_orig = jau::bindCaptureRefFunc(&stats, pv_capture); + const jau::fs::path_visitor pv_copy = jau::bindCaptureRefFunc(&stats_copy, pv_capture); + REQUIRE( true == jau::fs::visit(root_orig_stats, topts, pv_orig) ); + REQUIRE( true == jau::fs::visit(root_copy_stats, topts, pv_copy) ); + + jau::fprintf_td(stderr, "test40_copy_ext_r_p: copy %s, traverse %s\n", + to_string(copts).c_str(), to_string(topts).c_str()); + + jau::fprintf_td(stderr, "test40_copy_ext_r_p: source visitor stats\n%s\n", stats.to_string().c_str()); + jau::fprintf_td(stderr, "test40_copy_ext_r_p: destination visitor stats\n%s\n", stats_copy.to_string().c_str()); + + REQUIRE( 7 == stats.total_real ); + REQUIRE( 8 == stats.total_sym_links_existing ); + REQUIRE( 0 == stats.total_sym_links_not_existing ); + REQUIRE( 0 == stats.total_no_access ); + REQUIRE( 0 == stats.total_not_existing ); + REQUIRE( 60 == stats.total_file_bytes ); + REQUIRE( 4 == stats.files_real ); + REQUIRE( 7 == stats.files_sym_link ); + REQUIRE( 3 == stats.dirs_real ); + REQUIRE( 1 == stats.dirs_sym_link ); + + REQUIRE( 7 == stats_copy.total_real ); + REQUIRE( 7 == stats_copy.total_sym_links_existing ); + REQUIRE( 1 == stats_copy.total_sym_links_not_existing ); // symlink ../README.txt + REQUIRE( 0 == stats_copy.total_no_access ); + REQUIRE( 1 == stats_copy.total_not_existing ); // symlink ../README.txt + REQUIRE( 60 == stats_copy.total_file_bytes ); + REQUIRE( 4 == stats_copy.files_real ); + REQUIRE( 6 == stats_copy.files_sym_link ); + REQUIRE( 3 == stats_copy.dirs_real ); + REQUIRE( 1 == stats_copy.dirs_sym_link ); + } + { + // compare each file in detail O(n*n) + const jau::fs::traverse_options topts = jau::fs::traverse_options::recursive | + jau::fs::traverse_options::dir_entry; + struct search_and_result { + std::string basename; + jau::fs::file_stats stats; + bool match; + }; + const jau::fs::path_visitor pv1 = jau::bindCaptureRefFunc<bool, const jau::fs::file_stats, jau::fs::traverse_event, const jau::fs::file_stats&>(&root_copy_stats, + ( bool(*)(const jau::fs::file_stats*, jau::fs::traverse_event, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ + ( [](const jau::fs::file_stats* _root_copy_stats, jau::fs::traverse_event tevt1, const jau::fs::file_stats& element_stats1) -> bool { + (void)tevt1; + search_and_result sar { jau::fs::basename( element_stats1.path() ), element_stats1, false }; + const jau::fs::path_visitor pv2 = jau::bindCaptureRefFunc<bool, search_and_result, jau::fs::traverse_event, const jau::fs::file_stats&>(&sar, + ( bool(*)(search_and_result*, jau::fs::traverse_event, const jau::fs::file_stats&) ) /* help template type deduction of function-ptr */ + ( [](search_and_result* _sar, jau::fs::traverse_event tevt2, const jau::fs::file_stats& element_stats2) -> bool { + (void)tevt2; + const std::string basename2 = jau::fs::basename( element_stats2.path() ); + if( basename2 == _sar->basename || + ( "test_data" == _sar->basename && "test_data_copy_test40" == basename2 ) + ) + { + if( "README_slink08_relext.txt" == basename2 ) { + // symlink to ../README.txt not existent on target + _sar->match = element_stats2.is_link() && + !element_stats2.exists(); + } else { + _sar->match = + element_stats2.mode() == _sar->stats.mode() && + element_stats2.atime() == _sar->stats.atime() && + element_stats2.mtime() == _sar->stats.mtime() && + element_stats2.uid() == _sar->stats.uid() && + element_stats2.gid() == _sar->stats.gid() && + element_stats2.size() == _sar->stats.size(); + } + jau::fprintf_td(stderr, "test40_copy_ext_r_p.check: '%s', match %d\n\t source %s\n\t dest__ %s\n\n", + basename2.c_str(), _sar->match, + _sar->stats.to_string().c_str(), + element_stats2.to_string().c_str()); + return false; // done + } else { + return true; // continue search + } + } ) ); + if( jau::fs::visit(*_root_copy_stats, topts, pv2) ) { + jau::fprintf_td(stderr, "test40_copy_ext_r_p.check: '%s', not found!\n\t source %s\n\n", + sar.basename.c_str(), + element_stats1.to_string().c_str()); + return false; // not found, abort } else { - stats_ptr->total_real++; - } - jau::fprintf_td(stderr, "test05_visit_symlinks: total[real %d, symlink %d]: %s\n", - stats_ptr->total_real, stats_ptr->total_sym_link, element_stats.to_string(true).c_str()); - if( !element_stats.has_access() ) { - return false; - } - if( element_stats.is_file() ) { - if( element_stats.is_link() ) { - stats_ptr->files_sym_link++; - } else { - stats_ptr->files_real++; - } - } else if( element_stats.is_dir() ) { - if( element_stats.is_link() ) { - stats_ptr->dirs_sym_link++; + // found + if( sar.match ) { + return true; // found and matching, continue } else { - stats_ptr->dirs_real++; + return false; // found not matching, abort } } - return true; } ) ); - REQUIRE( true == jau::fs::visit(proot_stats, true /* follow_sym_link_dirs */, pv) ); + REQUIRE( true == jau::fs::visit(root_orig_stats, topts, pv1) ); + } + if constexpr ( _remove_target_test_dir ) { + REQUIRE( true == jau::fs::remove(root_copy, jau::fs::traverse_options::recursive) ); + } + } + + void test41_copy_ext_r_p_fsl() { + INFO_STR("\n\ntest41_copy_ext_r_p_fsl\n"); + + jau::fs::file_stats root_orig_stats(project_root1); + if( !root_orig_stats.exists() ) { + root_orig_stats = jau::fs::file_stats(project_root2); + } + REQUIRE( true == root_orig_stats.exists() ); + + const std::string root_copy = root+"_copy_test41"; + const jau::fs::copy_options copts = jau::fs::copy_options::recursive | + jau::fs::copy_options::preserve_all | + jau::fs::copy_options::follow_symlinks | + jau::fs::copy_options::verbose; + { + jau::fs::remove(root_copy, jau::fs::traverse_options::recursive); + + REQUIRE( true == jau::fs::copy(root_orig_stats.path(), root_copy, copts) ); + } + jau::fs::file_stats root_copy_stats(root_copy); + REQUIRE( true == root_copy_stats.exists() ); + REQUIRE( true == root_copy_stats.ok() ); + REQUIRE( true == root_copy_stats.is_dir() ); + + bool(*pv_capture)(visitor_stats*, jau::fs::traverse_event, const jau::fs::file_stats&) = + ( [](visitor_stats* stats_ptr, jau::fs::traverse_event tevt, const jau::fs::file_stats& element_stats) -> bool { + (void)tevt; + stats_ptr->add(element_stats); + return true; + } ); + { + + const jau::fs::traverse_options topts_orig = jau::fs::traverse_options::recursive | + jau::fs::traverse_options::dir_entry | + jau::fs::traverse_options::follow_symlinks; + + const jau::fs::traverse_options topts_copy = jau::fs::traverse_options::recursive | + jau::fs::traverse_options::dir_entry; + visitor_stats stats(topts_orig); + visitor_stats stats_copy(topts_copy); + const jau::fs::path_visitor pv_orig = jau::bindCaptureRefFunc(&stats, pv_capture); + const jau::fs::path_visitor pv_copy = jau::bindCaptureRefFunc(&stats_copy, pv_capture); + REQUIRE( true == jau::fs::visit(root_orig_stats, topts_orig, pv_orig) ); + REQUIRE( true == jau::fs::visit(root_copy_stats, topts_copy, pv_copy) ); + + jau::fprintf_td(stderr, "test41_copy_ext_r_p_fsl: copy %s, traverse_orig %s, traverse_copy %s\n", + to_string(copts).c_str(), to_string(topts_orig).c_str(), to_string(topts_copy).c_str()); + + jau::fprintf_td(stderr, "test41_copy_ext_r_p_fsl: source visitor stats\n%s\n", stats.to_string().c_str()); + jau::fprintf_td(stderr, "test41_copy_ext_r_p_fsl: destination visitor stats\n%s\n", stats_copy.to_string().c_str()); + REQUIRE( 9 == stats.total_real ); - REQUIRE( 5 == stats.total_sym_link ); + REQUIRE( 9 == stats.total_sym_links_existing ); + REQUIRE( 0 == stats.total_sym_links_not_existing ); + REQUIRE( 0 == stats.total_no_access ); + REQUIRE( 0 == stats.total_not_existing ); + REQUIRE( 60 < stats.total_file_bytes ); // some followed symlink files are of unknown size, e.g. /etc/fstab REQUIRE( 6 == stats.files_real ); - REQUIRE( 4 == stats.files_sym_link ); + REQUIRE( 8 == stats.files_sym_link ); REQUIRE( 3 == stats.dirs_real ); REQUIRE( 1 == stats.dirs_sym_link ); + + REQUIRE( 18 == stats_copy.total_real ); + REQUIRE( 0 == stats_copy.total_sym_links_existing ); + REQUIRE( 0 == stats_copy.total_sym_links_not_existing ); + REQUIRE( 0 == stats_copy.total_no_access ); + REQUIRE( 0 == stats_copy.total_not_existing ); + REQUIRE( 60 < stats_copy.total_file_bytes ); // some followed symlink files are of unknown size, e.g. /etc/fstab + REQUIRE( 14 == stats_copy.files_real ); + REQUIRE( 0 == stats_copy.files_sym_link ); + REQUIRE( 4 == stats_copy.dirs_real ); + REQUIRE( 0 == stats_copy.dirs_sym_link ); + } + if constexpr ( _remove_target_test_dir ) { + REQUIRE( true == jau::fs::remove(root_copy, jau::fs::traverse_options::recursive) ); } } - }; -METHOD_AS_TEST_CASE( TestFileUtil01::test01_mkdir, "Test TestFileUtil01 - test01_mkdir"); -METHOD_AS_TEST_CASE( TestFileUtil01::test02_touch, "Test TestFileUtil01 - test02_touch"); -METHOD_AS_TEST_CASE( TestFileUtil01::test03_visit, "Test TestFileUtil01 - test03_visit"); -METHOD_AS_TEST_CASE( TestFileUtil01::test04_cwd, "Test TestFileUtil01 - test04_cwd"); -METHOD_AS_TEST_CASE( TestFileUtil01::test04_symlink_file, "Test TestFileUtil01 - test04_symlink_file"); -METHOD_AS_TEST_CASE( TestFileUtil01::test05_visit_symlinks, "Test TestFileUtil01 - test05_visit_symlinks"); +METHOD_AS_TEST_CASE( TestFileUtil01::test01_cwd, "Test TestFileUtil01 - test01_cwd"); +METHOD_AS_TEST_CASE( TestFileUtil01::test02_dirname, "Test TestFileUtil01 - test02_dirname"); +METHOD_AS_TEST_CASE( TestFileUtil01::test03_basename, "Test TestFileUtil01 - test03_basename"); +METHOD_AS_TEST_CASE( TestFileUtil01::test04_file_stat, "Test TestFileUtil01 - test04_file_stat"); + +METHOD_AS_TEST_CASE( TestFileUtil01::test10_mkdir, "Test TestFileUtil01 - test10_mkdir"); +METHOD_AS_TEST_CASE( TestFileUtil01::test11_touch, "Test TestFileUtil01 - test11_touch"); + +METHOD_AS_TEST_CASE( TestFileUtil01::test20_visit, "Test TestFileUtil01 - test20_visit"); +METHOD_AS_TEST_CASE( TestFileUtil01::test21_symlink_file, "Test TestFileUtil01 - test21_symlink_file"); +METHOD_AS_TEST_CASE( TestFileUtil01::test22_visit_symlinks, "Test TestFileUtil01 - test22_visit_symlinks"); + +METHOD_AS_TEST_CASE( TestFileUtil01::test30_copy_file2dir, "Test TestFileUtil01 - test30_copy_file2dir"); +METHOD_AS_TEST_CASE( TestFileUtil01::test31_copy_file2file, "Test TestFileUtil01 - test31_copy_file2file"); + +METHOD_AS_TEST_CASE( TestFileUtil01::test40_copy_ext_r_p, "Test TestFileUtil01 - test40_copy_ext_r_p"); +METHOD_AS_TEST_CASE( TestFileUtil01::test41_copy_ext_r_p_fsl, "Test TestFileUtil01 - test41_copy_ext_r_p_fsl"); diff --git a/test_data/README_slink08_relext.txt b/test_data/README_slink08_relext.txt new file mode 120000 index 0000000..32d46ee --- /dev/null +++ b/test_data/README_slink08_relext.txt @@ -0,0 +1 @@ +../README.md
\ No newline at end of file diff --git a/test_data/dir_01/dir_01_02/file_03_slink.txt b/test_data/dir_01/dir_01_02/file_03_slink06.txt index e26f1fa..e26f1fa 120000 --- a/test_data/dir_01/dir_01_02/file_03_slink.txt +++ b/test_data/dir_01/dir_01_02/file_03_slink06.txt diff --git a/test_data/dir_01/dir_01_02_slink b/test_data/dir_01/dir_01_02_slink05 index c905156..c905156 120000 --- a/test_data/dir_01/dir_01_02_slink +++ b/test_data/dir_01/dir_01_02_slink05 diff --git a/test_data/dir_01/file_01_slink02.txt b/test_data/dir_01/file_01_slink02.txt new file mode 120000 index 0000000..1ae15e9 --- /dev/null +++ b/test_data/dir_01/file_01_slink02.txt @@ -0,0 +1 @@ +../file_01.txt
\ No newline at end of file diff --git a/test_data/dir_01/file_02_slink.txt b/test_data/dir_01/file_02_slink03.txt index 3a65244..3a65244 120000 --- a/test_data/dir_01/file_02_slink.txt +++ b/test_data/dir_01/file_02_slink03.txt diff --git a/test_data/dir_01/file_03_slink04.txt b/test_data/dir_01/file_03_slink04.txt new file mode 120000 index 0000000..ab2f316 --- /dev/null +++ b/test_data/dir_01/file_03_slink04.txt @@ -0,0 +1 @@ +dir_01_02/file_03.txt
\ No newline at end of file diff --git a/test_data/file_01_slink.txt b/test_data/file_01_slink01.txt index cfc1d83..cfc1d83 120000 --- a/test_data/file_01_slink.txt +++ b/test_data/file_01_slink01.txt diff --git a/test_data/fstab_slink07_absolute b/test_data/fstab_slink07_absolute new file mode 120000 index 0000000..8995e35 --- /dev/null +++ b/test_data/fstab_slink07_absolute @@ -0,0 +1 @@ +/etc/fstab
\ No newline at end of file |