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 }