blob: 4b6c612dc13f87c3e6a1dc8b8657d2b0bb7b24d9 [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// 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
5package bidirule
6
7import (
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
16const (
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
33type 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
46var 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: ErrInvalid,
124 n: len(strEN),
125 }, {
126 in: strES,
127 dir: bidi.LeftToRight,
128 err: ErrInvalid,
129 n: len(strES),
130 }, {
131 in: strET,
132 dir: bidi.LeftToRight,
133 err: ErrInvalid,
134 n: len(strET),
135 }, {
136 in: strCS,
137 dir: bidi.LeftToRight,
138 err: ErrInvalid,
139 n: len(strCS),
140 }, {
141 in: strNSM,
142 dir: bidi.LeftToRight,
143 err: ErrInvalid,
144 n: len(strNSM),
145 }, {
146 in: strBN,
147 dir: bidi.LeftToRight,
148 err: ErrInvalid,
149 n: len(strBN),
150 }, {
151 in: strB,
152 dir: bidi.LeftToRight,
153 err: ErrInvalid,
154 n: len(strB),
155 }, {
156 in: strS,
157 dir: bidi.LeftToRight,
158 err: ErrInvalid,
159 n: len(strS),
160 }, {
161 in: strWS,
162 dir: bidi.LeftToRight,
163 err: ErrInvalid,
164 n: len(strWS),
165 }, {
166 in: strON,
167 dir: bidi.LeftToRight,
168 err: ErrInvalid,
169 n: len(strON),
170 }, {
171 in: strEN + strR,
172 dir: bidi.RightToLeft,
173 err: ErrInvalid,
174 n: 3,
175 }, {
176 in: strES + strR,
177 dir: bidi.RightToLeft,
178 err: ErrInvalid,
179 n: 2,
180 }, {
181 in: strET + strR,
182 dir: bidi.RightToLeft,
183 err: ErrInvalid,
184 n: 1,
185 }, {
186 in: strCS + strR,
187 dir: bidi.RightToLeft,
188 err: ErrInvalid,
189 n: 1,
190 }, {
191 in: strNSM + strR,
192 dir: bidi.RightToLeft,
193 err: ErrInvalid,
194 n: 2,
195 }, {
196 in: strBN + strR,
197 dir: bidi.RightToLeft,
198 err: ErrInvalid,
199 n: 3,
200 }, {
201 in: strB + strR,
202 dir: bidi.RightToLeft,
203 err: ErrInvalid,
204 n: 3,
205 }, {
206 in: strS + strR,
207 dir: bidi.RightToLeft,
208 err: ErrInvalid,
209 n: 1,
210 }, {
211 in: strWS + strR,
212 dir: bidi.RightToLeft,
213 err: ErrInvalid,
214 n: 1,
215 }, {
216 in: strON + strR,
217 dir: bidi.RightToLeft,
218 err: ErrInvalid,
219 n: 1,
220 }},
221
222 // Rule 2.2: In an RTL label, only characters with the Bidi properties R,
223 // AL, AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
224 2: []ruleTest{{
225 in: strR + strR + strAL,
226 dir: bidi.RightToLeft,
227 }, {
228 in: strR + strAL + strR,
229 dir: bidi.RightToLeft,
230 }, {
231 in: strR + strAN + strAL,
232 dir: bidi.RightToLeft,
233 }, {
234 in: strR + strEN + strR,
235 dir: bidi.RightToLeft,
236 }, {
237 in: strR + strES + strR,
238 dir: bidi.RightToLeft,
239 }, {
240 in: strR + strCS + strR,
241 dir: bidi.RightToLeft,
242 }, {
243 in: strR + strET + strAL,
244 dir: bidi.RightToLeft,
245 }, {
246 in: strR + strON + strR,
247 dir: bidi.RightToLeft,
248 }, {
249 in: strR + strBN + strR,
250 dir: bidi.RightToLeft,
251 }, {
252 in: strR + strNSM + strAL,
253 dir: bidi.RightToLeft,
254 }, {
255 in: strR + strL + strR,
256 dir: bidi.RightToLeft,
257 n: len(strR),
258 err: ErrInvalid,
259 }, {
260 in: strR + strB + strR,
261 dir: bidi.RightToLeft,
262 n: len(strR),
263 err: ErrInvalid,
264 }, {
265 in: strR + strS + strAL,
266 dir: bidi.RightToLeft,
267 n: len(strR),
268 err: ErrInvalid,
269 }, {
270 in: strR + strWS + strAL,
271 dir: bidi.RightToLeft,
272 n: len(strR),
273 err: ErrInvalid,
274 }, {
275 in: strAL + strR + strAL,
276 dir: bidi.RightToLeft,
277 }, {
278 in: strAL + strAL + strR,
279 dir: bidi.RightToLeft,
280 }, {
281 in: strAL + strAN + strAL,
282 dir: bidi.RightToLeft,
283 }, {
284 in: strAL + strEN + strR,
285 dir: bidi.RightToLeft,
286 }, {
287 in: strAL + strES + strR,
288 dir: bidi.RightToLeft,
289 }, {
290 in: strAL + strCS + strR,
291 dir: bidi.RightToLeft,
292 }, {
293 in: strAL + strET + strAL,
294 dir: bidi.RightToLeft,
295 }, {
296 in: strAL + strON + strR,
297 dir: bidi.RightToLeft,
298 }, {
299 in: strAL + strBN + strR,
300 dir: bidi.RightToLeft,
301 }, {
302 in: strAL + strNSM + strAL,
303 dir: bidi.RightToLeft,
304 }, {
305 in: strAL + strL + strR,
306 dir: bidi.RightToLeft,
307 n: len(strAL),
308 err: ErrInvalid,
309 }, {
310 in: strAL + strB + strR,
311 dir: bidi.RightToLeft,
312 n: len(strAL),
313 err: ErrInvalid,
314 }, {
315 in: strAL + strS + strAL,
316 dir: bidi.RightToLeft,
317 n: len(strAL),
318 err: ErrInvalid,
319 }, {
320 in: strAL + strWS + strAL,
321 dir: bidi.RightToLeft,
322 n: len(strAL),
323 err: ErrInvalid,
324 }},
325
326 // Rule 2.3: In an RTL label, the end of the label must be a character with
327 // Bidi property R, AL, EN, or AN, followed by zero or more characters with
328 // Bidi property NSM.
329 3: []ruleTest{{
330 in: strR + strNSM,
331 dir: bidi.RightToLeft,
332 }, {
333 in: strR + strR,
334 dir: bidi.RightToLeft,
335 }, {
336 in: strR + strAL + strNSM,
337 dir: bidi.RightToLeft,
338 }, {
339 in: strR + strEN + strNSM + strNSM,
340 dir: bidi.RightToLeft,
341 }, {
342 in: strR + strAN,
343 dir: bidi.RightToLeft,
344 }, {
345 in: strR + strES + strNSM,
346 dir: bidi.RightToLeft,
347 n: len(strR + strES + strNSM),
348 err: ErrInvalid,
349 }, {
350 in: strR + strCS + strNSM + strNSM,
351 dir: bidi.RightToLeft,
352 n: len(strR + strCS + strNSM + strNSM),
353 err: ErrInvalid,
354 }, {
355 in: strR + strET,
356 dir: bidi.RightToLeft,
357 n: len(strR + strET),
358 err: ErrInvalid,
359 }, {
360 in: strR + strON + strNSM,
361 dir: bidi.RightToLeft,
362 n: len(strR + strON + strNSM),
363 err: ErrInvalid,
364 }, {
365 in: strR + strBN + strNSM + strNSM,
366 dir: bidi.RightToLeft,
367 n: len(strR + strBN + strNSM + strNSM),
368 err: ErrInvalid,
369 }, {
370 in: strR + strL + strNSM,
371 dir: bidi.RightToLeft,
372 n: len(strR),
373 err: ErrInvalid,
374 }, {
375 in: strR + strB + strNSM + strNSM,
376 dir: bidi.RightToLeft,
377 n: len(strR),
378 err: ErrInvalid,
379 }, {
380 in: strR + strS,
381 dir: bidi.RightToLeft,
382 n: len(strR),
383 err: ErrInvalid,
384 }, {
385 in: strR + strWS,
386 dir: bidi.RightToLeft,
387 n: len(strR),
388 err: ErrInvalid,
389 }, {
390 in: strAL + strNSM,
391 dir: bidi.RightToLeft,
392 }, {
393 in: strAL + strR,
394 dir: bidi.RightToLeft,
395 }, {
396 in: strAL + strAL + strNSM,
397 dir: bidi.RightToLeft,
398 }, {
399 in: strAL + strEN + strNSM + strNSM,
400 dir: bidi.RightToLeft,
401 }, {
402 in: strAL + strAN,
403 dir: bidi.RightToLeft,
404 }, {
405 in: strAL + strES + strNSM,
406 dir: bidi.RightToLeft,
407 n: len(strAL + strES + strNSM),
408 err: ErrInvalid,
409 }, {
410 in: strAL + strCS + strNSM + strNSM,
411 dir: bidi.RightToLeft,
412 n: len(strAL + strCS + strNSM + strNSM),
413 err: ErrInvalid,
414 }, {
415 in: strAL + strET,
416 dir: bidi.RightToLeft,
417 n: len(strAL + strET),
418 err: ErrInvalid,
419 }, {
420 in: strAL + strON + strNSM,
421 dir: bidi.RightToLeft,
422 n: len(strAL + strON + strNSM),
423 err: ErrInvalid,
424 }, {
425 in: strAL + strBN + strNSM + strNSM,
426 dir: bidi.RightToLeft,
427 n: len(strAL + strBN + strNSM + strNSM),
428 err: ErrInvalid,
429 }, {
430 in: strAL + strL + strNSM,
431 dir: bidi.RightToLeft,
432 n: len(strAL),
433 err: ErrInvalid,
434 }, {
435 in: strAL + strB + strNSM + strNSM,
436 dir: bidi.RightToLeft,
437 n: len(strAL),
438 err: ErrInvalid,
439 }, {
440 in: strAL + strS,
441 dir: bidi.RightToLeft,
442 n: len(strAL),
443 err: ErrInvalid,
444 }, {
445 in: strAL + strWS,
446 dir: bidi.RightToLeft,
447 n: len(strAL),
448 err: ErrInvalid,
449 }},
450
451 // Rule 2.4: In an RTL label, if an EN is present, no AN may be present,
452 // and vice versa.
453 4: []ruleTest{{
454 in: strR + strEN + strAN,
455 dir: bidi.RightToLeft,
456 n: len(strR + strEN),
457 err: ErrInvalid,
458 }, {
459 in: strR + strAN + strEN + strNSM,
460 dir: bidi.RightToLeft,
461 n: len(strR + strAN),
462 err: ErrInvalid,
463 }, {
464 in: strAL + strEN + strAN,
465 dir: bidi.RightToLeft,
466 n: len(strAL + strEN),
467 err: ErrInvalid,
468 }, {
469 in: strAL + strAN + strEN + strNSM,
470 dir: bidi.RightToLeft,
471 n: len(strAL + strAN),
472 err: ErrInvalid,
473 }},
474
475 // Rule 2.5: In an LTR label, only characters with the Bidi properties L,
476 // EN, ES, CS, ET, ON, BN, or NSM are allowed.
477 5: []ruleTest{{
478 in: strL + strL + strL,
479 dir: bidi.LeftToRight,
480 }, {
481 in: strL + strEN + strL,
482 dir: bidi.LeftToRight,
483 }, {
484 in: strL + strES + strL,
485 dir: bidi.LeftToRight,
486 }, {
487 in: strL + strCS + strL,
488 dir: bidi.LeftToRight,
489 }, {
490 in: strL + strET + strL,
491 dir: bidi.LeftToRight,
492 }, {
493 in: strL + strON + strL,
494 dir: bidi.LeftToRight,
495 }, {
496 in: strL + strBN + strL,
497 dir: bidi.LeftToRight,
498 }, {
499 in: strL + strNSM + strL,
500 dir: bidi.LeftToRight,
501 }, {
502 in: strL + strR + strL,
503 dir: bidi.RightToLeft,
504 n: len(strL),
505 err: ErrInvalid,
506 }, {
507 in: strL + strAL + strL,
508 dir: bidi.RightToLeft,
509 n: len(strL),
510 err: ErrInvalid,
511 }, {
512 in: strL + strAN + strL,
513 dir: bidi.RightToLeft,
514 n: len(strL),
515 err: ErrInvalid,
516 }, {
517 in: strL + strB + strL,
518 dir: bidi.LeftToRight,
519 n: len(strL + strB + strL),
520 err: ErrInvalid,
521 }, {
522 in: strL + strB + strL + strR,
523 dir: bidi.RightToLeft,
524 n: len(strL + strB + strL),
525 err: ErrInvalid,
526 }, {
527 in: strL + strS + strL,
528 dir: bidi.LeftToRight,
529 n: len(strL + strS + strL),
530 err: ErrInvalid,
531 }, {
532 in: strL + strS + strL + strR,
533 dir: bidi.RightToLeft,
534 n: len(strL + strS + strL),
535 err: ErrInvalid,
536 }, {
537 in: strL + strWS + strL,
538 dir: bidi.LeftToRight,
539 n: len(strL + strWS + strL),
540 err: ErrInvalid,
541 }, {
542 in: strL + strWS + strL + strR,
543 dir: bidi.RightToLeft,
544 n: len(strL + strWS + strL),
545 err: ErrInvalid,
546 }},
547
548 // Rule 2.6: In an LTR label, the end of the label must be a character with
549 // Bidi property L or EN, followed by zero or more characters with Bidi
550 // property NSM.
551 6: []ruleTest{{
552 in: strL,
553 dir: bidi.LeftToRight,
554 }, {
555 in: strL + strNSM,
556 dir: bidi.LeftToRight,
557 }, {
558 in: strL + strNSM + strNSM,
559 dir: bidi.LeftToRight,
560 }, {
561 in: strL + strEN,
562 dir: bidi.LeftToRight,
563 }, {
564 in: strL + strEN + strNSM,
565 dir: bidi.LeftToRight,
566 }, {
567 in: strL + strEN + strNSM + strNSM,
568 dir: bidi.LeftToRight,
569 }, {
570 in: strL + strES,
571 dir: bidi.LeftToRight,
572 n: len(strL + strES),
573 err: ErrInvalid,
574 }, {
575 in: strL + strES + strR,
576 dir: bidi.RightToLeft,
577 n: len(strL + strES),
578 err: ErrInvalid,
579 }, {
580 in: strL + strCS,
581 dir: bidi.LeftToRight,
582 n: len(strL + strCS),
583 err: ErrInvalid,
584 }, {
585 in: strL + strCS + strR,
586 dir: bidi.RightToLeft,
587 n: len(strL + strCS),
588 err: ErrInvalid,
589 }, {
590 in: strL + strET,
591 dir: bidi.LeftToRight,
592 n: len(strL + strET),
593 err: ErrInvalid,
594 }, {
595 in: strL + strET + strR,
596 dir: bidi.RightToLeft,
597 n: len(strL + strET),
598 err: ErrInvalid,
599 }, {
600 in: strL + strON,
601 dir: bidi.LeftToRight,
602 n: len(strL + strON),
603 err: ErrInvalid,
604 }, {
605 in: strL + strON + strR,
606 dir: bidi.RightToLeft,
607 n: len(strL + strON),
608 err: ErrInvalid,
609 }, {
610 in: strL + strBN,
611 dir: bidi.LeftToRight,
612 n: len(strL + strBN),
613 err: ErrInvalid,
614 }, {
615 in: strL + strBN + strR,
616 dir: bidi.RightToLeft,
617 n: len(strL + strBN),
618 err: ErrInvalid,
619 }, {
620 in: strL + strR,
621 dir: bidi.RightToLeft,
622 n: len(strL),
623 err: ErrInvalid,
624 }, {
625 in: strL + strAL,
626 dir: bidi.RightToLeft,
627 n: len(strL),
628 err: ErrInvalid,
629 }, {
630 in: strL + strAN,
631 dir: bidi.RightToLeft,
632 n: len(strL),
633 err: ErrInvalid,
634 }, {
635 in: strL + strB,
636 dir: bidi.LeftToRight,
637 n: len(strL + strB),
638 err: ErrInvalid,
639 }, {
640 in: strL + strB + strR,
641 dir: bidi.RightToLeft,
642 n: len(strL + strB),
643 err: ErrInvalid,
644 }, {
645 in: strL + strS,
646 dir: bidi.LeftToRight,
647 n: len(strL + strS),
648 err: ErrInvalid,
649 }, {
650 in: strL + strS + strR,
651 dir: bidi.RightToLeft,
652 n: len(strL + strS),
653 err: ErrInvalid,
654 }, {
655 in: strL + strWS,
656 dir: bidi.LeftToRight,
657 n: len(strL + strWS),
658 err: ErrInvalid,
659 }, {
660 in: strL + strWS + strR,
661 dir: bidi.RightToLeft,
662 n: len(strL + strWS),
663 err: ErrInvalid,
664 }},
665
666 // Incremental processing.
667 9: []ruleTest{{
668 in: "e\u0301", // é
669 dir: bidi.LeftToRight,
670
671 pSrc: 2,
672 nSrc: 1,
673 err0: transform.ErrShortSrc,
674 }, {
675 in: "e\u1000f", // é
676 dir: bidi.LeftToRight,
677
678 pSrc: 3,
679 nSrc: 1,
680 err0: transform.ErrShortSrc,
681 }, {
682 // Remain invalid once invalid.
683 in: strR + "ab",
684 dir: bidi.RightToLeft,
685 n: len(strR),
686 err: ErrInvalid,
687
688 pSrc: len(strR) + 1,
689 nSrc: len(strR),
690 err0: ErrInvalid,
691 }, {
692 // Short destination
693 in: "abcdefghij",
694 dir: bidi.LeftToRight,
695
696 pSrc: 10,
697 szDst: 5,
698 nSrc: 5,
699 err0: transform.ErrShortDst,
700 }, {
701 in: "\U000102f7",
702 dir: bidi.LeftToRight,
703 n: len("\U000102f7"),
704 err: ErrInvalid,
705 }, {
706 // Short destination splitting input rune
707 in: "e\u0301",
708 dir: bidi.LeftToRight,
709
710 pSrc: 3,
711 szDst: 2,
712 nSrc: 1,
713 err0: transform.ErrShortDst,
714 }, {
715 // Unicode 10.0.0 IDNA test string.
716 in: "FAX\u2a77\U0001d186",
717 dir: bidi.LeftToRight,
718 n: len("FAX\u2a77\U0001d186"),
719 err: ErrInvalid,
720 }, {
721 in: "\x80\u0660",
722 dir: bidi.RightToLeft,
723 n: 0,
724 err: ErrInvalid,
725 }},
726}
727
728func init() {
729 for rule, cases := range testCases {
730 for i, tc := range cases {
731 if tc.err == nil {
732 testCases[rule][i].n = len(tc.in)
733 }
734 }
735 }
736}
737
738func doTests(t *testing.T, fn func(t *testing.T, tc ruleTest)) {
739 for rule, cases := range testCases {
740 for i, tc := range cases {
741 name := fmt.Sprintf("%d/%d:%+q:%s", rule, i, tc.in, tc.in)
742 testtext.Run(t, name, func(t *testing.T) {
743 fn(t, tc)
744 })
745 }
746 }
747}
748
749func TestDirection(t *testing.T) {
750 doTests(t, func(t *testing.T, tc ruleTest) {
751 dir := Direction([]byte(tc.in))
752 if dir != tc.dir {
753 t.Errorf("dir was %v; want %v", dir, tc.dir)
754 }
755 })
756}
757
758func TestDirectionString(t *testing.T) {
759 doTests(t, func(t *testing.T, tc ruleTest) {
760 dir := DirectionString(tc.in)
761 if dir != tc.dir {
762 t.Errorf("dir was %v; want %v", dir, tc.dir)
763 }
764 })
765}
766
767func TestValid(t *testing.T) {
768 doTests(t, func(t *testing.T, tc ruleTest) {
769 got := Valid([]byte(tc.in))
770 want := tc.err == nil
771 if got != want {
772 t.Fatalf("Valid: got %v; want %v", got, want)
773 }
774
775 got = ValidString(tc.in)
776 want = tc.err == nil
777 if got != want {
778 t.Fatalf("Valid: got %v; want %v", got, want)
779 }
780 })
781}
782
783func TestSpan(t *testing.T) {
784 doTests(t, func(t *testing.T, tc ruleTest) {
785 // Skip tests that test for limited destination buffer size.
786 if tc.szDst > 0 {
787 return
788 }
789
790 r := New()
791 src := []byte(tc.in)
792
793 n, err := r.Span(src[:tc.pSrc], tc.pSrc == len(tc.in))
794 if err != tc.err0 {
795 t.Errorf("err0 was %v; want %v", err, tc.err0)
796 }
797 if n != tc.nSrc {
798 t.Fatalf("nSrc was %d; want %d", n, tc.nSrc)
799 }
800
801 n, err = r.Span(src[n:], true)
802 if err != tc.err {
803 t.Errorf("error was %v; want %v", err, tc.err)
804 }
805 if got := n + tc.nSrc; got != tc.n {
806 t.Errorf("n was %d; want %d", got, tc.n)
807 }
808 })
809}
810
811func TestTransform(t *testing.T) {
812 doTests(t, func(t *testing.T, tc ruleTest) {
813 r := New()
814
815 src := []byte(tc.in)
816 dst := make([]byte, len(tc.in))
817 if tc.szDst > 0 {
818 dst = make([]byte, tc.szDst)
819 }
820
821 // First transform operates on a zero-length string for most tests.
822 nDst, nSrc, err := r.Transform(dst, src[:tc.pSrc], tc.pSrc == len(tc.in))
823 if err != tc.err0 {
824 t.Errorf("err0 was %v; want %v", err, tc.err0)
825 }
826 if nDst != nSrc {
827 t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc)
828 }
829 if nSrc != tc.nSrc {
830 t.Fatalf("nSrc was %d; want %d", nSrc, tc.nSrc)
831 }
832
833 dst1 := make([]byte, len(tc.in))
834 copy(dst1, dst[:nDst])
835
836 nDst, nSrc, err = r.Transform(dst1[nDst:], src[nSrc:], true)
837 if err != tc.err {
838 t.Errorf("error was %v; want %v", err, tc.err)
839 }
840 if nDst != nSrc {
841 t.Fatalf("nDst (%d) and nSrc (%d) should match", nDst, nSrc)
842 }
843 n := nSrc + tc.nSrc
844 if n != tc.n {
845 t.Fatalf("n was %d; want %d", n, tc.n)
846 }
847 if got, want := string(dst1[:n]), tc.in[:tc.n]; got != want {
848 t.Errorf("got %+q; want %+q", got, want)
849 }
850 })
851}