// IACore-OSS; The Core Library for All IA Open Source Projects // Copyright (C) 2025 IAS (ias@iasoft.dev) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include using namespace IACore; // ----------------------------------------------------------------------------- // Test Block Definition // ----------------------------------------------------------------------------- IAT_BEGIN_BLOCK(Core, File) // Helper to generate a temp path for testing String GetTempPath(const String& filename) { auto path = std::filesystem::temp_directory_path() / filename; return path.string(); } // Helper to write raw data for setup (bypassing the class we are testing) void CreateDummyFile(const String& path, const String& content) { std::ofstream out(path); out << content; out.close(); } // ------------------------------------------------------------------------- // 1. Path Utilities (Pure Logic) // ------------------------------------------------------------------------- BOOL TestPathUtils() { // We use forward slashes as std::filesystem handles them cross-platform String complexPath = "assets/textures/hero_diffuse.png"; // Test ExtractDirectory String dir = File::ExtractDirectory(complexPath); // Note: On Windows this might return "assets\textures", check specific impl if strict // But std::filesystem usually normalizes based on the input string format. IAT_CHECK(dir.find("textures") != String::npos); // Test ExtractFilename (With Extension) String nameWithExt = File::ExtractFilename(complexPath); IAT_CHECK_EQ(nameWithExt, String("hero_diffuse.png")); // Test ExtractFilename (No Extension / Stem) String nameNoExt = File::ExtractFilename(complexPath); IAT_CHECK_EQ(nameNoExt, String("hero_diffuse")); return TRUE; } // ------------------------------------------------------------------------- // 2. Static Read String // ------------------------------------------------------------------------- BOOL TestStaticReadString() { String path = GetTempPath("ia_test_text.txt"); String content = "Hello IA Engine"; // Arrange CreateDummyFile(path, content); // Act auto result = File::ReadToString(path); // Assert IAT_CHECK(result.has_value()); IAT_CHECK_EQ(*result, content); // Cleanup std::filesystem::remove(path); return TRUE; } // ------------------------------------------------------------------------- // 3. Static Read Binary (Vector) // ------------------------------------------------------------------------- BOOL TestStaticReadVector() { String path = GetTempPath("ia_test_bin.dat"); // Arrange: Create a binary file manually std::ofstream out(path, std::ios::binary); UINT8 rawBytes[] = { 0xDE, 0xAD, 0xBE, 0xEF }; out.write((char*)rawBytes, 4); out.close(); // Act auto result = File::ReadToVector(path); // Assert IAT_CHECK(result.has_value()); Vector& vec = *result; IAT_CHECK_EQ(vec.size(), (SIZE_T)4); IAT_CHECK_EQ(vec[0], 0xDE); IAT_CHECK_EQ(vec[3], 0xEF); // Cleanup std::filesystem::remove(path); return TRUE; } // ------------------------------------------------------------------------- // 4. Instance Write & Read Loop // ------------------------------------------------------------------------- BOOL TestInstanceWriteRead() { String path = GetTempPath("ia_instance_io.bin"); UINT32 flagsWrite = (UINT32)File::EOpenFlags::Write | (UINT32)File::EOpenFlags::Binary | (UINT32)File::EOpenFlags::Trunc; // 1. Write { File f; auto res = f.Open(path, (File::EOpenFlags)flagsWrite); IAT_CHECK(res.has_value()); IAT_CHECK(f.IsOpen()); UINT32 magic = 12345; f.Write(&magic, sizeof(magic)); f.Close(); IAT_CHECK_NOT(f.IsOpen()); } // 2. Read Back { UINT32 flagsRead = (UINT32)File::EOpenFlags::Read | (UINT32)File::EOpenFlags::Binary; File f(path, (File::EOpenFlags)flagsRead); // Test RAII constructor IAT_CHECK(f.IsOpen()); UINT32 magicRead = 0; SIZE_T bytesRead = f.Read(&magicRead, sizeof(magicRead)); IAT_CHECK_EQ(bytesRead, sizeof(UINT32)); IAT_CHECK_EQ(magicRead, (UINT32)12345); } std::filesystem::remove(path); return TRUE; } // ------------------------------------------------------------------------- // 5. Append Mode // ------------------------------------------------------------------------- BOOL TestAppendMode() { String path = GetTempPath("ia_append.txt"); UINT32 flagsAppend = (UINT32)File::EOpenFlags::Write | (UINT32)File::EOpenFlags::Append; // Create initial file CreateDummyFile(path, "A"); // Open in append mode File f; const auto openResult = f.Open(path, (File::EOpenFlags)flagsAppend); if(!openResult) { IA_PANIC(openResult.error().c_str()) return FALSE; } char c = 'B'; f.Write(&c, 1); f.Close(); // Verify content is "AB" auto content = File::ReadToString(path); IAT_CHECK(content.has_value()); IAT_CHECK_EQ(*content, String("AB")); std::filesystem::remove(path); return TRUE; } // ------------------------------------------------------------------------- // 6. Error Handling // ------------------------------------------------------------------------- BOOL TestNonExistentFile() { String ghostPath = GetTempPath("this_does_not_exist.ghost"); // Ensure it really doesn't exist if(File::Exists(ghostPath)) std::filesystem::remove(ghostPath); // Test Static auto resStatic = File::ReadToString(ghostPath); IAT_CHECK_NOT(resStatic.has_value()); // Optional: Check error message content // IAT_CHECK(resStatic.error().find("not found") != String::npos); // Test Instance File f; auto resInstance = f.Open(ghostPath, File::EOpenFlags::Read); IAT_CHECK_NOT(resInstance.has_value()); IAT_CHECK_NOT(f.IsOpen()); return TRUE; } // ------------------------------------------------------------------------- // Registration // ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(TestPathUtils); IAT_ADD_TEST(TestStaticReadString); IAT_ADD_TEST(TestStaticReadVector); IAT_ADD_TEST(TestInstanceWriteRead); IAT_ADD_TEST(TestAppendMode); IAT_ADD_TEST(TestNonExistentFile); IAT_END_TEST_LIST() IAT_END_BLOCK() int main(int argc, char* argv[]) { UNUSED(argc); UNUSED(argv); // Define runner (StopOnFail=false, Verbose=true) ia::iatest::runner testRunner; // Run the BinaryReader block testRunner.testBlock(); return 0; }