All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fitbur.assertj.util.diff.DiffUtils Maven / Gradle / Ivy

There is a newer version: 1.0.0
Show newest version
/**
 * 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.
 *
 * Copyright 2012-2016 the original author or authors.
 */
package com.fitbur.assertj.util.diff;

import com.fitbur.assertj.util.diff.myers.Equalizer;
import com.fitbur.assertj.util.diff.myers.MyersDiff;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Copy from https://code.google.com/p/java-diff-utils/.
 * 

* Implements the difference and patching engine * * @author Dmitry Naumenko */ public class DiffUtils { private static Pattern unifiedDiffChunkRe = Pattern.compile("^@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@$"); /** * 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}. * @return The patch describing the difference between the original and * revised sequences. Never {@code null}. */ public static Patch diff(List original, List revised) { return DiffUtils.diff(original, revised, new MyersDiff()); } /** * 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 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 Patch diff(List original, List revised, Equalizer equalizer) { if (equalizer != null) { return DiffUtils.diff(original, revised, new MyersDiff<>(equalizer)); } return DiffUtils.diff(original, revised, new MyersDiff()); } /** * 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}. */ public static Patch diff(List original, List revised, DiffAlgorithm algorithm) { if (original == null) { throw new IllegalArgumentException("original must not be null"); } if (revised == null) { throw new IllegalArgumentException("revised must not be null"); } if (algorithm == null) { throw new IllegalArgumentException("algorithm must not be null"); } return algorithm.diff(original, revised); } /** * Patch the original text with given patch * * @param original * the original text * @param patch * the given patch * @return the revised text * @throws IllegalStateException * if can't apply patch */ public static List patch(List original, Patch patch) throws IllegalStateException { return patch.applyTo(original); } /** * Parse the given text in unified format and creates the list of deltas for * it. * * @param diff * the text in unified format * @return the patch with deltas. */ public static Patch parseUnifiedDiff(List diff) { boolean inPrelude = true; List rawChunk = new ArrayList<>(); Patch patch = new Patch<>(); int old_ln = 0, new_ln = 0; String tag; String rest; for (String line : diff) { // Skip leading lines until after we've seen one starting with '+++' if (inPrelude) { if (line.startsWith("+++")) { inPrelude = false; } continue; } Matcher m = unifiedDiffChunkRe.matcher(line); if (m.find()) { // Process the lines in the previous chunk if (rawChunk.size() != 0) { List oldChunkLines = new ArrayList<>(); List newChunkLines = new ArrayList<>(); for (String[] raw_line : rawChunk) { tag = raw_line[0]; rest = raw_line[1]; if (tag.equals(" ") || tag.equals("-")) { oldChunkLines.add(rest); } if (tag.equals(" ") || tag.equals("+")) { newChunkLines.add(rest); } } patch.addDelta(new ChangeDelta<>(new Chunk<>( old_ln - 1, oldChunkLines), new Chunk<>( new_ln - 1, newChunkLines))); rawChunk.clear(); } // Parse the @@ header old_ln = m.group(1) == null ? 1 : Integer.parseInt(m.group(1)); new_ln = m.group(3) == null ? 1 : Integer.parseInt(m.group(3)); if (old_ln == 0) { old_ln += 1; } if (new_ln == 0) { new_ln += 1; } } else { if (line.length() > 0) { tag = line.substring(0, 1); rest = line.substring(1); if (tag.equals(" ") || tag.equals("+") || tag.equals("-")) { rawChunk.add(new String[] { tag, rest }); } } else { rawChunk.add(new String[] { " ", "" }); } } } // Process the lines in the last chunk if (rawChunk.size() != 0) { List oldChunkLines = new ArrayList<>(); List newChunkLines = new ArrayList<>(); for (String[] raw_line : rawChunk) { tag = raw_line[0]; rest = raw_line[1]; if (tag.equals(" ") || tag.equals("-")) { oldChunkLines.add(rest); } if (tag.equals(" ") || tag.equals("+")) { newChunkLines.add(rest); } } patch.addDelta(new ChangeDelta<>(new Chunk<>(old_ln - 1, oldChunkLines), new Chunk<>(new_ln - 1, newChunkLines))); rawChunk.clear(); } return patch; } /** * generateUnifiedDiff takes a Patch and some other arguments, returning the * Unified Diff format text representing the Patch. * * @param original Filename of the original (unrevised file) * @param revised Filename of the revised file * @param originalLines Lines of the original file * @param patch Patch created by the diff() function * @param contextSize number of lines of context output around each difference * in the file. * @return List of strings representing the Unified Diff representation of * the Patch argument. * @author Bill James ([email protected]) */ public static List generateUnifiedDiff(String original, String revised, List originalLines, Patch patch, int contextSize) { if (!patch.getDeltas().isEmpty()) { List ret = new ArrayList<>(); ret.add("--- " + original); ret.add("+++ " + revised); List> patchDeltas = new ArrayList<>( patch.getDeltas()); // code outside the if block also works for single-delta issues. // current list of Delta's to process List> deltas = new ArrayList<>(); Delta delta = patchDeltas.get(0); deltas.add(delta); // add the first Delta to the current set // if there's more than 1 Delta, we may need to output them together if (patchDeltas.size() > 1) { for (int i = 1; i < patchDeltas.size(); i++) { // store the current position of the first Delta int position = delta.getOriginal().getPosition(); // Check if the next Delta is too close to the current // position. // And if it is, add it to the current set Delta nextDelta = patchDeltas.get(i); if ((position + delta.getOriginal().size() + contextSize) >= (nextDelta .getOriginal().getPosition() - contextSize)) { deltas.add(nextDelta); } else { // if it isn't, output the current set, // then create a new set and add the current Delta to // it. List curBlock = processDeltas(originalLines, deltas, contextSize); ret.addAll(curBlock); deltas.clear(); deltas.add(nextDelta); } delta = nextDelta; } } // don't forget to process the last set of Deltas List curBlock = processDeltas(originalLines, deltas, contextSize); ret.addAll(curBlock); return ret; } return new ArrayList<>(); } /** * processDeltas takes a list of Deltas and outputs them together in a * single block of Unified-Diff-format text. * * @param origLines the lines of the original file * @param deltas the Deltas to be output as a single block * @param contextSize the number of lines of context to place around block * @author Bill James ([email protected]) */ private static List processDeltas(List origLines, List> deltas, int contextSize) { List buffer = new ArrayList<>(); int origTotal = 0; // counter for total lines output from Original int revTotal = 0; // counter for total lines output from Original int line; Delta curDelta = deltas.get(0); // NOTE: +1 to overcome the 0-offset Position int origStart = curDelta.getOriginal().getPosition() + 1 - contextSize; if (origStart < 1) { origStart = 1; } int revStart = curDelta.getRevised().getPosition() + 1 - contextSize; if (revStart < 1) { revStart = 1; } // find the start of the wrapper context code int contextStart = curDelta.getOriginal().getPosition() - contextSize; if (contextStart < 0) { contextStart = 0; // clamp to the start of the file } // output the context before the first Delta for (line = contextStart; line < curDelta.getOriginal().getPosition(); line++) { // buffer.add(" " + origLines.get(line)); origTotal++; revTotal++; } // output the first Delta buffer.addAll(getDeltaText(curDelta)); origTotal += curDelta.getOriginal().getLines().size(); revTotal += curDelta.getRevised().getLines().size(); int deltaIndex = 1; while (deltaIndex < deltas.size()) { // for each of the other Deltas Delta nextDelta = deltas.get(deltaIndex); int intermediateStart = curDelta.getOriginal().getPosition() + curDelta.getOriginal().getLines().size(); for (line = intermediateStart; line < nextDelta.getOriginal() .getPosition(); line++) { // output the code between the last Delta and this one buffer.add(" " + origLines.get(line)); origTotal++; revTotal++; } buffer.addAll(getDeltaText(nextDelta)); // output the Delta origTotal += nextDelta.getOriginal().getLines().size(); revTotal += nextDelta.getRevised().getLines().size(); curDelta = nextDelta; deltaIndex++; } // Now output the post-Delta context code, clamping the end of the file contextStart = curDelta.getOriginal().getPosition() + curDelta.getOriginal().getLines().size(); for (line = contextStart; (line < (contextStart + contextSize)) && (line < origLines.size()); line++) { buffer.add(" " + origLines.get(line)); origTotal++; revTotal++; } // Create and insert the block header, conforming to the Unified Diff // standard String header = "@@ -" + origStart + "," + origTotal + " +" + revStart + "," + revTotal + " @@"; buffer.add(0, header); return buffer; } /** * getDeltaText returns the lines to be added to the Unified Diff text from * the Delta parameter * * @param delta the Delta to output * @return list of String lines of code. * @author Bill James ([email protected]) */ private static List getDeltaText(Delta delta) { List buffer = new ArrayList<>(); for (String original : delta.getOriginal().getLines()) { buffer.add("-" + original); } for (String original : delta.getRevised().getLines()) { buffer.add("+" + original); } return buffer; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy