Get basic full string width tests running

This commit is contained in:
Kovid Goyal 2025-04-11 10:45:39 +05:30
parent cf6bb29ef7
commit 3a4d32b85b
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
4 changed files with 137 additions and 11 deletions

View file

@ -2,10 +2,23 @@ package kitty
import (
_ "embed"
"encoding/json"
"fmt"
)
var _ = fmt.Print
//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
}

View file

@ -1,12 +1,130 @@
package cli
import (
"bytes"
"fmt"
"strconv"
"strings"
"github.com/google/go-cmp/cmp"
"kitty"
"kitty/tools/tui/loop"
"kitty/tools/utils"
"kitty/tools/wcswidth"
)
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) {
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
}

View file

@ -138,7 +138,7 @@ func KeyEventFromCSI(csi string) *KeyEvent {
}
orig_csi := csi
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
}
csi = csi[:len(csi)-1]

View file

@ -1,12 +1,12 @@
package wcswidth
import (
"encoding/json"
"fmt"
"strings"
"testing"
_ "embed"
"github.com/google/go-cmp/cmp"
"kitty"
@ -14,11 +14,6 @@ import (
var _ = fmt.Print
type GraphemeBreakTest struct {
Data []string `json:"data"`
Comment string `json:"comment"`
}
func TestSplitIntoGraphemes(t *testing.T) {
var m = map[string][]string{
" \u0308 ": {" \u0308", " "},
@ -29,9 +24,9 @@ func TestSplitIntoGraphemes(t *testing.T) {
t.Fatalf("Failed to split %#v into graphemes: %s", text, diff)
}
}
tests := []GraphemeBreakTest{}
if err := json.Unmarshal(kitty.GraphemeBreakTestData, &tests); err != nil {
t.Fatalf("Failed to parse GraphemeBreakTest JSON with error: %s", err)
tests, err := kitty.LoadGraphemeBreakTests()
if err != nil {
t.Fatal(err)
}
for i, x := range tests {
text := strings.Join(x.Data, "")