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