package api
import (
"context"
"go/ast"
"go/parser"
"go/token"
"io/fs"
"path/filepath"
"strings"
"testing"
)
// Every email the forge itself sends goes through sendMail, which renders
// the card. A new call to Mail.Send anywhere else would ship a message
// without it, so this walks the sources and fails on one, the way the
// purge test catches a new repo-keyed table. (Notify's email steps are
// held to the card by notify's own test.)
func TestMailSendHasOneCallSite(t *testing.T) {
var sites []string
fset := token.NewFileSet()
for _, root := range []string{"../../internal", "../../cmd"} {
filepath.WalkDir(root, func(path string, e fs.DirEntry, err error) error {
if err != nil || e.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") {
return nil
}
f, perr := parser.ParseFile(fset, path, nil, 0)
if perr != nil {
t.Fatal(perr)
}
ast.Inspect(f, func(n ast.Node) bool {
call, ok := n.(*ast.CallExpr)
if !ok {
return true
}
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok || sel.Sel.Name != "Send" {
return true
}
if recv, ok := sel.X.(*ast.SelectorExpr); ok && recv.Sel.Name == "Mail" {
sites = append(sites, filepath.Base(path)+":"+fset.Position(call.Pos()).String())
}
return true
})
return nil
})
}
if len(sites) != 1 || !strings.HasPrefix(sites[0], "transactional.go:") {
t.Fatalf("Mail.Send must be called only from sendMail (transactional.go); found %v", sites)
}
}
func TestSendMailSendsTheApplicationsCard(t *testing.T) {
mail := &fakeMail{}
d := Deps{Origin: "https://forge.example", Mail: mail}
if err := d.sendMail(context.Background(), "[email protected]", accountMail{Subject: "s", Text: "plain", Body: "<p>x</p>", Open: "Go", URL: "https://forge.example/x"}); err != nil {
t.Fatal(err)
}
if len(mail.sent) != 1 {
t.Fatalf("%d sent", len(mail.sent))
}
h := mail.sent[0].HTML
for _, want := range []string{`class="q-card"`, `src="https://forge.example/lockup.png" alt="QUARRY"`, `src="https://forge.example/lockup-sm.png" alt="QUARRY"`, `class="q-btn"`} {
if !strings.Contains(h, want) {
t.Errorf("card lacks %s", want)
}
}
if strings.Contains(h, ">quarry<") {
t.Error("lowercase quarry in an application email's header")
}
}