246 lines
8.0 KiB
C++
246 lines
8.0 KiB
C++
// 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;
|
|
} |