FxLibcTest/src/unistd/files.c

366 lines
9.4 KiB
C

#include <ft/test.h>
#include <ft/all-tests.h>
#include <ft/util.h>
#include <gint/gint.h>
#include <gint/bfile.h>
#include <gint/fs.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
extern char **fs_split_components(char *path, int *count);
static void log_comps(ft_test *t, char const *path, char const *solution)
{
ft_log(t, "Splitting: %s\n", path);
char *path_dup = strdup(path);
if(!path_dup) {
ft_log(t, " ENOMEM\n");
return;
}
int count;
char **comps = fs_split_components(path_dup, &count);
for(int i = 0; i < count; i++) {
ft_log(t, " --> %s\n", comps[i]);
}
if(count == 0) {
ft_log(t, " (empty)\n");
}
free(path_dup);
free(comps);
char *norm1 = fs_path_normalize(path);
ft_log(t, "Normalized (UTF-8): %s\n", norm1);
ft_assert(t, !strcmp(norm1, solution));
free(norm1);
uint16_t *norm2 = fs_path_normalize_fc(path);
ft_log(t, "Normalized (FC): ");
for(int i = 0; norm2[i]; i++) ft_log(t, "%c", norm2[i]);
ft_log(t, "\n\n");
free(norm2);
}
static void _ft_unistd_paths(ft_test *t)
{
ft_log(t, "\nPath normalization:\n\n");
log_comps(t, ".", "/");
log_comps(t, "/", "/");
log_comps(t, "/*", "/*");
log_comps(t, "/file.txt", "/file.txt");
log_comps(t, "file.txt", "/file.txt");
log_comps(t, "folder/file", "/folder/file");
log_comps(t, "a/b/c/d", "/a/b/c/d");
log_comps(t, "/a/b//c", "/a/b/c");
log_comps(t, "folder////file", "/folder/file");
log_comps(t, "//folder///file///", "/folder/file");
log_comps(t, "./../er//e/", "/er/e");
log_comps(t, "x/../y/z/../t", "/y/t");
}
ft_test ft_unistd_path = {
.name = "Path normalization",
.function = _ft_unistd_paths,
};
static void _ft_unistd_simple_write_switch(ft_test *t)
{
int fd, rc;
errno = 0;
DO_E(fd, open("ft_write.txt", O_WRONLY | O_CREAT), t, "%d");
ft_assert(t, fd >= 0);
if(fd >= 0) {
DO_E(rc, write(fd, "write\n", 6), t, "%d");
ft_assert(t, rc == 6);
DO_E(rc, write(fd, "line #2\n", 8), t, "%d");
ft_assert(t, rc == 8);
DO_E(rc, write(fd, "line #3\n", 8), t, "%d");
ft_assert(t, rc == 8);
}
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
}
static void _ft_unistd_simple_write(ft_test *t)
{
gint_world_switch(GINT_CALL(_ft_unistd_simple_write_switch,(void *)t));
}
ft_test ft_unistd_simple_write = {
.name = "Write simple file",
.function = _ft_unistd_simple_write,
};
static void _ft_unistd_write_odd_switch_1(ft_test *t)
{
int fd, rc;
errno = 0;
DO_E(fd, open("ft_odd1.txt", O_WRONLY | O_CREAT), t, "%d");
ft_assert(t, fd >= 0);
if(fd >= 0) {
DO_E(rc, write(fd, "write odd byte count\n", 21), t, "%d");
ft_assert(t, rc == 21);
DO_E(rc, write(fd, "again, cancelling it\n", 21), t, "%d");
ft_assert(t, rc == 21);
}
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
}
static void _ft_unistd_write_odd_switch_2(ft_test *t)
{
int fd, rc;
errno = 0;
DO_E(fd, open("ft_odd2.txt", O_WRONLY | O_CREAT), t, "%d");
ft_assert(t, fd >= 0);
if(fd >= 0) {
DO_E(rc, write(fd, "write odd byte count\n", 21), t, "%d");
ft_assert(t, rc == 21);
DO_E(rc, write(fd, "then even, keeping it\n", 22), t, "%d");
ft_assert(t, rc == 22);
}
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
}
static void _ft_unistd_write_odd(ft_test *t)
{
gint_world_switch(GINT_CALL(_ft_unistd_write_odd_switch_1, (void *)t));
gint_world_switch(GINT_CALL(_ft_unistd_write_odd_switch_2, (void *)t));
}
ft_test ft_unistd_write_odd = {
.name = "Odd-length writes",
.function = _ft_unistd_write_odd,
};
static void _ft_unistd_simple_read_switch(ft_test *t)
{
/* First we need to generate some stuff to read... */
int fd, rc;
errno = 0;
DO_E(fd, open("ft_read.txt", O_WRONLY | O_CREAT | O_TRUNC), t, "%d");
ft_assert(t, fd >= 0);
if(fd >= 0) {
DO_E(rc, write(fd, "_ft_unistd_simple_read", 22), t, "%d");
ft_assert(t, rc == 22);
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
}
else return;
/* Then actually read it */
DO_E(fd, open("ft_read.txt", O_RDONLY), t, "%d");
ft_assert(t, fd >= 0);
if(fd < 0) return;
int fugue_fd = (int)fs_get_descriptor(fd)->data;
ft_log(t, "[INFO] lseek(fd, 0, SEEK_CUR) = %ld\n",
lseek(fd, 0, SEEK_CUR));
DO_E(rc, BFile_Size(fugue_fd), t, "%d");
char buffer[29] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
DO_E(rc, read(fd, buffer, 11), t, "%d");
ft_assert(t, rc == 11);
ft_assert(t, !strcmp(buffer, "_ft_unistd_xxxxxxxxxxxxxxxxx"));
ft_log(t, "[INFO] lseek(fd, 0, SEEK_CUR) = %ld\n",
lseek(fd, 0, SEEK_CUR));
DO_E(rc, BFile_Size(fugue_fd), t, "%d");
DO_E(rc, read(fd, buffer + 11, 11), t, "%d");
ft_assert(t, rc == 11);
ft_assert(t, !strcmp(buffer, "_ft_unistd_simple_readxxxxxx"));
ft_log(t, "[INFO] lseek(fd, 0, SEEK_CUR) = %ld\n",
lseek(fd, 0, SEEK_CUR));
DO_E(rc, BFile_Size(fugue_fd), t, "%d");
ft_log(t, "[INFO] lseek(fd, 4, SEEK_SET) = %ld\n",
lseek(fd, 4, SEEK_SET));
ft_log(t, "[INFO] lseek(fd, 4, SEEK_END) = %ld\n",
lseek(fd, 4, SEEK_END));
ft_log(t, "[INFO] lseek(fd, 0, SEEK_CUR) = %ld\n",
lseek(fd, 4, SEEK_CUR));
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
}
static void _ft_unistd_simple_read(ft_test *t)
{
gint_world_switch(GINT_CALL(_ft_unistd_simple_read_switch, (void *)t));
}
ft_test ft_unistd_simple_read = {
.name = "Simple read",
.function = _ft_unistd_simple_read,
};
static void _ft_unistd_seek_patterns_switch(ft_test *t)
{
/* Generate a basic file */
int fd, rc;
errno = 0;
DO_E(fd, open("ft_seek.txt", O_WRONLY | O_CREAT | O_TRUNC), t, "%d");
ft_assert(t, fd >= 0);
if(fd >= 0) {
DO_E(rc, write(fd, "_ft_unistd_seek_patterns", 24), t, "%d");
ft_assert(t, rc == 24);
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
}
else return;
DO_E(fd, open("ft_seek.txt", O_RDWR), t, "%d");
ft_assert(t, fd >= 0);
if(fd < 0) return;
int fugue_fd = (int)fs_get_descriptor(fd)->data;
/* Read from the start */
char str[32] = { 0 };
DO_E(rc, read(fd, str, 8), t, "%d");
ft_assert(t, rc == 8 && !strncmp(str, "_ft_unis", 8));
DO_E(rc, read(fd, str, 4), t, "%d");
ft_assert(t, rc == 4 && !strncmp(str, "td_sunis", 8));
/* Rewind */
DO_E(rc, lseek(fd, 0, SEEK_SET), t, "%d");
ft_assert(t, rc == 0);
DO_E(rc, read(fd, str, 24), t, "%d");
ft_assert(t, rc == 24 && !strcmp(str, "_ft_unistd_seek_patterns"));
/* Read from the middle */
DO_E(rc, pread(fd, str, 8, (off_t)12), t, "%d");
ft_assert(t, rc == 8 && !strncmp(str, "eek_patt", 8));
/* Write to the end */
DO_E(rc, lseek(fd, -8, SEEK_END), t, "%d");
ft_assert(t, rc == 16);
DO_E(rc, write(fd, "methods!", 8), t, "%d");
ft_assert(t, rc == 8);
/* Read again from the end */
DO_E(rc, pread(fd, str, 8, (off_t)16), t, "%d");
ft_assert(t, rc == 8 && !strncmp(str, "methods!", 8));
/* Play around with absolute seeking */
DO_E(rc, lseek(fd, -4, SEEK_END), t, "%d");
ft_assert(t, rc == 20);
DO_E(rc, lseek(fd, 0, SEEK_END), t, "%d");
ft_assert(t, rc == BFile_Size(fugue_fd));
DO_E(rc, lseek(fd, 8, SEEK_SET), t, "%d");
ft_assert(t, rc == 8);
/* Relative seeking */
DO_E(rc, lseek(fd, -6, SEEK_CUR), t, "%d");
ft_assert(t, rc == 2);
/* Write in the middle */
DO_E(rc, pwrite(fd, "@", 1, (off_t)3), t, "%d");
ft_assert(t, rc == 1);
DO_E(rc, lseek(fd, 0, SEEK_SET), t, "%d");
ft_assert(t, rc == 0);
memset(str, 0, sizeof str);
DO_E(rc, read(fd, str, 24), t, "%d");
ft_assert(t, rc == 24 && !strcmp(str, "_ft@unistd_seek_methods!"));
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
}
static void _ft_unistd_seek_patterns(ft_test *t)
{
gint_world_switch(GINT_CALL(_ft_unistd_seek_patterns_switch,
(void *)t));
}
ft_test ft_unistd_seek_patterns = {
.name = "Seek patterns",
.function = _ft_unistd_seek_patterns,
};
static void _ft_unistd_folders_switch(ft_test *t)
{
int rc, fd, type, size;
/* Create a directory (don't fail if we already ran the test before) */
DO_E(rc, mkdir("ft_test", 0755), t, "%d");
ft_assert(t, rc == 0 || (rc == -1 && errno == EEXIST));
ft_log(t, "note: this folder might already exist\n");
/* Remove that directory */
DO_E(rc, rmdir("ft_test"), t, "%d");
ft_assert(t, rc == 0);
/* Create it anew (and empty) */
DO_E(rc, mkdir("ft_test", 0755), t, "%d");
ft_assert(t, rc == 0);
DO_E(rc, mkdir("ft_test", 0755), t, "%d");
ft_assert(t, rc == -1 && errno == EEXIST);
/* Create a file in that directory, write some stuff and close it */
DO_E(fd, open("ft_test/file.txt", O_RDWR | O_CREAT | O_TRUNC), t,"%d");
ft_assert(t, fd >= 0);
DO_E(rc, write(fd, "Some data\n", 10), t, "%d");
ft_assert(t, rc == 10);
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
/* Stat that file */
rc = BFile_Ext_Stat(u"\\\\fls0\\ft_test\\file.txt", &type, &size);
ft_log(t, "BFile_Ext_Stat()=%d (type=%d, size=%d)\n", rc, type, size);
ft_assert(t, rc == 0 && type == BFile_Type_File && size == 10);
/* Create a subfolder */
DO_E(rc, mkdir("ft_test/subfolder", 0755), t, "%d");
ft_assert(t, rc == 0);
/* Create a file in the subfolder and stat it again */
DO_E(fd, open("ft_test/subfolder/file.txt", O_RDWR | O_CREAT
| O_TRUNC), t, "%d");
ft_assert(t, fd >= 0);
DO_E(rc, write(fd, "Some data for the subfolder\n", 28), t, "%d");
ft_assert(t, rc == 28);
DO_E(rc, close(fd), t, "%d");
ft_assert(t, rc == 0);
rc = BFile_Ext_Stat(u"\\\\fls0\\ft_test\\subfolder\\file.txt",
&type, &size);
ft_log(t, "BFile_Ext_Stat()=%d (type=%d, size=%d)\n", rc, type, size);
ft_assert(t, rc == 0 && type == BFile_Type_File && size == 28);
}
static void _ft_unistd_folders(ft_test *t)
{
gint_world_switch(GINT_CALL(_ft_unistd_folders_switch, (void *)t));
}
ft_test ft_unistd_folders = {
.name = "Using folders",
.function = _ft_unistd_folders,
};