blob: 11684069d3386db2858336a509f85255cbeb523e [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// Copyright 2011 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
5package norm
6
7import "testing"
8
9// TestCase is used for most tests.
10type TestCase struct {
11 in []rune
12 out []rune
13}
14
15func runTests(t *testing.T, name string, fm Form, tests []TestCase) {
16 rb := reorderBuffer{}
17 rb.init(fm, nil)
18 for i, test := range tests {
19 rb.setFlusher(nil, appendFlush)
20 for j, rune := range test.in {
21 b := []byte(string(rune))
22 src := inputBytes(b)
23 info := rb.f.info(src, 0)
24 if j == 0 {
25 rb.ss.first(info)
26 } else {
27 rb.ss.next(info)
28 }
29 if rb.insertFlush(src, 0, info) < 0 {
30 t.Errorf("%s:%d: insert failed for rune %d", name, i, j)
31 }
32 }
33 rb.doFlush()
34 was := string(rb.out)
35 want := string(test.out)
36 if len(was) != len(want) {
37 t.Errorf("%s:%d: length = %d; want %d", name, i, len(was), len(want))
38 }
39 if was != want {
40 k, pfx := pidx(was, want)
41 t.Errorf("%s:%d: \nwas %s%+q; \nwant %s%+q", name, i, pfx, was[k:], pfx, want[k:])
42 }
43 }
44}
45
46func TestFlush(t *testing.T) {
47 const (
48 hello = "Hello "
49 world = "world!"
50 )
51 buf := make([]byte, maxByteBufferSize)
52 p := copy(buf, hello)
53 out := buf[p:]
54 rb := reorderBuffer{}
55 rb.initString(NFC, world)
56 if i := rb.flushCopy(out); i != 0 {
57 t.Errorf("wrote bytes on flush of empty buffer. (len(out) = %d)", i)
58 }
59
60 for i := range world {
61 // No need to set streamSafe values for this test.
62 rb.insertFlush(rb.src, i, rb.f.info(rb.src, i))
63 n := rb.flushCopy(out)
64 out = out[n:]
65 p += n
66 }
67
68 was := buf[:p]
69 want := hello + world
70 if string(was) != want {
71 t.Errorf(`output after flush was "%s"; want "%s"`, string(was), want)
72 }
73 if rb.nrune != 0 {
74 t.Errorf("non-null size of info buffer (rb.nrune == %d)", rb.nrune)
75 }
76 if rb.nbyte != 0 {
77 t.Errorf("non-null size of byte buffer (rb.nbyte == %d)", rb.nbyte)
78 }
79}
80
81var insertTests = []TestCase{
82 {[]rune{'a'}, []rune{'a'}},
83 {[]rune{0x300}, []rune{0x300}},
84 {[]rune{0x300, 0x316}, []rune{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220
85 {[]rune{0x316, 0x300}, []rune{0x316, 0x300}},
86 {[]rune{0x41, 0x316, 0x300}, []rune{0x41, 0x316, 0x300}},
87 {[]rune{0x41, 0x300, 0x316}, []rune{0x41, 0x316, 0x300}},
88 {[]rune{0x300, 0x316, 0x41}, []rune{0x316, 0x300, 0x41}},
89 {[]rune{0x41, 0x300, 0x40, 0x316}, []rune{0x41, 0x300, 0x40, 0x316}},
90}
91
92func TestInsert(t *testing.T) {
93 runTests(t, "TestInsert", NFD, insertTests)
94}
95
96var decompositionNFDTest = []TestCase{
97 {[]rune{0xC0}, []rune{0x41, 0x300}},
98 {[]rune{0xAC00}, []rune{0x1100, 0x1161}},
99 {[]rune{0x01C4}, []rune{0x01C4}},
100 {[]rune{0x320E}, []rune{0x320E}},
101 {[]rune("음ẻ과"), []rune{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}},
102}
103
104var decompositionNFKDTest = []TestCase{
105 {[]rune{0xC0}, []rune{0x41, 0x300}},
106 {[]rune{0xAC00}, []rune{0x1100, 0x1161}},
107 {[]rune{0x01C4}, []rune{0x44, 0x5A, 0x030C}},
108 {[]rune{0x320E}, []rune{0x28, 0x1100, 0x1161, 0x29}},
109}
110
111func TestDecomposition(t *testing.T) {
112 runTests(t, "TestDecompositionNFD", NFD, decompositionNFDTest)
113 runTests(t, "TestDecompositionNFKD", NFKD, decompositionNFKDTest)
114}
115
116var compositionTest = []TestCase{
117 {[]rune{0x41, 0x300}, []rune{0xC0}},
118 {[]rune{0x41, 0x316}, []rune{0x41, 0x316}},
119 {[]rune{0x41, 0x300, 0x35D}, []rune{0xC0, 0x35D}},
120 {[]rune{0x41, 0x316, 0x300}, []rune{0xC0, 0x316}},
121 // blocking starter
122 {[]rune{0x41, 0x316, 0x40, 0x300}, []rune{0x41, 0x316, 0x40, 0x300}},
123 {[]rune{0x1100, 0x1161}, []rune{0xAC00}},
124 // parenthesized Hangul, alternate between ASCII and Hangul.
125 {[]rune{0x28, 0x1100, 0x1161, 0x29}, []rune{0x28, 0xAC00, 0x29}},
126}
127
128func TestComposition(t *testing.T) {
129 runTests(t, "TestComposition", NFC, compositionTest)
130}