/* * 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 #include #include #include #include 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 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(), FudStatus::Success); Array data{"test"}; WriteResult expected{data.size(), FudStatus::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 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()); } auto finalDirEntryResult = directory.getNextEntry(); EXPECT_TRUE(finalDirEntryResult.isOkay()); EXPECT_EQ(finalDirEntryResult.getOkay(), std::nullopt); // ASSERT_EQ(removeRecursive(testDirName), FudStatus::Success); } } // namespace fud