golang.org/x/text@v0.14.0/secure/precis/enforce_test.go (about) 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. 4 5 package precis 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 "testing" 12 13 "golang.org/x/text/internal/testtext" 14 "golang.org/x/text/transform" 15 ) 16 17 type testCase struct { 18 input string 19 output string 20 err error 21 } 22 23 func doTests(t *testing.T, fn func(t *testing.T, p *Profile, tc testCase)) { 24 for _, g := range enforceTestCases { 25 for i, tc := range g.cases { 26 name := fmt.Sprintf("%s:%d:%+q", g.name, i, tc.input) 27 testtext.Run(t, name, func(t *testing.T) { 28 fn(t, g.p, tc) 29 }) 30 } 31 } 32 } 33 34 func TestString(t *testing.T) { 35 doTests(t, func(t *testing.T, p *Profile, tc testCase) { 36 if e, err := p.String(tc.input); tc.err != err || e != tc.output { 37 t.Errorf("got %+q (err: %v); want %+q (err: %v)", e, err, tc.output, tc.err) 38 } 39 }) 40 } 41 42 func TestBytes(t *testing.T) { 43 doTests(t, func(t *testing.T, p *Profile, tc testCase) { 44 if e, err := p.Bytes([]byte(tc.input)); tc.err != err || string(e) != tc.output { 45 t.Errorf("got %+q (err: %v); want %+q (err: %v)", string(e), err, tc.output, tc.err) 46 } 47 }) 48 49 t.Run("Copy", func(t *testing.T) { 50 // Test that calling Bytes with something that doesn't transform returns a 51 // copy. 52 orig := []byte("hello") 53 b, _ := NewFreeform().Bytes(orig) 54 if reflect.ValueOf(b).Pointer() == reflect.ValueOf(orig).Pointer() { 55 t.Error("original and result are the same slice; should be a copy") 56 } 57 }) 58 } 59 60 func TestAppend(t *testing.T) { 61 doTests(t, func(t *testing.T, p *Profile, tc testCase) { 62 if e, err := p.Append(nil, []byte(tc.input)); tc.err != err || string(e) != tc.output { 63 t.Errorf("got %+q (err: %v); want %+q (err: %v)", string(e), err, tc.output, tc.err) 64 } 65 }) 66 } 67 68 func TestStringMallocs(t *testing.T) { 69 if n := testtext.AllocsPerRun(100, func() { UsernameCaseMapped.String("helloworld") }); n > 0 { 70 // TODO: reduce this to 0. 71 t.Skipf("got %f allocs, want 0", n) 72 } 73 } 74 75 func TestAppendMallocs(t *testing.T) { 76 str := []byte("helloworld") 77 out := make([]byte, 0, len(str)) 78 if n := testtext.AllocsPerRun(100, func() { UsernameCaseMapped.Append(out, str) }); n > 0 { 79 t.Errorf("got %f allocs, want 0", n) 80 } 81 } 82 83 func TestTransformMallocs(t *testing.T) { 84 str := []byte("helloworld") 85 out := make([]byte, 0, len(str)) 86 tr := UsernameCaseMapped.NewTransformer() 87 if n := testtext.AllocsPerRun(100, func() { 88 tr.Reset() 89 tr.Transform(out, str, true) 90 }); n > 0 { 91 t.Errorf("got %f allocs, want 0", n) 92 } 93 } 94 95 func min(a, b int) int { 96 if a < b { 97 return a 98 } 99 return b 100 } 101 102 // TestTransformerShortBuffers tests that the precis.Transformer implements the 103 // spirit, not just the letter (the method signatures), of the 104 // transform.Transformer interface. 105 // 106 // In particular, it tests that, if one or both of the dst or src buffers are 107 // short, so that multiple Transform calls are required to complete the overall 108 // transformation, the end result is identical to one Transform call with 109 // sufficiently long buffers. 110 func TestTransformerShortBuffers(t *testing.T) { 111 srcUnit := []byte("a\u0300cce\u0301nts") // NFD normalization form. 112 wantUnit := []byte("àccénts") // NFC normalization form. 113 src := bytes.Repeat(srcUnit, 16) 114 want := bytes.Repeat(wantUnit, 16) 115 const long = 4096 116 dst := make([]byte, long) 117 118 // 5, 7, 9, 11, 13, 16 and 17 are all pair-wise co-prime, which means that 119 // slicing the dst and src buffers into 5, 7, 13 and 17 byte chunks will 120 // fall at different places inside the repeated srcUnit's and wantUnit's. 121 if len(srcUnit) != 11 || len(wantUnit) != 9 || len(src) > long || len(want) > long { 122 t.Fatal("inconsistent lengths") 123 } 124 125 tr := NewFreeform().NewTransformer() 126 for _, deltaD := range []int{5, 7, 13, 17, long} { 127 loop: 128 for _, deltaS := range []int{5, 7, 13, 17, long} { 129 tr.Reset() 130 d0 := 0 131 s0 := 0 132 for { 133 d1 := min(len(dst), d0+deltaD) 134 s1 := min(len(src), s0+deltaS) 135 nDst, nSrc, err := tr.Transform(dst[d0:d1:d1], src[s0:s1:s1], s1 == len(src)) 136 d0 += nDst 137 s0 += nSrc 138 if err == nil { 139 break 140 } 141 if err == transform.ErrShortDst || err == transform.ErrShortSrc { 142 continue 143 } 144 t.Errorf("deltaD=%d, deltaS=%d: %v", deltaD, deltaS, err) 145 continue loop 146 } 147 if s0 != len(src) { 148 t.Errorf("deltaD=%d, deltaS=%d: s0: got %d, want %d", deltaD, deltaS, s0, len(src)) 149 continue 150 } 151 if d0 != len(want) { 152 t.Errorf("deltaD=%d, deltaS=%d: d0: got %d, want %d", deltaD, deltaS, d0, len(want)) 153 continue 154 } 155 got := dst[:d0] 156 if !bytes.Equal(got, want) { 157 t.Errorf("deltaD=%d, deltaS=%d:\ngot %q\nwant %q", deltaD, deltaS, got, want) 158 continue 159 } 160 } 161 } 162 }