Files
lerko 476abbed00 test(tui): add tier 1 unit tests for pure logic functions
Cover search filtering, intent matching, card affordances, checklist
parsing, template slot discovery/resolve, date grouping, and truncation.
2026-05-19 21:10:51 -04:00

132 lines
3.4 KiB
Go

package tui
import (
"testing"
"github.com/lerko/nib/internal/db"
)
func TestMatchesIntent(t *testing.T) {
snippet := db.CardSnippet
template := db.CardTemplate
checklist := db.CardChecklist
note := db.CardNote
link := db.CardLink
decision := db.CardDecision
tests := []struct {
name string
cardType *db.CardType
intent intent
want bool
}{
{"all matches nil", nil, intentAll, true},
{"all matches snippet", &snippet, intentAll, true},
{"all matches template", &template, intentAll, true},
{"grab matches nil", nil, intentGrab, true},
{"grab matches snippet", &snippet, intentGrab, true},
{"grab rejects template", &template, intentGrab, false},
{"grab rejects note", &note, intentGrab, false},
{"read matches note", &note, intentRead, true},
{"read matches link", &link, intentRead, true},
{"read matches decision", &decision, intentRead, true},
{"read rejects snippet", &snippet, intentRead, false},
{"read rejects nil", nil, intentRead, false},
{"fill matches template", &template, intentFill, true},
{"fill matches checklist", &checklist, intentFill, true},
{"fill rejects snippet", &snippet, intentFill, false},
{"fill rejects nil", nil, intentFill, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := &db.Entity{CardType: tt.cardType}
if got := matchesIntent(e, tt.intent); got != tt.want {
t.Fatalf("matchesIntent(%v, %v) = %v, want %v", tt.cardType, tt.intent, got, tt.want)
}
})
}
}
func TestDetectAffordance(t *testing.T) {
snippet := db.CardSnippet
template := db.CardTemplate
checklist := db.CardChecklist
decision := db.CardDecision
link := db.CardLink
note := db.CardNote
tests := []struct {
name string
cardType *db.CardType
want string
}{
{"nil", nil, ""},
{"snippet", &snippet, "code"},
{"template", &template, "fill"},
{"checklist", &checklist, "steps"},
{"decision", &decision, "decide"},
{"link", &link, "link"},
{"note", &note, ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
e := &db.Entity{CardType: tt.cardType}
if got := detectAffordance(e); got != tt.want {
t.Fatalf("detectAffordance(%v) = %q, want %q", tt.cardType, got, tt.want)
}
})
}
}
func TestIntentCycle(t *testing.T) {
order := []intent{intentAll, intentGrab, intentRead, intentFill, intentAll}
for i := 0; i < len(order)-1; i++ {
got := order[i].next()
if got != order[i+1] {
t.Fatalf("%v.next() = %v, want %v", order[i], got, order[i+1])
}
}
}
func TestApplyFilter_PinnedFirst(t *testing.T) {
snippet := db.CardSnippet
c := newCardsModel()
c.setEntities([]*db.Entity{
{ID: "1", Body: "a", CardType: &snippet},
{ID: "2", Body: "b", Pinned: true, CardType: &snippet},
{ID: "3", Body: "c", CardType: &snippet},
})
if len(c.filtered) != 3 {
t.Fatalf("expected 3 filtered, got %d", len(c.filtered))
}
if c.filtered[0].ID != "2" {
t.Fatalf("pinned entity should be first, got %s", c.filtered[0].ID)
}
}
func TestApplyFilter_CursorClamps(t *testing.T) {
snippet := db.CardSnippet
template := db.CardTemplate
c := newCardsModel()
c.setEntities([]*db.Entity{
{ID: "1", Body: "a", CardType: &snippet},
{ID: "2", Body: "b", CardType: &snippet},
{ID: "3", Body: "c", CardType: &template},
})
c.cursor = 2
c.setIntent(intentFill)
if len(c.filtered) != 1 {
t.Fatalf("expected 1 fill entity, got %d", len(c.filtered))
}
if c.cursor != 0 {
t.Fatalf("cursor should clamp to 0, got %d", c.cursor)
}
}