1package daemon
2
3import (
4 "context"
5 "io"
6 "log/slog"
7 "testing"
8
9 "github.com/stretchr/testify/require"
10
11 "github.com/bnema/vev/internal/domain"
12 "github.com/bnema/vev/internal/domain/layout"
13 "github.com/bnema/vev/internal/protocol"
14)
15
16func TestNilPTYLifecyclePathsDoNotPanic(t *testing.T) {
17 d := New(nil, nil, slog.New(slog.NewTextHandler(io.Discard, nil)))
18 ctx, cancel := context.WithCancel(context.Background())
19 defer cancel()
20 sess := &session{sessionCore: sessionCore{id: "s", name: "s"}, ctx: ctx, cancel: cancel}
21 d.sessions[sess.id] = sess
22 first := newTab(nil, domain.Size{Cols: 41, Rows: 10})
23 second := newTab(nil, domain.Size{Cols: 41, Rows: 10})
24 sess.tabs = []*tab{first, second}
25
26 first.mu.Lock()
27 first.size = domain.Size{Cols: 20, Rows: 5}
28 first.bumpLayoutGenerationLocked()
29 first.mu.Unlock()
30 require.NotPanics(t, func() {
31 sess.geometry.applyTabLayout(d, sess, first)
32 })
33 require.Equal(t, 20, first.focusedPane().screen.Columns())
34 require.Equal(t, 5, first.focusedPane().screen.Rows())
35
36 first.tree = &layout.Tree{Root: &layout.Node{Kind: layout.Split, Dir: layout.Horizontal, Children: []*layout.Node{layout.NewLeaf("pane-1"), layout.NewLeaf("pane-2")}}, Focus: "pane-2"}
37 first.panes["pane-2"] = newPane("pane-2", nil, domain.Size{Cols: 20, Rows: 10})
38 require.NotPanics(t, func() {
39 require.NoError(t, d.closePane(sess, first, "pane-2", nil, false))
40 })
41 require.NotContains(t, first.panes, layout.PaneID("pane-2"))
42
43 require.NotPanics(t, func() { require.NoError(t, d.closeTab(sess, second, false)) })
44 require.Len(t, sess.tabs, 1)
45}
46
47func TestKillSessionIgnoresNilPanePTYs(t *testing.T) {
48 d := New(nil, nil, slog.New(slog.NewTextHandler(io.Discard, nil)))
49 ctx, cancel := context.WithCancel(context.Background())
50 sess := &session{sessionCore: sessionCore{id: "s", name: "s", ephemeral: true}, ctx: ctx, cancel: cancel, tabs: []*tab{newTab(nil, domain.Size{Cols: 10, Rows: 3})}}
51 d.sessions[sess.id] = sess
52
53 require.NotPanics(t, func() {
54 require.NoError(t, d.killSession(sess, protocol.ReasonSessionKilled, true))
55 })
56 require.NotContains(t, d.sessions, sess.id)
57}
58
59func TestNilPTYInputPathsDoNotPanic(t *testing.T) {
60 d := New(nil, nil, slog.New(slog.NewTextHandler(io.Discard, nil)))
61 ctx, cancel := context.WithCancel(context.Background())
62 defer cancel()
63 tb := newTab(nil, domain.Size{Cols: 10, Rows: 3})
64 sess := &session{sessionCore: sessionCore{id: "s", name: "s"}, ctx: ctx, cancel: cancel, tabs: []*tab{tb}}
65 ac := &attachedClient{}
66 ac.initOverlays()
67 ac.setSession(sess)
68
69 require.NotPanics(t, func() { d.writeToPane(sess, tb.focusedPane(), []byte("x")) })
70 require.NotPanics(t, func() { daemonKeyHandler{d: d, ac: ac}.Forward([]byte("x")) })
71}