1package protocol
2
3import (
4 "testing"
5 "time"
6
7 renderer "github.com/bnema/vev-vt"
8 "github.com/stretchr/testify/require"
9
10 "github.com/bnema/vev/internal/domain"
11)
12
13func previewTestRequest() RemotePreviewRequest {
14 return RemotePreviewRequest{
15 Version: RemotePreviewSchemaVersion,
16 Target: domain.RemoteSessionTarget{
17 Endpoint: "local", DisplayOrigin: "local", LifecycleID: domain.SessionLifecycleID{1}, SessionName: "work", LiveTabID: "tab-1",
18 },
19 Width: 80, Height: 24,
20 }
21}
22
23func TestValidateRemotePreviewWatch(t *testing.T) {
24 tests := []struct {
25 name string
26 mutate func(*RemotePreviewWatch)
27 wantErr bool
28 }{
29 {name: "valid"},
30 {name: "minimum interval", mutate: func(w *RemotePreviewWatch) { w.MinInterval = RemotePreviewWatchMinInterval }},
31 {name: "maximum interval", mutate: func(w *RemotePreviewWatch) { w.MinInterval = RemotePreviewWatchMaxInterval }},
32 {name: "zero interval", mutate: func(w *RemotePreviewWatch) { w.MinInterval = 0 }, wantErr: true},
33 {name: "interval below bound", mutate: func(w *RemotePreviewWatch) { w.MinInterval = 15 * time.Millisecond }, wantErr: true},
34 {name: "interval above bound", mutate: func(w *RemotePreviewWatch) { w.MinInterval = time.Second + time.Millisecond }, wantErr: true},
35 {name: "fractional millisecond", mutate: func(w *RemotePreviewWatch) { w.MinInterval = 33*time.Millisecond + 1 }, wantErr: true},
36 {name: "invalid request", mutate: func(w *RemotePreviewWatch) { w.Request.Width = 0 }, wantErr: true},
37 {name: "stopped target", mutate: func(w *RemotePreviewWatch) { w.Request.Target.Stopped = true }, wantErr: true},
38 }
39 for _, tt := range tests {
40 t.Run(tt.name, func(t *testing.T) {
41 watch := RemotePreviewWatch{Request: previewTestRequest(), MinInterval: 33 * time.Millisecond}
42 if tt.mutate != nil {
43 tt.mutate(&watch)
44 }
45 err := ValidateRemotePreviewWatch(watch)
46 if tt.wantErr {
47 require.ErrorIs(t, err, ErrInvalidRemotePreviewWatch)
48 return
49 }
50 require.NoError(t, err)
51 })
52 }
53}
54
55func TestValidateRemotePreviewCellRun(t *testing.T) {
56 valid := RemotePreview{
57 Version: RemotePreviewSchemaVersion, Status: RemotePreviewOK,
58 LifecycleID: domain.SessionLifecycleID{1}, TabID: "tab-1", Revision: 1,
59 Width: 2, Height: 1, Cells: []renderer.Cell{{Rune: 'x'}, {Rune: 'y'}},
60 }
61 tests := []struct {
62 name string
63 mutate func(*RemotePreview)
64 wantErr bool
65 }{
66 {name: "valid"},
67 {name: "double width continuation", mutate: func(p *RemotePreview) { p.Cells = []renderer.Cell{{Rune: '界'}, {Continuation: true}} }},
68 {name: "unknown status", mutate: func(p *RemotePreview) { p.Status = RemotePreviewTooLarge + 1 }, wantErr: true},
69 {name: "non-ok carries a viewport", mutate: func(p *RemotePreview) { p.Status = RemotePreviewNoSuchTarget }, wantErr: true},
70 {name: "cell count mismatch", mutate: func(p *RemotePreview) { p.Cells = p.Cells[:1] }, wantErr: true},
71 {name: "control rune", mutate: func(p *RemotePreview) { p.Cells = []renderer.Cell{{Rune: '\x1b'}, {Rune: 'x'}} }, wantErr: true},
72 {name: "orphan continuation", mutate: func(p *RemotePreview) { p.Cells = []renderer.Cell{{Continuation: true}, {Rune: 'x'}} }, wantErr: true},
73 {name: "unpaired double width", mutate: func(p *RemotePreview) { p.Cells = []renderer.Cell{{Rune: '界'}, {Rune: 'x'}} }, wantErr: true},
74 {name: "unsupported style", mutate: func(p *RemotePreview) {
75 p.Cells = []renderer.Cell{{Rune: 'x', Style: renderer.Style{Attrs: 1 << 7}}, {Rune: 'x'}}
76 }, wantErr: true},
77 }
78 for _, tt := range tests {
79 t.Run(tt.name, func(t *testing.T) {
80 preview := valid
81 preview.Cells = append([]renderer.Cell(nil), valid.Cells...)
82 if tt.mutate != nil {
83 tt.mutate(&preview)
84 }
85 require.Equal(t, tt.wantErr, ValidateRemotePreview(preview) != nil)
86 })
87 }
88}