Modified: trunk/Tools/Scripts/VCSUtils.pm (87640 => 87641)
--- trunk/Tools/Scripts/VCSUtils.pm 2011-05-29 19:13:46 UTC (rev 87640)
+++ trunk/Tools/Scripts/VCSUtils.pm 2011-05-29 19:38:46 UTC (rev 87641)
@@ -68,6 +68,7 @@
&makeFilePathRelative
&mergeChangeLogs
&normalizePath
+ &parseChunkRange
&parseFirstEOL
&parsePatch
&pathRelativeToSVNRepositoryRootForPath
@@ -98,7 +99,6 @@
# Project time zone for Cupertino, CA, US
my $changeLogTimeZone = "PST8PDT";
-my $chunkRangeRegEx = qr#^\@\@ -(\d+),(\d+) \+\d+,(\d+) \@\@#; # e.g. "@@ -2,6 +2,18 @@" or "@@ -2,6 +2,18 @@ foo()"
my $gitDiffStartRegEx = qr#^diff --git (\w/)?(.+) (\w/)?([^\r\n]+)#;
my $svnDiffStartRegEx = qr#^Index: ([^\r\n]+)#;
my $svnPropertiesStartRegEx = qr#^Property changes on: ([^\r\n]+)#; # $1 is normally the same as the index path.
@@ -485,6 +485,42 @@
return $eol;
}
+# Parses a chunk range line into its components.
+#
+# A chunk range line has the form: @@ -L_1,N_1 +L_2,N_2 @@, where the pairs (L_1, N_1),
+# (L_2, N_2) are ranges that represent the starting line number and line count in the
+# original file and new file, respectively.
+#
+# Note, some versions of GNU diff may omit the comma and trailing line count (e.g. N_1),
+# in which case the omitted line count defaults to 1. For example, GNU diff may output
+# @@ -1 +1 @@, which is equivalent to @@ -1,1 +1,1 @@.
+#
+# This subroutine returns undef if given an invalid or malformed chunk range.
+#
+# Args:
+# $line: the line to parse.
+#
+# Returns $chunkRangeHashRef
+# $chunkRangeHashRef: a hash reference representing the parts of a chunk range, as follows--
+# startingLine: the starting line in the original file.
+# lineCount: the line count in the original file.
+# newStartingLine: the new starting line in the new file.
+# newLineCount: the new line count in the new file.
+sub parseChunkRange($)
+{
+ my ($line) = @_;
+ my $chunkRangeRegEx = qr#^\@\@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? \@\@#;
+ if ($line !~ /$chunkRangeRegEx/) {
+ return;
+ }
+ my %chunkRange;
+ $chunkRange{startingLine} = $1;
+ $chunkRange{lineCount} = defined($2) ? $3 : 1;
+ $chunkRange{newStartingLine} = $4;
+ $chunkRange{newLineCount} = defined($5) ? $6 : 1;
+ return \%chunkRange;
+}
+
sub svnStatus($)
{
my ($fullPath) = @_;
@@ -905,8 +941,9 @@
}
if ($line !~ $headerStartRegEx) {
# Then we are in the body of the diff.
- $numTextChunks += $line =~ /$chunkRangeRegEx/;
- if ($indexPathEOL && $line !~ /$chunkRangeRegEx/) {
+ my $isChunkRange = defined(parseChunkRange($line));
+ $numTextChunks += 1 if $isChunkRange;
+ if ($indexPathEOL && !$isChunkRange) {
# The chunk range is part of the body of the diff, but its line endings should't be
# modified or patch(1) will complain. So, we only modify non-chunk range lines.
$line =~ s/\r\n|\r|\n/$indexPathEOL/g;
@@ -1500,15 +1537,16 @@
$deletedLineCount += $dateStartIndex - $chunkStartIndex;
# Update the initial chunk range.
- if ($lines[$chunkStartIndex - 1] !~ /$chunkRangeRegEx/) {
+ my $chunkRangeHashRef = parseChunkRange($lines[$chunkStartIndex - 1]);
+ if (!$chunkRangeHashRef) {
# FIXME: Handle errors differently from ChangeLog files that
# are okay but should not be altered. That way we can find out
# if improvements to the script ever become necessary.
$changeLogHashRef{patch} = $patch; # Error: unexpected patch string format.
return \%changeLogHashRef;
}
- my $oldSourceLineCount = $2;
- my $oldTargetLineCount = $3;
+ my $oldSourceLineCount = $chunkRangeHashRef->{lineCount};
+ my $oldTargetLineCount = $chunkRangeHashRef->{newLineCount};
my $sourceLineCount = $oldSourceLineCount + @overlappingLines - $deletedLineCount;
my $targetLineCount = $oldTargetLineCount + @overlappingLines - $deletedLineCount;
Added: trunk/Tools/Scripts/webkitperl/VCSUtils_unittest/parseChunkRange.pl (0 => 87641)
--- trunk/Tools/Scripts/webkitperl/VCSUtils_unittest/parseChunkRange.pl (rev 0)
+++ trunk/Tools/Scripts/webkitperl/VCSUtils_unittest/parseChunkRange.pl 2011-05-29 19:38:46 UTC (rev 87641)
@@ -0,0 +1,237 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2011 Research In Motion Limited. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek ([email protected])
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+# its contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Unit tests of VCSUtils::parseChunkRange().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+my @testCaseHashRefs = (
+###
+# Invalid and malformed chunk range
+##
+# FIXME: We should make this set of tests more comprehensive.
+{ # New test
+ testName => "[invalid] Empty string",
+ inputText => "",
+ expectedReturn => []
+},
+{ # New test
+ testName => "[invalid] Bogus chunk range",
+ inputText => "@@ this is not valid @@",
+ expectedReturn => []
+},
+{ # New test
+ testName => "[invalid] Chunk range missing -/+ prefix",
+ inputText => "@@ 0,0 1,4 @@",
+ expectedReturn => []
+},
+{ # New test
+ testName => "[invalid] Chunk range missing commas",
+ inputText => "@@ -0 0 +1 4 @@",
+ expectedReturn => []
+},
+{ # New test
+ testName => "[invalid] Chunk range with swapped old and rew ranges",
+ inputText => "@@ +0,0 -1,4 @@",
+ expectedReturn => []
+},
+{ # New test
+ testName => "[invalid] Chunk range with leading junk",
+ inputText => "leading junk @@ -0,0 +1,4 @@",
+ expectedReturn => []
+},
+###
+# Simple test cases
+##
+{ # New test
+ testName => "Line count is 0",
+ inputText => "@@ -0,0 +1,4 @@",
+ expectedReturn => [
+{
+ startingLine => 0,
+ lineCount => 0,
+ newStartingLine => 1,
+ newLineCount => 4,
+}
+]
+},
+{ # New test
+ testName => "Line count is 1",
+ inputText => "@@ -1 +1,4 @@",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 1,
+ newStartingLine => 1,
+ newLineCount => 4,
+}
+]
+},
+{ # New test
+ testName => "Both original and new line count is 1",
+ inputText => "@@ -1 +1 @@",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 1,
+ newStartingLine => 1,
+ newLineCount => 1,
+}
+]
+},
+{ # New test
+ testName => "Line count and new line count > 1",
+ inputText => "@@ -1,2 +1,4 @@",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 2,
+ newStartingLine => 1,
+ newLineCount => 4,
+}
+]
+},
+{ # New test
+ testName => "New line count is 0",
+ inputText => "@@ -1,4 +0,0 @@",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 4,
+ newStartingLine => 0,
+ newLineCount => 0,
+}
+]
+},
+{ # New test
+ testName => "New line count is 1",
+ inputText => "@@ -1,4 +1 @@",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 4,
+ newStartingLine => 1,
+ newLineCount => 1,
+}
+]
+},
+###
+# Chunk range followed by ending junk
+##
+{ # New test
+ testName => "Line count is 0 and chunk range has ending junk",
+ inputText => "@@ -0,0 +1,4 @@ foo()",
+ expectedReturn => [
+{
+ startingLine => 0,
+ lineCount => 0,
+ newStartingLine => 1,
+ newLineCount => 4,
+}
+]
+},
+{ # New test
+ testName => "Line count is 1 and chunk range has ending junk",
+ inputText => "@@ -1 +1,4 @@ foo()",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 1,
+ newStartingLine => 1,
+ newLineCount => 4,
+}
+]
+},
+{ # New test
+ testName => "Both original and new line count is 1 and chunk range has ending junk",
+ inputText => "@@ -1 +1 @@ foo()",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 1,
+ newStartingLine => 1,
+ newLineCount => 1,
+}
+]
+},
+{ # New test
+ testName => "Line count and new line count > 1 and chunk range has ending junk",
+ inputText => "@@ -1,2 +1,4 @@ foo()",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 2,
+ newStartingLine => 1,
+ newLineCount => 4,
+}
+]
+},
+{ # New test
+ testName => "New line count is 0 and chunk range has ending junk",
+ inputText => "@@ -1,4 +0,0 @@ foo()",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 4,
+ newStartingLine => 0,
+ newLineCount => 0,
+}
+]
+},
+{ # New test
+ testName => "New line count is 1 and chunk range has ending junk",
+ inputText => "@@ -1,4 +1 @@ foo()",
+ expectedReturn => [
+{
+ startingLine => 1,
+ lineCount => 4,
+ newStartingLine => 1,
+ newLineCount => 1,
+}
+]
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => $testCasesCount);
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "parseChunkRange(): $testCase->{testName}: comparing";
+
+ my @got = VCSUtils::parseChunkRange($testCase->{inputText});
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
+}