aboutsummaryrefslogtreecommitdiffstats
path: root/src/prove.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/prove.c')
-rw-r--r--src/prove.c463
1 files changed, 463 insertions, 0 deletions
diff --git a/src/prove.c b/src/prove.c
new file mode 100644
index 0000000..497ebda
--- /dev/null
+++ b/src/prove.c
@@ -0,0 +1,463 @@
+#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",
+ "#mark must be non-empty\n",
+ "#mark - empty error");
+
+ C_output_from_user_input_is(
+ "#mark foo&$foo=bar",
+ "#mark 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");
+}
+
+static void TEST_substitute_syntax_error()
+{
+ C_output_from_user_input_is(
+ "#substitute = ",
+ "#substitute must be non-empty\n",
+ "#substitute - syntax error");
+}
+
+static void TEST_substitute()
+{
+ C_output_from_user_input_contains(
+ "#substitute foo=bar",
+ "#new substitution: foo=bar\n",
+ "#substitute - new substitute is created");
+
+ C_edit_from_user_input_is(
+ "#substitute foo",
+ "#substitute foo=bar",
+ "#substitute - substitute can be edited");
+
+ C_simulated_output_is(
+ "The word foo should be bar",
+ "The word bar should be bar",
+ "#substitute - foo should be bar");
+
+ C_output_from_user_input_is(
+ "#substitute foo=",
+ "#deleting substitution: foo=bar\n",
+ "#substitute - substitute is deleted");
+
+ C_simulated_output_is(
+ "The word foo should not be bar",
+ "The word foo should not be bar",
+ "#substitute - foo should not be bar");
+}
+
+void prove()
+{
+ _is_proving = 1;
+
+ int looping = 2;
+ while (looping--) {
+ 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");
+
+ do_test(TEST_substitute_syntax_error, "#substitute syntax error");
+ do_test(TEST_substitute, "#substitute usage");
+ }
+
+ done_testing();
+
+ _is_proving = 0;
+}
+
+#else
+void prove()
+{
+ printf("Prove is disabled\n");
+}
+
+#endif
+
+