1
2
3
4
5 package norm
6
7 import (
8 "bufio"
9 "bytes"
10 "fmt"
11 "regexp"
12 "runtime"
13 "strconv"
14 "strings"
15 "sync"
16 "testing"
17 "time"
18 "unicode/utf8"
19
20 "golang.org/x/text/internal/gen"
21 "golang.org/x/text/internal/testtext"
22 )
23
24 var once sync.Once
25
26 func skipShort(t *testing.T) {
27 testtext.SkipIfNotLong(t)
28
29 once.Do(func() { loadTestData(t) })
30 }
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 const (
70 cRaw = iota
71 cNFC
72 cNFD
73 cNFKC
74 cNFKD
75 cMaxColumns
76 )
77
78
79 var part []Part
80
81 type Part struct {
82 name string
83 number int
84 tests []Test
85 }
86
87 type Test struct {
88 name string
89 partnr int
90 number int
91 r rune
92 cols [cMaxColumns]string
93 }
94
95 func (t Test) Name() string {
96 if t.number < 0 {
97 return part[t.partnr].name
98 }
99 return fmt.Sprintf("%s:%d", part[t.partnr].name, t.number)
100 }
101
102 var partRe = regexp.MustCompile(`@Part(\d) # (.*)$`)
103 var testRe = regexp.MustCompile(`^` + strings.Repeat(`([\dA-F ]+);`, 5) + ` # (.*)$`)
104
105 var counter int
106
107
108 func loadTestData(t *testing.T) {
109 f := gen.OpenUCDFile("NormalizationTest.txt")
110 defer f.Close()
111 scanner := bufio.NewScanner(f)
112 for scanner.Scan() {
113 line := scanner.Text()
114 if len(line) == 0 || line[0] == '#' {
115 continue
116 }
117 m := partRe.FindStringSubmatch(line)
118 if m != nil {
119 if len(m) < 3 {
120 t.Fatal("Failed to parse Part: ", line)
121 }
122 i, err := strconv.Atoi(m[1])
123 if err != nil {
124 t.Fatal(err)
125 }
126 name := m[2]
127 part = append(part, Part{name: name[:len(name)-1], number: i})
128 continue
129 }
130 m = testRe.FindStringSubmatch(line)
131 if m == nil || len(m) < 7 {
132 t.Fatalf(`Failed to parse: "%s" result: %#v`, line, m)
133 }
134 test := Test{name: m[6], partnr: len(part) - 1, number: counter}
135 counter++
136 for j := 1; j < len(m)-1; j++ {
137 for _, split := range strings.Split(m[j], " ") {
138 r, err := strconv.ParseUint(split, 16, 64)
139 if err != nil {
140 t.Fatal(err)
141 }
142 if test.r == 0 {
143
144 test.r = rune(r)
145 }
146 var buf [utf8.UTFMax]byte
147 sz := utf8.EncodeRune(buf[:], rune(r))
148 test.cols[j-1] += string(buf[:sz])
149 }
150 }
151 part := &part[len(part)-1]
152 part.tests = append(part.tests, test)
153 }
154 if scanner.Err() != nil {
155 t.Fatal(scanner.Err())
156 }
157 }
158
159 func cmpResult(t *testing.T, tc *Test, name string, f Form, gold, test, result string) {
160 if gold != result {
161 t.Errorf("%s:%s: %s(%+q)=%+q; want %+q: %s",
162 tc.Name(), name, fstr[f], test, result, gold, tc.name)
163 }
164 }
165
166 func cmpIsNormal(t *testing.T, tc *Test, name string, f Form, test string, result, want bool) {
167 if result != want {
168 t.Errorf("%s:%s: %s(%+q)=%v; want %v", tc.Name(), name, fstr[f], test, result, want)
169 }
170 }
171
172 func doTest(t *testing.T, tc *Test, f Form, gold, test string) {
173 testb := []byte(test)
174 result := f.Bytes(testb)
175 cmpResult(t, tc, "Bytes", f, gold, test, string(result))
176
177 sresult := f.String(test)
178 cmpResult(t, tc, "String", f, gold, test, sresult)
179
180 acc := []byte{}
181 i := Iter{}
182 i.InitString(f, test)
183 for !i.Done() {
184 acc = append(acc, i.Next()...)
185 }
186 cmpResult(t, tc, "Iter.Next", f, gold, test, string(acc))
187
188 buf := make([]byte, 128)
189 acc = nil
190 for p := 0; p < len(testb); {
191 nDst, nSrc, _ := f.Transform(buf, testb[p:], true)
192 acc = append(acc, buf[:nDst]...)
193 p += nSrc
194 }
195 cmpResult(t, tc, "Transform", f, gold, test, string(acc))
196
197 for i := range test {
198 out := f.Append(f.Bytes([]byte(test[:i])), []byte(test[i:])...)
199 cmpResult(t, tc, fmt.Sprintf(":Append:%d", i), f, gold, test, string(out))
200 }
201 cmpIsNormal(t, tc, "IsNormal", f, test, f.IsNormal([]byte(test)), test == gold)
202 cmpIsNormal(t, tc, "IsNormalString", f, test, f.IsNormalString(test), test == gold)
203 }
204
205 func doConformanceTests(t *testing.T, tc *Test, partn int) {
206 for i := 0; i <= 2; i++ {
207 doTest(t, tc, NFC, tc.cols[1], tc.cols[i])
208 doTest(t, tc, NFD, tc.cols[2], tc.cols[i])
209 doTest(t, tc, NFKC, tc.cols[3], tc.cols[i])
210 doTest(t, tc, NFKD, tc.cols[4], tc.cols[i])
211 }
212 for i := 3; i <= 4; i++ {
213 doTest(t, tc, NFC, tc.cols[3], tc.cols[i])
214 doTest(t, tc, NFD, tc.cols[4], tc.cols[i])
215 doTest(t, tc, NFKC, tc.cols[3], tc.cols[i])
216 doTest(t, tc, NFKD, tc.cols[4], tc.cols[i])
217 }
218 }
219
220 func TestCharacterByCharacter(t *testing.T) {
221 skipShort(t)
222 tests := part[1].tests
223 var last rune = 0
224 for i := 0; i <= len(tests); i++ {
225 var r rune
226 if i == len(tests) {
227 r = 0x2FA1E
228 } else {
229 r = tests[i].r
230 }
231 for last++; last < r; last++ {
232
233 tc := &Test{partnr: 1, number: -1}
234 char := string(last)
235 doTest(t, tc, NFC, char, char)
236 doTest(t, tc, NFD, char, char)
237 doTest(t, tc, NFKC, char, char)
238 doTest(t, tc, NFKD, char, char)
239 }
240 if i < len(tests) {
241 doConformanceTests(t, &tests[i], 1)
242 }
243 }
244 }
245
246 func TestStandardTests(t *testing.T) {
247 skipShort(t)
248 for _, j := range []int{0, 2, 3} {
249 for _, test := range part[j].tests {
250 doConformanceTests(t, &test, j)
251 }
252 }
253 }
254
255
256
257
258 func TestPerformance(t *testing.T) {
259 skipShort(t)
260 runtime.GOMAXPROCS(2)
261 success := make(chan bool, 1)
262 go func() {
263 buf := bytes.Repeat([]byte("\u035D"), 1024*1024)
264 buf = append(buf, "\u035B"...)
265 NFC.Append(nil, buf...)
266 success <- true
267 }()
268 timeout := time.After(1 * time.Second)
269 select {
270 case <-success:
271
272 case <-timeout:
273 t.Errorf(`unexpectedly long time to complete PerformanceTest`)
274 }
275 }
276
View as plain text