package lint import ( "os" "path/filepath" "testing" ) // writeFixture drops src at name under dir, creating parents. func writeFixture(t *testing.T, dir, name, src string) string { t.Helper() path := filepath.Join(dir, name) if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(path, []byte(src), 0o644); err != nil { t.Fatal(err) } return path } func TestRuleRawErrorRender(t *testing.T) { dir := t.TempDir() leaky := writeFixture(t, dir, "handlers.go", `package server func (h *H) bad(err error, attErr error) { h.renderFooPage(w, r, "", "Failed to save: "+err.Error()) // line 4: flag fireErrorToast(w, attErr.Error()) // line 5: flag (suffixed identifier) http.Error(w, err.Error(), 500) // line 6: flag h.Logger.Error("failed", slog.Any("error", err)) // line 7: ok — slog only slog.Error("failed to save: " + err.Error()) // line 8: ok — slog carve-out return fmt.Errorf("wrap: %w", err) // line 9: ok — no UI sink msg := err.Error() // line 10: ok — no UI sink on this line h.renderFooPage(w, r, "", "Failed to save. See the logs.") // line 11: ok — generic text only fireSuccessToast(w, "saved "+err.Error()) // line 12: flag (success toast is a sink too) } `) writeFixture(t, dir, "handlers_test.go", `package server func TestX(t *testing.T) { h.renderFooPage(w, r, "", "boom: "+err.Error()) // tests are exempt } `) got := ruleRawErrorRender(dir) wantLines := map[int]bool{4: true, 5: true, 6: true, 12: true} if len(got) != len(wantLines) { t.Fatalf("got %d violations, want %d: %+v", len(got), len(wantLines), got) } for _, viol := range got { if viol.File != leaky { t.Errorf("violation in %s, want only %s", viol.File, leaky) } if viol.Rule != "raw-error-render" { t.Errorf("rule = %q, want raw-error-render", viol.Rule) } if !wantLines[viol.Line] { t.Errorf("unexpected violation at line %d", viol.Line) } delete(wantLines, viol.Line) } for line := range wantLines { t.Errorf("missing violation at line %d", line) } } func TestRuleRawErrorRender_CleanDir(t *testing.T) { dir := t.TempDir() writeFixture(t, dir, "clean.go", `package server func (h *H) good(err error) { if fe, ok := web.FieldErrorsFromDB(err, nil); ok { h.renderFooFormErrors(w, r, fe) return } h.Logger.Error("failed to save", slog.Any("error", err)) h.renderFooPage(w, r, "", "Failed to save. Details are in the server logs.") } `) if got := ruleRawErrorRender(dir); len(got) != 0 { t.Fatalf("got %d violations on clean fixture, want 0: %+v", len(got), got) } }