~bigbes/sr-ht-spec

ref: cd1b8b014d4f88d3a972259e5bb7aee42d14013b sr-ht-spec/search/extract_test.go -rw-r--r-- 6.2 KiB
cd1b8b01 — Eugene Blikh deps: auxilia whose scribe.Err reads the whole error chain 9 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package search

import (
	"testing"

	"github.com/stretchr/testify/require"

	"sourcecraft.dev/bigbes/sr-ht-spec/doc"
	"sourcecraft.dev/bigbes/sr-ht-spec/gitx"
)

func byID(docs []Document) map[string]Document {
	m := make(map[string]Document, len(docs))
	for _, d := range docs {
		m[d.ID] = d
	}
	return m
}

func TestExtractCarriesSpaceRevisionAndPath(t *testing.T) {
	c := newCorpus(t, "~bigbes/specs", "8f14e45fceea167a5a36dedd4bea2543").
		add("specs/storage.md", "---\nid: SPEC-0001\ntitle: Storage model\n---\n\nBodies live in git.\n")
	docs := c.extract(t)

	require.Len(t, docs, 1)
	require.Equal(t, c.Space, docs[0].Space)
	require.Equal(t, "8f14e45fceea167a5a36dedd4bea2543", docs[0].Rev)
	require.Equal(t, "specs/storage.md", docs[0].Path)
	require.Equal(t, "specs", docs[0].Section)
	require.Equal(t, "SPEC-0001", docs[0].ID)
	require.Empty(t, docs[0].Anchor)
}

// Frontmatter is prepended to the searchable text, so a tag or an owner finds
// the document even though neither is prose. Carried over from warren.
func TestExtractIndexesFrontmatterAsText(t *testing.T) {
	c := newCorpus(t, "~bigbes/specs", "rev1").
		add("specs/storage.md", "---\nid: SPEC-0001\ntitle: Storage model\n"+
			"tags: [storage, review]\nowners: ['~bigbes']\nsummary: One tier, git objects only\n---\n\n"+
			"Bodies live in git.\n")
	docs := c.extract(t)

	require.Len(t, docs, 1)
	require.Contains(t, docs[0].Text, "storage")
	require.Contains(t, docs[0].Text, "review")
	require.Contains(t, docs[0].Text, "One tier, git objects only")
	require.Contains(t, docs[0].Text, "Bodies live in git.")
}

// A catalog is a page of one-line descriptions of other documents. Indexed
// whole, a query lands on the description instead of the document that owns it.
func TestExtractIndexesACatalogByTitleOnly(t *testing.T) {
	c := newCorpus(t, "~bigbes/specs", "rev1").
		add("specs/index.md", "# Specifications\n\n- [[SPEC-0001]] — the storage model\n- [[SPEC-0002]] — review\n").
		add("specs/storage.md", "---\nid: SPEC-0001\ntitle: Storage model\n---\n\nBodies live in git.\n")
	docs := byID(c.extract(t))

	catalog, ok := docs["specs/index"]
	require.True(t, ok, "the catalog is still indexed: %v", docs)
	require.Equal(t, doc.KindCatalog, kindOf(t, c, "specs/index.md"))
	require.Empty(t, catalog.Text, "a catalog contributes no body")
	require.Equal(t, "Specifications", catalog.Title)
}

func kindOf(t *testing.T, c *corpus, path string) doc.PageKind {
	t.Helper()
	arc := doc.FromDocuments(c.Space, c.Rev, c.docs)
	p, ok := arc.ByPath(path)
	require.True(t, ok)
	return p.Kind
}

