From 76f433d408da25e3291c4f4d47f8e60428a3e2e6 Mon Sep 17 00:00:00 2001 From: Steve Slaven Date: Mon, 23 Jan 2023 22:09:35 -0800 Subject: add --prove diff --git a/configure.ac b/configure.ac index a69864e..34a7666 100644 --- a/configure.ac +++ b/configure.ac @@ -25,6 +25,12 @@ AC_ARG_ENABLE(regex, [enable_regex="yes"] ) +AC_ARG_ENABLE(prove, + AC_HELP_STRING([--enable-prove], + [Enable prove option [[default=no]]]), + [AC_DEFINE(ENABLE_PROVE)] +) + AC_ARG_ENABLE(sort, AC_HELP_STRING([--enable-sort], [Sort aliases and actions [[default=no]]]), diff --git a/src/Makefile.am b/src/Makefile.am index caab15c..8b79eb7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,12 +5,12 @@ AM_CPPFLAGS=-D_XOPEN_SOURCE=700 -DPOWWOW_DIR=\"$(pkgdatadir)\" \ bin_PROGRAMS = powwow powwow-muc powwow-movieplay powwow_SOURCES = beam.c cmd.c log.c edit.c cmd2.c eval.c \ utils.c main.c tcp.c list.c map.c tty.c \ - ptr.c + ptr.c prove.c powwow_LDFLAGS = @dl_ldflags@ powwowdir = $(pkgincludedir) powwow_HEADERS = beam.h cmd.h log.h edit.h cmd2.h eval.h \ utils.h main.h tcp.h list.h map.h tty.h \ - ptr.h defines.h feature/regex.h + ptr.h defines.h feature/regex.h prove.h powwow_muc_SOURCES = powwow-muc.c powwow_movieplay_SOURCES = powwow-movieplay.c diff --git a/src/main.c b/src/main.c index 3c7fe9b..bb12270 100644 --- a/src/main.c +++ b/src/main.c @@ -89,6 +89,7 @@ extern int select(); #include "tty.h" #include "eval.h" #include "log.h" +#include "prove.h" /* local function declarations */ #ifdef MOTDFILE @@ -344,6 +345,11 @@ under certain conditions; type \"#help copyright\" for details.\n" ); } + if (argc == 2 && strcmp(argv[1], "--prove") == 0) { + prove(); + exit(0); + } + if (argc == 1 || argc == 3) { tty_add_initial_binds(); tty_add_walk_binds(); diff --git a/src/prove.c b/src/prove.c new file mode 100644 index 0000000..38d6b7c --- /dev/null +++ b/src/prove.c @@ -0,0 +1,421 @@ +#include +#include +#include + +#include "defines.h" +#include "main.h" +#include "utils.h" +#include "eval.h" +#include "list.h" +#include "edit.h" + +#ifdef ENABLE_PROVE + +/* + * Run powwow --prove to get TAP output + * + * To use with prove, create a script powwow.t that contains powwow --prove + * + * Then run: + * + * prove powwow.t + * + * Or without a wrapper .t: + * + * prove --exec '' ./src/powwow :: --prove + */ + +int _is_proving = 0; +int num_tests = 0; + +#define PROVE_TTY_OUTPUT_LENGTH 40000 +char prove_tty_output[PROVE_TTY_OUTPUT_LENGTH]; + +#define TAP_STRING_LENGTH 400 +char tap_string[TAP_STRING_LENGTH]; + +void prove_save_tty_output(const char *s) +{ + strncat(prove_tty_output, s, PROVE_TTY_OUTPUT_LENGTH - strlen(prove_tty_output) - 1); +} + +int is_proving() +{ + return _is_proving; +} + +static void t_clear_tty_output() +{ + strcpy(prove_tty_output, ""); +} + +static const char *t_get_tty_output() +{ + return prove_tty_output; +} + +static void tap_putchar(const char c) +{ + putchar(c); +} + +static void tap_printf(const char *format, ...) +{ + va_list va_args; + va_start(va_args, format); + vprintf(format, va_args); + va_end(va_args); +} + +static void tap_ok(const char *description) +{ + tap_printf("ok %d - %s\n", ++num_tests, description); +} + +static void tap_not_ok(const char *description) +{ + tap_printf("not ok %d - %s\n", ++num_tests, description); +} + +static void done_testing() { + tap_printf("1..%d\n", num_tests); +} + +char *tap_stringf(const char *format, ...) +{ + va_list va_args; + va_start(va_args, format); + vsnprintf(tap_string, TAP_STRING_LENGTH, format, va_args); + va_end(va_args); + return tap_string; +} + +static void todo(const char *description) +{ + tap_not_ok(tap_stringf("# TODO %s", description)); +} + +static void note(const char *description) +{ + int offset = 0; + char last_c = '\n'; + while (description[offset] != 0) { + if (last_c == '\n') { + tap_printf("# "); + } + + last_c = description[offset++]; + tap_putchar(last_c); + } + tap_putchar('\n'); +} + +static void note_tty_output() +{ + note(tap_stringf("error = %d", error)); + note("--- begin tty output ---"); + note(t_get_tty_output()); + note("--- end tty output ---"); +} + +static void t_reset_errors() +{ + error = 0; +} + +static void t_simulate_user_input(const char *original_line) +{ + char line[BUFSIZE]; + + // send in a copy since some function will modify input + strcpy(line, original_line); + + note(tap_stringf("Simulating input: %s", line)); + + clear_line(0); + t_reset_errors(); + edlen = strlen(line); + strcpy(edbuf, line); + parse_user_input(line, 1); +} + +static void t_simulate_output(const char *original_line) +{ + char line[BUFSIZE]; + + // send in a copy since some function will modify input + strcpy(line, original_line); + + note(tap_stringf("Simulating output: %s", line)); + + t_reset_errors(); + smart_print(line, 1); +} + + +static void C_ok(int arg, const char *description) +{ + if (arg) { + tap_ok(description); + } else { + tap_not_ok(description); + } +} + +static void C_is(const char *input, const char *match, const char *description) +{ + if (strcmp(input, match) == 0) { + tap_ok(description); + } else { + tap_not_ok(description); + note(tap_stringf( + "C_is FAILED\n" + " got: '%s'\n" + " expected: '%s'\n", + input, match)); + } +} + +static void C_contains(const char *input, const char *match, const char *description) +{ + if (strstr(input, match)) { + tap_ok(description); + } else { + tap_not_ok(description); + note(tap_stringf( + "C_contains FAILED\n" + " got: '%s'\n" + " expected: '%s'\n", + input, match)); + } +} + +static void C_output_from_user_input_contains(char *user_input, const char *output_contains, const char *description) +{ + t_clear_tty_output(); + t_simulate_user_input(user_input); + C_contains(t_get_tty_output(), output_contains, description); + note_tty_output(); +} + +static void C_output_from_user_input_is(char *user_input, const char *output_is, const char *description) +{ + t_clear_tty_output(); + t_simulate_user_input(user_input); + C_is(t_get_tty_output(), output_is, description); + note_tty_output(); +} + +static void C_simulated_output_contains(char *original_output, const char *output_contains, const char *description) +{ + t_clear_tty_output(); + t_simulate_output(original_output); + C_contains(t_get_tty_output(), output_contains, description); + note_tty_output(); +} + +static void C_simulated_output_is(char *original_output, const char *output_is, const char *description) +{ + t_clear_tty_output(); + t_simulate_output(original_output); + C_is(t_get_tty_output(), output_is, description); + note_tty_output(); +} + +static void C_edit_from_user_input_is(char *user_input, const char *output_is, const char *description) +{ + t_clear_tty_output(); + strcpy(inserted_next, ""); + t_simulate_user_input(user_input); + C_is(inserted_next, output_is, description); + note_tty_output(); +} + +static void t_start_new_test() +{ + /* this should init the globals again so everything is clean */ + t_reset_errors(); + + t_simulate_user_input("#reset all"); + + t_clear_tty_output(); +} + +static void do_test(void (*func)(), const char *name) +{ + note(tap_stringf("-=-=-=-=- Setting up for test %s -=-=-=-=-\n", name)); + t_start_new_test(); + (*func)(); + note(tap_stringf("-=-=-=-=- End test %s -=-=-=-=-\n", name)); +} + +static void TEST_tap() +{ + C_ok(1, "Should ok"); + return; + C_ok(0, "Should not ok"); +} + +static void TEST_mark_syntax_error() +{ + C_output_from_user_input_contains( + "#mark foo=bar", + "#invalid attribute syntax", + "#mark - syntax error"); + + C_output_from_user_input_is( + "#mark =bar", + "#marker must be non-null.\n", + "#mark - empty error"); + + C_output_from_user_input_is( + "#mark foo&$foo=bar", + "#error: two wildcards (& or $) may not be next to eachother\n", + "#mark - two consecutive wildcards"); +} + +static void TEST_mark_reset_step1() +{ + C_output_from_user_input_is( + "#mark foo=bold", + "#new mark: foo=bold \n", + "#mark - new mark is created"); + + C_simulated_output_is( + "The word foo should be bold", + "The word \x1b[1mfoo\x1b[0m should be bold", + "#mark - foo should be bold"); + + C_output_from_user_input_is( + "#mark", + + "#the following marker is defined:\n" + "#mark foo=bold \n", + + "#mark - can list marks"); +} + +static void TEST_mark_reset_step2() +{ + C_output_from_user_input_is( + "#mark", + "#no markers are defined.\n", + "#mark - there should be no marks defined after a reset"); + + C_simulated_output_is( + "The word foo should not be bold", + "The word foo should not be bold", + "#mark - foo should be not be bold because of test reset"); +} + + +static void TEST_mark() +{ + C_output_from_user_input_is( + "#mark match rest &=underline", + "#new mark: match rest &=underline \n", + "#mark - new mark is created with pattern"); + + C_output_from_user_input_is( + "#mark ^bar=underline", + "#new mark: ^bar=underline \n", + "#mark - new mark is created with anchor"); + + C_simulated_output_is( + "bar - The word bar should be underlined at the beginning", + "\x1b[4mbar\x1b[0m - The word bar should be underlined at the beginning", + "#mark - ^bar should be underlined"); + + + todo("The below test should fail when mbeg is fixed!"); + + // need to see if this is intended, mbeg suggests it should only match + // at beginning of the line + C_simulated_output_is( + "The word bar should be not be underlined if not at the beginning (mbeg - THIS IS BROKEN?)", + + //"The word bar should be not be underlined if not at the beginning", + "The word \x1b[4mbar\x1b[0m should be not be underlined if not at the beginning (mbeg - THIS IS BROKEN?)", + + "#mark - other bar should NOT be underlined"); + + todo("The above test should fail when mbeg is fixed!"); + + + C_output_from_user_input_is( + "#mark foo=bold", + "#new mark: foo=bold \n", + "#mark - new mark is created"); + + C_edit_from_user_input_is( + "#mark foo", + "#mark foo=bold ", + "#mark - mark can be edited"); + + C_simulated_output_is( + "The word foo should be bold", + "The word \x1b[1mfoo\x1b[0m should be bold", + "#mark - foo should be bold"); + + C_simulated_output_is( + "After match rest all should be underlined and foo should not be bold", + "After \x1b[4mmatch rest all should be underlined and foo should not be bold\x1b[0m", + "#mark - match rest should be underlined but foo is not bold, matches seem to be greedy"); + + C_simulated_output_is( + "The word foo and foo should be bold", + "The word \x1b[1mfoo\x1b[0m and \x1b[1mfoo\x1b[0m should be bold", + "#mark - multiple foo should be bold"); + + + C_output_from_user_input_is( + "#mark foo=", + "#deleting mark: foo=bold \n", + "#mark - mark is deleted"); + + C_output_from_user_input_is( + "#mark ^bar=", + "#deleting mark: ^bar=underline \n", + "#mark - mark is deleted"); + + C_output_from_user_input_is( + "#mark match rest &=", + "#deleting mark: match rest &=underline \n", + "#mark - mark is deleted"); + + C_simulated_output_is( + "The word foo should not be bold", + "The word foo should not be bold", + "#mark - foo should not be bold"); + + C_output_from_user_input_is( + "#mark", + "#no markers are defined.\n", + "#mark - all marks deleted"); +} + +void prove() +{ + _is_proving = 1; + + do_test(TEST_tap, "TAP output"); + + do_test(TEST_mark_syntax_error, "#mark syntax"); + do_test(TEST_mark_reset_step1, "#mark reset step 1"); + do_test(TEST_mark_reset_step2, "#mark reset step 2"); + do_test(TEST_mark, "#mark usage"); + + done_testing(); + + _is_proving = 0; +} + +#else +void prove() +{ + printf("Prove is disabled\n"); +} + +#endif + + diff --git a/src/prove.h b/src/prove.h new file mode 100644 index 0000000..36e3c41 --- /dev/null +++ b/src/prove.h @@ -0,0 +1,12 @@ +#ifndef _PROVE_H_ +#define _PROVE_H_ + +void prove(void); + +#ifdef ENABLE_PROVE +void prove_save_tty_output(const char *s); +int is_proving(); +#endif + +#endif /* _PROVE_H_ */ + diff --git a/src/tty.c b/src/tty.c index 104c780..a1e8590 100644 --- a/src/tty.c +++ b/src/tty.c @@ -34,6 +34,7 @@ #include "list.h" #include "tty.h" #include "tcp.h" +#include "prove.h" #ifndef USE_SGTTY # ifdef APOLLO @@ -815,6 +816,13 @@ void input_insert_follow_chars(char *str, int n) void tty_puts(const char *s) { +#ifdef ENABLE_PROVE + if (is_proving()) { + prove_save_tty_output(s); + return; + } +#endif + while (*s) tty_putc(*s++); } -- cgit v0.10.2