1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
12 "golang.org/x/text/internal/testtext"
13 "golang.org/x/text/transform"
16 func foldRune(r rune) (folded rune, ok bool) {
17 alt, ok := mapRunes[r]
18 if ok && alt.e&tagNeedsFold != 0 {
24 func widenRune(r rune) (wide rune, ok bool) {
25 alt, ok := mapRunes[r]
26 if k := alt.e.kind(); k == EastAsianHalfwidth || k == EastAsianNarrow {
32 func narrowRune(r rune) (narrow rune, ok bool) {
33 alt, ok := mapRunes[r]
34 if k := alt.e.kind(); k == EastAsianFullwidth || k == EastAsianWide || k == EastAsianAmbiguous {
40 func TestFoldSingleRunes(t *testing.T) {
41 for r := rune(0); r < 0x1FFFF; r++ {
42 if loSurrogate <= r && r <= hiSurrogate {
47 got := Fold.String(string(r))
49 t.Errorf("Fold().String(%U) = %+q; want %+q", r, got, want)
54 type transformTest struct {
67 func (tc *transformTest) doTest(t *testing.T, tr Transformer) {
68 testtext.Run(t, tc.desc, func(t *testing.T) {
69 b := make([]byte, tc.nBuf)
70 nDst, nSrc, err := tr.Transform(b, []byte(tc.src), tc.atEOF)
71 if got := string(b[:nDst]); got != tc.dst[:nDst] {
72 t.Errorf("dst was %+q; want %+q", got, tc.dst)
75 t.Errorf("nDst was %d; want %d", nDst, tc.nDst)
78 t.Errorf("nSrc was %d; want %d", nSrc, tc.nSrc)
81 t.Errorf("error was %v; want %v", err, tc.err)
83 if got := tr.String(tc.src); got != tc.dst {
84 t.Errorf("String(%q) = %q; want %q", tc.src, got, tc.dst)
86 n, err := tr.Span([]byte(tc.src), tc.atEOF)
87 if n != tc.nSpan || err != tc.errSpan {
88 t.Errorf("Span: got %d, %v; want %d, %v", n, err, tc.nSpan, tc.errSpan)
93 func TestFold(t *testing.T) {
94 for _, tc := range []transformTest{{
106 desc: "short source 1",
113 err: transform.ErrShortSrc,
115 errSpan: transform.ErrShortSrc,
117 desc: "short source 2",
124 err: transform.ErrShortSrc,
126 errSpan: transform.ErrShortSrc,
128 desc: "incomplete but terminated source 1",
139 desc: "incomplete but terminated source 2",
150 desc: "exact fit dst",
159 errSpan: transform.ErrEndOfSpan,
161 desc: "exact fit dst and src ascii",
179 err: transform.ErrShortDst,
183 desc: "empty dst ascii",
190 err: transform.ErrShortDst,
201 err: transform.ErrShortDst,
203 errSpan: transform.ErrEndOfSpan,
212 err: transform.ErrShortDst,
216 desc: "short dst fast path",
223 err: transform.ErrShortDst,
227 desc: "short dst larger buffer",
228 src: "\uff21" + strings.Repeat("0", 127) + "B",
230 dst: "A" + strings.Repeat("0", 127) + "B",
234 err: transform.ErrShortDst,
236 errSpan: transform.ErrEndOfSpan,
238 desc: "fast path alternation",
253 func TestWidenSingleRunes(t *testing.T) {
254 for r := rune(0); r < 0x1FFFF; r++ {
255 if loSurrogate <= r && r <= hiSurrogate {
258 alt, _ := widenRune(r)
260 got := Widen.String(string(r))
262 t.Errorf("Widen().String(%U) = %+q; want %+q", r, got, want)
267 func TestWiden(t *testing.T) {
268 for _, tc := range []transformTest{{
280 desc: "short source 1",
287 err: transform.ErrShortSrc,
289 errSpan: transform.ErrEndOfSpan,
291 desc: "short source 2",
298 err: transform.ErrShortSrc,
300 errSpan: transform.ErrEndOfSpan,
302 desc: "incomplete but terminated source 1",
311 errSpan: transform.ErrEndOfSpan,
313 desc: "incomplete but terminated source 2",
322 errSpan: transform.ErrEndOfSpan,
324 desc: "short source 1 some span",
331 err: transform.ErrShortSrc,
333 errSpan: transform.ErrShortSrc,
335 desc: "short source 2 some span",
342 err: transform.ErrShortSrc,
344 errSpan: transform.ErrShortSrc,
346 desc: "incomplete but terminated source 1 some span",
357 desc: "incomplete but terminated source 2 some span",
368 desc: "exact fit dst",
377 errSpan: transform.ErrEndOfSpan,
386 err: transform.ErrShortDst,
390 desc: "empty dst ascii",
397 err: transform.ErrShortDst,
399 errSpan: transform.ErrEndOfSpan,
408 err: transform.ErrShortDst,
410 errSpan: transform.ErrEndOfSpan,
419 err: transform.ErrShortDst,
423 desc: "short dst ascii",
426 dst: "ascii", // U+ff41, ...
430 err: transform.ErrShortDst,
432 errSpan: transform.ErrEndOfSpan,
443 errSpan: transform.ErrEndOfSpan,
449 func TestNarrowSingleRunes(t *testing.T) {
450 for r := rune(0); r < 0x1FFFF; r++ {
451 if loSurrogate <= r && r <= hiSurrogate {
454 alt, _ := narrowRune(r)
456 got := Narrow.String(string(r))
458 t.Errorf("Narrow().String(%U) = %+q; want %+q", r, got, want)
463 func TestNarrow(t *testing.T) {
464 for _, tc := range []transformTest{{
476 desc: "short source 1",
483 err: transform.ErrShortSrc,
485 errSpan: transform.ErrShortSrc,
487 desc: "short source 2",
494 err: transform.ErrShortSrc,
496 errSpan: transform.ErrEndOfSpan,
498 desc: "incomplete but terminated source 1",
507 errSpan: transform.ErrEndOfSpan,
509 desc: "incomplete but terminated source 2",
518 errSpan: transform.ErrEndOfSpan,
520 desc: "exact fit dst",
529 errSpan: transform.ErrEndOfSpan,
531 desc: "exact fit dst some span",
540 errSpan: transform.ErrEndOfSpan,
549 err: transform.ErrShortDst,
553 desc: "empty dst ascii",
560 err: transform.ErrShortDst,
571 err: transform.ErrShortDst,
573 errSpan: transform.ErrEndOfSpan,
582 err: transform.ErrShortDst,
586 // Create a narrow variant of ambiguous runes, if they exist.
596 errSpan: transform.ErrEndOfSpan,
598 desc: "short dst fast path",
605 err: transform.ErrShortDst,
609 desc: "short dst larger buffer",
610 src: "\uff21" + strings.Repeat("0", 127) + "B",
612 dst: "A" + strings.Repeat("0", 127) + "B",
616 err: transform.ErrShortDst,
618 errSpan: transform.ErrEndOfSpan,
620 desc: "fast path alternation",
635 func bench(b *testing.B, t Transformer, s string) {
636 dst := make([]byte, 1024)
638 b.SetBytes(int64(len(src)))
640 for i := 0; i < b.N; i++ {
641 t.Transform(dst, src, true)
645 func changingRunes(f func(r rune) (rune, bool)) string {
646 buf := &bytes.Buffer{}
647 for r := rune(0); r <= 0xFFFF; r++ {
648 if _, ok := foldRune(r); ok {
655 func BenchmarkFoldASCII(b *testing.B) {
656 bench(b, Fold, testtext.ASCII)
659 func BenchmarkFoldCJK(b *testing.B) {
660 bench(b, Fold, testtext.CJK)
663 func BenchmarkFoldNonCanonical(b *testing.B) {
664 bench(b, Fold, changingRunes(foldRune))
667 func BenchmarkFoldOther(b *testing.B) {
668 bench(b, Fold, testtext.TwoByteUTF8+testtext.ThreeByteUTF8)
671 func BenchmarkWideASCII(b *testing.B) {
672 bench(b, Widen, testtext.ASCII)
675 func BenchmarkWideCJK(b *testing.B) {
676 bench(b, Widen, testtext.CJK)
679 func BenchmarkWideNonCanonical(b *testing.B) {
680 bench(b, Widen, changingRunes(widenRune))
683 func BenchmarkWideOther(b *testing.B) {
684 bench(b, Widen, testtext.TwoByteUTF8+testtext.ThreeByteUTF8)
687 func BenchmarkNarrowASCII(b *testing.B) {
688 bench(b, Narrow, testtext.ASCII)
691 func BenchmarkNarrowCJK(b *testing.B) {
692 bench(b, Narrow, testtext.CJK)
695 func BenchmarkNarrowNonCanonical(b *testing.B) {
696 bench(b, Narrow, changingRunes(narrowRune))
699 func BenchmarkNarrowOther(b *testing.B) {
700 bench(b, Narrow, testtext.TwoByteUTF8+testtext.ThreeByteUTF8)