1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bidirule
import (
"fmt"
"testing"
"golang.org/x/text/internal/testtext"
"golang.org/x/text/unicode/bidi"
)
const (
strL = "ABC" // Left to right - most letters in LTR scripts
strR = "עברית" // Right to left - most letters in non-Arabic RTL scripts
strAL = "دبي" // Arabic letters - most letters in the Arabic script
strEN = "123" // European Number (0-9, and Extended Arabic-Indic numbers)
strES = "+-" // European Number Separator (+ and -)
strET = "$" // European Number Terminator (currency symbols, the hash sign, the percent sign and so on)
strAN = "\u0660" // Arabic Number; this encompasses the Arabic-Indic numbers, but not the Extended Arabic-Indic numbers
strCS = "," // Common Number Separator (. , / : et al)
strNSM = "\u0300" // Nonspacing Mark - most combining accents
strBN = "\u200d" // Boundary Neutral - control characters (ZWNJ, ZWJ, and others)
strB = "\u2029" // Paragraph Separator
strS = "\u0009" // Segment Separator
strWS = " " // Whitespace, including the SPACE character
strON = "@" // Other Neutrals, including @, &, parentheses, MIDDLE DOT
)
type ruleTest struct {
in string
dir bidi.Direction
n int // position at which the rule fails
err error
// For tests that split the string in two.
pSrc int // number of source bytes to consume first
szDst int // size of destination buffer
nSrc int // source bytes consumed and bytes written
err0 error // error after first run
}
func init() {
for rule, cases := range testCases {
for i, tc := range cases {
if tc.err == nil {
testCases[rule][i].n = len(tc.in)
}
}
}
}
func doTests(t *testing.T, fn func(t *testing.T, tc ruleTest)) {
for rule, cases := range testCases {
for i, tc := range cases {
name := fmt.Sprintf("%d/%d:%+q:%s", rule, i, tc.in, tc.in)
testtext.Run(t, name, func(t *testing.T) {
fn(t, tc)
})
}
}
}
func TestDirection(t *testing.T) {
doTests(t, func(t *testing.T, tc ruleTest) {
dir := Direction([]byte(tc.in))
if dir != tc.dir {
t.Errorf("dir was %v; want %v", dir, tc.dir)
}
})
}
func TestDirectionString(t *testing.T) {
doTests(t, func(t *testing.T, tc ruleTest) {
dir := DirectionString(tc.in)
if dir != tc.dir {
t.Errorf("dir was %v; want %v", dir, tc.dir)
}
})
}
func TestValid(t *testing.T) {
doTests(t, func(t *testing.T, tc ruleTest) {
got := Valid([]byte(tc.in))
want := tc.err == nil
if got != want {
t.Fatalf("Valid: got %v; want %v", got, want)
}
got = ValidString(tc.in)
want = tc.err == nil
if got != want {
t.Fatalf("Valid: got %v; want %v", got, want)
}
})
}
func TestSpan(t *testing.T) {
doTests(t, func(t *testing.T, tc ruleTest) {
// Skip tests that test for limited destination buffer size.
if tc.szDst > 0 {
return
}
r := New()
src := []byte(tc.in)
n, err := r.Span(src[:tc.pSrc], tc.pSrc == len(tc.in))
if err != tc.err0 {
t.Errorf("err0 was %v; want %v", err, tc.err0)
}
if n != tc.nSrc {
t.Fatalf("nSrc was %d; want %d", n, tc.nSrc)
}
n, err = r.Span(src[n:], true)
if err != tc.err {
t.Errorf("error was %v; want %v", err, tc.err)
}
if got := n + tc.nSrc; got != tc.n {
t.Errorf("n was %d; want %d", got, tc.n)
}
})
}
func TestTransform(t *testing.T) {
doTests(t, func(t *testing.T, tc ruleTest) {
r := New()
src := []byte(tc.in)
dst := make([]byte, len(tc.in))
if tc.szDst > 0 {
dst = make([]byte, tc.szDst)
}
// First transform operates on a zero-length string for most tests.
nDst, nSrc, err := r.Transform(dst, src[:tc.pSrc], tc.pSrc == len(tc.in))
if err != tc.err0 {
t.Errorf("err0 was %v; want %v", err, tc.err0)
}
if nDst != nSrc {
t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc)
}
if nSrc != tc.nSrc {
t.Fatalf("nSrc was %d; want %d", nSrc, tc.nSrc)
}
dst1 := make([]byte, len(tc.in))
copy(dst1, dst[:nDst])
nDst, nSrc, err = r.Transform(dst1[nDst:], src[nSrc:], true)
if err != tc.err {
t.Errorf("error was %v; want %v", err, tc.err)
}
if nDst != nSrc {
t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc)
}
n := nSrc + tc.nSrc
if n != tc.n {
t.Fatalf("n was %d; want %d", n, tc.n)
}
if got, want := string(dst1[:n]), tc.in[:tc.n]; got != want {
t.Errorf("got %+q; want %+q", got, want)
}
})
}
|