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")
}
}