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 (at] gmail.com) 5 # Copyright (C) 2012 Daniel Bates (dbates (at] 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 } 806