1package daemon
2
3import (
4 "testing"
5
6 "github.com/stretchr/testify/require"
7
8 renderer "github.com/bnema/vev-vt"
9 "github.com/bnema/vev/internal/domain"
10 scopy "github.com/bnema/vev/internal/usecase/copy"
11 "github.com/bnema/vev/internal/usecase/mouse"
12)
13
14func TestCopyMouseMapTopBarAndContent(t *testing.T) {
15 p := newPane("pane", nil, domain.Size{Cols: 5, Rows: 2})
16 doc := scopy.NewDocument(scopy.NewSnapshotFromRows([][]renderer.Cell{testRow("alpha"), testRow("bravo")}, 5, 2), domain.DefaultWordSeparators)
17 geometry := copyMouseGeometry{pane: p, content: domain.Rect{X: 0, Y: 1, Width: 5, Height: 2}}
18
19 _, ok := mapCopyMouse(mouse.Event{Col: 0, Row: 0}, geometry, 0, doc, false)
20 require.False(t, ok)
21 mapped, ok := mapCopyMouse(mouse.Event{Col: 0, Row: 1}, geometry, 0, doc, false)
22 require.True(t, ok)
23 require.Same(t, p, mapped.pane)
24 require.Equal(t, scopy.Pos{Row: 0, Col: 0}, mapped.pos)
25 mapped, ok = mapCopyMouse(mouse.Event{Col: 4, Row: 2}, geometry, 0, doc, false)
26 require.True(t, ok)
27 require.Equal(t, scopy.Pos{Row: 1, Col: 4}, mapped.pos)
28 _, ok = mapCopyMouse(mouse.Event{Col: 0, Row: 3}, geometry, 0, doc, false)
29 require.False(t, ok, "bottom status is not content")
30}
31
32func TestCopyMouseMapClampsAndNormalizesWideCells(t *testing.T) {
33 p := newPane("pane", nil, domain.Size{Cols: 4, Rows: 1})
34 doc := scopy.NewDocument(scopy.NewSnapshotFromRows([][]renderer.Cell{{{Rune: 'a'}, {Rune: '界'}, {Continuation: true}, {Rune: 'b'}}}, 4, 1), domain.DefaultWordSeparators)
35 geometry := copyMouseGeometry{pane: p, content: domain.Rect{X: 3, Y: 1, Width: 4, Height: 1}}
36
37 mapped, ok := mapCopyMouse(mouse.Event{Col: 5, Row: 1}, geometry, 0, doc, false)
38 require.True(t, ok)
39 require.Equal(t, scopy.Pos{Row: 0, Col: 1}, mapped.pos)
40 mapped, ok = mapCopyMouse(mouse.Event{Col: 99, Row: 99}, geometry, 0, doc, true)
41 require.True(t, ok)
42 require.Equal(t, scopy.Pos{Row: 0, Col: 3}, mapped.pos)
43}
44
45func TestCopyMouseMapSplitAndFloatingRects(t *testing.T) {
46 p := newPane("pane", nil, domain.Size{Cols: 4, Rows: 2})
47 doc := scopy.NewDocument(scopy.NewSnapshotFromRows([][]renderer.Cell{testRow("abcd"), testRow("efgh")}, 4, 2), domain.DefaultWordSeparators)
48 for _, tc := range []struct {
49 name string
50 geometry domain.Rect
51 ev mouse.Event
52 want scopy.Pos
53 ok bool
54 }{
55 {"split content", domain.Rect{X: 21, Y: 2, Width: 4, Height: 2}, mouse.Event{Col: 23, Row: 3}, scopy.Pos{Row: 1, Col: 2}, true},
56 {"split title", domain.Rect{X: 21, Y: 2, Width: 4, Height: 2}, mouse.Event{Col: 21, Row: 1}, scopy.Pos{}, false},
57 {"floating inner", domain.Rect{X: 10, Y: 5, Width: 4, Height: 2}, mouse.Event{Col: 11, Row: 5}, scopy.Pos{Row: 0, Col: 1}, true},
58 {"floating border", domain.Rect{X: 10, Y: 5, Width: 4, Height: 2}, mouse.Event{Col: 9, Row: 5}, scopy.Pos{}, false},
59 } {
60 t.Run(tc.name, func(t *testing.T) {
61 mapped, ok := mapCopyMouse(tc.ev, copyMouseGeometry{pane: p, content: tc.geometry}, 0, doc, false)
62 require.Equal(t, tc.ok, ok)
63 if ok {
64 require.Equal(t, tc.want, mapped.pos)
65 }
66 })
67 }
68}
69
70func TestCopyMouseGeometryUsesClientFrameExactlyOnce(t *testing.T) {
71 p, release := newBlockingPTY(t)
72 defer release()
73 d, sess, _, _ := newManualSessionWithPTYs(t, p)
74 tb := testAttachmentTab(sess)
75
76 tb.mu.Lock()
77 geometry, ok := hitTestCopyMouseGeometryLocked(tb, d.currentFloatingConfig(), 0, 1)
78 tb.mu.Unlock()
79 require.True(t, ok)
80 require.Equal(t, 1, geometry.content.Y)
81 _, ok = mapCopyMouse(mouse.Event{Col: 0, Row: 1}, geometry, 0,
82 scopy.NewDocument(scopy.NewSnapshotFromRows([][]renderer.Cell{testRow("a")}, 80, 1), domain.DefaultWordSeparators), false)
83 require.True(t, ok)
84}