package index
import (
"fmt"
"path/filepath"
"testing"
"time"
"craftdesign.group/quarry/internal/artifact"
)
// Behind walks ancestry, and ancestry on a real trunk is a ladder:
// branches keep merging trunk in, so every old check-in is reachable
// along many paths of many lengths. The walk must cost the number of
// ancestors, not the number of paths — a ladder a thousand rungs tall
// answers in milliseconds, and answers the same number a hand count
// gives.
func TestBehindCostsAncestorsNotPaths(t *testing.T) {
ix, err := Open(filepath.Join(t.TempDir(), "index.db"))
if err != nil {
t.Fatal(err)
}
defer ix.Close()
h := func(i int, side string) string { return fmt.Sprintf("%s%039d", side, i)[:40] }
when := func(i int) string {
return time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(i) * time.Minute).Format("2006-01-02T15:04:05")
}
feat := []artifact.Tag{{Name: "*branch", Target: "*", Value: "feat"}, {Name: "*sym-feat", Target: "*"}}
var batch []Parsed
ci := func(hash string, i int, parents []string, tags []artifact.Tag) {
batch = append(batch, Parsed{Hash: hash, Art: &artifact.Artifact{Type: artifact.Manifest,
Date: when(i), User: "dan", Comment: hash[:6], Parents: parents, Tags: tags}})
}
// Rung 0 on both rails, then each rung: trunk moves, and the branch
// merges that trunk check-in in.
const rungs = 1000
ci(h(0, "a"), 0, nil, nil)
ci(h(0, "b"), 1, []string{h(0, "a")}, feat)
for i := 1; i <= rungs; i++ {
ci(h(i, "a"), 2*i, []string{h(i-1, "a")}, nil)
ci(h(i, "b"), 2*i+1, []string{h(i-1, "b"), h(i, "a")}, feat)
}
// Three trunk check-ins the branch has not merged.
for i := 1; i <= 3; i++ {
ci(h(rungs+i, "a"), 2*rungs+10+i, []string{h(rungs+i-1, "a")}, nil)
}
if err := ix.FoldNow(batch); err != nil {
t.Fatal(err)
}
start := time.Now()
behind, err := ix.Behind("feat", "trunk")
if err != nil {
t.Fatal(err)
}
if behind != 3 {
t.Fatalf("behind = %d, want 3", behind)
}
if took := time.Since(start); took > 1500*time.Millisecond {
t.Fatalf("Behind took %v on a %d-rung ladder; the walk is counting paths", took, rungs)
}
}