mirror of
https://github.com/java-diff-utils/java-diff-utils.git
synced 2026-03-13 10:11:17 +08:00
Compare commits
11 Commits
java-diff-
...
java-diff-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fd3bd8e06 | ||
|
|
eeb819cad4 | ||
|
|
e73742c4fc | ||
|
|
0545519fc3 | ||
|
|
bc65f9703c | ||
|
|
ea9942da12 | ||
|
|
8fdd239961 | ||
|
|
37f9eafaa9 | ||
|
|
0fd38db8ae | ||
|
|
3663cb5d87 | ||
|
|
8ae1f6cbbf |
8
.github/release.yml
vendored
Normal file
8
.github/release.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
changelog:
|
||||||
|
categories:
|
||||||
|
- title: Bugs solved
|
||||||
|
labels:
|
||||||
|
- "bug"
|
||||||
|
- title: Changes and new Features
|
||||||
|
labels:
|
||||||
|
- "*"
|
||||||
@@ -89,7 +89,7 @@ Just add the code below to your maven dependencies:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.github.java-diff-utils</groupId>
|
<groupId>io.github.java-diff-utils</groupId>
|
||||||
<artifactId>java-diff-utils</artifactId>
|
<artifactId>java-diff-utils</artifactId>
|
||||||
<version>4.9</version>
|
<version>4.11</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -97,5 +97,5 @@ or using gradle:
|
|||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
// https://mvnrepository.com/artifact/io.github.java-diff-utils/java-diff-utils
|
// https://mvnrepository.com/artifact/io.github.java-diff-utils/java-diff-utils
|
||||||
implementation "io.github.java-diff-utils:java-diff-utils:4.5"
|
implementation "io.github.java-diff-utils:java-diff-utils:4.11"
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>io.github.java-diff-utils</groupId>
|
<groupId>io.github.java-diff-utils</groupId>
|
||||||
<artifactId>java-diff-utils-parent</artifactId>
|
<artifactId>java-diff-utils-parent</artifactId>
|
||||||
<version>4.11</version>
|
<version>4.12</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>java-diff-utils-jgit</artifactId>
|
<artifactId>java-diff-utils-jgit</artifactId>
|
||||||
<name>java-diff-utils-jgit</name>
|
<name>java-diff-utils-jgit</name>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>io.github.java-diff-utils</groupId>
|
<groupId>io.github.java-diff-utils</groupId>
|
||||||
<artifactId>java-diff-utils-parent</artifactId>
|
<artifactId>java-diff-utils-parent</artifactId>
|
||||||
<version>4.11</version>
|
<version>4.12</version>
|
||||||
</parent>
|
</parent>
|
||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
|||||||
@@ -70,6 +70,19 @@ public abstract class AbstractDelta<T> implements Serializable {
|
|||||||
|
|
||||||
protected abstract void restore(List<T> target);
|
protected abstract void restore(List<T> target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply patch fuzzy.
|
||||||
|
*
|
||||||
|
* @param target the list this patch will be applied to
|
||||||
|
* @param fuzz the number of elements to ignore before/after the patched elements
|
||||||
|
* @param position the position this patch will be applied to. ignores {@code source.getPosition()}
|
||||||
|
* @see <a href="https://www.gnu.org/software/diffutils/manual/html_node/Inexact.html">Description of Fuzzy Patch</a> for more information.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("RedundantThrows")
|
||||||
|
protected void applyFuzzyToAt(List<T> target, int fuzz, int position) throws PatchFailedException {
|
||||||
|
throw new UnsupportedOperationException(this.getClass().getSimpleName() + " does not supports applying patch fuzzy");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new delta of the actual instance with customized chunk data.
|
* Create a new delta of the actual instance with customized chunk data.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -66,6 +66,19 @@ public final class ChangeDelta<T> extends AbstractDelta<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void applyFuzzyToAt(List<T> target, int fuzz, int position) throws PatchFailedException {
|
||||||
|
int size = getSource().size();
|
||||||
|
for (int i = fuzz; i < size - fuzz; i++) {
|
||||||
|
target.remove(position + fuzz);
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = fuzz;
|
||||||
|
for (T line : getTarget().getLines().subList(fuzz, getTarget().size() - fuzz)) {
|
||||||
|
target.add(position + i, line);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[ChangeDelta, position: " + getSource().getPosition() + ", lines: "
|
return "[ChangeDelta, position: " + getSource().getPosition() + ", lines: "
|
||||||
|
|||||||
@@ -95,10 +95,28 @@ public final class Chunk<T> implements Serializable {
|
|||||||
* @throws com.github.difflib.patch.PatchFailedException
|
* @throws com.github.difflib.patch.PatchFailedException
|
||||||
*/
|
*/
|
||||||
public VerifyChunk verifyChunk(List<T> target) throws PatchFailedException {
|
public VerifyChunk verifyChunk(List<T> target) throws PatchFailedException {
|
||||||
if (position > target.size() || last() > target.size()) {
|
return verifyChunk(target, 0, getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies that this chunk's saved text matches the corresponding text in
|
||||||
|
* the given sequence.
|
||||||
|
*
|
||||||
|
* @param target the sequence to verify against.
|
||||||
|
* @param fuzz the count of ignored prefix/suffix
|
||||||
|
* @param position the position of target
|
||||||
|
* @throws com.github.difflib.patch.PatchFailedException
|
||||||
|
*/
|
||||||
|
public VerifyChunk verifyChunk(List<T> target, int fuzz, int position) throws PatchFailedException {
|
||||||
|
//noinspection UnnecessaryLocalVariable
|
||||||
|
int startIndex = fuzz;
|
||||||
|
int lastIndex = size() - fuzz;
|
||||||
|
int last = position + size() - 1;
|
||||||
|
|
||||||
|
if (position + fuzz > target.size() || last - fuzz > target.size()) {
|
||||||
return VerifyChunk.POSITION_OUT_OF_TARGET;
|
return VerifyChunk.POSITION_OUT_OF_TARGET;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < size(); i++) {
|
for (int i = startIndex; i < lastIndex; i++) {
|
||||||
if (!target.get(position + i).equals(lines.get(i))) {
|
if (!target.get(position + i).equals(lines.get(i))) {
|
||||||
return VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET;
|
return VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,14 @@ public class EqualDelta<T> extends AbstractDelta<T> {
|
|||||||
protected void restore(List<T> target) {
|
protected void restore(List<T> target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void applyFuzzyToAt(List<T> target, int fuzz, int delta) {
|
||||||
|
// equals so no operations
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "[EqualDelta, position: " + getSource().getPosition() + ", lines: "
|
return "[EqualDelta, position: " + getSource().getPosition() + ", lines: "
|
||||||
|
|||||||
@@ -66,6 +66,117 @@ public final class Patch<T> implements Serializable {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class PatchApplyingContext<T> {
|
||||||
|
public final List<T> result;
|
||||||
|
public final int maxFuzz;
|
||||||
|
|
||||||
|
// the position last patch applied to.
|
||||||
|
public int lastPatchEnd = -1;
|
||||||
|
|
||||||
|
///// passing values from find to apply
|
||||||
|
public int currentFuzz = 0;
|
||||||
|
|
||||||
|
public int defaultPosition;
|
||||||
|
public boolean beforeOutRange = false;
|
||||||
|
public boolean afterOutRange = false;
|
||||||
|
|
||||||
|
private PatchApplyingContext(List<T> result, int maxFuzz) {
|
||||||
|
this.result = result;
|
||||||
|
this.maxFuzz = maxFuzz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<T> applyFuzzy(List<T> target, int maxFuzz) throws PatchFailedException {
|
||||||
|
PatchApplyingContext<T> ctx = new PatchApplyingContext<>(new ArrayList<>(target), maxFuzz);
|
||||||
|
|
||||||
|
// the difference between patch's position and actually applied position
|
||||||
|
int lastPatchDelta = 0;
|
||||||
|
|
||||||
|
for (AbstractDelta<T> delta : getDeltas()) {
|
||||||
|
ctx.defaultPosition = delta.getSource().getPosition() + lastPatchDelta;
|
||||||
|
int patchPosition = findPositionFuzzy(ctx, delta);
|
||||||
|
if (0 <= patchPosition) {
|
||||||
|
delta.applyFuzzyToAt(ctx.result, ctx.currentFuzz, patchPosition);
|
||||||
|
lastPatchDelta = patchPosition - delta.getSource().getPosition();
|
||||||
|
ctx.lastPatchEnd = delta.getSource().last() + lastPatchDelta;
|
||||||
|
} else {
|
||||||
|
conflictOutput.processConflict(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET, delta, ctx.result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// negative for not found
|
||||||
|
private int findPositionFuzzy(PatchApplyingContext<T> ctx, AbstractDelta<T> delta) throws PatchFailedException {
|
||||||
|
for (int fuzz = 0; fuzz <= ctx.maxFuzz; fuzz++) {
|
||||||
|
ctx.currentFuzz = fuzz;
|
||||||
|
int foundPosition = findPositionWithFuzz(ctx, delta, fuzz);
|
||||||
|
if (foundPosition >= 0) {
|
||||||
|
return foundPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// negative for not found
|
||||||
|
private int findPositionWithFuzz(PatchApplyingContext<T> ctx, AbstractDelta<T> delta, int fuzz) throws PatchFailedException {
|
||||||
|
if (delta.getSource().verifyChunk(ctx.result, fuzz, ctx.defaultPosition) == VerifyChunk.OK) {
|
||||||
|
return ctx.defaultPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.beforeOutRange = false;
|
||||||
|
ctx.afterOutRange = false;
|
||||||
|
|
||||||
|
// moreDelta >= 0: just for overflow guard, not a normal condition
|
||||||
|
//noinspection OverflowingLoopIndex
|
||||||
|
for (int moreDelta = 0; moreDelta >= 0; moreDelta++) {
|
||||||
|
int pos = findPositionWithFuzzAndMoreDelta(ctx, delta, fuzz, moreDelta);
|
||||||
|
if (pos >= 0) {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
if (ctx.beforeOutRange && ctx.afterOutRange) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// negative for not found
|
||||||
|
private int findPositionWithFuzzAndMoreDelta(PatchApplyingContext<T> ctx, AbstractDelta<T> delta, int fuzz, int moreDelta) throws PatchFailedException {
|
||||||
|
// range check: can't apply before end of last patch
|
||||||
|
if (!ctx.beforeOutRange) {
|
||||||
|
int beginAt = ctx.defaultPosition - moreDelta + fuzz;
|
||||||
|
// We can't apply patch before end of last patch.
|
||||||
|
if (beginAt <= ctx.lastPatchEnd) {
|
||||||
|
ctx.beforeOutRange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// range check: can't apply after end of result
|
||||||
|
if (!ctx.afterOutRange) {
|
||||||
|
int beginAt = ctx.defaultPosition + moreDelta + delta.getSource().size() - fuzz;
|
||||||
|
// We can't apply patch before end of last patch.
|
||||||
|
if (ctx.result.size() < beginAt) {
|
||||||
|
ctx.afterOutRange = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx.beforeOutRange) {
|
||||||
|
VerifyChunk before = delta.getSource().verifyChunk(ctx.result, fuzz, ctx.defaultPosition - moreDelta);
|
||||||
|
if (before == VerifyChunk.OK) {
|
||||||
|
return ctx.defaultPosition - moreDelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ctx.afterOutRange) {
|
||||||
|
VerifyChunk after = delta.getSource().verifyChunk(ctx.result, fuzz, ctx.defaultPosition + moreDelta);
|
||||||
|
if (after == VerifyChunk.OK) {
|
||||||
|
return ctx.defaultPosition + moreDelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard Patch behaviour to throw an exception for pathching conflicts.
|
* Standard Patch behaviour to throw an exception for pathching conflicts.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ public final class DiffRowGenerator {
|
|||||||
|
|
||||||
private final boolean showInlineDiffs;
|
private final boolean showInlineDiffs;
|
||||||
private final boolean replaceOriginalLinefeedInChangesWithSpaces;
|
private final boolean replaceOriginalLinefeedInChangesWithSpaces;
|
||||||
|
private final boolean decompressDeltas;
|
||||||
|
|
||||||
private DiffRowGenerator(Builder builder) {
|
private DiffRowGenerator(Builder builder) {
|
||||||
showInlineDiffs = builder.showInlineDiffs;
|
showInlineDiffs = builder.showInlineDiffs;
|
||||||
@@ -182,6 +183,7 @@ public final class DiffRowGenerator {
|
|||||||
columnWidth = builder.columnWidth;
|
columnWidth = builder.columnWidth;
|
||||||
mergeOriginalRevised = builder.mergeOriginalRevised;
|
mergeOriginalRevised = builder.mergeOriginalRevised;
|
||||||
inlineDiffSplitter = builder.inlineDiffSplitter;
|
inlineDiffSplitter = builder.inlineDiffSplitter;
|
||||||
|
decompressDeltas = builder.decompressDeltas;
|
||||||
|
|
||||||
if (builder.equalizer != null) {
|
if (builder.equalizer != null) {
|
||||||
equalizer = builder.equalizer;
|
equalizer = builder.equalizer;
|
||||||
@@ -225,8 +227,14 @@ public final class DiffRowGenerator {
|
|||||||
int endPos = 0;
|
int endPos = 0;
|
||||||
final List<AbstractDelta<String>> deltaList = patch.getDeltas();
|
final List<AbstractDelta<String>> deltaList = patch.getDeltas();
|
||||||
|
|
||||||
for (AbstractDelta<String> originalDelta : deltaList) {
|
if (decompressDeltas) {
|
||||||
for (AbstractDelta<String> delta : decompressDeltas(originalDelta)) {
|
for (AbstractDelta<String> originalDelta : deltaList) {
|
||||||
|
for (AbstractDelta<String> delta : decompressDeltas(originalDelta)) {
|
||||||
|
endPos = transformDeltaIntoDiffRow(original, endPos, diffRows, delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (AbstractDelta<String> delta : deltaList) {
|
||||||
endPos = transformDeltaIntoDiffRow(original, endPos, diffRows, delta);
|
endPos = transformDeltaIntoDiffRow(original, endPos, diffRows, delta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,6 +450,7 @@ public final class DiffRowGenerator {
|
|||||||
|
|
||||||
private boolean showInlineDiffs = false;
|
private boolean showInlineDiffs = false;
|
||||||
private boolean ignoreWhiteSpaces = false;
|
private boolean ignoreWhiteSpaces = false;
|
||||||
|
private boolean decompressDeltas = true;
|
||||||
|
|
||||||
private BiFunction<Tag, Boolean, String> oldTag
|
private BiFunction<Tag, Boolean, String> oldTag
|
||||||
= (tag, f) -> f ? "<span class=\"editOldInline\">" : "</span>";
|
= (tag, f) -> f ? "<span class=\"editOldInline\">" : "</span>";
|
||||||
@@ -554,7 +563,8 @@ public final class DiffRowGenerator {
|
|||||||
* Set the column width of generated lines of original and revised
|
* Set the column width of generated lines of original and revised
|
||||||
* texts.
|
* texts.
|
||||||
*
|
*
|
||||||
* @param width the width to set. Making it < 0 doesn't make any sense. Default 80.
|
* @param width the width to set. Making it < 0 doesn't make any
|
||||||
|
* sense. Default 80.
|
||||||
* @return builder with config of column width
|
* @return builder with config of column width
|
||||||
*/
|
*/
|
||||||
public Builder columnWidth(int width) {
|
public Builder columnWidth(int width) {
|
||||||
@@ -586,6 +596,19 @@ public final class DiffRowGenerator {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deltas could be in a state, that would produce some unreasonable
|
||||||
|
* results within an inline diff. So the deltas are decompressed into
|
||||||
|
* smaller parts and rebuild. But this could result in more differences.
|
||||||
|
*
|
||||||
|
* @param decompressDeltas
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Builder decompressDeltas(boolean decompressDeltas) {
|
||||||
|
this.decompressDeltas = decompressDeltas;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Per default each character is separatly processed. This variant
|
* Per default each character is separatly processed. This variant
|
||||||
* introduces processing by word, which does not deliver in word
|
* introduces processing by word, which does not deliver in word
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ public final class UnifiedDiffReader {
|
|||||||
line = line.substring(0, matcher.start());
|
line = line.substring(0, matcher.start());
|
||||||
}
|
}
|
||||||
line = line.split("\t")[0];
|
line = line.split("\t")[0];
|
||||||
return line.substring(4).replaceFirst("^(a|b|old|new)(\\/)?", "")
|
return line.substring(4).replaceFirst("^(a|b|old|new)/", "")
|
||||||
.trim();
|
.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.github.difflib.algorithm.myers;
|
|||||||
|
|
||||||
import com.github.difflib.patch.*;
|
import com.github.difflib.patch.*;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@@ -9,8 +10,13 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
import java.io.ObjectOutputStream;
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@@ -57,6 +63,104 @@ public class WithMeyersDiffWithLinearSpacePatchTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// region testPatch_fuzzyApply utils
|
||||||
|
|
||||||
|
private List<String> intRange(int count) {
|
||||||
|
return IntStream.range(0, count)
|
||||||
|
.mapToObj(Integer::toString)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
private final List<String> join(List<String>... lists) {
|
||||||
|
return Arrays.stream(lists).flatMap(Collection::stream).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class FuzzyApplyTestPair {
|
||||||
|
public final List<String> from;
|
||||||
|
public final List<String> to;
|
||||||
|
public final int requiredFuzz;
|
||||||
|
|
||||||
|
private FuzzyApplyTestPair(List<String> from, List<String> to, int requiredFuzz) {
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.requiredFuzz = requiredFuzz;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fuzzyApply() throws PatchFailedException {
|
||||||
|
Patch<String> patch = new Patch<>();
|
||||||
|
List<String> deltaFrom = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff");
|
||||||
|
List<String> deltaTo = Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fff");
|
||||||
|
patch.addDelta(new ChangeDelta<>(
|
||||||
|
new Chunk<>(6, deltaFrom),
|
||||||
|
new Chunk<>(6, deltaTo)));
|
||||||
|
|
||||||
|
//noinspection unchecked
|
||||||
|
List<String>[] moves = new List[] {
|
||||||
|
intRange(6), // no patch move
|
||||||
|
intRange(3), // forward patch move
|
||||||
|
intRange(9), // backward patch move
|
||||||
|
intRange(0), // apply to the first
|
||||||
|
};
|
||||||
|
|
||||||
|
for (FuzzyApplyTestPair pair : FUZZY_APPLY_TEST_PAIRS) {
|
||||||
|
for (List<String> move : moves) {
|
||||||
|
List<String> from = join(move, pair.from);
|
||||||
|
List<String> to = join(move, pair.to);
|
||||||
|
|
||||||
|
for (int i = 0; i < pair.requiredFuzz; i++) {
|
||||||
|
int maxFuzz = i;
|
||||||
|
assertThrows(PatchFailedException.class, () ->
|
||||||
|
patch.applyFuzzy(from, maxFuzz),
|
||||||
|
() -> "fail for " + from + " -> " + to + " for fuzz " + maxFuzz + " required " + pair.requiredFuzz);
|
||||||
|
}
|
||||||
|
for (int i = pair.requiredFuzz; i < 4; i++) {
|
||||||
|
int maxFuzz = i;
|
||||||
|
assertEquals(to, patch.applyFuzzy(from, maxFuzz),
|
||||||
|
() -> "with " + maxFuzz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fuzzyApplyTwoSideBySidePatches() throws PatchFailedException {
|
||||||
|
Patch<String> patch = new Patch<>();
|
||||||
|
List<String> deltaFrom = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff");
|
||||||
|
List<String> deltaTo = Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fff");
|
||||||
|
patch.addDelta(new ChangeDelta<>(
|
||||||
|
new Chunk<>(0, deltaFrom),
|
||||||
|
new Chunk<>(0, deltaTo)));
|
||||||
|
patch.addDelta(new ChangeDelta<>(
|
||||||
|
new Chunk<>(6, deltaFrom),
|
||||||
|
new Chunk<>(6, deltaTo)));
|
||||||
|
|
||||||
|
|
||||||
|
assertEquals(join(deltaTo, deltaTo), patch.applyFuzzy(join(deltaFrom, deltaFrom), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fuzzyApplyToNearest() throws PatchFailedException {
|
||||||
|
Patch<String> patch = new Patch<>();
|
||||||
|
List<String> deltaFrom = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff");
|
||||||
|
List<String> deltaTo = Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fff");
|
||||||
|
patch.addDelta(new ChangeDelta<>(
|
||||||
|
new Chunk<>(0, deltaFrom),
|
||||||
|
new Chunk<>(0, deltaTo)));
|
||||||
|
patch.addDelta(new ChangeDelta<>(
|
||||||
|
new Chunk<>(10, deltaFrom),
|
||||||
|
new Chunk<>(10, deltaTo)));
|
||||||
|
|
||||||
|
assertEquals(join(deltaTo, deltaFrom, deltaTo),
|
||||||
|
patch.applyFuzzy(join(deltaFrom, deltaFrom, deltaFrom), 0));
|
||||||
|
assertEquals(join(intRange(1), deltaTo, deltaFrom, deltaTo),
|
||||||
|
patch.applyFuzzy(join(intRange(1), deltaFrom, deltaFrom, deltaFrom), 0));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPatch_Serializable() throws IOException, ClassNotFoundException {
|
public void testPatch_Serializable() throws IOException, ClassNotFoundException {
|
||||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||||
@@ -101,4 +205,190 @@ public class WithMeyersDiffWithLinearSpacePatchTest {
|
|||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class FuzzyApplyTestDataGenerator {
|
||||||
|
private static String createList(List<String> values) {
|
||||||
|
return values.stream()
|
||||||
|
.map(x -> '"' + x + '"')
|
||||||
|
.collect(Collectors.joining(", ", "Arrays.asList(", ")"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
String[] deltaFrom = new String[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
|
||||||
|
String[] deltaTo = new String[] { "aaa", "bbb", "cxc", "dxd", "eee", "fff" };
|
||||||
|
|
||||||
|
List<FuzzyApplyTestPair> pairs = new ArrayList<>();
|
||||||
|
|
||||||
|
// create test data.
|
||||||
|
// Brute-force search
|
||||||
|
String[] changedValue = new String[]{"axa", "bxb", "czc", "dzd", "exe", "fxf"};
|
||||||
|
for (int i = 0; i < 1 << 6; i++) {
|
||||||
|
if ((i & 0b001100) != 0 && (i & 0b001100) != 0b001100) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] from = deltaFrom.clone();
|
||||||
|
String[] to = deltaTo.clone();
|
||||||
|
for (int j = 0; j < 6; j++) {
|
||||||
|
if ((i & (1 << j)) != 0) {
|
||||||
|
from[j] = changedValue[j];
|
||||||
|
to[j] = changedValue[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int requiredFuzz;
|
||||||
|
if ((i & 0b001100) != 0) {
|
||||||
|
requiredFuzz = 3;
|
||||||
|
} else if ((i & 0b010010) != 0) {
|
||||||
|
requiredFuzz = 2;
|
||||||
|
} else if ((i & 0b100001) != 0) {
|
||||||
|
requiredFuzz = 1;
|
||||||
|
} else {
|
||||||
|
requiredFuzz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pairs.add(new FuzzyApplyTestPair(Arrays.asList(from), Arrays.asList(to), requiredFuzz));
|
||||||
|
}
|
||||||
|
pairs.sort(Comparator.comparingInt(a -> a.requiredFuzz));
|
||||||
|
System.out.println("FuzzyApplyTestPair[] pairs = new FuzzyApplyTestPair[] {");
|
||||||
|
for (FuzzyApplyTestPair pair : pairs) {
|
||||||
|
System.out.println(" new FuzzyApplyTestPair(");
|
||||||
|
System.out.println(" " + createList(pair.from) + ",");
|
||||||
|
System.out.println(" " + createList(pair.to) + ",");
|
||||||
|
System.out.println(" " + pair.requiredFuzz + "),");
|
||||||
|
}
|
||||||
|
System.out.println("};");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final FuzzyApplyTestPair[] FUZZY_APPLY_TEST_PAIRS = new FuzzyApplyTestPair[] {
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff"),
|
||||||
|
Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fff"),
|
||||||
|
0),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bbb", "ccc", "ddd", "eee", "fff"),
|
||||||
|
Arrays.asList("axa", "bbb", "cxc", "dxd", "eee", "fff"),
|
||||||
|
1),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fxf"),
|
||||||
|
Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fxf"),
|
||||||
|
1),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bbb", "ccc", "ddd", "eee", "fxf"),
|
||||||
|
Arrays.asList("axa", "bbb", "cxc", "dxd", "eee", "fxf"),
|
||||||
|
1),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bxb", "ccc", "ddd", "eee", "fff"),
|
||||||
|
Arrays.asList("aaa", "bxb", "cxc", "dxd", "eee", "fff"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bxb", "ccc", "ddd", "eee", "fff"),
|
||||||
|
Arrays.asList("axa", "bxb", "cxc", "dxd", "eee", "fff"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bbb", "ccc", "ddd", "exe", "fff"),
|
||||||
|
Arrays.asList("aaa", "bbb", "cxc", "dxd", "exe", "fff"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bbb", "ccc", "ddd", "exe", "fff"),
|
||||||
|
Arrays.asList("axa", "bbb", "cxc", "dxd", "exe", "fff"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bxb", "ccc", "ddd", "exe", "fff"),
|
||||||
|
Arrays.asList("aaa", "bxb", "cxc", "dxd", "exe", "fff"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bxb", "ccc", "ddd", "exe", "fff"),
|
||||||
|
Arrays.asList("axa", "bxb", "cxc", "dxd", "exe", "fff"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bxb", "ccc", "ddd", "eee", "fxf"),
|
||||||
|
Arrays.asList("aaa", "bxb", "cxc", "dxd", "eee", "fxf"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bxb", "ccc", "ddd", "eee", "fxf"),
|
||||||
|
Arrays.asList("axa", "bxb", "cxc", "dxd", "eee", "fxf"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bbb", "ccc", "ddd", "exe", "fxf"),
|
||||||
|
Arrays.asList("aaa", "bbb", "cxc", "dxd", "exe", "fxf"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bbb", "ccc", "ddd", "exe", "fxf"),
|
||||||
|
Arrays.asList("axa", "bbb", "cxc", "dxd", "exe", "fxf"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bxb", "ccc", "ddd", "exe", "fxf"),
|
||||||
|
Arrays.asList("aaa", "bxb", "cxc", "dxd", "exe", "fxf"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bxb", "ccc", "ddd", "exe", "fxf"),
|
||||||
|
Arrays.asList("axa", "bxb", "cxc", "dxd", "exe", "fxf"),
|
||||||
|
2),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bbb", "czc", "dzd", "eee", "fff"),
|
||||||
|
Arrays.asList("aaa", "bbb", "czc", "dzd", "eee", "fff"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bbb", "czc", "dzd", "eee", "fff"),
|
||||||
|
Arrays.asList("axa", "bbb", "czc", "dzd", "eee", "fff"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bxb", "czc", "dzd", "eee", "fff"),
|
||||||
|
Arrays.asList("aaa", "bxb", "czc", "dzd", "eee", "fff"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bxb", "czc", "dzd", "eee", "fff"),
|
||||||
|
Arrays.asList("axa", "bxb", "czc", "dzd", "eee", "fff"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bbb", "czc", "dzd", "exe", "fff"),
|
||||||
|
Arrays.asList("aaa", "bbb", "czc", "dzd", "exe", "fff"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bbb", "czc", "dzd", "exe", "fff"),
|
||||||
|
Arrays.asList("axa", "bbb", "czc", "dzd", "exe", "fff"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bxb", "czc", "dzd", "exe", "fff"),
|
||||||
|
Arrays.asList("aaa", "bxb", "czc", "dzd", "exe", "fff"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bxb", "czc", "dzd", "exe", "fff"),
|
||||||
|
Arrays.asList("axa", "bxb", "czc", "dzd", "exe", "fff"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bbb", "czc", "dzd", "eee", "fxf"),
|
||||||
|
Arrays.asList("aaa", "bbb", "czc", "dzd", "eee", "fxf"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bbb", "czc", "dzd", "eee", "fxf"),
|
||||||
|
Arrays.asList("axa", "bbb", "czc", "dzd", "eee", "fxf"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bxb", "czc", "dzd", "eee", "fxf"),
|
||||||
|
Arrays.asList("aaa", "bxb", "czc", "dzd", "eee", "fxf"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bxb", "czc", "dzd", "eee", "fxf"),
|
||||||
|
Arrays.asList("axa", "bxb", "czc", "dzd", "eee", "fxf"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bbb", "czc", "dzd", "exe", "fxf"),
|
||||||
|
Arrays.asList("aaa", "bbb", "czc", "dzd", "exe", "fxf"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bbb", "czc", "dzd", "exe", "fxf"),
|
||||||
|
Arrays.asList("axa", "bbb", "czc", "dzd", "exe", "fxf"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("aaa", "bxb", "czc", "dzd", "exe", "fxf"),
|
||||||
|
Arrays.asList("aaa", "bxb", "czc", "dzd", "exe", "fxf"),
|
||||||
|
3),
|
||||||
|
new FuzzyApplyTestPair(
|
||||||
|
Arrays.asList("axa", "bxb", "czc", "dzd", "exe", "fxf"),
|
||||||
|
Arrays.asList("axa", "bxb", "czc", "dzd", "exe", "fxf"),
|
||||||
|
3),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ import java.util.List;
|
|||||||
public class ComputeDifference {
|
public class ComputeDifference {
|
||||||
|
|
||||||
private static final String ORIGINAL = TestConstants.MOCK_FOLDER + "original.txt";
|
private static final String ORIGINAL = TestConstants.MOCK_FOLDER + "original.txt";
|
||||||
private static final String RIVISED = TestConstants.MOCK_FOLDER + "revised.txt";
|
private static final String REVISED = TestConstants.MOCK_FOLDER + "revised.txt";
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
List<String> original = Files.readAllLines(new File(ORIGINAL).toPath());
|
List<String> original = Files.readAllLines(new File(ORIGINAL).toPath());
|
||||||
List<String> revised = Files.readAllLines(new File(RIVISED).toPath());
|
List<String> revised = Files.readAllLines(new File(REVISED).toPath());
|
||||||
|
|
||||||
// Compute diff. Get the Patch object. Patch is the container for computed deltas.
|
// Compute diff. Get the Patch object. Patch is the container for computed deltas.
|
||||||
Patch<String> patch = DiffUtils.diff(original, revised);
|
Patch<String> patch = DiffUtils.diff(original, revised);
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package com.github.difflib.patch;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class ChunkTest {
|
||||||
|
@Test
|
||||||
|
void verifyChunk() throws PatchFailedException {
|
||||||
|
Chunk<Character> chunk = new Chunk<>(7, toCharList("test"));
|
||||||
|
|
||||||
|
// normal check
|
||||||
|
assertEquals(VerifyChunk.OK,
|
||||||
|
chunk.verifyChunk(toCharList("prefix test suffix")));
|
||||||
|
assertEquals(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET,
|
||||||
|
chunk.verifyChunk(toCharList("prefix es suffix"), 0, 7));
|
||||||
|
|
||||||
|
// position
|
||||||
|
assertEquals(VerifyChunk.OK,
|
||||||
|
chunk.verifyChunk(toCharList("short test suffix"), 0, 6));
|
||||||
|
assertEquals(VerifyChunk.OK,
|
||||||
|
chunk.verifyChunk(toCharList("loonger test suffix"), 0, 8));
|
||||||
|
assertEquals(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET,
|
||||||
|
chunk.verifyChunk(toCharList("prefix test suffix"), 0, 6));
|
||||||
|
assertEquals(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET,
|
||||||
|
chunk.verifyChunk(toCharList("prefix test suffix"), 0, 8));
|
||||||
|
|
||||||
|
// fuzz
|
||||||
|
assertEquals(VerifyChunk.OK,
|
||||||
|
chunk.verifyChunk(toCharList("prefix test suffix"), 1, 7));
|
||||||
|
assertEquals(VerifyChunk.OK,
|
||||||
|
chunk.verifyChunk(toCharList("prefix es suffix"), 1, 7));
|
||||||
|
assertEquals(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET,
|
||||||
|
chunk.verifyChunk(toCharList("prefix suffix"), 1, 7));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Character> toCharList(String str) {
|
||||||
|
return str.chars().mapToObj(x -> (char) x).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,8 +16,10 @@
|
|||||||
package com.github.difflib.patch;
|
package com.github.difflib.patch;
|
||||||
|
|
||||||
import com.github.difflib.DiffUtils;
|
import com.github.difflib.DiffUtils;
|
||||||
|
import static com.github.difflib.patch.Patch.CONFLICT_PRODUCES_MERGE_CONFLICT;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import static java.util.stream.Collectors.joining;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -27,6 +29,7 @@ import org.junit.jupiter.api.Test;
|
|||||||
* @author tw
|
* @author tw
|
||||||
*/
|
*/
|
||||||
public class PatchWithMeyerDiffTest {
|
public class PatchWithMeyerDiffTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPatch_Change_withExceptionProcessor() {
|
public void testPatch_Change_withExceptionProcessor() {
|
||||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||||
@@ -48,4 +51,18 @@ public class PatchWithMeyerDiffTest {
|
|||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPatchThreeWayIssue138() throws PatchFailedException {
|
||||||
|
List<String> base = Arrays.asList("Imagine there's no heaven".split("\\s+"));
|
||||||
|
List<String> left = Arrays.asList("Imagine there's no HEAVEN".split("\\s+"));
|
||||||
|
List<String> right = Arrays.asList("IMAGINE there's no heaven".split("\\s+"));
|
||||||
|
|
||||||
|
Patch<String> rightPatch = DiffUtils.diff(base, right)
|
||||||
|
.withConflictOutput(CONFLICT_PRODUCES_MERGE_CONFLICT);
|
||||||
|
|
||||||
|
List<String> applied = rightPatch.applyTo(left);
|
||||||
|
|
||||||
|
assertEquals("IMAGINE there's no HEAVEN", applied.stream().collect(joining(" ")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -641,7 +641,7 @@ public class DiffRowGeneratorTest {
|
|||||||
|
|
||||||
assertThat(rows).extracting(item -> item.getTag().name()).containsExactly("CHANGE", "DELETE", "EQUAL", "CHANGE", "EQUAL");
|
assertThat(rows).extracting(item -> item.getTag().name()).containsExactly("CHANGE", "DELETE", "EQUAL", "CHANGE", "EQUAL");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCorrectChangeIssue114_2() throws IOException {
|
public void testCorrectChangeIssue114_2() throws IOException {
|
||||||
List<String> original = Arrays.asList("A", "B", "C", "D", "E");
|
List<String> original = Arrays.asList("A", "B", "C", "D", "E");
|
||||||
@@ -662,7 +662,7 @@ public class DiffRowGeneratorTest {
|
|||||||
assertThat(rows).extracting(item -> item.getTag().name()).containsExactly("CHANGE", "DELETE", "EQUAL", "CHANGE", "EQUAL");
|
assertThat(rows).extracting(item -> item.getTag().name()).containsExactly("CHANGE", "DELETE", "EQUAL", "CHANGE", "EQUAL");
|
||||||
assertThat(rows.get(1).toString()).isEqualTo("[DELETE,~B~,]");
|
assertThat(rows.get(1).toString()).isEqualTo("[DELETE,~B~,]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIssue119WrongContextLength() throws IOException {
|
public void testIssue119WrongContextLength() throws IOException {
|
||||||
String original = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue_119_original.txt")).collect(joining("\n"));
|
String original = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue_119_original.txt")).collect(joining("\n"));
|
||||||
@@ -683,4 +683,106 @@ public class DiffRowGeneratorTest {
|
|||||||
.filter(item -> item.getTag() != DiffRow.Tag.EQUAL)
|
.filter(item -> item.getTag() != DiffRow.Tag.EQUAL)
|
||||||
.forEach(System.out::println);
|
.forEach(System.out::println);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIssue129WithDeltaDecompression() {
|
||||||
|
List<String> lines1 = Arrays.asList(
|
||||||
|
"apple1",
|
||||||
|
"apple2",
|
||||||
|
"apple3",
|
||||||
|
"A man named Frankenstein abc to Switzerland for cookies!",
|
||||||
|
"banana1",
|
||||||
|
"banana2",
|
||||||
|
"banana3");
|
||||||
|
List<String> lines2 = Arrays.asList(
|
||||||
|
"apple1",
|
||||||
|
"apple2",
|
||||||
|
"apple3",
|
||||||
|
"A man named Frankenstein",
|
||||||
|
"xyz",
|
||||||
|
"to Switzerland for cookies!",
|
||||||
|
"banana1",
|
||||||
|
"banana2",
|
||||||
|
"banana3");
|
||||||
|
int[] entry = {1};
|
||||||
|
String txt = DiffRowGenerator.create()
|
||||||
|
.showInlineDiffs(true)
|
||||||
|
.oldTag((tag, isOpening) -> isOpening ? "==old" + tag + "==>" : "<==old==")
|
||||||
|
.newTag((tag, isOpening) -> isOpening ? "==new" + tag + "==>" : "<==new==")
|
||||||
|
.build()
|
||||||
|
.generateDiffRows(lines1, lines2)
|
||||||
|
.stream()
|
||||||
|
.map(row -> row.getTag().toString())
|
||||||
|
.collect(joining(" "));
|
||||||
|
// .forEachOrdered(row -> {
|
||||||
|
// System.out.printf("%4d %-8s %-80s %-80s\n", entry[0]++,
|
||||||
|
// row.getTag(), row.getOldLine(), row.getNewLine());
|
||||||
|
// });
|
||||||
|
|
||||||
|
assertThat(txt).isEqualTo("EQUAL EQUAL EQUAL CHANGE INSERT INSERT EQUAL EQUAL EQUAL");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIssue129SkipDeltaDecompression() {
|
||||||
|
List<String> lines1 = Arrays.asList(
|
||||||
|
"apple1",
|
||||||
|
"apple2",
|
||||||
|
"apple3",
|
||||||
|
"A man named Frankenstein abc to Switzerland for cookies!",
|
||||||
|
"banana1",
|
||||||
|
"banana2",
|
||||||
|
"banana3");
|
||||||
|
List<String> lines2 = Arrays.asList(
|
||||||
|
"apple1",
|
||||||
|
"apple2",
|
||||||
|
"apple3",
|
||||||
|
"A man named Frankenstein",
|
||||||
|
"xyz",
|
||||||
|
"to Switzerland for cookies!",
|
||||||
|
"banana1",
|
||||||
|
"banana2",
|
||||||
|
"banana3");
|
||||||
|
int[] entry = {1};
|
||||||
|
String txt =
|
||||||
|
DiffRowGenerator.create()
|
||||||
|
.showInlineDiffs(true)
|
||||||
|
.decompressDeltas(false)
|
||||||
|
.oldTag((tag, isOpening) -> isOpening ? "==old" + tag + "==>" : "<==old==")
|
||||||
|
.newTag((tag, isOpening) -> isOpening ? "==new" + tag + "==>" : "<==new==")
|
||||||
|
.build()
|
||||||
|
.generateDiffRows(lines1, lines2)
|
||||||
|
.stream()
|
||||||
|
.map(row -> row.getTag().toString())
|
||||||
|
.collect(joining(" "));
|
||||||
|
// .forEachOrdered(row -> {
|
||||||
|
// System.out.printf("%4d %-8s %-80s %-80s\n", entry[0]++,
|
||||||
|
// row.getTag(), row.getOldLine(), row.getNewLine());
|
||||||
|
// });
|
||||||
|
|
||||||
|
assertThat(txt).isEqualTo("EQUAL EQUAL EQUAL CHANGE CHANGE CHANGE EQUAL EQUAL EQUAL");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIssue129SkipWhitespaceChanges() throws IOException {
|
||||||
|
String original = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue129_1.txt")).collect(joining("\n"));
|
||||||
|
String revised = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue129_2.txt")).collect(joining("\n"));
|
||||||
|
|
||||||
|
DiffRowGenerator generator = DiffRowGenerator.create()
|
||||||
|
.showInlineDiffs(true)
|
||||||
|
.mergeOriginalRevised(true)
|
||||||
|
.inlineDiffByWord(true)
|
||||||
|
.ignoreWhiteSpaces(true)
|
||||||
|
.oldTag((tag, isOpening) -> isOpening ? "==old" + tag + "==>" : "<==old==")
|
||||||
|
.newTag((tag, isOpening) -> isOpening ? "==new" + tag + "==>" : "<==new==")
|
||||||
|
.build();
|
||||||
|
List<DiffRow> rows = generator.generateDiffRows(
|
||||||
|
Arrays.asList(original.split("\n")),
|
||||||
|
Arrays.asList(revised.split("\n")));
|
||||||
|
|
||||||
|
assertThat(rows).hasSize(13);
|
||||||
|
|
||||||
|
rows.stream()
|
||||||
|
.filter(item -> item.getTag() != DiffRow.Tag.EQUAL)
|
||||||
|
.forEach(System.out::println);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ public class UnifiedDiffReaderTest {
|
|||||||
assertThat(diff.getFiles().size()).isEqualTo(1);
|
assertThat(diff.getFiles().size()).isEqualTo(1);
|
||||||
|
|
||||||
UnifiedDiffFile file1 = diff.getFiles().get(0);
|
UnifiedDiffFile file1 = diff.getFiles().get(0);
|
||||||
assertThat(file1.getFromFile()).isEqualTo(".vhd");
|
assertThat(file1.getFromFile()).isEqualTo("a.vhd");
|
||||||
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1);
|
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1);
|
||||||
|
|
||||||
assertThat(diff.getTail()).isNull();
|
assertThat(diff.getTail()).isNull();
|
||||||
@@ -384,4 +384,14 @@ public class UnifiedDiffReaderTest {
|
|||||||
|
|
||||||
assertThat(diff.getFiles()).extracting(f -> f.getFromFile()).contains("src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java");
|
assertThat(diff.getFiles()).extracting(f -> f.getFromFile()).contains("src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseIssue141() throws IOException {
|
||||||
|
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
|
||||||
|
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue141.diff"));
|
||||||
|
UnifiedDiffFile file1 = diff.getFiles().get(0);
|
||||||
|
|
||||||
|
assertThat(file1.getFromFile()).isEqualTo("a.txt");
|
||||||
|
assertThat(file1.getToFile()).isEqualTo("a1.txt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 java-diff-utils.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.github.difflib.unifieddiff;
|
||||||
|
|
||||||
|
import com.github.difflib.patch.PatchFailedException;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import static java.util.stream.Collectors.joining;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@Disabled("for next release")
|
||||||
|
public class UnifiedDiffRoundTripNewLineTest {
|
||||||
|
@Test
|
||||||
|
public void testIssue135MissingNoNewLineInPatched() throws IOException, PatchFailedException {
|
||||||
|
String beforeContent = "rootProject.name = \"sample-repo\"";
|
||||||
|
String afterContent = "rootProject.name = \"sample-repo\"\n";
|
||||||
|
String patch = "diff --git a/settings.gradle b/settings.gradle\n" +
|
||||||
|
"index ef3b8e2..ab30124 100644\n" +
|
||||||
|
"--- a/settings.gradle\n" +
|
||||||
|
"+++ b/settings.gradle\n" +
|
||||||
|
"@@ -1 +1 @@\n" +
|
||||||
|
"-rootProject.name = \"sample-repo\"\n" +
|
||||||
|
"\\ No newline at end of file\n" +
|
||||||
|
"+rootProject.name = \"sample-repo\"\n";
|
||||||
|
UnifiedDiff unifiedDiff = UnifiedDiffReader.parseUnifiedDiff(new ByteArrayInputStream(patch.getBytes()));
|
||||||
|
String unifiedAfterContent = unifiedDiff.getFiles().get(0).getPatch()
|
||||||
|
.applyTo(Arrays.asList(beforeContent.split("\n"))).stream().collect(joining("\n"));
|
||||||
|
assertEquals(afterContent, unifiedAfterContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated
|
||||||
|
to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or
|
||||||
|
any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to
|
||||||
|
dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live.
|
||||||
|
It is altogether fitting and proper that we should do this. But, in a larger sense, we can not dedicate -- we can not
|
||||||
|
consecrate -- we can not hallow -- this ground. The brave men, living and dead, who struggled here, have consecrated it,
|
||||||
|
far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never
|
||||||
|
forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought
|
||||||
|
here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us -- that
|
||||||
|
from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion -- that
|
||||||
|
we here highly resolve that these dead shall not have died in vain -- that this nation, under God, shall have a new birth of
|
||||||
|
freedom -- and that government of the people, by the people, for the people, shall not perish from the earth.
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and
|
||||||
|
dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether
|
||||||
|
that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that
|
||||||
|
war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives
|
||||||
|
that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we
|
||||||
|
can not dedicate -- we can not consecrate -- we can not hallow -- this ground. The brave men, living and dead, who
|
||||||
|
struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long
|
||||||
|
remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated
|
||||||
|
here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here
|
||||||
|
dedicated to the great task remaining before us -- that from these honored dead we take increased devotion to that cause
|
||||||
|
for which they gave the last full measure of devotion -- that we here highly resolve that these dead shall not have died
|
||||||
|
in vain -- that this nation, under God, shall have a new birth of freedom -- and that government of the people, by the
|
||||||
|
people, for the people, shall not perish from the earth.
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
--- a.txt
|
||||||
|
+++ a1.txt
|
||||||
|
@@ -8,7 +8,7 @@
|
||||||
|
<Setting>
|
||||||
|
<Setting a>
|
||||||
|
<setting b>
|
||||||
|
- <value>23</value>
|
||||||
|
+ <value>24</value>
|
||||||
|
</setting b>
|
||||||
|
<setting c>
|
||||||
|
<value>1</value>
|
||||||
6
pom.xml
6
pom.xml
@@ -3,7 +3,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>io.github.java-diff-utils</groupId>
|
<groupId>io.github.java-diff-utils</groupId>
|
||||||
<artifactId>java-diff-utils-parent</artifactId>
|
<artifactId>java-diff-utils-parent</artifactId>
|
||||||
<version>4.11</version>
|
<version>4.12</version>
|
||||||
<name>java-diff-utils-parent</name>
|
<name>java-diff-utils-parent</name>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<modules>
|
<modules>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<connection>scm:git:https://github.com/java-diff-utils/java-diff-utils.git</connection>
|
<connection>scm:git:https://github.com/java-diff-utils/java-diff-utils.git</connection>
|
||||||
<developerConnection>scm:git:ssh://git@github.com:java-diff-utils/java-diff-utils.git</developerConnection>
|
<developerConnection>scm:git:ssh://git@github.com:java-diff-utils/java-diff-utils.git</developerConnection>
|
||||||
<url>https://github.com/java-diff-utils/java-diff-utils.git</url>
|
<url>https://github.com/java-diff-utils/java-diff-utils.git</url>
|
||||||
<tag>java-diff-utils-parent-4.11</tag>
|
<tag>java-diff-utils-parent-4.12</tag>
|
||||||
</scm>
|
</scm>
|
||||||
<issueManagement>
|
<issueManagement>
|
||||||
<system>GitHub Issues</system>
|
<system>GitHub Issues</system>
|
||||||
@@ -199,7 +199,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-gpg-plugin</artifactId>
|
<artifactId>maven-gpg-plugin</artifactId>
|
||||||
<version>1.4</version>
|
<version>1.6</version>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<id>sign-artifacts</id>
|
<id>sign-artifacts</id>
|
||||||
|
|||||||
Reference in New Issue
Block a user