1142 lines
33 KiB
C
1142 lines
33 KiB
C
#include <ft/test.h>
|
|
#include <ft/all-tests.h>
|
|
#include <ft/util.h>
|
|
#include <ft/streams.h>
|
|
|
|
#include <gint/gint.h>
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include "util.h"
|
|
|
|
static void _stdio_open_switch(ft_test *t)
|
|
{
|
|
int fd, rc;
|
|
FILE *fp;
|
|
|
|
/* Create a basic file */
|
|
DO_E(fd, creat("ft_stdio.txt", 0755), t, "%d");
|
|
ft_assert(t, fd >= 0);
|
|
DO_E(rc, write(fd, "Hello, stdio!\n", 14), t, "%d");
|
|
ft_assert(t, rc == 14);
|
|
DO_E(rc, close(fd), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Try to open it with <stdio.h> */
|
|
DO_E(fp, fopen("ft_stdio.txt", "r"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
|
|
/* Change buffer settings a couple times */
|
|
DO_E(rc, setvbuf(fp, NULL, _IONBF, 0), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, setvbuf(fp, NULL, _IOLBF, 1024), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, setvbuf(fp, NULL, _IOFBF, BUFSIZ), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
|
|
/* Reopen with different permissions */
|
|
DO_E(fp, freopen("ft_stdio.txt", "w+", fp), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(fp, freopen("ft_stdio.txt", "rb+", fp), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(fp, freopen("ft_stdio.txt", "ab", fp), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(fp, freopen("ft_stdio.txt", "w", fp), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
}
|
|
|
|
static void _stdio_open(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_stdio_open_switch, (void *)t));
|
|
}
|
|
|
|
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"; /* ISO/IEC 9899:1999, 7.19.8.1§2 (length 591) */
|
|
|
|
static void _ft_stdio_simple_read_switch(ft_test *t)
|
|
{
|
|
int fd, rc;
|
|
FILE *fp;
|
|
char *str = malloc(384);
|
|
fpos_t pos1, pos2;
|
|
|
|
/* 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);
|
|
if(fp == NULL) return;
|
|
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);
|
|
|
|
/* Move around with fgetpos() and fsetpos() */
|
|
DO_E(rc, fgetpos(fp, &pos1), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_assert(t, (size_t)pos1 == 571);
|
|
DO_E(rc, fseek(fp, 12, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, fgetpos(fp, &pos2), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_assert(t, (size_t)pos2 == 12);
|
|
DO_E(rc, fsetpos(fp, &pos1), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 571);
|
|
DO_E(rc, fsetpos(fp, &pos2), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 12);
|
|
|
|
/* 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,
|
|
};
|
|
|
|
static void _ft_stdio_simple_write_switch(ft_test *t)
|
|
{
|
|
FILE *fp;
|
|
int rc;
|
|
|
|
/* Open a new file */
|
|
DO_E(fp, fopen("ft_stdio.txt", "w"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
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);
|
|
|
|
/* Write small parts into the buffer until it flushes */
|
|
DO_E(rc, fwrite(filler, 1, 32, fp), t, "%d");
|
|
ft_assert(t, rc == 32);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->fdpos == 0);
|
|
ft_assert(t, fp->bufpos == 32);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 32);
|
|
DO_E(rc, fwrite(filler, 1, 32, fp), t, "%d");
|
|
ft_assert(t, rc == 32);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->fdpos == 0);
|
|
ft_assert(t, fp->bufpos == 64);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 64);
|
|
DO_E(rc, fwrite(filler, 1, 32, fp), t, "%d");
|
|
ft_assert(t, rc == 32);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->fdpos == 0);
|
|
ft_assert(t, fp->bufpos == 96);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 96);
|
|
DO_E(rc, fwrite(filler, 1, 32, fp), t, "%d");
|
|
ft_assert(t, rc == 32);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->fdpos == 128);
|
|
ft_assert(t, fp->bufpos == 0);
|
|
|
|
/* Write small bits and flush them immediately */
|
|
DO_E(rc, fwrite(filler, 1, 9, fp), t, "%d");
|
|
ft_assert(t, rc == 9);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->fdpos == 128);
|
|
ft_assert(t, fp->bufpos == 9);
|
|
DO_E(rc, fflush(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_assert(t, fp->fdpos == 137);
|
|
ft_assert(t, fp->bufpos == 0);
|
|
|
|
/* Write a large section which will flush several times */
|
|
DO_E(rc, fwrite(filler, 1, 591, fp), t, "%d");
|
|
ft_assert(t, rc == 591);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->fdpos == 649);
|
|
ft_assert(t, fp->bufpos == 79);
|
|
|
|
/* Flush by seeking somewhere else */
|
|
DO_E(rc, fseek(fp, -16, SEEK_END), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 712);
|
|
ft_assert(t, fp->bufpos == 0);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 712);
|
|
|
|
/* Now overwrite the last 16 bytes and extend the file */
|
|
DO_E(rc, fwrite(filler, 1, 32, fp), t, "%d");
|
|
ft_assert(t, rc == 32);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->fdpos == 712);
|
|
ft_assert(t, fp->bufpos == 32);
|
|
|
|
/* Close the file, which should flush */
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Check the new file size */
|
|
DO_E(fp, fopen("ft_stdio.txt", "r"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
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 == 744);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
}
|
|
|
|
static void _ft_stdio_simple_write(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_ft_stdio_simple_write_switch, (void *)t));
|
|
}
|
|
|
|
ft_test ft_stdio_simple_write = {
|
|
.name = "Simple file writing",
|
|
.function = _ft_stdio_simple_write,
|
|
};
|
|
|
|
static void _ft_stdio_line_buffering_switch(ft_test *t)
|
|
{
|
|
FILE *fp;
|
|
int rc;
|
|
|
|
/* Open a new line-buffered file */
|
|
DO_E(fp, fopen("ft_stdio.txt", "w"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, setvbuf(fp, NULL, _IOLBF, 128), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
|
|
/* Write some short strings, which should flush due to newlines */
|
|
DO_E(rc, fwrite("Line #1\n", 1, 8, fp), t, "%d");
|
|
ft_assert(t, rc == 8);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 8);
|
|
ft_assert(t, fp->bufpos == 0);
|
|
DO_E(rc, fwrite("A longer line #2\n", 1, 17, fp), t, "%d");
|
|
ft_assert(t, rc == 17);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 25);
|
|
ft_assert(t, fp->bufpos == 0);
|
|
DO_E(rc, fwrite("Partial line #", 1, 14, fp), t, "%d");
|
|
ft_assert(t, rc == 14);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 25);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->bufpos == 14);
|
|
DO_E(rc, fwrite("3\nand something on the-- ", 1, 25, fp), t, "%d");
|
|
ft_assert(t, rc == 25);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 41);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->bufpos == 23);
|
|
|
|
/* The buffer should still flush when full */
|
|
DO_E(rc, fwrite(filler, 1, 250, fp), t, "%d");
|
|
ft_assert(t, rc == 250);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 297);
|
|
ft_assert(t, fp->bufdir == __FILE_BUF_WRITE);
|
|
ft_assert(t, fp->bufpos == 17);
|
|
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
}
|
|
|
|
static void _ft_stdio_line_buffering(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_ft_stdio_line_buffering_switch,
|
|
(void *)t));
|
|
}
|
|
|
|
ft_test ft_stdio_line_buffering = {
|
|
.name = "Writing with line buffering",
|
|
.function = _ft_stdio_line_buffering,
|
|
};
|
|
|
|
static void _ft_stdio_update_ungetc_switch(ft_test *t)
|
|
{
|
|
FILE *fp;
|
|
int rc;
|
|
char str[128];
|
|
|
|
/* Create a file in update mode with w+ */
|
|
DO_E(fp, fopen("ft_stdio.txt", "w+"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
/* Write some data, then re-read it, then re-write it */
|
|
DO_E(rc, fwrite(filler, 1, 64, fp), t, "%d");
|
|
ft_assert(t, rc == 64);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fseek(fp, 0, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fread(str, 1, 16, fp), t, "%d");
|
|
ft_assert(t, rc == 16);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fread(str, 1, 48, fp), t, "%d");
|
|
ft_assert(t, rc == 48);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, ftell(fp) == 64);
|
|
DO_E(rc, fseek(fp, -16, SEEK_CUR), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, fwrite(str, 1, 48, fp), t, "%d");
|
|
ft_assert(t, rc == 48);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fwrite(str, 1, 16, fp), t, "%d");
|
|
ft_assert(t, rc == 16);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, ftell(fp) == 112);
|
|
/* Re-read it and check it */
|
|
rewind(fp);
|
|
ft_log(t, "rewind(fp)\n");
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fread(str, 1, 112, fp), t, "%d");
|
|
ft_assert(t, rc == 112);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !memcmp(str, filler, 48));
|
|
ft_assert(t, !memcmp(str+48, filler+16, 48));
|
|
ft_assert(t, !memcmp(str+96, filler+16, 16));
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log(t, "\n");
|
|
|
|
/* Reopen that file with r+ */
|
|
DO_E(fp, fopen("ft_stdio.txt", "r+"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
/* ungetc() some characters before position 0 */
|
|
DO_E(rc, ungetc('#', fp), t, "'%c'");
|
|
ft_assert(t, rc == '#');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ungetc('!', fp), t, "'%c'");
|
|
ft_assert(t, rc == '!');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ungetc('$', fp), t, "'%c'");
|
|
ft_assert(t, rc == '$');
|
|
ft_log_FILE(t, "", fp);
|
|
/* Read them back along with some actual data */
|
|
DO_E(rc, fread(str, 1, 51, fp), t, "%d");
|
|
ft_assert(t, rc == 51);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !memcmp(str, "$!#", 3) && !memcmp(str+3, filler, 48));
|
|
/* Do it again after position 0 */
|
|
DO_E(rc, ungetc('#', fp), t, "'%c'");
|
|
ft_assert(t, rc == '#');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ungetc('!', fp), t, "'%c'");
|
|
ft_assert(t, rc == '!');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ungetc('$', fp), t, "'%c'");
|
|
ft_assert(t, rc == '$');
|
|
ft_log_FILE(t, "", fp);
|
|
/* Read them back as well as the second segment */
|
|
DO_E(rc, fread(str, 1, 51, fp), t, "%d");
|
|
ft_assert(t, rc == 51);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !memcmp(str, "$!#", 3) && !memcmp(str+3, filler+16, 48));
|
|
/* Push some characters but discard them by rewind() */
|
|
DO_E(rc, ungetc('#', fp), t, "'%c'");
|
|
ft_assert(t, rc == '#');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fseek(fp, 0, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fread(str, 1, 48, fp), t, "%d");
|
|
ft_assert(t, rc == 48);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !memcmp(str, filler, 48));
|
|
/* Discard buffered data by a write (nonstandard but supported) */
|
|
DO_E(rc, fwrite(filler, 1, 48, fp), t, "%d");
|
|
ft_assert(t, rc == 48);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Try ungetc() like previousy but with a non-buffered stream */
|
|
DO_E(fp, fopen("ft_stdio.txt", "r+"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, setvbuf(fp, NULL, _IONBF, 0), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
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 == 112);
|
|
DO_E(rc, fseek(fp, 0, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
/* ungetc() some characters before position 0 */
|
|
DO_E(rc, ungetc('#', fp), t, "'%c'");
|
|
ft_assert(t, rc == '#');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ungetc('!', fp), t, "'%c'");
|
|
ft_assert(t, rc == '!');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ungetc('$', fp), t, "'%c'");
|
|
ft_assert(t, rc == '$');
|
|
ft_log_FILE(t, "", fp);
|
|
/* Read them back along with some actual data */
|
|
DO_E(rc, fread(str, 1, 51, fp), t, "%d");
|
|
ft_assert(t, rc == 51);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !memcmp(str, "$!#", 3) && !memcmp(str+3, filler, 48));
|
|
/* Do it again after position 0 */
|
|
DO_E(rc, ungetc('#', fp), t, "'%c'");
|
|
ft_assert(t, rc == '#');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ungetc('!', fp), t, "'%c'");
|
|
ft_assert(t, rc == '!');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ungetc('$', fp), t, "'%c'");
|
|
ft_assert(t, rc == '$');
|
|
ft_log_FILE(t, "", fp);
|
|
/* Read them back as well as the second segment */
|
|
DO_E(rc, fread(str, 1, 51, fp), t, "%d");
|
|
ft_assert(t, rc == 51);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !memcmp(str, "$!#", 3) && !memcmp(str+3, filler, 48));
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
}
|
|
|
|
static void _ft_stdio_update_ungetc(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_ft_stdio_update_ungetc_switch,
|
|
(void *)t));
|
|
}
|
|
|
|
ft_test ft_stdio_update_ungetc = {
|
|
.name = "Update modes and ungetc()",
|
|
.function = _ft_stdio_update_ungetc,
|
|
};
|
|
|
|
static void _ft_stdio_append_switch(ft_test *t)
|
|
{
|
|
FILE *fp;
|
|
int rc;
|
|
char str[40];
|
|
|
|
/* Remove the file if it exists */
|
|
DO_E(rc, remove("ft_append.txt"), t, "%d");
|
|
ft_assert(t, rc == 0 || (rc == -1 && errno == ENOENT));
|
|
|
|
/* Append some data with mode a */
|
|
DO_E(fp, fopen("ft_append.txt", "a"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fwrite("Line #1\n", 1, 8, fp), t, "%d");
|
|
ft_assert(t, rc == 8);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fseek(fp, 0, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_assert(t, ftell(fp) == 0);
|
|
DO_E(rc, fwrite("Line #2\n", 1, 8, fp), t, "%d");
|
|
ft_assert(t, rc == 8);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 16);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Append more with a+ */
|
|
DO_E(fp, fopen("ft_append.txt", "a+"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
DO_E(rc, fseek(fp, 0, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_assert(t, ftell(fp) == 0);
|
|
DO_E(rc, fread(str, 1, 8, fp), t, "%d");
|
|
ft_assert(t, rc == 8);
|
|
ft_assert(t, ftell(fp) == 8);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fwrite(str, 1, 8, fp), t, "%d");
|
|
ft_assert(t, rc == 8);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 24);
|
|
DO_E(rc, fseek(fp, 8, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, fread(str, 1, 16, fp), t, "%d");
|
|
ft_assert(t, rc == 16);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fseek(fp, -8, SEEK_END), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_assert(t, ftell(fp) == 16);
|
|
DO_E(rc, fwrite(str, 1, 16, fp), t, "%d");
|
|
ft_assert(t, rc == 16);
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, ftell(fp), t, "%d");
|
|
ft_assert(t, rc == 40);
|
|
DO_E(rc, fseek(fp, 0, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, fread(str, 1, 40, fp), t, "%d");
|
|
ft_assert(t, rc == 40);
|
|
ft_assert(t, !memcmp(str,
|
|
"Line #1\nLine #2\nLine #1\nLine #2\nLine #1\n", 40));
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
}
|
|
|
|
static void _ft_stdio_append(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_ft_stdio_append_switch, (void *)t));
|
|
}
|
|
|
|
ft_test ft_stdio_append = {
|
|
.name = "Append modes",
|
|
.function = _ft_stdio_append,
|
|
};
|
|
|
|
static void _ft_stdio_fdopen_switch(ft_test *t)
|
|
{
|
|
int fd, rc;
|
|
FILE *fp;
|
|
char str[128];
|
|
|
|
/* Write some stuff through fdopen() */
|
|
DO_E(fd, creat("ft_fdopen.txt", 0755), t, "%d");
|
|
ft_assert(t, fd >= 0);
|
|
if(fd < 0) return;
|
|
DO_E(fp, fdopen(fd, "w"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) {
|
|
close(fd);
|
|
return;
|
|
}
|
|
DO_E(rc, fwrite(filler, 1, 128, fp), t, "%d");
|
|
ft_assert(t, rc == 128);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Check that the contents are correct */
|
|
DO_E(fp, fopen("ft_fdopen.txt", "r"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
DO_E(rc, fread(str, 1, 128, fp), t, "%d");
|
|
ft_assert(t, rc == 128);
|
|
ft_assert(t, !memcmp(str, filler, 128));
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
}
|
|
|
|
static void _ft_stdio_fdopen(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_ft_stdio_fdopen_switch, (void *)t));
|
|
}
|
|
|
|
ft_test ft_stdio_fdopen = {
|
|
.name = "FILE wrapper with fdopen()",
|
|
.function = _ft_stdio_fdopen,
|
|
};
|
|
|
|
static void _ft_stdio_write_chars_switch(ft_test *t)
|
|
{
|
|
FILE *fp;
|
|
int rc;
|
|
|
|
/* Create a buffered file with basic data */
|
|
DO_E(fp, fopen("ft_fput.txt", "w"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, setvbuf(fp, NULL, _IOFBF, 32), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, fputs("Test!", fp), t, "%d");
|
|
ft_assert(t, rc >= 0);
|
|
ft_log_FILE(t, "",fp);
|
|
ft_assert(t, fp->fdpos == 0);
|
|
ft_assert(t, fp->bufpos == 5);
|
|
DO_E(rc, fputs("Testing fputs() on _IOFBF streams\n", fp), t, "%d");
|
|
ft_assert(t, rc >= 0);
|
|
ft_log_FILE(t, "",fp);
|
|
ft_assert(t, fp->fdpos == 32);
|
|
ft_assert(t, fp->bufpos == 7);
|
|
for(int i = 0; i < 26; i++) {
|
|
DO_E(rc, fputc('A'+i, fp), t, "'%c'");
|
|
ft_assert(t, rc == 'A'+i);
|
|
DO_E(rc, fputc('a'+i, fp), t, "'%c'");
|
|
ft_assert(t, rc == 'a'+i);
|
|
}
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 64);
|
|
ft_assert(t, fp->bufpos == 27);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Same, but make it line-buffered */
|
|
DO_E(fp, fopen("ft_fput.txt", "w"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, setvbuf(fp, NULL, _IOLBF, 32), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, fputs("Testing fputs() on _IOLBF streams\n", fp), t, "%d");
|
|
ft_assert(t, rc >= 0);
|
|
ft_log_FILE(t, "",fp);
|
|
ft_assert(t, fp->fdpos == 34);
|
|
ft_assert(t, fp->bufpos == 0);
|
|
for(int i = 0; i < 26; i++) {
|
|
DO_E(rc, fputc('a'+i, fp), t, "'%c'");
|
|
ft_assert(t, rc == 'a'+i);
|
|
}
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 34);
|
|
ft_assert(t, fp->bufpos == 26);
|
|
DO_E(rc, putc('\n', fp), t, "%d");
|
|
ft_assert(t, rc == '\n');
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, fp->fdpos == 61);
|
|
ft_assert(t, fp->bufpos == 0);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Same with unbuffered */
|
|
DO_E(fp, fopen("ft_fput.txt", "w"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, setvbuf(fp, NULL, _IONBF, 0), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, fputs("Testing fputs() on _IONBF streams\n", fp), t, "%d");
|
|
ft_assert(t, rc >= 0);
|
|
ft_log_FILE(t, "",fp);
|
|
/* Urgh this is going to be so slow. Don't do that kids */
|
|
for(int i = 0; i < 26; i++) {
|
|
DO_E(rc, putc('a'+i, fp), t, "'%c'");
|
|
ft_assert(t, rc == 'a'+i);
|
|
}
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
}
|
|
|
|
static void _ft_stdio_write_chars(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_ft_stdio_write_chars_switch, (void *)t));
|
|
}
|
|
|
|
ft_test ft_stdio_write_chars = {
|
|
.name = "Character output functions",
|
|
.function = _ft_stdio_write_chars,
|
|
};
|
|
|
|
static void _ft_stdio_read_chars_switch(ft_test *t)
|
|
{
|
|
FILE *fp;
|
|
int rc;
|
|
char str[20], *retstr;
|
|
|
|
/* Create an initial file with some filler */
|
|
DO_E(fp, fopen("ft_fget.txt", "w"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
DO_E(rc, fputs("Line #1\nLine #2\nLine #3", fp), t, "%d");
|
|
ft_assert(t, rc >= 0);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Read it with fgets() and fgetc() */
|
|
DO_E(fp, fopen("ft_fget.txt", "r"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
DO_E(rc, setvbuf(fp, NULL, _IOFBF, 14), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
memset(str, 0xff, sizeof str);
|
|
DO_E(retstr, fgets(str, 20, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "Line #1\n"));
|
|
memset(str, 0xff, sizeof str);
|
|
DO_E(retstr, fgets(str, 6, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "Line "));
|
|
memset(str, 0xff, sizeof str);
|
|
DO_E(retstr, fgets(str, 20, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !strcmp(str, "#2\n"));
|
|
ft_log(t, "Reading to EOF with fgetc()...\n");
|
|
for(int i = 0; !feof(fp); i++) {
|
|
int c = fgetc(fp);
|
|
if(c == EOF) break;
|
|
str[i] = c;
|
|
str[i+1] = 0;
|
|
}
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "Line #3"));
|
|
|
|
/* Test fgets() at end of file */
|
|
DO_E(rc, fseek(fp, 16, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(retstr, fgets(str, 20, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "Line #3"));
|
|
|
|
/* Test interactions of fgets() and fgetc() with ungetc() */
|
|
DO_E(rc, fseek(fp, 8, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, ungetc('#', fp), t, "'%c'");
|
|
ft_assert(t, rc == '#');
|
|
DO_E(rc, ungetc('!', fp), t, "'%c'");
|
|
ft_assert(t, rc == '!');
|
|
DO_E(rc, ungetc('$', fp), t, "'%c'");
|
|
ft_assert(t, rc == '$');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(retstr, fgets(str, 20, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "$!#Line #2\n"));
|
|
DO_E(rc, ungetc('#', fp), t, "'%c'");
|
|
ft_assert(t, rc == '#');
|
|
DO_E(rc, ungetc('!', fp), t, "'%c'");
|
|
ft_assert(t, rc == '!');
|
|
DO_E(rc, ungetc('$', fp), t, "'%c'");
|
|
ft_assert(t, rc == '$');
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "Reading to EOF with fgetc()...\n");
|
|
for(int i = 0; !feof(fp); i++) {
|
|
int c = getc(fp);
|
|
if(c == EOF) break;
|
|
str[i] = c;
|
|
str[i+1] = 0;
|
|
}
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "$!#Line #3"));
|
|
|
|
/* Try again without buffering */
|
|
rewind(fp);
|
|
ft_log(t, "rewind(fp)\n");
|
|
DO_E(rc, setvbuf(fp, NULL, _IONBF, 0), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
memset(str, 0xff, sizeof str);
|
|
DO_E(retstr, fgets(str, 20, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "Line #1\n"));
|
|
memset(str, 0xff, sizeof str);
|
|
DO_E(retstr, fgets(str, 6, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "Line "));
|
|
memset(str, 0xff, sizeof str);
|
|
DO_E(retstr, fgets(str, 20, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !strcmp(str, "#2\n"));
|
|
ft_log(t, "Reading to EOF with fgetc()...\n");
|
|
for(int i = 0; !feof(fp); i++) {
|
|
int c = fgetc(fp);
|
|
if(c == EOF) break;
|
|
str[i] = c;
|
|
str[i+1] = 0;
|
|
}
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "Line #3"));
|
|
|
|
/* Re-test interactions with ungetc() */
|
|
DO_E(rc, fseek(fp, 8, SEEK_SET), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
DO_E(rc, ungetc('#', fp), t, "'%c'");
|
|
ft_assert(t, rc == '#');
|
|
DO_E(rc, ungetc('!', fp), t, "'%c'");
|
|
ft_assert(t, rc == '!');
|
|
DO_E(rc, ungetc('$', fp), t, "'%c'");
|
|
ft_assert(t, rc == '$');
|
|
ft_log_FILE(t, "", fp);
|
|
DO_E(retstr, fgets(str, 20, fp), t, "%p");
|
|
ft_assert(t, retstr != NULL);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "str = '%s'\n", str);
|
|
ft_assert(t, !strcmp(str, "$!#Line #2\n"));
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
}
|
|
|
|
static void _ft_stdio_read_chars(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_ft_stdio_read_chars_switch, (void *)t));
|
|
}
|
|
|
|
ft_test ft_stdio_read_chars = {
|
|
.name = "Character input functions",
|
|
.function = _ft_stdio_read_chars,
|
|
};
|
|
|
|
static int _ft_stdio_stdstreams_input_pos;
|
|
static ssize_t _ft_stdio_stdstreams_input(void *data, size_t request_size)
|
|
{
|
|
int available = strlen(filler) - _ft_stdio_stdstreams_input_pos;
|
|
int size = min(available, request_size);
|
|
if(size <= 0)
|
|
return 0;
|
|
|
|
memcpy(data, filler + _ft_stdio_stdstreams_input_pos, size);
|
|
_ft_stdio_stdstreams_input_pos += size;
|
|
return size;
|
|
}
|
|
|
|
static ft_test *_ft_stdio_stdstreams_output_t;
|
|
static ssize_t _ft_stdio_stdstreams_output(void const *data, size_t size)
|
|
{
|
|
if(!_ft_stdio_stdstreams_output_t)
|
|
return -1;
|
|
|
|
ft_log_raw(_ft_stdio_stdstreams_output_t, "<out/err> ", 10);
|
|
ft_log_raw(_ft_stdio_stdstreams_output_t, data, size);
|
|
return size;
|
|
}
|
|
|
|
static void delayed_printf(char const *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vprintf(fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
static void delayed_dprintf(int fd, char const *fmt, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vdprintf(fd, fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
static void _ft_stdio_stdstreams(ft_test *t)
|
|
{
|
|
ft_log(t, "For this test, stdin will read from a fixed string, and "
|
|
"stdout and stderr will output here, with a prefix before "
|
|
"every write.\n\n");
|
|
|
|
_ft_stdio_stdstreams_input_pos = 0;
|
|
ft_streams_input = _ft_stdio_stdstreams_input;
|
|
|
|
/* Get rid of previous data left in the buffer... */
|
|
fflush(stdin);
|
|
|
|
_ft_stdio_stdstreams_output_t = t;
|
|
ft_streams_output = _ft_stdio_stdstreams_output;
|
|
|
|
fputs("Test string!\n", stdout);
|
|
puts("Take this!");
|
|
printf("pos = %d\n", _ft_stdio_stdstreams_input_pos);
|
|
delayed_printf("best number = %d\n", 73);
|
|
puts("Let's read stuff from stdin...");
|
|
|
|
char str[33];
|
|
for(int i = 0; i < 32; i++)
|
|
str[i] = getchar();
|
|
str[32] = 0;
|
|
puts(str);
|
|
|
|
fprintf(stderr, "This on stderr");
|
|
fprintf(stderr, "You can tell because it's not _IOLBF!\n");
|
|
|
|
fgets(str, 33, stdin);
|
|
puts(str);
|
|
|
|
putchar('p');
|
|
putchar('u');
|
|
putchar('t');
|
|
putchar('c');
|
|
putchar('h');
|
|
putchar('a');
|
|
putchar('r');
|
|
putchar('\n');
|
|
|
|
errno = ENOMEM;
|
|
perror(NULL);
|
|
errno = 0;
|
|
perror("but now");
|
|
|
|
/* Yes, this is bad practice */
|
|
fflush(stdout);
|
|
dprintf(STDOUT_FILENO, "dprintf = %p\n", dprintf);
|
|
delayed_dprintf(STDOUT_FILENO, "vdprintf = %p\n", vdprintf);
|
|
|
|
ft_streams_input = NULL;
|
|
ft_streams_output = NULL;
|
|
|
|
ft_log(t, "\n-- end --");
|
|
}
|
|
|
|
ft_test ft_stdio_stdstreams = {
|
|
.name = "stdin, stdout, and stderr",
|
|
.function = _ft_stdio_stdstreams,
|
|
};
|
|
|
|
static void _ft_stdio_getdelim_switch(ft_test *t)
|
|
{
|
|
FILE *fp;
|
|
int rc;
|
|
size_t n=0;
|
|
ssize_t result;
|
|
char *lineptr = NULL;
|
|
|
|
/* Create an initial file with some filler */
|
|
DO_E(fp, fopen("ft_getdelim.txt", "w"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
DO_E(rc, fputs("Line #1\nLine #2\n\nAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ\nLine #3", fp), t, "%d");
|
|
ft_assert(t, rc >= 0);
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
/* Read it with getline() and getdelim() */
|
|
DO_E(fp, fopen("ft_getdelim.txt", "r"), t, "%p");
|
|
ft_assert(t, fp != NULL);
|
|
if(fp == NULL) return;
|
|
DO_E(rc, setvbuf(fp, NULL, _IOFBF, 14), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
ft_log_FILE(t, "", fp);
|
|
/* also test automatic alloc if lineptr=NULL */
|
|
DO_E(result, getline(&lineptr, &n, fp), t, "%ld");
|
|
ft_assert(t, result == 8);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "lineptr = '%s'\n", lineptr);
|
|
ft_assert(t, !strcmp(lineptr, "Line #1\n"));
|
|
DO_E(result, getdelim(&lineptr, &n, ' ', fp), t, "%ld");
|
|
ft_assert(t, result == 5);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "lineptr = '%s'\n", lineptr);
|
|
ft_assert(t, !strcmp(lineptr, "Line "));
|
|
DO_E(result, getline(&lineptr, &n, fp), t, "%ld");
|
|
ft_assert(t, result == 3);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_assert(t, !strcmp(lineptr, "#2\n"));
|
|
/* Test getline with 0 char line */
|
|
DO_E(result, getline(&lineptr, &n, fp), t, "%ld");
|
|
ft_assert(t, result == 1);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "lineptr = '%s'\n", lineptr);
|
|
ft_assert(t, !strcmp(lineptr, "\n"));
|
|
/* Test getline with long line */
|
|
DO_E(result, getline(&lineptr, &n, fp), t, "%ld");
|
|
ft_assert(t, result == 105);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "lineptr = '%s'\n", lineptr);
|
|
ft_log(t, "n = '%u'\n", n);
|
|
ft_assert(t, !strcmp(lineptr, "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ\n"));
|
|
/* test that we don't get -1 in case delim iss last symbol in file */
|
|
DO_E(result, getdelim(&lineptr, &n, '3', fp), t, "%ld");
|
|
ft_assert(t, result == 7);
|
|
ft_log_FILE(t, "", fp);
|
|
ft_log(t, "lineptr = '%s'\n", lineptr);
|
|
ft_log(t, "n = '%u'\n", n);
|
|
ft_assert(t, !strcmp(lineptr, "Line #3"));
|
|
ft_log(t, "Reading to EOF with getdelim(delim not in file)...\n");
|
|
rewind(fp);
|
|
ft_log(t, "rewind(fp)\n");
|
|
DO_E(result, getdelim(&lineptr, &n, '5', fp), t, "%ld");
|
|
ft_assert(t, result == -1);
|
|
ft_log(t, "lineptr = '%s'\n", lineptr);
|
|
ft_assert(t, !strcmp(lineptr, "Line #1\nLine #2\n\nAAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ\nLine #3"));
|
|
DO_E(rc, fclose(fp), t, "%d");
|
|
ft_assert(t, rc == 0);
|
|
|
|
}
|
|
|
|
static void _ft_stdio_getdelim(ft_test *t)
|
|
{
|
|
gint_world_switch(GINT_CALL(_ft_stdio_getdelim_switch, (void *)t));
|
|
}
|
|
|
|
ft_test ft_stdio_getdelim = {
|
|
.name = "delimited string input",
|
|
.function = _ft_stdio_getdelim,
|
|
};
|