.
This commit is contained in:
parent
524ec0d1ce
commit
61c1060a98
16 changed files with 5043 additions and 31 deletions
387
tests/os_tests.c
Normal file
387
tests/os_tests.c
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
#include "runner.h"
|
||||
#include "../colla.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, OS_FILE_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, OS_FILE_READ);
|
||||
ASSERT(os_handle_valid(h_read));
|
||||
ASSERT(!os_handle_match(h_read, zero));
|
||||
|
||||
oshandle_t h_read2 = os_file_open(test_file, OS_FILE_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, OS_FILE_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, OS_FILE_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, OS_FILE_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, OS_FILE_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");
|
||||
os_file_write_all_str(relative_path, strv("hello world"));
|
||||
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);
|
||||
|
||||
os_file_delete(relative_path);
|
||||
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_file_delete(strv("test_dir/test_file.txt"));
|
||||
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, OS_FILE_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);
|
||||
warn(">> %zu", entry->file_size);
|
||||
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
|
||||
typedef struct {
|
||||
u64 canary_beg;
|
||||
oshandle_t mutex;
|
||||
oshandle_t cond_mutex;
|
||||
oshandle_t cond;
|
||||
int counter;
|
||||
u64 canary_end;
|
||||
} cond_test_data;
|
||||
|
||||
static int cond_test_thread(u64 thread_id, void *userdata) {
|
||||
cond_test_data *data = (cond_test_data*)userdata;
|
||||
|
||||
info("%zu %zu", data->canary_beg, data->canary_end);
|
||||
|
||||
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) {
|
||||
cond_test_data data = {
|
||||
.mutex = os_mutex_create(),
|
||||
.cond_mutex = os_mutex_create(),
|
||||
.cond = os_cond_create(),
|
||||
.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_mutex_lock(data.cond_mutex);
|
||||
os_cond_wait(data.cond, data.cond_mutex, 1000);
|
||||
os_mutex_unlock(data.cond_mutex);
|
||||
|
||||
// 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_mutex_free(data.cond_mutex);
|
||||
os_cond_free(data.cond);
|
||||
}
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue