8 "github.com/stretchr/testify/require"
11 func TestViewMergesInTheOrderOfTheRollbackPush(t *testing.T) {
12 tree := ViewBuiltTree{}
16 var states *ViewPushEntry
18 for tick := range 20001 {
19 states = viewPush(tick, states)
20 starts := states.starts()
21 view.high = len(starts)
22 view.low = len(starts)
23 _, err := view.Append(tree)
24 require.NoError(t, err)
26 lines := make([]int, len(view.lines))
27 for n, line := range view.lines {
28 lines[n] = line.index << line.level
31 require.Equal(t, starts, lines, "t=%d", tick)
35 func TestViewMergesInOneBatchFromHighToLow(t *testing.T) {
36 tree := ViewBuiltTree{}
38 view := newView(10, 5)
39 sizes := make([]int, 0, 20)
41 _, err := view.Append(tree)
42 require.NoError(t, err)
44 sizes = append(sizes, view.Size())
47 require.Equal(t, []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 5, 6, 7, 8, 9, 10, 5, 6, 7, 8}, sizes)
50 func TestViewMergesOnlyBuiltParents(t *testing.T) {
52 sizes: map[NodeKey]int{
64 _, err := view.Append(tree)
65 require.NoError(t, err)
68 require.Equal(t, []NodeKey{{0, 0}, {0, 1}, {0, 2}, {0, 3}}, view.lines)
69 require.True(t, view.merging)
71 tree.sizes[NodeKey{1, 0}] = 1
72 _, err := view.Append(tree)
73 require.NoError(t, err)
74 require.Equal(t, []NodeKey{{1, 0}, {0, 2}, {0, 3}, {0, 4}}, view.lines)
75 require.True(t, view.merging)
77 tree.sizes[NodeKey{1, 1}] = 1
78 tree.sizes[NodeKey{1, 2}] = 1
79 tree.sizes[NodeKey{2, 0}] = 1
80 _, err = view.Append(tree)
81 require.NoError(t, err)
82 require.Equal(t, []NodeKey{{2, 0}, {1, 2}}, view.lines)
83 require.False(t, view.merging)
86 func TestViewRendersPendingLinesWithoutTheirMessage(t *testing.T) {
88 sizes: map[NodeKey]int{
95 view, err := restoreView(ViewState{
96 Lines: [][2]int{{1, 0}, {0, 2}},
97 }, viewChatHigh, viewChatLow, tree)
98 require.NoError(t, err)
99 require.Equal(t, "<chat>\n0+2|aaa aaa\n2+1|"+viewPending+"\n</chat>", view.Render())
100 require.Equal(t, 7+len(viewPending), view.Size())
103 func TestViewCoarsenTakesTheCoarserLines(t *testing.T) {
104 view, err := restoreView(ViewState{
105 Lines: [][2]int{{1, 0}, {0, 2}, {0, 3}, {0, 4}, {0, 5}},
106 }, 100, 100, ViewBuiltTree{})
107 require.NoError(t, err)
109 other, err := restoreView(ViewState{
110 Lines: [][2]int{{0, 0}, {0, 1}, {1, 1}, {0, 4}, {0, 5}},
111 }, 100, 100, ViewBuiltTree{})
112 require.NoError(t, err)
114 require.NoError(t, view.Coarsen(other, ViewBuiltTree{}))
115 require.Equal(t, []NodeKey{{1, 0}, {1, 1}, {0, 4}, {0, 5}}, view.lines)
118 require.NoError(t, view.Coarsen(other, ViewBuiltTree{}))
119 require.Equal(t, []NodeKey{{2, 0}, {1, 2}}, view.lines)
120 require.False(t, view.merging)
123 func TestViewContextStopsAtTheFirstPendingLine(t *testing.T) {
124 tree := ViewPartTree{
125 sizes: map[NodeKey]int{
133 view, err := restoreView(ViewState{
134 Lines: [][2]int{{1, 0}, {0, 2}, {0, 3}},
136 require.NoError(t, err)
137 require.Equal(t, "<chat>\n</chat>", view.Context(0))
138 require.Equal(t, "<chat>\n0+2|a\n</chat>", view.Context(2))
139 require.Equal(t, "<chat>\n0+2|a\n</chat>", view.Context(3))
142 func TestRestoreViewRejectsAGap(t *testing.T) {
143 _, err := restoreView(ViewState{
144 Lines: [][2]int{{0, 0}, {0, 2}},
145 }, viewChatHigh, viewChatLow, ViewBuiltTree{})
146 require.ErrorContains(t, err, "does not start at message 1")
149 // ViewBuiltTree is a tree with each node built, with 1 byte of text.
150 type ViewBuiltTree struct{}
152 func (v ViewBuiltTree) Built(_, _ int) (bool, error) {
156 func (ViewBuiltTree) Node(level, index int) (Node, bool, error) {
157 return treeTestNode(level, index, "a"), true, nil
160 // ViewPushEntry is one entry of the rollback state list of the reference
161 // design, newest first. Under push alone, life stays 0, so the entry leaves it
163 type ViewPushEntry struct {
169 // starts returns the states of the list, oldest first.
170 func (e *ViewPushEntry) starts() []int {
173 for entry := e; entry != nil; entry = entry.older {
174 starts = append(starts, entry.state)
177 slices.Reverse(starts)
182 // ViewPartTree is a tree with the built nodes of its sizes.
183 type ViewPartTree struct {
184 sizes map[NodeKey]int
187 func (p ViewPartTree) Built(level, index int) (bool, error) {
188 _, built := p.sizes[NodeKey{level, index}]
192 func (p ViewPartTree) Node(level, index int) (Node, bool, error) {
193 size, built := p.sizes[NodeKey{level, index}]
195 return Node{}, false, nil
198 text := strings.Repeat("a", size)
203 return treeTestNode(level, index, text), true, nil
206 // viewPush adds state to the newest end of states and returns the new list. An
207 // empty list gets one entry. When the newest entry is not kept, it becomes kept
208 // with its own state, and state is dropped. When it is kept, state becomes a
209 // new newest entry, and the state of the old newest entry goes to the older
210 // entries by the same push.
211 func viewPush(state int, states *ViewPushEntry) *ViewPushEntry {
213 return &ViewPushEntry{
219 return &ViewPushEntry{
226 return &ViewPushEntry{
228 older: viewPush(states.state, states.older),