1package vt
2
3import (
4 "testing"
5
6 renderer "github.com/bnema/vev-vt/core"
7 "github.com/stretchr/testify/require"
8)
9
10func TestHistoryConfigurationUsesOnlyApplicationLimits(t *testing.T) {
11 for _, tt := range []struct {
12 name string
13 config HistoryConfig
14 valid bool
15 }{
16 {"disabled", HistoryConfig{}, true},
17 {"both explicit", HistoryConfig{MaxRows: 20, MaxBytes: 4096}, true},
18 {"bytes only", HistoryConfig{MaxBytes: 1024}, true},
19 {"rows only", HistoryConfig{MaxRows: 4}, true},
20 {"negative rows", HistoryConfig{MaxRows: -1}, false},
21 {"negative grouping", HistoryConfig{ChunkRows: -1}, false},
22 {"oversized grouping", HistoryConfig{ChunkRows: 257}, false},
23 } {
24 t.Run(tt.name, func(t *testing.T) {
25 if tt.valid {
26 require.NoError(t, tt.config.Validate())
27 return
28 }
29 require.ErrorIs(t, tt.config.Validate(), ErrInvalidHistoryConfig)
30 require.Panics(t, func() { NewHistory(tt.config) })
31 _, err := HistoryFromBlobs(tt.config, nil, nil)
32 require.ErrorIs(t, err, ErrInvalidHistoryConfig)
33 })
34 }
35 require.Zero(t, NewHistory(HistoryConfig{MaxRows: 4}).ByteCap(), "library must not supply a byte policy")
36 disabled := NewHistory(HistoryConfig{})
37 require.NoError(t, disabled.Append(historyRow("ignored"), LineBound{End: 7}))
38 require.Zero(t, disabled.Len())
39}
40
41func TestHistoryByteOnlyLimit(t *testing.T) {
42 const budget = 2*(renderer.StoredCellLogicalBytes+renderer.RowDescriptorLogicalBytes) + renderer.StyleRecordLogicalBytes
43 h := NewHistory(HistoryConfig{MaxBytes: budget})
44 for _, text := range []string{"a", "b", "c"} {
45 require.NoError(t, h.Append(historyRow(text), LineBound{End: 1}))
46 }
47 require.Zero(t, h.Cap(), "no independent line ceiling")
48 require.Equal(t, budget, h.ByteCap())
49 require.Equal(t, []string{"b", "c"}, historyViewTexts(h.View()))
50 require.Equal(t, budget, h.LogicalBytes())
51 require.Zero(t, h.Limits().MaxRows)
52}
53
54func TestHistoryLimitsReloadIsValidatedAndPreservesViews(t *testing.T) {
55 h := NewHistory(HistoryConfig{MaxRows: 8, MaxBytes: 1 << 20, ChunkRows: 8})
56 for _, text := range []string{"a", "b", "c", "d"} {
57 require.NoError(t, h.Append(historyRow(text), LineBound{End: 1}))
58 }
59 view := h.View()
60 before := h.Limits()
61 require.ErrorIs(t, h.SetLimits(HistoryConfig{MaxRows: -1}), ErrInvalidHistoryConfig)
62 require.Equal(t, before, h.Limits())
63 require.Equal(t, 4, h.Len())
64 require.NoError(t, h.SetLimits(HistoryConfig{MaxRows: 2, MaxBytes: 1 << 20, ChunkRows: 1}))
65 require.Equal(t, []string{"c", "d"}, historyViewTexts(h.View()))
66 require.Equal(t, []string{"a", "b", "c", "d"}, historyViewTexts(view))
67 next := h.NextRowID()
68 require.NoError(t, h.SetLimits(HistoryConfig{}))
69 require.Zero(t, h.Len())
70 require.Zero(t, h.LogicalBytes())
71 require.Equal(t, next, h.NextRowID())
72 require.NoError(t, h.SetLimits(HistoryConfig{MaxBytes: 4096}))
73 require.NoError(t, h.Append(historyRow("new"), LineBound{End: 3}))
74 require.Equal(t, next, h.View().RowID(0))
75}