~bigbes/sr-ht-spec

ref: c74776077006e81af82c2fd53cb186271b42bee9 sr-ht-spec/doc/fixture_test.go -rw-r--r-- 3.4 KiB
c7477607 — Eugene Blikh authn: accept tokens.sr.ht working tokens beside the agent token 10 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
package doc

import (
	"context"
	"fmt"
	"sort"
	"testing"
	"time"

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

// Fixtures are real git objects, built in-process through gitx. Nothing here
// shells out to git and nothing reads a checkout — which is the point of the
// port: if these tests could be satisfied by a directory of files, they would
// not be testing the thing that changed.

var fxSpace = core.SpaceRef{Owner: "bigbes", Name: "rfcs"}

func fxSig(n int) gitx.Signature {
	return gitx.Signature{
		Name:  "bigbes",
		Email: "bigbes@gmail.com",
		When:  time.Date(2026, 7, 22, 12, 0, 0, 0, time.UTC).Add(time.Duration(n) * time.Minute),
	}
}

// space creates an empty bare space under a temp repos root.
func space(t *testing.T) *gitx.Repo {
	t.Helper()
	repo, err := gitx.Create(context.Background(), t.TempDir(), fxSpace, gitx.CreateOptions{Owner: fxSig(0)})
	if err != nil {
		t.Fatalf("gitx.Create: %v", err)
	}
	return repo
}

// commit writes files onto a fresh proposal branch cut from base and returns
// the branch name. A proposal branch is used rather than the approved branch
// because the write path refuses the latter by design, and because reading a
// proposal branch is one of the three revisions the read plane must serve
// through this exact code path.
func commit(t *testing.T, repo *gitx.Repo, n int, base string, files map[string]string) string {
	t.Helper()
	ctx := context.Background()

	branch, err := gitx.ProposalBranch(int64(n))
	if err != nil {
		t.Fatalf("ProposalBranch(%d): %v", n, err)
	}
	if _, err := repo.CreateProposalBranch(ctx, branch, base); err != nil {
		t.Fatalf("CreateProposalBranch(%q, %q): %v", branch, base, err)
	}

	paths := make([]string, 0, len(files))
	for p := range files {
		paths = append(paths, p)
	}
	sort.Strings(paths)

	writes := make([]gitx.Write, 0, len(files))
	for _, p := range paths {
		writes = append(writes, gitx.Write{Path: p, Content: []byte(files[p])})
	}
	meta := gitx.CommitMeta{
		Message:   fmt.Sprintf("fixture %d", n),
		Author:    fxSig(n),
		Committer: fxSig(n),
	}
	if _, err := repo.CommitProposal(ctx, branch, writes, meta); err != nil {
		t.Fatalf("CommitProposal(%q): %v", branch, err)
	}
	return branch
}

// archiveOf commits files into a fresh space and builds the archive of the
// result — the whole path from git objects to Archive.
//
// The read half is spelled out here rather than hidden behind a helper in this
// package, because this package no longer has one: service/ owns the one route
// from a revision to an Archive, and a convenience wrapper here would be a
// second one growing back.
func archiveOf(t *testing.T, files map[string]string) *Archive {
	t.Helper()
	repo := space(t)
	rev := commit(t, repo, 1, repo.ApprovedBranch(), files)
	return archiveAt(t, repo, rev)
}

// archiveAt reads one revision and builds its archive.
func archiveAt(t *testing.T, repo *gitx.Repo, rev string) *Archive {
	t.Helper()
	docs, err := repo.ListDocuments(context.Background(), rev)
	if err != nil {
		t.Fatalf("ListDocuments(%q): %v", rev, err)
	}
	return FromDocuments(fxSpace, rev, docs)
}

// mustPage looks a document up by path, failing the test when it is absent.
func mustPage(t *testing.T, a *Archive, path string) *Page {
	t.Helper()
	p, ok := a.ByPath(path)
	if !ok {
		var have []string
		for _, p := range a.Pages {
			have = append(have, p.Path)
		}
		t.Fatalf("document %q missing; archive holds %v", path, have)
	}
	return p
}