Skip to content
quarry Artifact [06e48c0318]
Login

Artifact [06e48c0318]

Artifact 06e48c03182ab1056fe17e28ff6de2ac0d2c6a0625ef50eca38cb441ee5f67f5:


package api

import (
	"context"
	"path/filepath"
	"regexp"
	"strings"
	"testing"
	"time"

	"craftdesign.group/quarry/internal/artifact"
	"craftdesign.group/quarry/internal/index"
	"craftdesign.group/quarry/internal/oltp"
)

// A mention's references link in the mail to the same places the site
// sends them, each with its state as a PNG and its label, every address
// absolute; one that resolves to nothing stays the author's text.
func TestMailReferencesResolveLikeTheSite(t *testing.T) {
	ix, err := index.Open(filepath.Join(t.TempDir(), "m.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { ix.Close() })
	tid, cid, lid := strings.Repeat("ab", 20), strings.Repeat("c3", 20), strings.Repeat("d4", 20)
	if err := ix.FoldNow([]index.Parsed{
		{Hash: "t1", Art: &artifact.Artifact{Type: artifact.Ticket, TicketID: tid, Date: "2026-08-15T09:00:00", User: "dan",
			Fields: []artifact.Field{{Name: "status", Value: "Fixed"}, {Name: "title", Value: "a closed ticket"}}}},
		{Hash: cid, Art: &artifact.Artifact{Type: artifact.Manifest, Date: "2026-08-17T09:00:00", User: "dan", Comment: "a check-in"}},
		{Hash: "w1", Art: &artifact.Artifact{Type: artifact.Wiki, WikiTitle: "Guide", Date: "2026-08-15T10:00:00", User: "dan",
			Mimetype: "text/x-markdown", Body: []byte("# Guide\n")}},
		{Hash: lid, Art: &artifact.Artifact{Type: artifact.Forum, ThreadTitle: "Land it", Date: "2026-08-18T09:00:00", User: "dan",
			Body: []byte("zit-landing: 1\nbranch: b\ntarget: trunk\n\nmessage\n")}},
	}); err != nil {
		t.Fatal(err)
	}
	db, err := oltp.Open(filepath.Join(t.TempDir(), "o.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { db.Close() })
	if err := db.TicketNumbersAssign("demo", []string{tid}); err != nil {
		t.Fatal(err)
	}
	tl, ll := func(_ string, n int) (string, bool) { return tid, n == 1 }, func(_ string, n int) (string, bool) { return lid, n == 768 }
	ln := func(_, id string) int {
		if id == lid {
			return 768
		}
		return 0
	}
	prevT, prevL, prevN := ticketByNumber.Swap(&tl), landingByNumber.Swap(&ll), landingNumberOfRef.Swap(&ln)
	d := Deps{Origin: "https://forge.example", Numbers: db, CanRead: func(context.Context, string) bool { return true },
		CapsFor: func(_, _ string) CapSet { return fakeCaps(anyCapLetters) }}
	d.Repos = NewRepos(map[string]*Repo{"demo": {Index: ix}})
	facts := func(repo, prefix string) (ticketFact, bool) { return d.ticketFactOf(repo, prefix, 0) }
	prevF := ticketFacts.Swap(&facts)
	t.Cleanup(func() {
		ticketByNumber.Store(prevT)
		landingByNumber.Store(prevL)
		landingNumberOfRef.Store(prevN)
		ticketFacts.Store(prevF)
	})

	text := "landed in !768, ticket #1, hash " + cid[:12] + ", see [[Guide]], and !999"
	e := d.withMailHTML(NotifyEvent{Workflow: "quarry-mention", To: "eve", Payload: map[string]any{
		"repo": "demo", "from": "dan", "text": text, "surface": "chat", "link": "https://forge.example/r/demo/chat/1"}}, time.Now())
	h, _ := e.Payload["html"].(string)
	for _, want := range []string{
		`href="https://forge.example/r/demo/landing/` + lid, `alt="landing 768, open"`, `/icons/landing-open.png`,
		`href="https://forge.example/r/demo/ticket/` + tid, `alt="ticket 1, closed"`, `/icons/ticket-closed.png`,
		`href="https://forge.example/r/demo/checkin/` + cid,
		`href="https://forge.example/r/demo/wiki/Guide`,
		`>768</a>`, `>1</a>`, "and !999",
	} {
		if !strings.Contains(h, want) {
			t.Errorf("mail lacks %s", want)
		}
	}
	for _, banned := range []string{"data-ref", "<svg", "tref-state", ">!768<"} {
		if strings.Contains(h, banned) {
			t.Errorf("mail carries %q", banned)
		}
	}
	for _, m := range regexp.MustCompile(`(?:src|href)="([^"]*)"`).FindAllStringSubmatch(h, -1) {
		if !strings.HasPrefix(m[1], "https://") {
			t.Errorf("non-absolute %q", m[1])
		}
	}
}