version_bump_test.go

 1package completions
 2
 3import (
 4	"testing"
 5
 6	"charm.land/lipgloss/v2"
 7	"github.com/sahilm/fuzzy"
 8	"github.com/stretchr/testify/require"
 9)
10
11// TestCompletionItem_MutatorsBumpVersion covers F6 ยง4.5 for the
12// completions popup: SetMatch and SetFocused must bump Version()
13// when the observable state changes, and dedupe (no bump) when the
14// supplied value is identical to the current state. Without
15// dedupe, the steady completions popup would invalidate the
16// list-level memo on every keystroke that produced the same match.
17func TestCompletionItem_MutatorsBumpVersion(t *testing.T) {
18	t.Parallel()
19
20	mkItem := func() *CompletionItem {
21		return NewCompletionItem(
22			"internal/ui/chat/user.go",
23			FileCompletionValue{Path: "internal/ui/chat/user.go"},
24			lipgloss.NewStyle(),
25			lipgloss.NewStyle(),
26			lipgloss.NewStyle(),
27		)
28	}
29
30	t.Run("SetFocused", func(t *testing.T) {
31		t.Parallel()
32		item := mkItem()
33
34		// First transition (false -> true) must bump.
35		before := item.Version()
36		item.SetFocused(true)
37		require.Greater(t, item.Version(), before, "SetFocused(true) must bump")
38
39		// Re-applying the same focus state must not bump.
40		stable := item.Version()
41		item.SetFocused(true)
42		require.Equal(t, stable, item.Version(), "SetFocused with same value must not bump")
43
44		// Transition back must bump.
45		item.SetFocused(false)
46		require.Greater(t, item.Version(), stable, "SetFocused(false) must bump")
47	})
48
49	t.Run("SetMatch", func(t *testing.T) {
50		t.Parallel()
51		item := mkItem()
52
53		match := fuzzy.Match{
54			Str:            "user",
55			Index:          0,
56			Score:          5,
57			MatchedIndexes: []int{0, 1, 2, 3},
58		}
59		before := item.Version()
60		item.SetMatch(match)
61		require.Greater(t, item.Version(), before, "SetMatch with new value must bump")
62
63		// Re-applying an equivalent match (same fields, equal slice
64		// contents) must not bump.
65		stable := item.Version()
66		same := fuzzy.Match{
67			Str:            "user",
68			Index:          0,
69			Score:          5,
70			MatchedIndexes: []int{0, 1, 2, 3},
71		}
72		item.SetMatch(same)
73		require.Equal(t, stable, item.Version(), "SetMatch with equivalent value must not bump")
74
75		// A different match (different MatchedIndexes) must bump.
76		different := fuzzy.Match{
77			Str:            "user",
78			Index:          0,
79			Score:          5,
80			MatchedIndexes: []int{0, 2},
81		}
82		item.SetMatch(different)
83		require.Greater(t, item.Version(), stable, "SetMatch with different indexes must bump")
84	})
85}