aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/main.c6
-rw-r--r--src/prove.c421
-rw-r--r--src/prove.h12
-rw-r--r--src/tty.c8
5 files changed, 449 insertions, 2 deletions
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 <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_ */
+
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++);
}