...

Source file src/golang.org/x/text/secure/precis/enforce_test.go

Documentation: golang.org/x/text/secure/precis

     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  }
   163  

View as plain text