diff --git a/include/ft/all-tests.h b/include/ft/all-tests.h index 6011acf..57d8726 100644 --- a/include/ft/all-tests.h +++ b/include/ft/all-tests.h @@ -28,6 +28,7 @@ extern ft_test ft_stdio_printf_basics; extern ft_test ft_stdio_printf_formats; extern ft_test ft_stdio_printf_fp; extern ft_test ft_stdio_open; +extern ft_test ft_stdio_simple_read; /* stdlib */ extern ft_test ft_stdlib_arith; diff --git a/src/main.c b/src/main.c index d5dd1a8..4225ede 100644 --- a/src/main.c +++ b/src/main.c @@ -44,6 +44,7 @@ ft_list headers_libc[] = { &ft_stdio_printf_formats, &ft_stdio_printf_fp, &ft_stdio_open, + &ft_stdio_simple_read, NULL, }}, { _("stdlib.h", ""), (ft_test*[]){ diff --git a/src/stdio/files.c b/src/stdio/files.c index 2efe4b9..442290b 100644 --- a/src/stdio/files.c +++ b/src/stdio/files.c @@ -30,6 +30,7 @@ static void _stdio_open_switch(ft_test *t) DO_E(fp, fopen("ft_stdio.txt", "r"), t, "%p"); ft_assert(t, fp != NULL); ft_log_FILE(t, "", fp); + if(!fp) return; /* Change buffer settings a couple times */ DO_E(rc, setvbuf(fp, NULL, _IONBF, 0), t, "%d"); @@ -69,3 +70,169 @@ ft_test ft_stdio_open = { .name = "Opening files", .function = _stdio_open, }; + +static char const *filler = +"The fread function reads, into the array pointed to by ptr, up to nmemb " +"elements whose size is specified by size, from the stream pointed to by " +"stream. For each object, size calls are made to the fgetc function and the " +"results stored, in the order read, in an array of unsigned char exactly " +"overlaying the object. The file position indicator for the stream (if " +"defined) is advanced by the number of characters successfully read. If an " +"error occurs, the resulting value of the file position indicator for the " +"stream is indeterminate. If a partial element is read, its value is " +"indeterminate.\n"; /* length 591 */ + +static void _ft_stdio_simple_read_switch(ft_test *t) +{ + int fd, rc; + FILE *fp; + char *str = malloc(384); + + /* Create a basic large file (compared to its buffer size) */ + DO_E(fd, creat("ft_stdio.txt", 0755), t, "%d"); + ft_assert(t, fd >= 0); + DO_E(rc, write(fd, filler, 591), t, "%d"); + ft_assert(t, rc == 591); + DO_E(rc, close(fd), t, "%d"); + ft_assert(t, rc == 0); + + /* Read it through a buffer of size 128 */ + DO_E(fp, fopen("ft_stdio.txt", "r"), t, "%p"); + ft_assert(t, fp != NULL); + ft_log_FILE(t, "", fp); + DO_E(rc, setvbuf(fp, NULL, _IOFBF, 128), t, "%d"); + ft_assert(t, rc == 0); + ft_log_FILE(t, "", fp); + DO_E(rc, ftell(fp), t, "%d"); + ft_assert(t, rc == 0); + + /* Perform a first read of 16 bytes */ + DO_E(rc, fread(str, 1, 16, fp), t, "%d"); + ft_assert(t, rc == 16 && !memcmp(str, "The fread functi", 16)); + ft_log_FILE(t, "", fp); + ft_assert(t, fp->bufdir == __FILE_BUF_READ); + ft_assert(t, fp->fdpos == 128); + ft_assert(t, fp->bufread == 128); + ft_assert(t, fp->bufpos == 16); + ft_assert(t, fp->eof == 0); + ft_assert(t, feof(fp) == 0); + + /* Perform several reads that are longer than the buffer */ + DO_E(rc, fread(str, 1, 384, fp), t, "%d"); + ft_assert(t, rc == 384 && !memcmp(str, filler+16, 384)); + ft_log_FILE(t, "", fp); + ft_assert(t, fp->bufdir == __FILE_BUF_READ); + ft_assert(t, fp->fdpos == 512); + ft_assert(t, fp->bufread == 128); + ft_assert(t, fp->bufpos == 16); + ft_assert(t, fp->eof == 0); + ft_assert(t, feof(fp) == 0); + + /* Flush that buffer and check that we remain in place */ + DO_E(rc, fflush(fp), t, "%d"); + ft_assert(t, rc == 0); + ft_log_FILE(t, "", fp); + ft_assert(t, fp->bufdir == __FILE_BUF_READ); + ft_assert(t, fp->fdpos == 400); + ft_assert(t, fp->bufread == 0); + ft_assert(t, fp->bufpos == 0); + DO_E(rc, ftell(fp), t, "%d"); + ft_assert(t, rc == 400); + + /* Do another standard read that will reach end-of-file on the fd */ + DO_E(rc, fread(str, 1, 150, fp), t, "%d"); + ft_assert(t, rc == 150); + ft_log_FILE(t, "", fp); + ft_assert(t, fp->bufdir == __FILE_BUF_READ); + ft_assert(t, fp->fdpos == 591); + ft_assert(t, fp->bufread == 63); + ft_assert(t, fp->bufpos == 22); + ft_assert(t, fp->eof == 1); + ft_assert(t, feof(fp) == 0); + + /* Do one last read that will not be entirely fulfilled */ + DO_E(rc, fread(str, 1, 64, fp), t, "%d"); + ft_assert(t, rc == 41); + ft_log_FILE(t, "", fp); + ft_assert(t, fp->bufdir == __FILE_BUF_READ); + ft_assert(t, fp->fdpos == 591); + ft_assert(t, fp->bufread == 0); + ft_assert(t, fp->bufpos == 0); + ft_assert(t, fp->eof == 1); + ft_assert(t, feof(fp) == 1); + DO_E(rc, ftell(fp), t, "%d"); + ft_assert(t, rc == 591); + + /* Rewind and move around */ + rewind(fp); + ft_log(t, "rewind(fp)\n"); + DO_E(rc, ftell(fp), t, "%d"); + ft_assert(t, rc == 0); + DO_E(rc, fseek(fp, -20, SEEK_END), t, "%d"); + ft_assert(t, rc == 0); + DO_E(rc, ftell(fp), t, "%d"); + ft_assert(t, rc == 571); + ft_assert(t, fp->eof == 0); + ft_assert(t, feof(fp) == 0); + + /* Seek at end of file, the EOF flag should be cleared */ + DO_E(rc, fseek(fp, 0, SEEK_END), t, "%d"); + ft_assert(t, rc == 0); + DO_E(rc, ftell(fp), t, "%d"); + ft_assert(t, rc == 591); + ft_assert(t, fp->eof == 0); + ft_assert(t, feof(fp) == 0); + + /* Attempt to read and get 0+EOF but no error */ + DO_E(rc, fread(str, 8, 1, fp), t, "%d"); + ft_assert(t, rc == 0); + ft_assert(t, fp->eof == 1); + ft_assert(t, feof(fp) == 1); + + /* Read into the buffer, then flush by seeking */ + DO_E(rc, fseek(fp, 0, SEEK_SET), t, "%d"); + ft_assert(t, rc == 0); + DO_E(rc, fread(str, 1, 64, fp), t, "%d"); + ft_assert(t, rc == 64); + ft_assert(t, !memcmp(str, filler, 64)); + ft_log_FILE(t, "", fp); + ft_assert(t, fp->bufdir == __FILE_BUF_READ); + ft_assert(t, fp->fdpos == 128); + ft_assert(t, fp->bufread == 128); + ft_assert(t, fp->bufpos == 64); + ft_assert(t, fp->eof == 0); + ft_assert(t, feof(fp) == 0); + DO_E(rc, fseek(fp, 16, SEEK_SET), t, "%d"); + ft_assert(t, rc == 0); + ft_log_FILE(t, "", fp); + ft_assert(t, fp->fdpos == 16); + ft_assert(t, fp->bufread == 0); + ft_assert(t, fp->bufpos == 0); + ft_assert(t, fp->eof == 0); + ft_assert(t, feof(fp) == 0); + DO_E(rc, fread(str, 1, 64, fp), t, "%d"); + ft_assert(t, rc == 64); + ft_assert(t, !memcmp(str, filler+16, 64)); + ft_log_FILE(t, "", fp); + ft_assert(t, fp->bufdir == __FILE_BUF_READ); + ft_assert(t, fp->fdpos == 144); + ft_assert(t, fp->bufread == 128); + ft_assert(t, fp->bufpos == 64); + ft_assert(t, fp->eof == 0); + ft_assert(t, feof(fp) == 0); + + DO_E(rc, fclose(fp), t, "%d"); + ft_assert(t, rc == 0); + + free(str); +} + +static void _ft_stdio_simple_read(ft_test *t) +{ + gint_world_switch(GINT_CALL(_ft_stdio_simple_read_switch, (void *)t)); +} + +ft_test ft_stdio_simple_read = { + .name = "Simple file reading", + .function = _ft_stdio_simple_read, +}; diff --git a/src/stdio/util.h b/src/stdio/util.h index 48d9b35..b60e02e 100644 --- a/src/stdio/util.h +++ b/src/stdio/util.h @@ -13,7 +13,7 @@ static inline void ft_log_FILE(ft_test *t, char const *prefix, FILE *fp) return; } - ft_log(t, "{fd %d/%d, mode %s%s%s%s%s%s, %s", + ft_log(t, "{fd %d @%d, mode %s%s%s%s%s%s, %s", fp->fd, fp->fdpos, fp->readable ? "r" : "", fp->writable ? "w" : "",