OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / text / secure / bidirule / bidirule_test.go
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         "golang.org/x/text/internal/testtext"
12         "golang.org/x/text/transform"
13         "golang.org/x/text/unicode/bidi"
14 )
15
16 const (
17         strL   = "ABC"    // Left to right - most letters in LTR scripts
18         strR   = "עברית"  // Right to left - most letters in non-Arabic RTL scripts
19         strAL  = "دبي"    // Arabic letters - most letters in the Arabic script
20         strEN  = "123"    // European Number (0-9, and Extended Arabic-Indic numbers)
21         strES  = "+-"     // European Number Separator (+ and -)
22         strET  = "$"      // European Number Terminator (currency symbols, the hash sign, the percent sign and so on)
23         strAN  = "\u0660" // Arabic Number; this encompasses the Arabic-Indic numbers, but not the Extended Arabic-Indic numbers
24         strCS  = ","      // Common Number Separator (. , / : et al)
25         strNSM = "\u0300" // Nonspacing Mark - most combining accents
26         strBN  = "\u200d" // Boundary Neutral - control characters (ZWNJ, ZWJ, and others)
27         strB   = "\u2029" // Paragraph Separator
28         strS   = "\u0009" // Segment Separator
29         strWS  = " "      // Whitespace, including the SPACE character
30         strON  = "@"      // Other Neutrals, including @, &, parentheses, MIDDLE DOT
31 )
32
33 type ruleTest struct {
34         in  string
35         dir bidi.Direction
36         n   int // position at which the rule fails
37         err error
38
39         // For tests that split the string in two.
40         pSrc  int   // number of source bytes to consume first
41         szDst int   // size of destination buffer
42         nSrc  int   // source bytes consumed and bytes written
43         err0  error // error after first run
44 }
45
46 var testCases = [][]ruleTest{
47         // Go-specific rules.
48         // Invalid UTF-8 is invalid.
49         0: []ruleTest{{
50                 in:  "",
51                 dir: bidi.LeftToRight,
52         }, {
53                 in:  "\x80",
54                 dir: bidi.LeftToRight,
55                 err: ErrInvalid,
56                 n:   0,
57         }, {
58                 in:  "\xcc",
59                 dir: bidi.LeftToRight,
60                 err: ErrInvalid,
61                 n:   0,
62         }, {
63                 in:  "abc\x80",
64                 dir: bidi.LeftToRight,
65                 err: ErrInvalid,
66                 n:   3,
67         }, {
68                 in:  "abc\xcc",
69                 dir: bidi.LeftToRight,
70                 err: ErrInvalid,
71                 n:   3,
72         }, {
73                 in:  "abc\xccdef",
74                 dir: bidi.LeftToRight,
75                 err: ErrInvalid,
76                 n:   3,
77         }, {
78                 in:  "\xccdef",
79                 dir: bidi.LeftToRight,
80                 err: ErrInvalid,
81                 n:   0,
82         }, {
83                 in:  strR + "\x80",
84                 dir: bidi.RightToLeft,
85                 err: ErrInvalid,
86                 n:   len(strR),
87         }, {
88                 in:  strR + "\xcc",
89                 dir: bidi.RightToLeft,
90                 err: ErrInvalid,
91                 n:   len(strR),
92         }, {
93                 in:  strAL + "\xcc" + strR,
94                 dir: bidi.RightToLeft,
95                 err: ErrInvalid,
96                 n:   len(strAL),
97         }, {
98                 in:  "\xcc" + strR,
99                 dir: bidi.RightToLeft,
100                 err: ErrInvalid,
101                 n:   0,
102         }},
103
104         // Rule 2.1: The first character must be a character with Bidi property L,
105         // R, or AL.  If it has the R or AL property, it is an RTL label; if it has
106         // the L property, it is an LTR label.
107         1: []ruleTest{{
108                 in:  strL,
109                 dir: bidi.LeftToRight,
110         }, {
111                 in:  strR,
112                 dir: bidi.RightToLeft,
113         }, {
114                 in:  strAL,
115                 dir: bidi.RightToLeft,
116         }, {
117                 in:  strAN,
118                 dir: bidi.RightToLeft,
119                 err: ErrInvalid,
120         }, {
121                 in:  strEN,
122                 dir: bidi.LeftToRight,
123                 err: nil, // not an RTL string
124         }, {
125                 in:  strES,
126                 dir: bidi.LeftToRight,
127                 err: nil, // not an RTL string
128         }, {
129                 in:  strET,
130                 dir: bidi.LeftToRight,
131                 err: nil, // not an RTL string
132         }, {
133                 in:  strCS,
134                 dir: bidi.LeftToRight,
135                 err: nil, // not an RTL string
136         }, {
137                 in:  strNSM,
138                 dir: bidi.LeftToRight,
139                 err: nil, // not an RTL string
140         }, {
141                 in:  strBN,
142                 dir: bidi.LeftToRight,
143                 err: nil, // not an RTL string
144         }, {
145                 in:  strB,
146                 dir: bidi.LeftToRight,
147                 err: nil, // not an RTL string
148         }, {
149                 in:  strS,
150                 dir: bidi.LeftToRight,
151                 err: nil, // not an RTL string
152         }, {
153                 in:  strWS,
154                 dir: bidi.LeftToRight,
155                 err: nil, // not an RTL string
156         }, {
157                 in:  strON,
158                 dir: bidi.LeftToRight,
159                 err: nil, // not an RTL string
160         }, {
161                 in:  strEN + strR,
162                 dir: bidi.RightToLeft,
163                 err: ErrInvalid,
164                 n:   3,
165         }, {
166                 in:  strES + strR,
167                 dir: bidi.RightToLeft,
168                 err: ErrInvalid,
169                 n:   2,
170         }, {
171                 in:  strET + strR,
172                 dir: bidi.RightToLeft,
173                 err: ErrInvalid,
174                 n:   1,
175         }, {
176                 in:  strCS + strR,
177                 dir: bidi.RightToLeft,
178                 err: ErrInvalid,
179                 n:   1,
180         }, {
181                 in:  strNSM + strR,
182                 dir: bidi.RightToLeft,
183                 err: ErrInvalid,
184                 n:   2,
185         }, {
186                 in:  strBN + strR,
187                 dir: bidi.RightToLeft,
188                 err: ErrInvalid,
189                 n:   3,
190         }, {
191                 in:  strB + strR,
192                 dir: bidi.RightToLeft,
193                 err: ErrInvalid,
194                 n:   3,
195         }, {
196                 in:  strS + strR,
197                 dir: bidi.RightToLeft,
198                 err: ErrInvalid,
199                 n:   1,
200         }, {
201                 in:  strWS + strR,
202                 dir: bidi.RightToLeft,
203                 err: ErrInvalid,
204                 n:   1,
205         }, {
206                 in:  strON + strR,
207                 dir: bidi.RightToLeft,
208                 err: ErrInvalid,
209                 n:   1,
210         }},
211
212         // Rule 2.2: In an RTL label, only characters with the Bidi properties R,
213         // AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
214         2: []ruleTest{{
215                 in:  strR + strR + strAL,
216                 dir: bidi.RightToLeft,
217         }, {
218                 in:  strR + strAL + strR,
219                 dir: bidi.RightToLeft,
220         }, {
221                 in:  strR + strAN + strAL,
222                 dir: bidi.RightToLeft,
223         }, {
224                 in:  strR + strEN + strR,
225                 dir: bidi.RightToLeft,
226         }, {
227                 in:  strR + strES + strR,
228                 dir: bidi.RightToLeft,
229         }, {
230                 in:  strR + strCS + strR,
231                 dir: bidi.RightToLeft,
232         }, {
233                 in:  strR + strET + strAL,
234                 dir: bidi.RightToLeft,
235         }, {
236                 in:  strR + strON + strR,
237                 dir: bidi.RightToLeft,
238         }, {
239                 in:  strR + strBN + strR,
240                 dir: bidi.RightToLeft,
241         }, {
242                 in:  strR + strNSM + strAL,
243                 dir: bidi.RightToLeft,
244         }, {
245                 in:  strR + strL + strR,
246                 dir: bidi.RightToLeft,
247                 n:   len(strR),
248                 err: ErrInvalid,
249         }, {
250                 in:  strR + strB + strR,
251                 dir: bidi.RightToLeft,
252                 n:   len(strR),
253                 err: ErrInvalid,
254         }, {
255                 in:  strR + strS + strAL,
256                 dir: bidi.RightToLeft,
257                 n:   len(strR),
258                 err: ErrInvalid,
259         }, {
260                 in:  strR + strWS + strAL,
261                 dir: bidi.RightToLeft,
262                 n:   len(strR),
263                 err: ErrInvalid,
264         }, {
265                 in:  strAL + strR + strAL,
266                 dir: bidi.RightToLeft,
267         }, {
268                 in:  strAL + strAL + strR,
269                 dir: bidi.RightToLeft,
270         }, {
271                 in:  strAL + strAN + strAL,
272                 dir: bidi.RightToLeft,
273         }, {
274                 in:  strAL + strEN + strR,
275                 dir: bidi.RightToLeft,
276         }, {
277                 in:  strAL + strES + strR,
278                 dir: bidi.RightToLeft,
279         }, {
280                 in:  strAL + strCS + strR,
281                 dir: bidi.RightToLeft,
282         }, {
283                 in:  strAL + strET + strAL,
284                 dir: bidi.RightToLeft,
285         }, {
286                 in:  strAL + strON + strR,
287                 dir: bidi.RightToLeft,
288         }, {
289                 in:  strAL + strBN + strR,
290                 dir: bidi.RightToLeft,
291         }, {
292                 in:  strAL + strNSM + strAL,
293                 dir: bidi.RightToLeft,
294         }, {
295                 in:  strAL + strL + strR,
296                 dir: bidi.RightToLeft,
297                 n:   len(strAL),
298                 err: ErrInvalid,
299         }, {
300                 in:  strAL + strB + strR,
301                 dir: bidi.RightToLeft,
302                 n:   len(strAL),
303                 err: ErrInvalid,
304         }, {
305                 in:  strAL + strS + strAL,
306                 dir: bidi.RightToLeft,
307                 n:   len(strAL),
308                 err: ErrInvalid,
309         }, {
310                 in:  strAL + strWS + strAL,
311                 dir: bidi.RightToLeft,
312                 n:   len(strAL),
313                 err: ErrInvalid,
314         }},
315
316         // Rule 2.3: In an RTL label, the end of the label must be a character with
317         // Bidi property R, AL, EN, or AN, followed by zero or more characters with
318         // Bidi property NSM.
319         3: []ruleTest{{
320                 in:  strR + strNSM,
321                 dir: bidi.RightToLeft,
322         }, {
323                 in:  strR + strR,
324                 dir: bidi.RightToLeft,
325         }, {
326                 in:  strR + strAL + strNSM,
327                 dir: bidi.RightToLeft,
328         }, {
329                 in:  strR + strEN + strNSM + strNSM,
330                 dir: bidi.RightToLeft,
331         }, {
332                 in:  strR + strAN,
333                 dir: bidi.RightToLeft,
334         }, {
335                 in:  strR + strES + strNSM,
336                 dir: bidi.RightToLeft,
337                 n:   len(strR + strES + strNSM),
338                 err: ErrInvalid,
339         }, {
340                 in:  strR + strCS + strNSM + strNSM,
341                 dir: bidi.RightToLeft,
342                 n:   len(strR + strCS + strNSM + strNSM),
343                 err: ErrInvalid,
344         }, {
345                 in:  strR + strET,
346                 dir: bidi.RightToLeft,
347                 n:   len(strR + strET),
348                 err: ErrInvalid,
349         }, {
350                 in:  strR + strON + strNSM,
351                 dir: bidi.RightToLeft,
352                 n:   len(strR + strON + strNSM),
353                 err: ErrInvalid,
354         }, {
355                 in:  strR + strBN + strNSM + strNSM,
356                 dir: bidi.RightToLeft,
357                 n:   len(strR + strBN + strNSM + strNSM),
358                 err: ErrInvalid,
359         }, {
360                 in:  strR + strL + strNSM,
361                 dir: bidi.RightToLeft,
362                 n:   len(strR),
363                 err: ErrInvalid,
364         }, {
365                 in:  strR + strB + strNSM + strNSM,
366                 dir: bidi.RightToLeft,
367                 n:   len(strR),
368                 err: ErrInvalid,
369         }, {
370                 in:  strR + strS,
371                 dir: bidi.RightToLeft,
372                 n:   len(strR),
373                 err: ErrInvalid,
374         }, {
375                 in:  strR + strWS,
376                 dir: bidi.RightToLeft,
377                 n:   len(strR),
378                 err: ErrInvalid,
379         }, {
380                 in:  strAL + strNSM,
381                 dir: bidi.RightToLeft,
382         }, {
383                 in:  strAL + strR,
384                 dir: bidi.RightToLeft,
385         }, {
386                 in:  strAL + strAL + strNSM,
387                 dir: bidi.RightToLeft,
388         }, {
389                 in:  strAL + strEN + strNSM + strNSM,
390                 dir: bidi.RightToLeft,
391         }, {
392                 in:  strAL + strAN,
393                 dir: bidi.RightToLeft,
394         }, {
395                 in:  strAL + strES + strNSM,
396                 dir: bidi.RightToLeft,
397                 n:   len(strAL + strES + strNSM),
398                 err: ErrInvalid,
399         }, {
400                 in:  strAL + strCS + strNSM + strNSM,
401                 dir: bidi.RightToLeft,
402                 n:   len(strAL + strCS + strNSM + strNSM),
403                 err: ErrInvalid,
404         }, {
405                 in:  strAL + strET,
406                 dir: bidi.RightToLeft,
407                 n:   len(strAL + strET),
408                 err: ErrInvalid,
409         }, {
410                 in:  strAL + strON + strNSM,
411                 dir: bidi.RightToLeft,
412                 n:   len(strAL + strON + strNSM),
413                 err: ErrInvalid,
414         }, {
415                 in:  strAL + strBN + strNSM + strNSM,
416                 dir: bidi.RightToLeft,
417                 n:   len(strAL + strBN + strNSM + strNSM),
418                 err: ErrInvalid,
419         }, {
420                 in:  strAL + strL + strNSM,
421                 dir: bidi.RightToLeft,
422                 n:   len(strAL),
423                 err: ErrInvalid,
424         }, {
425                 in:  strAL + strB + strNSM + strNSM,
426                 dir: bidi.RightToLeft,
427                 n:   len(strAL),
428                 err: ErrInvalid,
429         }, {
430                 in:  strAL + strS,
431                 dir: bidi.RightToLeft,
432                 n:   len(strAL),
433                 err: ErrInvalid,
434         }, {
435                 in:  strAL + strWS,
436                 dir: bidi.RightToLeft,
437                 n:   len(strAL),
438                 err: ErrInvalid,
439         }},
440
441         // Rule 2.4: In an RTL label, if an EN is present, no AN may be present,
442         // and vice versa.
443         4: []ruleTest{{
444                 in:  strR + strEN + strAN,
445                 dir: bidi.RightToLeft,
446                 n:   len(strR + strEN),
447                 err: ErrInvalid,
448         }, {
449                 in:  strR + strAN + strEN + strNSM,
450                 dir: bidi.RightToLeft,
451                 n:   len(strR + strAN),
452                 err: ErrInvalid,
453         }, {
454                 in:  strAL + strEN + strAN,
455                 dir: bidi.RightToLeft,
456                 n:   len(strAL + strEN),
457                 err: ErrInvalid,
458         }, {
459                 in:  strAL + strAN + strEN + strNSM,
460                 dir: bidi.RightToLeft,
461                 n:   len(strAL + strAN),
462                 err: ErrInvalid,
463         }},
464
465         // Rule 2.5: In an LTR label, only characters with the Bidi properties L,
466         // EN, ES, CS, ET, ON, BN, or NSM are allowed.
467         5: []ruleTest{{
468                 in:  strL + strL + strL,
469                 dir: bidi.LeftToRight,
470         }, {
471                 in:  strL + strEN + strL,
472                 dir: bidi.LeftToRight,
473         }, {
474                 in:  strL + strES + strL,
475                 dir: bidi.LeftToRight,
476         }, {
477                 in:  strL + strCS + strL,
478                 dir: bidi.LeftToRight,
479         }, {
480                 in:  strL + strET + strL,
481                 dir: bidi.LeftToRight,
482         }, {
483                 in:  strL + strON + strL,
484                 dir: bidi.LeftToRight,
485         }, {
486                 in:  strL + strBN + strL,
487                 dir: bidi.LeftToRight,
488         }, {
489                 in:  strL + strNSM + strL,
490                 dir: bidi.LeftToRight,
491         }, {
492                 in:  strL + strR + strL,
493                 dir: bidi.RightToLeft,
494                 n:   len(strL),
495                 err: ErrInvalid,
496         }, {
497                 in:  strL + strAL + strL,
498                 dir: bidi.RightToLeft,
499                 n:   len(strL),
500                 err: ErrInvalid,
501         }, {
502                 in:  strL + strAN + strL,
503                 dir: bidi.RightToLeft,
504                 n:   len(strL),
505                 err: ErrInvalid,
506         }, {
507                 in:  strL + strB + strL,
508                 dir: bidi.LeftToRight,
509                 n:   len(strL + strAN + strL),
510                 err: nil,
511         }, {
512                 in:  strL + strB + strL + strR,
513                 dir: bidi.RightToLeft,
514                 n:   len(strL + strB + strL),
515                 err: ErrInvalid,
516         }, {
517                 in:  strL + strS + strL,
518                 dir: bidi.LeftToRight,
519                 n:   len(strL + strS + strL),
520                 err: nil,
521         }, {
522                 in:  strL + strS + strL + strR,
523                 dir: bidi.RightToLeft,
524                 n:   len(strL + strS + strL),
525                 err: ErrInvalid,
526         }, {
527                 in:  strL + strWS + strL,
528                 dir: bidi.LeftToRight,
529                 n:   len(strL + strWS + strL),
530                 err: nil,
531         }, {
532                 in:  strL + strWS + strL + strR,
533                 dir: bidi.RightToLeft,
534                 n:   len(strL + strWS + strL),
535                 err: ErrInvalid,
536         }},
537
538         // Rule 2.6: In an LTR label, the end of the label must be a character with
539         // Bidi property L or EN, followed by zero or more characters with Bidi
540         // property NSM.
541         6: []ruleTest{{
542                 in:  strL,
543                 dir: bidi.LeftToRight,
544         }, {
545                 in:  strL + strNSM,
546                 dir: bidi.LeftToRight,
547         }, {
548                 in:  strL + strNSM + strNSM,
549                 dir: bidi.LeftToRight,
550         }, {
551                 in:  strL + strEN,
552                 dir: bidi.LeftToRight,
553         }, {
554                 in:  strL + strEN + strNSM,
555                 dir: bidi.LeftToRight,
556         }, {
557                 in:  strL + strEN + strNSM + strNSM,
558                 dir: bidi.LeftToRight,
559         }, {
560                 in:  strL + strES,
561                 dir: bidi.LeftToRight,
562                 n:   len(strL + strES),
563                 err: nil,
564         }, {
565                 in:  strL + strES + strR,
566                 dir: bidi.RightToLeft,
567                 n:   len(strL + strES),
568                 err: ErrInvalid,
569         }, {
570                 in:  strL + strCS,
571                 dir: bidi.LeftToRight,
572                 n:   len(strL + strCS),
573                 err: nil,
574         }, {
575                 in:  strL + strCS + strR,
576                 dir: bidi.RightToLeft,
577                 n:   len(strL + strCS),
578                 err: ErrInvalid,
579         }, {
580                 in:  strL + strET,
581                 dir: bidi.LeftToRight,
582                 n:   len(strL + strET),
583                 err: nil,
584         }, {
585                 in:  strL + strET + strR,
586                 dir: bidi.RightToLeft,
587                 n:   len(strL + strET),
588                 err: ErrInvalid,
589         }, {
590                 in:  strL + strON,
591                 dir: bidi.LeftToRight,
592                 n:   len(strL + strON),
593                 err: nil,
594         }, {
595                 in:  strL + strON + strR,
596                 dir: bidi.RightToLeft,
597                 n:   len(strL + strON),
598                 err: ErrInvalid,
599         }, {
600                 in:  strL + strBN,
601                 dir: bidi.LeftToRight,
602                 n:   len(strL + strBN),
603                 err: nil,
604         }, {
605                 in:  strL + strBN + strR,
606                 dir: bidi.RightToLeft,
607                 n:   len(strL + strBN),
608                 err: ErrInvalid,
609         }, {
610                 in:  strL + strR,
611                 dir: bidi.RightToLeft,
612                 n:   len(strL),
613                 err: ErrInvalid,
614         }, {
615                 in:  strL + strAL,
616                 dir: bidi.RightToLeft,
617                 n:   len(strL),
618                 err: ErrInvalid,
619         }, {
620                 in:  strL + strAN,
621                 dir: bidi.RightToLeft,
622                 n:   len(strL),
623                 err: ErrInvalid,
624         }, {
625                 in:  strL + strB,
626                 dir: bidi.LeftToRight,
627                 n:   len(strL + strB),
628                 err: nil,
629         }, {
630                 in:  strL + strB + strR,
631                 dir: bidi.RightToLeft,
632                 n:   len(strL + strB),
633                 err: ErrInvalid,
634         }, {
635                 in:  strL + strB,
636                 dir: bidi.LeftToRight,
637                 n:   len(strL + strB),
638                 err: nil,
639         }, {
640                 in:  strL + strB + strR,
641                 dir: bidi.RightToLeft,
642                 n:   len(strL + strB),
643                 err: ErrInvalid,
644         }, {
645                 in:  strL + strB,
646                 dir: bidi.LeftToRight,
647                 n:   len(strL + strB),
648                 err: nil,
649         }, {
650                 in:  strL + strB + strR,
651                 dir: bidi.RightToLeft,
652                 n:   len(strL + strB),
653                 err: ErrInvalid,
654         }},
655
656         // Incremental processing.
657         9: []ruleTest{{
658                 in:  "e\u0301", // é
659                 dir: bidi.LeftToRight,
660
661                 pSrc: 2,
662                 nSrc: 1,
663                 err0: transform.ErrShortSrc,
664         }, {
665                 in:  "e\u1000f", // é
666                 dir: bidi.LeftToRight,
667
668                 pSrc: 3,
669                 nSrc: 1,
670                 err0: transform.ErrShortSrc,
671         }, {
672                 // Remain invalid once invalid.
673                 in:  strR + "ab",
674                 dir: bidi.RightToLeft,
675                 n:   len(strR),
676                 err: ErrInvalid,
677
678                 pSrc: len(strR) + 1,
679                 nSrc: len(strR),
680                 err0: ErrInvalid,
681         }, {
682                 // Short destination
683                 in:  "abcdefghij",
684                 dir: bidi.LeftToRight,
685
686                 pSrc:  10,
687                 szDst: 5,
688                 nSrc:  5,
689                 err0:  transform.ErrShortDst,
690         }, {
691                 // Short destination splitting input rune
692                 in:  "e\u0301",
693                 dir: bidi.LeftToRight,
694
695                 pSrc:  3,
696                 szDst: 2,
697                 nSrc:  1,
698                 err0:  transform.ErrShortDst,
699         }},
700 }
701
702 func init() {
703         for rule, cases := range testCases {
704                 for i, tc := range cases {
705                         if tc.err == nil {
706                                 testCases[rule][i].n = len(tc.in)
707                         }
708                 }
709         }
710 }
711
712 func doTests(t *testing.T, fn func(t *testing.T, tc ruleTest)) {
713         for rule, cases := range testCases {
714                 for i, tc := range cases {
715                         name := fmt.Sprintf("%d/%d:%+q:%s", rule, i, tc.in, tc.in)
716                         testtext.Run(t, name, func(t *testing.T) {
717                                 fn(t, tc)
718                         })
719                 }
720         }
721 }
722
723 func TestDirection(t *testing.T) {
724         doTests(t, func(t *testing.T, tc ruleTest) {
725                 dir := Direction([]byte(tc.in))
726                 if dir != tc.dir {
727                         t.Errorf("dir was %v; want %v", dir, tc.dir)
728                 }
729         })
730 }
731
732 func TestDirectionString(t *testing.T) {
733         doTests(t, func(t *testing.T, tc ruleTest) {
734                 dir := DirectionString(tc.in)
735                 if dir != tc.dir {
736                         t.Errorf("dir was %v; want %v", dir, tc.dir)
737                 }
738         })
739 }
740
741 func TestValid(t *testing.T) {
742         doTests(t, func(t *testing.T, tc ruleTest) {
743                 got := Valid([]byte(tc.in))
744                 want := tc.err == nil
745                 if got != want {
746                         t.Fatalf("Valid: got %v; want %v", got, want)
747                 }
748
749                 got = ValidString(tc.in)
750                 want = tc.err == nil
751                 if got != want {
752                         t.Fatalf("Valid: got %v; want %v", got, want)
753                 }
754         })
755 }
756
757 func TestSpan(t *testing.T) {
758         doTests(t, func(t *testing.T, tc ruleTest) {
759                 // Skip tests that test for limited destination buffer size.
760                 if tc.szDst > 0 {
761                         return
762                 }
763
764                 r := New()
765                 src := []byte(tc.in)
766
767                 n, err := r.Span(src[:tc.pSrc], tc.pSrc == len(tc.in))
768                 if err != tc.err0 {
769                         t.Errorf("err0 was %v; want %v", err, tc.err0)
770                 }
771                 if n != tc.nSrc {
772                         t.Fatalf("nSrc was %d; want %d", n, tc.nSrc)
773                 }
774
775                 n, err = r.Span(src[n:], true)
776                 if err != tc.err {
777                         t.Errorf("error was %v; want %v", err, tc.err)
778                 }
779                 if got := n + tc.nSrc; got != tc.n {
780                         t.Errorf("n was %d; want %d", got, tc.n)
781                 }
782         })
783 }
784
785 func TestTransform(t *testing.T) {
786         doTests(t, func(t *testing.T, tc ruleTest) {
787                 r := New()
788
789                 src := []byte(tc.in)
790                 dst := make([]byte, len(tc.in))
791                 if tc.szDst > 0 {
792                         dst = make([]byte, tc.szDst)
793                 }
794
795                 // First transform operates on a zero-length string for most tests.
796                 nDst, nSrc, err := r.Transform(dst, src[:tc.pSrc], tc.pSrc == len(tc.in))
797                 if err != tc.err0 {
798                         t.Errorf("err0 was %v; want %v", err, tc.err0)
799                 }
800                 if nDst != nSrc {
801                         t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc)
802                 }
803                 if nSrc != tc.nSrc {
804                         t.Fatalf("nSrc was %d; want %d", nSrc, tc.nSrc)
805                 }
806
807                 dst1 := make([]byte, len(tc.in))
808                 copy(dst1, dst[:nDst])
809
810                 nDst, nSrc, err = r.Transform(dst1[nDst:], src[nSrc:], true)
811                 if err != tc.err {
812                         t.Errorf("error was %v; want %v", err, tc.err)
813                 }
814                 if nDst != nSrc {
815                         t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc)
816                 }
817                 n := nSrc + tc.nSrc
818                 if n != tc.n {
819                         t.Fatalf("n was %d; want %d", n, tc.n)
820                 }
821                 if got, want := string(dst1[:n]), tc.in[:tc.n]; got != want {
822                         t.Errorf("got %+q; want %+q", got, want)
823                 }
824         })
825 }