test(vt): table-drive the live line-bounds test
- commit
- a6ee2149c92861e04e8a39be67a0332b83e22439
- author
- brice · · 2026-07-25 11:05 UTC
- parent
- 24c95ef
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +38 -19
M pkg/vt/screen_write_test.go +38 -19
| @@ -4,6 +4,7 @@ import ( | |||
| 4 | 4 | "testing" | |
| 5 | 5 | ||
| 6 | 6 | "github.com/bnema/vev/pkg/renderer" | |
| 7 | + | "github.com/stretchr/testify/require" | |
| 7 | 8 | ) | |
| 8 | 9 | ||
| 9 | 10 | func TestWritePrintableAndUTF8(t *testing.T) { | |
| @@ -924,26 +925,44 @@ func TestC1Controls(t *testing.T) { | |||
| 924 | 925 | } | |
| 925 | 926 | ||
| 926 | 927 | func TestScreenLineBoundsDescribesTheLiveGrid(t *testing.T) { | |
| 927 | - | s := NewScreen(4, 3) | |
| 928 | - | s.Write([]byte("abcdef")) // wraps after column 4 | |
| 929 | - | ||
| 930 | - | bounds := s.LineBounds() | |
| 931 | - | if len(bounds) != 3 { | |
| 932 | - | t.Fatalf("len(LineBounds()) = %d, want 3", len(bounds)) | |
| 933 | - | } | |
| 934 | - | if !bounds[0].Soft { | |
| 935 | - | t.Errorf("bounds[0].Soft = false, want true (row wrapped)") | |
| 936 | - | } | |
| 937 | - | if bounds[1].Soft { | |
| 938 | - | t.Errorf("bounds[1].Soft = true, want false (row did not wrap)") | |
| 939 | - | } | |
| 940 | - | if bounds[1].End != 2 { | |
| 941 | - | t.Errorf("bounds[1].End = %d, want 2", bounds[1].End) | |
| 928 | + | tests := []struct { | |
| 929 | + | name string | |
| 930 | + | width int | |
| 931 | + | height int | |
| 932 | + | write string | |
| 933 | + | want []LineBound | |
| 934 | + | // checkOwned exercises the caller-owned-copy guarantee: it only makes | |
| 935 | + | // sense to check once per LineBounds() call, so it lives on the case | |
| 936 | + | // whose write actually produces a soft-wrapped row 0 to corrupt. | |
| 937 | + | checkOwned bool | |
| 938 | + | }{ | |
| 939 | + | { | |
| 940 | + | name: "wraps after column width", | |
| 941 | + | width: 4, | |
| 942 | + | height: 3, | |
| 943 | + | write: "abcdef", // wraps after column 4 | |
| 944 | + | want: []LineBound{ | |
| 945 | + | {End: 4, Soft: true}, // row 0: filled the row and wrapped | |
| 946 | + | {End: 2, Soft: false}, // row 1: "ef", no wrap | |
| 947 | + | {End: 0, Soft: false}, // row 2: untouched | |
| 948 | + | }, | |
| 949 | + | checkOwned: true, | |
| 950 | + | }, | |
| 942 | 951 | } | |
| 943 | 952 | ||
| 944 | - | // The result is owned by the caller. | |
| 945 | - | bounds[0] = LineBound{} | |
| 946 | - | if !s.LineBounds()[0].Soft { | |
| 947 | - | t.Error("mutating the result changed the screen's own boundaries") | |
| 953 | + | for _, tt := range tests { | |
| 954 | + | t.Run(tt.name, func(t *testing.T) { | |
| 955 | + | s := NewScreen(tt.width, tt.height) | |
| 956 | + | s.Write([]byte(tt.write)) | |
| 957 | + | ||
| 958 | + | bounds := s.LineBounds() | |
| 959 | + | require.Equal(t, tt.want, bounds) | |
| 960 | + | ||
| 961 | + | if tt.checkOwned { | |
| 962 | + | // The result is owned by the caller. | |
| 963 | + | bounds[0] = LineBound{} | |
| 964 | + | require.True(t, s.LineBounds()[0].Soft, "mutating the result changed the screen's own boundaries") | |
| 965 | + | } | |
| 966 | + | }) | |
| 948 | 967 | } | |
| 949 | 968 | } | |
| @@ -4,6 +4,7 @@ import ( | |||||
| 4 | "testing" | 4 | "testing" | ||
| 5 | 5 | ||||
| 6 | "github.com/bnema/vev/pkg/renderer" | 6 | "github.com/bnema/vev/pkg/renderer" | ||
| 7 | + | "github.com/stretchr/testify/require" | |||
| 7 | ) | 8 | ) | ||
| 8 | 9 | ||||
| 9 | func TestWritePrintableAndUTF8(t *testing.T) { | 10 | func TestWritePrintableAndUTF8(t *testing.T) { | ||
| @@ -924,26 +925,44 @@ func TestC1Controls(t *testing.T) { | |||||
| 924 | } | 925 | } | ||
| 925 | 926 | ||||
| 926 | func TestScreenLineBoundsDescribesTheLiveGrid(t *testing.T) { | 927 | func TestScreenLineBoundsDescribesTheLiveGrid(t *testing.T) { | ||
| 927 | - | s := NewScreen(4, 3) | 928 | + | tests := []struct { |
| 928 | - | s.Write([]byte("abcdef")) // wraps after column 4 | 929 | + | name string |
| 929 | - | 930 | + | width int | |
| 930 | - | bounds := s.LineBounds() | 931 | + | height int |
| 931 | - | if len(bounds) != 3 { | 932 | + | write string |
| 932 | - | t.Fatalf("len(LineBounds()) = %d, want 3", len(bounds)) | 933 | + | want []LineBound |
| 933 | - | } | 934 | + | // checkOwned exercises the caller-owned-copy guarantee: it only makes |
| 934 | - | if !bounds[0].Soft { | 935 | + | // sense to check once per LineBounds() call, so it lives on the case |
| 935 | - | t.Errorf("bounds[0].Soft = false, want true (row wrapped)") | 936 | + | // whose write actually produces a soft-wrapped row 0 to corrupt. |
| 936 | - | } | 937 | + | checkOwned bool |
| 937 | - | if bounds[1].Soft { | 938 | + | }{ |
| 938 | - | t.Errorf("bounds[1].Soft = true, want false (row did not wrap)") | 939 | + | { |
| 939 | - | } | 940 | + | name: "wraps after column width", |
| 940 | - | if bounds[1].End != 2 { | 941 | + | width: 4, |
| 941 | - | t.Errorf("bounds[1].End = %d, want 2", bounds[1].End) | 942 | + | height: 3, |
| 943 | + | write: "abcdef", // wraps after column 4 | |||
| 944 | + | want: []LineBound{ | |||
| 945 | + | {End: 4, Soft: true}, // row 0: filled the row and wrapped | |||
| 946 | + | {End: 2, Soft: false}, // row 1: "ef", no wrap | |||
| 947 | + | {End: 0, Soft: false}, // row 2: untouched | |||
| 948 | + | }, | |||
| 949 | + | checkOwned: true, | |||
| 950 | + | }, | |||
| 942 | } | 951 | } | ||
| 943 | 952 | ||||
| 944 | - | // The result is owned by the caller. | 953 | + | for _, tt := range tests { |
| 945 | - | bounds[0] = LineBound{} | 954 | + | t.Run(tt.name, func(t *testing.T) { |
| 946 | - | if !s.LineBounds()[0].Soft { | 955 | + | s := NewScreen(tt.width, tt.height) |
| 947 | - | t.Error("mutating the result changed the screen's own boundaries") | 956 | + | s.Write([]byte(tt.write)) |
| 957 | + | ||||
| 958 | + | bounds := s.LineBounds() | |||
| 959 | + | require.Equal(t, tt.want, bounds) | |||
| 960 | + | ||||
| 961 | + | if tt.checkOwned { | |||
| 962 | + | // The result is owned by the caller. | |||
| 963 | + | bounds[0] = LineBound{} | |||
| 964 | + | require.True(t, s.LineBounds()[0].Soft, "mutating the result changed the screen's own boundaries") | |||
| 965 | + | } | |||
| 966 | + | }) | |||
| 948 | } | 967 | } | ||
| 949 | } | 968 | } | ||