Skip to content
quarry Artifact [281505f833]
Login

Artifact [281505f833]

Artifact 281505f833b25e64c28589725063bb138cf132106862770bac792ff31e1c4b63:


package api

import (
	"context"
	"path/filepath"
	"strings"
	"testing"

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

// forumStore folds n threads into a fresh index.
func forumStore(t *testing.T, n int) *Repo {
	t.Helper()
	ix, err := index.Open(filepath.Join(t.TempDir(), "i.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { ix.Close() })
	var batch []index.Parsed
	for i := 0; i < n; i++ {
		h := strings.Repeat("ab", 31) + string(rune('0'+i%10)) + string(rune('a'+i/10))
		batch = append(batch, index.Parsed{Hash: h, Art: &artifact.Artifact{
			Type: artifact.Forum, ThreadTitle: "thread", Date: "2026-09-01T10:00:00", User: "dan",
		}})
	}
	if len(batch) > 0 {
		if err := ix.FoldNow(batch); err != nil {
			t.Fatal(err)
		}
	}
	return &Repo{Index: ix}
}

// The forum tab must count what the forum PAGE shows. On zeitforge the
// badge read 4 — fossil's own legacy threads — beside a page listing
// 3,558 from the companion, and a number that disagrees with the page
// it labels is worse than no number at all.
func TestTheForumCountIncludesTheCompanion(t *testing.T) {
	parent, companion := forumStore(t, 2), forumStore(t, 5)
	d := Deps{
		Repos:      NewRepos(map[string]*Repo{"fossil": parent, "fossil-forum": companion}),
		Companions: &fakeCompanions{bound: map[string]string{"fossil": "fossil-forum"}},
	}
	if got := d.companionForumThreads(context.Background(), "fossil"); got != 5 {
		t.Errorf("FAIL: the companion contributed %d threads, want 5", got)
	}
	// An unbound repository contributes nothing from anywhere else.
	if got := d.companionForumThreads(context.Background(), "fossil-forum"); got != 0 {
		t.Errorf("FAIL: an unbound store borrowed %d threads", got)
	}
}

// A binding that names a store this node does not serve must not break
// the counts op — every repository page calls it, and one misconfigured
// binding would take out a nav that is otherwise fine. The forum page
// itself still says so properly, which is where it belongs.
func TestABrokenBindingDoesNotBreakTheCounts(t *testing.T) {
	d := Deps{
		Repos:      NewRepos(map[string]*Repo{"fossil": forumStore(t, 2)}),
		Companions: &fakeCompanions{bound: map[string]string{"fossil": "nowhere"}},
	}
	if got := d.companionForumThreads(context.Background(), "fossil"); got != 0 {
		t.Errorf("FAIL: a dangling binding counted %d", got)
	}
	// And the forum page still refuses in an operator's words.
	if _, err := d.forumRepoFor(context.Background(), "fossil"); err == nil {
		t.Error("FAIL: a dangling binding resolved to something")
	}
}

// A forge with no binding table at all behaves exactly as before.
func TestNoCompanionPlaneIsHarmless(t *testing.T) {
	d := Deps{Repos: NewRepos(map[string]*Repo{"fossil": forumStore(t, 2)})}
	if got := d.companionForumThreads(context.Background(), "fossil"); got != 0 {
		t.Errorf("FAIL: got %d with no companion plane", got)
	}
}