github.com/liquid-dev/text@v0.3.3-liquid/secure/bidirule/bidirule_test.go (about)

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