From ac993e1cf8ec4c55cbd1e80c7b94ac492d6dc4e8 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss Date: Fri, 6 Mar 2026 06:36:01 +0100 Subject: [FEAT] HeapMgr: Add LockDelegate to allocation calls, and re-introduce double-free prevention. [CHORE] FileMgr: Cleanup and tweaks. [CHORE] ABI: Update copyright year. Signed-off-by: Amlal El Mahrouss --- src/kernel/HALKit/ARM64/CxxAbi.cpp | 2 +- src/kernel/src/FileMgr.cpp | 1 + src/kernel/src/GUIDWizard.cpp | 4 +- src/kernel/src/HeapMgr.cpp | 18 ++- src/libDDK/src/DriverBase.cpp | 1 + test/kernel_test/Makefile | 22 ---- test/kernel_test/error.test.cc | 67 ----------- test/kernel_test/print.test.cc | 73 ------------ test/kernel_test/process.test.cc | 78 ------------- test/kernel_tests/.keep | 0 test/libsystem_test/Makefile | 22 ---- test/libsystem_test/io.test.cc | 155 -------------------------- test/libsystem_test/memory.test.cc | 136 ---------------------- test/libsystem_test/thread.test.cc | 142 ----------------------- test/user_tests/kernel_test/Makefile | 22 ++++ test/user_tests/kernel_test/error.test.cc | 67 +++++++++++ test/user_tests/kernel_test/print.test.cc | 73 ++++++++++++ test/user_tests/kernel_test/process.test.cc | 78 +++++++++++++ test/user_tests/libsystem_test/Makefile | 22 ++++ test/user_tests/libsystem_test/io.test.cc | 155 ++++++++++++++++++++++++++ test/user_tests/libsystem_test/memory.test.cc | 136 ++++++++++++++++++++++ test/user_tests/libsystem_test/thread.test.cc | 142 +++++++++++++++++++++++ 22 files changed, 715 insertions(+), 701 deletions(-) delete mode 100644 test/kernel_test/Makefile delete mode 100644 test/kernel_test/error.test.cc delete mode 100644 test/kernel_test/print.test.cc delete mode 100644 test/kernel_test/process.test.cc create mode 100644 test/kernel_tests/.keep delete mode 100644 test/libsystem_test/Makefile delete mode 100644 test/libsystem_test/io.test.cc delete mode 100644 test/libsystem_test/memory.test.cc delete mode 100644 test/libsystem_test/thread.test.cc create mode 100644 test/user_tests/kernel_test/Makefile create mode 100644 test/user_tests/kernel_test/error.test.cc create mode 100644 test/user_tests/kernel_test/print.test.cc create mode 100644 test/user_tests/kernel_test/process.test.cc create mode 100644 test/user_tests/libsystem_test/Makefile create mode 100644 test/user_tests/libsystem_test/io.test.cc create mode 100644 test/user_tests/libsystem_test/memory.test.cc create mode 100644 test/user_tests/libsystem_test/thread.test.cc diff --git a/src/kernel/HALKit/ARM64/CxxAbi.cpp b/src/kernel/HALKit/ARM64/CxxAbi.cpp index e68d8b14..45c59e9b 100644 --- a/src/kernel/HALKit/ARM64/CxxAbi.cpp +++ b/src/kernel/HALKit/ARM64/CxxAbi.cpp @@ -1,4 +1,4 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Copyright 2024-2026, Amlal El Mahrouss (amlal@nekernel.org) // Licensed under the Apache License, Version 2.0 (see LICENSE file) // Official repository: https://github.com/ne-foss-org/nekernel diff --git a/src/kernel/src/FileMgr.cpp b/src/kernel/src/FileMgr.cpp index 5781760c..91114d8b 100644 --- a/src/kernel/src/FileMgr.cpp +++ b/src/kernel/src/FileMgr.cpp @@ -17,6 +17,7 @@ STATIC IFilesystemMgr* kMountedFilesystem = nullptr; /// @brief FilesystemMgr getter. /// @return The mounted filesystem. _Output IFilesystemMgr* IFilesystemMgr::GetMounted() { + MUST_PASS(kMountedFilesystem); return kMountedFilesystem; } diff --git a/src/kernel/src/GUIDWizard.cpp b/src/kernel/src/GUIDWizard.cpp index d739e6f0..ac3c2f4a 100644 --- a/src/kernel/src/GUIDWizard.cpp +++ b/src/kernel/src/GUIDWizard.cpp @@ -1,4 +1,4 @@ -// Copyright 2024-2025, Amlal El Mahrouss (amlal@nekernel.org) +// Copyright 2024-2026, Amlal El Mahrouss (amlal@nekernel.org) // Licensed under the Apache License, Version 2.0 (see LICENSE file) // Official repository: https://github.com/ne-foss-org/nekernel @@ -37,7 +37,7 @@ auto cf_make_sequence(const Array& uuidSeq) -> Ref { // @brief Tries to make a guid out of a string. // This function is not complete for now auto cf_try_guid_to_string(Ref& seq) -> ErrorOr> { - Char buf[kGUIDSize]; + Char buf[kGUIDSize] = {0}; for (SizeT index = 0; index < 16; ++index) { buf[index] = seq.Leak()->fU8[index] + kGUIDAsciiBegin; diff --git a/src/kernel/src/HeapMgr.cpp b/src/kernel/src/HeapMgr.cpp index 9ebf8e3c..a13bd9c2 100644 --- a/src/kernel/src/HeapMgr.cpp +++ b/src/kernel/src/HeapMgr.cpp @@ -9,6 +9,7 @@ #include #include #include +#include /* ======================================== @@ -82,9 +83,15 @@ STATIC PageMgr kPageMgr; /// @param user User enable bit. /// @return The newly allocated pointer. _Output VoidPtr mm_alloc_ptr(SizeT sz, Bool wr, Bool user, SizeT pad_amount) { + static Bool locked = false; + LockDelegate<255> lock{&locked}; + auto sz_fix = sz; if (sz_fix == 0) return nullptr; + + locked = true; + sz_fix += sizeof(Detail::MM_INFORMATION_BLOCK); auto wrapper = kPageMgr.Request(wr, user, No, sz_fix, pad_amount); @@ -93,7 +100,10 @@ _Output VoidPtr mm_alloc_ptr(SizeT sz, Bool wr, Bool user, SizeT pad_amount) { reinterpret_cast(wrapper.VirtualAddress() + sizeof(Detail::MM_INFORMATION_BLOCK)); - if (!heap_info_ptr) return nullptr; + if (!heap_info_ptr) { + locked = false; + return nullptr; + } heap_info_ptr->fSize = sz_fix; heap_info_ptr->fMagic = kHeapMgrMagic; @@ -114,6 +124,8 @@ _Output VoidPtr mm_alloc_ptr(SizeT sz, Bool wr, Bool user, SizeT pad_amount) { (Void)(kout << "HeapMgr: Registered heap address: " << hex_number(reinterpret_cast(heap_info_ptr)) << kendl); + locked = false; + return result; } @@ -198,6 +210,8 @@ _Output Int32 mm_free_ptr(VoidPtr heap_ptr) { kPageMgr.Free(pte_address); return kErrorSuccess; + } else { + ke_panic(RUNTIME_CHECK_TLS, "Double-Free Detected on HeapMgr, aborting."); } return kErrorInternal; @@ -227,9 +241,7 @@ _Output Boolean mm_protect_ptr(VoidPtr heap_ptr) { reinterpret_cast((UIntPtr) heap_ptr - sizeof(Detail::MM_INFORMATION_BLOCK)); - /// TODO: if valid, present and is heap header, then compute crc32 if (heap_info_ptr && heap_info_ptr->fPresent && kHeapMgrMagic == heap_info_ptr->fMagic) { - /// TODO: Protect only the header, information in it may change. heap_info_ptr->fCRC32 = ke_calculate_crc32((Char*) heap_info_ptr, sizeof(Detail::MM_INFORMATION_BLOCK)); diff --git a/src/libDDK/src/DriverBase.cpp b/src/libDDK/src/DriverBase.cpp index ca222579..2567dd4b 100644 --- a/src/libDDK/src/DriverBase.cpp +++ b/src/libDDK/src/DriverBase.cpp @@ -4,3 +4,4 @@ #include + diff --git a/test/kernel_test/Makefile b/test/kernel_test/Makefile deleted file mode 100644 index c4057a5e..00000000 --- a/test/kernel_test/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -################################################## -# (c) Amlal El Mahrouss and NeKernel Authors, licensed under the Apache 2.0 license. -# This file is for kernel testing. -################################################## - -GCC=x86_64-w64-mingw32-g++ -Wl,-subsystem=17 -LIB=-L../../src/libSystem -lSystem -STD=-std=c++20 -DKT_TESTING_ENABLED -INCLUDE=-I../../src -I../../public -I../../public/frameworks/ -I../../ - -OBJ_FILES = \ - error.test.exe \ - print.test.exe \ - process.test.exe - -.PHONY: all -all: $(OBJ_FILES) - -%.exe: %.cc - @echo "==> Building test: $@" - $(GCC) $(LIB) $< \ - $(STD) $(INCLUDE) -o $(basename $<).exe \ No newline at end of file diff --git a/test/kernel_test/error.test.cc b/test/kernel_test/error.test.cc deleted file mode 100644 index ece8f71d..00000000 --- a/test/kernel_test/error.test.cc +++ /dev/null @@ -1,67 +0,0 @@ -/// \file error.test.cc -/// \brief Error handling API tests. -/// \author Amlal El Mahrouss (amlal at nekernel dot org) - -#include -#include - -/// \note ErrGetLastError tests -KT_DECL_TEST(ErrGetLastErrorInitial, []() -> bool { - SInt32 error = ErrGetLastError(); - return error >= 0; -}); - -KT_DECL_TEST(ErrGetLastErrorAfterSuccess, []() -> bool { - auto heap = MmCreateHeap(1024, 0); - if (!heap) return NO; - - SInt32 error = ErrGetLastError(); - MmDestroyHeap(heap); - - return error == 0; -}); - -KT_DECL_TEST(ErrGetLastErrorAfterFailure, []() -> bool { - auto heap = MmCreateHeap(0, 0); - - SInt32 error = ErrGetLastError(); - - return error != 0; -}); - -KT_DECL_TEST(ErrGetLastErrorAfterInvalidFile, []() -> bool { - auto file = IoOpenFile("/invalid/path/that/does/not/exist", nullptr); - - SInt32 error = ErrGetLastError(); - - if (file) IoCloseFile(file); - - return error != 0; -}); - -KT_DECL_TEST(ErrGetLastErrorAfterNullOp, []() -> bool { - auto ptr = MmCopyMemory(nullptr, nullptr, 10); - - SInt32 error = ErrGetLastError(); - - return error != 0; -}); - -KT_DECL_TEST(ErrGetLastErrorMultipleCalls, []() -> bool { - SInt32 error1 = ErrGetLastError(); - SInt32 error2 = ErrGetLastError(); - - return error1 == error2; -}); - -/// \brief Run error tests. -IMPORT_C SInt32 KT_TEST_MAIN() { - KT_RUN_TEST(ErrGetLastErrorInitial); - KT_RUN_TEST(ErrGetLastErrorAfterSuccess); - KT_RUN_TEST(ErrGetLastErrorAfterFailure); - KT_RUN_TEST(ErrGetLastErrorAfterInvalidFile); - KT_RUN_TEST(ErrGetLastErrorAfterNullOp); - KT_RUN_TEST(ErrGetLastErrorMultipleCalls); - - return KT_TEST_SUCCESS; -} diff --git a/test/kernel_test/print.test.cc b/test/kernel_test/print.test.cc deleted file mode 100644 index 4f9bc828..00000000 --- a/test/kernel_test/print.test.cc +++ /dev/null @@ -1,73 +0,0 @@ -/// \file kout.test.cc -/// \brief Konsole Out tests. - -#include -#include - -/// \note PrintGet tests -KT_DECL_TEST(PrintIsNull, []() -> bool { return PrintGet("/null/") == nullptr; }); -KT_DECL_TEST(PrintIsNotNull, []() -> bool { return PrintGet(nullptr) != nullptr; }); - -/// \note PrintCreate/PrintRelease tests -KT_DECL_TEST(PrintCreateValid, []() -> bool { - auto handle = PrintCreate(); - if (!handle) return NO; - PrintRelease(handle); - return YES; -}); - -KT_DECL_TEST(PrintReleaseValid, []() -> bool { - auto handle = PrintCreate(); - if (!handle) return NO; - return PrintRelease(handle) == 0; -}); - -KT_DECL_TEST(PrintReleaseNull, []() -> bool { return PrintRelease(nullptr) != 0; }); - -/// \note PrintOut tests -KT_DECL_TEST(PrintOutValid, []() -> bool { - SInt32 result = PrintOut(nullptr, "Test output\n"); - return result >= 0; -}); - -KT_DECL_TEST(PrintOutWithHandle, []() -> bool { - auto handle = PrintCreate(); - SInt32 result = PrintOut(handle, "Test with handle\n"); - PrintRelease(handle); - return result >= 0; -}); - -KT_DECL_TEST(PrintOutNull, []() -> bool { - SInt32 result = PrintOut(nullptr, nullptr); - return result < 0; -}); - -KT_DECL_TEST(PrintOutFormatted, []() -> bool { - SInt32 result = PrintOut(nullptr, "Value: %d\n", 42); - return result >= 0; -}); - -/// \note PrintIn tests -KT_DECL_TEST(PrintInValid, []() -> bool { - SInt32 result = PrintIn(nullptr, "Input prompt: "); - return result >= 0; -}); - -/// \brief Run 'kout' test. -SInt32 KT_TEST_MAIN() { - KT_RUN_TEST(PrintIsNull); - KT_RUN_TEST(PrintIsNotNull); - - KT_RUN_TEST(PrintCreateValid); - KT_RUN_TEST(PrintReleaseValid); - KT_RUN_TEST(PrintReleaseNull); - - KT_RUN_TEST(PrintOutValid); - KT_RUN_TEST(PrintOutWithHandle); - KT_RUN_TEST(PrintOutNull); - KT_RUN_TEST(PrintOutFormatted); - - KT_RUN_TEST(PrintInValid); - - return KT_TEST_SUCCESS; -} diff --git a/test/kernel_test/process.test.cc b/test/kernel_test/process.test.cc deleted file mode 100644 index 2ec7d191..00000000 --- a/test/kernel_test/process.test.cc +++ /dev/null @@ -1,78 +0,0 @@ -/// \file process.test.cc -/// \brief Process management tests. -/// \author Amlal El Mahrouss (amlal at nekernel dot org) - -#include -#include - -/// \note RtlSpawnProcess tests -KT_DECL_TEST(ProcessHasFailed, []() -> bool { - /// \todo we return -1 here, should we document that or classify as common knowledge? - return RtlSpawnProcess("/", 0, nullptr, nullptr, 0) == -1; -}); - -KT_DECL_TEST(ProcessHasSucceeded, []() -> bool { - /// \note Any process greater than zero, exists within a specific team domain (real-time, high, or - /// low domains). - return RtlSpawnProcess("/system/list", 0, nullptr, nullptr, 0) > 0; -}); - -KT_DECL_TEST(ProcessSpawnNullPath, - []() -> bool { return RtlSpawnProcess(nullptr, 0, nullptr, nullptr, 0) == -1; }); - -KT_DECL_TEST(ProcessSpawnInvalidPath, []() -> bool { - return RtlSpawnProcess("/invalid/nonexistent", 0, nullptr, nullptr, 0) == -1; -}); - -/// \note RtlSpawnIB tests -KT_DECL_TEST(ProcessSpawnIBValid, []() -> bool { - UIntPtr pid = RtlSpawnProcess("/system/list", 0, nullptr, nullptr, 0); - if (pid <= 0) return NO; - - UInt32 result = RtlSpawnIB(pid); - return result == 0; -}); - -KT_DECL_TEST(ProcessSpawnIBInvalid, []() -> bool { - UInt32 result = RtlSpawnIB(0); - return result > 0; -}); - -/// \note RtlExitProcess tests -KT_DECL_TEST(ProcessExitValid, []() -> bool { - UIntPtr pid = RtlSpawnProcess("/system/list", 0, nullptr, nullptr, 0); - if (pid <= 0) return NO; - - Bool result = RtlExitProcess(pid, 0); - return result == YES; -}); - -KT_DECL_TEST(ProcessExitWithCode, []() -> bool { - UIntPtr pid = RtlSpawnProcess("/system/list", 0, nullptr, nullptr, 0); - if (pid <= 0) return NO; - - Bool result = RtlExitProcess(pid, 42); - return result == YES; -}); - -KT_DECL_TEST(ProcessExitInvalid, []() -> bool { - Bool result = RtlExitProcess(0, 0); - return result == NO; -}); - -/// \brief Run 'process' test. -IMPORT_C SInt32 KT_TEST_MAIN() { - KT_RUN_TEST(ProcessHasFailed); - KT_RUN_TEST(ProcessHasSucceeded); - KT_RUN_TEST(ProcessSpawnNullPath); - KT_RUN_TEST(ProcessSpawnInvalidPath); - - KT_RUN_TEST(ProcessSpawnIBValid); - KT_RUN_TEST(ProcessSpawnIBInvalid); - - KT_RUN_TEST(ProcessExitValid); - KT_RUN_TEST(ProcessExitWithCode); - KT_RUN_TEST(ProcessExitInvalid); - - return KT_TEST_SUCCESS; -} diff --git a/test/kernel_tests/.keep b/test/kernel_tests/.keep new file mode 100644 index 00000000..e69de29b diff --git a/test/libsystem_test/Makefile b/test/libsystem_test/Makefile deleted file mode 100644 index a2bb9d4f..00000000 --- a/test/libsystem_test/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -################################################## -# (c) Amlal El Mahrouss and NeKernel Authors, licensed under the Apache 2.0 license. -# This file is for libsystem testing. -################################################## - -GCC=x86_64-w64-mingw32-g++ -Wl,-subsystem=17 -LIB=-L../../src/libSystem -lSystem -STD=-std=c++20 -DKT_TESTING_ENABLED -INCLUDE=-I../../src -I../../public -I../../public/frameworks/ -I../../ - -OBJ_FILES = \ - thread.test.exe \ - memory.test.exe \ - io.test.exe - -.PHONY: all -all: $(OBJ_FILES) - -%.exe: %.cc - @echo "==> Building test: $@" - $(GCC) $(LIB) $< \ - $(STD) $(INCLUDE) -o $(basename $<).exe \ No newline at end of file diff --git a/test/libsystem_test/io.test.cc b/test/libsystem_test/io.test.cc deleted file mode 100644 index dfc21990..00000000 --- a/test/libsystem_test/io.test.cc +++ /dev/null @@ -1,155 +0,0 @@ -/// \file io.test.cc -/// \brief File I/O API tests. -/// \author Amlal El Mahrouss (amlal at nekernel dot org) - -#include -#include - -/// \note File open/close tests - -KT_DECL_TEST(IoOpenFileInvalid, []() -> bool { - auto file = IoOpenFile(nullptr, nullptr); - return file == nullptr; -}); - -KT_DECL_TEST(IoOpenFileValidPath, []() -> bool { - auto file = IoOpenFile("/test.txt", nullptr); - if (!file) return NO; - IoCloseFile(file); - return YES; -}); - -KT_DECL_TEST(IoCloseFileValid, []() -> bool { - auto file = IoOpenFile("/test.txt", nullptr); - if (!file) return NO; - IoCloseFile(file); - return YES; -}); - -/// \note File positioning tests - -KT_DECL_TEST(IoSeekFileValid, []() -> bool { - auto file = IoOpenFile("/test.txt", nullptr); - if (!file) return NO; - - UInt64 pos = IoSeekFile(file, 100); - IoCloseFile(file); - - return pos != ~0UL; -}); - -KT_DECL_TEST(IoTellFileValid, []() -> bool { - auto file = IoOpenFile("/test.txt", nullptr); - if (!file) return NO; - - IoSeekFile(file, 50); - UInt64 pos = IoTellFile(file); - IoCloseFile(file); - - return pos == 50; -}); - -KT_DECL_TEST(IoRewindFileValid, []() -> bool { - auto file = IoOpenFile("/test.txt", nullptr); - if (!file) return NO; - - IoSeekFile(file, 100); - IoRewindFile(file); - UInt64 pos = IoTellFile(file); - IoCloseFile(file); - - return pos == 0; -}); - -/// \note File read/write tests - -KT_DECL_TEST(IoWriteFileValid, []() -> bool { - auto file = IoOpenFile("/test_write.txt", nullptr); - if (!file) return NO; - - const char data[] = "Test data"; - UInt32 written = IoWriteFile(file, (VoidPtr) data, sizeof(data)); - IoCloseFile(file); - - return written == sizeof(data); -}); - -KT_DECL_TEST(IoReadFileValid, []() -> bool { - auto file = IoOpenFile("/test_read.txt", nullptr); - if (!file) return NO; - - char buffer[64]; - VoidPtr buf_ptr = buffer; - UInt32 read = IoReadFile(file, &buf_ptr, sizeof(buffer)); - IoCloseFile(file); - - return read > 0; -}); - -KT_DECL_TEST(IoWriteFileNull, []() -> bool { - auto file = IoOpenFile("/test.txt", nullptr); - if (!file) return NO; - - UInt32 written = IoWriteFile(file, nullptr, 10); - IoCloseFile(file); - - return written == 0; -}); - -/// \note File metadata tests - -KT_DECL_TEST(IoMimeFileValid, []() -> bool { - auto file = IoOpenFile("/test.txt", nullptr); - if (!file) return NO; - - const Char* mime = IoMimeFile(file); - IoCloseFile(file); - - return mime != nullptr; -}); - -KT_DECL_TEST(IoDimFileValid, []() -> bool { - auto file = IoOpenFile("/test_dir", nullptr); - if (!file) return NO; - - const Char* dim = IoDimFile(file); - IoCloseFile(file); - - return dim != nullptr; -}); - -/// \note File control tests - -KT_DECL_TEST(IoCtrlFileValid, []() -> bool { - auto file = IoOpenFile("/test.txt", nullptr); - if (!file) return NO; - - char in_data[16] = {0}; - char out_data[16] = {0}; - SInt32 result = IoCtrlFile(file, 1, in_data, out_data); - IoCloseFile(file); - - return result != 0; -}); - -/// \brief Run file I/O tests. -SInt32 KT_TEST_MAIN() { - KT_RUN_TEST(IoOpenFileInvalid); - KT_RUN_TEST(IoOpenFileValidPath); - KT_RUN_TEST(IoCloseFileValid); - - KT_RUN_TEST(IoSeekFileValid); - KT_RUN_TEST(IoTellFileValid); - KT_RUN_TEST(IoRewindFileValid); - - KT_RUN_TEST(IoWriteFileValid); - KT_RUN_TEST(IoReadFileValid); - KT_RUN_TEST(IoWriteFileNull); - - KT_RUN_TEST(IoMimeFileValid); - KT_RUN_TEST(IoDimFileValid); - - KT_RUN_TEST(IoCtrlFileValid); - - return KT_TEST_SUCCESS; -} diff --git a/test/libsystem_test/memory.test.cc b/test/libsystem_test/memory.test.cc deleted file mode 100644 index 28d758cc..00000000 --- a/test/libsystem_test/memory.test.cc +++ /dev/null @@ -1,136 +0,0 @@ -/// \file memory.test.cc -/// \brief Memory Manager API tests. -/// \author Amlal El Mahrouss (amlal at nekernel dot org) - -#include -#include - -/// \note Memory allocation tests - -KT_DECL_TEST(MmCreateHeapSuccess, []() -> bool { - auto heap = MmCreateHeap(1024, 0); - if (!heap) return NO; - MmDestroyHeap(heap); - return YES; -}); - -KT_DECL_TEST(MmCreateHeapZeroSize, []() -> bool { - auto heap = MmCreateHeap(0, 0); - return heap == nullptr; -}); - -KT_DECL_TEST(MmDestroyHeapValid, []() -> bool { - auto heap = MmCreateHeap(1024, 0); - if (!heap) return NO; - return MmDestroyHeap(heap) == 0; -}); - -KT_DECL_TEST(MmDestroyHeapNull, []() -> bool { return MmDestroyHeap(nullptr) != 0; }); - -/// \note Memory operations tests - -KT_DECL_TEST(MmCopyMemoryNonOverlapping, []() -> bool { - char src[16] = "Hello, World!"; - char dst[16] = {0}; - - auto result = MmCopyMemory(dst, src, 13); - if (!result) return NO; - - return MmStrCmp(src, dst) == 0; -}); - -KT_DECL_TEST(MmCopyMemoryNull, - []() -> bool { return MmCopyMemory(nullptr, nullptr, 10) == nullptr; }); - -KT_DECL_TEST(MmFillMemoryPattern, []() -> bool { - char buffer[16] = {0}; - MmFillMemory(buffer, 16, 0xAA); - - for (int i = 0; i < 16; i++) { - if ((unsigned char) buffer[i] != 0xAA) return NO; - } - return YES; -}); - -KT_DECL_TEST(MmFillMemoryNull, []() -> bool { return MmFillMemory(nullptr, 10, 0xFF) == nullptr; }); - -KT_DECL_TEST(MmCmpMemoryEqual, []() -> bool { - char buf1[8] = {1, 2, 3, 4, 5, 6, 7, 8}; - char buf2[8] = {1, 2, 3, 4, 5, 6, 7, 8}; - - return MmCmpMemory(buf1, buf2, 8) == 0; -}); - -KT_DECL_TEST(MmCmpMemoryNotEqual, []() -> bool { - char buf1[8] = {1, 2, 3, 4, 5, 6, 7, 8}; - char buf2[8] = {1, 2, 3, 9, 5, 6, 7, 8}; - - return MmCmpMemory(buf1, buf2, 8) != 0; -}); - -/// \note String operations tests - -KT_DECL_TEST(MmStrLenNonEmpty, []() -> bool { - const char* str = "Hello"; - return MmStrLen(str) == 5; -}); - -KT_DECL_TEST(MmStrLenEmpty, []() -> bool { - const char* str = ""; - return MmStrLen(str) == 0; -}); - -KT_DECL_TEST(MmStrLenNull, []() -> bool { return MmStrLen(nullptr) < 0; }); - -KT_DECL_TEST(MmStrCmpEqual, []() -> bool { return MmStrCmp("test", "test") == 0; }); - -KT_DECL_TEST(MmStrCmpNotEqual, []() -> bool { return MmStrCmp("test", "fest") != 0; }); - -/// \note Heap flags tests - -KT_DECL_TEST(MmSetGetHeapFlags, []() -> bool { - auto heap = MmCreateHeap(1024, 0x01); - if (!heap) return NO; - - MmSetHeapFlags(heap, 0x02); - UInt32 flags = MmGetHeapFlags(heap); - - MmDestroyHeap(heap); - return flags == 0x02; -}); - -KT_DECL_TEST(MmFillCRC32HeapValid, []() -> bool { - auto heap = MmCreateHeap(1024, 0); - if (!heap) return NO; - - UInt32 crc = MmFillCRC32Heap(heap); - - MmDestroyHeap(heap); - return crc != 0; -}); - -/// \brief Run memory tests. -IMPORT_C SInt32 KT_TEST_MAIN() { - KT_RUN_TEST(MmCreateHeapSuccess); - KT_RUN_TEST(MmCreateHeapZeroSize); - KT_RUN_TEST(MmDestroyHeapValid); - KT_RUN_TEST(MmDestroyHeapNull); - - KT_RUN_TEST(MmCopyMemoryNonOverlapping); - KT_RUN_TEST(MmCopyMemoryNull); - KT_RUN_TEST(MmFillMemoryPattern); - KT_RUN_TEST(MmFillMemoryNull); - KT_RUN_TEST(MmCmpMemoryEqual); - KT_RUN_TEST(MmCmpMemoryNotEqual); - - KT_RUN_TEST(MmStrLenNonEmpty); - KT_RUN_TEST(MmStrLenEmpty); - KT_RUN_TEST(MmStrLenNull); - KT_RUN_TEST(MmStrCmpEqual); - KT_RUN_TEST(MmStrCmpNotEqual); - - KT_RUN_TEST(MmSetGetHeapFlags); - KT_RUN_TEST(MmFillCRC32HeapValid); - - return KT_TEST_SUCCESS; -} diff --git a/test/libsystem_test/thread.test.cc b/test/libsystem_test/thread.test.cc deleted file mode 100644 index db248e26..00000000 --- a/test/libsystem_test/thread.test.cc +++ /dev/null @@ -1,142 +0,0 @@ -/// \file thread.test.cc -/// \brief Threading API tests. -/// \author Amlal El Mahrouss (amlal at nekernel dot org) - -#include -#include - -/// \note Thread procedure for testing -static SInt32 test_thread_proc(SInt32 argc, Char** argv) { - return 0; -} - -static SInt32 test_thread_proc_with_arg(SInt32 argc, Char** argv) { - if (argc > 0 && argv) { - return 1; - } - return 0; -} - -/// \note Thread creation tests - -KT_DECL_TEST(ThrCreateThreadValid, []() -> bool { - auto thread = ThrCreateThread("test_thread", test_thread_proc, 0, 0); - if (!thread) return NO; - ThrJoinThread(thread); - return YES; -}); - -KT_DECL_TEST(ThrCreateThreadNull, []() -> bool { - auto thread = ThrCreateThread(nullptr, nullptr, 0, 0); - return thread == nullptr; -}); - -KT_DECL_TEST(ThrCreateThreadWithName, []() -> bool { - auto thread = ThrCreateThread("named_thread", test_thread_proc, 0, 0); - if (!thread) return NO; - ThrJoinThread(thread); - return YES; -}); - -/// \note Thread lifecycle tests - -KT_DECL_TEST(ThrJoinThreadValid, []() -> bool { - auto thread = ThrCreateThread("join_test", test_thread_proc, 0, 0); - if (!thread) return NO; - - SInt32 result = ThrJoinThread(thread); - return result == 0; -}); - -KT_DECL_TEST(ThrDetachThreadValid, []() -> bool { - auto thread = ThrCreateThread("detach_test", test_thread_proc, 0, 0); - if (!thread) return NO; - - SInt32 result = ThrDetachThread(thread); - return result == 0; -}); - -KT_DECL_TEST(ThrYieldThreadValid, []() -> bool { - auto thread = ThrCreateThread("yield_test", test_thread_proc, 0, 0); - if (!thread) return NO; - - SInt32 result = ThrYieldThread(thread); - ThrJoinThread(thread); - - return result == 0; -}); - -/// \note Thread exit tests - -KT_DECL_TEST(ThrExitThreadValid, []() -> bool { - auto thread = ThrCreateThread("exit_test", test_thread_proc, 0, 0); - if (!thread) return NO; - - SInt32 result = ThrExitThread(thread, 0); - return result == 0; -}); - -KT_DECL_TEST(ThrExitThreadWithCode, []() -> bool { - auto thread = ThrCreateThread("exit_code_test", test_thread_proc, 0, 0); - if (!thread) return NO; - - SInt32 result = ThrExitThread(thread, 42); - return result == 0; -}); - -/// \note Thread argument tests - -KT_DECL_TEST(ThrCreateThreadWithArgs, []() -> bool { - auto thread = ThrCreateThread("args_test", test_thread_proc_with_arg, 1, 0); - if (!thread) return NO; - ThrJoinThread(thread); - return YES; -}); - -KT_DECL_TEST(ThrCreateThreadMultiple, []() -> bool { - auto thread1 = ThrCreateThread("multi_test_1", test_thread_proc, 0, 0); - auto thread2 = ThrCreateThread("multi_test_2", test_thread_proc, 0, 0); - - if (!thread1 || !thread2) return NO; - - ThrJoinThread(thread1); - ThrJoinThread(thread2); - - return YES; -}); - -/// \note Current thread tests - -KT_DECL_TEST(ThrExitCurrentThreadValid, []() -> bool { - // Note: Can't directly test this as it would exit the test thread - // This is a placeholder for integration testing - return YES; -}); - -KT_DECL_TEST(ThrExitMainThreadValid, []() -> bool { - // Note: Can't directly test this as it would exit the main thread - // This is a placeholder for integration testing - return YES; -}); - -/// \brief Run threading tests. -IMPORT_C SInt32 KT_TEST_MAIN() { - KT_RUN_TEST(ThrCreateThreadValid); - KT_RUN_TEST(ThrCreateThreadNull); - KT_RUN_TEST(ThrCreateThreadWithName); - - KT_RUN_TEST(ThrJoinThreadValid); - KT_RUN_TEST(ThrDetachThreadValid); - KT_RUN_TEST(ThrYieldThreadValid); - - KT_RUN_TEST(ThrExitThreadValid); - KT_RUN_TEST(ThrExitThreadWithCode); - - KT_RUN_TEST(ThrCreateThreadWithArgs); - KT_RUN_TEST(ThrCreateThreadMultiple); - - KT_RUN_TEST(ThrExitCurrentThreadValid); - KT_RUN_TEST(ThrExitMainThreadValid); - - return KT_TEST_SUCCESS; -} diff --git a/test/user_tests/kernel_test/Makefile b/test/user_tests/kernel_test/Makefile new file mode 100644 index 00000000..c4057a5e --- /dev/null +++ b/test/user_tests/kernel_test/Makefile @@ -0,0 +1,22 @@ +################################################## +# (c) Amlal El Mahrouss and NeKernel Authors, licensed under the Apache 2.0 license. +# This file is for kernel testing. +################################################## + +GCC=x86_64-w64-mingw32-g++ -Wl,-subsystem=17 +LIB=-L../../src/libSystem -lSystem +STD=-std=c++20 -DKT_TESTING_ENABLED +INCLUDE=-I../../src -I../../public -I../../public/frameworks/ -I../../ + +OBJ_FILES = \ + error.test.exe \ + print.test.exe \ + process.test.exe + +.PHONY: all +all: $(OBJ_FILES) + +%.exe: %.cc + @echo "==> Building test: $@" + $(GCC) $(LIB) $< \ + $(STD) $(INCLUDE) -o $(basename $<).exe \ No newline at end of file diff --git a/test/user_tests/kernel_test/error.test.cc b/test/user_tests/kernel_test/error.test.cc new file mode 100644 index 00000000..ece8f71d --- /dev/null +++ b/test/user_tests/kernel_test/error.test.cc @@ -0,0 +1,67 @@ +/// \file error.test.cc +/// \brief Error handling API tests. +/// \author Amlal El Mahrouss (amlal at nekernel dot org) + +#include +#include + +/// \note ErrGetLastError tests +KT_DECL_TEST(ErrGetLastErrorInitial, []() -> bool { + SInt32 error = ErrGetLastError(); + return error >= 0; +}); + +KT_DECL_TEST(ErrGetLastErrorAfterSuccess, []() -> bool { + auto heap = MmCreateHeap(1024, 0); + if (!heap) return NO; + + SInt32 error = ErrGetLastError(); + MmDestroyHeap(heap); + + return error == 0; +}); + +KT_DECL_TEST(ErrGetLastErrorAfterFailure, []() -> bool { + auto heap = MmCreateHeap(0, 0); + + SInt32 error = ErrGetLastError(); + + return error != 0; +}); + +KT_DECL_TEST(ErrGetLastErrorAfterInvalidFile, []() -> bool { + auto file = IoOpenFile("/invalid/path/that/does/not/exist", nullptr); + + SInt32 error = ErrGetLastError(); + + if (file) IoCloseFile(file); + + return error != 0; +}); + +KT_DECL_TEST(ErrGetLastErrorAfterNullOp, []() -> bool { + auto ptr = MmCopyMemory(nullptr, nullptr, 10); + + SInt32 error = ErrGetLastError(); + + return error != 0; +}); + +KT_DECL_TEST(ErrGetLastErrorMultipleCalls, []() -> bool { + SInt32 error1 = ErrGetLastError(); + SInt32 error2 = ErrGetLastError(); + + return error1 == error2; +}); + +/// \brief Run error tests. +IMPORT_C SInt32 KT_TEST_MAIN() { + KT_RUN_TEST(ErrGetLastErrorInitial); + KT_RUN_TEST(ErrGetLastErrorAfterSuccess); + KT_RUN_TEST(ErrGetLastErrorAfterFailure); + KT_RUN_TEST(ErrGetLastErrorAfterInvalidFile); + KT_RUN_TEST(ErrGetLastErrorAfterNullOp); + KT_RUN_TEST(ErrGetLastErrorMultipleCalls); + + return KT_TEST_SUCCESS; +} diff --git a/test/user_tests/kernel_test/print.test.cc b/test/user_tests/kernel_test/print.test.cc new file mode 100644 index 00000000..4f9bc828 --- /dev/null +++ b/test/user_tests/kernel_test/print.test.cc @@ -0,0 +1,73 @@ +/// \file kout.test.cc +/// \brief Konsole Out tests. + +#include +#include + +/// \note PrintGet tests +KT_DECL_TEST(PrintIsNull, []() -> bool { return PrintGet("/null/") == nullptr; }); +KT_DECL_TEST(PrintIsNotNull, []() -> bool { return PrintGet(nullptr) != nullptr; }); + +/// \note PrintCreate/PrintRelease tests +KT_DECL_TEST(PrintCreateValid, []() -> bool { + auto handle = PrintCreate(); + if (!handle) return NO; + PrintRelease(handle); + return YES; +}); + +KT_DECL_TEST(PrintReleaseValid, []() -> bool { + auto handle = PrintCreate(); + if (!handle) return NO; + return PrintRelease(handle) == 0; +}); + +KT_DECL_TEST(PrintReleaseNull, []() -> bool { return PrintRelease(nullptr) != 0; }); + +/// \note PrintOut tests +KT_DECL_TEST(PrintOutValid, []() -> bool { + SInt32 result = PrintOut(nullptr, "Test output\n"); + return result >= 0; +}); + +KT_DECL_TEST(PrintOutWithHandle, []() -> bool { + auto handle = PrintCreate(); + SInt32 result = PrintOut(handle, "Test with handle\n"); + PrintRelease(handle); + return result >= 0; +}); + +KT_DECL_TEST(PrintOutNull, []() -> bool { + SInt32 result = PrintOut(nullptr, nullptr); + return result < 0; +}); + +KT_DECL_TEST(PrintOutFormatted, []() -> bool { + SInt32 result = PrintOut(nullptr, "Value: %d\n", 42); + return result >= 0; +}); + +/// \note PrintIn tests +KT_DECL_TEST(PrintInValid, []() -> bool { + SInt32 result = PrintIn(nullptr, "Input prompt: "); + return result >= 0; +}); + +/// \brief Run 'kout' test. +SInt32 KT_TEST_MAIN() { + KT_RUN_TEST(PrintIsNull); + KT_RUN_TEST(PrintIsNotNull); + + KT_RUN_TEST(PrintCreateValid); + KT_RUN_TEST(PrintReleaseValid); + KT_RUN_TEST(PrintReleaseNull); + + KT_RUN_TEST(PrintOutValid); + KT_RUN_TEST(PrintOutWithHandle); + KT_RUN_TEST(PrintOutNull); + KT_RUN_TEST(PrintOutFormatted); + + KT_RUN_TEST(PrintInValid); + + return KT_TEST_SUCCESS; +} diff --git a/test/user_tests/kernel_test/process.test.cc b/test/user_tests/kernel_test/process.test.cc new file mode 100644 index 00000000..2ec7d191 --- /dev/null +++ b/test/user_tests/kernel_test/process.test.cc @@ -0,0 +1,78 @@ +/// \file process.test.cc +/// \brief Process management tests. +/// \author Amlal El Mahrouss (amlal at nekernel dot org) + +#include +#include + +/// \note RtlSpawnProcess tests +KT_DECL_TEST(ProcessHasFailed, []() -> bool { + /// \todo we return -1 here, should we document that or classify as common knowledge? + return RtlSpawnProcess("/", 0, nullptr, nullptr, 0) == -1; +}); + +KT_DECL_TEST(ProcessHasSucceeded, []() -> bool { + /// \note Any process greater than zero, exists within a specific team domain (real-time, high, or + /// low domains). + return RtlSpawnProcess("/system/list", 0, nullptr, nullptr, 0) > 0; +}); + +KT_DECL_TEST(ProcessSpawnNullPath, + []() -> bool { return RtlSpawnProcess(nullptr, 0, nullptr, nullptr, 0) == -1; }); + +KT_DECL_TEST(ProcessSpawnInvalidPath, []() -> bool { + return RtlSpawnProcess("/invalid/nonexistent", 0, nullptr, nullptr, 0) == -1; +}); + +/// \note RtlSpawnIB tests +KT_DECL_TEST(ProcessSpawnIBValid, []() -> bool { + UIntPtr pid = RtlSpawnProcess("/system/list", 0, nullptr, nullptr, 0); + if (pid <= 0) return NO; + + UInt32 result = RtlSpawnIB(pid); + return result == 0; +}); + +KT_DECL_TEST(ProcessSpawnIBInvalid, []() -> bool { + UInt32 result = RtlSpawnIB(0); + return result > 0; +}); + +/// \note RtlExitProcess tests +KT_DECL_TEST(ProcessExitValid, []() -> bool { + UIntPtr pid = RtlSpawnProcess("/system/list", 0, nullptr, nullptr, 0); + if (pid <= 0) return NO; + + Bool result = RtlExitProcess(pid, 0); + return result == YES; +}); + +KT_DECL_TEST(ProcessExitWithCode, []() -> bool { + UIntPtr pid = RtlSpawnProcess("/system/list", 0, nullptr, nullptr, 0); + if (pid <= 0) return NO; + + Bool result = RtlExitProcess(pid, 42); + return result == YES; +}); + +KT_DECL_TEST(ProcessExitInvalid, []() -> bool { + Bool result = RtlExitProcess(0, 0); + return result == NO; +}); + +/// \brief Run 'process' test. +IMPORT_C SInt32 KT_TEST_MAIN() { + KT_RUN_TEST(ProcessHasFailed); + KT_RUN_TEST(ProcessHasSucceeded); + KT_RUN_TEST(ProcessSpawnNullPath); + KT_RUN_TEST(ProcessSpawnInvalidPath); + + KT_RUN_TEST(ProcessSpawnIBValid); + KT_RUN_TEST(ProcessSpawnIBInvalid); + + KT_RUN_TEST(ProcessExitValid); + KT_RUN_TEST(ProcessExitWithCode); + KT_RUN_TEST(ProcessExitInvalid); + + return KT_TEST_SUCCESS; +} diff --git a/test/user_tests/libsystem_test/Makefile b/test/user_tests/libsystem_test/Makefile new file mode 100644 index 00000000..a2bb9d4f --- /dev/null +++ b/test/user_tests/libsystem_test/Makefile @@ -0,0 +1,22 @@ +################################################## +# (c) Amlal El Mahrouss and NeKernel Authors, licensed under the Apache 2.0 license. +# This file is for libsystem testing. +################################################## + +GCC=x86_64-w64-mingw32-g++ -Wl,-subsystem=17 +LIB=-L../../src/libSystem -lSystem +STD=-std=c++20 -DKT_TESTING_ENABLED +INCLUDE=-I../../src -I../../public -I../../public/frameworks/ -I../../ + +OBJ_FILES = \ + thread.test.exe \ + memory.test.exe \ + io.test.exe + +.PHONY: all +all: $(OBJ_FILES) + +%.exe: %.cc + @echo "==> Building test: $@" + $(GCC) $(LIB) $< \ + $(STD) $(INCLUDE) -o $(basename $<).exe \ No newline at end of file diff --git a/test/user_tests/libsystem_test/io.test.cc b/test/user_tests/libsystem_test/io.test.cc new file mode 100644 index 00000000..dfc21990 --- /dev/null +++ b/test/user_tests/libsystem_test/io.test.cc @@ -0,0 +1,155 @@ +/// \file io.test.cc +/// \brief File I/O API tests. +/// \author Amlal El Mahrouss (amlal at nekernel dot org) + +#include +#include + +/// \note File open/close tests + +KT_DECL_TEST(IoOpenFileInvalid, []() -> bool { + auto file = IoOpenFile(nullptr, nullptr); + return file == nullptr; +}); + +KT_DECL_TEST(IoOpenFileValidPath, []() -> bool { + auto file = IoOpenFile("/test.txt", nullptr); + if (!file) return NO; + IoCloseFile(file); + return YES; +}); + +KT_DECL_TEST(IoCloseFileValid, []() -> bool { + auto file = IoOpenFile("/test.txt", nullptr); + if (!file) return NO; + IoCloseFile(file); + return YES; +}); + +/// \note File positioning tests + +KT_DECL_TEST(IoSeekFileValid, []() -> bool { + auto file = IoOpenFile("/test.txt", nullptr); + if (!file) return NO; + + UInt64 pos = IoSeekFile(file, 100); + IoCloseFile(file); + + return pos != ~0UL; +}); + +KT_DECL_TEST(IoTellFileValid, []() -> bool { + auto file = IoOpenFile("/test.txt", nullptr); + if (!file) return NO; + + IoSeekFile(file, 50); + UInt64 pos = IoTellFile(file); + IoCloseFile(file); + + return pos == 50; +}); + +KT_DECL_TEST(IoRewindFileValid, []() -> bool { + auto file = IoOpenFile("/test.txt", nullptr); + if (!file) return NO; + + IoSeekFile(file, 100); + IoRewindFile(file); + UInt64 pos = IoTellFile(file); + IoCloseFile(file); + + return pos == 0; +}); + +/// \note File read/write tests + +KT_DECL_TEST(IoWriteFileValid, []() -> bool { + auto file = IoOpenFile("/test_write.txt", nullptr); + if (!file) return NO; + + const char data[] = "Test data"; + UInt32 written = IoWriteFile(file, (VoidPtr) data, sizeof(data)); + IoCloseFile(file); + + return written == sizeof(data); +}); + +KT_DECL_TEST(IoReadFileValid, []() -> bool { + auto file = IoOpenFile("/test_read.txt", nullptr); + if (!file) return NO; + + char buffer[64]; + VoidPtr buf_ptr = buffer; + UInt32 read = IoReadFile(file, &buf_ptr, sizeof(buffer)); + IoCloseFile(file); + + return read > 0; +}); + +KT_DECL_TEST(IoWriteFileNull, []() -> bool { + auto file = IoOpenFile("/test.txt", nullptr); + if (!file) return NO; + + UInt32 written = IoWriteFile(file, nullptr, 10); + IoCloseFile(file); + + return written == 0; +}); + +/// \note File metadata tests + +KT_DECL_TEST(IoMimeFileValid, []() -> bool { + auto file = IoOpenFile("/test.txt", nullptr); + if (!file) return NO; + + const Char* mime = IoMimeFile(file); + IoCloseFile(file); + + return mime != nullptr; +}); + +KT_DECL_TEST(IoDimFileValid, []() -> bool { + auto file = IoOpenFile("/test_dir", nullptr); + if (!file) return NO; + + const Char* dim = IoDimFile(file); + IoCloseFile(file); + + return dim != nullptr; +}); + +/// \note File control tests + +KT_DECL_TEST(IoCtrlFileValid, []() -> bool { + auto file = IoOpenFile("/test.txt", nullptr); + if (!file) return NO; + + char in_data[16] = {0}; + char out_data[16] = {0}; + SInt32 result = IoCtrlFile(file, 1, in_data, out_data); + IoCloseFile(file); + + return result != 0; +}); + +/// \brief Run file I/O tests. +SInt32 KT_TEST_MAIN() { + KT_RUN_TEST(IoOpenFileInvalid); + KT_RUN_TEST(IoOpenFileValidPath); + KT_RUN_TEST(IoCloseFileValid); + + KT_RUN_TEST(IoSeekFileValid); + KT_RUN_TEST(IoTellFileValid); + KT_RUN_TEST(IoRewindFileValid); + + KT_RUN_TEST(IoWriteFileValid); + KT_RUN_TEST(IoReadFileValid); + KT_RUN_TEST(IoWriteFileNull); + + KT_RUN_TEST(IoMimeFileValid); + KT_RUN_TEST(IoDimFileValid); + + KT_RUN_TEST(IoCtrlFileValid); + + return KT_TEST_SUCCESS; +} diff --git a/test/user_tests/libsystem_test/memory.test.cc b/test/user_tests/libsystem_test/memory.test.cc new file mode 100644 index 00000000..28d758cc --- /dev/null +++ b/test/user_tests/libsystem_test/memory.test.cc @@ -0,0 +1,136 @@ +/// \file memory.test.cc +/// \brief Memory Manager API tests. +/// \author Amlal El Mahrouss (amlal at nekernel dot org) + +#include +#include + +/// \note Memory allocation tests + +KT_DECL_TEST(MmCreateHeapSuccess, []() -> bool { + auto heap = MmCreateHeap(1024, 0); + if (!heap) return NO; + MmDestroyHeap(heap); + return YES; +}); + +KT_DECL_TEST(MmCreateHeapZeroSize, []() -> bool { + auto heap = MmCreateHeap(0, 0); + return heap == nullptr; +}); + +KT_DECL_TEST(MmDestroyHeapValid, []() -> bool { + auto heap = MmCreateHeap(1024, 0); + if (!heap) return NO; + return MmDestroyHeap(heap) == 0; +}); + +KT_DECL_TEST(MmDestroyHeapNull, []() -> bool { return MmDestroyHeap(nullptr) != 0; }); + +/// \note Memory operations tests + +KT_DECL_TEST(MmCopyMemoryNonOverlapping, []() -> bool { + char src[16] = "Hello, World!"; + char dst[16] = {0}; + + auto result = MmCopyMemory(dst, src, 13); + if (!result) return NO; + + return MmStrCmp(src, dst) == 0; +}); + +KT_DECL_TEST(MmCopyMemoryNull, + []() -> bool { return MmCopyMemory(nullptr, nullptr, 10) == nullptr; }); + +KT_DECL_TEST(MmFillMemoryPattern, []() -> bool { + char buffer[16] = {0}; + MmFillMemory(buffer, 16, 0xAA); + + for (int i = 0; i < 16; i++) { + if ((unsigned char) buffer[i] != 0xAA) return NO; + } + return YES; +}); + +KT_DECL_TEST(MmFillMemoryNull, []() -> bool { return MmFillMemory(nullptr, 10, 0xFF) == nullptr; }); + +KT_DECL_TEST(MmCmpMemoryEqual, []() -> bool { + char buf1[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + char buf2[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + return MmCmpMemory(buf1, buf2, 8) == 0; +}); + +KT_DECL_TEST(MmCmpMemoryNotEqual, []() -> bool { + char buf1[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + char buf2[8] = {1, 2, 3, 9, 5, 6, 7, 8}; + + return MmCmpMemory(buf1, buf2, 8) != 0; +}); + +/// \note String operations tests + +KT_DECL_TEST(MmStrLenNonEmpty, []() -> bool { + const char* str = "Hello"; + return MmStrLen(str) == 5; +}); + +KT_DECL_TEST(MmStrLenEmpty, []() -> bool { + const char* str = ""; + return MmStrLen(str) == 0; +}); + +KT_DECL_TEST(MmStrLenNull, []() -> bool { return MmStrLen(nullptr) < 0; }); + +KT_DECL_TEST(MmStrCmpEqual, []() -> bool { return MmStrCmp("test", "test") == 0; }); + +KT_DECL_TEST(MmStrCmpNotEqual, []() -> bool { return MmStrCmp("test", "fest") != 0; }); + +/// \note Heap flags tests + +KT_DECL_TEST(MmSetGetHeapFlags, []() -> bool { + auto heap = MmCreateHeap(1024, 0x01); + if (!heap) return NO; + + MmSetHeapFlags(heap, 0x02); + UInt32 flags = MmGetHeapFlags(heap); + + MmDestroyHeap(heap); + return flags == 0x02; +}); + +KT_DECL_TEST(MmFillCRC32HeapValid, []() -> bool { + auto heap = MmCreateHeap(1024, 0); + if (!heap) return NO; + + UInt32 crc = MmFillCRC32Heap(heap); + + MmDestroyHeap(heap); + return crc != 0; +}); + +/// \brief Run memory tests. +IMPORT_C SInt32 KT_TEST_MAIN() { + KT_RUN_TEST(MmCreateHeapSuccess); + KT_RUN_TEST(MmCreateHeapZeroSize); + KT_RUN_TEST(MmDestroyHeapValid); + KT_RUN_TEST(MmDestroyHeapNull); + + KT_RUN_TEST(MmCopyMemoryNonOverlapping); + KT_RUN_TEST(MmCopyMemoryNull); + KT_RUN_TEST(MmFillMemoryPattern); + KT_RUN_TEST(MmFillMemoryNull); + KT_RUN_TEST(MmCmpMemoryEqual); + KT_RUN_TEST(MmCmpMemoryNotEqual); + + KT_RUN_TEST(MmStrLenNonEmpty); + KT_RUN_TEST(MmStrLenEmpty); + KT_RUN_TEST(MmStrLenNull); + KT_RUN_TEST(MmStrCmpEqual); + KT_RUN_TEST(MmStrCmpNotEqual); + + KT_RUN_TEST(MmSetGetHeapFlags); + KT_RUN_TEST(MmFillCRC32HeapValid); + + return KT_TEST_SUCCESS; +} diff --git a/test/user_tests/libsystem_test/thread.test.cc b/test/user_tests/libsystem_test/thread.test.cc new file mode 100644 index 00000000..db248e26 --- /dev/null +++ b/test/user_tests/libsystem_test/thread.test.cc @@ -0,0 +1,142 @@ +/// \file thread.test.cc +/// \brief Threading API tests. +/// \author Amlal El Mahrouss (amlal at nekernel dot org) + +#include +#include + +/// \note Thread procedure for testing +static SInt32 test_thread_proc(SInt32 argc, Char** argv) { + return 0; +} + +static SInt32 test_thread_proc_with_arg(SInt32 argc, Char** argv) { + if (argc > 0 && argv) { + return 1; + } + return 0; +} + +/// \note Thread creation tests + +KT_DECL_TEST(ThrCreateThreadValid, []() -> bool { + auto thread = ThrCreateThread("test_thread", test_thread_proc, 0, 0); + if (!thread) return NO; + ThrJoinThread(thread); + return YES; +}); + +KT_DECL_TEST(ThrCreateThreadNull, []() -> bool { + auto thread = ThrCreateThread(nullptr, nullptr, 0, 0); + return thread == nullptr; +}); + +KT_DECL_TEST(ThrCreateThreadWithName, []() -> bool { + auto thread = ThrCreateThread("named_thread", test_thread_proc, 0, 0); + if (!thread) return NO; + ThrJoinThread(thread); + return YES; +}); + +/// \note Thread lifecycle tests + +KT_DECL_TEST(ThrJoinThreadValid, []() -> bool { + auto thread = ThrCreateThread("join_test", test_thread_proc, 0, 0); + if (!thread) return NO; + + SInt32 result = ThrJoinThread(thread); + return result == 0; +}); + +KT_DECL_TEST(ThrDetachThreadValid, []() -> bool { + auto thread = ThrCreateThread("detach_test", test_thread_proc, 0, 0); + if (!thread) return NO; + + SInt32 result = ThrDetachThread(thread); + return result == 0; +}); + +KT_DECL_TEST(ThrYieldThreadValid, []() -> bool { + auto thread = ThrCreateThread("yield_test", test_thread_proc, 0, 0); + if (!thread) return NO; + + SInt32 result = ThrYieldThread(thread); + ThrJoinThread(thread); + + return result == 0; +}); + +/// \note Thread exit tests + +KT_DECL_TEST(ThrExitThreadValid, []() -> bool { + auto thread = ThrCreateThread("exit_test", test_thread_proc, 0, 0); + if (!thread) return NO; + + SInt32 result = ThrExitThread(thread, 0); + return result == 0; +}); + +KT_DECL_TEST(ThrExitThreadWithCode, []() -> bool { + auto thread = ThrCreateThread("exit_code_test", test_thread_proc, 0, 0); + if (!thread) return NO; + + SInt32 result = ThrExitThread(thread, 42); + return result == 0; +}); + +/// \note Thread argument tests + +KT_DECL_TEST(ThrCreateThreadWithArgs, []() -> bool { + auto thread = ThrCreateThread("args_test", test_thread_proc_with_arg, 1, 0); + if (!thread) return NO; + ThrJoinThread(thread); + return YES; +}); + +KT_DECL_TEST(ThrCreateThreadMultiple, []() -> bool { + auto thread1 = ThrCreateThread("multi_test_1", test_thread_proc, 0, 0); + auto thread2 = ThrCreateThread("multi_test_2", test_thread_proc, 0, 0); + + if (!thread1 || !thread2) return NO; + + ThrJoinThread(thread1); + ThrJoinThread(thread2); + + return YES; +}); + +/// \note Current thread tests + +KT_DECL_TEST(ThrExitCurrentThreadValid, []() -> bool { + // Note: Can't directly test this as it would exit the test thread + // This is a placeholder for integration testing + return YES; +}); + +KT_DECL_TEST(ThrExitMainThreadValid, []() -> bool { + // Note: Can't directly test this as it would exit the main thread + // This is a placeholder for integration testing + return YES; +}); + +/// \brief Run threading tests. +IMPORT_C SInt32 KT_TEST_MAIN() { + KT_RUN_TEST(ThrCreateThreadValid); + KT_RUN_TEST(ThrCreateThreadNull); + KT_RUN_TEST(ThrCreateThreadWithName); + + KT_RUN_TEST(ThrJoinThreadValid); + KT_RUN_TEST(ThrDetachThreadValid); + KT_RUN_TEST(ThrYieldThreadValid); + + KT_RUN_TEST(ThrExitThreadValid); + KT_RUN_TEST(ThrExitThreadWithCode); + + KT_RUN_TEST(ThrCreateThreadWithArgs); + KT_RUN_TEST(ThrCreateThreadMultiple); + + KT_RUN_TEST(ThrExitCurrentThreadValid); + KT_RUN_TEST(ThrExitMainThreadValid); + + return KT_TEST_SUCCESS; +} -- cgit v1.2.3