mirror of
https://github.com/java-diff-utils/java-diff-utils.git
synced 2026-03-13 10:11:17 +08:00
Merge introduce-optimized-meyers-algorithm
This commit is contained in:
@@ -15,9 +15,10 @@
|
||||
*/
|
||||
package com.github.difflib;
|
||||
|
||||
import com.github.difflib.algorithm.DiffAlgorithmFactory;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmI;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmListener;
|
||||
import com.github.difflib.algorithm.myers.MyersDiff;
|
||||
import com.github.difflib.algorithm.myers.MeyersDiff;
|
||||
import com.github.difflib.patch.AbstractDelta;
|
||||
import com.github.difflib.patch.Patch;
|
||||
import com.github.difflib.patch.PatchFailedException;
|
||||
@@ -34,26 +35,35 @@ import java.util.function.BiPredicate;
|
||||
public final class DiffUtils {
|
||||
|
||||
/**
|
||||
* Computes the difference between the original and revised list of elements with default diff
|
||||
* algorithm
|
||||
* This factory generates the DEFAULT_DIFF algorithm for all these routines.
|
||||
*/
|
||||
static DiffAlgorithmFactory DEFAULT_DIFF = MeyersDiff.factory();
|
||||
|
||||
public static void withDefaultDiffAlgorithmFactory(DiffAlgorithmFactory factory) {
|
||||
DEFAULT_DIFF = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference between the original and revised list of elements
|
||||
* with default diff algorithm
|
||||
*
|
||||
* @param <T> types to be diffed
|
||||
* @param original The original text. Must not be {@code null}.
|
||||
* @param revised The revised text. Must not be {@code null}.
|
||||
* @param progress progress listener
|
||||
* @return The patch describing the difference between the original and revised sequences. Never
|
||||
* {@code null}.
|
||||
* @return The patch describing the difference between the original and
|
||||
* revised sequences. Never {@code null}.
|
||||
*/
|
||||
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmListener progress) {
|
||||
return DiffUtils.diff(original, revised, new MyersDiff<>(), progress);
|
||||
return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), progress);
|
||||
}
|
||||
|
||||
public static <T> Patch<T> diff(List<T> original, List<T> revised) {
|
||||
return DiffUtils.diff(original, revised, new MyersDiff<>(), null);
|
||||
return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), null);
|
||||
}
|
||||
|
||||
|
||||
public static <T> Patch<T> diff(List<T> original, List<T> revised, boolean includeEqualParts) {
|
||||
return DiffUtils.diff(original, revised, new MyersDiff<>(), null, includeEqualParts);
|
||||
return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), null, includeEqualParts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,45 +77,46 @@ public final class DiffUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference between the original and revised list of elements with default diff
|
||||
* algorithm
|
||||
* Computes the difference between the original and revised list of elements
|
||||
* with default diff algorithm
|
||||
*
|
||||
* @param source The original text. Must not be {@code null}.
|
||||
* @param target The revised text. Must not be {@code null}.
|
||||
*
|
||||
* @param equalizer the equalizer object to replace the default compare algorithm
|
||||
* (Object.equals). If {@code null} the default equalizer of the default algorithm is used..
|
||||
* @return The patch describing the difference between the original and revised sequences. Never
|
||||
* {@code null}.
|
||||
* @param equalizer the equalizer object to replace the default compare
|
||||
* algorithm (Object.equals). If {@code null} the default equalizer of the
|
||||
* default algorithm is used..
|
||||
* @return The patch describing the difference between the original and
|
||||
* revised sequences. Never {@code null}.
|
||||
*/
|
||||
public static <T> Patch<T> diff(List<T> source, List<T> target,
|
||||
BiPredicate<T, T> equalizer) {
|
||||
if (equalizer != null) {
|
||||
return DiffUtils.diff(source, target,
|
||||
new MyersDiff<>(equalizer));
|
||||
DEFAULT_DIFF.create(equalizer));
|
||||
}
|
||||
return DiffUtils.diff(source, target, new MyersDiff<>());
|
||||
return DiffUtils.diff(source, target, new MeyersDiff<>());
|
||||
}
|
||||
|
||||
public static <T> Patch<T> diff(List<T> original, List<T> revised,
|
||||
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress) {
|
||||
return diff(original, revised, algorithm, progress, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Computes the difference between the original and revised list of elements with default diff
|
||||
* algorithm
|
||||
* Computes the difference between the original and revised list of elements
|
||||
* with default diff algorithm
|
||||
*
|
||||
* @param original The original text. Must not be {@code null}.
|
||||
* @param revised The revised text. Must not be {@code null}.
|
||||
* @param algorithm The diff algorithm. Must not be {@code null}.
|
||||
* @param progress The diff algorithm listener.
|
||||
* @param includeEqualParts Include equal data parts into the patch.
|
||||
* @return The patch describing the difference between the original and revised sequences. Never
|
||||
* {@code null}.
|
||||
* @return The patch describing the difference between the original and
|
||||
* revised sequences. Never {@code null}.
|
||||
*/
|
||||
public static <T> Patch<T> diff(List<T> original, List<T> revised,
|
||||
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress,
|
||||
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress,
|
||||
boolean includeEqualParts) {
|
||||
Objects.requireNonNull(original, "original must not be null");
|
||||
Objects.requireNonNull(revised, "revised must not be null");
|
||||
@@ -115,23 +126,23 @@ public final class DiffUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference between the original and revised list of elements with default diff
|
||||
* algorithm
|
||||
* Computes the difference between the original and revised list of elements
|
||||
* with default diff algorithm
|
||||
*
|
||||
* @param original The original text. Must not be {@code null}.
|
||||
* @param revised The revised text. Must not be {@code null}.
|
||||
* @param algorithm The diff algorithm. Must not be {@code null}.
|
||||
* @return The patch describing the difference between the original and revised sequences. Never
|
||||
* {@code null}.
|
||||
* @return The patch describing the difference between the original and
|
||||
* revised sequences. Never {@code null}.
|
||||
*/
|
||||
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmI<T> algorithm) {
|
||||
return diff(original, revised, algorithm, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference between the given texts inline. This one uses the "trick" to make out
|
||||
* of texts lists of characters, like DiffRowGenerator does and merges those changes at the end
|
||||
* together again.
|
||||
* Computes the difference between the given texts inline. This one uses the
|
||||
* "trick" to make out of texts lists of characters, like DiffRowGenerator
|
||||
* does and merges those changes at the end together again.
|
||||
*
|
||||
* @param original
|
||||
* @param revised
|
||||
|
||||
@@ -36,4 +36,12 @@ public class Change {
|
||||
this.startRevised = startRevised;
|
||||
this.endRevised = endRevised;
|
||||
}
|
||||
|
||||
public Change withEndOriginal(int endOriginal) {
|
||||
return new Change(deltaType, startOriginal, endOriginal, startRevised, endRevised);
|
||||
}
|
||||
|
||||
public Change withEndRevised(int endRevised) {
|
||||
return new Change(deltaType, startOriginal, endOriginal, startRevised, endRevised);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2021 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.algorithm;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
/**
|
||||
* Tool to create new instances of a diff algorithm. This one is only needed at the moment to
|
||||
* set DiffUtils default diff algorithm.
|
||||
* @author tw
|
||||
*/
|
||||
public interface DiffAlgorithmFactory {
|
||||
<T> DiffAlgorithmI<T> create();
|
||||
|
||||
<T> DiffAlgorithmI<T> create(BiPredicate<T, T> equalizer);
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.github.difflib.algorithm.myers;
|
||||
|
||||
import com.github.difflib.algorithm.Change;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmFactory;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmI;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmListener;
|
||||
import com.github.difflib.patch.DeltaType;
|
||||
@@ -26,18 +27,17 @@ import java.util.Objects;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
/**
|
||||
* A clean-room implementation of Eugene Myers greedy differencing algorithm.
|
||||
* A clean-room implementation of Eugene Meyers greedy differencing algorithm.
|
||||
*/
|
||||
public final class MyersDiff<T> implements DiffAlgorithmI<T> {
|
||||
public final class MeyersDiff<T> implements DiffAlgorithmI<T> {
|
||||
|
||||
private final BiPredicate<T, T> DEFAULT_EQUALIZER = Object::equals;
|
||||
private final BiPredicate<T, T> equalizer;
|
||||
|
||||
public MyersDiff() {
|
||||
equalizer = DEFAULT_EQUALIZER;
|
||||
public MeyersDiff() {
|
||||
equalizer = Object::equals;
|
||||
}
|
||||
|
||||
public MyersDiff(final BiPredicate<T, T> equalizer) {
|
||||
public MeyersDiff(final BiPredicate<T, T> equalizer) {
|
||||
Objects.requireNonNull(equalizer, "equalizer must not be null");
|
||||
this.equalizer = equalizer;
|
||||
}
|
||||
@@ -64,8 +64,9 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the minimum diffpath that expresses de differences between the original and revised
|
||||
* sequences, according to Gene Myers differencing algorithm.
|
||||
* Computes the minimum diffpath that expresses de differences between the
|
||||
* original and revised sequences, according to Gene Myers differencing
|
||||
* algorithm.
|
||||
*
|
||||
* @param orig The original sequence.
|
||||
* @param rev The revised sequence.
|
||||
@@ -139,8 +140,8 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> {
|
||||
* @param orig The original sequence.
|
||||
* @param rev The revised sequence.
|
||||
* @return A {@link Patch} script corresponding to the path.
|
||||
* @throws DifferentiationFailedException if a {@link Patch} could not be built from the given
|
||||
* path.
|
||||
* @throws DifferentiationFailedException if a {@link Patch} could not be
|
||||
* built from the given path.
|
||||
*/
|
||||
private List<Change> buildRevision(PathNode actualPath, List<T> orig, List<T> rev) {
|
||||
Objects.requireNonNull(actualPath, "path is null");
|
||||
@@ -177,4 +178,23 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> {
|
||||
}
|
||||
return changes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory to create instances of this specific diff algorithm.
|
||||
*/
|
||||
public static DiffAlgorithmFactory factory() {
|
||||
return new DiffAlgorithmFactory() {
|
||||
@Override
|
||||
public <T> DiffAlgorithmI<T>
|
||||
create() {
|
||||
return new MeyersDiff<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DiffAlgorithmI<T>
|
||||
create(BiPredicate < T, T > equalizer) {
|
||||
return new MeyersDiff<T>(equalizer);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright 2021 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.algorithm.myers;
|
||||
|
||||
import com.github.difflib.algorithm.Change;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmFactory;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmI;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmListener;
|
||||
import com.github.difflib.patch.DeltaType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tw
|
||||
*/
|
||||
public class MeyersDiffWithLinearSpace<T> implements DiffAlgorithmI<T> {
|
||||
|
||||
private final BiPredicate<T, T> equalizer;
|
||||
|
||||
public MeyersDiffWithLinearSpace() {
|
||||
equalizer = Object::equals;
|
||||
}
|
||||
|
||||
public MeyersDiffWithLinearSpace(final BiPredicate<T, T> equalizer) {
|
||||
Objects.requireNonNull(equalizer, "equalizer must not be null");
|
||||
this.equalizer = equalizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Change> computeDiff(List<T> source, List<T> target, DiffAlgorithmListener progress) {
|
||||
Objects.requireNonNull(source, "source list must not be null");
|
||||
Objects.requireNonNull(target, "target list must not be null");
|
||||
|
||||
if (progress != null) {
|
||||
progress.diffStart();
|
||||
}
|
||||
|
||||
DiffData data = new DiffData(source, target);
|
||||
|
||||
int maxIdx = source.size() + target.size();
|
||||
|
||||
buildScript(data, 0, source.size(), 0, target.size(), idx -> {
|
||||
if (progress != null) {
|
||||
progress.diffStep(idx, maxIdx);
|
||||
}
|
||||
});
|
||||
|
||||
if (progress != null) {
|
||||
progress.diffEnd();
|
||||
}
|
||||
return data.script;
|
||||
}
|
||||
|
||||
private void buildScript(DiffData data, int start1, int end1, int start2, int end2, Consumer<Integer> progress) {
|
||||
if (progress != null) {
|
||||
progress.accept((end1 - start1) / 2 + (end2 - start2) / 2);
|
||||
}
|
||||
final Snake middle = getMiddleSnake(data, start1, end1, start2, end2);
|
||||
if (middle == null
|
||||
|| middle.start == end1 && middle.diag == end1 - end2
|
||||
|| middle.end == start1 && middle.diag == start1 - start2) {
|
||||
int i = start1;
|
||||
int j = start2;
|
||||
while (i < end1 || j < end2) {
|
||||
if (i < end1 && j < end2 && equalizer.test(data.source.get(i), data.target.get(j))) {
|
||||
//script.append(new KeepCommand<>(left.charAt(i)));
|
||||
++i;
|
||||
++j;
|
||||
} else {
|
||||
//TODO: compress these commands.
|
||||
if (end1 - start1 > end2 - start2) {
|
||||
//script.append(new DeleteCommand<>(left.charAt(i)));
|
||||
if (data.script.isEmpty()
|
||||
|| data.script.get(data.script.size() - 1).endOriginal != i
|
||||
|| data.script.get(data.script.size() - 1).deltaType != DeltaType.DELETE) {
|
||||
data.script.add(new Change(DeltaType.DELETE, i, i + 1, j, j));
|
||||
} else {
|
||||
data.script.set(data.script.size() - 1, data.script.get(data.script.size() - 1).withEndOriginal(i + 1));
|
||||
}
|
||||
++i;
|
||||
} else {
|
||||
if (data.script.isEmpty()
|
||||
|| data.script.get(data.script.size() - 1).endRevised != j
|
||||
|| data.script.get(data.script.size() - 1).deltaType != DeltaType.INSERT) {
|
||||
data.script.add(new Change(DeltaType.INSERT, i, i, j, j + 1));
|
||||
} else {
|
||||
data.script.set(data.script.size() - 1, data.script.get(data.script.size() - 1).withEndRevised(j + 1));
|
||||
}
|
||||
++j;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buildScript(data, start1, middle.start, start2, middle.start - middle.diag, progress);
|
||||
buildScript(data, middle.end, end1, middle.end - middle.diag, end2, progress);
|
||||
}
|
||||
}
|
||||
|
||||
private Snake getMiddleSnake(DiffData data, int start1, int end1, int start2, int end2) {
|
||||
final int m = end1 - start1;
|
||||
final int n = end2 - start2;
|
||||
if (m == 0 || n == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final int delta = m - n;
|
||||
final int sum = n + m;
|
||||
final int offset = (sum % 2 == 0 ? sum : sum + 1) / 2;
|
||||
data.vDown[1 + offset] = start1;
|
||||
data.vUp[1 + offset] = end1 + 1;
|
||||
|
||||
for (int d = 0; d <= offset; ++d) {
|
||||
// Down
|
||||
for (int k = -d; k <= d; k += 2) {
|
||||
// First step
|
||||
|
||||
final int i = k + offset;
|
||||
if (k == -d || k != d && data.vDown[i - 1] < data.vDown[i + 1]) {
|
||||
data.vDown[i] = data.vDown[i + 1];
|
||||
} else {
|
||||
data.vDown[i] = data.vDown[i - 1] + 1;
|
||||
}
|
||||
|
||||
int x = data.vDown[i];
|
||||
int y = x - start1 + start2 - k;
|
||||
|
||||
while (x < end1 && y < end2 && equalizer.test(data.source.get(x), data.target.get(y))) {
|
||||
data.vDown[i] = ++x;
|
||||
++y;
|
||||
}
|
||||
// Second step
|
||||
if (delta % 2 != 0 && delta - d <= k && k <= delta + d) {
|
||||
if (data.vUp[i - delta] <= data.vDown[i]) {
|
||||
return buildSnake(data, data.vUp[i - delta], k + start1 - start2, end1, end2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Up
|
||||
for (int k = delta - d; k <= delta + d; k += 2) {
|
||||
// First step
|
||||
final int i = k + offset - delta;
|
||||
if (k == delta - d
|
||||
|| k != delta + d && data.vUp[i + 1] <= data.vUp[i - 1]) {
|
||||
data.vUp[i] = data.vUp[i + 1] - 1;
|
||||
} else {
|
||||
data.vUp[i] = data.vUp[i - 1];
|
||||
}
|
||||
|
||||
int x = data.vUp[i] - 1;
|
||||
int y = x - start1 + start2 - k;
|
||||
while (x >= start1 && y >= start2 && equalizer.test(data.source.get(x), data.target.get(y))) {
|
||||
data.vUp[i] = x--;
|
||||
y--;
|
||||
}
|
||||
// Second step
|
||||
if (delta % 2 == 0 && -d <= k && k <= d) {
|
||||
if (data.vUp[i] <= data.vDown[i + delta]) {
|
||||
return buildSnake(data, data.vUp[i], k + start1 - start2, end1, end2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// According to Myers, this cannot happen
|
||||
throw new IllegalStateException("could not find a diff path");
|
||||
}
|
||||
|
||||
private Snake buildSnake(DiffData data, final int start, final int diag, final int end1, final int end2) {
|
||||
int end = start;
|
||||
while (end - diag < end2 && end < end1 && equalizer.test(data.source.get(end), data.target.get(end - diag))) {
|
||||
++end;
|
||||
}
|
||||
return new Snake(start, end, diag);
|
||||
}
|
||||
|
||||
private class DiffData {
|
||||
|
||||
final int size;
|
||||
final int[] vDown;
|
||||
final int[] vUp;
|
||||
final List<Change> script;
|
||||
final List<T> source;
|
||||
final List<T> target;
|
||||
|
||||
public DiffData(List<T> source, List<T> target) {
|
||||
this.source = source;
|
||||
this.target = target;
|
||||
size = source.size() + target.size() + 2;
|
||||
vDown = new int[size];
|
||||
vUp = new int[size];
|
||||
script = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private class Snake {
|
||||
|
||||
final int start;
|
||||
final int end;
|
||||
final int diag;
|
||||
|
||||
public Snake(final int start, final int end, final int diag) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.diag = diag;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory to create instances of this specific diff algorithm.
|
||||
*/
|
||||
public static DiffAlgorithmFactory factory() {
|
||||
return new DiffAlgorithmFactory() {
|
||||
@Override
|
||||
public <T> DiffAlgorithmI<T>
|
||||
create() {
|
||||
return new MeyersDiffWithLinearSpace<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> DiffAlgorithmI<T>
|
||||
create(BiPredicate < T, T > equalizer) {
|
||||
return new MeyersDiffWithLinearSpace<T>(equalizer);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -72,26 +72,45 @@ public final class UnifiedDiffReader {
|
||||
// [/^---\s/, from_file], [/^\+\+\+\s/, to_file], [/^@@\s+\-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/, chunk],
|
||||
// [/^-/, del], [/^\+/, add], [/^\\ No newline at end of file$/, eof]];
|
||||
private UnifiedDiff parse() throws IOException, UnifiedDiffParserException {
|
||||
String headerTxt = "";
|
||||
LOG.log(Level.FINE, "header parsing");
|
||||
String line = null;
|
||||
while (READER.ready()) {
|
||||
line = READER.readLine();
|
||||
LOG.log(Level.FINE, "parsing line {0}", line);
|
||||
if (DIFF_COMMAND.validLine(line) || INDEX.validLine(line)
|
||||
|| FROM_FILE.validLine(line) || TO_FILE.validLine(line)
|
||||
|| NEW_FILE_MODE.validLine(line)) {
|
||||
break;
|
||||
} else {
|
||||
headerTxt += line + "\n";
|
||||
}
|
||||
}
|
||||
if (!"".equals(headerTxt)) {
|
||||
data.setHeader(headerTxt);
|
||||
}
|
||||
// String headerTxt = "";
|
||||
// LOG.log(Level.FINE, "header parsing");
|
||||
// String line = null;
|
||||
// while (READER.ready()) {
|
||||
// line = READER.readLine();
|
||||
// LOG.log(Level.FINE, "parsing line {0}", line);
|
||||
// if (DIFF_COMMAND.validLine(line) || INDEX.validLine(line)
|
||||
// || FROM_FILE.validLine(line) || TO_FILE.validLine(line)
|
||||
// || NEW_FILE_MODE.validLine(line)) {
|
||||
// break;
|
||||
// } else {
|
||||
// headerTxt += line + "\n";
|
||||
// }
|
||||
// }
|
||||
// if (!"".equals(headerTxt)) {
|
||||
// data.setHeader(headerTxt);
|
||||
// }
|
||||
|
||||
String line = READER.readLine();
|
||||
while (line != null) {
|
||||
if (!CHUNK.validLine(line)) {
|
||||
String headerTxt = "";
|
||||
LOG.log(Level.FINE, "header parsing");
|
||||
while (line != null) {
|
||||
LOG.log(Level.FINE, "parsing line {0}", line);
|
||||
if (validLine(line, DIFF_COMMAND, SIMILARITY_INDEX, INDEX,
|
||||
FROM_FILE, TO_FILE,
|
||||
RENAME_FROM, RENAME_TO,
|
||||
NEW_FILE_MODE, DELETED_FILE_MODE,
|
||||
CHUNK)) {
|
||||
break;
|
||||
} else {
|
||||
headerTxt += line + "\n";
|
||||
}
|
||||
line = READER.readLine();
|
||||
}
|
||||
if (!"".equals(headerTxt)) {
|
||||
data.setHeader(headerTxt);
|
||||
}
|
||||
if (line != null && !CHUNK.validLine(line)) {
|
||||
initFileIfNecessary();
|
||||
while (line != null && !CHUNK.validLine(line)) {
|
||||
if (!processLine(line, DIFF_COMMAND, SIMILARITY_INDEX, INDEX,
|
||||
@@ -107,7 +126,7 @@ public final class UnifiedDiffReader {
|
||||
processLine(line, CHUNK);
|
||||
while ((line = READER.readLine()) != null) {
|
||||
line = checkForNoNewLineAtTheEndOfTheFile(line);
|
||||
|
||||
|
||||
if (!processLine(line, LINE_NORMAL, LINE_ADD, LINE_DEL)) {
|
||||
throw new UnifiedDiffParserException("expected data line not found");
|
||||
}
|
||||
@@ -186,6 +205,19 @@ public final class UnifiedDiffReader {
|
||||
return false;
|
||||
//throw new UnifiedDiffParserException("parsing error at line " + line);
|
||||
}
|
||||
|
||||
private boolean validLine(String line, UnifiedDiffLine ... rules) {
|
||||
if (line == null) {
|
||||
return false;
|
||||
}
|
||||
for (UnifiedDiffLine rule : rules) {
|
||||
if (rule.validLine(line)) {
|
||||
LOG.fine(" >>> accepted rule " + rule.toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void initFileIfNecessary() {
|
||||
if (!originalTxt.isEmpty() || !revisedTxt.isEmpty()) {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2021 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.algorithm.myers;
|
||||
|
||||
import com.github.difflib.DiffUtils;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmListener;
|
||||
import com.github.difflib.patch.Patch;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import java.util.stream.IntStream;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tw
|
||||
*/
|
||||
public class MeyersDiffWithLinearSpaceTest {
|
||||
|
||||
@Test
|
||||
public void testDiffMyersExample1Forward() {
|
||||
List<String> original = Arrays.asList("A", "B", "C", "A", "B", "B", "A");
|
||||
List<String> revised = Arrays.asList("C", "B", "A", "B", "A", "C");
|
||||
final Patch<String> patch = Patch.generate(original, revised, new MeyersDiffWithLinearSpace<String>().computeDiff(original, revised, null));
|
||||
assertNotNull(patch);
|
||||
System.out.println(patch);
|
||||
assertEquals(5, patch.getDeltas().size());
|
||||
assertEquals("Patch{deltas=[[InsertDelta, position: 0, lines: [C]], [DeleteDelta, position: 0, lines: [A]], [DeleteDelta, position: 2, lines: [C]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiffMyersExample1ForwardWithListener() {
|
||||
List<String> original = Arrays.asList("A", "B", "C", "A", "B", "B", "A");
|
||||
List<String> revised = Arrays.asList("C", "B", "A", "B", "A", "C");
|
||||
|
||||
List<String> logdata = new ArrayList<>();
|
||||
final Patch<String> patch = Patch.generate(original, revised,
|
||||
new MeyersDiffWithLinearSpace<String>().computeDiff(original, revised, new DiffAlgorithmListener() {
|
||||
@Override
|
||||
public void diffStart() {
|
||||
logdata.add("start");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void diffStep(int value, int max) {
|
||||
logdata.add(value + " - " + max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void diffEnd() {
|
||||
logdata.add("end");
|
||||
}
|
||||
}));
|
||||
assertNotNull(patch);
|
||||
System.out.println(patch);
|
||||
assertEquals(5, patch.getDeltas().size());
|
||||
assertEquals("Patch{deltas=[[InsertDelta, position: 0, lines: [C]], [DeleteDelta, position: 0, lines: [A]], [DeleteDelta, position: 2, lines: [C]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
|
||||
System.out.println(logdata);
|
||||
assertEquals(11, logdata.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPerformanceProblemsIssue124() {
|
||||
List<String> old = Arrays.asList("abcd");
|
||||
List<String> newl = IntStream.range(0, 90000)
|
||||
.boxed()
|
||||
.map(i -> i.toString())
|
||||
.collect(toList());
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
Patch<String> diff = DiffUtils.diff(old, newl, new MeyersDiffWithLinearSpace<String>());
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println("Finished in " + (end - start) + "ms and resulted " + diff.getDeltas().size() + " deltas");
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,7 @@ public class MyersDiffTest {
|
||||
public void testDiffMyersExample1Forward() {
|
||||
List<String> original = Arrays.asList("A", "B", "C", "A", "B", "B", "A");
|
||||
List<String> revised = Arrays.asList("C", "B", "A", "B", "A", "C");
|
||||
final Patch<String> patch = Patch.generate(original, revised, new MyersDiff<String>().computeDiff(original, revised, null));
|
||||
final Patch<String> patch = Patch.generate(original, revised, new MeyersDiff<String>().computeDiff(original, revised, null));
|
||||
assertNotNull(patch);
|
||||
assertEquals(4, patch.getDeltas().size());
|
||||
assertEquals("Patch{deltas=[[DeleteDelta, position: 0, lines: [A, B]], [InsertDelta, position: 3, lines: [B]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
|
||||
@@ -47,7 +47,7 @@ public class MyersDiffTest {
|
||||
|
||||
List<String> logdata = new ArrayList<>();
|
||||
final Patch<String> patch = Patch.generate(original, revised,
|
||||
new MyersDiff<String>().computeDiff(original, revised, new DiffAlgorithmListener() {
|
||||
new MeyersDiff<String>().computeDiff(original, revised, new DiffAlgorithmListener() {
|
||||
@Override
|
||||
public void diffStart() {
|
||||
logdata.add("start");
|
||||
@@ -69,5 +69,4 @@ public class MyersDiffTest {
|
||||
System.out.println(logdata);
|
||||
assertEquals(8, logdata.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.github.difflib.patch;
|
||||
package com.github.difflib.algorithm.myers;
|
||||
|
||||
import com.github.difflib.patch.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
@@ -15,14 +16,14 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.github.difflib.DiffUtils;
|
||||
|
||||
public class PatchTest {
|
||||
public class WithMeyersDiffWithLinearSpacePatchTest {
|
||||
|
||||
@Test
|
||||
public void testPatch_Insert() {
|
||||
final List<String> insertTest_from = Arrays.asList("hhh");
|
||||
final List<String> insertTest_to = Arrays.asList("hhh", "jjj", "kkk", "lll");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(insertTest_from, insertTest_to);
|
||||
final Patch<String> patch = DiffUtils.diff(insertTest_from, insertTest_to, new MeyersDiffWithLinearSpace<String>());
|
||||
try {
|
||||
assertEquals(insertTest_to, DiffUtils.patch(insertTest_from, patch));
|
||||
} catch (PatchFailedException e) {
|
||||
@@ -35,7 +36,7 @@ public class PatchTest {
|
||||
final List<String> deleteTest_from = Arrays.asList("ddd", "fff", "ggg", "hhh");
|
||||
final List<String> deleteTest_to = Arrays.asList("ggg");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(deleteTest_from, deleteTest_to);
|
||||
final Patch<String> patch = DiffUtils.diff(deleteTest_from, deleteTest_to, new MeyersDiffWithLinearSpace<String>());
|
||||
try {
|
||||
assertEquals(deleteTest_to, DiffUtils.patch(deleteTest_from, patch));
|
||||
} catch (PatchFailedException e) {
|
||||
@@ -48,7 +49,7 @@ public class PatchTest {
|
||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to, new MeyersDiffWithLinearSpace<String>());
|
||||
try {
|
||||
assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, patch));
|
||||
} catch (PatchFailedException e) {
|
||||
@@ -61,7 +62,7 @@ public class PatchTest {
|
||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to, new MeyersDiffWithLinearSpace<String>());
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream out = new ObjectOutputStream(baos);
|
||||
out.writeObject(patch);
|
||||
@@ -84,7 +85,7 @@ public class PatchTest {
|
||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to, new MeyersDiffWithLinearSpace<String>());
|
||||
|
||||
changeTest_from.set(2, "CDC");
|
||||
|
||||
@@ -92,9 +93,9 @@ public class PatchTest {
|
||||
|
||||
try {
|
||||
List<String> data = DiffUtils.patch(changeTest_from, patch);
|
||||
assertEquals(9, data.size());
|
||||
assertEquals(11, data.size());
|
||||
|
||||
assertEquals(Arrays.asList("aaa", "<<<<<< HEAD", "bbb", "CDC", "======", "bbb", "ccc", ">>>>>>> PATCH", "ddd"), data);
|
||||
assertEquals(Arrays.asList("aaa", "bxb", "cxc", "<<<<<< HEAD", "bbb", "CDC", "======", "bbb", "ccc", ">>>>>>> PATCH", "ddd"), data);
|
||||
|
||||
} catch (PatchFailedException e) {
|
||||
fail(e.getMessage());
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.github.difflib.patch;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import com.github.difflib.DiffUtils;
|
||||
import com.github.difflib.algorithm.DiffAlgorithmFactory;
|
||||
import com.github.difflib.algorithm.myers.MeyersDiff;
|
||||
import com.github.difflib.algorithm.myers.MeyersDiffWithLinearSpace;
|
||||
import java.util.stream.Stream;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
public class PatchWithAllDiffAlgorithmsTest {
|
||||
|
||||
private static Stream<Arguments> provideAlgorithms() {
|
||||
return Stream.of(
|
||||
Arguments.of(MeyersDiff.factory()),
|
||||
Arguments.of(MeyersDiffWithLinearSpace.factory()));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterAll() {
|
||||
DiffUtils.withDefaultDiffAlgorithmFactory(MeyersDiff.factory());
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideAlgorithms")
|
||||
public void testPatch_Insert(DiffAlgorithmFactory factory) {
|
||||
DiffUtils.withDefaultDiffAlgorithmFactory(factory);
|
||||
|
||||
final List<String> insertTest_from = Arrays.asList("hhh");
|
||||
final List<String> insertTest_to = Arrays.asList("hhh", "jjj", "kkk", "lll");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(insertTest_from, insertTest_to);
|
||||
try {
|
||||
assertEquals(insertTest_to, DiffUtils.patch(insertTest_from, patch));
|
||||
} catch (PatchFailedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideAlgorithms")
|
||||
public void testPatch_Delete(DiffAlgorithmFactory factory) {
|
||||
DiffUtils.withDefaultDiffAlgorithmFactory(factory);
|
||||
|
||||
final List<String> deleteTest_from = Arrays.asList("ddd", "fff", "ggg", "hhh");
|
||||
final List<String> deleteTest_to = Arrays.asList("ggg");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(deleteTest_from, deleteTest_to);
|
||||
try {
|
||||
assertEquals(deleteTest_to, DiffUtils.patch(deleteTest_from, patch));
|
||||
} catch (PatchFailedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideAlgorithms")
|
||||
public void testPatch_Change(DiffAlgorithmFactory factory) {
|
||||
DiffUtils.withDefaultDiffAlgorithmFactory(factory);
|
||||
|
||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
|
||||
try {
|
||||
assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, patch));
|
||||
} catch (PatchFailedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideAlgorithms")
|
||||
public void testPatch_Serializable(DiffAlgorithmFactory factory) throws IOException, ClassNotFoundException {
|
||||
DiffUtils.withDefaultDiffAlgorithmFactory(factory);
|
||||
|
||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream out = new ObjectOutputStream(baos);
|
||||
out.writeObject(patch);
|
||||
out.close();
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
|
||||
ObjectInputStream in = new ObjectInputStream(bais);
|
||||
Patch<String> result = (Patch<String>) in.readObject();
|
||||
in.close();
|
||||
|
||||
try {
|
||||
assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, result));
|
||||
} catch (PatchFailedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2021 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.patch;
|
||||
|
||||
import com.github.difflib.DiffUtils;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tw
|
||||
*/
|
||||
public class PatchWithMeyerDiffTest {
|
||||
@Test
|
||||
public void testPatch_Change_withExceptionProcessor() {
|
||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
|
||||
|
||||
changeTest_from.set(2, "CDC");
|
||||
|
||||
patch.withConflictOutput(Patch.CONFLICT_PRODUCES_MERGE_CONFLICT);
|
||||
|
||||
try {
|
||||
List<String> data = DiffUtils.patch(changeTest_from, patch);
|
||||
assertEquals(9, data.size());
|
||||
|
||||
assertEquals(Arrays.asList("aaa", "<<<<<< HEAD", "bbb", "CDC", "======", "bbb", "ccc", ">>>>>>> PATCH", "ddd"), data);
|
||||
|
||||
} catch (PatchFailedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2021 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.patch;
|
||||
|
||||
import com.github.difflib.DiffUtils;
|
||||
import com.github.difflib.algorithm.myers.MeyersDiff;
|
||||
import com.github.difflib.algorithm.myers.MeyersDiffWithLinearSpace;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tw
|
||||
*/
|
||||
public class PatchWithMeyerDiffWithLinearSpaceTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void setupClass() {
|
||||
DiffUtils.withDefaultDiffAlgorithmFactory(MeyersDiffWithLinearSpace.factory());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void resetClass() {
|
||||
DiffUtils.withDefaultDiffAlgorithmFactory(MeyersDiff.factory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPatch_Change_withExceptionProcessor() {
|
||||
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
|
||||
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
|
||||
|
||||
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
|
||||
|
||||
changeTest_from.set(2, "CDC");
|
||||
|
||||
patch.withConflictOutput(Patch.CONFLICT_PRODUCES_MERGE_CONFLICT);
|
||||
|
||||
try {
|
||||
List<String> data = DiffUtils.patch(changeTest_from, patch);
|
||||
assertEquals(11, data.size());
|
||||
|
||||
assertEquals(Arrays.asList("aaa", "bxb", "cxc", "<<<<<< HEAD", "bbb", "CDC", "======", "bbb", "ccc", ">>>>>>> PATCH", "ddd"), data);
|
||||
|
||||
} catch (PatchFailedException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,4 +364,24 @@ public class UnifiedDiffReaderTest {
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseIssue122() throws IOException {
|
||||
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
|
||||
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue122.diff"));
|
||||
|
||||
assertThat(diff.getFiles().size()).isEqualTo(1);
|
||||
|
||||
assertThat(diff.getFiles()).extracting(f -> f.getFromFile()).contains("coders/wpg.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseIssue123() throws IOException {
|
||||
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
|
||||
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue123.diff"));
|
||||
|
||||
assertThat(diff.getFiles().size()).isEqualTo(2);
|
||||
|
||||
assertThat(diff.getFiles()).extracting(f -> f.getFromFile()).contains("src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
diff -r fcd3ed3394f6 -r 135bdcb88b8d coders/wpg.c
|
||||
--- a/coders/wpg.c Sun Nov 05 01:11:09 2017 +0100
|
||||
+++ b/coders/wpg.c Sun Nov 05 01:35:28 2017 +0100
|
||||
@@ -340,12 +340,15 @@
|
||||
|
||||
|
||||
if(RetVal==MagickFail)
|
||||
+ {
|
||||
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"ImportImagePixelArea failed for row: %ld, bpp: %d", y, bpp);
|
||||
+ return MagickFail;
|
||||
+ }
|
||||
|
||||
- if (!SyncImagePixels(image))
|
||||
+ if(!SyncImagePixels(image))
|
||||
{
|
||||
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"SyncImagePixels failed for row: %ld, bpp: %d", y, bpp);
|
||||
- RetVal = MagickFail;
|
||||
+ return MagickFail;
|
||||
}
|
||||
|
||||
return RetVal;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
Index: src/java/test/org/apache/zookeeper/test/ACLTest.java
|
||||
===================================================================
|
||||
--- src/java/test/org/apache/zookeeper/test/ACLTest.java (revision 1510080)
|
||||
+++ src/java/test/org/apache/zookeeper/test/ACLTest.java (working copy)
|
||||
@@ -28,6 +28,7 @@
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.zookeeper.CreateMode;
|
||||
+import org.apache.zookeeper.KeeperException;
|
||||
import org.apache.zookeeper.PortAssignment;
|
||||
import org.apache.zookeeper.WatchedEvent;
|
||||
import org.apache.zookeeper.Watcher;
|
||||
@@ -35,8 +36,10 @@
|
||||
import org.apache.zookeeper.ZooKeeper;
|
||||
import org.apache.zookeeper.Watcher.Event.KeeperState;
|
||||
import org.apache.zookeeper.ZooDefs.Ids;
|
||||
+import org.apache.zookeeper.ZooDefs.Perms;
|
||||
import org.apache.zookeeper.data.ACL;
|
||||
import org.apache.zookeeper.data.Id;
|
||||
+import org.apache.zookeeper.data.Stat;
|
||||
import org.apache.zookeeper.server.ServerCnxnFactory;
|
||||
import org.apache.zookeeper.server.SyncRequestProcessor;
|
||||
import org.apache.zookeeper.server.ZooKeeperServer;
|
||||
@@ -77,6 +80,48 @@
|
||||
ClientBase.CONNECTION_TIMEOUT));
|
||||
}
|
||||
}
|
||||
+
|
||||
+ /**
|
||||
+ * Verify that getAcl should fail when there is not
|
||||
+ * read permission to that node
|
||||
+ */
|
||||
+ @Test
|
||||
+ public void testAclReadPermission() throws Exception {
|
||||
+ File tmpDir = ClientBase.createTmpDir();
|
||||
+ ClientBase.setupTestEnv();
|
||||
+ ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
|
||||
+ SyncRequestProcessor.setSnapCount(1000);
|
||||
+ final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
|
||||
+ ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);
|
||||
+ f.startup(zks);
|
||||
+ ZooKeeper zk;
|
||||
+ String path = "/node1";
|
||||
+ boolean readPermLimitWorks = false;
|
||||
+ try {
|
||||
+ LOG.info("starting up the zookeeper server .. waiting");
|
||||
+ Assert.assertTrue("waiting for server being up",
|
||||
+ ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));
|
||||
+ zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);
|
||||
+ Id id = new Id("ip", "127.0.0.1");
|
||||
+ ArrayList<ACL> acl = new ArrayList<ACL>(); // Not set read permission
|
||||
+ acl.add(new ACL(Perms.CREATE, id));
|
||||
+ acl.add(new ACL(Perms.DELETE, id));
|
||||
+ acl.add(new ACL(Perms.WRITE, id));
|
||||
+ acl.add(new ACL(Perms.ADMIN, id));
|
||||
+ zk.create(path, path.getBytes(), acl, CreateMode.PERSISTENT);
|
||||
+ Stat stat = new Stat();
|
||||
+ zk.getACL(path, stat); // Should cause exception without read permission
|
||||
+ } catch (KeeperException.NoAuthException e) {
|
||||
+ readPermLimitWorks = true;
|
||||
+ } finally {
|
||||
+ f.shutdown();
|
||||
+ Assert.assertTrue("waiting for server down",
|
||||
+ ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT));
|
||||
+ }
|
||||
+ if (!readPermLimitWorks) {
|
||||
+ Assert.fail("Should not reach here as ACL has no read permission");
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/**
|
||||
* Verify that acl optimization of storing just
|
||||
Index: src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java
|
||||
===================================================================
|
||||
--- src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java (revision 1510080)
|
||||
+++ src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java (working copy)
|
||||
@@ -324,6 +324,17 @@
|
||||
GetACLRequest getACLRequest = new GetACLRequest();
|
||||
ByteBufferInputStream.byteBuffer2Record(request.request,
|
||||
getACLRequest);
|
||||
+ DataNode n = zks.getZKDatabase().getNode(getACLRequest.getPath());
|
||||
+ if (n == null) {
|
||||
+ throw new KeeperException.NoNodeException();
|
||||
+ }
|
||||
+ Long aclL;
|
||||
+ synchronized(n) {
|
||||
+ aclL = n.acl;
|
||||
+ }
|
||||
+ PrepRequestProcessor.checkACL(zks, zks.getZKDatabase().convertLong(aclL),
|
||||
+ ZooDefs.Perms.READ,
|
||||
+ request.authInfo);
|
||||
Stat stat = new Stat();
|
||||
List<ACL> acl =
|
||||
zks.getZKDatabase().getACL(getACLRequest.getPath(), stat);
|
||||
@@ -1,7 +1,7 @@
|
||||
handlers=java.util.logging.ConsoleHandler
|
||||
|
||||
.level=INFO
|
||||
com.github.difflib.unifieddiff.level=FINE
|
||||
com.github.difflib.unifieddiff.level=INFO
|
||||
|
||||
java.util.logging.ConsoleHandler.level=INFO
|
||||
#java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
|
||||
|
||||
Reference in New Issue
Block a user