From cf40969c238d54fcedd1b6b2d05c5164883b800a Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Fri, 14 Jan 2022 18:39:33 +0100 Subject: [PATCH] stdio: add tests for standard streams and misc functions --- include/ft/all-tests.h | 1 + include/ft/streams.h | 16 +++++++ include/ft/test.h | 5 +- src/main.c | 46 ++++++++++++++++++ src/stdio/files.c | 104 +++++++++++++++++++++++++++++++++++++++++ src/test.c | 18 ++++++- 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 include/ft/streams.h diff --git a/include/ft/all-tests.h b/include/ft/all-tests.h index 2effa24..158c344 100644 --- a/include/ft/all-tests.h +++ b/include/ft/all-tests.h @@ -36,6 +36,7 @@ extern ft_test ft_stdio_append; extern ft_test ft_stdio_fdopen; extern ft_test ft_stdio_write_chars; extern ft_test ft_stdio_read_chars; +extern ft_test ft_stdio_stdstreams; /* stdlib */ extern ft_test ft_stdlib_arith; diff --git a/include/ft/streams.h b/include/ft/streams.h new file mode 100644 index 0000000..2e9359b --- /dev/null +++ b/include/ft/streams.h @@ -0,0 +1,16 @@ +//--- +// fxlibctest.streams: Control of stdin/stdout/stderr +//--- + +#ifndef _FT_STREAMS_H_ +#define _FT_STREAMS_H_ + +#include + +typedef ssize_t console_input_function_t(void *data, size_t size); +typedef ssize_t console_output_function_t(void const *data, size_t size); + +extern console_input_function_t *ft_streams_input; +extern console_output_function_t *ft_streams_output; + +#endif /* _FT_STREAMS_H_ */ diff --git a/include/ft/test.h b/include/ft/test.h index 4338843..b9eff6c 100644 --- a/include/ft/test.h +++ b/include/ft/test.h @@ -60,7 +60,10 @@ void ft_skip(ft_test *test, int amount); /* ft_log(): Write some data in a test's log */ __attribute__((format(printf, 2, 3))) -void ft_log(ft_test *test, char const *format, ...); +int ft_log(ft_test *test, char const *format, ...); + +/* Same without formatted printing */ +void ft_log_raw(ft_test *test, char const *str, size_t size); //--- // Test lists (to organize by header) diff --git a/src/main.c b/src/main.c index d4083c0..ee6398e 100644 --- a/src/main.c +++ b/src/main.c @@ -7,10 +7,13 @@ #include #include #include +#include #include #include +#include +#include #include /* We don't initialize the test result fields in the ft_list objects below */ @@ -52,6 +55,7 @@ ft_list headers_libc[] = { &ft_stdio_fdopen, &ft_stdio_write_chars, &ft_stdio_read_chars, + &ft_stdio_stdstreams, NULL, }}, { _("stdlib.h", ""), (ft_test*[]){ @@ -115,6 +119,40 @@ ft_list headers_posix[] = { #pragma GCC diagnostic pop +/* The descriptor type for stdin */ + +console_input_function_t *ft_streams_input = NULL; + +ssize_t stdin_read(GUNUSED void *data, void *buf, size_t size) +{ + return ft_streams_input ? ft_streams_input(buf, size) : 0; +} + +fs_descriptor_type_t stdin_type = { + .read = stdin_read, + .write = NULL, + .lseek = NULL, + .close = NULL, +}; + +/* The descriptor type for stdout/stderr */ + +console_output_function_t *ft_streams_output = NULL; + +ssize_t stdouterr_write(GUNUSED void *data, void const *buf, size_t size) +{ + return ft_streams_output ? ft_streams_output(buf, size) : 0; +} + +fs_descriptor_type_t stdouterr_type = { + .read = NULL, + .write = stdouterr_write, + .lseek = NULL, + .close = NULL, +}; + +/* Main function */ + int main(void) { /* Set up the capabilities for the standard library implementation */ @@ -122,6 +160,14 @@ int main(void) if(isSH4()) __cpucap |= __CPUCAP_SH4ALDSP; + /* Open stdin/stdout/stderr with our custom type */ + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + open_generic(&stdin_type, NULL, STDIN_FILENO); + open_generic(&stdouterr_type, NULL, STDOUT_FILENO); + open_generic(&stdouterr_type, NULL, STDERR_FILENO); + __printf_enable_fp(); __printf_enable_fixed(); diff --git a/src/stdio/files.c b/src/stdio/files.c index 034397b..20ac6c0 100644 --- a/src/stdio/files.c +++ b/src/stdio/files.c @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -954,3 +955,106 @@ 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, " ", 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, +}; diff --git a/src/test.c b/src/test.c index 6613a93..f16235e 100644 --- a/src/test.c +++ b/src/test.c @@ -44,21 +44,35 @@ void ft_skip(ft_test *test, int count) test->skipped += count; } -void ft_log(ft_test *test, char const *format, ...) +int ft_log(ft_test *test, char const *format, ...) { va_list args1, args2; va_start(args1, format); va_copy(args2, args1); int size = vsnprintf(NULL, 0, format, args1); + if(test->log_size + size > 0xffff) return 0; + + char *newlog = realloc(test->log, test->log_size + size + 1); + if(!newlog) return 0; + + vsnprintf(newlog + test->log_size, size + 1, format, args2); + test->log = newlog; + test->log_size += size; + return size; +} + +void ft_log_raw(ft_test *test, char const *str, size_t size) +{ if(test->log_size + size > 0xffff) return; char *newlog = realloc(test->log, test->log_size + size + 1); if(!newlog) return; - vsnprintf(newlog + test->log_size, size + 1, format, args2); + memcpy(newlog + test->log_size, str, size); test->log = newlog; test->log_size += size; + test->log[test->log_size] = 0; } //---