mirror of
https://github.com/kovidgoyal/kitty
synced 2026-07-19 23:14:55 +02:00
Get basic full string width tests running
This commit is contained in:
15
embeds.go
15
embeds.go
@@ -2,10 +2,23 @@ package kitty
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Print
|
var _ = fmt.Print
|
||||||
|
|
||||||
//go:embed kitty_tests/GraphemeBreakTest.json
|
//go:embed kitty_tests/GraphemeBreakTest.json
|
||||||
var GraphemeBreakTestData []byte
|
var grapheme_break_test_data []byte
|
||||||
|
|
||||||
|
type GraphemeBreakTest struct {
|
||||||
|
Data []string `json:"data"`
|
||||||
|
Comment string `json:"comment"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadGraphemeBreakTests() (ans []GraphemeBreakTest, err error) {
|
||||||
|
if err := json.Unmarshal(grapheme_break_test_data, &ans); err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to parse GraphemeBreakTest JSON with error: %s", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,130 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
|
"kitty"
|
||||||
|
"kitty/tools/tui/loop"
|
||||||
|
"kitty/tools/utils"
|
||||||
|
"kitty/tools/wcswidth"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Print
|
var _ = fmt.Print
|
||||||
|
|
||||||
|
type test_struct struct {
|
||||||
|
description string
|
||||||
|
expected_cursor_positions []int
|
||||||
|
actual_cursor_positions []int
|
||||||
|
payload string
|
||||||
|
}
|
||||||
|
|
||||||
|
const cursor_position_report = "\x1b[6n"
|
||||||
|
|
||||||
|
func run_tests(tests []*test_struct) (err error) {
|
||||||
|
lp, err := loop.New(loop.NoAlternateScreen)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buf := strings.Builder{}
|
||||||
|
buf.WriteString(loop.PENDING_UPDATE.EscapeCodeToSet())
|
||||||
|
for _, t := range tests {
|
||||||
|
buf.WriteString(t.payload)
|
||||||
|
buf.WriteString("\r\x1b[K")
|
||||||
|
if buf.Len() > 512*1024 {
|
||||||
|
buf.WriteString(loop.PENDING_UPDATE.EscapeCodeToReset())
|
||||||
|
buf.WriteString(loop.PENDING_UPDATE.EscapeCodeToSet())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buf.WriteString(loop.PENDING_UPDATE.EscapeCodeToReset())
|
||||||
|
buf.WriteString("\x1b[c")
|
||||||
|
|
||||||
|
lp.OnInitialize = func() (string, error) {
|
||||||
|
lp.SetCursorVisible(false)
|
||||||
|
lp.Printf("Running %d tests, please wait...\n", len(tests))
|
||||||
|
lp.QueueWriteString(buf.String())
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
lp.OnFinalize = func() string {
|
||||||
|
lp.SetCursorVisible(true)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
current_test_idx := 0
|
||||||
|
lp.OnEscapeCode = func(typ loop.EscapeCodeType, data []byte) error {
|
||||||
|
if typ == loop.CSI {
|
||||||
|
switch data[len(data)-1] {
|
||||||
|
case 'c':
|
||||||
|
lp.Quit(0)
|
||||||
|
case 'R':
|
||||||
|
if idx := bytes.IndexByte(data, ';'); idx > -1 {
|
||||||
|
if xpos, e := strconv.Atoi(utils.UnsafeBytesToString(data[idx+1 : len(data)-1])); e == nil {
|
||||||
|
t := tests[current_test_idx]
|
||||||
|
if len(t.actual_cursor_positions) >= len(t.expected_cursor_positions) && current_test_idx+1 < len(tests) {
|
||||||
|
current_test_idx += 1
|
||||||
|
t = tests[current_test_idx]
|
||||||
|
}
|
||||||
|
t.actual_cursor_positions = append(t.actual_cursor_positions, xpos-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err = lp.Run(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return show_results(tests)
|
||||||
|
}
|
||||||
|
|
||||||
|
func show_results(tests []*test_struct) (err error) {
|
||||||
|
num_failures := 0
|
||||||
|
for _, t := range tests {
|
||||||
|
if diff := cmp.Diff(t.expected_cursor_positions, t.actual_cursor_positions); diff != "" {
|
||||||
|
fmt.Println("\x1b[31mTest failed\x1b[39m:", t.description)
|
||||||
|
fmt.Println(diff)
|
||||||
|
num_failures++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if num_failures > 0 {
|
||||||
|
err = fmt.Errorf("%d out of %d tests failed.", num_failures, len(tests))
|
||||||
|
} else {
|
||||||
|
fmt.Printf("All %d tests passed!\n", len(tests))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func has_control_chars(text string) bool {
|
||||||
|
for _, ch := range text {
|
||||||
|
if ch < ' ' {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func main() (rc int, err error) {
|
func main() (rc int, err error) {
|
||||||
|
var tests []*test_struct
|
||||||
|
if gb_tests, err := kitty.LoadGraphemeBreakTests(); err == nil {
|
||||||
|
for i, t := range gb_tests {
|
||||||
|
desc := fmt.Sprintf("Unicode GraphemeBreakTest: #%d (%s)", i, t.Comment)
|
||||||
|
text := strings.Join(t.Data, "")
|
||||||
|
if has_control_chars(text) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
payload := " " + text + cursor_position_report
|
||||||
|
test := test_struct{description: desc, payload: payload, expected_cursor_positions: []int{1 + wcswidth.Stringwidth(text)}}
|
||||||
|
tests = append(tests, &test)
|
||||||
|
}
|
||||||
|
if err = run_tests(tests); err != nil {
|
||||||
|
return 1, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 1, err
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ func KeyEventFromCSI(csi string) *KeyEvent {
|
|||||||
}
|
}
|
||||||
orig_csi := csi
|
orig_csi := csi
|
||||||
last_char := csi[len(csi)-1:]
|
last_char := csi[len(csi)-1:]
|
||||||
if !strings.Contains("u~ABCDEHFPQRS", last_char) || (last_char == "~" && (csi == "200~" || csi == "201~")) {
|
if !strings.Contains("u~ABCDEHFPQS", last_char) || (last_char == "~" && (csi == "200~" || csi == "201~")) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
csi = csi[:len(csi)-1]
|
csi = csi[:len(csi)-1]
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package wcswidth
|
package wcswidth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
"kitty"
|
"kitty"
|
||||||
@@ -14,11 +14,6 @@ import (
|
|||||||
|
|
||||||
var _ = fmt.Print
|
var _ = fmt.Print
|
||||||
|
|
||||||
type GraphemeBreakTest struct {
|
|
||||||
Data []string `json:"data"`
|
|
||||||
Comment string `json:"comment"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSplitIntoGraphemes(t *testing.T) {
|
func TestSplitIntoGraphemes(t *testing.T) {
|
||||||
var m = map[string][]string{
|
var m = map[string][]string{
|
||||||
" \u0308 ": {" \u0308", " "},
|
" \u0308 ": {" \u0308", " "},
|
||||||
@@ -29,9 +24,9 @@ func TestSplitIntoGraphemes(t *testing.T) {
|
|||||||
t.Fatalf("Failed to split %#v into graphemes: %s", text, diff)
|
t.Fatalf("Failed to split %#v into graphemes: %s", text, diff)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tests := []GraphemeBreakTest{}
|
tests, err := kitty.LoadGraphemeBreakTests()
|
||||||
if err := json.Unmarshal(kitty.GraphemeBreakTestData, &tests); err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to parse GraphemeBreakTest JSON with error: %s", err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
for i, x := range tests {
|
for i, x := range tests {
|
||||||
text := strings.Join(x.Data, "")
|
text := strings.Join(x.Data, "")
|
||||||
|
|||||||
Reference in New Issue
Block a user