// Copyright 2016 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. package precis import ( "fmt" "math/rand" "testing" "unicode" "golang.org/x/text/internal/testtext" "golang.org/x/text/transform" ) // copyOrbit is a Transformer for the sole purpose of testing the apply method, // testing that apply will always call Span for the prefix of the input that // remains identical and then call Transform for the remainder. It will produce // inconsistent output for other usage patterns. // Provided that copyOrbit is used this way, the first t bytes of the output // will be identical to the input and the remaining output will be the result // of calling caseOrbit on the remaining input bytes. type copyOrbit int func (t copyOrbit) Reset() {} func (t copyOrbit) Span(src []byte, atEOF bool) (n int, err error) { if int(t) == len(src) { return int(t), nil } return int(t), transform.ErrEndOfSpan } // Transform implements transform.Transformer specifically for testing the apply method. // See documentation of copyOrbit before using this method. func (t copyOrbit) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { n := copy(dst, src) for i, c := range dst[:n] { dst[i] = orbitCase(c) } return n, n, nil } func orbitCase(c byte) byte { if unicode.IsLower(rune(c)) { return byte(unicode.ToUpper(rune(c))) } else { return byte(unicode.ToLower(rune(c))) } } func TestBuffers(t *testing.T) { want := "Those who cannot remember the past are condemned to compute it." spans := rand.Perm(len(want) + 1) // Compute the result of applying copyOrbit(span) transforms in reverse. input := []byte(want) for i := len(spans) - 1; i >= 0; i-- { for j := spans[i]; j < len(input); j++ { input[j] = orbitCase(input[j]) } } // Apply the copyOrbit(span) transforms. b := buffers{src: input} for _, n := range spans { b.apply(copyOrbit(n)) if n%11 == 0 { b.apply(transform.Nop) } } if got := string(b.src); got != want { t.Errorf("got %q; want %q", got, want) } } type compareTestCase struct { a string b string result bool } var compareTestCases = []struct { name string p *Profile cases []compareTestCase }{ {"Nickname", Nickname, []compareTestCase{ {"a", "b", false}, {" Swan of Avon ", "swan of avon", true}, {"Foo", "foo", true}, {"foo", "foo", true}, {"Foo Bar", "foo bar", true}, {"foo bar", "foo bar", true}, {"\u03A3", "\u03C3", true}, {"\u03A3", "\u03C2", false}, {"\u03C3", "\u03C2", false}, {"Richard \u2163", "richard iv", true}, {"Å", "å", true}, {"ff", "ff", true}, // because of NFKC {"ß", "sS", false}, // After applying the Nickname profile, \u00a8 becomes \u0020\u0308, // however because the nickname profile is not idempotent, applying it again // to \u0020\u0308 results in \u0308. This behavior is "correct", even if it // is unexpected. {"\u00a8", "\u0020\u0308", false}, {"\u0020\u0308", "\u0308", true}, }}, } func doCompareTests(t *testing.T, fn func(t *testing.T, p *Profile, tc compareTestCase)) { for _, g := range compareTestCases { for i, tc := range g.cases { name := fmt.Sprintf("%s:%d:%+q", g.name, i, tc.a) testtext.Run(t, name, func(t *testing.T) { fn(t, g.p, tc) }) } } } func TestCompare(t *testing.T) { doCompareTests(t, func(t *testing.T, p *Profile, tc compareTestCase) { if result := p.Compare(tc.a, tc.b); result != tc.result { t.Errorf("got %v; want %v", result, tc.result) } }) } func TestCompareString(t *testing.T) { doCompareTests(t, func(t *testing.T, p *Profile, tc compareTestCase) { a, err := p.CompareKey(tc.a) if err != nil { t.Errorf("Unexpected error when creating key: %v", err) return } b, err := p.CompareKey(tc.b) if err != nil { t.Errorf("Unexpected error when creating key: %v", err) return } if result := (a == b); result != tc.result { t.Errorf("got %v; want %v", result, tc.result) } }) }