ajhahn.de
← eeco
Go 91 lines
package workflow

import "testing"

// Fingerprint literals are assembled from fragments here for the same
// reason as in attribution.go: this test file is tracked source, and
// eeco's own comment-hygiene / leak-guard scan it. A contiguous
// attribution literal would (correctly) make eeco fail its own gate.
const (
	fragCoAB = "Co-" + "Authored-" + "By"
	fragGen  = "Gener" + "ated"
)

func TestDetector_Clean(t *testing.T) {
	d, err := NewDetector(nil)
	if err != nil {
		t.Fatal(err)
	}
	goods := []string{
		"package main\n\nfunc main() {}\n",
		"// guidance on authoring and code review\n",
		"see the `" + fragCoAB + "` trailer in the docs\n",          // backticked prose, not a trailer line
		"  note: " + fragCoAB + " is a git trailer key\n",           // token mid-line, no colon at start
		fragGen + " the quarterly report by hand on a fair day\n",   // "fair" must not trip the AI token
		fragGen + " with the standard build pipeline\n",             // no tool token
		"the model was " + fragGen + " by a deterministic script\n", // "model"/"script" excluded by design
	}
	for i, g := range goods {
		if f := d.Scan("clean.txt", g); len(f) != 0 {
			t.Errorf("good[%d] flagged %+v\n  input=%q", i, f, g)
		}
	}
}

func TestDetector_Fingerprints(t *testing.T) {
	d, _ := NewDetector(nil)
	coAB := fragCoAB + ": A Person <[email protected]>"
	cases := []struct{ name, in string }{
		{"trailer at line start", coAB + "\n"},
		{"trailer after whitespace", "    " + coAB + "\n"},
		{"with-tool line", fragGen + " with an AI assistant\n"},
		{"by-cli line", "report " + fragGen + " by the project CLI\n"},
		{"by-agent line", fragGen + " by a coding agent for us\n"},
		{"robot emoji line", "\U0001F916 " + fragGen + " with a coding agent\n"},
	}
	for _, c := range cases {
		got := d.Scan("bad.txt", c.in)
		if len(got) == 0 {
			t.Errorf("%s: expected a finding, input=%q", c.name, c.in)
			continue
		}
		if got[0].Line != 1 {
			t.Errorf("%s: line = %d, want 1", c.name, got[0].Line)
		}
	}
}

func TestDetector_MultiLineNumbers(t *testing.T) {
	d, _ := NewDetector(nil)
	in := "clean line\nanother clean line\n" + fragCoAB + ": X <x@y>\n"
	got := d.Scan("f", in)
	if len(got) != 1 || got[0].Line != 3 {
		t.Fatalf("want one finding on line 3, got %+v", got)
	}
}

func TestDetector_ScanResponse(t *testing.T) {
	d, _ := NewDetector(nil)
	got := d.ScanResponse(fragCoAB + ": X <x@y>\n")
	want := []string{"line 1: co-authored-by trailer"}
	if len(got) != 1 || got[0] != want[0] {
		t.Errorf("ScanResponse(attribution) = %v, want %v", got, want)
	}
	if r := d.ScanResponse("a clean response with no fingerprint\n"); r != nil {
		t.Errorf("ScanResponse(clean) = %v, want nil", r)
	}
}

func TestDetector_ExtraPattern(t *testing.T) {
	d, err := NewDetector([]string{`INTERNAL-CODENAME`})
	if err != nil {
		t.Fatal(err)
	}
	if f := d.Scan("x", "leaked INTERNAL-CODENAME here\n"); len(f) == 0 {
		t.Error("configured extra pattern was not applied")
	}
	if _, err := NewDetector([]string{"("}); err == nil {
		t.Error("an invalid extra regex must be a loud error")
	}
}