blob: a0bf1d1368e686efd6d8908ed54a3a24a274ce33 [file] [log] [blame] [edit]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build goexperiment.jsonv2
package jsonwire
import (
"cmp"
"slices"
"testing"
"unicode/utf16"
"unicode/utf8"
)
func TestQuoteRune(t *testing.T) {
tests := []struct{ in, want string }{
{"x", `'x'`},
{"\n", `'\n'`},
{"'", `'\''`},
{"\xff", `'\xff'`},
{"💩", `'💩'`},
{"💩"[:1], `'\xf0'`},
{"\uffff", `'\uffff'`},
{"\U00101234", `'\U00101234'`},
}
for _, tt := range tests {
got := QuoteRune([]byte(tt.in))
if got != tt.want {
t.Errorf("quoteRune(%q) = %s, want %s", tt.in, got, tt.want)
}
}
}
var compareUTF16Testdata = []string{"", "\r", "1", "f\xfe", "f\xfe\xff", "f\xff", "\u0080", "\u00f6", "\u20ac", "\U0001f600", "\ufb33"}
func TestCompareUTF16(t *testing.T) {
for i, si := range compareUTF16Testdata {
for j, sj := range compareUTF16Testdata {
got := CompareUTF16([]byte(si), []byte(sj))
want := cmp.Compare(i, j)
if got != want {
t.Errorf("CompareUTF16(%q, %q) = %v, want %v", si, sj, got, want)
}
}
}
}
func FuzzCompareUTF16(f *testing.F) {
for _, td1 := range compareUTF16Testdata {
for _, td2 := range compareUTF16Testdata {
f.Add([]byte(td1), []byte(td2))
}
}
// CompareUTF16Simple is identical to CompareUTF16,
// but relies on naively converting a string to a []uint16 codepoints.
// It is easy to verify as correct, but is slow.
CompareUTF16Simple := func(x, y []byte) int {
ux := utf16.Encode([]rune(string(x)))
uy := utf16.Encode([]rune(string(y)))
return slices.Compare(ux, uy)
}
f.Fuzz(func(t *testing.T, s1, s2 []byte) {
// Compare the optimized and simplified implementations.
got := CompareUTF16(s1, s2)
want := CompareUTF16Simple(s1, s2)
if got != want && utf8.Valid(s1) && utf8.Valid(s2) {
t.Errorf("CompareUTF16(%q, %q) = %v, want %v", s1, s2, got, want)
}
})
}
func TestTruncatePointer(t *testing.T) {
tests := []struct{ in, want string }{
{"hello", "hello"},
{"/a/b/c", "/a/b/c"},
{"/a/b/c/d/e/f/g", "/a/b/…/f/g"},
{"supercalifragilisticexpialidocious", "super…cious"},
{"/supercalifragilisticexpialidocious/supercalifragilisticexpialidocious", "/supe…/…cious"},
{"/supercalifragilisticexpialidocious/supercalifragilisticexpialidocious/supercalifragilisticexpialidocious", "/supe…/…/…cious"},
{"/a/supercalifragilisticexpialidocious/supercalifragilisticexpialidocious", "/a/…/…cious"},
{"/supercalifragilisticexpialidocious/supercalifragilisticexpialidocious/b", "/supe…/…/b"},
{"/fizz/buzz/bazz", "/fizz/…/bazz"},
{"/fizz/buzz/bazz/razz", "/fizz/…/razz"},
{"/////////////////////////////", "/////…/////"},
{"/🎄❤️✨/🎁✅😊/🎅🔥⭐", "/🎄…/…/…⭐"},
}
for _, tt := range tests {
got := TruncatePointer(tt.in, 10)
if got != tt.want {
t.Errorf("TruncatePointer(%q) = %q, want %q", tt.in, got, tt.want)
}
}
}