mirror of
https://github.com/genuinetools/reg.git
synced 2024-09-15 15:11:02 -04:00
163 lines
4.6 KiB
Go
163 lines
4.6 KiB
Go
|
// Copyright 2015 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 (
|
||
|
"bytes"
|
||
|
"fmt"
|
||
|
"reflect"
|
||
|
"testing"
|
||
|
|
||
|
"golang.org/x/text/internal/testtext"
|
||
|
"golang.org/x/text/transform"
|
||
|
)
|
||
|
|
||
|
type testCase struct {
|
||
|
input string
|
||
|
output string
|
||
|
err error
|
||
|
}
|
||
|
|
||
|
func doTests(t *testing.T, fn func(t *testing.T, p *Profile, tc testCase)) {
|
||
|
for _, g := range enforceTestCases {
|
||
|
for i, tc := range g.cases {
|
||
|
name := fmt.Sprintf("%s:%d:%+q", g.name, i, tc.input)
|
||
|
testtext.Run(t, name, func(t *testing.T) {
|
||
|
fn(t, g.p, tc)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestString(t *testing.T) {
|
||
|
doTests(t, func(t *testing.T, p *Profile, tc testCase) {
|
||
|
if e, err := p.String(tc.input); tc.err != err || e != tc.output {
|
||
|
t.Errorf("got %+q (err: %v); want %+q (err: %v)", e, err, tc.output, tc.err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestBytes(t *testing.T) {
|
||
|
doTests(t, func(t *testing.T, p *Profile, tc testCase) {
|
||
|
if e, err := p.Bytes([]byte(tc.input)); tc.err != err || string(e) != tc.output {
|
||
|
t.Errorf("got %+q (err: %v); want %+q (err: %v)", string(e), err, tc.output, tc.err)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
t.Run("Copy", func(t *testing.T) {
|
||
|
// Test that calling Bytes with something that doesn't transform returns a
|
||
|
// copy.
|
||
|
orig := []byte("hello")
|
||
|
b, _ := NewFreeform().Bytes(orig)
|
||
|
if reflect.ValueOf(b).Pointer() == reflect.ValueOf(orig).Pointer() {
|
||
|
t.Error("original and result are the same slice; should be a copy")
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestAppend(t *testing.T) {
|
||
|
doTests(t, func(t *testing.T, p *Profile, tc testCase) {
|
||
|
if e, err := p.Append(nil, []byte(tc.input)); tc.err != err || string(e) != tc.output {
|
||
|
t.Errorf("got %+q (err: %v); want %+q (err: %v)", string(e), err, tc.output, tc.err)
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestStringMallocs(t *testing.T) {
|
||
|
if n := testtext.AllocsPerRun(100, func() { UsernameCaseMapped.String("helloworld") }); n > 0 {
|
||
|
// TODO: reduce this to 0.
|
||
|
t.Skipf("got %f allocs, want 0", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestAppendMallocs(t *testing.T) {
|
||
|
str := []byte("helloworld")
|
||
|
out := make([]byte, 0, len(str))
|
||
|
if n := testtext.AllocsPerRun(100, func() { UsernameCaseMapped.Append(out, str) }); n > 0 {
|
||
|
t.Errorf("got %f allocs, want 0", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestTransformMallocs(t *testing.T) {
|
||
|
str := []byte("helloworld")
|
||
|
out := make([]byte, 0, len(str))
|
||
|
tr := UsernameCaseMapped.NewTransformer()
|
||
|
if n := testtext.AllocsPerRun(100, func() {
|
||
|
tr.Reset()
|
||
|
tr.Transform(out, str, true)
|
||
|
}); n > 0 {
|
||
|
t.Errorf("got %f allocs, want 0", n)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func min(a, b int) int {
|
||
|
if a < b {
|
||
|
return a
|
||
|
}
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
// TestTransformerShortBuffers tests that the precis.Transformer implements the
|
||
|
// spirit, not just the letter (the method signatures), of the
|
||
|
// transform.Transformer interface.
|
||
|
//
|
||
|
// In particular, it tests that, if one or both of the dst or src buffers are
|
||
|
// short, so that multiple Transform calls are required to complete the overall
|
||
|
// transformation, the end result is identical to one Transform call with
|
||
|
// sufficiently long buffers.
|
||
|
func TestTransformerShortBuffers(t *testing.T) {
|
||
|
srcUnit := []byte("a\u0300cce\u0301nts") // NFD normalization form.
|
||
|
wantUnit := []byte("àccénts") // NFC normalization form.
|
||
|
src := bytes.Repeat(srcUnit, 16)
|
||
|
want := bytes.Repeat(wantUnit, 16)
|
||
|
const long = 4096
|
||
|
dst := make([]byte, long)
|
||
|
|
||
|
// 5, 7, 9, 11, 13, 16 and 17 are all pair-wise co-prime, which means that
|
||
|
// slicing the dst and src buffers into 5, 7, 13 and 17 byte chunks will
|
||
|
// fall at different places inside the repeated srcUnit's and wantUnit's.
|
||
|
if len(srcUnit) != 11 || len(wantUnit) != 9 || len(src) > long || len(want) > long {
|
||
|
t.Fatal("inconsistent lengths")
|
||
|
}
|
||
|
|
||
|
tr := NewFreeform().NewTransformer()
|
||
|
for _, deltaD := range []int{5, 7, 13, 17, long} {
|
||
|
loop:
|
||
|
for _, deltaS := range []int{5, 7, 13, 17, long} {
|
||
|
tr.Reset()
|
||
|
d0 := 0
|
||
|
s0 := 0
|
||
|
for {
|
||
|
d1 := min(len(dst), d0+deltaD)
|
||
|
s1 := min(len(src), s0+deltaS)
|
||
|
nDst, nSrc, err := tr.Transform(dst[d0:d1:d1], src[s0:s1:s1], s1 == len(src))
|
||
|
d0 += nDst
|
||
|
s0 += nSrc
|
||
|
if err == nil {
|
||
|
break
|
||
|
}
|
||
|
if err == transform.ErrShortDst || err == transform.ErrShortSrc {
|
||
|
continue
|
||
|
}
|
||
|
t.Errorf("deltaD=%d, deltaS=%d: %v", deltaD, deltaS, err)
|
||
|
continue loop
|
||
|
}
|
||
|
if s0 != len(src) {
|
||
|
t.Errorf("deltaD=%d, deltaS=%d: s0: got %d, want %d", deltaD, deltaS, s0, len(src))
|
||
|
continue
|
||
|
}
|
||
|
if d0 != len(want) {
|
||
|
t.Errorf("deltaD=%d, deltaS=%d: d0: got %d, want %d", deltaD, deltaS, d0, len(want))
|
||
|
continue
|
||
|
}
|
||
|
got := dst[:d0]
|
||
|
if !bytes.Equal(got, want) {
|
||
|
t.Errorf("deltaD=%d, deltaS=%d:\ngot %q\nwant %q", deltaD, deltaS, got, want)
|
||
|
continue
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|