Skip to content
quarry Artifact [af0ee3851d]
Login

Artifact [af0ee3851d]

Artifact af0ee3851d72436b532135dd74ebc351d0acff327dedb74c8d218287a7e2bb0d:


package markup

import (
	"html/template"
	"regexp"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/idn"
)

// The identicon is idn's face, cell for cell, drawn as a table: five
// rows of five, a cell coloured exactly where the grid is on and in the
// shade the grid says.
func TestIdenticonMarkMatchesTheGrid(t *testing.T) {
	const name = "dantest-sandbox"
	got := string(IdenticonMark(name))
	for _, banned := range []string{"<svg", "<img", "display:grid", "display:flex", "url("} {
		if strings.Contains(got, banned) {
			t.Errorf("mark carries %s", banned)
		}
	}
	inner := got[strings.Index(got, `align="center"`):]
	rows := strings.Split(inner, "<tr>")[1:]
	if len(rows) != 5 {
		t.Fatalf("%d rows", len(rows))
	}
	lit, deep := idn.Hex(name, markLit), idn.Hex(name, markDeep)
	for r, row := range rows {
		cells := regexp.MustCompile(`<td [^>]*>`).FindAllString(row, -1)
		if len(cells) != 5 {
			t.Fatalf("row %d: %d cells", r, len(cells))
		}
		for c, cell := range cells {
			want := ""
			switch idn.Grid(name)[r][c] {
			case 1:
				want = `bgcolor="` + lit + `"`
			case 2:
				want = `bgcolor="` + deep + `"`
			}
			if has := strings.Contains(cell, "bgcolor="); has != (want != "") || (want != "" && !strings.Contains(cell, want)) {
				t.Errorf("cell %d,%d = %s, want %q", r, c, cell, want)
			}
		}
	}
}

func TestAvatarMarkIsOneSizedImage(t *testing.T) {
	got := string(AvatarMark("https://forge.example/r/alpha/avatar", "alpha"))
	for _, want := range []string{`src="https://forge.example/r/alpha/avatar"`, `width="28"`, `height="28"`, `border-radius:6px`, `alt="alpha"`} {
		if !strings.Contains(got, want) {
			t.Errorf("missing %s", want)
		}
	}
}

// With nothing else to name, a card is the application's: its Q logo and
// the word QUARRY as styled text (never an image, so a client that
// recolours dark mail recolours it too), again in the footer, small.
func TestAccountCardIsTheApplicationsNotARepositorys(t *testing.T) {
	const logo = "https://forge.example/apple-touch-icon.png"
	got, ok := EmailDocument(EmailDoc{Title: "t", Surface: "account", Body: "<p>x</p>", Why: "w", LogoURL: logo,
		HomeURL: "https://forge.example", HomeName: "forge.example"})
	if !ok {
		t.Fatal("fell back")
	}
	if n := strings.Count(got, `<img src="`+logo+`"`); n != 2 {
		t.Errorf("%d logo images, want header and footer", n)
	}
	if n := strings.Count(got, ">QUARRY<"); n != 2 {
		t.Errorf("%d QUARRY words, want header and footer", n)
	}
	for _, want := range []string{
		"font-family:'Iosevka Fixed','Iosevka','Arial Narrow','Roboto Condensed','Helvetica Neue Condensed',sans-serif",
		"font-weight:600;text-transform:uppercase;letter-spacing:", "color:#282828;",
		`.q-word { color:#f0ece4 !important; }`,
		`href="https://cdn.jsdelivr.net/npm/@fontsource/iosevka/600.css"`,
	} {
		if !strings.Contains(got, want) {
			t.Errorf("missing %s", want)
		}
	}
	for _, banned := range []string{"lockup", "wordmark", "&#9670;", "Sent by", ">quarry<", "b9541a"} {
		if strings.Contains(got, banned) {
			t.Errorf("carries %q", banned)
		}
	}
	if strings.Contains(got, "zeitforge.app/") {
		t.Error("a font or image is fetched from the forge: a self-hosted fetch is a read signal")
	}
}

// A repository's header keeps its own mark and name; the footer carries
// the small logo and the word.
func TestRepoCardKeepsItsMarkAndFooterHasTheWord(t *testing.T) {
	const logo = "https://forge.example/apple-touch-icon.png"
	got, _ := EmailDocument(EmailDoc{Title: "t", Name: "alpha", Mark: IdenticonMark("alpha"), Body: "<p>x</p>", LogoURL: logo})
	if strings.Count(got, "<img") != 1 || strings.Count(got, ">QUARRY<") != 1 || strings.Contains(got, "lockup") {
		t.Errorf("repo card: %d images, %d words", strings.Count(got, "<img"), strings.Count(got, ">QUARRY<"))
	}
}

