Compare commits

3 Commits

Author SHA1 Message Date
f5c2ed89a4 Add tests for file IO API 2026-01-02 18:56:19 +00:00
989a5f60c4 Update file IO API 2026-01-02 18:56:09 +00:00
659a3e457c Reformat 2026-01-02 17:17:25 +00:00
7 changed files with 312 additions and 27 deletions

View File

@@ -8,7 +8,9 @@
#include "../../base/strings/str8/str8.h" #include "../../base/strings/str8/str8.h"
#include <stdio.h> #include <stdio.h>
File *wapp_file_open(Str8RO *filepath, FileAccessMode mode) { WFile *wapp_file_open(Str8RO *filepath, FileAccessMode mode) {
wapp_debug_assert(filepath != NULL, "`filepath` should not be NULL");
wapp_persist const char *modes[FILE_ACCESS_MODE_COUNT] = { wapp_persist const char *modes[FILE_ACCESS_MODE_COUNT] = {
[WAPP_FA_MODE_R] = "r", [WAPP_FA_MODE_R] = "r",
[WAPP_FA_MODE_W] = "w", [WAPP_FA_MODE_W] = "w",
@@ -36,25 +38,25 @@ File *wapp_file_open(Str8RO *filepath, FileAccessMode mode) {
return fopen((const char *)tmp, modes[mode]); return fopen((const char *)tmp, modes[mode]);
} }
u64 wapp_file_get_current_position(File *file) { i64 wapp_file_get_current_position(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL."); wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return (u64)ftell(file); return ftell(file);
} }
i32 wapp_file_seek(File *file, u64 offset, FileSeekOrigin origin) { i32 wapp_file_seek(WFile *file, u64 offset, FileSeekOrigin origin) {
wapp_debug_assert(file != NULL, "`file` should not be NULL."); wapp_debug_assert(file != NULL, "`file` should not be NULL.");
// TODO (Abdelrahman): Revisit conversion to long // TODO (Abdelrahman): Revisit conversion to long
return fseek(file, (long)offset, origin); return fseek(file, (long)offset, origin);
} }
u64 wapp_file_get_length(File *file) { i64 wapp_file_get_length(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL."); wapp_debug_assert(file != NULL, "`file` should not be NULL.");
u64 current = wapp_file_get_current_position(file); i64 current = wapp_file_get_current_position(file);
wapp_file_seek(file, 0, WAPP_SEEK_END); wapp_file_seek(file, 0, WAPP_SEEK_END);
u64 output = ftell(file); i64 output = wapp_file_get_current_position(file);
// Restore position // Restore position
wapp_file_seek(file, current, WAPP_SEEK_START); wapp_file_seek(file, current, WAPP_SEEK_START);
@@ -62,7 +64,27 @@ u64 wapp_file_get_length(File *file) {
return output; return output;
} }
u64 wapp_file_read(GenericArray dst_buf, File *file, u64 item_count) { u64 wapp_file_read(void *dst_buf, WFile *file, u64 byte_count) {
wapp_debug_assert(dst_buf != NULL && file != NULL,
"`dst_buf` and `file` should not be NULL.");
u64 file_length = wapp_file_get_length(file);
u64 copy_byte_count = file_length <= byte_count ? file_length : byte_count;
u64 count = fread(dst_buf, sizeof(u8), copy_byte_count, file);
if (ferror(file)) { return 0; }
return count;
}
u64 wapp_file_write(const void *src_buf, WFile *file, u64 byte_count) {
wapp_debug_assert(src_buf != NULL && file != NULL,
"`src_buf` and `file` should not be NULL.");
return fwrite(src_buf, sizeof(u8), byte_count, file);
}
u64 wapp_file_read_array(GenericArray dst_buf, WFile *file, u64 item_count) {
wapp_debug_assert(dst_buf != NULL && file != NULL, wapp_debug_assert(dst_buf != NULL && file != NULL,
"`dst_buf` and `file` should not be NULL."); "`dst_buf` and `file` should not be NULL.");
@@ -78,15 +100,17 @@ u64 wapp_file_read(GenericArray dst_buf, File *file, u64 item_count) {
copy_byte_count = file_length <= dst_byte_capacity ? file_length : dst_byte_capacity; copy_byte_count = file_length <= dst_byte_capacity ? file_length : dst_byte_capacity;
} }
u64 count = fread(dst_buf, sizeof(u8), copy_byte_count, file); u64 byte_count = wapp_file_read(dst_buf, file, copy_byte_count);
if (ferror(file)) { return 0; } if (byte_count == 0) {
return 0;
}
wapp_array_set_count(dst_buf, count / item_size); wapp_array_set_count(dst_buf, byte_count / item_size);
return wapp_array_count(dst_buf); return wapp_array_count(dst_buf);
} }
u64 wapp_file_write(const GenericArray src_buf, File *file, u64 item_count) { u64 wapp_file_write_array(const GenericArray src_buf, WFile *file, u64 item_count) {
wapp_debug_assert(src_buf != NULL && file != NULL, wapp_debug_assert(src_buf != NULL && file != NULL,
"`src_buf` and `file` should not be NULL."); "`src_buf` and `file` should not be NULL.");
@@ -95,15 +119,29 @@ u64 wapp_file_write(const GenericArray src_buf, File *file, u64 item_count) {
u64 req_byte_count = item_count * item_size; u64 req_byte_count = item_count * item_size;
u64 to_copy = req_byte_count <= src_byte_count ? req_byte_count : src_byte_count; u64 to_copy = req_byte_count <= src_byte_count ? req_byte_count : src_byte_count;
return fwrite(src_buf, sizeof(u8), to_copy, file); u64 byte_count = wapp_file_write(src_buf, file, to_copy);
return byte_count / item_size;
} }
i32 wapp_file_flush(File *file) { i32 wapp_file_flush(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL."); wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return fflush(file); return fflush(file);
} }
i32 wapp_file_close(File *file) { i32 wapp_file_close(WFile *file) {
wapp_debug_assert(file != NULL, "`file` should not be NULL."); wapp_debug_assert(file != NULL, "`file` should not be NULL.");
return fclose(file); return fclose(file);
} }
i32 wapp_file_remove(Str8RO *filepath) {
wapp_debug_assert(filepath != NULL, "`filepath` should not be NULL");
wapp_persist c8 tmp[WAPP_PATH_MAX] = {0};
wapp_debug_assert(filepath->size < WAPP_PATH_MAX, "`filepath` exceeds max path limit.");
memset(tmp, 0, WAPP_PATH_MAX);
memcpy(tmp, filepath->buf, filepath->size);
return remove((const char *)tmp);
}

View File

@@ -11,7 +11,7 @@
BEGIN_C_LINKAGE BEGIN_C_LINKAGE
#endif // !WAPP_PLATFORM_CPP #endif // !WAPP_PLATFORM_CPP
typedef FILE File; typedef FILE WFile;
typedef enum { typedef enum {
WAPP_FA_MODE_R, // Equivalent to r WAPP_FA_MODE_R, // Equivalent to r
@@ -40,14 +40,17 @@ typedef enum {
WAPP_SEEK_END = SEEK_END, WAPP_SEEK_END = SEEK_END,
} FileSeekOrigin; } FileSeekOrigin;
File *wapp_file_open(Str8RO *filename, FileAccessMode mode); WFile *wapp_file_open(Str8RO *filename, FileAccessMode mode);
u64 wapp_file_get_current_position(File *file); i64 wapp_file_get_current_position(WFile *file);
i32 wapp_file_seek(File *file, u64 offset, FileSeekOrigin origin); i32 wapp_file_seek(WFile *file, u64 offset, FileSeekOrigin origin);
u64 wapp_file_get_length(File *file); i64 wapp_file_get_length(WFile *file);
u64 wapp_file_read(GenericArray dst_buf, File *file, u64 item_count); u64 wapp_file_read(void *dst_buf, WFile *file, u64 byte_count);
u64 wapp_file_write(const GenericArray src_buf, File *file, u64 item_count); u64 wapp_file_write(const void *src_buf, WFile *file, u64 byte_count);
i32 wapp_file_flush(File *file); u64 wapp_file_read_array(GenericArray dst_buf, WFile *file, u64 item_count);
i32 wapp_file_close(File *file); u64 wapp_file_write_array(const GenericArray src_buf, WFile *file, u64 item_count);
i32 wapp_file_flush(WFile *file);
i32 wapp_file_close(WFile *file);
i32 wapp_file_remove(Str8RO *filepath);
#ifdef WAPP_PLATFORM_CPP #ifdef WAPP_PLATFORM_CPP
END_C_LINKAGE END_C_LINKAGE

98
tests/file/test_file.c Normal file
View File

@@ -0,0 +1,98 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "test_file.h"
#define DST_CAPACITY 5
wapp_intern Str8RO test_filename = wapp_str8_lit_ro_initialiser_list("wapptest.bin");
wapp_intern WFile *test_fp = NULL;
wapp_intern I32Array src_array1 = wapp_array(i32, 0, 1, 2, 3, 4);
wapp_intern I32Array src_array2 = wapp_array(i32, 5, 6, 7, 8, 9);
wapp_intern I32Array src_array3 = wapp_array(i32, 10, 11, 12, 13, 14);
wapp_intern I32Array dst_array = wapp_array_with_capacity(i32, DST_CAPACITY, false);
wapp_intern i32 dst_buf[DST_CAPACITY] = {0};
TestFuncResult test_wapp_file_open(void) {
test_fp = wapp_file_open(&test_filename, WAPP_FA_MODE_WB_EX);
return wapp_tester_result(test_fp != NULL);
}
TestFuncResult test_wapp_file_get_current_position(void) {
u64 pos = wapp_file_get_current_position(test_fp);
return wapp_tester_result(pos == 0);
}
TestFuncResult test_wapp_file_seek(void) {
wapp_file_write_array((GenericArray)src_array1, test_fp, wapp_array_count(src_array1));
i32 seek_result = wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
b8 result = seek_result == 0;
wapp_file_seek(test_fp, 0, WAPP_SEEK_START);
return wapp_tester_result(result);
}
TestFuncResult test_wapp_file_get_length(void) {
i64 length = wapp_file_get_length(test_fp);
return wapp_tester_result(length == (i64)(wapp_array_count(src_array1) * wapp_array_item_size(src_array1)));
}
TestFuncResult test_wapp_file_read(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_START);
u64 byte_count = DST_CAPACITY * sizeof(i32);
u64 count = wapp_file_read((void *)dst_buf, test_fp, byte_count);
b8 result = count == byte_count;
for (u64 i = 0; i < DST_CAPACITY; ++i) {
result = result && (dst_buf[i] == *wapp_array_get(i32, src_array1, i));
}
return wapp_tester_result(result);
}
TestFuncResult test_wapp_file_write(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
u64 expected_count = wapp_array_count(src_array2) * wapp_array_item_size(src_array2);
u64 count = wapp_file_write((void *)src_array2, test_fp, expected_count);
return wapp_tester_result(count == expected_count);
}
TestFuncResult test_wapp_file_read_array(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_START);
u64 count = wapp_file_read_array((GenericArray)dst_array, test_fp, wapp_array_count(src_array1));
b8 result = count == wapp_array_count(src_array1) &&
wapp_array_count(dst_array) == wapp_array_count(src_array1);
for (u64 i = 0; i < wapp_array_count(dst_array); ++i) {
result = result && (*wapp_array_get(i32, dst_array, i) == *wapp_array_get(i32, src_array1, i));
}
return wapp_tester_result(result);
}
TestFuncResult test_wapp_file_write_array(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
u64 count = wapp_file_write_array((GenericArray)src_array3, test_fp, wapp_array_count(src_array3));
return wapp_tester_result(count == wapp_array_count(src_array3));
}
TestFuncResult test_wapp_file_flush(void) {
i32 flush_result = wapp_file_flush(test_fp);
return wapp_tester_result(flush_result == 0);
}
TestFuncResult test_wapp_file_close(void) {
i32 close_result = wapp_file_close(test_fp);
return wapp_tester_result(close_result == 0);
}
TestFuncResult test_wapp_file_remove(void) {
i32 remove_result = wapp_file_remove(&test_filename);
return wapp_tester_result(remove_result == 0);
}

102
tests/file/test_file.cc Normal file
View File

@@ -0,0 +1,102 @@
// vim:fileencoding=utf-8:foldmethod=marker
#include "test_file.h"
#define DST_CAPACITY 5
wapp_intern Str8RO test_filename = wapp_str8_lit_ro_initialiser_list("wapptest.bin");
wapp_intern WFile *test_fp = NULL;
wapp_intern i32 dst_buf[DST_CAPACITY] = {0};
wapp_intern I32Array src_array1;
wapp_intern I32Array src_array2;
wapp_intern I32Array src_array3;
wapp_intern I32Array dst_array ;
TestFuncResult test_wapp_file_open(void) {
src_array1 = wapp_array(i32, 0, 1, 2, 3, 4);
src_array2 = wapp_array(i32, 5, 6, 7, 8, 9);
src_array3 = wapp_array(i32, 10, 11, 12, 13, 14);
dst_array = wapp_array_with_capacity(i32, DST_CAPACITY, false);
test_fp = wapp_file_open(&test_filename, WAPP_FA_MODE_WB_EX);
return wapp_tester_result(test_fp != NULL);
}
TestFuncResult test_wapp_file_get_current_position(void) {
u64 pos = wapp_file_get_current_position(test_fp);
return wapp_tester_result(pos == 0);
}
TestFuncResult test_wapp_file_seek(void) {
wapp_file_write_array((GenericArray)src_array1, test_fp, wapp_array_count(src_array1));
i32 seek_result = wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
b8 result = seek_result == 0;
wapp_file_seek(test_fp, 0, WAPP_SEEK_START);
return wapp_tester_result(result);
}
TestFuncResult test_wapp_file_get_length(void) {
i64 length = wapp_file_get_length(test_fp);
return wapp_tester_result(length == (i64)(wapp_array_count(src_array1) * wapp_array_item_size(src_array1)));
}
TestFuncResult test_wapp_file_read(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_START);
u64 byte_count = DST_CAPACITY * sizeof(i32);
u64 count = wapp_file_read((void *)dst_buf, test_fp, byte_count);
b8 result = count == byte_count;
for (u64 i = 0; i < DST_CAPACITY; ++i) {
result = result && (dst_buf[i] == *wapp_array_get(i32, src_array1, i));
}
return wapp_tester_result(result);
}
TestFuncResult test_wapp_file_write(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
u64 expected_count = wapp_array_count(src_array2) * wapp_array_item_size(src_array2);
u64 count = wapp_file_write((void *)src_array2, test_fp, expected_count);
return wapp_tester_result(count == expected_count);
}
TestFuncResult test_wapp_file_read_array(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_START);
u64 count = wapp_file_read_array((GenericArray)dst_array, test_fp, wapp_array_count(src_array1));
b8 result = count == wapp_array_count(src_array1) &&
wapp_array_count(dst_array) == wapp_array_count(src_array1);
for (u64 i = 0; i < wapp_array_count(dst_array); ++i) {
result = result && (*wapp_array_get(i32, dst_array, i) == *wapp_array_get(i32, src_array1, i));
}
return wapp_tester_result(result);
}
TestFuncResult test_wapp_file_write_array(void) {
wapp_file_seek(test_fp, 0, WAPP_SEEK_END);
u64 count = wapp_file_write_array((GenericArray)src_array3, test_fp, wapp_array_count(src_array3));
return wapp_tester_result(count == wapp_array_count(src_array3));
}
TestFuncResult test_wapp_file_flush(void) {
i32 flush_result = wapp_file_flush(test_fp);
return wapp_tester_result(flush_result == 0);
}
TestFuncResult test_wapp_file_close(void) {
i32 close_result = wapp_file_close(test_fp);
return wapp_tester_result(close_result == 0);
}
TestFuncResult test_wapp_file_remove(void) {
i32 remove_result = wapp_file_remove(&test_filename);
return wapp_tester_result(remove_result == 0);
}

20
tests/file/test_file.h Normal file
View File

@@ -0,0 +1,20 @@
// vim:fileencoding=utf-8:foldmethod=marker
#ifndef TEST_FILE_H
#define TEST_FILE_H
#include "wapp.h"
TestFuncResult test_wapp_file_open(void);
TestFuncResult test_wapp_file_get_current_position(void);
TestFuncResult test_wapp_file_seek(void);
TestFuncResult test_wapp_file_get_length(void);
TestFuncResult test_wapp_file_read(void);
TestFuncResult test_wapp_file_write(void);
TestFuncResult test_wapp_file_read_array(void);
TestFuncResult test_wapp_file_write_array(void);
TestFuncResult test_wapp_file_flush(void);
TestFuncResult test_wapp_file_close(void);
TestFuncResult test_wapp_file_remove(void);
#endif // !TEST_FILE_H

View File

@@ -5,6 +5,7 @@
#include "test_str8_array.h" #include "test_str8_array.h"
#include "test_i32_array.h" #include "test_i32_array.h"
#include "test_cpath.h" #include "test_cpath.h"
#include "test_file.h"
#include "test_shell_commander.h" #include "test_shell_commander.h"
#include "wapp.h" #include "wapp.h"
#include <stdlib.h> #include <stdlib.h>
@@ -70,6 +71,17 @@ int main(void) {
test_cpath_join_path, test_cpath_join_path,
test_cpath_dirname, test_cpath_dirname,
test_cpath_dirup, test_cpath_dirup,
test_wapp_file_open,
test_wapp_file_get_current_position,
test_wapp_file_seek,
test_wapp_file_get_length,
test_wapp_file_read,
test_wapp_file_write,
test_wapp_file_read_array,
test_wapp_file_write_array,
test_wapp_file_flush,
test_wapp_file_close,
test_wapp_file_remove,
test_commander_cmd_success, test_commander_cmd_success,
test_commander_cmd_failure, test_commander_cmd_failure,
test_commander_cmd_out_buf_success, test_commander_cmd_out_buf_success,

View File

@@ -5,6 +5,7 @@
#include "test_str8_array.h" #include "test_str8_array.h"
#include "test_i32_array.h" #include "test_i32_array.h"
#include "test_cpath.h" #include "test_cpath.h"
#include "test_file.h"
#include "test_shell_commander.h" #include "test_shell_commander.h"
#include "wapp.h" #include "wapp.h"
#include <stdlib.h> #include <stdlib.h>
@@ -70,6 +71,17 @@ int main(void) {
test_cpath_join_path, test_cpath_join_path,
test_cpath_dirname, test_cpath_dirname,
test_cpath_dirup, test_cpath_dirup,
test_wapp_file_open,
test_wapp_file_get_current_position,
test_wapp_file_seek,
test_wapp_file_get_length,
test_wapp_file_read,
test_wapp_file_write,
test_wapp_file_read_array,
test_wapp_file_write_array,
test_wapp_file_flush,
test_wapp_file_close,
test_wapp_file_remove,
test_commander_cmd_success, test_commander_cmd_success,
test_commander_cmd_failure, test_commander_cmd_failure,
test_commander_cmd_out_buf_success, test_commander_cmd_out_buf_success,