1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-07-30 03:23:08 +03:00

Add a mechanism to insert non-model items into list contexts

Not used by anything yet.
This commit is contained in:
Stefan Haller
2023-08-08 12:46:04 +02:00
parent 4ee4f6f34b
commit 3df01aaff0
6 changed files with 325 additions and 25 deletions

View File

@ -1,6 +1,7 @@
package context
import (
"fmt"
"strings"
"testing"
@ -10,11 +11,12 @@ import (
func TestListRenderer_renderLines(t *testing.T) {
scenarios := []struct {
name string
modelStrings []string
startIdx int
endIdx int
expectedOutput string
name string
modelStrings []string
nonModelIndices []int
startIdx int
endIdx int
expectedOutput string
}{
{
name: "Render whole list",
@ -52,16 +54,79 @@ func TestListRenderer_renderLines(t *testing.T) {
expectedOutput: `
c`,
},
{
name: "Whole list with section headers",
modelStrings: []string{"a", "b", "c"},
nonModelIndices: []int{1, 3},
startIdx: 0,
endIdx: 5,
expectedOutput: `
a
--- 1 (0) ---
b
c
--- 3 (1) ---`,
},
{
name: "Multiple consecutive headers",
modelStrings: []string{"a", "b", "c"},
nonModelIndices: []int{0, 0, 2, 2, 2},
startIdx: 0,
endIdx: 8,
expectedOutput: `
--- 0 (0) ---
--- 0 (1) ---
a
b
--- 2 (2) ---
--- 2 (3) ---
--- 2 (4) ---
c`,
},
{
name: "Partial list with headers, beginning",
modelStrings: []string{"a", "b", "c"},
nonModelIndices: []int{1, 3},
startIdx: 0,
endIdx: 3,
expectedOutput: `
a
--- 1 (0) ---
b`,
},
{
name: "Partial list with headers, end (beyond end index)",
modelStrings: []string{"a", "b", "c"},
nonModelIndices: []int{1, 3},
startIdx: 2,
endIdx: 7,
expectedOutput: `
b
c
--- 3 (1) ---`,
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
viewModel := NewListViewModel[string](func() []string { return s.modelStrings })
var getNonModelItems func() []*NonModelItem
if s.nonModelIndices != nil {
getNonModelItems = func() []*NonModelItem {
return lo.Map(s.nonModelIndices, func(modelIndex int, nonModelIndex int) *NonModelItem {
return &NonModelItem{
Index: modelIndex,
Content: fmt.Sprintf("--- %d (%d) ---", modelIndex, nonModelIndex),
}
})
}
}
self := &ListRenderer{
list: viewModel,
getDisplayStrings: func(startIdx int, endIdx int) [][]string {
return lo.Map(s.modelStrings[startIdx:endIdx],
func(s string, _ int) []string { return []string{s} })
},
getNonModelItems: getNonModelItems,
}
expectedOutput := strings.Join(lo.Map(
@ -72,3 +137,120 @@ func TestListRenderer_renderLines(t *testing.T) {
})
}
}
func TestListRenderer_ModelIndexToViewIndex_and_back(t *testing.T) {
scenarios := []struct {
name string
numModelItems int
nonModelIndices []int
modelIndices []int
expectedViewIndices []int
viewIndices []int
expectedModelIndices []int
}{
{
name: "no headers (no getNonModelItems provided)",
numModelItems: 3,
nonModelIndices: nil, // no get
modelIndices: []int{-1, 0, 1, 2, 3, 4},
expectedViewIndices: []int{0, 0, 1, 2, 3, 3},
viewIndices: []int{-1, 0, 1, 2, 3, 4},
expectedModelIndices: []int{0, 0, 1, 2, 3, 3},
},
{
name: "no headers (getNonModelItems returns zero items)",
numModelItems: 3,
nonModelIndices: []int{},
modelIndices: []int{-1, 0, 1, 2, 3, 4},
expectedViewIndices: []int{0, 0, 1, 2, 3, 3},
viewIndices: []int{-1, 0, 1, 2, 3, 4},
expectedModelIndices: []int{0, 0, 1, 2, 3, 3},
},
{
name: "basic",
numModelItems: 3,
nonModelIndices: []int{1, 2},
/*
0: model 0
1: --- header 0 ---
2: model 1
3: --- header 1 ---
4: model 2
*/
modelIndices: []int{-1, 0, 1, 2, 3, 4},
expectedViewIndices: []int{0, 0, 2, 4, 5, 5},
viewIndices: []int{-1, 0, 1, 2, 3, 4, 5, 6},
expectedModelIndices: []int{0, 0, 1, 1, 2, 2, 3, 3},
},
{
name: "consecutive section headers",
numModelItems: 3,
nonModelIndices: []int{0, 0, 2, 2, 2, 3, 3},
/*
0: --- header 0 ---
1: --- header 1 ---
2: model 0
3: model 1
4: --- header 2 ---
5: --- header 3 ---
6: --- header 4 ---
7: model 2
8: --- header 5 ---
9: --- header 6 ---
*/
modelIndices: []int{-1, 0, 1, 2, 3, 4},
expectedViewIndices: []int{2, 2, 3, 7, 10, 10},
viewIndices: []int{-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
expectedModelIndices: []int{0, 0, 0, 0, 1, 2, 2, 2, 2, 3, 3, 3, 3},
},
}
for _, s := range scenarios {
t.Run(s.name, func(t *testing.T) {
// Expect lists of equal length for each test:
assert.Equal(t, len(s.modelIndices), len(s.expectedViewIndices))
assert.Equal(t, len(s.viewIndices), len(s.expectedModelIndices))
modelInts := lo.Range(s.numModelItems)
viewModel := NewListViewModel[int](func() []int { return modelInts })
var getNonModelItems func() []*NonModelItem
if s.nonModelIndices != nil {
getNonModelItems = func() []*NonModelItem {
return lo.Map(s.nonModelIndices, func(modelIndex int, _ int) *NonModelItem {
return &NonModelItem{Index: modelIndex, Content: ""}
})
}
}
self := &ListRenderer{
list: viewModel,
getDisplayStrings: func(startIdx int, endIdx int) [][]string {
return lo.Map(modelInts[startIdx:endIdx],
func(i int, _ int) []string { return []string{fmt.Sprint(i)} })
},
getNonModelItems: getNonModelItems,
}
// Need to render first so that it knows the non-model items
self.renderLines(-1, -1)
for i := 0; i < len(s.modelIndices); i++ {
assert.Equal(t, s.expectedViewIndices[i], self.ModelIndexToViewIndex(s.modelIndices[i]))
}
for i := 0; i < len(s.viewIndices); i++ {
assert.Equal(t, s.expectedModelIndices[i], self.ViewIndexToModelIndex(s.viewIndices[i]))
}
})
}
}