summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominick Allen <djallen@librehumanitas.org>2024-09-28 00:23:22 -0500
committerDominick Allen <djallen@librehumanitas.org>2024-09-28 00:23:22 -0500
commit07d30629d78474ed810cad73ead71db96079aff0 (patch)
tree5f43fd8f6a818a590818e0c474f03a1f05076dba
parent63711877057f1f89b4d1774e24fe20907a3af656 (diff)
Add directory interface.
-rw-r--r--CMakeLists.txt2
-rw-r--r--include/fud_c_file.hpp37
-rw-r--r--include/fud_directory.hpp87
-rw-r--r--include/fud_string.hpp8
-rw-r--r--source/fud_c_file.cpp65
-rw-r--r--source/fud_directory.cpp192
-rw-r--r--source/fud_string.cpp38
-rw-r--r--test/CMakeLists.txt1
-rw-r--r--test/test_directory.cpp147
9 files changed, 565 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 348cd36..df61f24 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,7 @@ add_library(fud SHARED
source/fud_utf8.cpp
source/fud_utf8_iterator.cpp
source/fud_sqlite.cpp
+ source/fud_directory.cpp
)
include(cmake/warnings.cmake)
@@ -96,6 +97,7 @@ set(FUD_HEADERS
"include/fud_utf8.hpp"
"include/fud_utf8_iterator.hpp"
"include/fud_sqlite"
+ "include/fud_directory.hpp"
)
set_target_properties(fud PROPERTIES PUBLIC_HEADER "${FUD_HEADERS}")
diff --git a/include/fud_c_file.hpp b/include/fud_c_file.hpp
index f563a35..674130c 100644
--- a/include/fud_c_file.hpp
+++ b/include/fud_c_file.hpp
@@ -18,8 +18,8 @@
#ifndef FUD_C_FILE_HPP
#define FUD_C_FILE_HPP
-#include "fud_string.hpp"
#include "fud_result.hpp"
+#include "fud_string.hpp"
#include <cstdint>
#include <cstdio>
@@ -88,7 +88,8 @@ enum class FileStatus
Error,
};
-static inline const char* FileStatusToString(FileStatus status) {
+static inline const char* FileStatusToString(FileStatus status)
+{
switch (status) {
case FileStatus::Success:
return "Success";
@@ -114,6 +115,11 @@ struct [[nodiscard]] ReadResult {
FileStatus status{FileStatus::Success};
};
+struct [[nodiscard]] WriteResult {
+ size_t bytesWritten{0};
+ FileStatus status{FileStatus::Success};
+};
+
class CBinaryFile {
public:
CBinaryFile(const String& filename, CFileMode mode);
@@ -146,6 +152,32 @@ class CBinaryFile {
return read(&destination, sizeof(destination), length, offset);
}
+ [[nodiscard]] WriteResult write(const void* source, size_t sourceSize, size_t length);
+
+ [[nodiscard]] WriteResult write(const void* source, size_t sourceSize, size_t length, size_t offset);
+
+ template <typename T>
+ [[nodiscard]] WriteResult write(const T& source)
+ {
+ return write(source, sizeof(source), sizeof(source));
+ }
+
+ template <typename T>
+ [[nodiscard]] WriteResult write(const T& source, size_t sourceSize, size_t length)
+ {
+ auto offsetResult = size();
+ if (offsetResult.isError()) {
+ return WriteResult{0, offsetResult.getError()};
+ }
+ return write(source, sourceSize, length, offsetResult.getOkay());
+ }
+
+ template <typename T>
+ [[nodiscard]] WriteResult write(const T& source, size_t sourceSize, size_t length, size_t offset)
+ {
+ return write(static_cast<const void*>(&source), sourceSize, length, offset);
+ }
+
private:
FileStatus reset() const;
@@ -158,5 +190,4 @@ class CBinaryFile {
} // namespace fud
-
#endif
diff --git a/include/fud_directory.hpp b/include/fud_directory.hpp
new file mode 100644
index 0000000..ac48b7b
--- /dev/null
+++ b/include/fud_directory.hpp
@@ -0,0 +1,87 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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.
+ */
+
+#ifndef FUD_DIRECTORY_HPP
+#define FUD_DIRECTORY_HPP
+
+#include "fud_result.hpp"
+#include "fud_status.hpp"
+#include "fud_string.hpp"
+
+#include <cstdint>
+#include <cstdio>
+#include <dirent.h>
+#include <optional>
+#include <ctime>
+
+namespace fud {
+
+enum class DirectoryEntryType : uint8_t
+{
+ Block,
+ Character,
+ Directory,
+ NamedPipe,
+ SymbolicLink,
+ RegularFile,
+ UnixSocket,
+ Unknown
+};
+
+/** \brief Simplified Directory Entry */
+struct DirectoryEntry {
+ String name;
+ size_t size;
+ size_t links;
+ time_t modificationTime;
+ DirectoryEntryType entryType;
+};
+
+class Directory {
+ public:
+ explicit Directory(String name);
+ Directory(const Directory& rhs) = delete;
+ Directory(Directory&& rhs);
+ ~Directory();
+ Directory& operator=(const Directory& rhs) = delete;
+ Directory& operator=(Directory&& rhs);
+
+ constexpr FudStatus status() const
+ {
+ return m_status;
+ }
+
+ constexpr int errorCode() const
+ {
+ return m_errorCode;
+ }
+
+ Result<std::optional<DirectoryEntry>, FudStatus> getNextEntry();
+
+ FudStatus reset();
+
+ private:
+ String m_name{};
+ DIR* m_directory{nullptr};
+ FudStatus m_status{FudStatus::ObjectInvalid};
+ int m_errorCode{-1};
+ int m_dirFd{-1};
+};
+
+} // namespace fud
+
+#endif
diff --git a/include/fud_string.hpp b/include/fud_string.hpp
index 97b7036..9e423ef 100644
--- a/include/fud_string.hpp
+++ b/include/fud_string.hpp
@@ -113,9 +113,13 @@ class String {
std::optional<utf8> pop();
- [[nodiscard]] FudStatus catenate(StringView source);
+ [[nodiscard]] FudStatus append(StringView source);
- [[nodiscard]] String append(const String& rhs) const;
+ [[nodiscard]] String catenate(const String& rhs) const;
+
+ [[nodiscard]] String catenate(const char* rhs) const;
+
+ [[nodiscard]] bool compare(const String& rhs) const;
const utf8* begin() const;
diff --git a/source/fud_c_file.cpp b/source/fud_c_file.cpp
index a85fd00..cad4c9d 100644
--- a/source/fud_c_file.cpp
+++ b/source/fud_c_file.cpp
@@ -29,7 +29,7 @@ CBinaryFile::CBinaryFile(const String& filename, CFileMode mode)
CBinaryFile::CBinaryFile(const String& filename, CFileMode mode, const String& extraFlags)
: m_filename{filename},
m_extraFlags{extraFlags},
- m_mode{String(CBinaryFileModeFromFlags(mode)).append(extraFlags)},
+ m_mode{String(CBinaryFileModeFromFlags(mode)).catenate(extraFlags)},
m_modeFlags{mode}
{
}
@@ -137,8 +137,8 @@ ReadResult CBinaryFile::read(void* destination, size_t destinationSize, size_t l
return result;
}
- auto* destPtr = static_cast<char*>(destination);
- result.bytesRead = fread(destPtr, 1, length, m_file);
+ auto* destBytes = static_cast<char*>(destination);
+ result.bytesRead = fread(destBytes, 1, length, m_file);
static_cast<void>(reset());
if (result.bytesRead != length) {
result.status = FileStatus::PartialSuccess;
@@ -149,6 +149,65 @@ ReadResult CBinaryFile::read(void* destination, size_t destinationSize, size_t l
return result;
}
+WriteResult CBinaryFile::write(const void* source, size_t sourceSize, size_t length)
+{
+ auto offsetResult = size();
+ if (offsetResult.isError()) {
+ return WriteResult{0, offsetResult.getError()};
+ }
+
+ return write(source, sourceSize, length, offsetResult.getOkay());
+}
+
+WriteResult CBinaryFile::write(const void* source, size_t sourceSize, size_t length, size_t offset)
+{
+ WriteResult result{};
+ if (length == 0) {
+ return result;
+ }
+
+ if (source == nullptr) {
+ result.status = FileStatus::NullPointer;
+ return result;
+ }
+
+ if (offset > LONG_MAX || SIZE_MAX - offset < length || sourceSize < length) {
+ result.status = FileStatus::InvalidArgument;
+ return result;
+ }
+
+ auto fileSizeResult = size();
+ if (fileSizeResult.isError()) {
+ result.status = fileSizeResult.getError();
+ return result;
+ }
+
+ // TODO: proper way of handling this
+ auto fileSize = fileSizeResult.getOkay();
+ int seekResult;
+ if (offset > fileSize) {
+ seekResult = fseek(m_file, 0, SEEK_END);
+ } else {
+ seekResult = fseek(m_file, static_cast<long>(offset), SEEK_SET);
+ }
+
+ if (seekResult != 0) {
+ result.status = FileStatus::Error;
+ return result;
+ }
+
+ auto* sourceBytes = static_cast<const char*>(source);
+ result.bytesWritten = fwrite(sourceBytes, 1, length, m_file);
+ static_cast<void>(reset());
+ if (result.bytesWritten != length) {
+ result.status = FileStatus::PartialSuccess;
+ } else {
+ result.status = FileStatus::Success;
+ }
+
+ return result;
+}
+
FileStatus CBinaryFile::reset() const {
if (!isOpen()) {
return FileStatus::InvalidState;
diff --git a/source/fud_directory.cpp b/source/fud_directory.cpp
new file mode 100644
index 0000000..39f2e10
--- /dev/null
+++ b/source/fud_directory.cpp
@@ -0,0 +1,192 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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.
+ */
+
+#include "fud_directory.hpp"
+
+#include <cerrno>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+namespace fud {
+
+Directory::Directory(String name) : m_name{name}
+{
+ if (!m_name.valid()) {
+ return;
+ }
+
+ if (!m_name.utf8Valid()) {
+ m_status = FudStatus::Utf8Invalid;
+ return;
+ }
+
+ m_directory = opendir(m_name.c_str());
+ if (m_directory == nullptr) {
+ m_status = FudStatus::Failure;
+ m_errorCode = errno;
+ return;
+ }
+
+ m_dirFd = dirfd(m_directory);
+ if (m_dirFd == -1) {
+ m_status = FudStatus::Failure;
+ m_errorCode = errno;
+ closedir(m_directory);
+ m_directory = nullptr;
+ return;
+ }
+
+ m_errorCode = 0;
+ m_status = FudStatus::Success;
+}
+
+Directory::Directory(Directory&& rhs) :
+ m_name{std::move(rhs.m_name)}, m_directory{rhs.m_directory}, m_dirFd{rhs.m_dirFd}
+{
+ rhs.m_directory = nullptr;
+ rhs.m_dirFd = -1;
+}
+
+Directory& Directory::operator=(Directory&& rhs)
+{
+ m_name = std::move(rhs.m_name);
+ m_directory = rhs.m_directory;
+ m_dirFd = rhs.m_dirFd;
+
+ rhs.m_directory = nullptr;
+ rhs.m_dirFd = -1;
+
+ return *this;
+}
+
+Directory::~Directory()
+{
+ if (m_directory != nullptr) {
+ closedir(m_directory);
+ m_directory = nullptr;
+ }
+}
+
+Result<std::optional<DirectoryEntry>, FudStatus> Directory::getNextEntry()
+{
+ using RetType = Result<std::optional<DirectoryEntry>, FudStatus>;
+
+ if (m_directory == nullptr || m_dirFd == -1) {
+ m_status = FudStatus::ObjectInvalid;
+ return RetType::error(m_status);
+ }
+
+ errno = 0;
+ auto* dirEntry = readdir(m_directory);
+ if (dirEntry == nullptr) {
+ if (errno != 0) {
+ m_errorCode = errno;
+ m_status = FudStatus::Failure;
+ return RetType::error(m_status);
+ } else {
+ return RetType::okay(std::nullopt);
+ }
+ }
+
+ const char* entryName = dirEntry->d_name;
+ if (entryName == nullptr) {
+ m_errorCode = -1;
+ m_status = FudStatus::NullPointer;
+ return RetType::error(m_status);
+ }
+
+ m_errorCode = 0;
+
+ using Stat = struct stat;
+ Stat statBuffer{};
+ auto flags = 0;
+ auto status = fstatat(m_dirFd, entryName, &statBuffer, flags);
+ if (status == -1) {
+ m_errorCode = errno;
+ m_status = FudStatus::Failure;
+ return RetType::error(m_status);
+ }
+
+ DirectoryEntryType entryType;
+ switch (statBuffer.st_mode & S_IFMT) {
+ case S_IFBLK:
+ entryType = DirectoryEntryType::Block;
+ break;
+ case S_IFCHR:
+ entryType = DirectoryEntryType::Character;
+ break;
+ case S_IFDIR:
+ entryType = DirectoryEntryType::Directory;
+ break;
+ case S_IFIFO:
+ entryType = DirectoryEntryType::NamedPipe;
+ break;
+ case S_IFLNK:
+ entryType = DirectoryEntryType::SymbolicLink;
+ break;
+ case S_IFREG:
+ entryType = DirectoryEntryType::RegularFile;
+ break;
+ case S_IFSOCK:
+ entryType = DirectoryEntryType::UnixSocket;
+ break;
+ default:
+ entryType = DirectoryEntryType::Unknown;
+ break;
+ }
+
+ static_assert(std::is_same_v<decltype(statBuffer.st_size), long>);
+ static_assert(sizeof(decltype(statBuffer.st_size)) <= sizeof(size_t));
+
+ size_t size{0};
+ if (statBuffer.st_size < 0) {
+ size = SIZE_MAX;
+ } else {
+ size = static_cast<size_t>(statBuffer.st_size);
+ }
+
+ static_assert(std::is_same_v<decltype(statBuffer.st_nlink), unsigned long>);
+ static_assert(sizeof(decltype(statBuffer.st_nlink)) <= sizeof(size_t));
+
+ DirectoryEntry entry{
+ String{dirEntry->d_name},
+ size,
+ static_cast<size_t>(statBuffer.st_nlink),
+ statBuffer.st_mtime,
+ entryType};
+
+ if (!entry.name.valid()) {
+ m_status = FudStatus::StringInvalid;
+ return RetType::error(m_status);
+ }
+
+ m_status = FudStatus::Success;
+ return RetType::okay(std::move(entry));
+}
+
+FudStatus Directory::reset()
+{
+ if (m_directory != nullptr) {
+ rewinddir(m_directory);
+ } else {
+ m_status = FudStatus::ObjectInvalid;
+ return m_status;
+ }
+ return FudStatus::NotImplemented;
+}
+
+} // namespace fud
diff --git a/source/fud_string.cpp b/source/fud_string.cpp
index 74742e1..52d6b8f 100644
--- a/source/fud_string.cpp
+++ b/source/fud_string.cpp
@@ -236,7 +236,7 @@ FudStatus String::pushBack(const FudUtf8& letter)
return FudStatus::Success;
}
-FudStatus String::catenate(StringView source)
+FudStatus String::append(StringView source)
{
if (!valid()) {
return FudStatus::StringInvalid;
@@ -262,13 +262,19 @@ FudStatus String::catenate(StringView source)
return status;
}
-String String::append(const String& rhs) const
+String String::catenate(const char* rhs) const
+{
+ String rhsString{rhs};
+ return catenate(rhsString);
+}
+
+String String::catenate(const String& rhs) const
{
String output{};
output.m_length = 1;
output.m_capacity = 0;
- if (!valid()) {
+ if (!valid() || !rhs.valid()) {
return output;
}
@@ -279,7 +285,9 @@ String String::append(const String& rhs) const
}
auto* destPtr = output.data();
- auto status = copyMem(destPtr, m_capacity, rhs.data(), rhs.length());
+ auto status = copyMem(destPtr, m_capacity, data(), length());
+ fudAssert(status == FudStatus::Success);
+ status = copyMem(destPtr + length(), m_capacity, rhs.data(), rhs.length());
fudAssert(status == FudStatus::Success);
static_cast<void>(status);
fudAssert(output.nullTerminate() == FudStatus::Success);
@@ -287,6 +295,28 @@ String String::append(const String& rhs) const
return output;
}
+bool String::compare(const String& rhs) const {
+ if (!valid() || !rhs.valid()) {
+ return false;
+ }
+
+ if (length() != rhs.length()) {
+ return false;
+ }
+
+ if (isLarge() && data() == rhs.data())
+ {
+ return true;
+ }
+
+ auto diffResult = compareMem(data(), length(), rhs.data(), rhs.length());
+ if (diffResult.isError()) {
+ return false;
+ }
+
+ return diffResult.getOkay() == 0;
+}
+
const utf8* String::begin() const
{
return data();
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 73968fe..9061d55 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -54,6 +54,7 @@ endfunction()
fud_add_test(test_result SOURCES test_result.cpp)
fud_add_test(test_string SOURCES test_string.cpp)
fud_add_test(test_sqlite SOURCES test_sqlite.cpp)
+fud_add_test(test_directory SOURCES test_directory.cpp)
# fud_add_test(test_deserialize_number SOURCES test_deserialize_number.cpp)
# fud_add_test(test_ext_algorithm SOURCES test_algorithm.cpp)
# fud_add_test(test_ext_array SOURCES
diff --git a/test/test_directory.cpp b/test/test_directory.cpp
new file mode 100644
index 0000000..9cec80d
--- /dev/null
+++ b/test/test_directory.cpp
@@ -0,0 +1,147 @@
+/*
+ * libfud
+ * Copyright 2024 Dominick Allen
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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.
+ */
+
+#include "fud_array.hpp"
+#include "fud_c_file.hpp"
+#include "fud_directory.hpp"
+#include "fud_memory.hpp"
+#include "fud_string.hpp"
+#include "test_common.hpp"
+
+#include "gtest/gtest.h"
+#include <algorithm>
+#include <cerrno>
+#include <fcntl.h>
+#include <ftw.h>
+#include <ranges>
+
+namespace fud {
+
+int unlink_cb(const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf)
+{
+ int retValue = remove(fpath);
+
+ EXPECT_EQ(retValue, 0);
+ if (retValue) {
+ perror(fpath);
+ }
+
+ return retValue;
+}
+
+FudStatus removeRecursive(const String& path)
+{
+ if (!path.utf8Valid()) {
+ return FudStatus::Utf8Invalid;
+ }
+ if (path.length() < 5) {
+ return FudStatus::InvalidInput;
+ }
+ const String prefix{"/tmp/"};
+ auto diffResult = compareMem(path.data(), path.length(), prefix.data(), prefix.length());
+ if (diffResult.isError()) {
+ return FudStatus::InvalidInput;
+ }
+ auto diff = diffResult.getOkay();
+ if (diff != 0) {
+ return FudStatus::InvalidInput;
+ }
+ constexpr int maxOpenFd = 64;
+ auto status = nftw(path.c_str(), unlink_cb, maxOpenFd, FTW_DEPTH | FTW_PHYS);
+ if (status == 0) {
+ return FudStatus::Success;
+ }
+
+ if (errno == ENOENT) {
+ return FudStatus::Success;
+ }
+
+ return FudStatus::Failure;
+}
+
+TEST(FudDirectory, Basic)
+{
+ const String testDirName{"/tmp/fud_directory_test"};
+ ASSERT_TRUE(testDirName.utf8Valid());
+ constexpr mode_t pathMode = 0777;
+ const Array<String, 2> files{
+ String{"file1"},
+ String{"file2"},
+ };
+ ASSERT_TRUE(files[0].utf8Valid());
+ ASSERT_TRUE(files[1].utf8Valid());
+
+ ASSERT_EQ(removeRecursive(testDirName), FudStatus::Success);
+
+ auto mkdirResult = mkdir(testDirName.c_str(), pathMode);
+ EXPECT_EQ(mkdirResult, 0);
+ if (mkdirResult != 0) {
+ ASSERT_EQ(removeRecursive(testDirName), FudStatus::Success);
+ return;
+ }
+
+ const String testDirNamePrefix = testDirName.catenate("/");
+ ASSERT_TRUE(testDirNamePrefix.utf8Valid());
+ for (const auto& fnameBase : files) {
+ const auto fname = testDirNamePrefix.catenate(fnameBase);
+ ASSERT_TRUE(fname.utf8Valid());
+ CBinaryFile file{fname, CFileMode::ReadWriteTruncate};
+ ASSERT_EQ(file.open(), FileStatus::Success);
+ Array<utf8, 5> data{"test"};
+ WriteResult expected{data.size(), FileStatus::Success};
+ auto writeResult = file.write(data);
+ ASSERT_EQ(writeResult.bytesWritten, expected.bytesWritten);
+ ASSERT_EQ(writeResult.status, expected.status);
+ }
+
+ Directory directory{testDirName};
+ ASSERT_EQ(directory.status(), FudStatus::Success);
+ ASSERT_EQ(directory.errorCode(), 0);
+
+ const Array<DirectoryEntry, 4> expectedFiles{
+ DirectoryEntry{String{"."}, 0, 2, 0, DirectoryEntryType::Directory},
+ DirectoryEntry{String{".."}, 0, 1, 0, DirectoryEntryType::Directory},
+ DirectoryEntry{files[0], files[0].size(), 1, 0, DirectoryEntryType::RegularFile},
+ DirectoryEntry{files[1], files[1].size(), 1, 0, DirectoryEntryType::RegularFile},
+ };
+ ASSERT_TRUE(expectedFiles[0].name.compare(expectedFiles[0].name));
+
+ for (auto idx = 0; idx < expectedFiles.size(); ++idx) {
+ auto dirEntryResult = directory.getNextEntry();
+ EXPECT_TRUE(dirEntryResult.isOkay());
+ const auto dirEntryOpt = dirEntryResult.getOkay();
+ if (dirEntryOpt == std::nullopt) {
+ break;
+ }
+ const auto dirEntry = *dirEntryOpt;
+ const auto expected = std::find_if(
+ expectedFiles.begin(),
+ expectedFiles.end(),
+ [&dirEntry](const DirectoryEntry& entry) { return entry.name.compare(dirEntry.name) && entry.entryType == dirEntry.entryType; });
+ EXPECT_NE(expected, nullptr);
+ EXPECT_NE(expected, expectedFiles.end());
+ printf("%s %u\n", dirEntry.name.c_str(), static_cast<uint8_t>(dirEntry.entryType));
+ }
+
+ auto finalDirEntryResult = directory.getNextEntry();
+ EXPECT_TRUE(finalDirEntryResult.isOkay());
+ EXPECT_EQ(finalDirEntryResult.getOkay(), std::nullopt);
+
+ // ASSERT_EQ(removeRecursive(testDirName), FudStatus::Success);
+}
+
+} // namespace fud