Skip to content
quarry Artifact [81a5e607aa]
Login

Artifact [81a5e607aa]

Artifact 81a5e607aa2e6ae298abd2cbc66779f3d6410e4fd79df5afc2c1b36bc5e2ed03:


package web

import (
	"strings"
	"testing"

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

// Every kind the index can return must produce a link. forum and
// technote fell through hitOf's switch with no URL, so their titles
// rendered as <a href="">, which a browser resolves to the current
// page: clicking a forum result reloaded the search. The index found
// them, the facet chips offered them, and the one step that turns a hit
// into somewhere to go was missing.
//
// Driven by index.SearchKinds rather than a hand-written list, so a
// kind added to the index without a link here fails instead of
// shipping a dead result.
func TestEverySearchKindLinksSomewhere(t *testing.T) {
	// Refs by kind, in the shape searchDoc actually files them: a
	// check-in by hash, a wiki page by title, a ticket by id, a forum
	// post by its THREAD ROOT, a technote by its EVENT id.
	ref := map[string]string{
		"checkin":  strings.Repeat("a", 64),
		"wiki":     "Design Notes",
		"ticket":   strings.Repeat("b", 40),
		"forum":    strings.Repeat("c", 64),
		"technote": strings.Repeat("d", 40),
		"doc":      "b8c7665e121b25c3/www/quickstart.wiki",
		"file":     "b8c7665e121b25c3/src/main.c",
	}
	want := map[string]string{
		"checkin":  "/r/demo/checkin/",
		"wiki":     "/r/demo/wiki/",
		"ticket":   "/r/demo/ticket/",
		"forum":    "/r/demo/forum/",
		"technote": "/r/demo/technote/",
		"doc":      "/r/demo/doc/",
		"file":     "/r/demo/file/",
	}

	for _, kind := range index.SearchKinds {
		r, ok := ref[kind]
		if !ok {
			t.Fatalf("index.SearchKinds gained %q and this test does not know its ref shape", kind)
		}
		t.Run(kind, func(t *testing.T) {
			h := hitOf("demo", kind, r, "A Label", "a ⟦match⟧ here")
			if h.URL == "" {
				t.Fatalf("%s hit has no URL — the title renders as href=\"\" "+
					"and clicking it reloads the search", kind)
			}
			if !strings.HasPrefix(h.URL, want[kind]) {
				t.Errorf("%s URL = %q, want it under %q", kind, h.URL, want[kind])
			}

			// A hit with no label must still be clickable and must not
			// render as an empty link.
			bare := hitOf("demo", kind, r, "", "")
			if bare.URL == "" || strings.TrimSpace(bare.Label) == "" {
				t.Errorf("%s with no label: url=%q label=%q — both must be filled",
					kind, bare.URL, bare.Label)
			}
		})
	}
}

// The snippet's match markers become <mark> only AFTER escaping, so a
// hit whose content carries markup stays inert.
func TestSearchSnippetStaysInert(t *testing.T) {
	h := hitOf("demo", "checkin", strings.Repeat("a", 64), "L",
		"before ⟦<script>alert(1)</script>⟧ after")
	got := string(h.Snippet)
	if strings.Contains(got, "<script>") {
		t.Errorf("snippet passed markup through: %q", got)
	}
	if !strings.Contains(got, "<mark>") || !strings.Contains(got, "&lt;script&gt;") {
		t.Errorf("snippet = %q, want escaped content inside <mark>", got)
	}
}