Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit-test for UpwardFileSearch(). #783

Merged
merged 10 commits into from
Apr 22, 2021
2 changes: 1 addition & 1 deletion .github/bin/build-and-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ BAZEL_OPTS="${BAZEL_OPTS} --cxxopt=-Wno-array-bounds" # kythe

case "$MODE" in
test)
bazel test $BAZEL_OPTS //...
bazel test --test_output=errors $BAZEL_OPTS //...
;;

compile|clean)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/macos-compile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ jobs:
fetch-depth: 0
- name: Build
run: |
bazel test --cxxopt=-Wno-range-loop-analysis ...
bazel test --test_output=errors --cxxopt=-Wno-range-loop-analysis ...
13 changes: 12 additions & 1 deletion common/util/file_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,18 @@ absl::Status SetContents(absl::string_view filename,
}

std::string JoinPath(absl::string_view base, absl::string_view name) {
return absl::StrCat(base, "/", name);
// TODO: this will certainly be different on Windows
hzeller marked this conversation as resolved.
Show resolved Hide resolved
static constexpr absl::string_view kFileSeparator = "/";

// Make sure that we don't concatenate multiple superfluous separators.
// Note, since we're using string_view, the substr() operations are cheap.
while (!base.empty() && base[base.length() - 1] == kFileSeparator[0]) {
base = base.substr(0, base.length() - 1);
}
hzeller marked this conversation as resolved.
Show resolved Hide resolved
while (!name.empty() && name[0] == kFileSeparator[0]) {
name = name.substr(1);
}
return absl::StrCat(base, kFileSeparator, name);
}

absl::Status CreateDir(absl::string_view dir) {
Expand Down
69 changes: 69 additions & 0 deletions common/util/file_util_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <vector>

#include "absl/status/status.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
Expand All @@ -27,6 +28,8 @@ using testing::HasSubstr;

#undef EXPECT_OK
#define EXPECT_OK(value) EXPECT_TRUE((value).ok())
#undef ASSERT_OK
#define ASSERT_OK(value) ASSERT_TRUE((value).ok())

namespace verible {
namespace util {
Expand Down Expand Up @@ -61,6 +64,23 @@ TEST(FileUtil, Stem) {
EXPECT_EQ(file::Stem("/foo/bar"), "/foo/bar");
}

TEST(FileUtil, JoinPath) {
EXPECT_EQ(file::JoinPath("foo", ""), "foo/");
EXPECT_EQ(file::JoinPath("", "bar"), "/bar");
hzeller marked this conversation as resolved.
Show resolved Hide resolved
EXPECT_EQ(file::JoinPath("foo", "bar"), "foo/bar");

// Assemble an absolute path
EXPECT_EQ(file::JoinPath("", "bar"), "/bar");
EXPECT_EQ(file::JoinPath("/", "bar"), "/bar");
EXPECT_EQ(file::JoinPath("///", "///bar"), "/bar");

// Lightly canonicalize multiple consecutive slashes
EXPECT_EQ(file::JoinPath("foo/", "bar"), "foo/bar");
EXPECT_EQ(file::JoinPath("foo///", "bar"), "foo/bar");
EXPECT_EQ(file::JoinPath("foo/", "/bar"), "foo/bar");
EXPECT_EQ(file::JoinPath("foo/", "///bar"), "foo/bar");
}

TEST(FileUtil, CreateDir) {
const std::string test_dir = file::JoinPath(testing::TempDir(), "test_dir");
const std::string test_file = file::JoinPath(test_dir, "foo");
Expand Down Expand Up @@ -152,6 +172,55 @@ TEST(FileUtil, FileExistsDirectoryErrorMessage) {
EXPECT_THAT(s.message(), HasSubstr("is a directory"));
}

static bool CreateFsStructure(absl::string_view base_dir,
const std::vector<absl::string_view>& tree) {
for (absl::string_view path : tree) {
const std::string full_path = file::JoinPath(base_dir, path);
if (absl::EndsWith(path, "/")) {
if (!file::CreateDir(full_path).ok()) return false;
} else {
if (!file::SetContents(full_path, "(content)").ok()) return false;
}
}
return true;
}

TEST(FileUtil, UpwardFileSearchTest) {
const std::string root_dir = file::JoinPath(testing::TempDir(), "up-search");
ASSERT_OK(file::CreateDir(root_dir));
ASSERT_TRUE(CreateFsStructure(root_dir, {
"toplevel-file",
"foo/",
"foo/foo-file",
"foo/bar/",
"foo/bar/baz/",
"foo/bar/baz/baz-file",
}));
std::string result;
// Same directory
EXPECT_OK(file::UpwardFileSearch(file::JoinPath(root_dir, "foo"), "foo-file",
&result));
// We don't compare the full path, as the UpwardFileSearch() makes it an
// realpath which might not entirely match our root_dir prefix anymore; but
// we do know that the suffix should be the same.
EXPECT_TRUE(absl::EndsWith(result, "up-search/foo/foo-file"));

// Somewhere below
EXPECT_OK(file::UpwardFileSearch(file::JoinPath(root_dir, "foo/bar/baz"),
"foo-file", &result));
EXPECT_TRUE(absl::EndsWith(result, "up-search/foo/foo-file"));

// Find toplevel file
EXPECT_OK(file::UpwardFileSearch(file::JoinPath(root_dir, "foo/bar/baz"),
"toplevel-file", &result));
EXPECT_TRUE(absl::EndsWith(result, "up-search/toplevel-file"));

// Negative test.
auto status = file::UpwardFileSearch(file::JoinPath(root_dir, "foo/bar/baz"),
"unknownfile", &result);
EXPECT_FALSE(status.ok());
}

TEST(FileUtil, ReadEmptyDirectory) {
const std::string test_dir = file::JoinPath(testing::TempDir(), "empty_dir");
ASSERT_TRUE(file::CreateDir(test_dir).ok());
Expand Down