#include #include #include #include #include #include #include #include #include #include #include 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 */ DO_E(rc, mkdir("ft_test", 0755), t, "%d"); ft_assert(t, rc == 0); 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); /* Clean up everything */ DO_E(rc, rmdir("ft_test/subfolder"), t, "%d"); ft_assert(t, rc == -1 && errno == ENOTEMPTY); DO_E(rc, unlink("ft_test/subfolder"), t, "%d"); ft_assert(t, rc == -1 && errno == ENOTDIR); DO_E(rc, unlink("ft_test/subfolder/file.txt"), t, "%d"); ft_assert(t, rc == 0); DO_E(rc, rmdir("ft_test/subfolder"), t, "%d"); ft_assert(t, rc == 0); DO_E(rc, unlink("ft_test/file.txt"), t, "%d"); ft_assert(t, rc == 0); DO_E(rc, rmdir("ft_test"), t, "%d"); ft_assert(t, rc == 0); } 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, };