1
2
3
4
5 package bidi
6
7 import (
8 "flag"
9 "fmt"
10 "log"
11 "strconv"
12 "strings"
13 "testing"
14
15 "golang.org/x/text/internal/gen"
16 "golang.org/x/text/internal/testtext"
17 "golang.org/x/text/internal/ucd"
18 "golang.org/x/text/unicode/norm"
19 )
20
21 var testLevels = flag.Bool("levels", false, "enable testing of levels")
22
23
24
25 func TestBidiCore(t *testing.T) {
26 testtext.SkipIfNotLong(t)
27
28 r := gen.OpenUCDFile("BidiTest.txt")
29 defer r.Close()
30
31 var wantLevels, wantOrder []string
32 p := ucd.New(r, ucd.Part(func(p *ucd.Parser) {
33 s := strings.Split(p.String(0), ":")
34 switch s[0] {
35 case "Levels":
36 wantLevels = strings.Fields(s[1])
37 case "Reorder":
38 wantOrder = strings.Fields(s[1])
39 default:
40 log.Fatalf("Unknown part %q.", s[0])
41 }
42 }))
43
44 for p.Next() {
45 types := []Class{}
46 for _, s := range p.Strings(0) {
47 types = append(types, bidiClass[s])
48 }
49
50 pairTypes := make([]bracketType, len(types))
51 pairValues := make([]rune, len(types))
52
53 for i := uint(0); i < 3; i++ {
54 if p.Uint(1)&(1<<i) == 0 {
55 continue
56 }
57 lev := level(int(i) - 1)
58 par, err := newParagraph(types, pairTypes, pairValues, lev)
59 if err != nil {
60 t.Error(err)
61 }
62
63 if *testLevels {
64 levels := par.getLevels([]int{len(types)})
65 for i, s := range wantLevels {
66 if s == "x" {
67 continue
68 }
69 l, _ := strconv.ParseUint(s, 10, 8)
70 if level(l)&1 != levels[i]&1 {
71 t.Errorf("%s:%d:levels: got %v; want %v", p.String(0), lev, levels, wantLevels)
72 break
73 }
74 }
75 }
76
77 order := par.getReordering([]int{len(types)})
78 gotOrder := filterOrder(types, order)
79 if got, want := fmt.Sprint(gotOrder), fmt.Sprint(wantOrder); got != want {
80 t.Errorf("%s:%d:order: got %v; want %v\noriginal %v", p.String(0), lev, got, want, order)
81 }
82 }
83 }
84 if err := p.Err(); err != nil {
85 log.Fatal(err)
86 }
87 }
88
89 var removeClasses = map[Class]bool{
90 LRO: true,
91 RLO: true,
92 RLE: true,
93 LRE: true,
94 PDF: true,
95 BN: true,
96 }
97
98
99
100 func TestBidiCharacters(t *testing.T) {
101 testtext.SkipIfNotLong(t)
102
103 ucd.Parse(gen.OpenUCDFile("BidiCharacterTest.txt"), func(p *ucd.Parser) {
104 var (
105 types []Class
106 pairTypes []bracketType
107 pairValues []rune
108 parLevel level
109
110 wantLevel = level(p.Int(2))
111 wantLevels = p.Strings(3)
112 wantVisualOrder = p.Strings(4)
113 )
114
115 switch l := p.Int(1); l {
116 case 0, 1:
117 parLevel = level(l)
118 case 2:
119 parLevel = implicitLevel
120 default:
121
122 }
123
124 runes := p.Runes(0)
125
126 for _, r := range runes {
127
128 if d := norm.NFKD.PropertiesString(string(r)).Decomposition(); d != nil {
129 r = []rune(string(d))[0]
130 }
131 p, _ := LookupRune(r)
132
133
134 types = append(types, p.Class())
135
136 switch {
137 case !p.IsBracket():
138 pairTypes = append(pairTypes, bpNone)
139 pairValues = append(pairValues, 0)
140 case p.IsOpeningBracket():
141 pairTypes = append(pairTypes, bpOpen)
142 pairValues = append(pairValues, r)
143 default:
144 pairTypes = append(pairTypes, bpClose)
145 pairValues = append(pairValues, p.reverseBracket(r))
146 }
147 }
148 par, err := newParagraph(types, pairTypes, pairValues, parLevel)
149 if err != nil {
150 t.Error(err)
151 }
152
153
154 if got := par.embeddingLevel; got != wantLevel {
155 t.Errorf("%v:level: got %d; want %d", string(runes), got, wantLevel)
156 }
157
158 if *testLevels {
159 gotLevels := getLevelStrings(types, par.getLevels([]int{len(types)}))
160 if got, want := fmt.Sprint(gotLevels), fmt.Sprint(wantLevels); got != want {
161 t.Errorf("%04X %q:%d: got %v; want %v\nval: %x\npair: %v", runes, string(runes), parLevel, got, want, pairValues, pairTypes)
162 }
163 }
164
165 order := par.getReordering([]int{len(types)})
166 order = filterOrder(types, order)
167 if got, want := fmt.Sprint(order), fmt.Sprint(wantVisualOrder); got != want {
168 t.Errorf("%04X %q:%d: got %v; want %v\ngot order: %s", runes, string(runes), parLevel, got, want, reorder(runes, order))
169 }
170 })
171 }
172
173 func getLevelStrings(cl []Class, levels []level) []string {
174 var results []string
175 for i, l := range levels {
176 if !removeClasses[cl[i]] {
177 results = append(results, fmt.Sprint(l))
178 } else {
179 results = append(results, "x")
180 }
181 }
182 return results
183 }
184
185 func filterOrder(cl []Class, order []int) []int {
186 no := []int{}
187 for _, o := range order {
188 if !removeClasses[cl[o]] {
189 no = append(no, o)
190 }
191 }
192 return no
193 }
194
195 func reorder(r []rune, order []int) string {
196 nr := make([]rune, len(order))
197 for i, o := range order {
198 nr[i] = r[o]
199 }
200 return string(nr)
201 }
202
203
204
205 var bidiClass = map[string]Class{
206 "AL": AL,
207 "AN": AN,
208 "B": B,
209 "BN": BN,
210 "CS": CS,
211 "EN": EN,
212 "ES": ES,
213 "ET": ET,
214 "L": L,
215 "NSM": NSM,
216 "ON": ON,
217 "R": R,
218 "S": S,
219 "WS": WS,
220
221 "LRO": LRO,
222 "RLO": RLO,
223 "LRE": LRE,
224 "RLE": RLE,
225 "PDF": PDF,
226 "LRI": LRI,
227 "RLI": RLI,
228 "FSI": FSI,
229 "PDI": PDI,
230 }
231
View as plain text