diff options
| -rw-r--r-- | configure.ac | 6 | ||||
| -rw-r--r-- | src/Makefile.am | 4 | ||||
| -rw-r--r-- | src/main.c | 6 | ||||
| -rw-r--r-- | src/prove.c | 421 | ||||
| -rw-r--r-- | src/prove.h | 12 | ||||
| -rw-r--r-- | src/tty.c | 8 | 
6 files changed, 455 insertions, 2 deletions
| 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 @@ -89,6 +89,7 @@ extern int select();  #include "tty.h"  #include "eval.h"  #include "log.h" +#include "prove.h"  /*     local function declarations       */  #ifdef MOTDFILE @@ -345,6 +346,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 <stdio.h> +#include <stdarg.h> +#include <string.h> + +#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_ */ + @@ -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++);  } | 
