353 lines
13 KiB
C++
353 lines
13 KiB
C++
/*
|
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License").
|
|
* You may not use this file except in compliance with the License.
|
|
* A copy of the License is located at
|
|
*
|
|
* http://aws.amazon.com/apache2.0/
|
|
*
|
|
* or in the "license" file accompanying this file. This file is distributed
|
|
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
|
|
* express or implied. See the License for the specific language governing
|
|
* permissions and limitations under the License.
|
|
*/
|
|
|
|
#if defined(FILE_SYSTEM_UTILS_ENABLED)
|
|
|
|
#include <climits>
|
|
#include <fstream>
|
|
#include <gtest/gtest.h>
|
|
|
|
#include "AVSCommon/Utils/FileSystem/FileSystemUtils.h"
|
|
|
|
namespace alexaClientSDK {
|
|
namespace avsCommon {
|
|
namespace utils {
|
|
namespace filesystem {
|
|
namespace test {
|
|
|
|
using namespace std;
|
|
using namespace ::testing;
|
|
|
|
class FileSystemUtilsTest : public ::testing::Test {
|
|
public:
|
|
void SetUp() override {
|
|
char dirName[L_tmpnam + 1]{};
|
|
ASSERT_NE(nullptr, tmpnam(dirName));
|
|
WORKING_DIR = dirName + string("_FileSystemUtilsTest/");
|
|
|
|
ASSERT_FALSE(exists(WORKING_DIR));
|
|
createDirectory(WORKING_DIR);
|
|
ASSERT_TRUE(exists(WORKING_DIR));
|
|
|
|
#if defined(__linux__) or defined(__APPLE__)
|
|
// on some OS, the temp path is symbolically linked, which can cause issues for prefix tests
|
|
// to accommodate this, get the realpath of the temp directory
|
|
char resolved_path[PATH_MAX + 1];
|
|
ASSERT_NE(nullptr, ::realpath(WORKING_DIR.c_str(), resolved_path));
|
|
WORKING_DIR = string(resolved_path);
|
|
ASSERT_TRUE(exists(WORKING_DIR));
|
|
#endif
|
|
|
|
ASSERT_FALSE(WORKING_DIR.empty());
|
|
if (*WORKING_DIR.rbegin() != '/') {
|
|
WORKING_DIR += "/";
|
|
}
|
|
}
|
|
|
|
void TearDown() override {
|
|
removeAll(WORKING_DIR);
|
|
ASSERT_FALSE(exists(WORKING_DIR));
|
|
}
|
|
|
|
static void createFile(const string& filePath, const string& content = "defaultContent") {
|
|
ofstream of(filePath);
|
|
ASSERT_TRUE(of.good());
|
|
of << content;
|
|
of.close();
|
|
ASSERT_TRUE(of.good());
|
|
}
|
|
|
|
static void createDirectory(const string& dirPath) {
|
|
makeDirectory(dirPath);
|
|
ASSERT_TRUE(exists(dirPath));
|
|
}
|
|
|
|
static string unifyDelimiter(string path) {
|
|
replace(path.begin(), path.end(), '\\', '/');
|
|
return path;
|
|
};
|
|
|
|
string WORKING_DIR;
|
|
};
|
|
|
|
TEST_F(FileSystemUtilsTest, testChangingFilePermissions) {
|
|
auto path = WORKING_DIR + "file.txt";
|
|
auto originalContent = "testing";
|
|
auto updatedContent = "updated_testing";
|
|
string content;
|
|
ifstream reader;
|
|
ofstream writer;
|
|
|
|
// setup test file with content
|
|
writer.open(path);
|
|
writer << originalContent;
|
|
writer.close();
|
|
ASSERT_TRUE(exists(path));
|
|
|
|
#ifndef _WIN32 // all files in windows are readable
|
|
// giving the file write only permission makes it impossible for us to read it
|
|
ASSERT_TRUE(changePermissions(path, OWNER_WRITE));
|
|
reader.open(path);
|
|
ASSERT_FALSE(reader.good());
|
|
#endif
|
|
|
|
// changing the permissions to read only will allow us then to read
|
|
ASSERT_TRUE(changePermissions(path, OWNER_READ));
|
|
reader.open(path);
|
|
ASSERT_TRUE(reader.good());
|
|
reader >> content;
|
|
ASSERT_EQ(content, originalContent);
|
|
reader.close();
|
|
|
|
// however, with read only permission, we cannot then write
|
|
writer.open(path);
|
|
ASSERT_FALSE(writer.good());
|
|
|
|
// finally, giving the file read/write permission allows us to both update it and read it again
|
|
ASSERT_TRUE(changePermissions(path, OWNER_WRITE | OWNER_READ));
|
|
writer.open(path);
|
|
ASSERT_TRUE(writer.good());
|
|
writer << updatedContent;
|
|
writer.close();
|
|
|
|
reader.open(path);
|
|
ASSERT_TRUE(reader.good());
|
|
reader >> content;
|
|
ASSERT_EQ(content, updatedContent);
|
|
reader.close();
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testExistsValidatesThatAFileOrDirectoryExists) { // NOLINT
|
|
auto file = WORKING_DIR + "file";
|
|
auto directory = WORKING_DIR + "directory";
|
|
|
|
ASSERT_FALSE(exists(file));
|
|
ASSERT_FALSE(exists(directory));
|
|
createFile(file);
|
|
createDirectory(directory);
|
|
ASSERT_TRUE(exists(file));
|
|
ASSERT_TRUE(exists(directory));
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testMovingFileToNewPath) { // NOLINT
|
|
auto directoryBefore = WORKING_DIR + "directory/";
|
|
auto directoryAfter = WORKING_DIR + "newDirectory/";
|
|
auto fileBefore = WORKING_DIR + "file";
|
|
auto fileAfter = directoryBefore + "newFileName";
|
|
|
|
createDirectory(directoryBefore);
|
|
createFile(fileBefore);
|
|
ASSERT_TRUE(exists(directoryBefore));
|
|
ASSERT_TRUE(exists(fileBefore));
|
|
|
|
ASSERT_TRUE(move(fileBefore, fileAfter));
|
|
ASSERT_FALSE(exists(fileBefore));
|
|
ASSERT_TRUE(exists(fileAfter));
|
|
|
|
ASSERT_TRUE(move(directoryBefore, directoryAfter));
|
|
ASSERT_FALSE(exists(directoryBefore));
|
|
ASSERT_TRUE(exists(directoryAfter));
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testCheckingDiskSpace) { // NOLINT
|
|
ASSERT_GT(availableSpace(WORKING_DIR), 0UL);
|
|
ASSERT_EQ(availableSpace("/some/non/existing/directory"), 0UL);
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testCheckingSizeOfFilesAndDirectory) { // NOLINT
|
|
auto subDirectory = WORKING_DIR + "directory/";
|
|
auto file1 = WORKING_DIR + "file1";
|
|
auto file2 = subDirectory + "file2";
|
|
string fileContent = "This is some text to fill into the file that's being created";
|
|
|
|
createDirectory(subDirectory);
|
|
createFile(file1, fileContent);
|
|
createFile(file2, fileContent);
|
|
ASSERT_EQ(sizeOf(file1), fileContent.size());
|
|
ASSERT_EQ(sizeOf(file2), fileContent.size());
|
|
ASSERT_EQ(sizeOf(WORKING_DIR), fileContent.size() * 2);
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testThatCurrentDirectoryExists) { // NOLINT
|
|
auto dir = currentDirectory();
|
|
ASSERT_FALSE(dir.empty());
|
|
ASSERT_TRUE(exists(dir));
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testMakeDirectory) { // NOLINT
|
|
Permissions mode = OWNER_WRITE | OWNER_READ | OWNER_EXEC;
|
|
auto simpleDirName = WORKING_DIR + "simple-dir-name";
|
|
auto recursiveCreate = WORKING_DIR + "first-directory/second-directory/third-directory";
|
|
auto repeatedSlash = WORKING_DIR + "before-double-slash//after-double-slash";
|
|
auto recursiveCreateWithSlashAtEnd = WORKING_DIR + "slash/at/the/end/";
|
|
auto filePath = WORKING_DIR + "file";
|
|
auto filePathFollowedByDir = WORKING_DIR + "file/some/dir";
|
|
createFile(filePath);
|
|
|
|
ASSERT_TRUE(makeDirectory(simpleDirName));
|
|
ASSERT_TRUE(exists(simpleDirName));
|
|
ASSERT_TRUE(makeDirectory(simpleDirName));
|
|
ASSERT_TRUE(makeDirectory(recursiveCreate, mode));
|
|
ASSERT_TRUE(exists(recursiveCreate));
|
|
ASSERT_TRUE(makeDirectory(repeatedSlash, mode));
|
|
ASSERT_TRUE(exists(repeatedSlash));
|
|
ASSERT_TRUE(makeDirectory(recursiveCreateWithSlashAtEnd, mode));
|
|
ASSERT_TRUE(exists(recursiveCreateWithSlashAtEnd));
|
|
ASSERT_FALSE(makeDirectory(filePath, mode));
|
|
ASSERT_FALSE(makeDirectory(filePathFollowedByDir, mode));
|
|
ASSERT_FALSE(makeDirectory(WORKING_DIR + "first-directory/../this-fails", mode));
|
|
ASSERT_FALSE(makeDirectory(WORKING_DIR + "first-directory/./this-fails", mode));
|
|
ASSERT_FALSE(makeDirectory(""));
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testPathContainsPrefix) { // NOLINT
|
|
auto prefix = WORKING_DIR + "davs";
|
|
createDirectory(prefix);
|
|
string good_path = prefix + "/valid_locale";
|
|
string ok_path = prefix + "/valid_locale/../still/valid";
|
|
string minimal_ok_path = prefix;
|
|
ASSERT_TRUE(pathContainsPrefix(good_path, prefix));
|
|
ASSERT_TRUE(pathContainsPrefix(ok_path, prefix));
|
|
ASSERT_TRUE(pathContainsPrefix(minimal_ok_path, prefix));
|
|
|
|
string sneaky_bad_path = prefix + "/../../system/bin";
|
|
string flagrant_bad_path = "/system/bin";
|
|
string invalid_bad_path = "&*$)#%^*(";
|
|
ASSERT_FALSE(pathContainsPrefix(sneaky_bad_path, prefix));
|
|
ASSERT_FALSE(pathContainsPrefix(flagrant_bad_path, prefix));
|
|
ASSERT_FALSE(pathContainsPrefix(invalid_bad_path, prefix));
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testFileBasename) { // NOLINT
|
|
EXPECT_EQ(basenameOf("/tmp/file.txt"), "file.txt");
|
|
EXPECT_EQ(basenameOf("/tmp/directory"), "directory");
|
|
EXPECT_EQ(basenameOf("/tmp/directory/"), "directory");
|
|
EXPECT_EQ(basenameOf("/tmp/directory//"), "directory");
|
|
EXPECT_EQ(basenameOf("/tmp"), "tmp");
|
|
EXPECT_EQ(basenameOf("tmp/"), "tmp");
|
|
EXPECT_EQ(basenameOf("tmp"), "tmp");
|
|
EXPECT_EQ(basenameOf("tmp///"), "tmp");
|
|
EXPECT_EQ(basenameOf("/t"), "t");
|
|
EXPECT_EQ(basenameOf("t/"), "t");
|
|
EXPECT_EQ(basenameOf("/"), "");
|
|
EXPECT_EQ(basenameOf("////"), "");
|
|
EXPECT_EQ(basenameOf("/some/.."), "..");
|
|
EXPECT_EQ(basenameOf("/some/."), ".");
|
|
EXPECT_EQ(basenameOf(".."), "..");
|
|
EXPECT_EQ(basenameOf("."), ".");
|
|
EXPECT_EQ(basenameOf(""), "");
|
|
|
|
#ifdef _WIN32
|
|
// Windows is able to accept '\\' as well as '/' delimiters
|
|
EXPECT_EQ(basenameOf("\\tmp\\directory\\"), "directory");
|
|
EXPECT_EQ(basenameOf("C:\\tmp\\directory"), "directory");
|
|
#endif
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testPathDirname) { // NOLINT
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/tmp/file.txt")), "/tmp/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/tmp/directory")), "/tmp/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/tmp/directory/")), "/tmp/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/tmp/directory//")), "/tmp/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/tmp")), "/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("tmp/")), "./");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("tmp")), "./");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("tmp///")), "./");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/t")), "/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("t/")), "./");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/")), "/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("////")), "/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/some/..")), "/some/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("/some/.")), "/some/");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("..")), "./");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf(".")), "./");
|
|
EXPECT_EQ(unifyDelimiter(parentDirNameOf("")), "./");
|
|
|
|
#ifdef _WIN32
|
|
// Windows is able to accept '\\' as well as '/' delimiters
|
|
EXPECT_EQ(parentDirNameOf("C:\\tmp/path"), "C:\\tmp\\");
|
|
EXPECT_EQ(parentDirNameOf("C:/tmp/path"), "C:\\tmp\\");
|
|
EXPECT_EQ(parentDirNameOf("C:/"), "C:\\");
|
|
EXPECT_EQ(parentDirNameOf("C:"), "C:\\");
|
|
#endif
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testListOfDifferentKinds) { // NOLINT
|
|
string file1 = "file1";
|
|
string file2 = "file2";
|
|
string dir1 = "dir1";
|
|
string dir2 = "dir2";
|
|
string link = "link";
|
|
createFile(WORKING_DIR + file1);
|
|
createFile(WORKING_DIR + file2);
|
|
createDirectory(WORKING_DIR + dir1);
|
|
createDirectory(WORKING_DIR + dir2);
|
|
|
|
auto files = list(WORKING_DIR, FileType::REGULAR_FILE);
|
|
auto directories = list(WORKING_DIR, FileType::DIRECTORY);
|
|
auto all = list(WORKING_DIR, FileType::ALL);
|
|
auto def = list(WORKING_DIR);
|
|
|
|
ASSERT_EQ(all, def);
|
|
ASSERT_EQ(all.size(), 4UL);
|
|
ASSERT_EQ(files.size(), 2UL);
|
|
ASSERT_EQ(directories.size(), 2UL);
|
|
|
|
ASSERT_TRUE(find(all.begin(), all.end(), file1) != all.end());
|
|
ASSERT_TRUE(find(all.begin(), all.end(), file2) != all.end());
|
|
ASSERT_TRUE(find(all.begin(), all.end(), dir1) != all.end());
|
|
ASSERT_TRUE(find(all.begin(), all.end(), dir2) != all.end());
|
|
|
|
ASSERT_TRUE(find(files.begin(), files.end(), file1) != files.end());
|
|
ASSERT_TRUE(find(files.begin(), files.end(), file2) != files.end());
|
|
|
|
ASSERT_TRUE(find(directories.begin(), directories.end(), dir1) != directories.end());
|
|
ASSERT_TRUE(find(directories.begin(), directories.end(), dir2) != directories.end());
|
|
}
|
|
|
|
TEST_F(FileSystemUtilsTest, testRemoveAllFilesAndOrDirectories) { // NOLINT
|
|
string file = "file.txt";
|
|
string directory = "dir";
|
|
string fullDirectory = "fulldir";
|
|
|
|
createFile(WORKING_DIR + file);
|
|
createDirectory(WORKING_DIR + directory);
|
|
createDirectory(WORKING_DIR + fullDirectory + "/" + fullDirectory + "/" + fullDirectory);
|
|
createFile(WORKING_DIR + fullDirectory + "/" + fullDirectory + "/" + file);
|
|
createFile(WORKING_DIR + fullDirectory + "/" + file);
|
|
|
|
ASSERT_TRUE(exists(WORKING_DIR + file));
|
|
ASSERT_TRUE(removeAll(WORKING_DIR + file));
|
|
ASSERT_FALSE(exists(WORKING_DIR + file));
|
|
|
|
ASSERT_TRUE(exists(WORKING_DIR + directory));
|
|
ASSERT_TRUE(removeAll(WORKING_DIR + directory));
|
|
ASSERT_FALSE(exists(WORKING_DIR + directory));
|
|
|
|
ASSERT_TRUE(exists(WORKING_DIR + fullDirectory));
|
|
ASSERT_TRUE(removeAll(WORKING_DIR + fullDirectory));
|
|
ASSERT_FALSE(exists(WORKING_DIR + fullDirectory));
|
|
|
|
ASSERT_TRUE(removeAll(WORKING_DIR + file));
|
|
ASSERT_FALSE(exists(WORKING_DIR + file));
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace filesystem
|
|
} // namespace utils
|
|
} // namespace avsCommon
|
|
} // namespace alexaClientSDK
|
|
|
|
#endif // FILE_SYSTEM_UTILS_ENABLED
|