Home | History | Annotate | Download | only in VCSUtils_unittest
      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