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 35use strict; 36use warnings; 37 38use Test::More; 39use VCSUtils; 40 41my @testCaseHashRefs = ( 42#### 43# Simple test cases 44## 45{ 46 # New test 47 diffName => "simple: add svn:executable", 48 inputText => <<'END', 49Added: svn:executable 50 + * 51END 52 expectedReturn => [ 53{ 54 name => "svn:executable", 55 propertyChangeDelta => 1, 56 value => "*", 57}, 58undef], 59 expectedNextLine => undef, 60}, 61{ 62 # New test 63 diffName => "simple: delete svn:executable", 64 inputText => <<'END', 65Deleted: svn:executable 66 - * 67END 68 expectedReturn => [ 69{ 70 name => "svn:executable", 71 propertyChangeDelta => -1, 72 value => "*", 73}, 74undef], 75 expectedNextLine => undef, 76}, 77{ 78 # New test 79 diffName => "simple: add svn:mergeinfo", 80 inputText => <<'END', 81Added: svn:mergeinfo 82 Merged /trunk/Makefile:r33020 83END 84 expectedReturn => [ 85{ 86 name => "svn:mergeinfo", 87 propertyChangeDelta => 1, 88 value => "/trunk/Makefile:r33020", 89}, 90undef], 91 expectedNextLine => undef, 92}, 93{ 94 # New test 95 diffName => "simple: delete svn:mergeinfo", 96 inputText => <<'END', 97Deleted: svn:mergeinfo 98 Reverse-merged /trunk/Makefile:r33020 99END 100 expectedReturn => [ 101{ 102 name => "svn:mergeinfo", 103 propertyChangeDelta => -1, 104 value => "/trunk/Makefile:r33020", 105}, 106undef], 107 expectedNextLine => undef, 108}, 109{ 110 # New test 111 diffName => "simple: modified svn:mergeinfo", 112 inputText => <<'END', 113Modified: svn:mergeinfo 114 Reverse-merged /trunk/Makefile:r33020 115 Merged /trunk/Makefile:r41697 116END 117 expectedReturn => [ 118{ 119 name => "svn:mergeinfo", 120 propertyChangeDelta => 1, 121 value => "/trunk/Makefile:r41697", 122}, 123undef], 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', 133Name: svn:mergeinfo 134 Reverse-merged /trunk/Makefile:r33020 135 Merged /trunk/Makefile:r41697 136END 137 expectedReturn => [ 138{ 139 name => "svn:mergeinfo", 140 propertyChangeDelta => 1, 141 value => "/trunk/Makefile:r41697", 142}, 143undef], 144 expectedNextLine => undef, 145}, 146{ 147 # New test 148 diffName => "simple: delete svn:executable using SVN 1.4 syntax", 149 inputText => <<'END', 150Name: svn:executable 151 - * 152END 153 expectedReturn => [ 154{ 155 name => "svn:executable", 156 propertyChangeDelta => -1, 157 value => "*", 158}, 159undef], 160 expectedNextLine => undef, 161}, 162{ 163 # New test 164 diffName => "simple: add svn:executable using SVN 1.4 syntax", 165 inputText => <<'END', 166Name: svn:executable 167 + * 168END 169 expectedReturn => [ 170{ 171 name => "svn:executable", 172 propertyChangeDelta => 1, 173 value => "*", 174}, 175undef], 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', 185Added: svn:executable 186## -0,0 +1 ## 187+* 188\ No newline at end of property 189END 190 expectedReturn => [ 191{ 192 name => "svn:executable", 193 propertyChangeDelta => 1, 194 value => "*", 195}, 196undef], 197 expectedNextLine => undef, 198}, 199{ 200 # New test 201 diffName => "simple: delete svn:executable using SVN 1.7 syntax", 202 inputText => <<'END', 203Deleted: svn:executable 204## -1 +0,0 ## 205-* 206\ No newline at end of property 207END 208 expectedReturn => [ 209{ 210 name => "svn:executable", 211 propertyChangeDelta => -1, 212 value => "*", 213}, 214undef], 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', 221Added: svn:mime-type 222## -0,0 +1 ## 223+image/png 224\ No newline at end of property 225Added: svn:executable 226## -0,0 +1 ## 227+* 228\ No newline at end of property 229END 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', 246Added: svn:executable 247 + * 248 249Index: Makefile.shared 250END 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', 264Added: svn:executable 265 + * 266 267Index: Makefile.shared 268END 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', 283Added: svn:executable 284 + * 285 286Property changes on: Makefile.shared 287END 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', 301Added: svn:executable 302 + * 303 304Property changes on: Makefile.shared 305END 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', 320Name: documentation 321 + A 322long sentence that spans 323multiple lines. 324 325Index: Makefile.shared 326END 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', 340Name: documentation 341 + A 342long sentence that spans 343multiple lines. 344 345Index: Makefile.shared 346END 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', 361Name: documentation 362 + A 363long sentence that spans 364multiple lines. 365 366Property changes on: Makefile.shared 367END 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', 381Name: documentation 382 + A 383long sentence that spans 384multiple lines. 385 386Property changes on: Makefile.shared 387END 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', 405Added: svn:executable 406 + * 407 408Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== 409END 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', 423Added: svn:executable 424 + * 425 426Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== 427END 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', 442Name: documentation 443 + A 444long sentence that spans 445multiple lines. 446 447Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== 448END 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', 462Name: documentation 463 + A 464long sentence that spans 465multiple lines. 466 467Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== 468END 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', 483Modified: documentation 484 - A 485long sentence that spans 486multiple lines. 487 + Another 488long sentence that spans 489multiple lines. 490 491Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== 492END 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', 506Modified: documentation 507 - A 508long sentence that spans 509multiple lines. 510 + Another 511long sentence that spans 512multiple lines. 513 514Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== 515END 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', 533Added: svn:executable 534 + * 535Added: documentation 536 + A sentence. 537END 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', 551Name: documentation 552 + A 553long sentence that spans 554multiple lines. 555Name: svn:executable 556 + * 557END 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', 571Modified: documentation 572 - A 573long sentence that spans 574multiple lines. 575 + Another 576long sentence that spans 577multiple lines. 578Added: svn:executable 579 + * 580END 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', 594Added: svn:mergeinfo 595 Merged /trunk/Makefile:r33020 596 Merged /trunk/Makefile.shared:r58350 597END 598 expectedReturn => [ 599{ 600 name => "svn:mergeinfo", 601 propertyChangeDelta => 1, 602 value => "/trunk/Makefile.shared:r58350", 603}, 604undef], 605 expectedNextLine => undef, 606}, 607{ 608 # New test 609 diffName => "'Reverse-merged' change followed by 'Reverse-merged' change", 610 inputText => <<'END', 611Deleted: svn:mergeinfo 612 Reverse-merged /trunk/Makefile:r33020 613 Reverse-merged /trunk/Makefile.shared:r58350 614END 615 expectedReturn => [ 616{ 617 name => "svn:mergeinfo", 618 propertyChangeDelta => -1, 619 value => "/trunk/Makefile.shared:r58350", 620}, 621undef], 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', 634Added: documentation 635 + A sentence. 636 637END 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', 651Added: documentation 652 + A sentence. 653 654END 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', 669Added: documentation 670 + A sentence. 671 672 673Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== 674END 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', 688Added: documentation 689 + A sentence. 690 691 692Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== 693END 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', 708Modified: documentation 709 - A long sentence. 710 711 + A sentence. 712END 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', 726Modified: documentation 727 - A long sentence. 728 729 + A sentence. 730END 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', 745Modified: documentation 746 - A 747long sentence that spans 748multiple lines. 749 750 + Another 751long sentence that spans 752multiple lines. 753END 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', 767Modified: documentation 768 - A 769long sentence that spans 770multiple lines. 771 772 + Another 773long sentence that spans 774multiple lines. 775END 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 788my $testCasesCount = @testCaseHashRefs; 789plan(tests => 2 * $testCasesCount); # Total number of assertions. 790 791foreach 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