| // 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. |
| |
| //go:build go1.10 |
| // +build go1.10 |
| |
| package bidirule |
| |
| import ( |
| "golang.org/x/text/transform" |
| "golang.org/x/text/unicode/bidi" |
| ) |
| |
| var testCases = [][]ruleTest{ |
| // Go-specific rules. |
| // Invalid UTF-8 is invalid. |
| 0: []ruleTest{{ |
| in: "", |
| dir: bidi.LeftToRight, |
| }, { |
| in: "\x80", |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: 0, |
| }, { |
| in: "\xcc", |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: 0, |
| }, { |
| in: "abc\x80", |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: 3, |
| }, { |
| in: "abc\xcc", |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: 3, |
| }, { |
| in: "abc\xccdef", |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: 3, |
| }, { |
| in: "\xccdef", |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: 0, |
| }, { |
| in: strR + "\x80", |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: len(strR), |
| }, { |
| in: strR + "\xcc", |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: len(strR), |
| }, { |
| in: strAL + "\xcc" + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: len(strAL), |
| }, { |
| in: "\xcc" + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 0, |
| }}, |
| |
| // Rule 2.1: The first character must be a character with Bidi property L, |
| // R, or AL. If it has the R or AL property, it is an RTL label; if it has |
| // the L property, it is an LTR label. |
| 1: []ruleTest{{ |
| in: strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAN, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| }, { |
| in: strEN, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strEN), |
| }, { |
| in: strES, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strES), |
| }, { |
| in: strET, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strET), |
| }, { |
| in: strCS, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strCS), |
| }, { |
| in: strNSM, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strNSM), |
| }, { |
| in: strBN, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strBN), |
| }, { |
| in: strB, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strB), |
| }, { |
| in: strS, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strS), |
| }, { |
| in: strWS, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strWS), |
| }, { |
| in: strON, |
| dir: bidi.LeftToRight, |
| err: ErrInvalid, |
| n: len(strON), |
| }, { |
| in: strEN + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 3, |
| }, { |
| in: strES + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 2, |
| }, { |
| in: strET + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 1, |
| }, { |
| in: strCS + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 1, |
| }, { |
| in: strNSM + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 2, |
| }, { |
| in: strBN + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 3, |
| }, { |
| in: strB + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 3, |
| }, { |
| in: strS + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 1, |
| }, { |
| in: strWS + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 1, |
| }, { |
| in: strON + strR, |
| dir: bidi.RightToLeft, |
| err: ErrInvalid, |
| n: 1, |
| }}, |
| |
| // Rule 2.2: In an RTL label, only characters with the Bidi properties R, |
| // AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed. |
| 2: []ruleTest{{ |
| in: strR + strR + strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strAL + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strAN + strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strEN + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strES + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strCS + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strET + strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strON + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strBN + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strNSM + strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strL + strR, |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| }, { |
| in: strR + strB + strR, |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| }, { |
| in: strR + strS + strAL, |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| }, { |
| in: strR + strWS + strAL, |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strR + strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strAL + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strAN + strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strEN + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strES + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strCS + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strET + strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strON + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strBN + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strNSM + strAL, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strL + strR, |
| dir: bidi.RightToLeft, |
| n: len(strAL), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strB + strR, |
| dir: bidi.RightToLeft, |
| n: len(strAL), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strS + strAL, |
| dir: bidi.RightToLeft, |
| n: len(strAL), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strWS + strAL, |
| dir: bidi.RightToLeft, |
| n: len(strAL), |
| err: ErrInvalid, |
| }}, |
| |
| // Rule 2.3: In an RTL label, the end of the label must be a character with |
| // Bidi property R, AL, EN, or AN, followed by zero or more characters with |
| // Bidi property NSM. |
| 3: []ruleTest{{ |
| in: strR + strNSM, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strAL + strNSM, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strEN + strNSM + strNSM, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strAN, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strR + strES + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strR + strES + strNSM), |
| err: ErrInvalid, |
| }, { |
| in: strR + strCS + strNSM + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strR + strCS + strNSM + strNSM), |
| err: ErrInvalid, |
| }, { |
| in: strR + strET, |
| dir: bidi.RightToLeft, |
| n: len(strR + strET), |
| err: ErrInvalid, |
| }, { |
| in: strR + strON + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strR + strON + strNSM), |
| err: ErrInvalid, |
| }, { |
| in: strR + strBN + strNSM + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strR + strBN + strNSM + strNSM), |
| err: ErrInvalid, |
| }, { |
| in: strR + strL + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| }, { |
| in: strR + strB + strNSM + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| }, { |
| in: strR + strS, |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| }, { |
| in: strR + strWS, |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strNSM, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strR, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strAL + strNSM, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strEN + strNSM + strNSM, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strAN, |
| dir: bidi.RightToLeft, |
| }, { |
| in: strAL + strES + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strAL + strES + strNSM), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strCS + strNSM + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strAL + strCS + strNSM + strNSM), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strET, |
| dir: bidi.RightToLeft, |
| n: len(strAL + strET), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strON + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strAL + strON + strNSM), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strBN + strNSM + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strAL + strBN + strNSM + strNSM), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strL + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strAL), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strB + strNSM + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strAL), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strS, |
| dir: bidi.RightToLeft, |
| n: len(strAL), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strWS, |
| dir: bidi.RightToLeft, |
| n: len(strAL), |
| err: ErrInvalid, |
| }}, |
| |
| // Rule 2.4: In an RTL label, if an EN is present, no AN may be present, |
| // and vice versa. |
| 4: []ruleTest{{ |
| in: strR + strEN + strAN, |
| dir: bidi.RightToLeft, |
| n: len(strR + strEN), |
| err: ErrInvalid, |
| }, { |
| in: strR + strAN + strEN + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strR + strAN), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strEN + strAN, |
| dir: bidi.RightToLeft, |
| n: len(strAL + strEN), |
| err: ErrInvalid, |
| }, { |
| in: strAL + strAN + strEN + strNSM, |
| dir: bidi.RightToLeft, |
| n: len(strAL + strAN), |
| err: ErrInvalid, |
| }}, |
| |
| // Rule 2.5: In an LTR label, only characters with the Bidi properties L, |
| // EN, ES, CS, ET, ON, BN, or NSM are allowed. |
| 5: []ruleTest{{ |
| in: strL + strL + strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strEN + strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strES + strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strCS + strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strET + strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strON + strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strBN + strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strNSM + strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strR + strL, |
| dir: bidi.RightToLeft, |
| n: len(strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strAL + strL, |
| dir: bidi.RightToLeft, |
| n: len(strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strAN + strL, |
| dir: bidi.RightToLeft, |
| n: len(strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strB + strL, |
| dir: bidi.LeftToRight, |
| n: len(strL + strB + strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strB + strL + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strB + strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strS + strL, |
| dir: bidi.LeftToRight, |
| n: len(strL + strS + strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strS + strL + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strS + strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strWS + strL, |
| dir: bidi.LeftToRight, |
| n: len(strL + strWS + strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strWS + strL + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strWS + strL), |
| err: ErrInvalid, |
| }}, |
| |
| // Rule 2.6: In an LTR label, the end of the label must be a character with |
| // Bidi property L or EN, followed by zero or more characters with Bidi |
| // property NSM. |
| 6: []ruleTest{{ |
| in: strL, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strNSM, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strNSM + strNSM, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strEN, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strEN + strNSM, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strEN + strNSM + strNSM, |
| dir: bidi.LeftToRight, |
| }, { |
| in: strL + strES, |
| dir: bidi.LeftToRight, |
| n: len(strL + strES), |
| err: ErrInvalid, |
| }, { |
| in: strL + strES + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strES), |
| err: ErrInvalid, |
| }, { |
| in: strL + strCS, |
| dir: bidi.LeftToRight, |
| n: len(strL + strCS), |
| err: ErrInvalid, |
| }, { |
| in: strL + strCS + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strCS), |
| err: ErrInvalid, |
| }, { |
| in: strL + strET, |
| dir: bidi.LeftToRight, |
| n: len(strL + strET), |
| err: ErrInvalid, |
| }, { |
| in: strL + strET + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strET), |
| err: ErrInvalid, |
| }, { |
| in: strL + strON, |
| dir: bidi.LeftToRight, |
| n: len(strL + strON), |
| err: ErrInvalid, |
| }, { |
| in: strL + strON + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strON), |
| err: ErrInvalid, |
| }, { |
| in: strL + strBN, |
| dir: bidi.LeftToRight, |
| n: len(strL + strBN), |
| err: ErrInvalid, |
| }, { |
| in: strL + strBN + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strBN), |
| err: ErrInvalid, |
| }, { |
| in: strL + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strAL, |
| dir: bidi.RightToLeft, |
| n: len(strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strAN, |
| dir: bidi.RightToLeft, |
| n: len(strL), |
| err: ErrInvalid, |
| }, { |
| in: strL + strB, |
| dir: bidi.LeftToRight, |
| n: len(strL + strB), |
| err: ErrInvalid, |
| }, { |
| in: strL + strB + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strB), |
| err: ErrInvalid, |
| }, { |
| in: strL + strS, |
| dir: bidi.LeftToRight, |
| n: len(strL + strS), |
| err: ErrInvalid, |
| }, { |
| in: strL + strS + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strS), |
| err: ErrInvalid, |
| }, { |
| in: strL + strWS, |
| dir: bidi.LeftToRight, |
| n: len(strL + strWS), |
| err: ErrInvalid, |
| }, { |
| in: strL + strWS + strR, |
| dir: bidi.RightToLeft, |
| n: len(strL + strWS), |
| err: ErrInvalid, |
| }}, |
| |
| // Incremental processing. |
| 9: []ruleTest{{ |
| in: "e\u0301", // é |
| dir: bidi.LeftToRight, |
| |
| pSrc: 2, |
| nSrc: 1, |
| err0: transform.ErrShortSrc, |
| }, { |
| in: "e\u1000f", // é |
| dir: bidi.LeftToRight, |
| |
| pSrc: 3, |
| nSrc: 1, |
| err0: transform.ErrShortSrc, |
| }, { |
| // Remain invalid once invalid. |
| in: strR + "ab", |
| dir: bidi.RightToLeft, |
| n: len(strR), |
| err: ErrInvalid, |
| |
| pSrc: len(strR) + 1, |
| nSrc: len(strR), |
| err0: ErrInvalid, |
| }, { |
| // Short destination |
| in: "abcdefghij", |
| dir: bidi.LeftToRight, |
| |
| pSrc: 10, |
| szDst: 5, |
| nSrc: 5, |
| err0: transform.ErrShortDst, |
| }, { |
| in: "\U000102f7", |
| dir: bidi.LeftToRight, |
| n: len("\U000102f7"), |
| err: ErrInvalid, |
| }, { |
| // Short destination splitting input rune |
| in: "e\u0301", |
| dir: bidi.LeftToRight, |
| |
| pSrc: 3, |
| szDst: 2, |
| nSrc: 1, |
| err0: transform.ErrShortDst, |
| }, { |
| // Unicode 10.0.0 IDNA test string. |
| in: "FAX\u2a77\U0001d186", |
| dir: bidi.LeftToRight, |
| n: len("FAX\u2a77\U0001d186"), |
| err: ErrInvalid, |
| }, { |
| in: "\x80\u0660", |
| dir: bidi.RightToLeft, |
| n: 0, |
| err: ErrInvalid, |
| }}, |
| } |