stdio: add tests for standard streams and misc functions

This commit is contained in:
Lephenixnoir 2022-01-14 18:39:33 +01:00
parent 58bab5137f
commit cf40969c23
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
6 changed files with 187 additions and 3 deletions

View File

@ -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;

16
include/ft/streams.h Normal file
View File

@ -0,0 +1,16 @@
//---
// fxlibctest.streams: Control of stdin/stdout/stderr
//---
#ifndef _FT_STREAMS_H_
#define _FT_STREAMS_H_
#include <stddef.h>
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_ */

View File

@ -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)

View File

@ -7,10 +7,13 @@
#include <ft/widgets/flog.h>
#include <ft/test.h>
#include <ft/all-tests.h>
#include <ft/streams.h>
#include <fxlibc/printf.h>
#include <gint/hardware.h>
#include <gint/fs.h>
#include <unistd.h>
#include <bits/cpucap.h>
/* 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", "<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();

View File

@ -1,6 +1,7 @@
#include <ft/test.h>
#include <ft/all-tests.h>
#include <ft/util.h>
#include <ft/streams.h>
#include <gint/gint.h>
@ -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, "<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,
};

View File

@ -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;
}
//---