Skip to content

Commit

Permalink
add read and write file validators #249
Browse files Browse the repository at this point in the history
Signed-off-by: Rafi Wiener <rafiw@mellanox.com>
  • Loading branch information
Rafi Wiener committed Mar 18, 2019
1 parent be8a08f commit 8402e14
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 3 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ CLI11 has several Validators built in that perform some common checks
- `CLI::Transformer(...)`: 🚧 Modify the input using a map. See [Transforming Validators](#transforming-validators) for more details.
- `CLI::CheckedTransformer(...)`: 🚧 Modify the input using a map, and Require that the input is either in the set or already one of the outputs of the set. See [Transforming Validators](#transforming-validators) for more details.
- `CLI::ExistingFile`: Requires that the file exists if given.
- `CLI::ExistingReadFile`: Requires that the file given exists and have permission to read it.
- `CLI::ExistingWriteFile`: Requires that the file given exists and have permission to write to it.
- `CLI::ExistingDirectory`: Requires that the directory exists.
- `CLI::ExistingPath`: Requires that the path (file or directory) exists.
- `CLI::NonexistentPath`: Requires that the path does not exist.
Expand Down
2 changes: 1 addition & 1 deletion examples/validators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ int main(int argc, char **argv) {
CLI::App app("Validator checker");

std::string file;
app.add_option("-f,--file,file", file, "File name")->check(CLI::ExistingFile);
app.add_option("-f,--file,file", file, "File name")->check(CLI::ExistingReadableFile);

int count;
app.add_option("-v,--value", count, "Value in range")->check(CLI::Range(3, 6));
Expand Down
13 changes: 11 additions & 2 deletions include/CLI/Validators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ namespace detail {
/// Check for an existing file (returns error message if check fails)
class ExistingFileValidator : public Validator {
public:
ExistingFileValidator() : Validator("FILE") {
func_ = [](std::string &filename) {
ExistingFileValidator(unsigned short mode = 0) : Validator("FILE") {
func_ = [mode](std::string &filename) {
struct stat buffer;
bool exist = stat(filename.c_str(), &buffer) == 0;
bool is_dir = (buffer.st_mode & S_IFDIR) != 0;
Expand All @@ -226,6 +226,9 @@ class ExistingFileValidator : public Validator {
} else if(is_dir) {
return "File is actually a directory: " + filename;
}
if(mode && !(buffer.st_mode & mode)) {
return "File doesn't have the wanted permission: " + filename;
}
return std::string();
};
}
Expand Down Expand Up @@ -328,6 +331,12 @@ class PositiveNumber : public Validator {
/// Check for existing file (returns error message if check fails)
const detail::ExistingFileValidator ExistingFile;

/// Check that the file exist and available for read
const detail::ExistingFileValidator ExistingReadableFile(S_IREAD);

/// Check that the file exist and available for write
const detail::ExistingFileValidator ExistingWritableFile(S_IWRITE);

/// Check for an existing directory (returns error message if check fails)
const detail::ExistingDirectoryValidator ExistingDirectory;

Expand Down
45 changes: 45 additions & 0 deletions tests/AppTest.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "app_helper.hpp"
#include <complex>
#include <cstdlib>
#include <sys/stat.h>

#include "gmock/gmock.h"

Expand Down Expand Up @@ -1466,6 +1467,50 @@ TEST_F(TApp, FileExists) {
EXPECT_FALSE(CLI::ExistingFile(myfile).empty());
}

TEST_F(TApp, FileExistsForRead) {
std::string myfile{"TestNonFileNotUsed.txt"};
EXPECT_FALSE(CLI::ExistingReadableFile(myfile).empty());

bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);

std::string filename = "Failed";
app.add_option("--file", filename)->check(CLI::ExistingReadableFile);
args = {"--file", myfile};

run();

EXPECT_EQ(myfile, filename);
#ifdef __linux__
my_chmod(myfile.c_str(), 0);
EXPECT_THROW(run(), CLI::ValidationError);
#endif
std::remove(myfile.c_str());
EXPECT_FALSE(CLI::ExistingFile(myfile).empty());
}

TEST_F(TApp, FileExistsForWrite) {
std::string myfile{"TestNonFileNotUsed.txt"};
EXPECT_FALSE(CLI::ExistingWritableFile(myfile).empty());

bool ok = static_cast<bool>(std::ofstream(myfile.c_str()).put('a')); // create file
EXPECT_TRUE(ok);

std::string filename = "Failed";
app.add_option("--file", filename)->check(CLI::ExistingWritableFile);
args = {"--file", myfile};

run();
EXPECT_EQ(myfile, filename);

my_chmod(myfile.c_str(), S_IREAD);
EXPECT_THROW(run(), CLI::ValidationError);

int ret = std::remove(myfile.c_str());
EXPECT_EQ(ret, 0);
EXPECT_FALSE(CLI::ExistingFile(myfile).empty());
}

TEST_F(TApp, NotFileExists) {
std::string myfile{"TestNonFileNotUsed.txt"};
EXPECT_FALSE(CLI::ExistingFile(myfile).empty());
Expand Down
9 changes: 9 additions & 0 deletions tests/app_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "gtest/gtest.h"
#include <iostream>
#include <sys/stat.h>

typedef std::vector<std::string> input_t;

Expand Down Expand Up @@ -55,3 +56,11 @@ inline void unset_env(std::string name) {
unsetenv(name.c_str());
#endif
}

inline int my_chmod(const char *path, int mode) {
#ifdef _WIN32
return _chmod(path, mode);
#else
return chmod(path, mode);
#endif
}

0 comments on commit 8402e14

Please sign in to comment.