summaryrefslogtreecommitdiffstats
path: root/tests/test_goal.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_goal.cpp')
-rw-r--r--tests/test_goal.cpp230
1 files changed, 230 insertions, 0 deletions
diff --git a/tests/test_goal.cpp b/tests/test_goal.cpp
new file mode 100644
index 0000000..8e06517
--- /dev/null
+++ b/tests/test_goal.cpp
@@ -0,0 +1,230 @@
+#include "goal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int failures = 0;
+static int checks = 0;
+
+#define CHECK(cond, msg) \
+ do { \
+ checks++; \
+ if (!(cond)) { \
+ failures++; \
+ fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, (msg)); \
+ } \
+ } while (0)
+
+#define CHECK_CONT(hay, needle, msg) \
+ do { \
+ checks++; \
+ if (!hay || !strstr(hay, needle)) { \
+ failures++; \
+ fprintf(stderr, \
+ "FAIL %s:%d: %s (got `%s`, want substring `%s`)\n", \
+ __FILE__, __LINE__, (msg), hay ? hay : "(null)", \
+ (needle)); \
+ } \
+ } while (0)
+
+#define CHECK_NOT_CONT(hay, needle, msg) \
+ do { \
+ checks++; \
+ if (hay && strstr(hay, needle)) { \
+ failures++; \
+ fprintf(stderr, "FAIL %s:%d: %s (found `%s` in `%s`)\n", \
+ __FILE__, __LINE__, (msg), (needle), hay); \
+ } \
+ } while (0)
+
+static void test_parse_defaults(void)
+{
+ goal_spec spec;
+ char *err = NULL;
+ CHECK(goal_parse("all tests pass", &spec, &err) == 1, "parse");
+ CHECK(strcmp(spec.criteria, "all tests pass") == 0, "criteria");
+ CHECK(spec.max_tries == GOAL_DEFAULT_MAX_TRIES, "default cap");
+ goal_spec_free(&spec);
+}
+
+static void test_parse_reads_cap(void)
+{
+ goal_spec spec;
+ char *err = NULL;
+ CHECK(goal_parse("all tests pass, stop after 3 tries", &spec, &err) == 1,
+ "parse");
+ CHECK(strcmp(spec.criteria, "all tests pass") == 0, "criteria");
+ CHECK(spec.max_tries == 3, "cap");
+ goal_spec_free(&spec);
+}
+
+static void test_parse_cap_without_tries_word(void)
+{
+ goal_spec spec;
+ char *err = NULL;
+ CHECK(goal_parse("make it green, stop after 10", &spec, &err) == 1, "parse");
+ CHECK(strcmp(spec.criteria, "make it green") == 0, "criteria");
+ CHECK(spec.max_tries == 10, "cap");
+ goal_spec_free(&spec);
+}
+
+static void test_parse_tries_word_case_insensitive(void)
+{
+ goal_spec spec;
+ char *err = NULL;
+ CHECK(goal_parse("ship it, stop after 4 TRIES", &spec, &err) == 1,
+ "uppercase TRIES accepted");
+ CHECK(spec.max_tries == 4, "cap");
+ goal_spec_free(&spec);
+}
+
+static void test_parse_rejections(void)
+{
+ goal_spec spec;
+ char *err = NULL;
+
+ err = NULL;
+ CHECK(goal_parse(" ", &spec, &err) == 0, "empty input rejected");
+ CHECK(err && strstr(err, "success criteria") != NULL, "empty err msg");
+ free(err);
+
+ err = NULL;
+ CHECK(goal_parse("stop after 5 tries", &spec, &err) == 0,
+ "missing criteria rejected");
+ CHECK(err && strstr(err, "before `stop after`") != NULL, "missing err msg");
+ free(err);
+
+ err = NULL;
+ CHECK(goal_parse("ship it, stop after", &spec, &err) == 0,
+ "missing cap rejected");
+ CHECK(err && strstr(err, "number of tries") != NULL, "missing cap err");
+ free(err);
+
+ err = NULL;
+ CHECK(goal_parse("ship it, stop after 0 tries", &spec, &err) == 0,
+ "zero cap rejected");
+ CHECK(err && strstr(err, "at least 1 try") != NULL, "zero cap err");
+ free(err);
+
+ err = NULL;
+ CHECK(goal_parse("ship it, stop after 5xyz", &spec, &err) == 0,
+ "junk after the number rejected");
+ CHECK(err && strstr(err, "number of tries") != NULL, "junk err msg");
+ free(err);
+}
+
+static void test_first_attempt_prompt(void)
+{
+ goal_spec spec;
+ spec.criteria = xstrdup("all tests pass");
+ spec.max_tries = 5;
+ char *prompt = goal_prompt(&spec, 1, NULL);
+ CHECK_CONT(prompt, "all tests pass", "states the goal");
+ CHECK_NOT_CONT(prompt, "NOT yet met", "no feedback on first attempt");
+ CHECK_CONT(prompt, "fully met", "asks to keep going");
+ free(prompt);
+ goal_spec_free(&spec);
+}
+
+static void test_later_attempt_prompt(void)
+{
+ goal_spec spec;
+ spec.criteria = xstrdup("all tests pass");
+ spec.max_tries = 3;
+ char *prompt = goal_prompt(&spec, 2, "the build still fails on x86");
+ CHECK_CONT(prompt, "attempt 2 of 3", "attempt framing");
+ CHECK_CONT(prompt, "NOT yet met", "verdict phrasing");
+ CHECK_CONT(prompt, "the build still fails on x86", "includes feedback");
+ free(prompt);
+
+ char *no_fb = goal_prompt(&spec, 4, NULL);
+ CHECK_CONT(no_fb, "attempt 4 of 3", "attempt number");
+ CHECK_CONT(no_fb, "no specific feedback was given", "fallback feedback");
+ free(no_fb);
+ goal_spec_free(&spec);
+}
+
+static void test_verdict_met(void)
+{
+ goal_verdict v;
+ goal_parse_verdict("MET\nAll tests pass and the suite is green.", &v);
+ CHECK(v.met, "met detected");
+ CHECK_CONT(v.reason, "green", "reason captured");
+ free(v.reason);
+}
+
+static void test_verdict_not_met(void)
+{
+ goal_verdict v;
+ goal_parse_verdict("NOT MET\nTwo tests still fail in the linux job.", &v);
+ CHECK(!v.met, "not met detected");
+ CHECK_CONT(v.reason, "still fail", "reason captured");
+ free(v.reason);
+}
+
+static void test_verdict_garbage(void)
+{
+ goal_verdict v;
+ goal_parse_verdict("I think we are close! Let me keep going.", &v);
+ CHECK(!v.met, "conservative on garbage");
+ CHECK_CONT(v.reason, "close", "first line is the reason");
+ free(v.reason);
+}
+
+static void test_verdict_unmet_is_not_met(void)
+{
+ /* "UNMET" contains the substring "MET"; it must not read as met. */
+ goal_verdict v;
+ goal_parse_verdict("UNMET\nStill failing.", &v);
+ CHECK(!v.met, "UNMET is not met");
+ free(v.reason);
+
+ goal_parse_verdict("NOT UNMET", &v);
+ CHECK(!v.met, "NOT UNMET is not met");
+ free(v.reason);
+
+ goal_parse_verdict("unmet", &v);
+ CHECK(!v.met, "lowercase unmet is not met");
+ free(v.reason);
+
+ goal_parse_verdict("MET", &v);
+ CHECK(v.met, "plain MET is met");
+ free(v.reason);
+}
+
+static void test_verdict_no_reason(void)
+{
+ goal_verdict v;
+ goal_parse_verdict("MET", &v);
+ CHECK(v.met, "bare MET is met");
+ CHECK_CONT(v.reason, "did not give a reason", "fallback reason");
+ free(v.reason);
+}
+
+static void test_preamble(void)
+{
+ const char *p = goal_evaluator_preamble();
+ CHECK_CONT(p, "MET", "mentions MET token");
+ CHECK_CONT(p, "NOT MET", "mentions NOT MET token");
+ CHECK_CONT(p, "strict", "strict reviewer");
+}
+
+int main(void)
+{
+ test_parse_defaults();
+ test_parse_reads_cap();
+ test_parse_cap_without_tries_word();
+ test_parse_tries_word_case_insensitive();
+ test_parse_rejections();
+ test_first_attempt_prompt();
+ test_later_attempt_prompt();
+ test_verdict_met();
+ test_verdict_not_met();
+ test_verdict_garbage();
+ test_verdict_unmet_is_not_met();
+ test_verdict_no_reason();
+ test_preamble();
+ printf("%d checks, %d failures\n", checks, failures);
+ return failures ? 1 : 0;
+}