Skip to content

Commit

Permalink
fs: Add nearest_extant_parent() function and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
irydacea committed Oct 5, 2016
1 parent ea9d077 commit f379546
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/filesystem.hpp
Expand Up @@ -182,6 +182,19 @@ std::string base_name(const std::string& file);
*/
std::string directory_name(const std::string& file);

/**
* Finds the nearest parent in existence for a file or directory.
*
* @note The file's own existence is not checked.
*
* @returns An absolute path to the closest parent of the given path, or an
* empty string if none could be found. While on POSIX platforms this
* cannot happen (unless the original path was already empty), on
* Windows it might be the case that the original path refers to a
* drive letter or network share that does not exist.
*/
std::string nearest_extant_parent(const std::string& file);

/**
* Returns the absolute path of a file.
*
Expand Down
20 changes: 20 additions & 0 deletions src/filesystem_boost.cpp
Expand Up @@ -920,6 +920,26 @@ std::string directory_name(const std::string& file)
return path(file).parent_path().string();
}

std::string nearest_extant_parent(const std::string& file)
{
if(file.empty()) {
return "";
}

bfs::path p{file};
error_code ec;

do {
p = p.parent_path();
bfs::path q = canonical(p, ec);
if (!ec) {
p = q;
}
} while(ec && !is_root(p.string()));

return ec ? "" : p.string();
}

bool is_path_sep(char c)
{
static const path sep = path("/").make_preferred();
Expand Down
21 changes: 21 additions & 0 deletions src/tests/test_filesystem.cpp
Expand Up @@ -190,6 +190,27 @@ BOOST_AUTO_TEST_CASE( test_fs_wml_path )
BOOST_CHECK( get_wml_location("why_would_anyone_ever_name_a_file_like_this").empty() );
}

BOOST_AUTO_TEST_CASE( test_fs_search )
{
const std::string& userdata = get_user_data_dir();

BOOST_CHECK_EQUAL( nearest_extant_parent(userdata + "/THIS_DOES_NOT_EXIST/foo/bar"), userdata );

BOOST_CHECK_EQUAL( nearest_extant_parent(gamedata + "/THIS_DOES_NOT_EXIST_EITHER/foo"), gamedata );
BOOST_CHECK_EQUAL( nearest_extant_parent(gamedata + "/data/_main.cfg"), gamedata + "/data" );
BOOST_CHECK_EQUAL( nearest_extant_parent(gamedata + "/data/core/THIS_DOES_NOT_EXIST/test"), gamedata + "/data/core" );

BOOST_CHECK_EQUAL( nearest_extant_parent("/THIS_HOPEFULLY_DOES_NOT_EXIST"), "/" );
BOOST_CHECK_EQUAL( nearest_extant_parent("/bin/THIS_HOPEFULLY_DOES_NOT_EXIST/foo/bar/."), "/bin" );
BOOST_CHECK_EQUAL( nearest_extant_parent("/bin/THIS_HOPEFULLY_DOES_NOT_EXIST/foo"), "/bin" );
BOOST_CHECK_EQUAL( nearest_extant_parent("/bin/THIS_HOPEFULLY_DOES_NOT_EXIST"), "/bin" );
// Directories that don't exist can't have a .. entry.
BOOST_CHECK_EQUAL( nearest_extant_parent("/bin/THIS_HOPEFULLY_DOES_NOT_EXIST/.."), "/bin" );
BOOST_CHECK_EQUAL( nearest_extant_parent("/bin/."), "/bin" );
BOOST_CHECK_EQUAL( nearest_extant_parent("/bin/./../bin/././"), "/bin" );
BOOST_CHECK_EQUAL( nearest_extant_parent("/bin/./../././"), "/" );
}

BOOST_AUTO_TEST_CASE( test_fs_fluff )
{
BOOST_CHECK( ends_with("foobarbazbat", "bazbat") );
Expand Down

0 comments on commit f379546

Please sign in to comment.