// The wordmark is the word as text for everyone, and, in Gmail only, the
// badge image (Gmail recolours text it does not report and never images).
// The hidden copy is display:none, so one reading of QUARRY reaches a
// screen reader.
func TestWordmarkIsTextEverywhereAndTheBadgeInGmail(t *testing.T) {
	const logo, big, small = "https://forge.example/apple-touch-icon.png?v=aaaa1111", "https://forge.example/badge.png?v=bbbb2222", "https://forge.example/badge-sm.png?v=cccc3333"
	got, ok := EmailDocument(EmailDoc{Title: "t", Surface: "account", Body: "<p>x</p>", Why: "w", LogoURL: logo, BadgeURL: big, BadgeSmallURL: small})
	if !ok {
		t.Fatal("fell back")
	}
	for _, want := range []string{
		// Text, in the application's face, white where a client is told dark.
		`<span class="q-word q-wm-t" style="font-family:'Iosevka Fixed','Iosevka','Arial Narrow','Roboto Condensed','Helvetica Neue Condensed',sans-serif;font-size:36px;line-height:36px;font-weight:600;text-transform:uppercase;letter-spacing:0;color:#282828;">QUARRY</span>`,
		`font-size:18px;line-height:18px;`,
		`.q-word { color:#f0ece4 !important; }`, `[data-ogsc] .q-word { color:#f0ece4 !important; }`,
		// The badge: hidden by default, shown only in Gmail, which also drops the logo cell and the text.
		`<img class="q-wm-b" src="` + big + `" alt="QUARRY" width="92" height="28" style="display:none;max-height:0;overflow:hidden;mso-hide:all;`,
		`<img class="q-wm-b" src="` + small + `" alt="QUARRY" width="59" height="18" style="display:none;`,
		`u + .body .q-lgtd, u + .body .q-wm-t { display:none !important; }`,
		`u + .body .q-wm-b { display:block !important;`,
		`class="q-lgtd"`, `<body class="body"`, `<!doctype html>`,
		`href="https://cdn.jsdelivr.net/npm/@fontsource/iosevka/600.css"`,
	} {
		if !strings.Contains(got, want) {
			t.Errorf("missing %s", want)
		}
	}
	for _, banned := range []string{"wordmark", "lockup", "ink.png", "b9541a", "q-wm-d", "q-wm-l"} {
		if strings.Contains(got, banned) {
			t.Errorf("carries %q", banned)
		}
	}
	if n := strings.Count(got, ">QUARRY<"); n != 2 {
		t.Errorf("%d text copies, want header and footer", n)
	}
	if n := strings.Count(got, `alt="QUARRY"`); n != 2 {
		t.Errorf("%d badge images, want header and footer", n)
	}
	// Without a badge the text is all there is, and it is visible.
	got, _ = EmailDocument(EmailDoc{Title: "t", Surface: "account", Body: "<p>x</p>", Why: "w"})
	if strings.Contains(got, "<img") || !strings.Contains(got, ">QUARRY<") {
		t.Error("no-badge fallback")
	}
}

// headerOf is the card's header: everything between the body and the
// line naming what happened.
func headerOf(t *testing.T, doc string) string {
	t.Helper()
	i := strings.Index(doc, `<body`)
	j := strings.Index(doc, `<div class="q-text" style="font-size:15px;`)
	if i < 0 || j < i {
		t.Fatal("no header found")
	}
	return doc[i:j]
}

// A repository's email names the repository in its header, with its own
// mark: never the application's wordmark, in text or as the badge. The
// footer of every email, repository or not, keeps the wordmark.
func TestRepositoryHeaderNeverCarriesTheWordmark(t *testing.T) {
	const logo = "https://forge.example/apple-touch-icon.png?v=aaaa1111"
	for name, mark := range map[string]string{
		"alpha":  string(IdenticonMark("alpha")),
		"quarry": string(AvatarMark(logo, "quarry")),
	} {
		got, _ := EmailDocument(EmailDoc{Title: "t", Name: name, Mark: template.HTML(mark), Surface: "chat", Body: "<p>x</p>", Why: "w",
			LogoURL: logo, BadgeURL: "https://forge.example/badge.png?v=b", BadgeSmallURL: "https://forge.example/badge-sm.png?v=c"})
		head := headerOf(t, got)
		for _, banned := range []string{"QUARRY", "q-wm", "badge", "q-word"} {
			if strings.Contains(head, banned) {
				t.Errorf("%s: the header carries %q: %s", name, banned, head)
			}
		}
		if !strings.Contains(head, ">"+name+"<") {
			t.Errorf("%s: the header does not name the repository", name)
		}
		foot := got[strings.Index(got, `class="q-rule q-muted"`):]
		if !strings.Contains(foot, ">QUARRY<") || !strings.Contains(foot, `class="q-wm-b"`) {
			t.Errorf("%s: the footer lost the wordmark", name)
		}
	}
	// An application email has it in the header too.
	app, _ := EmailDocument(EmailDoc{Title: "t", Surface: "account", Body: "<p>x</p>", Why: "w", LogoURL: logo, BadgeURL: "https://forge.example/badge.png?v=b"})
	if h := headerOf(t, app); !strings.Contains(h, ">QUARRY<") || !strings.Contains(h, `class="q-wm-b"`) {
		t.Error("an application email's header lost the wordmark")
	}
}