summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDominick Allen <djallen@librehumanitas.org>2024-10-27 09:04:05 -0500
committerDominick Allen <djallen@librehumanitas.org>2024-10-27 09:04:05 -0500
commitb8345246dcc2121bcb6d1515a9341789de20199f (patch)
tree4a25857512a90ff38e8a40166c54694b74920216 /test
parentf84b8259f6e980fed647d8e1ec0634f89ee59c06 (diff)
First crack at file objects.
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt5
-rw-r--r--test/test_common.cpp60
-rw-r--r--test/test_common.hpp13
-rw-r--r--test/test_directory.cpp45
-rw-r--r--test/test_file.cpp97
5 files changed, 170 insertions, 50 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 788e4ba..aef8052 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -13,12 +13,16 @@ endif()
set(gtest_URL https://github.com/google/googletest.git)
set(gtest_TAG v1.14.0)
+# Keep this setting above the FetchContent_Declare for googletest
+set(INSTALL_GTEST OFF CACHE BOOL "Enable installation of googletest.")
+
FetchContent_Declare(
googletest
GIT_REPOSITORY ${gtest_URL}
GIT_TAG ${gtest_TAG}
)
FetchContent_MakeAvailable(googletest)
+
include(GoogleTest)
enable_testing()
@@ -61,6 +65,7 @@ fud_add_test(test_allocator SOURCES test_allocator.cpp)
fud_add_test(test_assert SOURCES test_assert.cpp)
# fud_add_test(test_c_file SOURCES test_c_file.cpp)
fud_add_test(test_directory SOURCES test_directory.cpp)
+fud_add_test(test_file SOURCES test_file.cpp)
fud_add_test(test_format SOURCES test_format.cpp)
fud_add_test(test_option SOURCES test_option.cpp)
fud_add_test(test_result SOURCES test_result.cpp)
diff --git a/test/test_common.cpp b/test/test_common.cpp
index d3e1704..784cb0d 100644
--- a/test/test_common.cpp
+++ b/test/test_common.cpp
@@ -16,7 +16,12 @@
*/
#include "test_common.hpp"
+
+#include "fud_string.hpp"
+
#include <cstdlib>
+#include <ftw.h>
+#include <gtest/gtest.h>
namespace fud {
@@ -34,22 +39,69 @@ MockFudAlloc globalDefaultMockAlloc{};
MockFudDealloc globalDefaultMockDealloc{};
-void* MockFudAllocator::allocate(size_t size) {
+void* MockFudAllocator::allocate(size_t size)
+{
return (*m_allocator)(size);
}
-void MockFudAllocator::deallocate(void* pointer) {
+void MockFudAllocator::deallocate(void* pointer)
+{
return (*m_deallocator)(pointer);
}
MockFudAllocator globalMockFudAlloc{};
-void* fudAlloc(size_t size) {
+void* fudAlloc(size_t size)
+{
return globalMockFudAlloc.allocate(size);
}
-void fudFree(void* ptr) {
+void fudFree(void* ptr)
+{
return globalMockFudAlloc.deallocate(ptr);
}
+int unlink_cb(const char* fpath, const struct stat* sb_unused, int typeflag, struct FTW* ftwbuf)
+{
+ static_cast<void>(sb_unused);
+ int retValue = remove(fpath);
+
+ EXPECT_EQ(retValue, 0);
+ if (retValue != 0) {
+ perror(fpath);
+ }
+
+ return retValue;
+}
+
+FudStatus removeRecursive(const String& path)
+{
+ if (!path.utf8Valid()) {
+ return FudStatus::Utf8Invalid;
+ }
+ if (path.length() < 5) {
+ return FudStatus::ArgumentInvalid;
+ }
+ auto prefix{String::makeFromCString("/tmp/").takeOkay()};
+ auto diffResult = compareMem(path.data(), path.length(), prefix.data(), prefix.length());
+ if (diffResult.isError()) {
+ return FudStatus::ArgumentInvalid;
+ }
+ auto diff = diffResult.getOkay();
+ if (diff != 0) {
+ return FudStatus::ArgumentInvalid;
+ }
+ 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;
+}
+
} // namespace fud
diff --git a/test/test_common.hpp b/test/test_common.hpp
index f049fed..3d7ecba 100644
--- a/test/test_common.hpp
+++ b/test/test_common.hpp
@@ -18,9 +18,15 @@
#ifndef FUD_TEST_COMMON_HPP
#define FUD_TEST_COMMON_HPP
+#include "fud_status.hpp"
+
#include <cstddef>
#include <cstdlib>
+extern "C" {
+int unlink_cb(const char* fpath, const struct stat* sb_unused, int typeflag, struct FTW* ftwbuf);
+}
+
namespace fud {
// NOLINTBEGIN(cppcoreguidelines-macro-usage)
@@ -70,11 +76,14 @@ struct MockFudAllocator {
void deallocate(void* pointer);
MockFudAlloc* m_allocator{&globalDefaultMockAlloc};
- MockFudDealloc* m_deallocator{&globalDefaultMockDealloc};;
+ MockFudDealloc* m_deallocator{&globalDefaultMockDealloc};
};
extern MockFudAllocator globalMockFudAlloc;
-} // namespace ext_lib
+class String;
+FudStatus removeRecursive(const String& path);
+
+} // namespace fud
#endif
diff --git a/test/test_directory.cpp b/test/test_directory.cpp
index 2f69dab..e30dafb 100644
--- a/test/test_directory.cpp
+++ b/test/test_directory.cpp
@@ -18,8 +18,8 @@
#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>
@@ -30,49 +30,6 @@
namespace fud {
-int unlink_cb(const char* fpath, const struct stat* sb_unused, int typeflag, struct FTW* ftwbuf)
-{
- static_cast<void>(sb_unused);
- int retValue = remove(fpath);
-
- EXPECT_EQ(retValue, 0);
- if (retValue != 0) {
- perror(fpath);
- }
-
- return retValue;
-}
-
-FudStatus removeRecursive(const String& path)
-{
- if (!path.utf8Valid()) {
- return FudStatus::Utf8Invalid;
- }
- if (path.length() < 5) {
- return FudStatus::ArgumentInvalid;
- }
- auto prefix{String::makeFromCString("/tmp/").takeOkay()};
- auto diffResult = compareMem(path.data(), path.length(), prefix.data(), prefix.length());
- if (diffResult.isError()) {
- return FudStatus::ArgumentInvalid;
- }
- auto diff = diffResult.getOkay();
- if (diff != 0) {
- return FudStatus::ArgumentInvalid;
- }
- 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 auto testDirName{String::makeFromCString("/tmp/fud_directory_test").takeOkay()};
diff --git a/test/test_file.cpp b/test/test_file.cpp
new file mode 100644
index 0000000..06e6bcc
--- /dev/null
+++ b/test/test_file.cpp
@@ -0,0 +1,97 @@
+/*
+ * 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_file.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 {
+
+TEST(FudFile, Basic)
+{
+ constexpr const char* testDirCName = "/tmp/fud_directory_test";
+ const auto testDirName{String::makeFromCString(testDirCName).takeOkay()};
+ ASSERT_TRUE(testDirName.utf8Valid());
+ constexpr mode_t pathMode = 0777;
+
+ 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;
+ }
+
+ String testName1{String::makeFromCStrings(testDirCName, "/", "test1").takeOkay()};
+ String testName2{String::makeFromCStrings(testDirCName, "/", "test2").takeOkay()};
+
+ auto rmFile = [](const auto& filename) -> int {
+ auto result = unlink(filename.c_str());
+ if (result == -1) {
+ if (errno == ENOENT) {
+ return 0;
+ }
+ }
+ return result;
+ };
+ ASSERT_EQ(rmFile(testName1), 0);
+ ASSERT_EQ(rmFile(testName2), 0);
+
+ auto fileResult{RegularFile::open(testName1.asView(), FileAccessMode::Read, OpenFlags{}, NullOpt)};
+ EXPECT_EQ(fileResult.takeErrorOr(FudStatus::Success), FudStatus::NotFound);
+
+ /* The irony of the ability for TOCTOU bugs to be present in the test does
+ * not escape me. */
+
+ auto createFile = [](const auto& filename) -> int {
+ constexpr int allPerms = 0777;
+ auto handleResult = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, allPerms);
+ if (handleResult >= 0) {
+ close(handleResult);
+ }
+ return handleResult;
+ };
+ ASSERT_GE(createFile(testName1), 0);
+
+ fileResult = RegularFile::open(testName1.asView(), FileAccessMode::Read, OpenFlags{}, NullOpt);
+ ASSERT_TRUE(fileResult.isOkay());
+ auto file{fileResult.takeOkay()};
+ ASSERT_EQ(file.close(), FudStatus::Success);
+
+ ASSERT_EQ(rmFile(testName1), 0);
+ ASSERT_GE(createFile(testName2), 0);
+ ASSERT_EQ(symlink(testName2.c_str(), testName1.c_str()), 0);
+
+ fileResult = RegularFile::open(testName2.asView(), FileAccessMode::Read, OpenFlags{}, NullOpt);
+ ASSERT_TRUE(fileResult.isOkay());
+ file = fileResult.takeOkay();
+ ASSERT_EQ(file.close(), FudStatus::Success);
+
+ fileResult = RegularFile::open(testName1.asView(), FileAccessMode::Read, OpenFlags{}, NullOpt);
+ ASSERT_TRUE(fileResult.isError());
+ EXPECT_EQ(fileResult.getError(), FudStatus::Failure);
+}
+
+} // namespace fud