Skip to content

Commit 8df661f

Browse files
committed
Further to issue dnaumenko#20: corresponding fix to generateUnifiedDiff()
DiffUtils.generateUnifiedDiff() produced off-by-one positions for hunks with empty context/content. EmptyContextUnifiedDiffTest.java has been improved to test for this. (Some test resource files renamed in light of more general use).
1 parent 1d6d7c6 commit 8df661f

File tree

5 files changed

+65
-32
lines changed

5 files changed

+65
-32
lines changed

src/main/java/difflib/DiffUtils.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,14 @@ private static List<String> processDeltas(List<String> origLines,
384384
revTotal++;
385385
}
386386

387+
// In case of empty chunk and context
388+
if (origTotal == 0 && origStart > 1)
389+
--origStart;
390+
391+
// In case of empty chunk and context
392+
if (revTotal == 0 && revStart > 1)
393+
--revStart;
394+
387395
// Create and insert the block header, conforming to the Unified Diff
388396
// standard
389397
StringBuffer header = new StringBuffer();
Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package diffutils;
22

33
import java.io.BufferedReader;
4-
import java.io.File;
54
import java.io.FileReader;
65
import java.io.IOException;
76
import java.util.LinkedList;
@@ -18,48 +17,74 @@ public class EmptyContextUnifiedDiffTest extends TestCase {
1817
public List<String> fileToLines(String filename) {
1918
List<String> lines = new LinkedList<String>();
2019
String line = "";
20+
BufferedReader in = null;
2121
try {
22-
BufferedReader in = new BufferedReader(new FileReader(filename));
22+
in = new BufferedReader(new FileReader(filename));
2323
while ((line = in.readLine()) != null) {
2424
lines.add(line);
2525
}
2626
} catch (IOException e) {
2727
e.printStackTrace();
2828
fail(e.getMessage());
29+
} finally {
30+
if (in != null) {
31+
try {
32+
in.close();
33+
} catch (IOException e) {
34+
// ignore ... any errors should already have been
35+
// reported via an IOException from the final flush.
36+
}
37+
}
2938
}
3039
return lines;
3140
}
3241

33-
public void testUnifiedContextInsert() {
34-
testUnifiedContextXXX(TestConstants.MOCK_FOLDER + "uc_insert_patch.txt", TestConstants.MOCK_FOLDER
35-
+ "uc_insert_revised.txt");
42+
public void testEmptyUnifiedContextPatch() {
43+
List<String> origLines = fileToLines(TestConstants.MOCK_FOLDER + "unified_empty_context_original.txt");
44+
List<String> revLines = fileToLines(TestConstants.MOCK_FOLDER + "unified_empty_context_revised.txt");
45+
List<String> unifiedDiff = fileToLines(TestConstants.MOCK_FOLDER + "unified_empty_context_patch.txt");
46+
47+
List<String> patchedLines = null;
48+
Patch patch = DiffUtils.parseUnifiedDiff(unifiedDiff);
49+
50+
try {
51+
patchedLines = (List<String>) patch.applyTo(origLines);
52+
} catch (PatchFailedException e) {
53+
fail(e.getMessage());
54+
}
55+
56+
verifyLinesEqual(patchedLines, revLines);
57+
}
58+
59+
public void testEmptyUnifiedContextDiff() {
60+
List<String> origLines = fileToLines(TestConstants.MOCK_FOLDER + "unified_empty_context_original.txt");
61+
List<String> revLines = fileToLines(TestConstants.MOCK_FOLDER + "unified_empty_context_revised.txt");
62+
63+
List<String> patchedLines = null;
64+
65+
// Generate a 0-context diff then reapply
66+
Patch generatedPatch = DiffUtils.diff(origLines, revLines);
67+
List<String> generatedDiff = DiffUtils.generateUnifiedDiff("original", "revised", origLines, generatedPatch, 0);
68+
Patch newPatch = DiffUtils.parseUnifiedDiff(generatedDiff);
69+
70+
try {
71+
patchedLines = (List<String>) newPatch.applyTo(origLines);
72+
} catch (PatchFailedException e) {
73+
fail(e.getMessage());
74+
}
75+
76+
verifyLinesEqual(patchedLines, revLines);
77+
}
78+
79+
public void verifyLinesEqual(List<String> patchedLines, List<String> revLines) {
80+
assertTrue(revLines.size() == patchedLines.size());
81+
for (int i = 0; i < revLines.size(); i++) {
82+
String l1 = revLines.get(i);
83+
String l2 = patchedLines.get(i);
84+
if (!l1.equals(l2)) {
85+
fail("Line " + (i + 1) + " of the patched file did not match the revised original");
86+
}
87+
}
3688
}
3789

38-
public void testUnifiedContextXXX(String patch_file, String revised_file) {
39-
List<String> origLines = fileToLines(TestConstants.MOCK_FOLDER + "uc_original.txt");
40-
List<String> revLines = fileToLines(revised_file);
41-
List<String> unifiedDiff = fileToLines(patch_file);
42-
List<String> patchedLines = null;
43-
Patch patch = DiffUtils.parseUnifiedDiff(unifiedDiff);
44-
45-
try {
46-
patchedLines = (List<String>) patch.applyTo(origLines);
47-
} catch (PatchFailedException e) {
48-
fail(e.getMessage());
49-
}
50-
51-
verifyLinesEqual(patchedLines, revLines);
52-
}
53-
54-
public void verifyLinesEqual(List<String> patchedLines, List<String> revLines) {
55-
assertTrue(revLines.size() == patchedLines.size());
56-
for (int i = 0; i < revLines.size(); i++) {
57-
String l1 = revLines.get(i);
58-
String l2 = patchedLines.get(i);
59-
if (!l1.equals(l2)) {
60-
fail("Line " + (i + 1) + " of the patched file did not match the revised original");
61-
}
62-
}
63-
}
64-
6590
}
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)