VCSUtils.pm doesn't support SVN 1.7 diff files
[WebKit-https.git] / Tools / Scripts / webkitperl / VCSUtils_unittest / parseSvnProperty.pl
1 #!/usr/bin/perl -w
2 #
3 # Copyright (C) Research in Motion Limited 2010. All Rights Reserved.
4 # Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
5 # Copyright (C) 2012 Daniel Bates (dbates@intudata.com)
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are
9 # met:
10 #
11 #     * Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 #     * Redistributions in binary form must reproduce the above
14 # copyright notice, this list of conditions and the following disclaimer
15 # in the documentation and/or other materials provided with the
16 # distribution.
17 #     * Neither the name of Apple Computer, Inc. ("Apple") nor the names of
18 # its contributors may be used to endorse or promote products derived
19 # from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
33 # Unit tests of parseSvnProperty().
34
35 use strict;
36 use warnings;
37
38 use Test::More;
39 use VCSUtils;
40
41 my @testCaseHashRefs = (
42 ####
43 # Simple test cases
44 ##
45 {
46     # New test
47     diffName => "simple: add svn:executable",
48     inputText => <<'END',
49 Added: svn:executable
50    + *
51 END
52     expectedReturn => [
53 {
54     name => "svn:executable",
55     propertyChangeDelta => 1,
56     value => "*",
57 },
58 undef],
59     expectedNextLine => undef,
60 },
61 {
62     # New test
63     diffName => "simple: delete svn:executable",
64     inputText => <<'END',
65 Deleted: svn:executable
66    - *
67 END
68     expectedReturn => [
69 {
70     name => "svn:executable",
71     propertyChangeDelta => -1,
72     value => "*",
73 },
74 undef],
75     expectedNextLine => undef,
76 },
77 {
78     # New test
79     diffName => "simple: add svn:mergeinfo",
80     inputText => <<'END',
81 Added: svn:mergeinfo
82    Merged /trunk/Makefile:r33020
83 END
84     expectedReturn => [
85 {
86     name => "svn:mergeinfo",
87     propertyChangeDelta => 1,
88     value => "/trunk/Makefile:r33020",
89 },
90 undef],
91     expectedNextLine => undef,
92 },
93 {
94     # New test
95     diffName => "simple: delete svn:mergeinfo",
96     inputText => <<'END',
97 Deleted: svn:mergeinfo
98    Reverse-merged /trunk/Makefile:r33020
99 END
100     expectedReturn => [
101 {
102     name => "svn:mergeinfo",
103     propertyChangeDelta => -1,
104     value => "/trunk/Makefile:r33020",
105 },
106 undef],
107     expectedNextLine => undef,
108 },
109 {
110     # New test
111     diffName => "simple: modified svn:mergeinfo",
112     inputText => <<'END',
113 Modified: svn:mergeinfo
114    Reverse-merged /trunk/Makefile:r33020
115    Merged /trunk/Makefile:r41697
116 END
117     expectedReturn => [
118 {
119     name => "svn:mergeinfo",
120     propertyChangeDelta => 1,
121     value => "/trunk/Makefile:r41697",
122 },
123 undef],
124     expectedNextLine => undef,
125 },
126 ####
127 # Using SVN 1.4 syntax
128 ##
129 {
130     # New test
131     diffName => "simple: modified svn:mergeinfo using SVN 1.4 syntax",
132     inputText => <<'END',
133 Name: svn:mergeinfo
134    Reverse-merged /trunk/Makefile:r33020
135    Merged /trunk/Makefile:r41697
136 END
137     expectedReturn => [
138 {
139     name => "svn:mergeinfo",
140     propertyChangeDelta => 1,
141     value => "/trunk/Makefile:r41697",
142 },
143 undef],
144     expectedNextLine => undef,
145 },
146 {
147     # New test
148     diffName => "simple: delete svn:executable using SVN 1.4 syntax",
149     inputText => <<'END',
150 Name: svn:executable
151    - *
152 END
153     expectedReturn => [
154 {
155     name => "svn:executable",
156     propertyChangeDelta => -1,
157     value => "*",
158 },
159 undef],
160     expectedNextLine => undef,
161 },
162 {
163     # New test
164     diffName => "simple: add svn:executable using SVN 1.4 syntax",
165     inputText => <<'END',
166 Name: svn:executable
167    + *
168 END
169     expectedReturn => [
170 {
171     name => "svn:executable",
172     propertyChangeDelta => 1,
173     value => "*",
174 },
175 undef],
176     expectedNextLine => undef,
177 },
178 ####
179 # Using SVN 1.7 syntax
180 ##
181 {
182     # New test
183     diffName => "simple: add svn:executable using SVN 1.7 syntax",
184     inputText => <<'END',
185 Added: svn:executable
186 ## -0,0 +1 ##
187 +*
188 \ No newline at end of property
189 END
190     expectedReturn => [
191 {
192     name => "svn:executable",
193     propertyChangeDelta => 1,
194     value => "*",
195 },
196 undef],
197     expectedNextLine => undef,
198 },
199 {
200     # New test
201     diffName => "simple: delete svn:executable using SVN 1.7 syntax",
202     inputText => <<'END',
203 Deleted: svn:executable
204 ## -1 +0,0 ##
205 -*
206 \ No newline at end of property
207 END
208     expectedReturn => [
209 {
210     name => "svn:executable",
211     propertyChangeDelta => -1,
212     value => "*",
213 },
214 undef],
215     expectedNextLine => undef,
216 },
217 {
218     # New test
219     diffName => "add svn:mime-type and add svn:executable using SVN 1.7 syntax",
220     inputText => <<'END',
221 Added: svn:mime-type
222 ## -0,0 +1 ##
223 +image/png
224 \ No newline at end of property
225 Added: svn:executable
226 ## -0,0 +1 ##
227 +*
228 \ No newline at end of property
229 END
230     expectedReturn => [
231 {
232     name => "svn:mime-type",
233     propertyChangeDelta => 1,
234     value => "image/png",
235 },
236 "Added: svn:executable\n"],
237     expectedNextLine => "## -0,0 +1 ##\n",
238 },
239 ####
240 # Property value followed by empty line and start of next diff
241 ##
242 {
243     # New test
244     diffName => "add svn:executable, followed by empty line and start of next diff",
245     inputText => <<'END',
246 Added: svn:executable
247    + *
248
249 Index: Makefile.shared
250 END
251     expectedReturn => [
252 {
253     name => "svn:executable",
254     propertyChangeDelta => 1,
255     value => "*",
256 },
257 "\n"],
258     expectedNextLine => "Index: Makefile.shared\n",
259 },
260 {
261     # New test
262     diffName => "add svn:executable, followed by empty line and start of next diff using Windows line endings",
263     inputText => toWindowsLineEndings(<<'END',
264 Added: svn:executable
265    + *
266
267 Index: Makefile.shared
268 END
269 ),
270     expectedReturn => [
271 {
272     name => "svn:executable",
273     propertyChangeDelta => 1,
274     value => "*",
275 },
276 "\r\n"],
277     expectedNextLine => "Index: Makefile.shared\r\n",
278 },
279 {
280     # New test
281     diffName => "add svn:executable, followed by empty line and start of next property diff",
282     inputText => <<'END',
283 Added: svn:executable
284    + *
285
286 Property changes on: Makefile.shared
287 END
288     expectedReturn => [
289 {
290     name => "svn:executable",
291     propertyChangeDelta => 1,
292     value => "*",
293 },
294 "\n"],
295     expectedNextLine => "Property changes on: Makefile.shared\n",
296 },
297 {
298     # New test
299     diffName => "add svn:executable, followed by empty line and start of next property diff using Windows line endings",
300     inputText => toWindowsLineEndings(<<'END',
301 Added: svn:executable
302    + *
303
304 Property changes on: Makefile.shared
305 END
306 ),
307     expectedReturn => [
308 {
309     name => "svn:executable",
310     propertyChangeDelta => 1,
311     value => "*",
312 },
313 "\r\n"],
314     expectedNextLine => "Property changes on: Makefile.shared\r\n",
315 },
316 {
317     # New test
318     diffName => "multi-line '+' change, followed by empty line and start of next diff",
319     inputText => <<'END',
320 Name: documentation
321    + A
322 long sentence that spans
323 multiple lines.
324
325 Index: Makefile.shared
326 END
327     expectedReturn => [
328 {
329     name => "documentation",
330     propertyChangeDelta => 1,
331     value => "A\nlong sentence that spans\nmultiple lines.",
332 },
333 "\n"],
334     expectedNextLine => "Index: Makefile.shared\n",
335 },
336 {
337     # New test
338     diffName => "multi-line '+' change, followed by empty line and start of next diff using Windows line endings",
339     inputText => toWindowsLineEndings(<<'END',
340 Name: documentation
341    + A
342 long sentence that spans
343 multiple lines.
344
345 Index: Makefile.shared
346 END
347 ),
348     expectedReturn => [
349 {
350     name => "documentation",
351     propertyChangeDelta => 1,
352     value => "A\r\nlong sentence that spans\r\nmultiple lines.",
353 },
354 "\r\n"],
355     expectedNextLine => "Index: Makefile.shared\r\n",
356 },
357 {
358     # New test
359     diffName => "multi-line '+' change, followed by empty line and start of next property diff",
360     inputText => <<'END',
361 Name: documentation
362    + A
363 long sentence that spans
364 multiple lines.
365
366 Property changes on: Makefile.shared
367 END
368     expectedReturn => [
369 {
370     name => "documentation",
371     propertyChangeDelta => 1,
372     value => "A\nlong sentence that spans\nmultiple lines.",
373 },
374 "\n"],
375     expectedNextLine => "Property changes on: Makefile.shared\n",
376 },
377 {
378     # New test
379     diffName => "multi-line '+' change, followed by empty line and start of next property diff using Windows line endings",
380     inputText => toWindowsLineEndings(<<'END',
381 Name: documentation
382    + A
383 long sentence that spans
384 multiple lines.
385
386 Property changes on: Makefile.shared
387 END
388 ),
389     expectedReturn => [
390 {
391     name => "documentation",
392     propertyChangeDelta => 1,
393     value => "A\r\nlong sentence that spans\r\nmultiple lines.",
394 },
395 "\r\n"],
396     expectedNextLine => "Property changes on: Makefile.shared\r\n",
397 },
398 ####
399 # Property value followed by empty line and start of binary patch
400 ##
401 {
402     # New test
403     diffName => "add svn:executable, followed by empty line and start of binary patch",
404     inputText => <<'END',
405 Added: svn:executable
406    + *
407
408 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
409 END
410     expectedReturn => [
411 {
412     name => "svn:executable",
413     propertyChangeDelta => 1,
414     value => "*",
415 },
416 "\n"],
417     expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
418 },
419 {
420     # New test
421     diffName => "add svn:executable, followed by empty line and start of binary patch using Windows line endings",
422     inputText => toWindowsLineEndings(<<'END',
423 Added: svn:executable
424    + *
425
426 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
427 END
428 ),
429     expectedReturn => [
430 {
431     name => "svn:executable",
432     propertyChangeDelta => 1,
433     value => "*",
434 },
435 "\r\n"],
436     expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\r\n",
437 },
438 {
439     # New test
440     diffName => "multi-line '+' change, followed by empty line and start of binary patch",
441     inputText => <<'END',
442 Name: documentation
443    + A
444 long sentence that spans
445 multiple lines.
446
447 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
448 END
449     expectedReturn => [
450 {
451     name => "documentation",
452     propertyChangeDelta => 1,
453     value => "A\nlong sentence that spans\nmultiple lines.",
454 },
455 "\n"],
456     expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
457 },
458 {
459     # New test
460     diffName => "multi-line '+' change, followed by empty line and start of binary patch using Windows line endings",
461     inputText => toWindowsLineEndings(<<'END',
462 Name: documentation
463    + A
464 long sentence that spans
465 multiple lines.
466
467 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
468 END
469 ),
470     expectedReturn => [
471 {
472     name => "documentation",
473     propertyChangeDelta => 1,
474     value => "A\r\nlong sentence that spans\r\nmultiple lines.",
475 },
476 "\r\n"],
477     expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\r\n",
478 },
479 {
480     # New test
481     diffName => "multi-line '-' change, followed by multi-line '+' change, empty line, and start of binary patch",
482     inputText => <<'END',
483 Modified: documentation
484    - A
485 long sentence that spans
486 multiple lines.
487    + Another
488 long sentence that spans
489 multiple lines.
490
491 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
492 END
493     expectedReturn => [
494 {
495     name => "documentation",
496     propertyChangeDelta => 1,
497     value => "Another\nlong sentence that spans\nmultiple lines.",
498 },
499 "\n"],
500     expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
501 },
502 {
503     # New test
504     diffName => "multi-line '-' change, followed by multi-line '+' change, empty line, and start of binary patch using Windows line endings",
505     inputText => toWindowsLineEndings(<<'END',
506 Modified: documentation
507    - A
508 long sentence that spans
509 multiple lines.
510    + Another
511 long sentence that spans
512 multiple lines.
513
514 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
515 END
516 ),
517     expectedReturn => [
518 {
519     name => "documentation",
520     propertyChangeDelta => 1,
521     value => "Another\r\nlong sentence that spans\r\nmultiple lines.",
522 },
523 "\r\n"],
524     expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\r\n",
525 },
526 ####
527 # Successive properties
528 ##
529 {
530     # New test
531     diffName => "single-line '+' change followed by custom property with single-line '+' change",
532     inputText => <<'END',
533 Added: svn:executable
534    + *
535 Added: documentation
536    + A sentence.
537 END
538     expectedReturn => [
539 {
540     name => "svn:executable",
541     propertyChangeDelta => 1,
542     value => "*",
543 },
544 "Added: documentation\n"],
545     expectedNextLine => "   + A sentence.\n",
546 },
547 {
548     # New test
549     diffName => "multi-line '+' change, followed by svn:executable",
550     inputText => <<'END',
551 Name: documentation
552    + A
553 long sentence that spans
554 multiple lines.
555 Name: svn:executable
556    + *
557 END
558     expectedReturn => [
559 {
560     name => "documentation",
561     propertyChangeDelta => 1,
562     value => "A\nlong sentence that spans\nmultiple lines.",
563 },
564 "Name: svn:executable\n"],
565     expectedNextLine => "   + *\n",
566 },
567 {
568     # New test
569     diffName => "multi-line '-' change, followed by multi-line '+' change and add svn:executable",
570     inputText => <<'END',
571 Modified: documentation
572    - A
573 long sentence that spans
574 multiple lines.
575    + Another
576 long sentence that spans
577 multiple lines.
578 Added: svn:executable
579    + *
580 END
581     expectedReturn => [
582 {
583     name => "documentation",
584     propertyChangeDelta => 1,
585     value => "Another\nlong sentence that spans\nmultiple lines.",
586 },
587 "Added: svn:executable\n"],
588     expectedNextLine => "   + *\n",
589 },
590 {
591     # New test
592     diffName => "'Merged' change followed by 'Merged' change",
593     inputText => <<'END',
594 Added: svn:mergeinfo
595    Merged /trunk/Makefile:r33020
596    Merged /trunk/Makefile.shared:r58350
597 END
598     expectedReturn => [
599 {
600     name => "svn:mergeinfo",
601     propertyChangeDelta => 1,
602     value => "/trunk/Makefile.shared:r58350",
603 },
604 undef],
605     expectedNextLine => undef,
606 },
607 {
608     # New test
609     diffName => "'Reverse-merged' change followed by 'Reverse-merged' change",
610     inputText => <<'END',
611 Deleted: svn:mergeinfo
612    Reverse-merged /trunk/Makefile:r33020
613    Reverse-merged /trunk/Makefile.shared:r58350
614 END
615     expectedReturn => [
616 {
617     name => "svn:mergeinfo",
618     propertyChangeDelta => -1,
619     value => "/trunk/Makefile.shared:r58350",
620 },
621 undef],
622     expectedNextLine => undef,
623 },
624 ####
625 # Property values with trailing new lines.
626 ##
627 # FIXME: We do not support property values with trailing new lines, since it is difficult to
628 #        disambiguate them from the empty line that preceeds the contents of a binary patch as
629 #        in the test case (above): "multi-line '+' change, followed by empty line and start of binary patch".
630 {
631     # New test
632     diffName => "single-line '+' with trailing new line",
633     inputText => <<'END',
634 Added: documentation
635    + A sentence.
636
637 END
638     expectedReturn => [
639 {
640     name => "documentation",
641     propertyChangeDelta => 1,
642     value => "A sentence.",
643 },
644 "\n"],
645     expectedNextLine => undef,
646 },
647 {
648     # New test
649     diffName => "single-line '+' with trailing new line using Windows line endings",
650     inputText => toWindowsLineEndings(<<'END',
651 Added: documentation
652    + A sentence.
653
654 END
655 ),
656     expectedReturn => [
657 {
658     name => "documentation",
659     propertyChangeDelta => 1,
660     value => "A sentence.",
661 },
662 "\r\n"],
663     expectedNextLine => undef,
664 },
665 {
666     # New test
667     diffName => "single-line '+' with trailing new line, followed by empty line and start of binary patch",
668     inputText => <<'END',
669 Added: documentation
670    + A sentence.
671
672
673 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
674 END
675     expectedReturn => [
676 {
677     name => "documentation",
678     propertyChangeDelta => 1,
679     value => "A sentence.",
680 },
681 "\n"],
682     expectedNextLine => "\n",
683 },
684 {
685     # New test
686     diffName => "single-line '+' with trailing new line, followed by empty line and start of binary patch using Windows line endings",
687     inputText => toWindowsLineEndings(<<'END',
688 Added: documentation
689    + A sentence.
690
691
692 Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
693 END
694 ),
695     expectedReturn => [
696 {
697     name => "documentation",
698     propertyChangeDelta => 1,
699     value => "A sentence.",
700 },
701 "\r\n"],
702     expectedNextLine => "\r\n",
703 },
704 {
705     # New test
706     diffName => "single-line '-' change with trailing new line, and single-line '+' change",
707     inputText => <<'END',
708 Modified: documentation
709    - A long sentence.
710
711    + A sentence.
712 END
713     expectedReturn => [
714 {
715     name => "documentation",
716     propertyChangeDelta => -1, # Since we only interpret the '-' property.
717     value => "A long sentence.",
718 },
719 "\n"],
720     expectedNextLine => "   + A sentence.\n",
721 },
722 {
723     # New test
724     diffName => "single-line '-' change with trailing new line, and single-line '+' change using Windows line endings",
725     inputText => toWindowsLineEndings(<<'END',
726 Modified: documentation
727    - A long sentence.
728
729    + A sentence.
730 END
731 ),
732     expectedReturn => [
733 {
734     name => "documentation",
735     propertyChangeDelta => -1, # Since we only interpret the '-' property.
736     value => "A long sentence.",
737 },
738 "\r\n"],
739     expectedNextLine => "   + A sentence.\r\n",
740 },
741 {
742     # New test
743     diffName => "multi-line '-' change with trailing new line, and multi-line '+' change",
744     inputText => <<'END',
745 Modified: documentation
746    - A
747 long sentence that spans
748 multiple lines.
749
750    + Another
751 long sentence that spans
752 multiple lines.
753 END
754     expectedReturn => [
755 {
756     name => "documentation",
757     propertyChangeDelta => -1, # Since we only interpret the '-' property.
758     value => "A\nlong sentence that spans\nmultiple lines.",
759 },
760 "\n"],
761     expectedNextLine => "   + Another\n",
762 },
763 {
764     # New test
765     diffName => "multi-line '-' change with trailing new line, and multi-line '+' change using Windows line endings",
766     inputText => toWindowsLineEndings(<<'END',
767 Modified: documentation
768    - A
769 long sentence that spans
770 multiple lines.
771
772    + Another
773 long sentence that spans
774 multiple lines.
775 END
776 ),
777     expectedReturn => [
778 {
779     name => "documentation",
780     propertyChangeDelta => -1, # Since we only interpret the '-' property.
781     value => "A\r\nlong sentence that spans\r\nmultiple lines.",
782 },
783 "\r\n"],
784     expectedNextLine => "   + Another\r\n",
785 },
786 );
787
788 my $testCasesCount = @testCaseHashRefs;
789 plan(tests => 2 * $testCasesCount); # Total number of assertions.
790
791 foreach my $testCase (@testCaseHashRefs) {
792     my $testNameStart = "parseSvnProperty(): $testCase->{diffName}: comparing";
793
794     my $fileHandle;
795     open($fileHandle, "<", \$testCase->{inputText});
796     my $line = <$fileHandle>;
797
798     my @got = VCSUtils::parseSvnProperty($fileHandle, $line);
799     my $expectedReturn = $testCase->{expectedReturn};
800
801     is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
802
803     my $gotNextLine = <$fileHandle>;
804     is($gotNextLine, $testCase->{expectedNextLine},  "$testNameStart next read line.");
805 }