You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

179 lines
4.4 KiB

  1. // Copyright 2016 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 idna
  5. import (
  6. "fmt"
  7. "strconv"
  8. "strings"
  9. "testing"
  10. "golang.org/x/text/internal/gen"
  11. "golang.org/x/text/internal/testtext"
  12. "golang.org/x/text/internal/ucd"
  13. )
  14. func TestAllocToUnicode(t *testing.T) {
  15. avg := testtext.AllocsPerRun(1000, func() {
  16. ToUnicode("www.golang.org")
  17. })
  18. if avg > 0 {
  19. t.Errorf("got %f; want 0", avg)
  20. }
  21. }
  22. func TestAllocToASCII(t *testing.T) {
  23. avg := testtext.AllocsPerRun(1000, func() {
  24. ToASCII("www.golang.org")
  25. })
  26. if avg > 0 {
  27. t.Errorf("got %f; want 0", avg)
  28. }
  29. }
  30. func TestProfiles(t *testing.T) {
  31. testCases := []struct {
  32. name string
  33. want, got *Profile
  34. }{
  35. {"Punycode", punycode, New()},
  36. {"Registration", registration, New(ValidateForRegistration())},
  37. {"Registration", registration, New(
  38. ValidateForRegistration(),
  39. VerifyDNSLength(true),
  40. BidiRule(),
  41. )},
  42. {"Lookup", lookup, New(MapForLookup(), BidiRule(), Transitional(true))},
  43. {"Display", display, New(MapForLookup(), BidiRule())},
  44. }
  45. for _, tc := range testCases {
  46. // Functions are not comparable, but the printed version will include
  47. // their pointers.
  48. got := fmt.Sprintf("%#v", tc.got)
  49. want := fmt.Sprintf("%#v", tc.want)
  50. if got != want {
  51. t.Errorf("%s: \ngot %#v,\nwant %#v", tc.name, got, want)
  52. }
  53. }
  54. }
  55. // doTest performs a single test f(input) and verifies that the output matches
  56. // out and that the returned error is expected. The errors string contains
  57. // all allowed error codes as categorized in
  58. // https://www.unicode.org/Public/idna/9.0.0/IdnaTest.txt:
  59. // P: Processing
  60. // V: Validity
  61. // A: to ASCII
  62. // B: Bidi
  63. // C: Context J
  64. func doTest(t *testing.T, f func(string) (string, error), name, input, want, errors string) {
  65. errors = strings.Trim(errors, "[]")
  66. test := "ok"
  67. if errors != "" {
  68. test = "err:" + errors
  69. }
  70. // Replace some of the escape sequences to make it easier to single out
  71. // tests on the command name.
  72. in := strings.Trim(strconv.QuoteToASCII(input), `"`)
  73. in = strings.Replace(in, `\u`, "#", -1)
  74. in = strings.Replace(in, `\U`, "#", -1)
  75. name = fmt.Sprintf("%s/%s/%s", name, in, test)
  76. testtext.Run(t, name, func(t *testing.T) {
  77. got, err := f(input)
  78. if err != nil {
  79. code := err.(interface {
  80. code() string
  81. }).code()
  82. if strings.Index(errors, code) == -1 {
  83. t.Errorf("error %q not in set of expected errors {%v}", code, errors)
  84. }
  85. } else if errors != "" {
  86. t.Errorf("no errors; want error in {%v}", errors)
  87. }
  88. if want != "" && got != want {
  89. t.Errorf(`string: got %+q; want %+q`, got, want)
  90. }
  91. })
  92. }
  93. func TestConformance(t *testing.T) {
  94. testtext.SkipIfNotLong(t)
  95. r := gen.OpenUnicodeFile("idna", "", "IdnaTest.txt")
  96. defer r.Close()
  97. section := "main"
  98. started := false
  99. p := ucd.New(r, ucd.CommentHandler(func(s string) {
  100. if started {
  101. section = strings.ToLower(strings.Split(s, " ")[0])
  102. }
  103. }))
  104. transitional := New(Transitional(true), VerifyDNSLength(true), BidiRule(), MapForLookup())
  105. nonTransitional := New(VerifyDNSLength(true), BidiRule(), MapForLookup())
  106. for p.Next() {
  107. started = true
  108. // What to test
  109. profiles := []*Profile{}
  110. switch p.String(0) {
  111. case "T":
  112. profiles = append(profiles, transitional)
  113. case "N":
  114. profiles = append(profiles, nonTransitional)
  115. case "B":
  116. profiles = append(profiles, transitional)
  117. profiles = append(profiles, nonTransitional)
  118. }
  119. src := unescape(p.String(1))
  120. wantToUnicode := unescape(p.String(2))
  121. if wantToUnicode == "" {
  122. wantToUnicode = src
  123. }
  124. wantToASCII := unescape(p.String(3))
  125. if wantToASCII == "" {
  126. wantToASCII = wantToUnicode
  127. }
  128. wantErrToUnicode := ""
  129. if strings.HasPrefix(wantToUnicode, "[") {
  130. wantErrToUnicode = wantToUnicode
  131. wantToUnicode = ""
  132. }
  133. wantErrToASCII := ""
  134. if strings.HasPrefix(wantToASCII, "[") {
  135. wantErrToASCII = wantToASCII
  136. wantToASCII = ""
  137. }
  138. // TODO: also do IDNA tests.
  139. // invalidInIDNA2008 := p.String(4) == "NV8"
  140. for _, p := range profiles {
  141. name := fmt.Sprintf("%s:%s", section, p)
  142. doTest(t, p.ToUnicode, name+":ToUnicode", src, wantToUnicode, wantErrToUnicode)
  143. doTest(t, p.ToASCII, name+":ToASCII", src, wantToASCII, wantErrToASCII)
  144. }
  145. }
  146. }
  147. func unescape(s string) string {
  148. s, err := strconv.Unquote(`"` + s + `"`)
  149. if err != nil {
  150. panic(err)
  151. }
  152. return s
  153. }
  154. func BenchmarkProfile(b *testing.B) {
  155. for i := 0; i < b.N; i++ {
  156. Lookup.ToASCII("www.yahoogle.com")
  157. }
  158. }