Skip to content
quarry Artifact [0a114d1b93]
Login

Artifact [0a114d1b93]

Artifact 0a114d1b9349607f3d68ae77acb2bd343656696edf5bc645dd033f81dd6df14c:


package theme

import (
	"math"
	"strings"
	"testing"
)

// Every theme holds the floor quarry's own palette holds: each text
// colour at 4.5:1 on each ground it is drawn on.
func TestEveryThemeReadsOnItsGrounds(t *testing.T) {
	text := []string{"--fg", "--add", "--del", "--syn-kw", "--syn-str", "--syn-num",
		"--syn-fn", "--syn-type", "--syn-com", "--syn-builtin", "--syn-attr"}
	grounds := []string{"--code-block", "--add-row", "--del-row", "--add-mark", "--del-mark"}
	for _, th := range All {
		for _, g := range grounds {
			for _, c := range text {
				fg, bg := th.Value(c), th.Value(g)
				if r := Contrast(fg, bg); r < 4.5 {
					t.Errorf("FAIL: %s: %s %s on %s %s is %.2f:1", th.ID, c, fg, g, bg, r)
				}
			}
		}
		for _, c := range []string{"--fg", "--muted", "--accent"} {
			if r := Contrast(th.Value(c), th.Value("--bg")); r < 4.5 {
				t.Errorf("FAIL: %s: %s on the page is %.2f:1", th.ID, c, r)
			}
		}
	}
}

// What is not text still has to be seen: a line on the page and on a
// code block, a code pill on the page (and what is written on it), a
// highlight on the code it marks. Material and Rosé Pine once drew
// their lines in the page's own colour. A line stays a line, too: no
// heavier than 3:1 unless the theme is a high-contrast one.
func TestEveryThemeDrawsWhatIsNotText(t *testing.T) {
	for _, th := range All {
		v := th.Value
		for _, g := range []string{"--bg", "--code-block"} {
			if r := Contrast(v("--rule"), v(g)); r < 1.45 {
				t.Errorf("FAIL: %s: --rule on %s is %.2f:1", th.ID, g, r)
			}
		}
		if r := Contrast(v("--rule"), v("--bg")); r > 3 && !strings.Contains(th.ID, "high-contrast") {
			t.Errorf("FAIL: %s: --rule on the page is %.2f:1", th.ID, r)
		}
		if r := Contrast(v("--code-bg"), v("--bg")); r < 1.12 || r > 1.35 {
			t.Errorf("FAIL: %s: --code-bg on the page is %.2f:1", th.ID, r)
		}
		for _, c := range []string{"--fg", "--muted", "--accent", "--add", "--del"} {
			for _, g := range []string{"--bg", "--code-bg"} {
				if r := Contrast(v(c), v(g)); r < 4.5 {
					t.Errorf("FAIL: %s: %s on %s is %.2f:1", th.ID, c, g, r)
				}
			}
		}
		for _, g := range []string{"--code-block", "--bg"} {
			// --bg too: search highlights mark text on the page (#368).
			if d := math.Abs(luminance(v("--mark")) - luminance(v(g))); d < 0.06 {
				t.Errorf("FAIL: %s: --mark differs from %s by %.3f luminance", th.ID, g, d)
			}
		}
		if r := Contrast(v("--fg"), v("--mark")); r < 4.5 {
			t.Errorf("FAIL: %s: --fg on --mark is %.2f:1", th.ID, r)
		}
	}
}

// A theme is chosen by id from a cookie and served at its own URL, so
// both must be unique and every theme must carry every token a sheet
// writes.
func TestThemesAreWholeAndDistinct(t *testing.T) {
	if len(All) < 60 {
		t.Fatalf("FAIL: %d themes, want hunk's full set", len(All))
	}
	ids, urls := map[string]bool{}, map[string]bool{}
	for _, th := range All {
		if ids[th.ID] {
			t.Errorf("FAIL: duplicate id %s", th.ID)
		}
		ids[th.ID] = true
		for _, u := range []string{SiteURL(th), CodeURL(th)} {
			if urls[u] {
				t.Errorf("FAIL: duplicate url %s", u)
			}
			urls[u] = true
		}
		for _, name := range CodeTokens {
			if th.Value(name) == "" {
				t.Errorf("FAIL: %s has no %s", th.ID, name)
			}
		}
	}
	if len(Assets()) != 2*(len(All)+len(Families)) {
		t.Errorf("FAIL: %d assets for %d themes and %d families", len(Assets()), len(All), len(Families))
	}
	if _, ok := ByID("gruvbox-dark-hard"); !ok {
		t.Error("FAIL: no gruvbox-dark-hard")
	}
}

// The sheets are what the browser reads: the site one on the root,
// above paletteCSS's own selectors; the code one on what draws code,
// with only the code tokens.
func TestSheetsTargetTheRightElements(t *testing.T) {
	th, _ := ByID("catppuccin-mocha")
	site, code := SiteCSS(th), CodeCSS(th)
	if !strings.HasPrefix(site, ":root:root{") || !strings.Contains(site, "--bg:") || !strings.Contains(site, "color-scheme:dark") {
		t.Errorf("FAIL: site sheet: %s", site)
	}
	if !strings.HasPrefix(code, codeSelector+"{") || strings.Contains(code, "--bg:") || strings.Contains(code, "--accent:") {
		t.Errorf("FAIL: code sheet: %s", code)
	}
	if !strings.Contains(code, "--syn-kw:") || !strings.Contains(code, "--add-row:") {
		t.Errorf("FAIL: code sheet lacks syntax or diff tokens: %s", code)
	}
}