From ebde7c7e663b5dbe6d511e73fb4d17fbfc291c70 Mon Sep 17 00:00:00 2001 From: dev0 Date: Sun, 25 Jan 2026 22:08:16 +0530 Subject: [PATCH] Release Readt --- Tests/Unit/AsyncOps.cpp | 50 +------------------------ Tests/Unit/CLI.cpp | 31 ---------------- Tests/Unit/CMakeLists.txt | 5 --- Tests/Unit/DataOps.cpp | 7 ---- Tests/Unit/Environment.cpp | 53 ++------------------------- Tests/Unit/FileOps.cpp | 42 +-------------------- Tests/Unit/IPC.cpp | 41 ++------------------- Tests/Unit/JSON.cpp | 30 +-------------- Tests/Unit/Logger.cpp | 12 ++---- Tests/Unit/Main.cpp | 2 +- Tests/Unit/Platform.cpp | 34 +++-------------- Tests/Unit/ProcessOps.cpp | 73 ++++++------------------------------- Tests/Unit/RingBuffer.cpp | 23 +----------- Tests/Unit/SocketOps.cpp | 36 +----------------- Tests/Unit/StreamReader.cpp | 43 +++------------------- Tests/Unit/StreamWriter.cpp | 28 -------------- Tests/Unit/StringOps.cpp | 18 +-------- Tests/Unit/Utils.cpp | 67 ++++------------------------------ Tests/Unit/XML.cpp | 23 ------------ 19 files changed, 51 insertions(+), 567 deletions(-) diff --git a/Tests/Unit/AsyncOps.cpp b/Tests/Unit/AsyncOps.cpp index 775735b..66c1b56 100644 --- a/Tests/Unit/AsyncOps.cpp +++ b/Tests/Unit/AsyncOps.cpp @@ -20,44 +20,28 @@ using namespace IACore; -// ----------------------------------------------------------------------------- -// Helper: RAII Scheduler Guard -// ----------------------------------------------------------------------------- -// Ensures the scheduler is terminated at the end of a test scope, -// preventing state pollution between tests. struct SchedulerGuard { SchedulerGuard(u8 worker_count = 2) { - // We ignore the result here as we assume the test environment is clean. - // Specific initialization tests will check the result manually. + (void)AsyncOps::initialize_scheduler(worker_count); } ~SchedulerGuard() { AsyncOps::terminate_scheduler(); } }; -// ----------------------------------------------------------------------------- -// Test Block Definition -// ----------------------------------------------------------------------------- - IAT_BEGIN_BLOCK(Core, AsyncOps) -// ------------------------------------------------------------------------- -// 1. Initialization and Termination -// ------------------------------------------------------------------------- auto test_initialization() -> bool { - // Ensure clean state + AsyncOps::terminate_scheduler(); - // Initialize with specific worker countB const auto res = AsyncOps::initialize_scheduler(4); IAT_CHECK(res.has_value()); IAT_CHECK_EQ(AsyncOps::get_worker_count(), static_cast(4)); - // Terminate AsyncOps::terminate_scheduler(); - // Verify we can re-initialize const auto res2 = AsyncOps::initialize_scheduler(1); IAT_CHECK(res2.has_value()); IAT_CHECK_EQ(AsyncOps::get_worker_count(), static_cast(1)); @@ -66,20 +50,15 @@ auto test_initialization() -> bool { return true; } -// ------------------------------------------------------------------------- -// 2. Basic Task Execution -// ------------------------------------------------------------------------- auto test_basic_execution() -> bool { SchedulerGuard guard(2); AsyncOps::Schedule schedule; std::atomic run_count{0}; - // Schedule a simple task AsyncOps::schedule_task([&](AsyncOps::WorkerId) { run_count++; }, 0, &schedule); - // Wait for it to finish AsyncOps::wait_for_schedule_completion(&schedule); IAT_CHECK_EQ(run_count.load(), 1); @@ -87,9 +66,6 @@ auto test_basic_execution() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. Concurrency and Load -// ------------------------------------------------------------------------- auto test_concurrency() -> bool { SchedulerGuard guard(4); @@ -100,7 +76,6 @@ auto test_concurrency() -> bool { for (i32 i = 0; i < total_tasks; ++i) { AsyncOps::schedule_task( [&](AsyncOps::WorkerId) { - // Simulate a tiny bit of work to encourage thread switching std::this_thread::sleep_for(std::chrono::microseconds(10)); run_count++; }, @@ -114,19 +89,12 @@ auto test_concurrency() -> bool { return true; } -// ------------------------------------------------------------------------- -// 4. Priorities -// ------------------------------------------------------------------------- auto test_priorities() -> bool { SchedulerGuard guard(2); AsyncOps::Schedule schedule; std::atomic high_priority_ran{0}; std::atomic normal_priority_ran{0}; - // Verify API accepts priorities and executes them. - // Note: Deterministic priority testing is difficult in unit tests without - // mocking, so we primarily ensure the API functions correctly. - AsyncOps::schedule_task([&](AsyncOps::WorkerId) { high_priority_ran++; }, 0, &schedule, AsyncOps::Priority::High); @@ -141,18 +109,13 @@ auto test_priorities() -> bool { return true; } -// ------------------------------------------------------------------------- -// 5. Fire-and-Forget Tasks -// ------------------------------------------------------------------------- auto test_run_task_fire_and_forget() -> bool { SchedulerGuard guard(2); std::atomic executed{false}; - // run_task doesn't use a Schedule object, so we must sync manually AsyncOps::run_task([&]() { executed = true; }); - // Busy wait with timeout (max 1 second) for (int i = 0; i < 100; ++i) { if (executed.load()) break; @@ -164,34 +127,25 @@ auto test_run_task_fire_and_forget() -> bool { return true; } -// ------------------------------------------------------------------------- -// 6. Cancellation Safety -// ------------------------------------------------------------------------- auto test_cancellation_safety() -> bool { SchedulerGuard guard(2); - // 1. Cancel non-existent tag (Should be safe) AsyncOps::cancel_tasks_of_tag(999); AsyncOps::Schedule schedule; std::atomic counter{0}; - // 2. Schedule a task, wait for it AsyncOps::schedule_task([&](AsyncOps::WorkerId) { counter++; }, 10, &schedule); AsyncOps::wait_for_schedule_completion(&schedule); IAT_CHECK_EQ(counter.load(), 1); - // 3. Cancel tag 10 (already done, should be safe) AsyncOps::cancel_tasks_of_tag(10); return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_initialization); IAT_ADD_TEST(test_basic_execution); diff --git a/Tests/Unit/CLI.cpp b/Tests/Unit/CLI.cpp index e204a32..998f508 100644 --- a/Tests/Unit/CLI.cpp +++ b/Tests/Unit/CLI.cpp @@ -18,22 +18,14 @@ using namespace IACore; -// ----------------------------------------------------------------------------- -// Test Block Definition -// ----------------------------------------------------------------------------- - IAT_BEGIN_BLOCK(Core, CLI) -// ------------------------------------------------------------------------- -// 1. Basic Traversal -// ------------------------------------------------------------------------- auto test_basic_traversal() -> bool { const Vec args = {"ignored", "one", "two", "three"}; CLIParser parser(args); IAT_CHECK(parser.remaining()); - // Check sequential access IAT_CHECK_EQ(String(parser.next()), "one"); IAT_CHECK(parser.remaining()); @@ -42,30 +34,22 @@ auto test_basic_traversal() -> bool { IAT_CHECK_EQ(String(parser.next()), "three"); - // Should be exhausted now IAT_CHECK_NOT(parser.remaining()); - // Next on exhausted returns empty string view IAT_CHECK_EQ(String(parser.next()), ""); return true; } -// ------------------------------------------------------------------------- -// 2. Peek Functionality -// ------------------------------------------------------------------------- auto test_peek() -> bool { const Vec args = {"ignored", "peek_val", "next_val"}; CLIParser parser(args); - // Peek should return value but not advance IAT_CHECK_EQ(String(parser.peek()), "peek_val"); IAT_CHECK(parser.remaining()); - // Verify we are still at the same element IAT_CHECK_EQ(String(parser.next()), "peek_val"); - // Now we should be at next_val IAT_CHECK_EQ(String(parser.peek()), "next_val"); IAT_CHECK_EQ(String(parser.next()), "next_val"); @@ -74,29 +58,20 @@ auto test_peek() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. Consume Functionality -// ------------------------------------------------------------------------- auto test_consume() -> bool { const Vec args = {"ignored", "-v", "--output", "file.txt"}; CLIParser parser(args); - // 1. Try consuming something that isn't there IAT_CHECK_NOT(parser.consume("-x")); - // Verify we haven't moved IAT_CHECK_EQ(String(parser.peek()), "-v"); - // 2. Consume the correct flag IAT_CHECK(parser.consume("-v")); - // 3. Verify advancement IAT_CHECK_EQ(String(parser.peek()), "--output"); - // 4. Consume next IAT_CHECK(parser.consume("--output")); - // 5. Verify final argument IAT_CHECK_EQ(String(parser.next()), "file.txt"); IAT_CHECK_NOT(parser.remaining()); @@ -104,9 +79,6 @@ auto test_consume() -> bool { return true; } -// ------------------------------------------------------------------------- -// 4. Empty Argument List -// ------------------------------------------------------------------------- auto test_empty() -> bool { const Vec args = {}; CLIParser parser(args); @@ -119,9 +91,6 @@ auto test_empty() -> bool { return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_basic_traversal); IAT_ADD_TEST(test_peek); diff --git a/Tests/Unit/CMakeLists.txt b/Tests/Unit/CMakeLists.txt index bb8d350..1727f18 100644 --- a/Tests/Unit/CMakeLists.txt +++ b/Tests/Unit/CMakeLists.txt @@ -1,6 +1,3 @@ -# ------------------------------------------------ -# The Unified C++ Test Suite -# ------------------------------------------------ set(TEST_SOURCES AsyncOps.cpp CLI.cpp @@ -27,13 +24,11 @@ set(TEST_SOURCES add_executable(IACore_Test_Suite ${TEST_SOURCES}) -# Enable exceptions for testing framework target_compile_options(IACore_Test_Suite PRIVATE -fexceptions) set_target_properties(IACore_Test_Suite PROPERTIES USE_EXCEPTIONS ON) target_link_libraries(IACore_Test_Suite PRIVATE IACore) -# Copy necessary runtime assets add_custom_command(TARGET IACore_Test_Suite POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ diff --git a/Tests/Unit/DataOps.cpp b/Tests/Unit/DataOps.cpp index a849999..8236b7c 100644 --- a/Tests/Unit/DataOps.cpp +++ b/Tests/Unit/DataOps.cpp @@ -18,10 +18,6 @@ using namespace IACore; -// ----------------------------------------------------------------------------- -// Test Block Definition -// ----------------------------------------------------------------------------- - IAT_BEGIN_BLOCK(Core, DataOps) auto test_crc32() -> bool { @@ -101,9 +97,6 @@ auto test_hash_fnv1a() -> bool { return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_crc32); IAT_ADD_TEST(test_hash_fnv1a); diff --git a/Tests/Unit/Environment.cpp b/Tests/Unit/Environment.cpp index c64edf0..9c5dc5b 100644 --- a/Tests/Unit/Environment.cpp +++ b/Tests/Unit/Environment.cpp @@ -18,53 +18,35 @@ using namespace IACore; -// ----------------------------------------------------------------------------- -// Constants -// ----------------------------------------------------------------------------- static constexpr const char *TEST_KEY = "IA_TEST_ENV_VAR_12345"; static constexpr const char *TEST_VAL = "Hello World"; -// ----------------------------------------------------------------------------- -// Test Block Definition -// ----------------------------------------------------------------------------- - IAT_BEGIN_BLOCK(Core, Environment) -// ------------------------------------------------------------------------- -// 1. Basic Set and Get (The Happy Path) -// ------------------------------------------------------------------------- auto test_basic_cycle() -> bool { - // 1. Ensure clean slate + (void)Environment::unset(TEST_KEY); IAT_CHECK_NOT(Environment::exists(TEST_KEY)); - // 2. Set const auto set_res = Environment::set(TEST_KEY, TEST_VAL); IAT_CHECK(set_res.has_value()); IAT_CHECK(Environment::exists(TEST_KEY)); - // 3. Find (Optional) const auto opt = Environment::find(TEST_KEY); IAT_CHECK(opt.has_value()); IAT_CHECK_EQ(*opt, String(TEST_VAL)); - // 4. Get (Direct) const String val = Environment::get(TEST_KEY); IAT_CHECK_EQ(val, String(TEST_VAL)); - // Cleanup (void)Environment::unset(TEST_KEY); return true; } -// ------------------------------------------------------------------------- -// 2. Overwriting Values -// ------------------------------------------------------------------------- auto test_overwrite() -> bool { (void)Environment::set(TEST_KEY, "ValueA"); IAT_CHECK_EQ(Environment::get(TEST_KEY), String("ValueA")); - // Overwrite (void)Environment::set(TEST_KEY, "ValueB"); IAT_CHECK_EQ(Environment::get(TEST_KEY), String("ValueB")); @@ -72,9 +54,6 @@ auto test_overwrite() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. Unset Logic -// ------------------------------------------------------------------------- auto test_unset() -> bool { (void)Environment::set(TEST_KEY, "To Be Deleted"); IAT_CHECK(Environment::exists(TEST_KEY)); @@ -82,82 +61,58 @@ auto test_unset() -> bool { const auto unset_res = Environment::unset(TEST_KEY); IAT_CHECK(unset_res.has_value()); - // Verify it is actually gone IAT_CHECK_NOT(Environment::exists(TEST_KEY)); - // Find should return nullopt const auto opt = Environment::find(TEST_KEY); IAT_CHECK_NOT(opt.has_value()); return true; } -// ------------------------------------------------------------------------- -// 4. Default Value Fallbacks -// ------------------------------------------------------------------------- auto test_defaults() -> bool { const char *ghost_key = "IA_THIS_KEY_DOES_NOT_EXIST"; - // Ensure it really doesn't exist (void)Environment::unset(ghost_key); - // Test Get with implicit default ("") const String empty = Environment::get(ghost_key); IAT_CHECK(empty.empty()); - // Test Get with explicit default const String fallback = Environment::get(ghost_key, "MyDefault"); IAT_CHECK_EQ(fallback, String("MyDefault")); return true; } -// ------------------------------------------------------------------------- -// 5. Empty Strings vs Null/Unset -// ------------------------------------------------------------------------- -// Does Set(Key, "") create an existing empty variable, or unset it? -// Standard POSIX/Windows API behavior is that it EXISTS, but is empty. auto test_empty_value() -> bool { (void)Environment::set(TEST_KEY, ""); #if IA_PLATFORM_WINDOWS - // Windows behavior: Setting to empty string removes the variable - // IAT_CHECK_NOT(Environment::exists(TEST_KEY)); - // auto opt = Environment::find(TEST_KEY); - // IAT_CHECK_NOT(opt.has_value()); + #else - // POSIX behavior: Variable exists but is empty + IAT_CHECK(Environment::exists(TEST_KEY)); const auto opt = Environment::find(TEST_KEY); IAT_CHECK(opt.has_value()); IAT_CHECK(opt->empty()); #endif - // Cleanup (void)Environment::unset(TEST_KEY); IAT_CHECK_NOT(Environment::exists(TEST_KEY)); return true; } -// ------------------------------------------------------------------------- -// 6. Validation / Bad Input -// ------------------------------------------------------------------------- auto test_bad_input() -> bool { - // Setting an empty key should fail gracefully + const auto res = Environment::set("", "Value"); IAT_CHECK_NOT(res.has_value()); - // Unsetting an empty key should fail const auto res_unset = Environment::unset(""); IAT_CHECK_NOT(res_unset.has_value()); return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_basic_cycle); IAT_ADD_TEST(test_overwrite); diff --git a/Tests/Unit/FileOps.cpp b/Tests/Unit/FileOps.cpp index 0913e21..1ff3ae5 100644 --- a/Tests/Unit/FileOps.cpp +++ b/Tests/Unit/FileOps.cpp @@ -20,9 +20,6 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, FileOps) -// ------------------------------------------------------------------------- -// Helpers -// ------------------------------------------------------------------------- void cleanup_file(const Path &path) { std::error_code ec; if (std::filesystem::exists(path, ec)) { @@ -30,41 +27,30 @@ void cleanup_file(const Path &path) { } } -// ------------------------------------------------------------------------- -// 1. Text File I/O -// ------------------------------------------------------------------------- auto test_text_io() -> bool { const Path path = "iatest_fileops_text.txt"; const String content = "Hello IACore FileOps!\nLine 2"; - // 1. Write const auto write_res = FileOps::write_text_file(path, content, true); IAT_CHECK(write_res.has_value()); IAT_CHECK_EQ(*write_res, content.size()); - // 2. Read const auto read_res = FileOps::read_text_file(path); IAT_CHECK(read_res.has_value()); IAT_CHECK_EQ(*read_res, content); - // Cleanup cleanup_file(path); return true; } -// ------------------------------------------------------------------------- -// 2. Binary File I/O -// ------------------------------------------------------------------------- auto test_binary_io() -> bool { const Path path = "iatest_fileops_bin.bin"; const Vec content = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0xFF}; - // 1. Write const auto write_res = FileOps::write_binary_file(path, content, true); IAT_CHECK(write_res.has_value()); IAT_CHECK_EQ(*write_res, content.size()); - // 2. Read const auto read_res = FileOps::read_binary_file(path); IAT_CHECK(read_res.has_value()); IAT_CHECK_EQ(read_res->size(), content.size()); @@ -73,22 +59,16 @@ auto test_binary_io() -> bool { IAT_CHECK_EQ((*read_res)[i], content[i]); } - // Cleanup cleanup_file(path); return true; } -// ------------------------------------------------------------------------- -// 3. Memory Mapping (File) -// ------------------------------------------------------------------------- auto test_file_mapping() -> bool { const Path path = "iatest_fileops_map.txt"; const String content = "MappedContent"; - // Setup file (void)FileOps::write_text_file(path, content, true); - // Map usize size = 0; const auto map_res = FileOps::map_file(path, size); IAT_CHECK(map_res.has_value()); @@ -97,44 +77,34 @@ auto test_file_mapping() -> bool { const u8 *ptr = *map_res; IAT_CHECK(ptr != nullptr); - // Verify content via pointer String read_back(reinterpret_cast(ptr), size); IAT_CHECK_EQ(read_back, content); - // Unmap FileOps::unmap_file(ptr); cleanup_file(path); return true; } -// ------------------------------------------------------------------------- -// 4. Shared Memory -// ------------------------------------------------------------------------- auto test_shared_memory() -> bool { const String shm_name = "iatest_shm_block"; const usize shm_size = 4096; - // 1. Create as Owner auto owner_res = FileOps::map_shared_memory(shm_name, shm_size, true); IAT_CHECK(owner_res.has_value()); u8 *owner_ptr = *owner_res; - // Write data std::memset(owner_ptr, 0, shm_size); const String msg = "Shared Memory Message"; std::memcpy(owner_ptr, msg.data(), msg.size()); - // 2. Open as Client auto client_res = FileOps::map_shared_memory(shm_name, shm_size, false); IAT_CHECK(client_res.has_value()); u8 *client_ptr = *client_res; - // Verify data String read_msg(reinterpret_cast(client_ptr), msg.size()); IAT_CHECK_EQ(read_msg, msg); - // 3. Cleanup FileOps::unmap_file(owner_ptr); FileOps::unmap_file(client_ptr); FileOps::unlink_shared_memory(shm_name); @@ -142,14 +112,10 @@ auto test_shared_memory() -> bool { return true; } -// ------------------------------------------------------------------------- -// 5. Stream Integration -// ------------------------------------------------------------------------- auto test_stream_integration() -> bool { const Path path = "iatest_fileops_stream.bin"; cleanup_file(path); - // Write via StreamWriter { auto writer_res = FileOps::stream_to_file(path, true); IAT_CHECK(writer_res.has_value()); @@ -157,9 +123,8 @@ auto test_stream_integration() -> bool { (void)writer.write(0x12345678); (void)writer.write(0xFF); - } // Destructor should flush/close + } - // Read via StreamReader { auto reader_res = FileOps::stream_from_file(path); IAT_CHECK(reader_res.has_value()); @@ -167,7 +132,7 @@ auto test_stream_integration() -> bool { auto val_u32 = reader.read(); IAT_CHECK(val_u32.has_value()); - IAT_CHECK_EQ(*val_u32, 0x12345678); + IAT_CHECK_EQ(*val_u32, 0x12345678u); auto val_u8 = reader.read(); IAT_CHECK(val_u8.has_value()); @@ -178,9 +143,6 @@ auto test_stream_integration() -> bool { return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_text_io); IAT_ADD_TEST(test_binary_io); diff --git a/Tests/Unit/IPC.cpp b/Tests/Unit/IPC.cpp index ce0bda6..1cad067 100644 --- a/Tests/Unit/IPC.cpp +++ b/Tests/Unit/IPC.cpp @@ -21,45 +21,30 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, IPC) -// ------------------------------------------------------------------------- -// 1. Layout Constraints -// ------------------------------------------------------------------------- auto test_layout_constraints() -> bool { - // Verify alignment + IAT_CHECK_EQ(alignof(IpcSharedMemoryLayout), static_cast(64)); - // Verify offsets to ensure cache-line isolation - // Header is at 0 IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, meta), static_cast(0)); - // moni_control should be at 64 (cache line 1) IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, moni_control), static_cast(64)); - // ControlBlock is 128 bytes (64 for producer, 64 for consumer) - // So mino_control should be at 64 + 128 = 192 IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, mino_control), static_cast(192)); - // Data offsets should follow mino_control (192 + 128 = 320) IAT_CHECK_EQ(offsetof(IpcSharedMemoryLayout, moni_data_offset), static_cast(320)); - // Ensure the whole struct is a multiple of 64 IAT_CHECK_EQ(sizeof(IpcSharedMemoryLayout) % 64, static_cast(0)); return true; } -// ------------------------------------------------------------------------- -// 2. Manual Shared Memory & RingBuffer Setup -// ------------------------------------------------------------------------- auto test_manual_shm_ringbuffer() -> bool { const String shm_name = "IA_TEST_IPC_LAYOUT_CHECK"; - const usize shm_size = 16 * 1024; // 16KB + const usize shm_size = 16 * 1024; - // 1. Create Shared Memory - // Ensure it doesn't exist first FileOps::unlink_shared_memory(shm_name); auto map_res = FileOps::map_shared_memory(shm_name, shm_size, true); @@ -68,14 +53,10 @@ auto test_manual_shm_ringbuffer() -> bool { u8 *base_ptr = *map_res; auto *layout = reinterpret_cast(base_ptr); - // 2. Initialize Layout - // We simulate what IpcManager would do - layout->meta.magic = 0xDEADBEEF; // Dummy + layout->meta.magic = 0xDEADBEEF; layout->meta.version = 1; layout->meta.total_size = shm_size; - // Define data regions - // Data starts after the layout struct const usize header_size = IpcSharedMemoryLayout::get_header_size(); const usize data_available = shm_size - header_size; const usize half_data = data_available / 2; @@ -86,9 +67,6 @@ auto test_manual_shm_ringbuffer() -> bool { layout->mino_data_offset = header_size + half_data; layout->mino_data_size = half_data; - // 3. Initialize RingBuffers - // MONI (Manager Out, Node In) - // Manager is Owner of MONI Span moni_data_span(base_ptr + layout->moni_data_offset, static_cast(layout->moni_data_size)); auto moni_res = @@ -96,9 +74,6 @@ auto test_manual_shm_ringbuffer() -> bool { IAT_CHECK(moni_res.has_value()); auto moni = std::move(*moni_res); - // MINO (Manager In, Node Out) - // Manager is NOT Owner of MINO (Node writes to it) - // But for this test, let's pretend we are the Node for MINO to test writing Span mino_data_span(base_ptr + layout->mino_data_offset, static_cast(layout->mino_data_size)); auto mino_res = @@ -106,16 +81,12 @@ auto test_manual_shm_ringbuffer() -> bool { IAT_CHECK(mino_res.has_value()); auto _ = std::move(*mino_res); - // 4. Test Data Flow - // Write to MONI String msg = "IPC_TEST_MESSAGE"; IAT_CHECK( moni.push(100, Span(reinterpret_cast(msg.data()), msg.size())) .has_value()); - // Read from MONI (Simulate Node reading) - // Create a reader view auto moni_reader_res = RingBufferView::create(&layout->moni_control, moni_data_span, false); IAT_CHECK(moni_reader_res.has_value()); @@ -125,22 +96,18 @@ auto test_manual_shm_ringbuffer() -> bool { u8 buffer[128]; auto pop_res = moni_reader.pop(header, Span(buffer, 128)); IAT_CHECK(pop_res.has_value()); - IAT_CHECK(pop_res->has_value()); // Should have data + IAT_CHECK(pop_res->has_value()); IAT_CHECK_EQ(header.id, static_cast(100)); String received((char *)buffer, *pop_res.value()); IAT_CHECK_EQ(received, msg); - // Cleanup FileOps::unmap_file(base_ptr); FileOps::unlink_shared_memory(shm_name); return true; } -// ------------------------------------------------------------------------- -// 3. Manager Instantiation -// ------------------------------------------------------------------------- class TestManager : public IpcManager { public: void on_signal(NativeProcessID, u8) override {} diff --git a/Tests/Unit/JSON.cpp b/Tests/Unit/JSON.cpp index 4fbfd5a..3c1cd9b 100644 --- a/Tests/Unit/JSON.cpp +++ b/Tests/Unit/JSON.cpp @@ -18,31 +18,20 @@ using namespace IACore; -// ----------------------------------------------------------------------------- -// Test Structures for Serialization -// ----------------------------------------------------------------------------- struct UserProfile { String username; u32 id; bool is_active; Vec roles; - // Equality operator for verification bool operator==(const UserProfile &other) const { return username == other.username && id == other.id && is_active == other.is_active && roles == other.roles; } }; -// ----------------------------------------------------------------------------- -// Test Block Definition -// ----------------------------------------------------------------------------- - IAT_BEGIN_BLOCK(Core, JSON) -// ------------------------------------------------------------------------- -// 1. Dynamic JSON (nlohmann::json) -// ------------------------------------------------------------------------- auto test_dynamic_parse() -> bool { const String json_text = R"({ "string": "Hello World", @@ -58,7 +47,6 @@ auto test_dynamic_parse() -> bool { const auto &j = *res; - // Type checks and value retrieval IAT_CHECK(j["string"].is_string()); IAT_CHECK_EQ(j["string"].get(), String("Hello World")); @@ -88,7 +76,6 @@ auto test_dynamic_encode() -> bool { const String encoded = Json::encode(j); - // Simple containment check as key order isn't guaranteed IAT_CHECK(encoded.find("IACore") != String::npos); IAT_CHECK(encoded.find("version") != String::npos); IAT_CHECK(encoded.find("2") != String::npos); @@ -97,31 +84,25 @@ auto test_dynamic_encode() -> bool { } auto test_parse_invalid() -> bool { - const String bad_json = "{ key: value }"; // Missing quotes + const String bad_json = "{ key: value }"; auto res = Json::parse(bad_json); IAT_CHECK_NOT(res.has_value()); return true; } -// ------------------------------------------------------------------------- -// 2. Struct Serialization (Glaze) -// ------------------------------------------------------------------------- auto test_struct_round_trip() -> bool { UserProfile original{.username = "test_user", .id = 12345, .is_active = true, .roles = {"admin", "editor"}}; - // Struct -> JSON auto encode_res = Json::encode_struct(original); IAT_CHECK(encode_res.has_value()); String json_str = *encode_res; - // Verify JSON structure roughly IAT_CHECK(json_str.find("test_user") != String::npos); IAT_CHECK(json_str.find("roles") != String::npos); - // JSON -> Struct auto decode_res = Json::parse_to_struct(json_str); IAT_CHECK(decode_res.has_value()); @@ -138,9 +119,6 @@ auto test_struct_parse_error() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. Read-Only Parsing (simdjson) -// ------------------------------------------------------------------------- auto test_read_only() -> bool { const String json_text = R"({ "id": 999, @@ -154,19 +132,16 @@ auto test_read_only() -> bool { auto &doc = *res; simdjson::dom::element root = doc.root(); - // Check ID u64 id = 0; auto err_id = root["id"].get(id); IAT_CHECK(!err_id); IAT_CHECK_EQ(id, 999ULL); - // Check Name std::string_view name; auto err_name = root["name"].get(name); IAT_CHECK(!err_name); IAT_CHECK_EQ(String(name), String("Simd")); - // Check Array simdjson::dom::array scores; auto err_arr = root["scores"].get(scores); IAT_CHECK(!err_arr); @@ -175,9 +150,6 @@ auto test_read_only() -> bool { return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_dynamic_parse); IAT_ADD_TEST(test_dynamic_encode); diff --git a/Tests/Unit/Logger.cpp b/Tests/Unit/Logger.cpp index 2711ccc..c1ca899 100644 --- a/Tests/Unit/Logger.cpp +++ b/Tests/Unit/Logger.cpp @@ -24,14 +24,12 @@ IAT_BEGIN_BLOCK(Core, Logger) static constexpr const char *LOG_FILE = "iacore_test_log.txt"; auto test_file_logging() -> bool { - // 1. Enable logging to disk + const auto res = Logger::enable_logging_to_disk(LOG_FILE); IAT_CHECK(res.has_value()); - // 2. Set level to Trace to ensure we capture everything Logger::set_log_level(Logger::LogLevel::Trace); - // 3. Log unique messages const String msg_info = "Test_Info_Msg_123"; const String msg_err = "Test_Error_Msg_456"; const String msg_warn = "Test_Warn_Msg_789"; @@ -40,10 +38,8 @@ auto test_file_logging() -> bool { Logger::error("{}", msg_err); Logger::warn("{}", msg_warn); - // 4. Flush Logger::flush_logs(); - // 5. Read back auto read_res = FileOps::read_text_file(LOG_FILE); if (!read_res) { std::cout << console::YELLOW << " Warning: Could not read log file (" @@ -58,7 +54,6 @@ auto test_file_logging() -> bool { IAT_CHECK(content.find(msg_err) != String::npos); IAT_CHECK(content.find(msg_warn) != String::npos); - // Check for log tags IAT_CHECK(content.find("INFO") != String::npos); IAT_CHECK(content.find("ERROR") != String::npos); IAT_CHECK(content.find("WARN") != String::npos); @@ -67,7 +62,7 @@ auto test_file_logging() -> bool { } auto test_log_levels() -> bool { - // 1. Set level to Warn (Trace < Debug < Info < Warn < Error) + Logger::set_log_level(Logger::LogLevel::Warn); const String unique_info = "Hidden_Info_Msg"; @@ -85,9 +80,8 @@ auto test_log_levels() -> bool { const String content = *read_res; - // Info should NOT be present IAT_CHECK(content.find(unique_info) == String::npos); - // Warn SHOULD be present + IAT_CHECK(content.find(unique_warn) != String::npos); return true; diff --git a/Tests/Unit/Main.cpp b/Tests/Unit/Main.cpp index f00fa46..38eb0b9 100644 --- a/Tests/Unit/Main.cpp +++ b/Tests/Unit/Main.cpp @@ -33,7 +33,7 @@ IACORE_MAIN() { << "===============================================================\n" << console::RESET << "\n"; - const i32 result = Test::TestRegistry::run_all(); + Const result = Test::TestRegistry::run_all(); SocketOps::terminate(); diff --git a/Tests/Unit/Platform.cpp b/Tests/Unit/Platform.cpp index 7812549..0379a0f 100644 --- a/Tests/Unit/Platform.cpp +++ b/Tests/Unit/Platform.cpp @@ -21,9 +21,6 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, Platform) -// ------------------------------------------------------------------------- -// 1. OS Name Detection -// ------------------------------------------------------------------------- auto test_os_name() -> bool { const char *os_name = Platform::get_operating_system_name(); IAT_CHECK(os_name != nullptr); @@ -44,9 +41,6 @@ auto test_os_name() -> bool { return true; } -// ------------------------------------------------------------------------- -// 2. Architecture Name Detection -// ------------------------------------------------------------------------- auto test_arch_name() -> bool { const char *arch_name = Platform::get_architecture_name(); IAT_CHECK(arch_name != nullptr); @@ -65,60 +59,45 @@ auto test_arch_name() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. CPU Capabilities -// ------------------------------------------------------------------------- auto test_capabilities() -> bool { - // Initialize detection + const bool check_result = Platform::check_cpu(); IAT_CHECK(check_result); const auto &caps = Platform::get_capabilities(); - // We verify that we can access the capabilities struct. - // The actual value of hardware_crc32 depends on the host machine, - // so we cannot assert true or false, but we ensure no crash occurs. volatile bool has_crc = caps.hardware_crc32; (void)has_crc; return true; } -// ------------------------------------------------------------------------- -// 4. CPUID (x64 Only) -// ------------------------------------------------------------------------- #if IA_ARCH_X64 auto test_cpuid() -> bool { i32 regs[4] = {0}; - // Call CPUID with Function 0 (Vendor ID) Platform::cpuid(0, 0, regs); - // EAX (regs[0]) holds max supported function. Should be > 0 on any modern - // CPU. IAT_CHECK(regs[0] >= 0); - // EBX, EDX, ECX hold the vendor string. - // The order for the string is EBX, EDX, ECX. char vendor[13]; std::memset(vendor, 0, 13); - std::memcpy(vendor, ®s[1], 4); // EBX - std::memcpy(vendor + 4, ®s[3], 4); // EDX - std::memcpy(vendor + 8, ®s[2], 4); // ECX + std::memcpy(vendor, ®s[1], 4); + std::memcpy(vendor + 4, ®s[3], 4); + std::memcpy(vendor + 8, ®s[2], 4); vendor[12] = '\0'; const String vendor_str(vendor); IAT_CHECK(!vendor_str.empty()); - // Check against common vendors to ensure registers contained valid ASCII bool is_known = (vendor_str == "GenuineIntel" || vendor_str == "AuthenticAMD" || vendor_str == "KVMKVMKVM" || vendor_str == "Microsoft Hv" || vendor_str == "VBoxVBoxVBox"); if (!is_known) { - // Not a failure, just an unknown CPU vendor (or virtualization) + std::cout << " [Info] Unknown CPU Vendor: " << vendor_str << "\n"; } @@ -126,9 +105,6 @@ auto test_cpuid() -> bool { } #endif -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_os_name); IAT_ADD_TEST(test_arch_name); diff --git a/Tests/Unit/ProcessOps.cpp b/Tests/Unit/ProcessOps.cpp index b757543..d3206a7 100644 --- a/Tests/Unit/ProcessOps.cpp +++ b/Tests/Unit/ProcessOps.cpp @@ -18,9 +18,6 @@ using namespace IACore; -// ----------------------------------------------------------------------------- -// Platform Abstraction for Test Commands -// ----------------------------------------------------------------------------- #if IA_PLATFORM_WINDOWS #define CMD_ECHO_EXE "cmd.exe" #define CMD_ARG_PREFIX "/c echo" @@ -33,11 +30,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, ProcessOps) -// ------------------------------------------------------------------------- -// 1. Basic Execution (Exit Code 0) -// ------------------------------------------------------------------------- auto test_basic_run() -> bool { - // Simple "echo hello" + String captured; const auto result = @@ -45,26 +39,19 @@ auto test_basic_run() -> bool { [&](StringView line) { captured = line; }); IAT_CHECK(result.has_value()); - IAT_CHECK_EQ(*result, 0); // Exit code 0 + IAT_CHECK_EQ(*result, 0); - // We check if "HelloIA" is contained or equal. IAT_CHECK(captured.find("HelloIA") != String::npos); return true; } -// ------------------------------------------------------------------------- -// 2. Argument Parsing -// ------------------------------------------------------------------------- auto test_arguments() -> bool { Vec lines; - // Echo two distinct words. - // Windows: cmd.exe /c echo one two - // Linux: /bin/echo one two String args = String(CMD_ARG_PREFIX) + " one two"; if (!args.empty() && args[0] == ' ') { - args.erase(0, 1); // cleanup space if prefix empty + args.erase(0, 1); } const auto result = @@ -75,19 +62,12 @@ auto test_arguments() -> bool { IAT_CHECK_EQ(*result, 0); IAT_CHECK(lines.size() > 0); - // Output should contain "one two" IAT_CHECK(lines[0].find("one two") != String::npos); return true; } -// ------------------------------------------------------------------------- -// 3. Error / Non-Zero Exit Codes -// ------------------------------------------------------------------------- auto test_exit_codes() -> bool { - // We need a command that returns non-zero. - // Windows: cmd /c exit 1 - // Linux: /bin/sh -c "exit 1" String cmd; String arg; @@ -97,7 +77,7 @@ auto test_exit_codes() -> bool { arg = "/c exit 42"; #else cmd = "/bin/sh"; - arg = "-c \"exit 42\""; // quotes needed for sh -c + arg = "-c \"exit 42\""; #endif const auto result = @@ -109,21 +89,15 @@ auto test_exit_codes() -> bool { return true; } -// ------------------------------------------------------------------------- -// 4. Missing Executable Handling -// ------------------------------------------------------------------------- auto test_missing_exe() -> bool { - // Try to run a random string + const auto result = ProcessOps::spawn_process_sync("sdflkjghsdflkjg", "", [](StringView) {}); - // Windows: CreateProcess usually fails -> returns unexpected - // Linux: execvp fails inside child, returns 127 via waitpid - #if IA_PLATFORM_WINDOWS - IAT_CHECK_NOT(result.has_value()); // Should be an error string + IAT_CHECK_NOT(result.has_value()); #else - // Linux fork succeeds, but execvp fails, returning 127 + IAT_CHECK(result.has_value()); IAT_CHECK_EQ(*result, 127); #endif @@ -131,18 +105,12 @@ auto test_missing_exe() -> bool { return true; } -// ------------------------------------------------------------------------- -// 5. Line Buffer Logic (The 4096 split test) -// ------------------------------------------------------------------------- auto test_large_output() -> bool { - // Need to generate output larger than the internal 4096 buffer - // to ensure the "partial line" logic works when a line crosses a buffer - // boundary. String massive_string; massive_string.reserve(5000); for (i32 i = 0; i < 500; ++i) { - massive_string += "1234567890"; // 5000 chars + massive_string += "1234567890"; } String cmd; @@ -150,7 +118,7 @@ auto test_large_output() -> bool { #if IA_PLATFORM_WINDOWS cmd = "cmd.exe"; - // Windows has command line length limits (~8k), 5k is safe. + arg = "/c echo " + massive_string; #else cmd = "/bin/echo"; @@ -164,19 +132,12 @@ auto test_large_output() -> bool { IAT_CHECK(result.has_value()); IAT_CHECK_EQ(*result, 0); - // If the LineBuffer failed to stitch chunks, the length wouldn't match - // or we would get multiple callbacks if we expected 1 line. IAT_CHECK_EQ(captured.length(), massive_string.length()); return true; } -// ------------------------------------------------------------------------- -// 6. Multi-Line Handling -// ------------------------------------------------------------------------- auto test_multi_line() -> bool { - // Windows: cmd /c "echo A && echo B" - // Linux: /bin/sh -c "echo A; echo B" String cmd; String arg; @@ -206,22 +167,14 @@ auto test_multi_line() -> bool { IAT_CHECK(found_a); IAT_CHECK(found_b); - // We expect at least 2 lines. - // (Windows sometimes echoes the command itself depending on echo settings, - // but we check contents) + IAT_CHECK(line_count >= 2); return true; } -// ------------------------------------------------------------------------- -// 6. Complex Command Line Arguments Handling -// ------------------------------------------------------------------------- auto test_complex_arguments() -> bool { - // Should parse as 3 arguments: - // 1. -DDEFINED_MSG="Hello World" - // 2. -v - // 3. path/to/file + const String complex_args = "-DDEFINED_MSG=\\\"Hello World\\\" -v path/to/file"; @@ -241,14 +194,10 @@ auto test_complex_arguments() -> bool { IAT_CHECK(result.has_value()); IAT_CHECK_EQ(*result, 0); - // Verify the quotes were preserved in the output IAT_CHECK(captured.find("Hello World") != String::npos); return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_basic_run); IAT_ADD_TEST(test_arguments); diff --git a/Tests/Unit/RingBuffer.cpp b/Tests/Unit/RingBuffer.cpp index 3db86fa..698d52c 100644 --- a/Tests/Unit/RingBuffer.cpp +++ b/Tests/Unit/RingBuffer.cpp @@ -20,31 +20,23 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, RingBuffer) -// ------------------------------------------------------------------------- -// 1. Basic Push Pop -// ------------------------------------------------------------------------- auto test_push_pop() -> bool { - // Allocate raw memory for the ring buffer - // ControlBlock (128 bytes) + Data + Vec memory(sizeof(RingBufferView::ControlBlock) + 1024); - // Initialize as OWNER (Producer) auto producer_res = RingBufferView::create(Span(memory), true); IAT_CHECK(producer_res.has_value()); auto producer = std::move(*producer_res); - // Initialize as CONSUMER (Pointer to same memory) auto consumer_res = RingBufferView::create(Span(memory), false); IAT_CHECK(consumer_res.has_value()); auto consumer = std::move(*consumer_res); - // Data to send String msg = "Hello RingBuffer"; const auto push_res = producer.push( 1, Span(reinterpret_cast(msg.data()), msg.size())); IAT_CHECK(push_res.has_value()); - // Read back RingBufferView::PacketHeader header; u8 read_buf[128]; @@ -65,38 +57,28 @@ auto test_push_pop() -> bool { return true; } -// ------------------------------------------------------------------------- -// 2. Wrap Around -// ------------------------------------------------------------------------- auto test_wrap_around() -> bool { - // Small buffer to force wrapping quickly - // Capacity will be 100 bytes + Vec memory(sizeof(RingBufferView::ControlBlock) + 100); auto rb_res = RingBufferView::create(Span(memory), true); IAT_CHECK(rb_res.has_value()); auto rb = std::move(*rb_res); - // Fill buffer to near end - // Push 80 bytes Vec junk(80, 0xFF); const auto push1 = rb.push(1, junk); IAT_CHECK(push1.has_value()); - // Pop them to advance READ cursor RingBufferView::PacketHeader header; u8 out_buf[100]; const auto pop1 = rb.pop(header, out_buf); IAT_CHECK(pop1.has_value()); IAT_CHECK(pop1->has_value()); - // Now READ and WRITE are near index 80. - // Pushing 40 bytes should trigger a wrap-around (split write) Vec wrap_data(40, 0xAA); const auto push2 = rb.push(2, wrap_data); IAT_CHECK(push2.has_value()); - // Pop and verify integrity const auto pop2 = rb.pop(header, out_buf); IAT_CHECK(pop2.has_value()); IAT_CHECK(pop2->has_value()); @@ -104,7 +86,6 @@ auto test_wrap_around() -> bool { const usize pop_size = *pop2.value(); IAT_CHECK_EQ(pop_size, static_cast(40)); - // Check if data is intact bool match = true; for (usize i = 0; i < 40; i++) { if (out_buf[i] != 0xAA) { diff --git a/Tests/Unit/SocketOps.cpp b/Tests/Unit/SocketOps.cpp index 5191b7e..0701b9c 100644 --- a/Tests/Unit/SocketOps.cpp +++ b/Tests/Unit/SocketOps.cpp @@ -20,82 +20,56 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, SocketOps) -// ------------------------------------------------------------------------- -// 1. Initialization Logic -// ------------------------------------------------------------------------- auto test_initialization() -> bool { IAT_CHECK(SocketOps::is_initialized()); - // Increment ref count const auto res = SocketOps::initialize(); IAT_CHECK(res.has_value()); - // Decrement ref count SocketOps::terminate(); - // Should still be initialized (ref count > 0) IAT_CHECK(SocketOps::is_initialized()); return true; } -// ------------------------------------------------------------------------- -// 2. Port Availability Checks -// ------------------------------------------------------------------------- auto test_port_availability() -> bool { - // We cannot easily guarantee a port is free or taken without binding it, - // and SocketOps doesn't expose a generic TCP bind in its public API - // (only Unix sockets). - // However, we can verify the functions execute without crashing. const u16 port = 54321; - // These return bools, we just ensure they run. (void)SocketOps::is_port_available_tcp(port); (void)SocketOps::is_port_available_udp(port); return true; } -// ------------------------------------------------------------------------- -// 3. Unix Domain Socket Lifecycle (Create, Bind, Listen, Connect) -// ------------------------------------------------------------------------- auto test_unix_socket_lifecycle() -> bool { const String socket_path = "iatest_ipc.sock"; - // Ensure clean state SocketOps::unlink_file(socket_path.c_str()); - // 1. Create Server Socket auto server_res = SocketOps::create_unix_socket(); IAT_CHECK(server_res.has_value()); SocketHandle server = *server_res; - // 2. Bind auto bind_res = SocketOps::bind_unix_socket(server, socket_path.c_str()); if (!bind_res) { - // If bind fails (e.g. permissions), we clean up and fail the test + SocketOps::close(server); return false; } - // 3. Listen auto listen_res = SocketOps::listen(server); IAT_CHECK(listen_res.has_value()); - // 4. Create Client Socket auto client_res = SocketOps::create_unix_socket(); IAT_CHECK(client_res.has_value()); SocketHandle client = *client_res; - // 5. Connect - // Note: This relies on the OS backlog. We aren't calling accept() on the - // server, but connect() should succeed if the server is listening. auto connect_res = SocketOps::connect_unix_socket(client, socket_path.c_str()); IAT_CHECK(connect_res.has_value()); - // 6. Cleanup SocketOps::close(client); SocketOps::close(server); SocketOps::unlink_file(socket_path.c_str()); @@ -103,20 +77,15 @@ auto test_unix_socket_lifecycle() -> bool { return true; } -// ------------------------------------------------------------------------- -// 4. Unix Socket Error Handling -// ------------------------------------------------------------------------- auto test_unix_socket_errors() -> bool { const String socket_path = "iatest_missing.sock"; - // Ensure it doesn't exist SocketOps::unlink_file(socket_path.c_str()); auto client_res = SocketOps::create_unix_socket(); IAT_CHECK(client_res.has_value()); SocketHandle client = *client_res; - // Should fail to connect to non-existent file auto connect_res = SocketOps::connect_unix_socket(client, socket_path.c_str()); IAT_CHECK_NOT(connect_res.has_value()); @@ -126,9 +95,6 @@ auto test_unix_socket_errors() -> bool { return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_initialization); IAT_ADD_TEST(test_port_availability); diff --git a/Tests/Unit/StreamReader.cpp b/Tests/Unit/StreamReader.cpp index 3283030..4062a98 100644 --- a/Tests/Unit/StreamReader.cpp +++ b/Tests/Unit/StreamReader.cpp @@ -20,20 +20,15 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, StreamReader) -// ------------------------------------------------------------------------- -// 1. Basic Primitive Reading (u8) -// ------------------------------------------------------------------------- auto test_read_uint8() -> bool { u8 data[] = {0xAA, 0xBB, 0xCC}; StreamReader reader(data); - // Read First Byte auto val1 = reader.read(); IAT_CHECK(val1.has_value()); IAT_CHECK_EQ(*val1, 0xAA); IAT_CHECK_EQ(reader.cursor(), static_cast(1)); - // Read Second Byte auto val2 = reader.read(); IAT_CHECK(val2.has_value()); IAT_CHECK_EQ(*val2, 0xBB); @@ -41,12 +36,8 @@ auto test_read_uint8() -> bool { return true; } -// ------------------------------------------------------------------------- -// 2. Multi-byte Reading (Endianness check) -// ------------------------------------------------------------------------- auto test_read_multi_byte() -> bool { - // 0x04030201 in Little Endian memory layout - // IACore always assumes a Little Endian machine + u8 data[] = {0x01, 0x02, 0x03, 0x04}; StreamReader reader(data); @@ -61,12 +52,9 @@ auto test_read_multi_byte() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. Floating Point (Approx check) -// ------------------------------------------------------------------------- auto test_read_float() -> bool { const f32 pi = 3.14159f; - // Bit-cast float to bytes for setup + u8 data[4]; std::memcpy(data, &pi, 4); @@ -79,49 +67,37 @@ auto test_read_float() -> bool { return true; } -// ------------------------------------------------------------------------- -// 4. Batch Buffer Reading -// ------------------------------------------------------------------------- auto test_read_buffer() -> bool { u8 src[] = {1, 2, 3, 4, 5}; u8 dst[3] = {0}; StreamReader reader(src); - // Read 3 bytes into dst const auto res = reader.read(dst, 3); IAT_CHECK(res.has_value()); - // Verify dst content IAT_CHECK_EQ(dst[0], 1); IAT_CHECK_EQ(dst[1], 2); IAT_CHECK_EQ(dst[2], 3); - // Verify cursor IAT_CHECK_EQ(reader.cursor(), static_cast(3)); return true; } -// ------------------------------------------------------------------------- -// 5. Navigation (Seek, Skip, Remaining) -// ------------------------------------------------------------------------- auto test_navigation() -> bool { - u8 data[10] = {0}; // Zero init + u8 data[10] = {0}; StreamReader reader(data); IAT_CHECK_EQ(reader.remaining(), static_cast(10)); - // Skip reader.skip(5); IAT_CHECK_EQ(reader.cursor(), static_cast(5)); IAT_CHECK_EQ(reader.remaining(), static_cast(5)); - // Skip clamping - reader.skip(100); // Should clamp to 10 + reader.skip(100); IAT_CHECK_EQ(reader.cursor(), static_cast(10)); IAT_CHECK(reader.is_eof()); - // Seek reader.seek(2); IAT_CHECK_EQ(reader.cursor(), static_cast(2)); IAT_CHECK_EQ(reader.remaining(), static_cast(8)); @@ -130,22 +106,16 @@ auto test_navigation() -> bool { return true; } -// ------------------------------------------------------------------------- -// 6. Error Handling (EOF Protection) -// ------------------------------------------------------------------------- auto test_boundary_checks() -> bool { u8 data[] = {0x00, 0x00}; StreamReader reader(data); - // Valid read (void)reader.read(); IAT_CHECK(reader.is_eof()); - // Invalid Read Primitive auto val = reader.read(); - IAT_CHECK_NOT(val.has_value()); // Should be unexpected + IAT_CHECK_NOT(val.has_value()); - // Invalid Batch Read u8 buf[1]; auto batch = reader.read(buf, 1); IAT_CHECK_NOT(batch.has_value()); @@ -153,9 +123,6 @@ auto test_boundary_checks() -> bool { return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_read_uint8); IAT_ADD_TEST(test_read_multi_byte); diff --git a/Tests/Unit/StreamWriter.cpp b/Tests/Unit/StreamWriter.cpp index c74bc6f..75547db 100644 --- a/Tests/Unit/StreamWriter.cpp +++ b/Tests/Unit/StreamWriter.cpp @@ -21,24 +21,16 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, StreamWriter) -// ------------------------------------------------------------------------- -// 1. Memory Writer (Dynamic Vector) -// ------------------------------------------------------------------------- auto test_memory_writer() -> bool { StreamWriter writer; - // Write single byte repeated IAT_CHECK(writer.write(static_cast(0xAA), 1).has_value()); - // Write primitive (u32) - 0x12345678 - // Little Endian: 78 56 34 12 const u32 val = 0x12345678; IAT_CHECK(writer.write(val).has_value()); - // Check cursor IAT_CHECK_EQ(writer.cursor(), static_cast(1 + 4)); - // Check data content const u8 *ptr = writer.data(); IAT_CHECK_EQ(ptr[0], 0xAA); IAT_CHECK_EQ(ptr[1], 0x78); @@ -47,26 +39,19 @@ auto test_memory_writer() -> bool { return true; } -// ------------------------------------------------------------------------- -// 2. Fixed Buffer Writer (Non-Owning) -// ------------------------------------------------------------------------- auto test_fixed_buffer() -> bool { u8 buffer[4] = {0}; StreamWriter writer(Span(buffer, 4)); - // Write 2 bytes IAT_CHECK(writer.write(static_cast(0xFF), 2).has_value()); IAT_CHECK_EQ(writer.cursor(), static_cast(2)); - // Write 2 more bytes IAT_CHECK(writer.write(static_cast(0xEE), 2).has_value()); IAT_CHECK_EQ(writer.cursor(), static_cast(4)); - // Write 1 more byte -> Should fail (Out of bounds) const auto res = writer.write(static_cast(0x00), 1); IAT_CHECK_NOT(res.has_value()); - // Verify content IAT_CHECK_EQ(buffer[0], 0xFF); IAT_CHECK_EQ(buffer[1], 0xFF); IAT_CHECK_EQ(buffer[2], 0xEE); @@ -75,13 +60,9 @@ auto test_fixed_buffer() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. File Writer -// ------------------------------------------------------------------------- auto test_file_writer() -> bool { const Path path = "test_stream_writer.bin"; - // Ensure clean state if (std::filesystem::exists(path)) { std::filesystem::remove(path); } @@ -94,11 +75,9 @@ auto test_file_writer() -> bool { const String hello = "Hello World"; IAT_CHECK(writer.write(hello.data(), hello.size()).has_value()); - // Explicit flush IAT_CHECK(writer.flush().has_value()); } - // Verify file content via FileOps auto read_res = FileOps::read_binary_file(path); IAT_CHECK(read_res.has_value()); @@ -106,15 +85,11 @@ auto test_file_writer() -> bool { read_res->size()); IAT_CHECK_EQ(read_str, String("Hello World")); - // Cleanup std::filesystem::remove(path); return true; } -// ------------------------------------------------------------------------- -// 4. Primitive Types -// ------------------------------------------------------------------------- auto test_primitives() -> bool { StreamWriter writer; @@ -129,9 +104,6 @@ auto test_primitives() -> bool { return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_memory_writer); IAT_ADD_TEST(test_fixed_buffer); diff --git a/Tests/Unit/StringOps.cpp b/Tests/Unit/StringOps.cpp index 12f0d42..5bb222b 100644 --- a/Tests/Unit/StringOps.cpp +++ b/Tests/Unit/StringOps.cpp @@ -20,11 +20,8 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, StringOps) -// ------------------------------------------------------------------------- -// 1. Base64 Encoding -// ------------------------------------------------------------------------- auto test_base64_encode() -> bool { - // Case 1: Standard text + { const String s = "Hello World"; const Span data(reinterpret_cast(s.data()), s.size()); @@ -32,7 +29,6 @@ auto test_base64_encode() -> bool { IAT_CHECK_EQ(encoded, String("SGVsbG8gV29ybGQ=")); } - // Case 2: Padding Logic (1 byte -> 2 pad) { const String s = "M"; const Span data(reinterpret_cast(s.data()), s.size()); @@ -40,7 +36,6 @@ auto test_base64_encode() -> bool { IAT_CHECK_EQ(encoded, String("TQ==")); } - // Case 3: Padding Logic (2 bytes -> 1 pad) { const String s = "Ma"; const Span data(reinterpret_cast(s.data()), s.size()); @@ -48,7 +43,6 @@ auto test_base64_encode() -> bool { IAT_CHECK_EQ(encoded, String("TWE=")); } - // Case 4: Padding Logic (3 bytes -> 0 pad) { const String s = "Man"; const Span data(reinterpret_cast(s.data()), s.size()); @@ -56,7 +50,6 @@ auto test_base64_encode() -> bool { IAT_CHECK_EQ(encoded, String("TWFu")); } - // Case 5: Empty { const String encoded = StringOps::encode_base64({}); IAT_CHECK(encoded.empty()); @@ -65,11 +58,8 @@ auto test_base64_encode() -> bool { return true; } -// ------------------------------------------------------------------------- -// 2. Base64 Decoding -// ------------------------------------------------------------------------- auto test_base64_decode() -> bool { - // Case 1: Standard text + { const String encoded = "SGVsbG8gV29ybGQ="; const Vec decoded = StringOps::decode_base64(encoded); @@ -78,7 +68,6 @@ auto test_base64_decode() -> bool { IAT_CHECK_EQ(result, String("Hello World")); } - // Case 2: Empty { const Vec decoded = StringOps::decode_base64(""); IAT_CHECK(decoded.empty()); @@ -87,9 +76,6 @@ auto test_base64_decode() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. Round Trip (Binary Data) -// ------------------------------------------------------------------------- auto test_base64_round_trip() -> bool { Vec original; original.reserve(256); diff --git a/Tests/Unit/Utils.cpp b/Tests/Unit/Utils.cpp index 8ffca62..7c7be36 100644 --- a/Tests/Unit/Utils.cpp +++ b/Tests/Unit/Utils.cpp @@ -18,53 +18,35 @@ using namespace IACore; -// ----------------------------------------------------------------------------- -// Test Structs for Hashing (Must be defined at Global Scope) -// ----------------------------------------------------------------------------- - struct TestVec3 { f32 x, y, z; - // Equality operator required for hash maps, though strictly - // the hash function itself doesn't need it, it's good practice to test both. bool operator==(const TestVec3 &other) const { return x == other.x && y == other.y && z == other.z; } }; -// Inject the hash specialization into the ankerl namespace -// This proves the macro works structurally IA_MAKE_HASHABLE(TestVec3, &TestVec3::x, &TestVec3::y, &TestVec3::z); -// ----------------------------------------------------------------------------- -// Test Block Definition -// ----------------------------------------------------------------------------- - IAT_BEGIN_BLOCK(Core, Utils) -// ------------------------------------------------------------------------- -// 1. Binary <-> Hex String Conversion -// ------------------------------------------------------------------------- auto test_hex_conversion() -> bool { - // A. Binary To Hex + u8 bin[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0xFF}; String hex = Utils::binary_to_hex_string(bin); IAT_CHECK_EQ(hex, String("DEADBEEF00FF")); - // B. Hex To Binary (Valid Upper) auto res_upper = Utils::hex_string_to_binary("DEADBEEF00FF"); IAT_CHECK(res_upper.has_value()); IAT_CHECK_EQ(res_upper->size(), static_cast(6)); IAT_CHECK_EQ((*res_upper)[0], 0xDE); IAT_CHECK_EQ((*res_upper)[5], 0xFF); - // C. Hex To Binary (Valid Lower/Mixed) auto res_lower = Utils::hex_string_to_binary("deadbeef00ff"); IAT_CHECK(res_lower.has_value()); IAT_CHECK_EQ((*res_lower)[0], 0xDE); - // D. Round Trip Integrity Vec original = {1, 2, 3, 4, 5}; String s = Utils::binary_to_hex_string(original); auto back = Utils::hex_string_to_binary(s); @@ -75,19 +57,14 @@ auto test_hex_conversion() -> bool { return true; } -// ------------------------------------------------------------------------- -// 2. Hex Error Handling -// ------------------------------------------------------------------------- auto test_hex_errors() -> bool { - // Odd Length + auto odd = Utils::hex_string_to_binary("ABC"); IAT_CHECK_NOT(odd.has_value()); - // Invalid Characters auto invalid = Utils::hex_string_to_binary("ZZTOP"); IAT_CHECK_NOT(invalid.has_value()); - // Empty string is valid (empty vector) auto empty = Utils::hex_string_to_binary(""); IAT_CHECK(empty.has_value()); IAT_CHECK_EQ(empty->size(), static_cast(0)); @@ -95,9 +72,6 @@ auto test_hex_errors() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. Algorithms: Sorting -// ------------------------------------------------------------------------- auto test_sort() -> bool { Vec nums = {5, 1, 4, 2, 3}; @@ -112,48 +86,35 @@ auto test_sort() -> bool { return true; } -// ------------------------------------------------------------------------- -// 4. Algorithms: Binary Search (Left/Right) -// ------------------------------------------------------------------------- auto test_binary_search() -> bool { - // Must be sorted for Binary Search + Vec nums = {10, 20, 20, 20, 30}; - // Search Left (Lower Bound) -> First element >= value auto it_left = Utils::binary_search_left(nums, 20); IAT_CHECK(it_left != nums.end()); IAT_CHECK_EQ(*it_left, 20); - IAT_CHECK_EQ(std::distance(nums.begin(), it_left), 1); // Index 1 is first 20 + IAT_CHECK_EQ(std::distance(nums.begin(), it_left), 1); - // Search Right (Upper Bound) -> First element > value auto it_right = Utils::binary_search_right(nums, 20); IAT_CHECK(it_right != nums.end()); - IAT_CHECK_EQ(*it_right, 30); // Points to 30 - IAT_CHECK_EQ(std::distance(nums.begin(), it_right), 4); // Index 4 + IAT_CHECK_EQ(*it_right, 30); + IAT_CHECK_EQ(std::distance(nums.begin(), it_right), 4); - // Search for non-existent auto it_fail = Utils::binary_search_left(nums, 99); IAT_CHECK(it_fail == nums.end()); return true; } -// ------------------------------------------------------------------------- -// 5. Hashing Basics -// ------------------------------------------------------------------------- auto test_hash_basics() -> bool { u64 h1 = Utils::compute_hash(10, 20.5f, "Hello"); u64 h2 = Utils::compute_hash(10, 20.5f, "Hello"); u64 h3 = Utils::compute_hash(10, 20.5f, "World"); - // Determinism IAT_CHECK_EQ(h1, h2); - // Differentiation IAT_CHECK_NEQ(h1, h3); - // Order sensitivity (Golden ratio combine should care about order) - // Hash(A, B) != Hash(B, A) u64 order_a = Utils::compute_hash(1, 2); u64 order_b = Utils::compute_hash(2, 1); IAT_CHECK_NEQ(order_a, order_b); @@ -161,9 +122,6 @@ auto test_hash_basics() -> bool { return true; } -// ------------------------------------------------------------------------- -// 6. Macro Verification (IA_MAKE_HASHABLE) -// ------------------------------------------------------------------------- auto test_hash_macro() -> bool { TestVec3 v1{1.0f, 2.0f, 3.0f}; TestVec3 v2{1.0f, 2.0f, 3.0f}; @@ -175,30 +133,21 @@ auto test_hash_macro() -> bool { u64 h2 = hasher(v2); u64 h3 = hasher(v3); - IAT_CHECK_EQ(h1, h2); // Same content = same hash - IAT_CHECK_NEQ(h1, h3); // Different content = different hash - - // ------------------------------------------------------------- - // Verify ComputeHash integration - // ------------------------------------------------------------- + IAT_CHECK_EQ(h1, h2); + IAT_CHECK_NEQ(h1, h3); u64 h_manual = 0; Utils::hash_combine(h_manual, v1); u64 h_wrapper = Utils::compute_hash(v1); - // This proves ComputeHash found the specialization and mixed it correctly IAT_CHECK_EQ(h_manual, h_wrapper); - // Verify the avalanche effect took place (hWrapper should NOT be h1) IAT_CHECK_NEQ(h1, h_wrapper); return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_hex_conversion); IAT_ADD_TEST(test_hex_errors); diff --git a/Tests/Unit/XML.cpp b/Tests/Unit/XML.cpp index ad22837..d5e2f2c 100644 --- a/Tests/Unit/XML.cpp +++ b/Tests/Unit/XML.cpp @@ -21,9 +21,6 @@ using namespace IACore; IAT_BEGIN_BLOCK(Core, XML) -// ------------------------------------------------------------------------- -// 1. Basic String Parsing -// ------------------------------------------------------------------------- auto test_parse_string() -> bool { const String xml_content = R"( @@ -50,9 +47,6 @@ auto test_parse_string() -> bool { return true; } -// ------------------------------------------------------------------------- -// 2. Error Handling -// ------------------------------------------------------------------------- auto test_parse_error() -> bool { const String invalid_xml = ""; auto res = XML::parse_from_string(invalid_xml); @@ -60,9 +54,6 @@ auto test_parse_error() -> bool { return true; } -// ------------------------------------------------------------------------- -// 3. Serialization -// ------------------------------------------------------------------------- auto test_serialize() -> bool { const String xml_content = "Text"; auto res = XML::parse_from_string(xml_content); @@ -70,21 +61,16 @@ auto test_serialize() -> bool { String output = XML::serialize_to_string(*res); - // Basic containment check as formatting might vary IAT_CHECK(output.find("") != String::npos); IAT_CHECK(output.find("Text") != String::npos); return true; } -// ------------------------------------------------------------------------- -// 4. String Escaping -// ------------------------------------------------------------------------- auto test_escape() -> bool { const String raw = "< & > \" '"; const String escaped = XML::escape_xml_string(raw); - // Check for standard XML entities IAT_CHECK(escaped.find("<") != String::npos); IAT_CHECK(escaped.find("&") != String::npos); IAT_CHECK(escaped.find(">") != String::npos); @@ -94,18 +80,13 @@ auto test_escape() -> bool { return true; } -// ------------------------------------------------------------------------- -// 5. File I/O Integration -// ------------------------------------------------------------------------- auto test_file_io() -> bool { const Path path = "test_temp_xml_doc.xml"; const String content = "1.0"; - // 1. Write Test File auto write_res = FileOps::write_text_file(path, content, true); IAT_CHECK(write_res.has_value()); - // 2. Parse from File auto parse_res = XML::parse_from_file(path); IAT_CHECK(parse_res.has_value()); @@ -113,15 +94,11 @@ auto test_file_io() -> bool { IAT_CHECK_EQ(String(doc.child("config").child("ver").child_value()), String("1.0")); - // 3. Cleanup std::filesystem::remove(path); return true; } -// ------------------------------------------------------------------------- -// Registration -// ------------------------------------------------------------------------- IAT_BEGIN_TEST_LIST() IAT_ADD_TEST(test_parse_string); IAT_ADD_TEST(test_parse_error);