#include #include #include #include #include #include #include #include "CodeDweller/filesystem.hpp" //////////////////////////////////////////////////////////////////////////////// // Configuration /////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// Test directory name. const std::string testDirName("testDir"); /// Test file name. const std::string testFileName("testFile.txt"); //////////////////////////////////////////////////////////////////////////////// // End of configuration //////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// int nTotalTests = 0; int nPass = 0; int nFail = 0; bool result; #define NO_EXCEPTION_TERM(msg) \ std::cout \ << msg << " failed to throw exception at line " \ << __LINE__ << "." << std::endl #define EXCEPTION_TERM(msg) \ std::cout \ << msg << " threw unexpected exception: " << e.what() << std::endl #define RETURN_FALSE(msg) \ std::cout \ << msg << " at line " << __LINE__ << std::endl; \ return false; #define RUN_TEST(test) \ std::cout << " " #test ": "; \ std::cout.flush(); \ result = test(); \ std::cout << (result ? "ok" : "fail") << std::endl; \ nTotalTests++; \ if (result) nPass++; else nFail++; #define SUMMARY \ std::cout \ << "\nPass: " << nPass \ << ", Fail: " << nFail \ << ", Total: " << nTotalTests << std::endl //////////////////////////////////////////////////////////////////////////////// // Tests /////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// bool testFileOpsMoveFile() { std::string fromName = "from.txt"; std::string toName = "to.txt"; std::string const expectedContent = "fileContentForMoveTest"; std::string content; // Test nominal case. std::ofstream out(fromName.c_str()); out << expectedContent; out.close(); CodeDweller::FileOps::moveFile(fromName, toName); std::ifstream in(toName.c_str()); in >> content; in.close(); if (expectedContent != content) { RETURN_FALSE("FileOps::moveFile() failure"); } // Test moving to a file that exists. out.open(fromName.c_str()); out << expectedContent; out.close(); out.open(toName.c_str()); out << "not" + expectedContent; out.close(); CodeDweller::FileOps::moveFile(fromName, toName); in.open(toName.c_str()); in >> content; in.close(); if (expectedContent != content) { RETURN_FALSE("FileOps::moveFile() failure"); } // Test moving file that doesn't exist. try { (void) CodeDweller::FileOps::moveFile("doesNotExist", "alsoDoesNotExist"); NO_EXCEPTION_TERM("FileOps::moveFile()"); return false; } catch (std::exception &e) { } return true; } bool testFilePathIsAbsolute() { char const dirSep = CodeDweller::FilePath::DirectorySeparator; std::string testPath; // Test absolute paths. testPath = dirSep; testPath += "filename"; if (!CodeDweller::FilePath::isAbsolute(testPath)) { RETURN_FALSE("isAbsolute() failure"); } testPath += dirSep; testPath += "pathcomponent"; if (!CodeDweller::FilePath::isAbsolute(testPath)) { RETURN_FALSE("isAbsolute() failure"); } testPath += dirSep; if (!CodeDweller::FilePath::isAbsolute(testPath)) { RETURN_FALSE("isAbsolute() failure"); } #ifdef _WIN32 if (!CodeDweller::FilePath::isAbsolute("x:sll")) { RETURN_FALSE("isAbsolute() failure"); } if (!CodeDweller::FilePath::isAbsolute("x:\\sll")) { RETURN_FALSE("isAbsolute() failure"); } if (!CodeDweller::FilePath::isAbsolute("x:\\sll\\")) { RETURN_FALSE("isAbsolute() failure"); } if (!CodeDweller::FilePath::isAbsolute("x:\\sll\\lll")) { RETURN_FALSE("isAbsolute() failure"); } if (!CodeDweller::FilePath::isAbsolute("\\sll")) { RETURN_FALSE("isAbsolute() failure"); } if (!CodeDweller::FilePath::isAbsolute("\\sll\\")) { RETURN_FALSE("isAbsolute() failure"); } if (!CodeDweller::FilePath::isAbsolute("\\sll\\lll")) { RETURN_FALSE("isAbsolute() failure"); } #endif // Test relative paths. if (CodeDweller::FilePath::isAbsolute("")) { RETURN_FALSE("isAbsolute() failure"); } testPath = "Hello"; if (CodeDweller::FilePath::isAbsolute(testPath)) { RETURN_FALSE("isAbsolute() failure"); } testPath = "Hello"; testPath += dirSep; if (CodeDweller::FilePath::isAbsolute(testPath)) { RETURN_FALSE("isAbsolute() failure"); } testPath = "Hello"; testPath += dirSep; testPath += "file"; if (CodeDweller::FilePath::isAbsolute(testPath)) { RETURN_FALSE("isAbsolute() failure"); } return true; } bool testFilePathJoin() { char const dirSep = CodeDweller::FilePath::DirectorySeparator; std::vector comp0 = {"comp0", "comp1", "comp2"}; std::string expectedComp; // Test normal joining. for (auto &comp : comp0) { expectedComp += comp + dirSep; } expectedComp.pop_back(); if (expectedComp != CodeDweller::FilePath::join({comp0[0], comp0[1], comp0[2]})) { RETURN_FALSE("join() failure"); } // Test null component. if (expectedComp != CodeDweller::FilePath::join({comp0[0], comp0[1], "", comp0[2]})) { RETURN_FALSE("join() failure"); } if (expectedComp != CodeDweller::FilePath::join({"", comp0[0], comp0[1], "", comp0[2]})) { RETURN_FALSE("join() failure"); } if (expectedComp != CodeDweller::FilePath::join({"", comp0[0], comp0[1], "", comp0[2], ""})) { RETURN_FALSE("join() failure"); } // Test single input. expectedComp = "test"; if (expectedComp != CodeDweller::FilePath::join({expectedComp})) { RETURN_FALSE("join() failure"); } if (expectedComp != CodeDweller::FilePath::join({"", expectedComp})) { RETURN_FALSE("join() failure"); } if (expectedComp != CodeDweller::FilePath::join({"", expectedComp, ""})) { RETURN_FALSE("join() failure"); } if (expectedComp != CodeDweller::FilePath::join({"", expectedComp, "", ""})) { RETURN_FALSE("join() failure"); } if (expectedComp != CodeDweller::FilePath::join({"", "", expectedComp, ""})) { RETURN_FALSE("join() failure"); } #ifdef _WIN32 std::string absComponent = "\\abs"; #else std::string absComponent = "/abs"; #endif try { (void) CodeDweller::FilePath::join({"rel", absComponent}); NO_EXCEPTION_TERM("join()"); return false; } catch (std::exception &e) { } try { (void) CodeDweller::FilePath::join({"rel", absComponent, "otherrel"}); NO_EXCEPTION_TERM("join()"); return false; } catch (std::exception &e) { } return true; } long createTestFile(std::string fileName) { std::ofstream out(fileName.c_str()); std::string contents = "Content"; out << contents; out.close(); return contents.size(); } bool testFileReferenceFile() { try { size_t expectedFileSize = createTestFile(testFileName); CodeDweller::FileReference fileRef(testFileName); if (expectedFileSize != fileRef.Size()) { RETURN_FALSE("Size() failure"); } if (!fileRef.exists()) { RETURN_FALSE("exists() failure"); } if (fileRef.isDirectory()) { RETURN_FALSE("isDirectory() failure"); } std::string fullPath = fileRef.FullPath(); if (fullPath.find(testFileName) == std::string::npos) { RETURN_FALSE("FullPath() failure"); } // Test timestamp change. size_t timestamp0 = fileRef.ModTimestamp(); std::this_thread::sleep_for(std::chrono::seconds(5)); (void) createTestFile(testFileName); fileRef.refresh(); size_t diffTimestamp = fileRef.ModTimestamp() - timestamp0; if ((diffTimestamp < 4) || (6 < diffTimestamp)) { RETURN_FALSE("ModTimestamp() failure"); } } catch (std::exception &e) { EXCEPTION_TERM("FileReference()"); return false; } return true; } bool testFileReferenceNoFile() { try { std::remove(testFileName.c_str()); CodeDweller::FileReference fileRef(testFileName); if (0 != fileRef.Size()) { RETURN_FALSE("Size() failure"); } if (fileRef.exists()) { RETURN_FALSE("exists() failure"); } if (fileRef.isDirectory()) { RETURN_FALSE("isDirectory() failure"); } std::string fullPath = fileRef.FullPath(); if (!fullPath.empty()) { RETURN_FALSE("FullPath() failure"); } if (0 != fileRef.ModTimestamp()) { RETURN_FALSE("ModTimestamp() failure"); } // Create file. size_t expectedFileSize = createTestFile(testFileName); fileRef.refresh(); if (expectedFileSize != fileRef.Size()) { std::cout << "expected: " << expectedFileSize << ", fileRef: " << fileRef.Size() << "\n"; RETURN_FALSE("Size() failure"); } if (!fileRef.exists()) { RETURN_FALSE("exists() failure"); } if (fileRef.isDirectory()) { RETURN_FALSE("isDirectory() failure"); } fullPath = fileRef.FullPath(); if (fullPath.find(testFileName) == std::string::npos) { RETURN_FALSE("FullPath() failure"); } } catch (std::exception &e) { EXCEPTION_TERM("FileReference()"); return false; } return true; } bool testFileReferenceDir() { try { std::string fileName = testDirName + "/" + testFileName; std::remove(fileName.c_str()); (void) createTestFile(fileName); std::remove(fileName.c_str()); CodeDweller::FileReference fileRef(testDirName); if (!fileRef.exists()) { RETURN_FALSE("exists() failure"); } if (!fileRef.isDirectory()) { RETURN_FALSE("isDirectory() failure"); } std::string fullPath = fileRef.FullPath(); if (fullPath.find(testDirName) == std::string::npos) { RETURN_FALSE("FullPath() failure"); } // Test timestamp change. size_t timestamp0 = fileRef.ModTimestamp(); std::this_thread::sleep_for(std::chrono::seconds(5)); (void) createTestFile(fileName); fileRef.refresh(); size_t timestamp1 = fileRef.ModTimestamp(); size_t diffTimestamp = timestamp1 - timestamp0; if ((diffTimestamp < 4) || (6 < diffTimestamp)) { RETURN_FALSE("ModTimestamp() failure"); } } catch (std::exception &e) { EXCEPTION_TERM("FileReference()"); return false; } return true; } // Filter for files whose name contains "f1". bool filter(std::string name) { if (name.find("f1") != std::string::npos) { return true; } return false; } bool testDirectoryReferenceFiles() { char const dirSep = CodeDweller::FilePath::DirectorySeparator; std::unordered_set fileNames; std::string filteredFileName = testDirName + dirSep + "f1.txt"; fileNames.emplace(testDirName + dirSep + testFileName); fileNames.emplace(filteredFileName); fileNames.emplace(testDirName + dirSep + "f2.txt"); fileNames.emplace(testDirName + dirSep + "f3.txt"); try { for (auto &name : fileNames) { std::remove(name.c_str()); } CodeDweller::DirectoryReference dirRef(testDirName); if (dirRef.size() != 2) { RETURN_FALSE("Incorrect number of files were found by " "DirectoryReference"); } for (auto &name : fileNames) { (void) createTestFile(name); } dirRef.refresh(); for (auto &name : fileNames) { bool foundFile; foundFile = false; for (auto &fileRef : dirRef) { if (fileRef.FullPath().find(name) != std::string::npos) { foundFile = true; break; } } if (!foundFile) { RETURN_FALSE("Not all files were found by DirectoryReference"); } if (dirRef.size() != fileNames.size() + 2) { RETURN_FALSE("Incorrect number of files were found by " "DirectoryReference"); } } CodeDweller::DirectoryReference dirRefFilter(testDirName, filter); bool foundFile = false; for (auto &fileRef : dirRefFilter) { if (fileRef.FullPath().find(filteredFileName) != std::string::npos) { foundFile = true; break; } if (!foundFile) { RETURN_FALSE("Filtered file was not found by DirectoryReference"); } if (dirRefFilter.size() != 3) { RETURN_FALSE("Incorrect number of filtered files were found by " "DirectoryReference"); } } } catch (std::exception &e) { EXCEPTION_TERM("FileReference()"); return false; } #if 0 for (auto &name : fileNames) { std::remove(name.c_str()); } #endif return true; } bool testDirectoryReferenceNoDir() { try { CodeDweller::DirectoryReference dirRef("Doesntexist"); NO_EXCEPTION_TERM("DirectoryReference with non-existant directory"); return false; } catch (std::exception &e) { } return true; } //////////////////////////////////////////////////////////////////////////////// // End of tests //////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// int main() { std::cout << "CodeDweller::Filesystem unit tests" << std::endl << std::endl; RUN_TEST(testFileOpsMoveFile); RUN_TEST(testFilePathIsAbsolute); RUN_TEST(testFilePathJoin); RUN_TEST(testFileReferenceFile); RUN_TEST(testFileReferenceNoFile); RUN_TEST(testFileReferenceDir); RUN_TEST(testDirectoryReferenceFiles); RUN_TEST(testDirectoryReferenceNoDir); SUMMARY; return 0; }