// 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) } } }