// An activity log contributes its own title-only document plus one per dated
// entry, each anchored into the log it came from. Carried over from warren,
// where a hit anywhere in a 248 KB log resolved to the whole file.
func TestExtractSplitsAnActivityLogIntoEntries(t *testing.T) {
	c := newCorpus(t, "~bigbes/specs", "rev1").
		add("notes/log.md", "# Work log\n\n"+
			"## [2026-05-31] ingest | Imported the RFC set\nPulled 40 documents in from the old wiki.\n\n"+
			"## [2026-05-30] lint | Fixed frontmatter\nEvery document now carries a status.\n")
	docs := byID(c.extract(t))
	require.Len(t, docs, 3)

	page, ok := docs["notes/log"]
	require.True(t, ok)
	require.Equal(t, doc.LogSection, page.Section, "the log page moves to the log section")
	require.Empty(t, page.Text)

	first, ok := docs["notes/log#2026-05-31-1"]
	require.True(t, ok, "entries are keyed under their own document: %v", docs)
	require.Equal(t, doc.LogSection, first.Section)
	require.Equal(t, "notes/log.md", first.Path, "an entry points back at the log it lives in")
	require.Equal(t, "e-2026-05-31-1", first.Anchor)
	require.Equal(t, "2026-05-31 Imported the RFC set", first.Title)
	require.Contains(t, first.Text, "Pulled 40 documents in from the old wiki.")
	require.NotContains(t, first.Text, "Fixed frontmatter", "entries do not bleed into each other")
}

// doc.SplitLog names entries "log#<date>-<n>", after warren's single vault-wide
// log. Two logs in one space would then produce colliding ids, and in one index
// colliding ids are the same document — one log would silently overwrite the
// other. Entry ids are namespaced by their own document to prevent it.
func TestExtractNamespacesLogEntriesPerDocument(t *testing.T) {
	entry := "\n## [2026-05-31] ingest | Same day, two logs\nBody.\n"
	c := newCorpus(t, "~bigbes/specs", "rev1").
		add("log.md", "# Space log\n"+entry).
		add("notes/log.md", "# Notes log\n"+entry)
	docs := byID(c.extract(t))

	require.Contains(t, docs, "log#2026-05-31-1", "a log whose page id is \"log\" keeps warren's ids")
	require.Contains(t, docs, "notes/log#2026-05-31-1")
	require.Len(t, docs, 4, "two log pages and two entries, none of them merged")
}

// A page in the archive with no body is a caller bug. Indexing it with an empty
// body would leave a document that exists and is unfindable, which is the
// failure mode that surfaces months later.
func TestExtractRefusesAPageWithNoBody(t *testing.T) {
	c := newCorpus(t, "~bigbes/specs", "rev1").
		add("specs/storage.md", "---\nid: SPEC-0001\ntitle: Storage model\n---\n\nBodies live in git.\n")
	arc := doc.FromDocuments(c.Space, c.Rev, c.docs)

	_, err := Extract(arc, map[string][]byte{})
	require.ErrorContains(t, err, "no body supplied for specs/storage.md")
}

// A document whose frontmatter core rejects still renders and still indexes:
// --push-option=skip-validation means a broken header can reach the approved
// branch, and refusing to index it would turn a typo into a silent hole.
func TestExtractIndexesADocumentWithABrokenHeader(t *testing.T) {
	c := newCorpus(t, "~bigbes/specs", "rev1").
		add("specs/broken.md", "---\nid: [not, a, string\n---\n\n# Broken but readable\n\nThe body is still prose.\n")
	docs := c.extract(t)

	require.Len(t, docs, 1)
	require.Equal(t, "specs/broken", docs[0].ID, "it falls back to its path")
	require.Contains(t, docs[0].Text, "The body is still prose.")
}

func TestBodiesKeysByPath(t *testing.T) {
	got := Bodies([]gitx.Document{
		{Path: "a.md", Data: []byte("one")},
		{Path: "b/c.md", Data: []byte("two")},
	})
	require.Equal(t, map[string][]byte{"a.md": []byte("one"), "b/c.md": []byte("two")}, got)
}

func TestExtractNeedsAnArchive(t *testing.T) {
	_, err := Extract(nil, nil)
	require.ErrorContains(t, err, "needs an archive")
}