From f8423ebea413605b42de23f5dd06c5479d3fa1dd Mon Sep 17 00:00:00 2001 From: Ethan Werner Date: Sat, 10 Oct 2026 20:55:33 +0000 Subject: initial commit --- tests/test_goal.cpp | 230 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 tests/test_goal.cpp (limited to 'tests/test_goal.cpp') 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 +#include +#include + +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; +} -- cgit v1.3.1