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//go:build !go1.10
6// +build !go1.10
7
8package bidirule
9
10import (
11	"golang.org/x/text/transform"
12	"golang.org/x/text/unicode/bidi"
13)
14
15var testCases = [][]ruleTest{
16	// Go-specific rules.
17	// Invalid UTF-8 is invalid.
18	0: []ruleTest{{
19		in:  "",
20		dir: bidi.LeftToRight,
21	}, {
22		in:  "\x80",
23		dir: bidi.LeftToRight,
24		err: ErrInvalid,
25		n:   0,
26	}, {
27		in:  "\xcc",
28		dir: bidi.LeftToRight,
29		err: ErrInvalid,
30		n:   0,
31	}, {
32		in:  "abc\x80",
33		dir: bidi.LeftToRight,
34		err: ErrInvalid,
35		n:   3,
36	}, {
37		in:  "abc\xcc",
38		dir: bidi.LeftToRight,
39		err: ErrInvalid,
40		n:   3,
41	}, {
42		in:  "abc\xccdef",
43		dir: bidi.LeftToRight,
44		err: ErrInvalid,
45		n:   3,
46	}, {
47		in:  "\xccdef",
48		dir: bidi.LeftToRight,
49		err: ErrInvalid,
50		n:   0,
51	}, {
52		in:  strR + "\x80",
53		dir: bidi.RightToLeft,
54		err: ErrInvalid,
55		n:   len(strR),
56	}, {
57		in:  strR + "\xcc",
58		dir: bidi.RightToLeft,
59		err: ErrInvalid,
60		n:   len(strR),
61	}, {
62		in:  strAL + "\xcc" + strR,
63		dir: bidi.RightToLeft,
64		err: ErrInvalid,
65		n:   len(strAL),
66	}, {
67		in:  "\xcc" + strR,
68		dir: bidi.RightToLeft,
69		err: ErrInvalid,
70		n:   0,
71	}},
72
73	// Rule 2.1: The first character must be a character with Bidi property L,
74	// R, or AL.  If it has the R or AL property, it is an RTL label; if it has
75	// the L property, it is an LTR label.
76	1: []ruleTest{{
77		in:  strL,
78		dir: bidi.LeftToRight,
79	}, {
80		in:  strR,
81		dir: bidi.RightToLeft,
82	}, {
83		in:  strAL,
84		dir: bidi.RightToLeft,
85	}, {
86		in:  strAN,
87		dir: bidi.RightToLeft,
88		err: ErrInvalid,
89	}, {
90		in:  strEN,
91		dir: bidi.LeftToRight,
92		err: nil, // not an RTL string
93	}, {
94		in:  strES,
95		dir: bidi.LeftToRight,
96		err: nil, // not an RTL string
97	}, {
98		in:  strET,
99		dir: bidi.LeftToRight,
100		err: nil, // not an RTL string
101	}, {
102		in:  strCS,
103		dir: bidi.LeftToRight,
104		err: nil, // not an RTL string
105	}, {
106		in:  strNSM,
107		dir: bidi.LeftToRight,
108		err: nil, // not an RTL string
109	}, {
110		in:  strBN,
111		dir: bidi.LeftToRight,
112		err: nil, // not an RTL string
113	}, {
114		in:  strB,
115		dir: bidi.LeftToRight,
116		err: nil, // not an RTL string
117	}, {
118		in:  strS,
119		dir: bidi.LeftToRight,
120		err: nil, // not an RTL string
121	}, {
122		in:  strWS,
123		dir: bidi.LeftToRight,
124		err: nil, // not an RTL string
125	}, {
126		in:  strON,
127		dir: bidi.LeftToRight,
128		err: nil, // not an RTL string
129	}, {
130		in:  strEN + strR,
131		dir: bidi.RightToLeft,
132		err: ErrInvalid,
133		n:   3,
134	}, {
135		in:  strES + strR,
136		dir: bidi.RightToLeft,
137		err: ErrInvalid,
138		n:   2,
139	}, {
140		in:  strET + strR,
141		dir: bidi.RightToLeft,
142		err: ErrInvalid,
143		n:   1,
144	}, {
145		in:  strCS + strR,
146		dir: bidi.RightToLeft,
147		err: ErrInvalid,
148		n:   1,
149	}, {
150		in:  strNSM + strR,
151		dir: bidi.RightToLeft,
152		err: ErrInvalid,
153		n:   2,
154	}, {
155		in:  strBN + strR,
156		dir: bidi.RightToLeft,
157		err: ErrInvalid,
158		n:   3,
159	}, {
160		in:  strB + strR,
161		dir: bidi.RightToLeft,
162		err: ErrInvalid,
163		n:   3,
164	}, {
165		in:  strS + strR,
166		dir: bidi.RightToLeft,
167		err: ErrInvalid,
168		n:   1,
169	}, {
170		in:  strWS + strR,
171		dir: bidi.RightToLeft,
172		err: ErrInvalid,
173		n:   1,
174	}, {
175		in:  strON + strR,
176		dir: bidi.RightToLeft,
177		err: ErrInvalid,
178		n:   1,
179	}},
180
181	// Rule 2.2: In an RTL label, only characters with the Bidi properties R,
182	// AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
183	2: []ruleTest{{
184		in:  strR + strR + strAL,
185		dir: bidi.RightToLeft,
186	}, {
187		in:  strR + strAL + strR,
188		dir: bidi.RightToLeft,
189	}, {
190		in:  strR + strAN + strAL,
191		dir: bidi.RightToLeft,
192	}, {
193		in:  strR + strEN + strR,
194		dir: bidi.RightToLeft,
195	}, {
196		in:  strR + strES + strR,
197		dir: bidi.RightToLeft,
198	}, {
199		in:  strR + strCS + strR,
200		dir: bidi.RightToLeft,
201	}, {
202		in:  strR + strET + strAL,
203		dir: bidi.RightToLeft,
204	}, {
205		in:  strR + strON + strR,
206		dir: bidi.RightToLeft,
207	}, {
208		in:  strR + strBN + strR,
209		dir: bidi.RightToLeft,
210	}, {
211		in:  strR + strNSM + strAL,
212		dir: bidi.RightToLeft,
213	}, {
214		in:  strR + strL + strR,
215		dir: bidi.RightToLeft,
216		n:   len(strR),
217		err: ErrInvalid,
218	}, {
219		in:  strR + strB + strR,
220		dir: bidi.RightToLeft,
221		n:   len(strR),
222		err: ErrInvalid,
223	}, {
224		in:  strR + strS + strAL,
225		dir: bidi.RightToLeft,
226		n:   len(strR),
227		err: ErrInvalid,
228	}, {
229		in:  strR + strWS + strAL,
230		dir: bidi.RightToLeft,
231		n:   len(strR),
232		err: ErrInvalid,
233	}, {
234		in:  strAL + strR + strAL,
235		dir: bidi.RightToLeft,
236	}, {
237		in:  strAL + strAL + strR,
238		dir: bidi.RightToLeft,
239	}, {
240		in:  strAL + strAN + strAL,
241		dir: bidi.RightToLeft,
242	}, {
243		in:  strAL + strEN + strR,
244		dir: bidi.RightToLeft,
245	}, {
246		in:  strAL + strES + strR,
247		dir: bidi.RightToLeft,
248	}, {
249		in:  strAL + strCS + strR,
250		dir: bidi.RightToLeft,
251	}, {
252		in:  strAL + strET + strAL,
253		dir: bidi.RightToLeft,
254	}, {
255		in:  strAL + strON + strR,
256		dir: bidi.RightToLeft,
257	}, {
258		in:  strAL + strBN + strR,
259		dir: bidi.RightToLeft,
260	}, {
261		in:  strAL + strNSM + strAL,
262		dir: bidi.RightToLeft,
263	}, {
264		in:  strAL + strL + strR,
265		dir: bidi.RightToLeft,
266		n:   len(strAL),
267		err: ErrInvalid,
268	}, {
269		in:  strAL + strB + strR,
270		dir: bidi.RightToLeft,
271		n:   len(strAL),
272		err: ErrInvalid,
273	}, {
274		in:  strAL + strS + strAL,
275		dir: bidi.RightToLeft,
276		n:   len(strAL),
277		err: ErrInvalid,
278	}, {
279		in:  strAL + strWS + strAL,
280		dir: bidi.RightToLeft,
281		n:   len(strAL),
282		err: ErrInvalid,
283	}},
284
285	// Rule 2.3: In an RTL label, the end of the label must be a character with
286	// Bidi property R, AL, EN, or AN, followed by zero or more characters with
287	// Bidi property NSM.
288	3: []ruleTest{{
289		in:  strR + strNSM,
290		dir: bidi.RightToLeft,
291	}, {
292		in:  strR + strR,
293		dir: bidi.RightToLeft,
294	}, {
295		in:  strR + strAL + strNSM,
296		dir: bidi.RightToLeft,
297	}, {
298		in:  strR + strEN + strNSM + strNSM,
299		dir: bidi.RightToLeft,
300	}, {
301		in:  strR + strAN,
302		dir: bidi.RightToLeft,
303	}, {
304		in:  strR + strES + strNSM,
305		dir: bidi.RightToLeft,
306		n:   len(strR + strES + strNSM),
307		err: ErrInvalid,
308	}, {
309		in:  strR + strCS + strNSM + strNSM,
310		dir: bidi.RightToLeft,
311		n:   len(strR + strCS + strNSM + strNSM),
312		err: ErrInvalid,
313	}, {
314		in:  strR + strET,
315		dir: bidi.RightToLeft,
316		n:   len(strR + strET),
317		err: ErrInvalid,
318	}, {
319		in:  strR + strON + strNSM,
320		dir: bidi.RightToLeft,
321		n:   len(strR + strON + strNSM),
322		err: ErrInvalid,
323	}, {
324		in:  strR + strBN + strNSM + strNSM,
325		dir: bidi.RightToLeft,
326		n:   len(strR + strBN + strNSM + strNSM),
327		err: ErrInvalid,
328	}, {
329		in:  strR + strL + strNSM,
330		dir: bidi.RightToLeft,
331		n:   len(strR),
332		err: ErrInvalid,
333	}, {
334		in:  strR + strB + strNSM + strNSM,
335		dir: bidi.RightToLeft,
336		n:   len(strR),
337		err: ErrInvalid,
338	}, {
339		in:  strR + strS,
340		dir: bidi.RightToLeft,
341		n:   len(strR),
342		err: ErrInvalid,
343	}, {
344		in:  strR + strWS,
345		dir: bidi.RightToLeft,
346		n:   len(strR),
347		err: ErrInvalid,
348	}, {
349		in:  strAL + strNSM,
350		dir: bidi.RightToLeft,
351	}, {
352		in:  strAL + strR,
353		dir: bidi.RightToLeft,
354	}, {
355		in:  strAL + strAL + strNSM,
356		dir: bidi.RightToLeft,
357	}, {
358		in:  strAL + strEN + strNSM + strNSM,
359		dir: bidi.RightToLeft,
360	}, {
361		in:  strAL + strAN,
362		dir: bidi.RightToLeft,
363	}, {
364		in:  strAL + strES + strNSM,
365		dir: bidi.RightToLeft,
366		n:   len(strAL + strES + strNSM),
367		err: ErrInvalid,
368	}, {
369		in:  strAL + strCS + strNSM + strNSM,
370		dir: bidi.RightToLeft,
371		n:   len(strAL + strCS + strNSM + strNSM),
372		err: ErrInvalid,
373	}, {
374		in:  strAL + strET,
375		dir: bidi.RightToLeft,
376		n:   len(strAL + strET),
377		err: ErrInvalid,
378	}, {
379		in:  strAL + strON + strNSM,
380		dir: bidi.RightToLeft,
381		n:   len(strAL + strON + strNSM),
382		err: ErrInvalid,
383	}, {
384		in:  strAL + strBN + strNSM + strNSM,
385		dir: bidi.RightToLeft,
386		n:   len(strAL + strBN + strNSM + strNSM),
387		err: ErrInvalid,
388	}, {
389		in:  strAL + strL + strNSM,
390		dir: bidi.RightToLeft,
391		n:   len(strAL),
392		err: ErrInvalid,
393	}, {
394		in:  strAL + strB + strNSM + strNSM,
395		dir: bidi.RightToLeft,
396		n:   len(strAL),
397		err: ErrInvalid,
398	}, {
399		in:  strAL + strS,
400		dir: bidi.RightToLeft,
401		n:   len(strAL),
402		err: ErrInvalid,
403	}, {
404		in:  strAL + strWS,
405		dir: bidi.RightToLeft,
406		n:   len(strAL),
407		err: ErrInvalid,
408	}},
409
410	// Rule 2.4: In an RTL label, if an EN is present, no AN may be present,
411	// and vice versa.
412	4: []ruleTest{{
413		in:  strR + strEN + strAN,
414		dir: bidi.RightToLeft,
415		n:   len(strR + strEN),
416		err: ErrInvalid,
417	}, {
418		in:  strR + strAN + strEN + strNSM,
419		dir: bidi.RightToLeft,
420		n:   len(strR + strAN),
421		err: ErrInvalid,
422	}, {
423		in:  strAL + strEN + strAN,
424		dir: bidi.RightToLeft,
425		n:   len(strAL + strEN),
426		err: ErrInvalid,
427	}, {
428		in:  strAL + strAN + strEN + strNSM,
429		dir: bidi.RightToLeft,
430		n:   len(strAL + strAN),
431		err: ErrInvalid,
432	}},
433
434	// Rule 2.5: In an LTR label, only characters with the Bidi properties L,
435	// EN, ES, CS, ET, ON, BN, or NSM are allowed.
436	5: []ruleTest{{
437		in:  strL + strL + strL,
438		dir: bidi.LeftToRight,
439	}, {
440		in:  strL + strEN + strL,
441		dir: bidi.LeftToRight,
442	}, {
443		in:  strL + strES + strL,
444		dir: bidi.LeftToRight,
445	}, {
446		in:  strL + strCS + strL,
447		dir: bidi.LeftToRight,
448	}, {
449		in:  strL + strET + strL,
450		dir: bidi.LeftToRight,
451	}, {
452		in:  strL + strON + strL,
453		dir: bidi.LeftToRight,
454	}, {
455		in:  strL + strBN + strL,
456		dir: bidi.LeftToRight,
457	}, {
458		in:  strL + strNSM + strL,
459		dir: bidi.LeftToRight,
460	}, {
461		in:  strL + strR + strL,
462		dir: bidi.RightToLeft,
463		n:   len(strL),
464		err: ErrInvalid,
465	}, {
466		in:  strL + strAL + strL,
467		dir: bidi.RightToLeft,
468		n:   len(strL),
469		err: ErrInvalid,
470	}, {
471		in:  strL + strAN + strL,
472		dir: bidi.RightToLeft,
473		n:   len(strL),
474		err: ErrInvalid,
475	}, {
476		in:  strL + strB + strL,
477		dir: bidi.LeftToRight,
478		n:   len(strL + strAN + strL),
479		err: nil,
480	}, {
481		in:  strL + strB + strL + strR,
482		dir: bidi.RightToLeft,
483		n:   len(strL + strB + strL),
484		err: ErrInvalid,
485	}, {
486		in:  strL + strS + strL,
487		dir: bidi.LeftToRight,
488		n:   len(strL + strS + strL),
489		err: nil,
490	}, {
491		in:  strL + strS + strL + strR,
492		dir: bidi.RightToLeft,
493		n:   len(strL + strS + strL),
494		err: ErrInvalid,
495	}, {
496		in:  strL + strWS + strL,
497		dir: bidi.LeftToRight,
498		n:   len(strL + strWS + strL),
499		err: nil,
500	}, {
501		in:  strL + strWS + strL + strR,
502		dir: bidi.RightToLeft,
503		n:   len(strL + strWS + strL),
504		err: ErrInvalid,
505	}},
506
507	// Rule 2.6: In an LTR label, the end of the label must be a character with
508	// Bidi property L or EN, followed by zero or more characters with Bidi
509	// property NSM.
510	6: []ruleTest{{
511		in:  strL,
512		dir: bidi.LeftToRight,
513	}, {
514		in:  strL + strNSM,
515		dir: bidi.LeftToRight,
516	}, {
517		in:  strL + strNSM + strNSM,
518		dir: bidi.LeftToRight,
519	}, {
520		in:  strL + strEN,
521		dir: bidi.LeftToRight,
522	}, {
523		in:  strL + strEN + strNSM,
524		dir: bidi.LeftToRight,
525	}, {
526		in:  strL + strEN + strNSM + strNSM,
527		dir: bidi.LeftToRight,
528	}, {
529		in:  strL + strES,
530		dir: bidi.LeftToRight,
531		n:   len(strL + strES),
532		err: nil,
533	}, {
534		in:  strL + strES + strR,
535		dir: bidi.RightToLeft,
536		n:   len(strL + strES),
537		err: ErrInvalid,
538	}, {
539		in:  strL + strCS,
540		dir: bidi.LeftToRight,
541		n:   len(strL + strCS),
542		err: nil,
543	}, {
544		in:  strL + strCS + strR,
545		dir: bidi.RightToLeft,
546		n:   len(strL + strCS),
547		err: ErrInvalid,
548	}, {
549		in:  strL + strET,
550		dir: bidi.LeftToRight,
551		n:   len(strL + strET),
552		err: nil,
553	}, {
554		in:  strL + strET + strR,
555		dir: bidi.RightToLeft,
556		n:   len(strL + strET),
557		err: ErrInvalid,
558	}, {
559		in:  strL + strON,
560		dir: bidi.LeftToRight,
561		n:   len(strL + strON),
562		err: nil,
563	}, {
564		in:  strL + strON + strR,
565		dir: bidi.RightToLeft,
566		n:   len(strL + strON),
567		err: ErrInvalid,
568	}, {
569		in:  strL + strBN,
570		dir: bidi.LeftToRight,
571		n:   len(strL + strBN),
572		err: nil,
573	}, {
574		in:  strL + strBN + strR,
575		dir: bidi.RightToLeft,
576		n:   len(strL + strBN),
577		err: ErrInvalid,
578	}, {
579		in:  strL + strR,
580		dir: bidi.RightToLeft,
581		n:   len(strL),
582		err: ErrInvalid,
583	}, {
584		in:  strL + strAL,
585		dir: bidi.RightToLeft,
586		n:   len(strL),
587		err: ErrInvalid,
588	}, {
589		in:  strL + strAN,
590		dir: bidi.RightToLeft,
591		n:   len(strL),
592		err: ErrInvalid,
593	}, {
594		in:  strL + strB,
595		dir: bidi.LeftToRight,
596		n:   len(strL + strB),
597		err: nil,
598	}, {
599		in:  strL + strB + strR,
600		dir: bidi.RightToLeft,
601		n:   len(strL + strB),
602		err: ErrInvalid,
603	}, {
604		in:  strL + strB,
605		dir: bidi.LeftToRight,
606		n:   len(strL + strB),
607		err: nil,
608	}, {
609		in:  strL + strB + strR,
610		dir: bidi.RightToLeft,
611		n:   len(strL + strB),
612		err: ErrInvalid,
613	}, {
614		in:  strL + strB,
615		dir: bidi.LeftToRight,
616		n:   len(strL + strB),
617		err: nil,
618	}, {
619		in:  strL + strB + strR,
620		dir: bidi.RightToLeft,
621		n:   len(strL + strB),
622		err: ErrInvalid,
623	}},
624
625	// Incremental processing.
626	9: []ruleTest{{
627		in:  "e\u0301", // é
628		dir: bidi.LeftToRight,
629
630		pSrc: 2,
631		nSrc: 1,
632		err0: transform.ErrShortSrc,
633	}, {
634		in:  "e\u1000f", // é
635		dir: bidi.LeftToRight,
636
637		pSrc: 3,
638		nSrc: 1,
639		err0: transform.ErrShortSrc,
640	}, {
641		// Remain invalid once invalid.
642		in:  strR + "ab",
643		dir: bidi.RightToLeft,
644		n:   len(strR),
645		err: ErrInvalid,
646
647		pSrc: len(strR) + 1,
648		nSrc: len(strR),
649		err0: ErrInvalid,
650	}, {
651		// Short destination
652		in:  "abcdefghij",
653		dir: bidi.LeftToRight,
654
655		pSrc:  10,
656		szDst: 5,
657		nSrc:  5,
658		err0:  transform.ErrShortDst,
659	}, {
660		// Short destination splitting input rune
661		in:  "e\u0301",
662		dir: bidi.LeftToRight,
663
664		pSrc:  3,
665		szDst: 2,
666		nSrc:  1,
667		err0:  transform.ErrShortDst,
668	}},
669}
670