This commit is contained in:
alessandro bason 2025-06-24 17:47:08 +02:00
parent 95d74c2ef4
commit a66e58193f
25 changed files with 2600 additions and 93 deletions

374
tests/os_tests.c Normal file
View file

@ -0,0 +1,374 @@
#include "runner.h"
#include "../os.h"
#include "../arena.h"
#include <stdio.h>
// Handle Tests
UNIT_TEST(os_handle) {
oshandle_t zero = os_handle_zero();
ASSERT(!os_handle_valid(zero));
// Create a handle (using file open)
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
strview_t test_file = strv_init("test_file.txt");
// Create test file
oshandle_t h_write = os_file_open(test_file, FILEMODE_WRITE);
ASSERT(os_handle_valid(h_write));
os_file_puts(h_write, strv_init("test content"));
os_file_close(h_write);
// Open the file and test handle functions
oshandle_t h_read = os_file_open(test_file, FILEMODE_READ);
ASSERT(os_handle_valid(h_read));
ASSERT(!os_handle_match(h_read, zero));
oshandle_t h_read2 = os_file_open(test_file, FILEMODE_READ);
ASSERT(os_handle_valid(h_read2));
ASSERT(!os_handle_match(h_read, h_read2));
os_file_close(h_read);
os_file_close(h_read2);
os_file_delete(test_file);
arena_cleanup(&arena);
}
// File Operations Tests
UNIT_TEST(os_file_basic) {
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
strview_t test_file = strv_init("test_file.txt");
// Delete if exists
if (os_file_exists(test_file)) {
os_file_delete(test_file);
}
// Check existence
ASSERT(!os_file_exists(test_file));
// Create and write
oshandle_t h_write = os_file_open(test_file, FILEMODE_WRITE);
ASSERT(os_handle_valid(h_write));
os_file_putc(h_write, 'H');
os_file_puts(h_write, strv_init("ello World"));
os_file_close(h_write);
// Check existence after creation
ASSERT(os_file_exists(test_file));
// Read back
oshandle_t h_read = os_file_open(test_file, FILEMODE_READ);
ASSERT(os_handle_valid(h_read));
char buffer[12] = {0};
usize read = os_file_read(h_read, buffer, 11);
ASSERT(read == 11);
ASSERT(strcmp(buffer, "Hello World") == 0);
os_file_close(h_read);
// Clean up
os_file_delete(test_file);
ASSERT(!os_file_exists(test_file));
arena_cleanup(&arena);
}
UNIT_TEST(os_file_seek) {
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
strview_t test_file = strv_init("test_file.txt");
// Create and write
oshandle_t h_write = os_file_open(test_file, FILEMODE_WRITE);
ASSERT(os_handle_valid(h_write));
os_file_puts(h_write, strv_init("ABCDEFGHIJ"));
os_file_close(h_write);
// Open for reading
oshandle_t h_read = os_file_open(test_file, FILEMODE_READ);
ASSERT(os_handle_valid(h_read));
// Seek to position 5
ASSERT(os_file_seek(h_read, 5));
// Read from position 5
char buffer[6] = {0};
usize read = os_file_read(h_read, buffer, 5);
ASSERT(read == 5);
ASSERT(strcmp(buffer, "FGHIJ") == 0);
// Rewind and read from beginning
os_file_rewind(h_read);
char buffer2[6] = {0};
read = os_file_read(h_read, buffer2, 5);
ASSERT(read == 5);
ASSERT(strcmp(buffer2, "ABCDE") == 0);
// Test file position
ASSERT(os_file_tell(h_read) == 5);
// Test file size
ASSERT(os_file_size(h_read) == 10);
// Seek to end
ASSERT(os_file_seek_end(h_read));
ASSERT(os_file_is_finished(h_read));
os_file_close(h_read);
os_file_delete(test_file);
arena_cleanup(&arena);
}
UNIT_TEST(os_file_read_write_all) {
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
strview_t test_file = strv_init("test_file.txt");
// Write string
strview_t test_data = strv_init("This is test data for read/write all functions");
ASSERT(os_file_write_all_str(test_file, test_data));
// Read back as string
str_t read_data = os_file_read_all_str(&arena, test_file);
ASSERT(str_equals(read_data, str_init(&arena, "This is test data for read/write all functions")));
// Read as buffer
buffer_t buffer = os_file_read_all(&arena, test_file);
ASSERT(buffer.len == test_data.len);
ASSERT(memcmp(buffer.data, test_data.buf, test_data.len) == 0);
// Write buffer
const char *new_data = "New buffer data";
buffer_t write_buffer = {(u8*)new_data, strlen(new_data)};
ASSERT(os_file_write_all(test_file, write_buffer));
// Read back after buffer write
str_t read_new = os_file_read_all_str(&arena, test_file);
ASSERT(str_equals(read_new, str_init(&arena, "New buffer data")));
// Clean up
os_file_delete(test_file);
arena_cleanup(&arena);
}
UNIT_TEST(os_file_path) {
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
// Test path splitting
strview_t path = strv_init("/path/to/file.txt");
strview_t dir, name, ext;
os_file_split_path(path, &dir, &name, &ext);
ASSERT(strv_equals(dir, strv_init("/path/to")));
ASSERT(strv_equals(name, strv_init("file")));
ASSERT(strv_equals(ext, strv_init(".txt")));
// Test full path resolution
strview_t relative_path = strv_init("test_file.txt");
tstr_t full_path = os_file_fullpath(&arena, relative_path);
// Can't easily test the exact value, but can verify it's not empty
ASSERT(full_path.len > 0);
arena_cleanup(&arena);
}
// Directory Tests
UNIT_TEST(os_dir_operations) {
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
strview_t test_dir = strv_init("test_dir");
// Delete if exists
if (os_dir_exists(test_dir)) {
os_dir_delete(test_dir);
}
// Create directory
ASSERT(os_dir_create(test_dir));
ASSERT(os_dir_exists(test_dir));
// Create test file in directory
strview_t test_file_path = strv_init("test_dir/test_file.txt");
oshandle_t h_write = os_file_open(test_file_path, FILEMODE_WRITE);
ASSERT(os_handle_valid(h_write));
os_file_puts(h_write, strv_init("test content"));
os_file_close(h_write);
// Test directory listing
dir_t *dir = os_dir_open(&arena, test_dir);
ASSERT(os_dir_is_valid(dir));
bool found_file = false;
dir_foreach(&arena, entry, dir) {
if (str_equals(entry->name, str_init(&arena, "test_file.txt"))) {
found_file = true;
ASSERT(entry->type == DIRTYPE_FILE);
ASSERT(entry->file_size == 12); // "test content"
}
}
ASSERT(found_file);
// Clean up
os_file_delete(test_file_path);
os_dir_close(dir);
// Directory should now be empty, so we can delete it
os_dir_delete(test_dir);
ASSERT(!os_dir_exists(test_dir));
arena_cleanup(&arena);
}
// Environment Variable Tests
UNIT_TEST(os_env_vars) {
arena_t arena = arena_make(ARENA_MALLOC, KB(4));
arena_t scratch = arena_make(ARENA_MALLOC, KB(1));
// Set environment variable
strview_t key = strv_init("COLLA_TEST_VAR");
strview_t value = strv_init("test_value");
os_set_env_var(scratch, key, value);
// Get environment variable
str_t read_value = os_get_env_var(&arena, key);
ASSERT(str_equals(read_value, str_init(&arena, "test_value")));
// Get all environment variables
os_env_t *env = os_get_env(&arena);
ASSERT(env != NULL);
arena_cleanup(&scratch);
arena_cleanup(&arena);
}
// Virtual Memory Tests
UNIT_TEST(os_virtual_memory) {
usize page_size;
void *memory = os_reserve(MB(1), &page_size);
ASSERT(memory != NULL);
ASSERT(page_size > 0);
// Commit a page
ASSERT(os_commit(memory, 1));
// Write to the committed memory
memset(memory, 0x42, os_get_system_info().page_size);
// Release the memory
ASSERT(os_release(memory, MB(1)));
}
// Thread Tests
static int thread_test_func(u64 thread_id, void *userdata) {
int *value = (int*)userdata;
(*value)++;
return 42;
}
UNIT_TEST(os_thread) {
// Create thread data
int value = 0;
// Launch thread
oshandle_t thread = os_thread_launch(thread_test_func, &value);
ASSERT(os_handle_valid(thread));
// Get thread ID
u64 thread_id = os_thread_get_id(thread);
ASSERT(thread_id != 0);
// Join thread
int exit_code;
ASSERT(os_thread_join(thread, &exit_code));
ASSERT(exit_code == 42);
ASSERT(value == 1);
}
int test_mutex_trylock(u64 id, void *userdata) {
oshandle_t mutex = *((oshandle_t*)userdata);
return os_mutex_try_lock(mutex);
}
// Mutex Tests
UNIT_TEST(os_mutex) {
oshandle_t mutex = os_mutex_create();
ASSERT(os_handle_valid(mutex));
oshandle_t thread = os_thread_launch(test_mutex_trylock, &mutex);
// Lock mutex
os_mutex_lock(mutex);
int locked = 0;
os_thread_join(thread, &locked);
ASSERT(locked == false);
// Unlock
os_mutex_unlock(mutex);
// Try lock should succeed now
ASSERT(os_mutex_try_lock(mutex));
// Unlock again
os_mutex_unlock(mutex);
// Free mutex
os_mutex_free(mutex);
}
#if !COLLA_NO_CONDITION_VARIABLE
// Condition Variable Tests
struct cond_test_data {
oshandle_t mutex;
oshandle_t cond;
int counter;
};
static int cond_test_thread(u64 thread_id, void *userdata) {
struct cond_test_data *data = (struct cond_test_data*)userdata;
os_mutex_lock(data->mutex);
data->counter++;
os_mutex_unlock(data->mutex);
// Signal the condition
os_cond_signal(data->cond);
return 0;
}
UNIT_TEST(os_condition_variable) {
struct cond_test_data data;
data.mutex = os_mutex_create();
data.cond = os_cond_create();
data.counter = 0;
// Lock mutex before launching thread
os_mutex_lock(data.mutex);
// Launch thread
oshandle_t thread = os_thread_launch(cond_test_thread, &data);
// Wait for condition with timeout
os_cond_wait(data.cond, data.mutex, 1000);
// We should have the lock again, and counter should be 1
ASSERT(data.counter == 1);
// Unlock and cleanup
os_mutex_unlock(data.mutex);
os_thread_join(thread, NULL);
os_mutex_free(data.mutex);
os_cond_free(data.cond);
}
#endif