Files
apex-public/internal/eval/report_test.go
T
2026-07-06 11:05:50 -04:00

191 lines
5.3 KiB
Go

package eval
import (
"context"
"database/sql"
"os"
"path/filepath"
"strings"
"testing"
_ "modernc.org/sqlite"
)
func setupReportDB(t *testing.T) *sql.DB {
t.Helper()
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
t.Fatal(err)
}
schema := `
CREATE TABLE jobs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
url TEXT UNIQUE NOT NULL,
company TEXT NOT NULL,
title TEXT NOT NULL,
description TEXT,
source TEXT,
discovered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE applications (
id INTEGER PRIMARY KEY AUTOINCREMENT,
job_id INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'Evaluated',
score REAL,
archetype TEXT,
legitimacy TEXT,
evaluated_at TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE reports (
id INTEGER PRIMARY KEY AUTOINCREMENT,
application_id INTEGER NOT NULL,
report_md TEXT,
seq INTEGER,
slug TEXT,
legitimacy TEXT,
score REAL,
block_a TEXT, block_b TEXT, block_c TEXT, block_d TEXT,
block_e TEXT, block_f TEXT, block_g TEXT,
file_path TEXT,
stories TEXT,
generated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`
if _, err := db.Exec(schema); err != nil {
t.Fatal(err)
}
return db
}
func TestSlugify(t *testing.T) {
cases := map[string]string{
"Acme Corp": "acme-corp",
"Dragos, Inc.": "dragos-inc",
" Red/Canary ": "redcanary",
"../../etc/passwd": "etcpasswd",
"": "unknown",
"!@#$%^&*()": "unknown",
"Foo ___ Bar": "foo-bar",
strings.Repeat("x", 80): strings.Repeat("x", 64),
}
for in, want := range cases {
if got := Slugify(in); got != want {
t.Errorf("Slugify(%q) = %q, want %q", in, got, want)
}
}
}
func TestReportWriter_SaveEndToEnd(t *testing.T) {
db := setupReportDB(t)
defer db.Close()
tmp := t.TempDir()
w := &ReportWriter{DB: db, ReportsDir: tmp}
job := JobContext{
URL: "https://example.com/jobs/42",
Company: "Acme Corp",
Title: "Staff LLMOps",
Source: "greenhouse",
JDText: "Job description body.",
}
eval := Evaluation{
Archetype: "LLMOps",
Score: 4.2,
Legitimacy: TierHigh,
BlockA: "## A) Role Summary\n\nStaff LLMOps role.",
BlockB: "## B) CV Match\n\nStrong match.\n\n**Weighted score:** 4.2/5",
BlockG: "## G) Posting Legitimacy\n\n**Assessment:** High Confidence",
Raw: "full raw",
}
saved, err := w.Save(context.Background(), job, eval)
if err != nil {
t.Fatalf("Save: %v", err)
}
if saved.Seq != 1 {
t.Errorf("Seq = %d, want 1", saved.Seq)
}
if saved.ApplicationID == 0 || saved.ReportID == 0 {
t.Errorf("missing ids: app=%d report=%d", saved.ApplicationID, saved.ReportID)
}
if filepath.Dir(saved.FilePath) != tmp {
t.Errorf("file path outside ReportsDir: %q", saved.FilePath)
}
if _, err := os.Stat(saved.FilePath); err != nil {
t.Fatalf("report file missing: %v", err)
}
// Contents exercise RenderMarkdown: Block G appears before Block A.
body, err := os.ReadFile(saved.FilePath)
if err != nil {
t.Fatal(err)
}
s := string(body)
if !strings.Contains(s, "**Legitimacy:** high") {
t.Errorf("missing legitimacy header in report:\n%s", s)
}
gIdx := strings.Index(s, "## G)")
aIdx := strings.Index(s, "## A)")
if gIdx == -1 || aIdx == -1 || gIdx > aIdx {
t.Errorf("Block G should appear before Block A; gIdx=%d aIdx=%d", gIdx, aIdx)
}
// Save second eval for the same URL: seq should become 2, application
// should be updated (not duplicated).
eval.Score = 4.5
saved2, err := w.Save(context.Background(), job, eval)
if err != nil {
t.Fatalf("Save#2: %v", err)
}
if saved2.Seq != 2 {
t.Errorf("Seq#2 = %d, want 2", saved2.Seq)
}
if saved2.ApplicationID != saved.ApplicationID {
t.Errorf("application_id drifted: %d → %d", saved.ApplicationID, saved2.ApplicationID)
}
var appCount int
if err := db.QueryRow(`SELECT COUNT(*) FROM applications`).Scan(&appCount); err != nil {
t.Fatal(err)
}
if appCount != 1 {
t.Errorf("applications count = %d, want 1", appCount)
}
var reportCount int
if err := db.QueryRow(`SELECT COUNT(*) FROM reports`).Scan(&reportCount); err != nil {
t.Fatal(err)
}
if reportCount != 2 {
t.Errorf("reports count = %d, want 2", reportCount)
}
}
func TestReportWriter_StatusPreservedWhenReEvaluated(t *testing.T) {
db := setupReportDB(t)
defer db.Close()
w := &ReportWriter{DB: db, ReportsDir: t.TempDir()}
job := JobContext{URL: "https://example.com/j/1", Company: "Beta", Title: "SWE", Source: "ashby"}
eval := Evaluation{Score: 3.0, Legitimacy: TierCaution, BlockA: "## A) x", BlockG: "## G) y"}
if _, err := w.Save(context.Background(), job, eval); err != nil {
t.Fatalf("first save: %v", err)
}
// Simulate user advancing the pipeline.
if _, err := db.Exec(`UPDATE applications SET status = 'Applied' WHERE job_id = (SELECT id FROM jobs WHERE url = ?)`, job.URL); err != nil {
t.Fatal(err)
}
// Re-run eval — must NOT clobber 'Applied' back to 'Evaluated'.
eval.Score = 3.5
if _, err := w.Save(context.Background(), job, eval); err != nil {
t.Fatalf("second save: %v", err)
}
var status string
if err := db.QueryRow(`SELECT status FROM applications WHERE job_id = (SELECT id FROM jobs WHERE url = ?)`, job.URL).Scan(&status); err != nil {
t.Fatal(err)
}
if status != "Applied" {
t.Errorf("status = %q, want Applied (re-eval should not regress)", status)
}
}