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/unicode/bidi"
"golang.org/x/text/unicode/norm"
)
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:%[3]s", rule, i, norm.NFC.String(tc.in))
t.Run(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)
}
})
}
|