2023-01-11 12:14:07 +03:00
|
|
|
|
package twin
|
|
|
|
|
|
|
|
|
|
import (
|
2023-01-11 12:44:24 +03:00
|
|
|
|
"strings"
|
2023-01-11 12:14:07 +03:00
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
|
|
"gotest.tools/v3/assert"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func assertEncode(t *testing.T, incomingString string, expectedEvent Event, expectedRemainder string) {
|
2023-01-11 13:06:38 +03:00
|
|
|
|
actualEvent, actualRemainder := consumeEncodedEvent(incomingString)
|
|
|
|
|
|
2023-01-11 12:44:24 +03:00
|
|
|
|
message := strings.Replace(incomingString, "\x1b", "ESC", -1)
|
|
|
|
|
message = strings.Replace(message, "\r", "RET", -1)
|
|
|
|
|
|
2023-01-11 13:06:38 +03:00
|
|
|
|
assert.Assert(t, actualEvent != nil,
|
|
|
|
|
"Input: %s Result: %#v Expected: %#v", message, "nil", expectedEvent)
|
2023-01-11 12:44:24 +03:00
|
|
|
|
assert.Equal(t, *actualEvent, expectedEvent,
|
|
|
|
|
"Input: %s Result: %#v Expected: %#v", message, *actualEvent, expectedEvent)
|
|
|
|
|
assert.Equal(t, actualRemainder, expectedRemainder, message)
|
2023-01-11 12:14:07 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestConsumeEncodedEvent(t *testing.T) {
|
|
|
|
|
assertEncode(t, "a", EventRune{rune: 'a'}, "")
|
2023-01-11 12:44:24 +03:00
|
|
|
|
assertEncode(t, "\r", EventKeyCode{keyCode: KeyEnter}, "")
|
|
|
|
|
assertEncode(t, "\x1b", EventKeyCode{keyCode: KeyEscape}, "")
|
|
|
|
|
|
|
|
|
|
// Implicitly test having a remaining rune at the end
|
|
|
|
|
assertEncode(t, "\x1b[Ax", EventKeyCode{keyCode: KeyUp}, "x")
|
|
|
|
|
|
|
|
|
|
assertEncode(t, "\x1b[<64;127;41M", EventMouse{buttons: MouseWheelUp}, "")
|
|
|
|
|
assertEncode(t, "\x1b[<65;127;41M", EventMouse{buttons: MouseWheelDown}, "")
|
2023-01-11 13:06:38 +03:00
|
|
|
|
|
|
|
|
|
// This happens when users paste.
|
|
|
|
|
//
|
|
|
|
|
// Ref: https://github.com/walles/moar/issues/73
|
|
|
|
|
assertEncode(t, "1234", EventRune{rune: '1'}, "234")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestConsumeEncodedEventWithUnsupportedEscapeCode(t *testing.T) {
|
|
|
|
|
event, remainder := consumeEncodedEvent("\x1bXXXXX")
|
|
|
|
|
assert.Assert(t, event == nil)
|
|
|
|
|
assert.Equal(t, remainder, "")
|
2023-01-11 12:14:07 +03:00
|
|
|
|
}
|
2023-01-11 13:08:38 +03:00
|
|
|
|
|
|
|
|
|
func TestConsumeEncodedEventWithNoInput(t *testing.T) {
|
|
|
|
|
event, remainder := consumeEncodedEvent("")
|
|
|
|
|
assert.Assert(t, event == nil)
|
|
|
|
|
assert.Equal(t, remainder, "")
|
|
|
|
|
}
|
2023-03-24 00:42:40 +03:00
|
|
|
|
|
|
|
|
|
func TestRenderLine(t *testing.T) {
|
|
|
|
|
row := []Cell{
|
|
|
|
|
{
|
|
|
|
|
Rune: '<',
|
|
|
|
|
Style: StyleDefault.WithAttr(AttrReverse),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Rune: 'f',
|
|
|
|
|
Style: StyleDefault.WithAttr(AttrDim),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rendered, count := renderLine(row)
|
|
|
|
|
assert.Equal(t, count, 2)
|
|
|
|
|
reset := "[m"
|
|
|
|
|
reversed := "[7m"
|
|
|
|
|
notReversed := "[27m"
|
|
|
|
|
dim := "[2m"
|
|
|
|
|
clearToEol := "[K"
|
|
|
|
|
assert.Equal(t,
|
|
|
|
|
strings.ReplaceAll(rendered, "", "ESC"),
|
2023-10-09 20:45:27 +03:00
|
|
|
|
strings.ReplaceAll(reset+reversed+"<"+dim+notReversed+"f"+reset+clearToEol, "", "ESC"))
|
2023-03-24 00:42:40 +03:00
|
|
|
|
}
|
2023-10-08 13:00:07 +03:00
|
|
|
|
|
2023-10-10 21:46:53 +03:00
|
|
|
|
func TestRenderLineEmpty(t *testing.T) {
|
|
|
|
|
row := []Cell{}
|
|
|
|
|
|
|
|
|
|
rendered, count := renderLine(row)
|
|
|
|
|
assert.Equal(t, count, 0)
|
|
|
|
|
assert.Equal(t, rendered, "")
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-08 13:00:07 +03:00
|
|
|
|
func TestRenderLineLastReversed(t *testing.T) {
|
|
|
|
|
row := []Cell{
|
|
|
|
|
{
|
|
|
|
|
Rune: '<',
|
|
|
|
|
Style: StyleDefault.WithAttr(AttrReverse),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rendered, count := renderLine(row)
|
|
|
|
|
assert.Equal(t, count, 1)
|
|
|
|
|
reset := "[m"
|
|
|
|
|
reversed := "[7m"
|
|
|
|
|
clearToEol := "[K"
|
|
|
|
|
assert.Equal(t,
|
|
|
|
|
strings.ReplaceAll(rendered, "", "ESC"),
|
|
|
|
|
strings.ReplaceAll(reset+reversed+"<"+reset+clearToEol, "", "ESC"))
|
|
|
|
|
}
|
2023-10-10 07:01:49 +03:00
|
|
|
|
|
2023-10-10 22:33:18 +03:00
|
|
|
|
func TestRenderLineLastNonSpace(t *testing.T) {
|
|
|
|
|
row := []Cell{
|
|
|
|
|
{
|
|
|
|
|
Rune: 'X',
|
|
|
|
|
Style: StyleDefault,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rendered, count := renderLine(row)
|
|
|
|
|
assert.Equal(t, count, 1)
|
|
|
|
|
reset := "[m"
|
|
|
|
|
clearToEol := "[K"
|
|
|
|
|
assert.Equal(t,
|
|
|
|
|
strings.ReplaceAll(rendered, "", "ESC"),
|
|
|
|
|
strings.ReplaceAll(reset+"X"+clearToEol, "", "ESC"))
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-10 07:18:03 +03:00
|
|
|
|
func TestRenderLineLastReversedPlusTrailingSpace(t *testing.T) {
|
2023-10-10 07:01:49 +03:00
|
|
|
|
row := []Cell{
|
|
|
|
|
{
|
|
|
|
|
Rune: '<',
|
|
|
|
|
Style: StyleDefault.WithAttr(AttrReverse),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Rune: ' ',
|
|
|
|
|
Style: StyleDefault,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rendered, count := renderLine(row)
|
|
|
|
|
assert.Equal(t, count, 1)
|
|
|
|
|
reset := "[m"
|
|
|
|
|
reversed := "[7m"
|
|
|
|
|
clearToEol := "[K"
|
|
|
|
|
assert.Equal(t,
|
|
|
|
|
strings.ReplaceAll(rendered, "", "ESC"),
|
|
|
|
|
strings.ReplaceAll(reset+reversed+"<"+reset+clearToEol, "", "ESC"))
|
|
|
|
|
}
|
2023-10-10 07:18:03 +03:00
|
|
|
|
|
2023-10-10 22:26:43 +03:00
|
|
|
|
func TestRenderLineOnlyTrailingSpaces(t *testing.T) {
|
|
|
|
|
row := []Cell{
|
|
|
|
|
{
|
|
|
|
|
Rune: ' ',
|
|
|
|
|
Style: StyleDefault,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Rune: ' ',
|
|
|
|
|
Style: StyleDefault,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rendered, count := renderLine(row)
|
|
|
|
|
assert.Equal(t, count, 0)
|
|
|
|
|
assert.Equal(t, rendered, "")
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-10 07:18:03 +03:00
|
|
|
|
func TestRenderLineLastReversedSpaces(t *testing.T) {
|
|
|
|
|
row := []Cell{
|
|
|
|
|
{
|
|
|
|
|
Rune: ' ',
|
|
|
|
|
Style: StyleDefault.WithAttr(AttrReverse),
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rendered, count := renderLine(row)
|
|
|
|
|
assert.Equal(t, count, 1)
|
|
|
|
|
reset := "[m"
|
|
|
|
|
reversed := "[7m"
|
|
|
|
|
clearToEol := "[K"
|
|
|
|
|
assert.Equal(t,
|
|
|
|
|
strings.ReplaceAll(rendered, "", "ESC"),
|
|
|
|
|
strings.ReplaceAll(reset+reversed+" "+reset+clearToEol, "", "ESC"))
|
|
|
|
|
}
|
2023-10-10 22:38:03 +03:00
|
|
|
|
|
|
|
|
|
func TestRenderLineNonPrintable(t *testing.T) {
|
|
|
|
|
row := []Cell{
|
|
|
|
|
{
|
|
|
|
|
Rune: '',
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rendered, count := renderLine(row)
|
|
|
|
|
assert.Equal(t, count, 1)
|
|
|
|
|
reset := "[m"
|
|
|
|
|
white := "[37m"
|
|
|
|
|
redBg := "[41m"
|
|
|
|
|
bold := "[1m"
|
|
|
|
|
clearToEol := "[K"
|
|
|
|
|
assert.Equal(t,
|
|
|
|
|
strings.ReplaceAll(rendered, "", "ESC"),
|
|
|
|
|
strings.ReplaceAll(reset+white+redBg+bold+"?"+reset+clearToEol, "", "ESC"))
|
|
|
|
|
}
|