374 lines
9.9 KiB
C
374 lines
9.9 KiB
C
#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
|