mirror of
https://github.com/transmission/transmission
synced 2025-03-04 10:38:13 +00:00
test: improve file-win32, file-posix test coverage (#3761)
This commit is contained in:
parent
339b9580cf
commit
ae74a13eb1
5 changed files with 253 additions and 242 deletions
|
@ -116,29 +116,6 @@ static void set_system_error_if_file_found(tr_error** error, int code)
|
|||
}
|
||||
}
|
||||
|
||||
static constexpr auto stat_to_sys_path_info(struct stat const& sb)
|
||||
{
|
||||
auto info = tr_sys_path_info{};
|
||||
|
||||
if (S_ISREG(sb.st_mode))
|
||||
{
|
||||
info.type = TR_SYS_PATH_IS_FILE;
|
||||
}
|
||||
else if (S_ISDIR(sb.st_mode))
|
||||
{
|
||||
info.type = TR_SYS_PATH_IS_DIRECTORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.type = TR_SYS_PATH_IS_OTHER;
|
||||
}
|
||||
|
||||
info.size = static_cast<uint64_t>(sb.st_size);
|
||||
info.last_modified_at = sb.st_mtime;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static void set_file_for_single_pass(tr_sys_file_t handle)
|
||||
{
|
||||
/* Set hints about the lookahead buffer and caching. It's okay
|
||||
|
@ -167,126 +144,6 @@ static void set_file_for_single_pass(tr_sys_file_t handle)
|
|||
errno = err;
|
||||
}
|
||||
|
||||
#ifndef HAVE_MKDIRP
|
||||
|
||||
static bool create_path_require_dir(char const* path, tr_error** error)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (stat(path, &sb) == -1)
|
||||
{
|
||||
set_system_error(error, errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((sb.st_mode & S_IFMT) != S_IFDIR)
|
||||
{
|
||||
tr_error_set(error, ENOTDIR, fmt::format(FMT_STRING("File is in the way: {:s}"), path));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool create_path(char const* path_in, int permissions, tr_error** error)
|
||||
{
|
||||
/* make a temporary copy of path */
|
||||
auto path = tr_pathbuf{ path_in };
|
||||
|
||||
/* walk past the root */
|
||||
char* p = std::data(path);
|
||||
|
||||
while (*p == TR_PATH_DELIMITER)
|
||||
{
|
||||
++p;
|
||||
}
|
||||
|
||||
char* path_end = p + strlen(p);
|
||||
|
||||
while (path_end > path && *path_end == TR_PATH_DELIMITER)
|
||||
{
|
||||
--path_end;
|
||||
}
|
||||
|
||||
char* pp = nullptr;
|
||||
bool ret = false;
|
||||
tr_error* my_error = nullptr;
|
||||
|
||||
/* Go one level up on each iteration and attempt to create */
|
||||
for (pp = path_end; pp != nullptr; pp = strrchr(p, TR_PATH_DELIMITER))
|
||||
{
|
||||
*pp = '\0';
|
||||
|
||||
ret = mkdir(path, permissions) != -1;
|
||||
|
||||
if (ret)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == EEXIST)
|
||||
{
|
||||
ret = create_path_require_dir(path, &my_error);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
goto FAILURE;
|
||||
}
|
||||
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
set_system_error(&my_error, errno);
|
||||
goto FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret && pp == path_end)
|
||||
{
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
/* Go one level down on each iteration and attempt to create */
|
||||
for (pp = pp == nullptr ? p + strlen(p) : pp; pp < path_end; pp += strlen(pp))
|
||||
{
|
||||
*pp = TR_PATH_DELIMITER;
|
||||
|
||||
if (mkdir(path, permissions) == -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = create_path_require_dir(path, &my_error);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
FAILURE:
|
||||
|
||||
TR_ASSERT(!ret);
|
||||
TR_ASSERT(my_error != nullptr);
|
||||
|
||||
tr_logAddError(fmt::format(
|
||||
_("Couldn't create '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", path),
|
||||
fmt::arg("error", my_error->message),
|
||||
fmt::arg("error_code", my_error->code)));
|
||||
tr_error_propagate(error, &my_error);
|
||||
|
||||
CLEANUP:
|
||||
|
||||
TR_ASSERT(my_error == nullptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool tr_sys_path_exists(char const* path, tr_error** error)
|
||||
{
|
||||
TR_ASSERT(path != nullptr);
|
||||
|
@ -317,13 +174,31 @@ std::optional<tr_sys_path_info> tr_sys_path_get_info(std::string_view path, int
|
|||
ok = lstat(szpath, &sb) != -1;
|
||||
}
|
||||
|
||||
if (ok)
|
||||
if (!ok)
|
||||
{
|
||||
return stat_to_sys_path_info(sb);
|
||||
set_system_error(error, errno);
|
||||
return {};
|
||||
}
|
||||
|
||||
set_system_error(error, errno);
|
||||
return {};
|
||||
auto info = tr_sys_path_info{};
|
||||
|
||||
if (S_ISREG(sb.st_mode))
|
||||
{
|
||||
info.type = TR_SYS_PATH_IS_FILE;
|
||||
}
|
||||
else if (S_ISDIR(sb.st_mode))
|
||||
{
|
||||
info.type = TR_SYS_PATH_IS_DIRECTORY;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.type = TR_SYS_PATH_IS_OTHER;
|
||||
}
|
||||
|
||||
info.size = static_cast<uint64_t>(sb.st_size);
|
||||
info.last_modified_at = sb.st_mtime;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
bool tr_sys_path_is_relative(std::string_view path)
|
||||
|
@ -459,6 +334,13 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err
|
|||
|
||||
#else /* USE_COPYFILE */
|
||||
|
||||
auto const info = tr_sys_path_get_info(src_path, 0, error);
|
||||
if (!info)
|
||||
{
|
||||
tr_error_prefix(error, "Unable to get information on source file: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Other OSes require us to copy between file descriptors, so open them. */
|
||||
tr_sys_file_t const in = tr_sys_file_open(src_path, TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, error);
|
||||
if (in == TR_BAD_SYS_FILE)
|
||||
|
@ -467,14 +349,6 @@ bool tr_sys_path_copy(char const* src_path, char const* dst_path, tr_error** err
|
|||
return false;
|
||||
}
|
||||
|
||||
auto const info = tr_sys_file_get_info(in, error);
|
||||
if (!info)
|
||||
{
|
||||
tr_error_prefix(error, "Unable to get information on source file: ");
|
||||
tr_sys_file_close(in);
|
||||
return false;
|
||||
}
|
||||
|
||||
tr_sys_file_t const out = tr_sys_file_open(
|
||||
dst_path,
|
||||
TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE | TR_SYS_FILE_TRUNCATE,
|
||||
|
@ -685,19 +559,6 @@ bool tr_sys_file_close(tr_sys_file_t handle, tr_error** error)
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::optional<tr_sys_path_info> tr_sys_file_get_info(tr_sys_file_t handle, tr_error** error)
|
||||
{
|
||||
TR_ASSERT(handle != TR_BAD_SYS_FILE);
|
||||
|
||||
if (struct stat sb; fstat(handle, &sb) != -1)
|
||||
{
|
||||
return stat_to_sys_path_info(sb);
|
||||
}
|
||||
|
||||
set_system_error(error, errno);
|
||||
return {};
|
||||
}
|
||||
|
||||
bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, tr_error** error)
|
||||
{
|
||||
TR_ASSERT(handle != TR_BAD_SYS_FILE);
|
||||
|
@ -1143,6 +1004,40 @@ std::string tr_sys_dir_get_current(tr_error** error)
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef HAVE_MKDIRP
|
||||
|
||||
static bool tr_mkdirp_(std::string_view path, int permissions, tr_error** error)
|
||||
{
|
||||
auto walk = path.find_first_not_of('/'); // walk past the root
|
||||
auto subpath = tr_pathbuf{};
|
||||
|
||||
while (walk < std::size(path))
|
||||
{
|
||||
auto const end = path.find('/', walk);
|
||||
subpath.assign(path.substr(0, end));
|
||||
auto const info = tr_sys_path_get_info(subpath, 0);
|
||||
if (info && !info->isFolder())
|
||||
{
|
||||
tr_error_set(error, ENOTDIR, fmt::format(FMT_STRING("File is in the way: {:s}"), path));
|
||||
return false;
|
||||
}
|
||||
if (!info && mkdir(subpath, permissions) == -1)
|
||||
{
|
||||
set_system_error(error, errno);
|
||||
return false;
|
||||
}
|
||||
if (end == std::string_view::npos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
walk = end + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error** error)
|
||||
{
|
||||
TR_ASSERT(path != nullptr);
|
||||
|
@ -1155,7 +1050,7 @@ bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error**
|
|||
#ifdef HAVE_MKDIRP
|
||||
ret = mkdirp(path, permissions) != -1;
|
||||
#else
|
||||
ret = create_path(path, permissions, &my_error);
|
||||
ret = tr_mkdirp_(path, permissions, &my_error);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -1165,9 +1060,7 @@ bool tr_sys_dir_create(char const* path, int flags, int permissions, tr_error**
|
|||
|
||||
if (!ret && errno == EEXIST)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (stat(path, &sb) != -1 && S_ISDIR(sb.st_mode))
|
||||
if (auto const info = tr_sys_path_get_info(path); info && info->type == TR_SYS_PATH_IS_DIRECTORY)
|
||||
{
|
||||
tr_error_clear(&my_error);
|
||||
ret = true;
|
||||
|
|
|
@ -255,6 +255,12 @@ static bool create_dir(std::string_view path, int flags, int /*permissions*/, bo
|
|||
DWORD error_code = ERROR_SUCCESS;
|
||||
auto const wide_path = path_to_native_path(path);
|
||||
|
||||
// already exists (no-op)
|
||||
if (auto const info = tr_sys_path_get_info(path); info && info->isFolder())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((flags & TR_SYS_DIR_CREATE_PARENTS) != 0)
|
||||
{
|
||||
error_code = SHCreateDirectoryExW(nullptr, wide_path.c_str(), nullptr);
|
||||
|
@ -375,6 +381,24 @@ bool tr_sys_path_exists(char const* path, tr_error** error)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static std::optional<tr_sys_path_info> tr_sys_file_get_info_(tr_sys_file_t handle, tr_error** error)
|
||||
{
|
||||
TR_ASSERT(handle != TR_BAD_SYS_FILE);
|
||||
|
||||
auto attributes = BY_HANDLE_FILE_INFORMATION{};
|
||||
if (GetFileInformationByHandle(handle, &attributes))
|
||||
{
|
||||
return stat_to_sys_path_info(
|
||||
attributes.dwFileAttributes,
|
||||
attributes.nFileSizeLow,
|
||||
attributes.nFileSizeHigh,
|
||||
attributes.ftLastWriteTime);
|
||||
}
|
||||
|
||||
set_system_error(error, GetLastError());
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<tr_sys_path_info> tr_sys_path_get_info(std::string_view path, int flags, tr_error** error)
|
||||
{
|
||||
if (auto const wide_path = path_to_native_path(path); std::empty(wide_path))
|
||||
|
@ -397,7 +421,7 @@ std::optional<tr_sys_path_info> tr_sys_path_get_info(std::string_view path, int
|
|||
handle = CreateFileW(wide_path.c_str(), 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
auto ret = tr_sys_file_get_info(handle, error);
|
||||
auto ret = tr_sys_file_get_info_(handle, error);
|
||||
CloseHandle(handle);
|
||||
return ret;
|
||||
}
|
||||
|
@ -929,24 +953,6 @@ bool tr_sys_file_close(tr_sys_file_t handle, tr_error** error)
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::optional<tr_sys_path_info> tr_sys_file_get_info(tr_sys_file_t handle, tr_error** error)
|
||||
{
|
||||
TR_ASSERT(handle != TR_BAD_SYS_FILE);
|
||||
|
||||
auto attributes = BY_HANDLE_FILE_INFORMATION{};
|
||||
if (GetFileInformationByHandle(handle, &attributes))
|
||||
{
|
||||
return stat_to_sys_path_info(
|
||||
attributes.dwFileAttributes,
|
||||
attributes.nFileSizeLow,
|
||||
attributes.nFileSizeHigh,
|
||||
attributes.ftLastWriteTime);
|
||||
}
|
||||
|
||||
set_system_error(error, GetLastError());
|
||||
return {};
|
||||
}
|
||||
|
||||
bool tr_sys_file_read(tr_sys_file_t handle, void* buffer, uint64_t size, uint64_t* bytes_read, tr_error** error)
|
||||
{
|
||||
TR_ASSERT(handle != TR_BAD_SYS_FILE);
|
||||
|
@ -1248,16 +1254,17 @@ tr_sys_dir_t tr_sys_dir_open(char const* path, tr_error** error)
|
|||
{
|
||||
TR_ASSERT(path != nullptr);
|
||||
|
||||
#ifndef __clang__
|
||||
/* Clang gives "static_assert expression is not an integral constant expression" error */
|
||||
static_assert(TR_BAD_SYS_DIR == nullptr, "values should match");
|
||||
#endif
|
||||
if (auto const info = tr_sys_path_get_info(path, 0); !info || !info->isFolder())
|
||||
{
|
||||
set_system_error(error, ERROR_DIRECTORY);
|
||||
return TR_BAD_SYS_DIR;
|
||||
}
|
||||
|
||||
auto pattern = path_to_native_path(path);
|
||||
if (std::empty(pattern))
|
||||
{
|
||||
set_system_error(error, GetLastError());
|
||||
return nullptr;
|
||||
return TR_BAD_SYS_DIR;
|
||||
}
|
||||
|
||||
auto* const ret = new tr_sys_dir_win32{};
|
||||
|
|
|
@ -362,17 +362,6 @@ tr_sys_file_t tr_sys_file_open_temp(char* path_template, struct tr_error** error
|
|||
*/
|
||||
bool tr_sys_file_close(tr_sys_file_t handle, struct tr_error** error = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Portability wrapper for `fstat()`.
|
||||
*
|
||||
* @param[in] handle Valid file descriptor.
|
||||
* @param[out] error Pointer to error object. Optional, pass `nullptr` if you
|
||||
* are not interested in error details.
|
||||
*
|
||||
* @return info on success, or nullopt with `error` set accordingly.
|
||||
*/
|
||||
[[nodiscard]] std::optional<tr_sys_path_info> tr_sys_file_get_info(tr_sys_file_t handle, struct tr_error** error = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Portability wrapper for `read()`.
|
||||
*
|
||||
|
|
|
@ -235,17 +235,6 @@ TEST_F(FileTest, getInfo)
|
|||
EXPECT_GE(info->last_modified_at, t - 1);
|
||||
EXPECT_LE(info->last_modified_at, time(nullptr) + 1);
|
||||
|
||||
// Good file info (by handle)
|
||||
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0);
|
||||
info = tr_sys_file_get_info(fd, &err);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
EXPECT_EQ(TR_SYS_PATH_IS_FILE, info->type);
|
||||
EXPECT_EQ(4, info->size);
|
||||
EXPECT_GE(info->last_modified_at, t - 1);
|
||||
EXPECT_LE(info->last_modified_at, time(nullptr) + 1);
|
||||
tr_sys_file_close(fd);
|
||||
|
||||
tr_sys_path_remove(path1);
|
||||
|
||||
// Good directory info
|
||||
|
@ -280,16 +269,11 @@ TEST_F(FileTest, getInfo)
|
|||
EXPECT_GE(info->last_modified_at, t - 1);
|
||||
EXPECT_LE(info->last_modified_at, time(nullptr) + 1);
|
||||
|
||||
// Good file info (by handle)
|
||||
fd = tr_sys_file_open(path1, TR_SYS_FILE_READ, 0);
|
||||
info = tr_sys_file_get_info(fd, &err);
|
||||
// Symlink
|
||||
info = tr_sys_path_get_info(path1, TR_SYS_PATH_NO_FOLLOW, &err);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
EXPECT_EQ(TR_SYS_PATH_IS_FILE, info->type);
|
||||
EXPECT_EQ(4, info->size);
|
||||
EXPECT_GE(info->last_modified_at, t - 1);
|
||||
EXPECT_LE(info->last_modified_at, time(nullptr) + 1);
|
||||
tr_sys_file_close(fd);
|
||||
EXPECT_EQ(TR_SYS_PATH_IS_OTHER, info->type);
|
||||
|
||||
tr_sys_path_remove(path2);
|
||||
tr_sys_path_remove(path1);
|
||||
|
@ -315,6 +299,50 @@ TEST_F(FileTest, getInfo)
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(FileTest, readFile)
|
||||
{
|
||||
auto const test_dir = createTestDir(currentTestName());
|
||||
|
||||
auto const path = tr_pathbuf{ test_dir, "/a.txt"sv };
|
||||
auto constexpr Contents = "hello, world!"sv;
|
||||
createFileWithContents(path, Contents);
|
||||
|
||||
auto n_bytes_read = uint64_t{};
|
||||
tr_error* err = nullptr;
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto fd = tr_sys_file_open(path, TR_SYS_FILE_READ, 0);
|
||||
EXPECT_NE(TR_BAD_SYS_FILE, fd);
|
||||
|
||||
// successful read
|
||||
EXPECT_TRUE(tr_sys_file_read(fd, std::data(buf), std::size(buf), &n_bytes_read, &err));
|
||||
EXPECT_EQ(Contents, std::string_view(std::data(buf), n_bytes_read));
|
||||
EXPECT_EQ(std::size(Contents), n_bytes_read);
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
|
||||
// successful read_at
|
||||
auto const offset = 1U;
|
||||
EXPECT_TRUE(tr_sys_file_read_at(fd, std::data(buf), std::size(buf), offset, &n_bytes_read, &err));
|
||||
auto constexpr Expected = Contents.substr(offset);
|
||||
EXPECT_EQ(Expected, std::string_view(std::data(buf), n_bytes_read));
|
||||
EXPECT_EQ(std::size(Expected), n_bytes_read);
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
|
||||
tr_sys_file_close(fd);
|
||||
|
||||
// read from closed file
|
||||
n_bytes_read = 0;
|
||||
EXPECT_FALSE(tr_sys_file_read(fd, std::data(buf), std::size(buf), &n_bytes_read, &err));
|
||||
EXPECT_EQ(0, n_bytes_read);
|
||||
EXPECT_NE(nullptr, err);
|
||||
tr_error_clear(&err);
|
||||
|
||||
// read_at from closed file
|
||||
EXPECT_FALSE(tr_sys_file_read_at(fd, std::data(buf), std::size(buf), offset, &n_bytes_read, &err));
|
||||
EXPECT_EQ(0, n_bytes_read);
|
||||
EXPECT_NE(nullptr, err);
|
||||
tr_error_clear(&err);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, pathExists)
|
||||
{
|
||||
auto const test_dir = createTestDir(currentTestName());
|
||||
|
@ -1019,6 +1047,40 @@ TEST_F(FileTest, pathNativeSeparators)
|
|||
}
|
||||
}
|
||||
|
||||
TEST_F(FileTest, fileCopy)
|
||||
{
|
||||
auto const test_dir = createTestDir(currentTestName());
|
||||
|
||||
auto const path1 = tr_pathbuf{ test_dir, "/a.txt" };
|
||||
auto const path2 = tr_pathbuf{ test_dir, "/b.txt" };
|
||||
auto constexpr Contents = "hello, world!"sv;
|
||||
|
||||
// no source file
|
||||
tr_error* err = nullptr;
|
||||
EXPECT_FALSE(tr_sys_path_copy(path1, path2, &err));
|
||||
EXPECT_NE(nullptr, err);
|
||||
tr_error_clear(&err);
|
||||
|
||||
createFileWithContents(path1, Contents);
|
||||
|
||||
// source file exists but is inaccessible
|
||||
chmod(path1, 0);
|
||||
EXPECT_FALSE(tr_sys_path_copy(path1, test_dir, &err));
|
||||
EXPECT_NE(nullptr, err);
|
||||
tr_error_clear(&err);
|
||||
chmod(path1, 0600);
|
||||
|
||||
// source file exists but target is invalid
|
||||
EXPECT_FALSE(tr_sys_path_copy(path1, test_dir, &err));
|
||||
EXPECT_NE(nullptr, err);
|
||||
tr_error_clear(&err);
|
||||
|
||||
// source and target are valid
|
||||
createFileWithContents(path1, Contents);
|
||||
EXPECT_TRUE(tr_sys_path_copy(path1, path2, &err));
|
||||
EXPECT_EQ(nullptr, err);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, fileOpen)
|
||||
{
|
||||
auto const test_dir = createTestDir(currentTestName());
|
||||
|
@ -1089,7 +1151,7 @@ TEST_F(FileTest, fileOpen)
|
|||
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_TRUNCATE, 0600, &err);
|
||||
EXPECT_NE(TR_BAD_SYS_FILE, fd);
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
info = tr_sys_file_get_info(fd);
|
||||
info = tr_sys_path_get_info(path1);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(0U, info->size);
|
||||
tr_sys_file_close(fd);
|
||||
|
@ -1106,25 +1168,25 @@ TEST_F(FileTest, fileTruncate)
|
|||
{
|
||||
auto const test_dir = createTestDir(currentTestName());
|
||||
|
||||
auto const path1 = tr_pathbuf{ test_dir, "/a"sv };
|
||||
auto fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
||||
auto const path = tr_pathbuf{ test_dir, "/a"sv };
|
||||
auto fd = tr_sys_file_open(path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
||||
|
||||
tr_error* err = nullptr;
|
||||
EXPECT_TRUE(tr_sys_file_truncate(fd, 10, &err));
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
auto info = tr_sys_file_get_info(fd);
|
||||
auto info = tr_sys_path_get_info(path);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(10U, info->size);
|
||||
|
||||
EXPECT_TRUE(tr_sys_file_truncate(fd, 20, &err));
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
info = tr_sys_file_get_info(fd);
|
||||
info = tr_sys_path_get_info(path);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(20U, info->size);
|
||||
|
||||
EXPECT_TRUE(tr_sys_file_truncate(fd, 0, &err));
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
info = tr_sys_file_get_info(fd);
|
||||
info = tr_sys_path_get_info(path);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(0U, info->size);
|
||||
|
||||
|
@ -1133,22 +1195,27 @@ TEST_F(FileTest, fileTruncate)
|
|||
|
||||
tr_sys_file_close(fd);
|
||||
|
||||
info = tr_sys_path_get_info(path1);
|
||||
info = tr_sys_path_get_info(path);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(50U, info->size);
|
||||
|
||||
fd = tr_sys_file_open(path1, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
||||
fd = tr_sys_file_open(path, TR_SYS_FILE_WRITE | TR_SYS_FILE_CREATE, 0600);
|
||||
|
||||
EXPECT_TRUE(tr_sys_file_truncate(fd, 25, &err));
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
|
||||
tr_sys_file_close(fd);
|
||||
|
||||
info = tr_sys_path_get_info(path1);
|
||||
info = tr_sys_path_get_info(path);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(25U, info->size);
|
||||
|
||||
tr_sys_path_remove(path1);
|
||||
// try to truncate a closed file
|
||||
EXPECT_FALSE(tr_sys_file_truncate(fd, 10, &err));
|
||||
EXPECT_NE(nullptr, err);
|
||||
tr_error_clear(&err);
|
||||
|
||||
tr_sys_path_remove(path);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, filePreallocate)
|
||||
|
@ -1163,7 +1230,7 @@ TEST_F(FileTest, filePreallocate)
|
|||
if (tr_sys_file_preallocate(fd, prealloc_size, 0, &err))
|
||||
{
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
auto info = tr_sys_file_get_info(fd);
|
||||
auto info = tr_sys_path_get_info(path1);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(prealloc_size, info->size);
|
||||
}
|
||||
|
@ -1184,7 +1251,7 @@ TEST_F(FileTest, filePreallocate)
|
|||
if (tr_sys_file_preallocate(fd, prealloc_size, TR_SYS_FILE_PREALLOC_SPARSE, &err))
|
||||
{
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
auto info = tr_sys_file_get_info(fd);
|
||||
auto info = tr_sys_path_get_info(path1);
|
||||
EXPECT_TRUE(info);
|
||||
EXPECT_EQ(prealloc_size, info->size);
|
||||
}
|
||||
|
@ -1251,6 +1318,22 @@ TEST_F(FileTest, dirCreate)
|
|||
tr_sys_path_remove(path1);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, dirCreateTemp)
|
||||
{
|
||||
auto const test_dir = createTestDir(currentTestName());
|
||||
|
||||
tr_error* err = nullptr;
|
||||
auto path = tr_pathbuf{ test_dir, "/test-XXXXXX" };
|
||||
EXPECT_TRUE(tr_sys_dir_create_temp(std::data(path), &err));
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
tr_sys_path_remove(path);
|
||||
|
||||
path.assign(test_dir, "/path-does-not-exist/test-XXXXXX");
|
||||
EXPECT_FALSE(tr_sys_dir_create_temp(std::data(path), &err));
|
||||
EXPECT_NE(nullptr, err);
|
||||
tr_error_clear(&err);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, dirRead)
|
||||
{
|
||||
auto const test_dir = createTestDir(currentTestName());
|
||||
|
@ -1280,6 +1363,42 @@ TEST_F(FileTest, dirRead)
|
|||
EXPECT_TRUE(have2);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, dirOpen)
|
||||
{
|
||||
auto const test_dir = createTestDir(currentTestName());
|
||||
|
||||
auto const file = tr_pathbuf{ test_dir, "/foo.fxt" };
|
||||
auto constexpr Contents = "hello, world!"sv;
|
||||
createFileWithContents(file, std::data(Contents), std::size(Contents));
|
||||
|
||||
// path does not exist
|
||||
tr_error* err = nullptr;
|
||||
auto odir = tr_sys_dir_open("/no/such/path", &err);
|
||||
EXPECT_EQ(TR_BAD_SYS_DIR, odir);
|
||||
EXPECT_NE(err, nullptr);
|
||||
tr_error_clear(&err);
|
||||
|
||||
// path is not a directory
|
||||
odir = tr_sys_dir_open(file, &err);
|
||||
EXPECT_EQ(TR_BAD_SYS_DIR, odir);
|
||||
EXPECT_NE(err, nullptr);
|
||||
tr_error_clear(&err);
|
||||
|
||||
// path exists and is readable
|
||||
odir = tr_sys_dir_open(test_dir);
|
||||
EXPECT_NE(TR_BAD_SYS_DIR, odir);
|
||||
auto files = std::set<std::string>{};
|
||||
char const* filename = nullptr;
|
||||
while ((filename = tr_sys_dir_read_name(odir, &err)))
|
||||
{
|
||||
files.insert(filename);
|
||||
}
|
||||
EXPECT_EQ(3U, files.size());
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
EXPECT_TRUE(tr_sys_dir_close(odir, &err));
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace libtransmission
|
||||
|
|
|
@ -127,7 +127,6 @@ protected:
|
|||
auto path = tr_sys_dir_get_current(&error);
|
||||
if (error != nullptr)
|
||||
{
|
||||
std::cerr << "tr_sys_dir_get_current error: '" << error->message << "'" << std::endl;
|
||||
tr_error_free(error);
|
||||
}
|
||||
return path;
|
||||
|
@ -184,9 +183,13 @@ protected:
|
|||
|
||||
auto dir = tr_pathbuf{ path };
|
||||
dir.popdir();
|
||||
tr_error* error = nullptr;
|
||||
tr_sys_dir_create(dir, TR_SYS_DIR_CREATE_PARENTS, 0700, &error);
|
||||
EXPECT_EQ(nullptr, error) << "path[" << path << "] dir[" << dir << "] " << *error;
|
||||
if (auto const info = tr_sys_path_get_info(path); !info)
|
||||
{
|
||||
tr_error* error = nullptr;
|
||||
tr_sys_dir_create(dir, TR_SYS_DIR_CREATE_PARENTS, 0700, &error);
|
||||
EXPECT_EQ(nullptr, error) << "path[" << path << "] dir[" << dir << "] " << *error;
|
||||
tr_error_clear(&error);
|
||||
}
|
||||
|
||||
errno = tmperr;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue