This commit is contained in:
2025-12-08 01:18:13 +05:30
commit 3ed23336e2
56 changed files with 7103 additions and 0 deletions

246
Tests/Unit/FileOps.cpp Normal file
View File

@ -0,0 +1,246 @@
// 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 <https://www.gnu.org/licenses/>.
#include <IACore/FileOps.hpp>
#include <IACore/IATest.hpp>
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<true>(complexPath);
IAT_CHECK_EQ(nameWithExt, String("hero_diffuse.png"));
// Test ExtractFilename (No Extension / Stem)
String nameNoExt = File::ExtractFilename<false>(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<UINT8>& 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<false, true> testRunner;
// Run the BinaryReader block
testRunner.testBlock<Core_File>();
return 0;
}