package highlight
import (
"regexp"
"strings"
"testing"
)
func TestCodeByFilename(t *testing.T) {
out, ok := Code([]byte("package main\n"), "", "src/main.go")
if !ok {
t.Fatal("go file not highlighted")
}
if !strings.Contains(out, "<span class=") || !strings.Contains(out, "package") {
t.Fatalf("no classed spans:\n%s", out)
}
if strings.Contains(out, "style=") {
t.Fatalf("inline styles leak into output (classes only):\n%s", out)
}
}
func TestCodeByLanguage(t *testing.T) {
if _, ok := Code([]byte("SELECT 1;\n"), "sql", ""); !ok {
t.Fatal("language hint not used")
}
}
func TestCodeNoLexer(t *testing.T) {
// Pure binary-ish content with no filename or language: callers get
// ok=false and fall back to escaped <pre>.
if out, ok := Code([]byte{0x00, 0x01, 0x02}, "", "data.zzzunknown"); ok {
t.Fatalf("unexpected lexer match:\n%s", out)
}
}
func TestCSSHasBothThemes(t *testing.T) {
css := CSS()
if !strings.Contains(css, ".chroma") {
t.Fatal("no chroma rules")
}
if !strings.Contains(css, "prefers-color-scheme: dark") {
t.Fatal("no dark theme block")
}
}
func TestDarkThemeCoversEveryLightClass(t *testing.T) {
// Ticket 030: every token class colored in light mode must also be
// colored inside the dark block, or identifiers/punctuation render
// near-black on the dark background.
css := CSS()
i := strings.Index(css, "prefers-color-scheme: dark")
if i < 0 {
t.Fatal("no dark block")
}
light, dark := css[:i], css[i:]
re := regexp.MustCompile(`\.chroma \.([a-zA-Z0-9]+) `)
darkClasses := map[string]bool{}
for _, m := range re.FindAllStringSubmatch(dark, -1) {
darkClasses[m[1]] = true
}
for _, m := range re.FindAllStringSubmatch(light, -1) {
if !darkClasses[m[1]] {
t.Errorf("class .%s colored in light mode but not in dark", m[1])
}
}
// The classes the test round found invisible must now be covered.
for _, c := range []string{"nx", "p", "na", "nb", "bp"} {
if !darkClasses[c] {
t.Errorf("known-invisible class .%s still missing from dark block", c)
}
}
}
// The page offers three theme states, so this stylesheet must too. A
// bare prefers-color-scheme block leaves a reader who picks light on a
// dark-mode device with dark code colours on a light page, and makes
// picking dark on a light-mode device do nothing at all — the failure
// only ever shows up on someone else's device.
func TestDarkRulesAreThemeGuarded(t *testing.T) {
css := CSS()
media := strings.Index(css, "@media (prefers-color-scheme: dark)")
if media < 0 {
t.Fatal("no dark block at all")
}
inMedia := strings.Count(css[media:], `:root:not([data-theme="light"]) .chroma`)
explicit := strings.Count(css, `:root[data-theme="dark"] .chroma`)
if inMedia == 0 {
t.Error("the dark media query is unguarded: an explicit light choice cannot override it")
}
if explicit == 0 {
t.Error("no rules under an explicit dark choice: picking dark on a light-mode device does nothing")
}
if inMedia != explicit {
t.Errorf("guarded %d rules but repeated %d under explicit dark; the two states would disagree", inMedia, explicit)
}
}