enforce_test.go 4.6 KB

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