package index
import (
"strings"
"testing"
"craftdesign.group/quarry/internal/artifact"
)
// There is no verb that reports a tracker's schema: `zit ticket` takes
// field=value pairs and asks no questions. What the tickets CARRY is
// the schema as far as anything outside the store can know, and it has
// the right failure mode — a field nobody ever set is a field no form
// needs to offer.
func TestTheFieldNamesAreWhatTheTicketsCarry(t *testing.T) {
ix := openIndex(t)
tkt := func(n byte, fields ...artifact.Field) Parsed {
id := strings.Repeat(string([]byte{'a', n}), 20)
return Parsed{Hash: strings.Repeat(string([]byte{'c', n}), 20),
Art: &artifact.Artifact{Type: artifact.Ticket, TicketID: id,
Date: "2026-08-15T10:00:00", User: "dan", Fields: fields}}
}
if err := ix.FoldNow([]Parsed{
tkt('1', artifact.Field{Name: "title", Value: "one"},
artifact.Field{Name: "status", Value: "Open"},
artifact.Field{Name: "assignee", Value: "dan"}),
tkt('2', artifact.Field{Name: "title", Value: "two"},
artifact.Field{Name: "status", Value: "Open"},
artifact.Field{Name: "assignee", Value: "lou"}),
tkt('3', artifact.Field{Name: "title", Value: "three"},
artifact.Field{Name: "status", Value: "Open"},
artifact.Field{Name: "assigne", Value: "typo"}),
}); err != nil {
t.Fatal(err)
}
uses, err := ix.TicketFieldNames()
if err != nil {
t.Fatal(err)
}
count := map[string]int{}
for _, u := range uses {
count[u.Name] = u.Tickets
}
if count["assignee"] != 2 {
t.Errorf("FAIL: assignee on %d tickets, want 2 (%+v)", count["assignee"], uses)
}
// Counted so a caller can tell a column from a typo: one ticket with
// "assigne" is not a field the tracker defines.
if count["assigne"] != 1 {
t.Errorf("FAIL: the typo field counted %d, want 1", count["assigne"])
}
// Most-used first, so a form offers the real columns before the
// accidents.
if len(uses) == 0 || uses[0].Tickets < uses[len(uses)-1].Tickets {
t.Errorf("FAIL: not ordered most-used first: %+v", uses)
}
}
// A field set to nothing is not a field the tracker uses. Counting
// cleared values would keep a column alive forever after the last
// ticket dropped it.
func TestAClearedFieldIsNotCounted(t *testing.T) {
ix := openIndex(t)
id := strings.Repeat("b1", 20)
if err := ix.FoldNow([]Parsed{{Hash: strings.Repeat("c1", 20),
Art: &artifact.Artifact{Type: artifact.Ticket, TicketID: id,
Date: "2026-08-15T10:00:00", User: "dan", Fields: []artifact.Field{
{Name: "title", Value: "t"}, {Name: "status", Value: "Open"},
{Name: "assignee", Value: ""}}}}}); err != nil {
t.Fatal(err)
}
uses, err := ix.TicketFieldNames()
if err != nil {
t.Fatal(err)
}
for _, u := range uses {
if u.Name == "assignee" {
t.Errorf("FAIL: a cleared field is counted as used: %+v", u)
}
}
}