diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000000000000000000000000000000000..041b5c5122fd94748f90ce4cc3bcacee02586fd2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,24 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Example data +2. simple programm snippet +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**System** + - Java version + - Version [e.g. 22] diff --git a/.gitignore b/.gitignore index 0643ce7d4db53b5f89aa0ff88388a405cf0d6cdc..54a9c8cab252ea43b5a67dcb5e1dd3248bfa6887 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ -/target/ -/nbproject/ \ No newline at end of file +.idea/ +build/ +nbproject/ +target/ diff --git a/.travis.yml b/.travis.yml index e68631bc3763b30c0c0793836b447eb8a6d847c6..a4870debefd821883960deaef432fdf9111a1d14 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: java jdk: - - oraclejdk8 + - openjdk8 + - openjdk11 after_success: - - mvn clean \ No newline at end of file + - mvn clean diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000000000000000000000000000000000..2ba1be15dbb35f50d70b65114c6b6b831247be0f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,85 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +This project uses a custom versioning scheme (and not [Semantic Versioning](https://semver.org/spec/v2.0.0.html)). + +## [Unreleased] + +### Changed + +* Exchange `0 += 1` for `0 = 1` in UnifiedDiffUtils +* preview of new Unified Diff Reader / Writer. This is not yet feature complete but passes the tests of the old version. + * feel free to issue some change requests for the api. +* introduces lineNormalizer extension point to e.g. change html code encoding. (issue #41) + +## [4.0] – 2019-01-09 + +### Changed + +* moved to organisation **java-diff-utils** +* changed groupid to **io.github.java-diff-utils** and artifact id to **java-diff-utils** + +## [3.0] – 2018-10-18 + +### Added + +* Introduced a process listener to diff algorithms. For long running + diffs one could implement some progress information. +* automatic module name for JDK 9 and higher usage + +### Changed + +* changed generation of inline diffes, if there are different linefeeds within one diff, then these are excluded from the diff block. + +### Removed + +* Due to licensing issues Delta.java and DiffAlgorithm.java were removed. + +## [2.2] – 2017-11-09 + +### Added + +* released at maven central +* included checkstyle source code conventions +* allow configurable splitting of lines to define the blocks to compare (words, characters, phrases). + +### Changed + +* groupid changed to **com.github.wumpz**, due to maven central releasing + +## [2.0] – 2017-08-14 + +### Added + +* support for inline merge +* integrated JGit (Eclipse Licensed) to provide HistogramDiff to gain speed for large datasets + +### Changed + +* switch to maven and removed other artifacts +* changed groupid to **com.github.java-diff-utils** due to different forks at github +* updated maven plugins +* JDK 1.8 compatibility, sorry if you have to stick with older versions +* restructured packages heavily +* changed API +* changed Algorithm to provide only cursor positions + +### Removed + +* removed all kinds of helper classes in favour of new JDK 8 function classes like Predicate + +## 1.2 + +### Added + +* JDK 1.5 compatibility +* Ant build script +* Generate output in unified diff format (thanks for Bill James) + +[Unreleased]: https://github.com/java-diff-utils/java-diff-utils/compare/java-diff-utils-4.0...HEAD +[4.0]: https://github.com/java-diff-utils/java-diff-utils/compare/diff-utils-3.0...java-diff-utils-4.0 +[3.0]: https://github.com/java-diff-utils/java-diff-utils/compare/diff-utils-2.2...diff-utils-3.0 +[2.2]: https://github.com/java-diff-utils/java-diff-utils/compare/diff-utils-2.0...diff-utils-2.2 + diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index 057f67a40ad4fd9b0e557ccf4df6b0ab656348af..0000000000000000000000000000000000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,17 +0,0 @@ -### Expected Behavior - - -### Actual Behavior - - -### Steps to Reproduce the Problem - - 1. - 1. - 1. - -### Specifications - - - Version: - - Platform: - - Subsystem: diff --git a/README.md b/README.md index e62f0e5ccb2447c545a6cacaec13cf41db70f3ef..e0d8f1226bd962d398f0064e5c384b2d73e94b7e 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,22 @@ # java-diff-utils -## Status ## -[](https://travis-ci.org/java-diff-utils/java-diff-utils) [](https://www.codacy.com/app/wumpz/java-diff-utils?utm_source=github.com&utm_medium=referral&utm_content=java-diff-utils/java-diff-utils&utm_campaign=Badge_Grade) -[](http://maven-badges.herokuapp.com/maven-central/com.github.wumpz/diffutils) +## Status +[](https://travis-ci.org/java-diff-utils/java-diff-utils) +[](https://www.codacy.com/app/wumpz/java-diff-utils?utm_source=github.com&utm_medium=referral&utm_content=java-diff-utils/java-diff-utils&utm_campaign=Badge_Grade) +[](http://maven-badges.herokuapp.com/maven-central/io.github.java-diff-utils/java-diff-utils) + +## Intro -## Intro ## Diff Utils library is an OpenSource library for performing the comparison operations between texts: computing diffs, applying patches, generating unified diffs or parsing them, generating diff output for easy future displaying (like side-by-side view) and so on. Main reason to build this library was the lack of easy-to-use libraries with all the usual stuff you need while working with diff files. Originally it was inspired by JRCS library and it's nice design of diff module. **This is originally a fork of java-diff-utils from Google Code Archive.** -## Examples ## +## Examples -Look [here](https://github.com/wumpz/java-diff-utils/wiki) to find more helpful informations and examples. +Look [here](https://github.com/wumpz/java-diff-utils/wiki) to find more helpful informations and examples. These two outputs are generated using this java-diff-utils. The source code can also be found at the *Examples* page: @@ -22,7 +24,6 @@ These two outputs are generated using this java-diff-utils. The source code can This is a test ~senctence~**for diffutils**. - **Producing a side by side view of computed differences.** |original|new| @@ -31,102 +32,61 @@ This is a test ~senctence~**for diffutils**. |This is the second line.|This is the second line.| |~And here is the finish.~|| +## Main Features -## Main Features ## +* computing the difference between two texts. +* capable to hand more than plain ascii. Arrays or List of any type that implements hashCode() and equals() correctly can be subject to differencing using this library +* patch and unpatch the text with the given patch +* parsing the unified diff format +* producing human-readable differences +* inline difference construction +* Algorithms: + * Myer + * HistogramDiff using JGit Library - * computing the difference between two texts. - * capable to hand more than plain ascci. Arrays or List of any type that implements hashCode() and equals() correctly can be subject to differencing using this library - * patch and unpatch the text with the given patch - * parsing the unified diff format - * producing human-readable differences - * inline difference construction - * Algorithms: - * Myer - * HistogramDiff using JGit Library - -### Algoritms ### +### Algorithms * Myer's diff -* HistogramDiff +* HistogramDiff But it can easily replaced by any other which is better for handing your texts. I have plan to add implementation of some in future. -### Changelog ### - * Version 4.0-SNAPSHOT - * moved to organisation **java-diff-utils** - * changed groupid to **io.github.java-diff-utils** and artifact id to **java-diff-utils** - * Version 3.0 - * changed generation of inline diffes, if there are different linefeeds within one diff, then these are excluded - from the diff block. - * Due to licensing issues Delta.java and DiffAlgorithm.java were removed. - * Version 2.3-SNAPSHOT - * Introduced a process listener to diff algorithms. For long running - diffs one could implement some progress information. - * automatic module name for JDK 9 and higher usage - * Version 2.2 - * released at maven central - * included checkstyle source code conventions - * groupid changed to **com.github.wumpz**, due to maven central releasing - * allow configurable splitting of lines to define the blocks to compare (words, characters, phrases). - * Version 2.0 - * switch to maven and removed other artifacts - * changed groupid to **com.github.java-diff-utils** due to different forks at github - * updated maven plugins - * JDK 1.8 compatibility, sorry if you have to stick with older versions - * support for inline merge - * restructured packages heavily - * changed API - * changed Algorithm to provide only cursor positions - * integrated JGit (Eclipse Licensed) to provide HistogramDiff to gain speed for large datasets - * removed all kinds of helper classes in favour of new JDK 8 function classes like Predicate - * Version 1.2 - * JDK 1.5 compatibility - * Ant build script - * Generate output in unified diff format (thanks for Bill James) - ## Source Code conventions Recently a checkstyle process was integrated into the build process. java-diff-utils follows the sun java format convention. There are no TABs allowed. Use spaces. ```java public static <T> Patch<T> diff(List<T> original, List<T> revised, - BiPredicate<T, T> equalizer) throws DiffException { - if (equalizer != null) { - return DiffUtils.diff(original, revised, - new MyersDiff<>(equalizer)); - } - return DiffUtils.diff(original, revised, new MyersDiff<>()); + BiPredicate<T, T> equalizer) throws DiffException { + if (equalizer != null) { + return DiffUtils.diff(original, revised, + new MyersDiff<>(equalizer)); + } + return DiffUtils.diff(original, revised, new MyersDiff<>()); } ``` This is a valid piece of source code: + * blocks without braces are not allowed * after control statements (if, while, for) a whitespace is expected * the opening brace should be in the same line as the control statement -### To Install ### +### To Install Just add the code below to your maven dependencies: -``` -<dependency> - <groupId>com.github.wumpz</groupId> - <artifactId>diffutils</artifactId> - <version>3.0</version> -</dependency> -``` - -Attention. We changed groupid and artifactid. Starting with version 4 you have to use: -``` +```xml <dependency> <groupId>io.github.java-diff-utils</groupId> <artifactId>java-diff-utils</artifactId> - <version>4.0-SNAPSHOT</version> + <version>4.0</version> </dependency> ``` or using gradle: -``` -// https://mvnrepository.com/artifact/com.github.wumpz/diffutils -compile group: 'com.github.wumpz', name: 'diffutils', version: '2.2' + +```groovy +// https://mvnrepository.com/artifact/io.github.java-diff-utils/java-diff-utils +implementation "io.github.java-diff-utils:java-diff-utils:4.0" ``` diff --git a/java-diff-utils-jgit/nb-configuration.xml b/java-diff-utils-jgit/nb-configuration.xml new file mode 100644 index 0000000000000000000000000000000000000000..ca588fa8dbba2a7a1566772665f8c70c90a6ba87 --- /dev/null +++ b/java-diff-utils-jgit/nb-configuration.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project-shared-configuration> + <!-- +This file contains additional configuration written by modules in the NetBeans IDE. +The configuration is intended to be shared among all the users of project and +therefore it is assumed to be part of version control checkout. +Without this configuration present, some functionality in the IDE may be limited or fail altogether. +--> + <properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1"> + <!-- +Properties that influence various parts of the IDE, especially code formatting and the like. +You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up. +That way multiple projects can share the same settings (useful for formatting rules for example). +Any value defined here will override the pom.xml file value but is only applicable to the current project. +--> + <netbeans.compile.on.save>none</netbeans.compile.on.save> + <netbeans.hint.jdkPlatform>JDK_1.8</netbeans.hint.jdkPlatform> + </properties> +</project-shared-configuration> diff --git a/java-diff-utils-jgit/pom.xml b/java-diff-utils-jgit/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..7b37a55080aa7dd7ab1650dc6b03a5ea246e4e07 --- /dev/null +++ b/java-diff-utils-jgit/pom.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>io.github.java-diff-utils</groupId> + <artifactId>java-diff-utils-parent</artifactId> + <version>4.4</version> + </parent> + <artifactId>java-diff-utils-jgit</artifactId> + <name>java-diff-utils-jgit</name> + <packaging>jar</packaging> + <description>This is an extension of java-diff-utils using jgit to use its implementation of +some difference algorithms.</description> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <type>jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jgit</groupId> + <artifactId>org.eclipse.jgit</artifactId> + <version>4.4.1.201607150455-r</version> + <exclusions> + <exclusion> + <groupId>com.googlecode.javaewah</groupId> + <artifactId>JavaEWAH</artifactId> + </exclusion> + <exclusion> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + </exclusion> + <exclusion> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </exclusion> + <exclusion> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + </exclusion> + <exclusion> + <groupId>com.jcraft</groupId> + <artifactId>jsch</artifactId> + </exclusion> + <exclusion> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>java-diff-utils</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> \ No newline at end of file diff --git a/src/main/java/com/github/difflib/algorithm/jgit/HistogramDiff.java b/java-diff-utils-jgit/src/main/java/com/github/difflib/algorithm/jgit/HistogramDiff.java similarity index 96% rename from src/main/java/com/github/difflib/algorithm/jgit/HistogramDiff.java rename to java-diff-utils-jgit/src/main/java/com/github/difflib/algorithm/jgit/HistogramDiff.java index c2e941f2f3556a0d83fe5bb0dabd9c3ce48d3570..e3f6cd5b5fad7d357ed18c78989a2b86cb8402ef 100644 --- a/src/main/java/com/github/difflib/algorithm/jgit/HistogramDiff.java +++ b/java-diff-utils-jgit/src/main/java/com/github/difflib/algorithm/jgit/HistogramDiff.java @@ -18,7 +18,6 @@ package com.github.difflib.algorithm.jgit; import com.github.difflib.algorithm.Change; import com.github.difflib.algorithm.DiffAlgorithmI; import com.github.difflib.algorithm.DiffAlgorithmListener; -import com.github.difflib.algorithm.DiffException; import com.github.difflib.patch.DeltaType; import java.util.ArrayList; import java.util.List; @@ -37,7 +36,7 @@ import org.eclipse.jgit.diff.SequenceComparator; public class HistogramDiff<T> implements DiffAlgorithmI<T> { @Override - public List<Change> computeDiff(List<T> source, List<T> target, DiffAlgorithmListener progress) throws DiffException { + 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) { diff --git a/src/test/java/com/github/difflib/algorithm/jgit/HistogramDiffTest.java b/java-diff-utils-jgit/src/test/java/com/github/difflib/algorithm/jgit/HistogramDiffTest.java similarity index 94% rename from src/test/java/com/github/difflib/algorithm/jgit/HistogramDiffTest.java rename to java-diff-utils-jgit/src/test/java/com/github/difflib/algorithm/jgit/HistogramDiffTest.java index 0009f18b20a5ca0e95b88546f6b24ab2627beb5f..e1030242a5969140c6d0bfff795829d9b97fb082 100644 --- a/src/test/java/com/github/difflib/algorithm/jgit/HistogramDiffTest.java +++ b/java-diff-utils-jgit/src/test/java/com/github/difflib/algorithm/jgit/HistogramDiffTest.java @@ -16,7 +16,6 @@ package com.github.difflib.algorithm.jgit; import com.github.difflib.algorithm.DiffAlgorithmListener; -import com.github.difflib.algorithm.DiffException; import com.github.difflib.patch.Patch; import com.github.difflib.patch.PatchFailedException; import java.util.ArrayList; @@ -58,7 +57,7 @@ public class HistogramDiffTest { * Test of diff method, of class HistogramDiff. */ @Test - public void testDiff() throws DiffException, PatchFailedException { + public void testDiff() throws PatchFailedException { List<String> orgList = Arrays.asList("A", "B", "C", "A", "B", "B", "A"); List<String> revList = Arrays.asList("C", "B", "A", "B", "A", "C"); final Patch<String> patch = Patch.generate(orgList, revList, new HistogramDiff().computeDiff(orgList, revList, null)); @@ -72,7 +71,7 @@ public class HistogramDiffTest { } @Test - public void testDiffWithListener() throws DiffException, PatchFailedException { + public void testDiffWithListener() throws PatchFailedException { List<String> orgList = Arrays.asList("A", "B", "C", "A", "B", "B", "A"); List<String> revList = Arrays.asList("C", "B", "A", "B", "A", "C"); diff --git a/src/test/java/com/github/difflib/algorithm/jgit/LRHistogramDiffTest.java b/java-diff-utils-jgit/src/test/java/com/github/difflib/algorithm/jgit/LRHistogramDiffTest.java similarity index 77% rename from src/test/java/com/github/difflib/algorithm/jgit/LRHistogramDiffTest.java rename to java-diff-utils-jgit/src/test/java/com/github/difflib/algorithm/jgit/LRHistogramDiffTest.java index 5f93570d108ab3812b79758f7a70732413813591..02dfe85d141b5853a6325412dd0ae2c2c7709755 100644 --- a/src/test/java/com/github/difflib/algorithm/jgit/LRHistogramDiffTest.java +++ b/java-diff-utils-jgit/src/test/java/com/github/difflib/algorithm/jgit/LRHistogramDiffTest.java @@ -15,15 +15,18 @@ */ package com.github.difflib.algorithm.jgit; -import static com.github.difflib.DiffUtilsTest.readStringListFromInputStream; -import com.github.difflib.TestConstants; import com.github.difflib.algorithm.DiffAlgorithmListener; -import com.github.difflib.algorithm.DiffException; import com.github.difflib.patch.Patch; import com.github.difflib.patch.PatchFailedException; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import static java.util.stream.Collectors.toList; import java.util.zip.ZipFile; import org.junit.After; import org.junit.AfterClass; @@ -58,8 +61,8 @@ public class LRHistogramDiffTest { } @Test - public void testPossibleDiffHangOnLargeDatasetDnaumenkoIssue26() throws IOException, DiffException, PatchFailedException { - ZipFile zip = new ZipFile(TestConstants.MOCK_FOLDER + "/large_dataset1.zip"); + public void testPossibleDiffHangOnLargeDatasetDnaumenkoIssue26() throws IOException, PatchFailedException { + ZipFile zip = new ZipFile("target/test-classes/mocks/large_dataset1.zip"); List<String> original = readStringListFromInputStream(zip.getInputStream(zip.getEntry("ta"))); List<String> revised = readStringListFromInputStream(zip.getInputStream(zip.getEntry("tb"))); @@ -86,7 +89,14 @@ public class LRHistogramDiffTest { List<String> created = patch.applyTo(original); assertArrayEquals(revised.toArray(), created.toArray()); - assertEquals(50, logdata.size()); + assertEquals(246579, logdata.size()); } + public static List<String> readStringListFromInputStream(InputStream is) throws IOException { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(is, Charset.forName(StandardCharsets.UTF_8.name())))) { + + return reader.lines().collect(toList()); + } + } } diff --git a/src/test/resources/mocks/large_dataset1.zip b/java-diff-utils-jgit/src/test/resources/mocks/large_dataset1.zip similarity index 100% rename from src/test/resources/mocks/large_dataset1.zip rename to java-diff-utils-jgit/src/test/resources/mocks/large_dataset1.zip diff --git a/java-diff-utils/pom.xml b/java-diff-utils/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ea4d774a257eb9dba7500e27b93563811c65aef6 --- /dev/null +++ b/java-diff-utils/pom.xml @@ -0,0 +1,60 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>io.github.java-diff-utils</groupId> + <artifactId>java-diff-utils</artifactId> + <packaging>jar</packaging> + <name>java-diff-utils</name> + <parent> + <groupId>io.github.java-diff-utils</groupId> + <artifactId>java-diff-utils-parent</artifactId> + <version>4.4</version> + </parent> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + <type>jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.assertj</groupId> + <artifactId>assertj-core</artifactId> + <version>3.11.1</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.6.1</version> + <configuration> + <source>1.8</source> + <target>1.8</target> + <encoding>UTF-8</encoding> + </configuration> + </plugin> + <plugin> + <artifactId>maven-jar-plugin</artifactId> + <version>3.0.2</version> + <configuration> + <archive> + <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> + <manifestEntries> + <!-- identical to OSGI name --> + <Automatic-Module-Name>io.github.java-diff-utils</Automatic-Module-Name> + </manifestEntries> + </archive> + </configuration> + </plugin> + </plugins> + </build> +</project> + diff --git a/src/main/java/com/github/difflib/DiffUtils.java b/java-diff-utils/src/main/java/com/github/difflib/DiffUtils.java similarity index 98% rename from src/main/java/com/github/difflib/DiffUtils.java rename to java-diff-utils/src/main/java/com/github/difflib/DiffUtils.java index 8b144642173334be865a91628a14e86e64e10883..b57a0d2f2e1db628e149e43d5addc88069e9a413 100644 --- a/src/main/java/com/github/difflib/DiffUtils.java +++ b/java-diff-utils/src/main/java/com/github/difflib/DiffUtils.java @@ -28,7 +28,6 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.function.BiPredicate; -import static java.util.stream.Collectors.joining; /** * Implements the difference and patching engine @@ -143,7 +142,7 @@ public final class DiffUtils { if (lines.isEmpty()) { return Collections.emptyList(); } - return Collections.singletonList(lines.stream().collect(joining(delimiter))); + return Collections.singletonList(String.join(delimiter, lines)); } /** diff --git a/src/main/java/com/github/difflib/UnifiedDiffUtils.java b/java-diff-utils/src/main/java/com/github/difflib/UnifiedDiffUtils.java similarity index 99% rename from src/main/java/com/github/difflib/UnifiedDiffUtils.java rename to java-diff-utils/src/main/java/com/github/difflib/UnifiedDiffUtils.java index fe5b6f69631afb40524e8b38aaaccddbf963ccf3..d5812c3193c587ee103f9565cb2aa9ab15e326bb 100644 --- a/src/main/java/com/github/difflib/UnifiedDiffUtils.java +++ b/java-diff-utils/src/main/java/com/github/difflib/UnifiedDiffUtils.java @@ -83,10 +83,10 @@ public final class UnifiedDiffUtils { new_ln = m.group(3) == null ? 1 : Integer.parseInt(m.group(3)); if (old_ln == 0) { - old_ln += 1; + old_ln = 1; } if (new_ln == 0) { - new_ln += 1; + new_ln = 1; } } else { if (line.length() > 0) { diff --git a/src/main/java/com/github/difflib/algorithm/Change.java b/java-diff-utils/src/main/java/com/github/difflib/algorithm/Change.java similarity index 100% rename from src/main/java/com/github/difflib/algorithm/Change.java rename to java-diff-utils/src/main/java/com/github/difflib/algorithm/Change.java diff --git a/src/main/java/com/github/difflib/algorithm/DiffAlgorithmI.java b/java-diff-utils/src/main/java/com/github/difflib/algorithm/DiffAlgorithmI.java similarity index 100% rename from src/main/java/com/github/difflib/algorithm/DiffAlgorithmI.java rename to java-diff-utils/src/main/java/com/github/difflib/algorithm/DiffAlgorithmI.java diff --git a/src/main/java/com/github/difflib/algorithm/DiffAlgorithmListener.java b/java-diff-utils/src/main/java/com/github/difflib/algorithm/DiffAlgorithmListener.java similarity index 100% rename from src/main/java/com/github/difflib/algorithm/DiffAlgorithmListener.java rename to java-diff-utils/src/main/java/com/github/difflib/algorithm/DiffAlgorithmListener.java diff --git a/src/main/java/com/github/difflib/algorithm/DiffException.java b/java-diff-utils/src/main/java/com/github/difflib/algorithm/DiffException.java similarity index 100% rename from src/main/java/com/github/difflib/algorithm/DiffException.java rename to java-diff-utils/src/main/java/com/github/difflib/algorithm/DiffException.java diff --git a/src/main/java/com/github/difflib/algorithm/DifferentiationFailedException.java b/java-diff-utils/src/main/java/com/github/difflib/algorithm/DifferentiationFailedException.java similarity index 93% rename from src/main/java/com/github/difflib/algorithm/DifferentiationFailedException.java rename to java-diff-utils/src/main/java/com/github/difflib/algorithm/DifferentiationFailedException.java index 682a9b484fa33ffe5d35259d2af1143b033f01a4..e201e440a8b586ce94473797ce0583e22fcc1c48 100644 --- a/src/main/java/com/github/difflib/algorithm/DifferentiationFailedException.java +++ b/java-diff-utils/src/main/java/com/github/difflib/algorithm/DifferentiationFailedException.java @@ -18,8 +18,8 @@ package com.github.difflib.algorithm; /** * Thrown whenever the differencing engine cannot produce the differences between two revisions of ta text. * - * @see MyersDiff - * @see difflib.DiffAlgorithm + * @see com.github.difflib.algorithm.myers.MyersDiff + * @see DiffAlgorithmI */ public class DifferentiationFailedException extends DiffException { diff --git a/src/main/java/com/github/difflib/algorithm/myers/MyersDiff.java b/java-diff-utils/src/main/java/com/github/difflib/algorithm/myers/MyersDiff.java similarity index 99% rename from src/main/java/com/github/difflib/algorithm/myers/MyersDiff.java rename to java-diff-utils/src/main/java/com/github/difflib/algorithm/myers/MyersDiff.java index 8c1834117cb3adcdcf46878140fd45a957bad6b6..abcf31e229f06cc538157bd38d9b896a341e34c8 100644 --- a/src/main/java/com/github/difflib/algorithm/myers/MyersDiff.java +++ b/java-diff-utils/src/main/java/com/github/difflib/algorithm/myers/MyersDiff.java @@ -138,7 +138,7 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> { /** * Constructs a {@link Patch} from a difference path. * - * @param path The path. + * @param actualPath The path. * @param orig The original sequence. * @param rev The revised sequence. * @return A {@link Patch} script corresponding to the path. diff --git a/src/main/java/com/github/difflib/algorithm/myers/PathNode.java b/java-diff-utils/src/main/java/com/github/difflib/algorithm/myers/PathNode.java similarity index 87% rename from src/main/java/com/github/difflib/algorithm/myers/PathNode.java rename to java-diff-utils/src/main/java/com/github/difflib/algorithm/myers/PathNode.java index a3f2070c3697ea25aedb6e644405094e9e5e8ef8..fe8fd03aff8e133847e255373a3ca20c78274464 100644 --- a/src/main/java/com/github/difflib/algorithm/myers/PathNode.java +++ b/java-diff-utils/src/main/java/com/github/difflib/algorithm/myers/PathNode.java @@ -19,10 +19,6 @@ package com.github.difflib.algorithm.myers; * A node in a diffpath. * * @author <a href="mailto:juanco@suigeneris.org">Juanco Anez</a> - * - * @see DiffNode - * @see Snake - * */ public final class PathNode { @@ -78,10 +74,10 @@ public final class PathNode { } /** - * Skips sequences of {@link DiffNode DiffNodes} until a {@link Snake} or bootstrap node is found, or the end of the + * Skips sequences of {@link PathNode PathNodes} until a snake or bootstrap node is found, or the end of the * path is reached. * - * @return The next first {@link Snake} or bootstrap node in the path, or <code>null</code> if none found. + * @return The next first {@link PathNode} or bootstrap node in the path, or <code>null</code> if none found. */ public final PathNode previousSnake() { if (isBootstrap()) { @@ -102,9 +98,9 @@ public final class PathNode { PathNode node = this; while (node != null) { buf.append("("); - buf.append(Integer.toString(node.i)); + buf.append(node.i); buf.append(","); - buf.append(Integer.toString(node.j)); + buf.append(node.j); buf.append(")"); node = node.prev; } diff --git a/src/main/java/com/github/difflib/patch/AbstractDelta.java b/java-diff-utils/src/main/java/com/github/difflib/patch/AbstractDelta.java similarity index 100% rename from src/main/java/com/github/difflib/patch/AbstractDelta.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/AbstractDelta.java diff --git a/src/main/java/com/github/difflib/patch/ChangeDelta.java b/java-diff-utils/src/main/java/com/github/difflib/patch/ChangeDelta.java similarity index 97% rename from src/main/java/com/github/difflib/patch/ChangeDelta.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/ChangeDelta.java index 43f68b3546f489e8ac6b6224a3db4943deadf598..7c1cd98bb95347819a71c9b5824f9c544b4883d7 100644 --- a/src/main/java/com/github/difflib/patch/ChangeDelta.java +++ b/java-diff-utils/src/main/java/com/github/difflib/patch/ChangeDelta.java @@ -22,7 +22,7 @@ import java.util.Objects; * Describes the change-delta between original and revised texts. * * @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a> - * @param T The type of the compared elements in the data 'lines'. + * @param <T> The type of the compared elements in the data 'lines'. */ public final class ChangeDelta<T> extends AbstractDelta<T> { diff --git a/src/main/java/com/github/difflib/patch/Chunk.java b/java-diff-utils/src/main/java/com/github/difflib/patch/Chunk.java similarity index 90% rename from src/main/java/com/github/difflib/patch/Chunk.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/Chunk.java index ed70e20d9ec1af9d9d6007a23156df36d9b59025..70b57223caab109e3c3adde41dc98667fc1a694e 100644 --- a/src/main/java/com/github/difflib/patch/Chunk.java +++ b/java-diff-utils/src/main/java/com/github/difflib/patch/Chunk.java @@ -15,6 +15,7 @@ */ package com.github.difflib.patch; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -23,13 +24,14 @@ import java.util.Objects; * Holds the information about the part of text involved in the diff process * * <p> - * Text is represented as <code>Object[]</code> because the diff engine is capable of handling more than plain ascci. In - * fact, arrays or lists of any type that implements {@link java.lang.Object#hashCode hashCode()} and - * {@link java.lang.Object#equals equals()} correctly can be subject to differencing using this library. + * Text is represented as <code>Object[]</code> because the diff engine is capable of handling more + * than plain ascci. In fact, arrays or lists of any type that implements + * {@link java.lang.Object#hashCode hashCode()} and {@link java.lang.Object#equals equals()} + * correctly can be subject to differencing using this library. * </p> * * @author <a href="dm.naumenko@gmail.com>Dmitry Naumenko</a> - * @param T The type of the compared elements in the 'lines'. + * @param <T> The type of the compared elements in the 'lines'. */ public final class Chunk<T> { @@ -44,7 +46,7 @@ public final class Chunk<T> { */ public Chunk(int position, List<T> lines) { this.position = position; - this.lines = lines; + this.lines = new ArrayList<>(lines); } /** diff --git a/src/main/java/com/github/difflib/patch/DeleteDelta.java b/java-diff-utils/src/main/java/com/github/difflib/patch/DeleteDelta.java similarity index 96% rename from src/main/java/com/github/difflib/patch/DeleteDelta.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/DeleteDelta.java index 66a928cab8ac3cdd8457b7054020514a6f77efbb..cfbc427cc455cd05183ae5095ea08fc6e1f03df3 100644 --- a/src/main/java/com/github/difflib/patch/DeleteDelta.java +++ b/java-diff-utils/src/main/java/com/github/difflib/patch/DeleteDelta.java @@ -21,7 +21,7 @@ import java.util.List; * Describes the delete-delta between original and revised texts. * * @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a> - * @param T The type of the compared elements in the 'lines'. + * @param <T> The type of the compared elements in the 'lines'. */ public final class DeleteDelta<T> extends AbstractDelta<T> { diff --git a/src/main/java/com/github/difflib/patch/DeltaType.java b/java-diff-utils/src/main/java/com/github/difflib/patch/DeltaType.java similarity index 100% rename from src/main/java/com/github/difflib/patch/DeltaType.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/DeltaType.java diff --git a/src/main/java/com/github/difflib/patch/DiffException.java b/java-diff-utils/src/main/java/com/github/difflib/patch/DiffException.java similarity index 100% rename from src/main/java/com/github/difflib/patch/DiffException.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/DiffException.java diff --git a/src/main/java/com/github/difflib/patch/InsertDelta.java b/java-diff-utils/src/main/java/com/github/difflib/patch/InsertDelta.java similarity index 96% rename from src/main/java/com/github/difflib/patch/InsertDelta.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/InsertDelta.java index 08de5f1f2a18c3de43a0c5e8f5963f490aa31e1d..12164fa481ead79413eae856e61ded6fa763eb95 100644 --- a/src/main/java/com/github/difflib/patch/InsertDelta.java +++ b/java-diff-utils/src/main/java/com/github/difflib/patch/InsertDelta.java @@ -21,7 +21,7 @@ import java.util.List; * Describes the add-delta between original and revised texts. * * @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a> - * @param T The type of the compared elements in the 'lines'. + * @param <T> The type of the compared elements in the 'lines'. */ public final class InsertDelta<T> extends AbstractDelta<T> { diff --git a/src/main/java/com/github/difflib/patch/Patch.java b/java-diff-utils/src/main/java/com/github/difflib/patch/Patch.java similarity index 92% rename from src/main/java/com/github/difflib/patch/Patch.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/Patch.java index 9bbb30dc8606ff72307141d6b76f0046b2d039b0..688e9f16ec758f682ab98d4d8a67c0ce73374935 100644 --- a/src/main/java/com/github/difflib/patch/Patch.java +++ b/java-diff-utils/src/main/java/com/github/difflib/patch/Patch.java @@ -19,12 +19,9 @@ limitations under the License. */ package com.github.difflib.patch; +import static java.util.Comparator.comparing; import com.github.difflib.algorithm.Change; -import static com.github.difflib.patch.DeltaType.DELETE; -import static com.github.difflib.patch.DeltaType.INSERT; import java.util.ArrayList; -import java.util.Collections; -import static java.util.Comparator.comparing; import java.util.List; import java.util.ListIterator; @@ -32,7 +29,7 @@ import java.util.ListIterator; * Describes the patch holding all deltas between the original and revised texts. * * @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a> - * @param T The type of the compared elements in the 'lines'. + * @param <T> The type of the compared elements in the 'lines'. */ public final class Patch<T> { @@ -93,7 +90,7 @@ public final class Patch<T> { * @return the deltas */ public List<AbstractDelta<T>> getDeltas() { - Collections.sort(deltas, comparing(d -> d.getSource().getPosition())); + deltas.sort(comparing(d -> d.getSource().getPosition())); return deltas; } diff --git a/src/main/java/com/github/difflib/patch/PatchFailedException.java b/java-diff-utils/src/main/java/com/github/difflib/patch/PatchFailedException.java similarity index 100% rename from src/main/java/com/github/difflib/patch/PatchFailedException.java rename to java-diff-utils/src/main/java/com/github/difflib/patch/PatchFailedException.java diff --git a/src/main/java/com/github/difflib/text/DiffRow.java b/java-diff-utils/src/main/java/com/github/difflib/text/DiffRow.java similarity index 100% rename from src/main/java/com/github/difflib/text/DiffRow.java rename to java-diff-utils/src/main/java/com/github/difflib/text/DiffRow.java diff --git a/src/main/java/com/github/difflib/text/DiffRowGenerator.java b/java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java similarity index 87% rename from src/main/java/com/github/difflib/text/DiffRowGenerator.java rename to java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java index 2ed2662ee5a907bf06dc9771e5aac3618949e483..4f963cd7d4f477a1be75c9be0462c085719e1210 100644 --- a/src/main/java/com/github/difflib/text/DiffRowGenerator.java +++ b/java-diff-utils/src/main/java/com/github/difflib/text/DiffRowGenerator.java @@ -29,6 +29,7 @@ import java.util.function.BiPredicate; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static java.util.stream.Collectors.toList; /** * This class for generating DiffRows for side-by-sidy view. You can customize the way of generating. For example, show @@ -42,13 +43,16 @@ import java.util.regex.Pattern; * ignoreWhiteSpaces(true).columnWidth(100).build(); * </code> */ -public class DiffRowGenerator { +public final class DiffRowGenerator { public static final BiPredicate<String, String> DEFAULT_EQUALIZER = Object::equals; public static final BiPredicate<String, String> IGNORE_WHITESPACE_EQUALIZER = (original, revised) -> adjustWhitespace(original).equals(adjustWhitespace(revised)); + public static final Function<String, String> LINE_NORMALIZER_FOR_HTML = StringUtils::normalize; + + /** * Splitting lines by character to achieve char by char diff checking. */ @@ -60,6 +64,7 @@ public class DiffRowGenerator { return list; }; public static final Pattern SPLIT_BY_WORD_PATTERN = Pattern.compile("\\s+|[,.\\[\\](){}/\\\\*+\\-#]"); + /** * Splitting lines by word to achieve word by word diff checking. */ @@ -98,8 +103,7 @@ public class DiffRowGenerator { * * @param startPosition the position from which tag should start. The counting start from a zero. * @param endPosition the position before which tag should should be closed. - * @param tag the tag name without angle brackets, just a word - * @param cssClass the optional css class + * @param tagGenerator the tag generator */ static void wrapInTag(List<String> sequence, int startPosition, int endPosition, Function<Boolean, String> tagGenerator) { @@ -145,6 +149,7 @@ public class DiffRowGenerator { private final Function<Boolean, String> newTag; private final Function<Boolean, String> oldTag; private final boolean reportLinesUnchanged; + private final Function<String, String> lineNormalizer; private final boolean showInlineDiffs; @@ -158,8 +163,10 @@ public class DiffRowGenerator { inlineDiffSplitter = builder.inlineDiffSplitter; equalizer = ignoreWhiteSpaces ? IGNORE_WHITESPACE_EQUALIZER : DEFAULT_EQUALIZER; reportLinesUnchanged = builder.reportLinesUnchanged; + lineNormalizer = builder.lineNormalizer; Objects.requireNonNull(inlineDiffSplitter); + Objects.requireNonNull(lineNormalizer); } /** @@ -179,7 +186,6 @@ public class DiffRowGenerator { * for displaying side-by-side diff. * * @param original the original text - * @param revised the revised text * @param patch the given patch * @return the DiffRows between original and revised texts */ @@ -187,8 +193,7 @@ public class DiffRowGenerator { List<DiffRow> diffRows = new ArrayList<>(); int endPos = 0; final List<AbstractDelta<String>> deltaList = patch.getDeltas(); - for (int i = 0; i < deltaList.size(); i++) { - AbstractDelta<String> delta = deltaList.get(i); + for (AbstractDelta<String> delta : deltaList) { Chunk<String> orig = delta.getSource(); Chunk<String> rev = delta.getTarget(); @@ -199,7 +204,7 @@ public class DiffRowGenerator { // Inserted DiffRow if (delta instanceof InsertDelta) { endPos = orig.last() + 1; - for (String line : (List<String>) rev.getLines()) { + for (String line : rev.getLines()) { diffRows.add(buildDiffRow(Tag.INSERT, "", line)); } continue; @@ -208,7 +213,7 @@ public class DiffRowGenerator { // Deleted DiffRow if (delta instanceof DeleteDelta) { endPos = orig.last() + 1; - for (String line : (List<String>) orig.getLines()) { + for (String line : orig.getLines()) { diffRows.add(buildDiffRow(Tag.DELETE, line, "")); } continue; @@ -261,14 +266,22 @@ public class DiffRowGenerator { StringUtils.wrapText(newline, columnWidth)); } + List<String> normalizeLines(List<String> list) { + return reportLinesUnchanged + ? list + : list.stream() + .map(lineNormalizer::apply) + .collect(toList()); + } + /** * Add the inline diffs for given delta * * @param delta the given delta */ private List<DiffRow> generateInlineDiffs(AbstractDelta<String> delta) throws DiffException { - List<String> orig = StringUtils.normalize(delta.getSource().getLines()); - List<String> rev = StringUtils.normalize(delta.getTarget().getLines()); + List<String> orig = normalizeLines(delta.getSource().getLines()); + List<String> rev = normalizeLines(delta.getTarget().getLines()); List<String> origList; List<String> revList; String joinedOrig = String.join("\n", orig); @@ -337,9 +350,9 @@ public class DiffRowGenerator { private String preprocessLine(String line) { if (columnWidth == 0) { - return StringUtils.normalize(line); + return lineNormalizer.apply(line); } else { - return StringUtils.wrapText(StringUtils.normalize(line), columnWidth); + return StringUtils.wrapText(lineNormalizer.apply(line), columnWidth); } } @@ -361,6 +374,7 @@ public class DiffRowGenerator { private boolean mergeOriginalRevised = false; private boolean reportLinesUnchanged = false; private Function<String, List<String>> inlineDiffSplitter = SPLITTER_BY_CHARACTER; + private Function<String, String> lineNormalizer = LINE_NORMALIZER_FOR_HTML; private Builder() { } @@ -388,7 +402,8 @@ public class DiffRowGenerator { } /** - * Give the originial old and new text lines to Diffrow without any additional processing. + * Give the originial old and new text lines to Diffrow without any additional processing and without any tags to + * highlight the change. * * @param val the value to set. Default: false. * @return builder with configured reportLinesUnWrapped parameter @@ -401,7 +416,7 @@ public class DiffRowGenerator { /** * Generator for Old-Text-Tags. * - * @param tag the tag to set. Without angle brackets. Default: span. + * @param generator the tag generator * @return builder with configured ignoreBlankLines parameter */ public Builder oldTag(Function<Boolean, String> generator) { @@ -421,7 +436,7 @@ public class DiffRowGenerator { } /** - * Set the column with of generated lines of original and revised texts. + * Set the column width of generated lines of original and revised texts. * * @param width the width to set. Making it < 0 doesn't have any sense. Default 80. @return builder with config * ured ignoreBlankLines parameter @@ -454,17 +469,41 @@ public class DiffRowGenerator { } /** - * Per default each character is separatly processed. This variant introduces processing by word, which should - * deliver no in word changes. + * Per default each character is separatly processed. This variant introduces processing by word, which does not + * deliver in word changes. Therefore the whole word will be tagged as changed: + * + * <pre> + * false: (aBa : aba) -- changed: a(B)a : a(b)a + * true: (aBa : aba) -- changed: (aBa) : (aba) + * </pre> */ public Builder inlineDiffByWord(boolean inlineDiffByWord) { inlineDiffSplitter = inlineDiffByWord ? SPLITTER_BY_WORD : SPLITTER_BY_CHARACTER; return this; } + /** + * To provide some customized splitting a splitter can be provided. Here someone could think about sentence splitter, + * comma splitter or stuff like that. + * + * @param inlineDiffSplitter + * @return + */ public Builder inlineDiffBySplitter(Function<String, List<String>> inlineDiffSplitter) { this.inlineDiffSplitter = inlineDiffSplitter; return this; } + + /** + * By default DiffRowGenerator preprocesses lines for HTML output. Tabs and special HTML characters like "<" + * are replaced with its encoded value. To change this you can provide a customized line normalizer here. + * + * @param lineNormalizer + * @return + */ + public Builder lineNormalizer(Function<String, String> lineNormalizer) { + this.lineNormalizer = lineNormalizer; + return this; + } } } diff --git a/src/main/java/com/github/difflib/text/StringUtils.java b/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java similarity index 92% rename from src/main/java/com/github/difflib/text/StringUtils.java rename to java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java index 3a2dab054a9d4e59ba82373e4e4b1ac0c56e12da..a142548876c0692b1382f7d80fed7ff3ae8a9cbb 100644 --- a/src/main/java/com/github/difflib/text/StringUtils.java +++ b/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java @@ -34,12 +34,6 @@ final class StringUtils { return htmlEntites(str).replace("\t", " "); } - public static List<String> normalize(List<String> list) { - return list.stream() - .map(StringUtils::normalize) - .collect(toList()); - } - public static List<String> wrapText(List<String> list, int columnWidth) { return list.stream() .map(line -> wrapText(line, columnWidth)) diff --git a/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiff.java b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiff.java new file mode 100644 index 0000000000000000000000000000000000000000..bdabc5892d01359b4f8af00f00478feaa0f23d0f --- /dev/null +++ b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiff.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019 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.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; + +/** + * + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public final class UnifiedDiff { + + private String header; + private String tail; + private final List<UnifiedDiffFile> files = new ArrayList<>(); + + public String getHeader() { + return header; + } + + public void setHeader(String header) { + this.header = header; + } + + void addFile(UnifiedDiffFile file) { + files.add(file); + } + + public List<UnifiedDiffFile> getFiles() { + return Collections.unmodifiableList(files); + } + + void setTailTxt(String tailTxt) { + this.tail = tailTxt; + } + + public String getTail() { + return tail; + } + + public List<String> spplyPatchTo(Predicate<String> findFile, List<String> originalLines) throws PatchFailedException { + UnifiedDiffFile file = files.stream() + .filter(diff -> findFile.test(diff.getFromFile())) + .findFirst().orElse(null); + if (file != null) { + return file.getPatch().applyTo(originalLines); + } else { + return originalLines; + } + } + + public static UnifiedDiff from(String header, String tail, UnifiedDiffFile... files) { + UnifiedDiff diff = new UnifiedDiff(); + diff.setHeader(header); + diff.setTailTxt(tail); + for (UnifiedDiffFile file : files) { + diff.addFile(file); + } + return diff; + } +} diff --git a/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffFile.java b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffFile.java new file mode 100644 index 0000000000000000000000000000000000000000..c244184fcab6a751eb0ce021f9131693dded51a9 --- /dev/null +++ b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffFile.java @@ -0,0 +1,95 @@ +/* + * Copyright 2019 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.Patch; + +/** + * + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public final class UnifiedDiffFile { + + private String diffCommand; + private String fromFile; + private String fromTimestamp; + private String toFile; + private String toTimestamp; + private String index; + private Patch<String> patch = new Patch<>(); + + public String getDiffCommand() { + return diffCommand; + } + + public void setDiffCommand(String diffCommand) { + this.diffCommand = diffCommand; + } + + public String getFromFile() { + return fromFile; + } + + public void setFromFile(String fromFile) { + this.fromFile = fromFile; + } + + public String getToFile() { + return toFile; + } + + public void setToFile(String toFile) { + this.toFile = toFile; + } + + public void setIndex(String index) { + this.index = index; + } + + public String getIndex() { + return index; + } + + public Patch<String> getPatch() { + return patch; + } + + public String getFromTimestamp() { + return fromTimestamp; + } + + public void setFromTimestamp(String fromTimestamp) { + this.fromTimestamp = fromTimestamp; + } + + public String getToTimestamp() { + return toTimestamp; + } + + public void setToTimestamp(String toTimestamp) { + this.toTimestamp = toTimestamp; + } + + + + public static UnifiedDiffFile from(String fromFile, String toFile, Patch<String> patch) { + UnifiedDiffFile file = new UnifiedDiffFile(); + file.setFromFile(fromFile); + file.setToFile(toFile); + file.patch = patch; + return file; + } +} diff --git a/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffParserException.java b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffParserException.java new file mode 100644 index 0000000000000000000000000000000000000000..ab7114db363dfe1aee3ce40b2cd603d6af8d94eb --- /dev/null +++ b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffParserException.java @@ -0,0 +1,43 @@ +/* + * Copyright 2019 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; + +/** + * + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public class UnifiedDiffParserException extends RuntimeException { + + public UnifiedDiffParserException() { + } + + public UnifiedDiffParserException(String message) { + super(message); + } + + public UnifiedDiffParserException(String message, Throwable cause) { + super(message, cause); + } + + public UnifiedDiffParserException(Throwable cause) { + super(cause); + } + + public UnifiedDiffParserException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffReader.java b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffReader.java new file mode 100644 index 0000000000000000000000000000000000000000..c208786ca37a293d5a8a485541d52c40707789f7 --- /dev/null +++ b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffReader.java @@ -0,0 +1,323 @@ +/* + * Copyright 2019 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.ChangeDelta; +import com.github.difflib.patch.Chunk; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.BiConsumer; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public final class UnifiedDiffReader { + + static final Pattern UNIFIED_DIFF_CHUNK_REGEXP = Pattern.compile("^@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@"); + static final Pattern TIMESTAMP_REGEXP = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}\\.\\d{3,})"); + + private final InternalUnifiedDiffReader READER; + private final UnifiedDiff data = new UnifiedDiff(); + + private final UnifiedDiffLine DIFF_COMMAND = new UnifiedDiffLine(true, "^diff\\s", this::processDiff); + private final UnifiedDiffLine INDEX = new UnifiedDiffLine(true, "^index\\s[\\da-zA-Z]+\\.\\.[\\da-zA-Z]+(\\s(\\d+))?$", this::processIndex); + private final UnifiedDiffLine FROM_FILE = new UnifiedDiffLine(true, "^---\\s", this::processFromFile); + private final UnifiedDiffLine TO_FILE = new UnifiedDiffLine(true, "^\\+\\+\\+\\s", this::processToFile); + + private final UnifiedDiffLine CHUNK = new UnifiedDiffLine(false, UNIFIED_DIFF_CHUNK_REGEXP, this::processChunk); + private final UnifiedDiffLine LINE_NORMAL = new UnifiedDiffLine("^\\s", this::processNormalLine); + private final UnifiedDiffLine LINE_DEL = new UnifiedDiffLine("^-", this::processDelLine); + private final UnifiedDiffLine LINE_ADD = new UnifiedDiffLine("^\\+", this::processAddLine); + + private UnifiedDiffFile actualFile; + + UnifiedDiffReader(Reader reader) { + this.READER = new InternalUnifiedDiffReader(reader); + } + + // schema = [[/^\s+/, normal], [/^diff\s/, start], [/^new file mode \d+$/, new_file], + // [/^deleted file mode \d+$/, deleted_file], [/^index\s[\da-zA-Z]+\.\.[\da-zA-Z]+(\s(\d+))?$/, index], + // [/^---\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.INFO, "header parsing"); + String line = null; + while (READER.ready()) { + line = READER.readLine(); + LOG.log(Level.INFO, "parsing line {0}", line); + if (DIFF_COMMAND.validLine(line) || INDEX.validLine(line) + || FROM_FILE.validLine(line) || TO_FILE.validLine(line)) { + break; + } else { + headerTxt += line + "\n"; + } + } + if (!"".equals(headerTxt)) { + data.setHeader(headerTxt); + } + + while (line != null) { + if (!CHUNK.validLine(line)) { + initFileIfNecessary(); + while (!CHUNK.validLine(line)) { + if (processLine(line, DIFF_COMMAND, INDEX, FROM_FILE, TO_FILE) == false) { + throw new UnifiedDiffParserException("expected file start line not found"); + } + line = READER.readLine(); + } + } + processLine(line, CHUNK); + while ((line = READER.readLine()) != null) { + if (processLine(line, LINE_NORMAL, LINE_ADD, LINE_DEL) == false) { + throw new UnifiedDiffParserException("expected data line not found"); + } + if (originalTxt.size() == old_size && revisedTxt.size() == new_size) { + finalizeChunk(); + break; + } + } + line = READER.readLine(); + if (line == null || line.startsWith("--")) { + break; + } + } + + if (READER.ready()) { + String tailTxt = ""; + while (READER.ready()) { + tailTxt += READER.readLine() + "\n"; + } + data.setTailTxt(tailTxt); + } + + return data; + } + + static String[] parseFileNames(String line) { + String[] split = line.split(" "); + return new String[]{ + split[2].replaceAll("^a/", ""), + split[3].replaceAll("^b/", "") + }; + } + + private static final Logger LOG = Logger.getLogger(UnifiedDiffReader.class.getName()); + + public static UnifiedDiff parseUnifiedDiff(InputStream stream) throws IOException, UnifiedDiffParserException { + UnifiedDiffReader parser = new UnifiedDiffReader(new BufferedReader(new InputStreamReader(stream))); + return parser.parse(); + } + + private boolean processLine(String line, UnifiedDiffLine... rules) throws UnifiedDiffParserException { + for (UnifiedDiffLine rule : rules) { + if (rule.processLine(line)) { + LOG.info(" >>> processed rule " + rule.toString()); + return true; + } + } + LOG.info(" >>> no rule matched " + line); + return false; + //throw new UnifiedDiffParserException("parsing error at line " + line); + } + + private void initFileIfNecessary() { + if (!originalTxt.isEmpty() || !revisedTxt.isEmpty()) { + throw new IllegalStateException(); + } + actualFile = null; + if (actualFile == null) { + actualFile = new UnifiedDiffFile(); + data.addFile(actualFile); + } + } + + private void processDiff(MatchResult match, String line) { + //initFileIfNecessary(); + LOG.log(Level.INFO, "start {0}", line); + String[] fromTo = parseFileNames(READER.lastLine()); + actualFile.setFromFile(fromTo[0]); + actualFile.setToFile(fromTo[1]); + actualFile.setDiffCommand(line); + } + + private List<String> originalTxt = new ArrayList<>(); + private List<String> revisedTxt = new ArrayList<>(); + private int old_ln; + private int old_size; + private int new_ln; + private int new_size; + + private void finalizeChunk() { + if (!originalTxt.isEmpty() || !revisedTxt.isEmpty()) { + actualFile.getPatch().addDelta(new ChangeDelta<>(new Chunk<>( + old_ln - 1, originalTxt), new Chunk<>( + new_ln - 1, revisedTxt))); + old_ln = 0; + new_ln = 0; + originalTxt.clear(); + revisedTxt.clear(); + } + } + + private void processNormalLine(MatchResult match, String line) { + String cline = line.substring(1); + originalTxt.add(cline); + revisedTxt.add(cline); + } + + private void processAddLine(MatchResult match, String line) { + String cline = line.substring(1); + revisedTxt.add(cline); + } + + private void processDelLine(MatchResult match, String line) { + String cline = line.substring(1); + originalTxt.add(cline); + } + + private void processChunk(MatchResult match, String chunkStart) { + // finalizeChunk(); + old_ln = toInteger(match, 1, 1); + old_size = toInteger(match, 2, 0); + new_ln = toInteger(match, 3, 1); + new_size = toInteger(match, 4, 0); + if (old_ln == 0) { + old_ln = 1; + } + if (new_ln == 0) { + new_ln = 1; + } + } + + private static Integer toInteger(MatchResult match, int group, int defValue) throws NumberFormatException { + return Integer.valueOf(Objects.toString(match.group(group), "" + defValue)); + } + + private void processIndex(MatchResult match, String line) { + //initFileIfNecessary(); + LOG.log(Level.INFO, "index {0}", line); + actualFile.setIndex(line.substring(6)); + } + + private void processFromFile(MatchResult match, String line) { + //initFileIfNecessary(); + actualFile.setFromFile(extractFileName(line)); + actualFile.setFromTimestamp(extractTimestamp(line)); + } + + private void processToFile(MatchResult match, String line) { + //initFileIfNecessary(); + actualFile.setToFile(extractFileName(line)); + actualFile.setToTimestamp(extractTimestamp(line)); + } + + private String extractFileName(String _line) { + Matcher matcher = TIMESTAMP_REGEXP.matcher(_line); + String line = _line; + if (matcher.find()) { + line = line.substring(1, matcher.start()); + } + return line.substring(4).replaceFirst("^(a|b)\\/", "") + .replace(TIMESTAMP_REGEXP.toString(), "").trim(); + } + + private String extractTimestamp(String line) { + Matcher matcher = TIMESTAMP_REGEXP.matcher(line); + if (matcher.find()) { + return matcher.group(); + } + return null; + } + + final class UnifiedDiffLine { + + private final Pattern pattern; + private final BiConsumer<MatchResult, String> command; + private final boolean stopsHeaderParsing; + + public UnifiedDiffLine(String pattern, BiConsumer<MatchResult, String> command) { + this(false, pattern, command); + } + + public UnifiedDiffLine(boolean stopsHeaderParsing, String pattern, BiConsumer<MatchResult, String> command) { + this.pattern = Pattern.compile(pattern); + this.command = command; + this.stopsHeaderParsing = stopsHeaderParsing; + } + + public UnifiedDiffLine(boolean stopsHeaderParsing, Pattern pattern, BiConsumer<MatchResult, String> command) { + this.pattern = pattern; + this.command = command; + this.stopsHeaderParsing = stopsHeaderParsing; + } + + public boolean validLine(String line) { + Matcher m = pattern.matcher(line); + return m.find(); + } + + public boolean processLine(String line) throws UnifiedDiffParserException { + Matcher m = pattern.matcher(line); + if (m.find()) { + command.accept(m.toMatchResult(), line); + return true; + } else { + return false; + } + } + + public boolean isStopsHeaderParsing() { + return stopsHeaderParsing; + } + + @Override + public String toString() { + return "UnifiedDiffLine{" + "pattern=" + pattern + ", stopsHeaderParsing=" + stopsHeaderParsing + '}'; + } + } +} + +class InternalUnifiedDiffReader extends BufferedReader { + + private String lastLine; + + public InternalUnifiedDiffReader(Reader reader) { + super(reader); + } + + @Override + public String readLine() throws IOException { + lastLine = super.readLine(); + return lastLine(); + } + + String lastLine() { + return lastLine; + } +} diff --git a/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffWriter.java b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..c9488f9c0aac7474aec91e0fde6842437e8b6f8f --- /dev/null +++ b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/UnifiedDiffWriter.java @@ -0,0 +1,201 @@ +/* + * Copyright 2019 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.AbstractDelta; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @todo use an instance to store contextSize and originalLinesProvider. + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public class UnifiedDiffWriter { + + private static final Logger LOG = Logger.getLogger(UnifiedDiffWriter.class.getName()); + + public static void write(UnifiedDiff diff, Function<String, List<String>> originalLinesProvider, Writer writer, int contextSize) throws IOException { + write(diff, originalLinesProvider, line -> { + try { + writer.append(line).append("\n"); + } catch (IOException ex) { + LOG.log(Level.SEVERE, null, ex); + } + }, contextSize); + } + + public static void write(UnifiedDiff diff, Function<String, List<String>> originalLinesProvider, Consumer<String> writer, int contextSize) throws IOException { + writer.accept(diff.getHeader()); + + for (UnifiedDiffFile file : diff.getFiles()) { + List<AbstractDelta<String>> patchDeltas = new ArrayList<>( + file.getPatch().getDeltas()); + if (!patchDeltas.isEmpty()) { + writeOrNothing(writer, file.getDiffCommand()); + if (file.getIndex() != null) { + writer.accept("index " + file.getIndex()); + } + if (file.getFromFile() != null) { + writer.accept("--- " + file.getFromFile()); + } + if (file.getToFile() != null) { + writer.accept("+++ " + file.getToFile()); + } + + List<String> originalLines = originalLinesProvider.apply(file.getFromFile()); + + List<AbstractDelta<String>> deltas = new ArrayList<>(); + + AbstractDelta<String> 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++) { + int position = delta.getSource().getPosition(); + + // Check if the next Delta is too close to the current + // position. + // And if it is, add it to the current set + AbstractDelta<String> nextDelta = patchDeltas.get(i); + if ((position + delta.getSource().size() + contextSize) >= (nextDelta + .getSource().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. + processDeltas(writer, originalLines, deltas, contextSize); + deltas.clear(); + deltas.add(nextDelta); + } + delta = nextDelta; + } + + } + // don't forget to process the last set of Deltas + processDeltas(writer, originalLines, deltas, contextSize); + } + + } + if (diff.getTail() != null) { + writer.accept("--"); + writer.accept(diff.getTail()); + } + } + + private static void processDeltas(Consumer<String> writer, + List<String> origLines, List<AbstractDelta<String>> deltas, + int contextSize) { + List<String> 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; + + AbstractDelta<String> curDelta = deltas.get(0); + + // NOTE: +1 to overcome the 0-offset Position + int origStart = curDelta.getSource().getPosition() + 1 - contextSize; + if (origStart < 1) { + origStart = 1; + } + + int revStart = curDelta.getTarget().getPosition() + 1 - contextSize; + if (revStart < 1) { + revStart = 1; + } + + // find the start of the wrapper context code + int contextStart = curDelta.getSource().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.getSource().getPosition(); line++) { // + buffer.add(" " + origLines.get(line)); + origTotal++; + revTotal++; + } + // output the first Delta + getDeltaText(txt -> buffer.add(txt), curDelta); + origTotal += curDelta.getSource().getLines().size(); + revTotal += curDelta.getTarget().getLines().size(); + + int deltaIndex = 1; + while (deltaIndex < deltas.size()) { // for each of the other Deltas + AbstractDelta<String> nextDelta = deltas.get(deltaIndex); + int intermediateStart = curDelta.getSource().getPosition() + + curDelta.getSource().getLines().size(); + for (line = intermediateStart; line < nextDelta.getSource() + .getPosition(); line++) { + // output the code between the last Delta and this one + buffer.add(" " + origLines.get(line)); + origTotal++; + revTotal++; + } + getDeltaText(txt -> buffer.add(txt), nextDelta); // output the Delta + origTotal += nextDelta.getSource().getLines().size(); + revTotal += nextDelta.getTarget().getLines().size(); + curDelta = nextDelta; + deltaIndex++; + } + + // Now output the post-Delta context code, clamping the end of the file + contextStart = curDelta.getSource().getPosition() + + curDelta.getSource().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 + writer.accept("@@ -" + origStart + "," + origTotal + " +" + revStart + "," + revTotal + " @@"); + buffer.forEach(txt -> { + writer.accept(txt); + }); + } + + /** + * 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 (tankerbay@gmail.com) + */ + private static void getDeltaText(Consumer<String> writer, AbstractDelta<String> delta) { + for (String line : delta.getSource().getLines()) { + writer.accept("-" + line); + } + for (String line : delta.getTarget().getLines()) { + writer.accept("+" + line); + } + } + + private static void writeOrNothing(Consumer<String> writer, String str) throws IOException { + if (str != null) { + writer.accept(str); + } + } +} diff --git a/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/package-info.java b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..49edc6874171bbb79d30e07ca84071a91a90ac91 --- /dev/null +++ b/java-diff-utils/src/main/java/com/github/difflib/unifieddiff/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2019 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. + */ +/** + * This is the first test version of a multifile diff parser. The Api is still subject + * of change. + */ +package com.github.difflib.unifieddiff; diff --git a/src/test/java/com/github/difflib/DiffUtilsTest.java b/java-diff-utils/src/test/java/com/github/difflib/DiffUtilsTest.java similarity index 100% rename from src/test/java/com/github/difflib/DiffUtilsTest.java rename to java-diff-utils/src/test/java/com/github/difflib/DiffUtilsTest.java diff --git a/src/test/java/com/github/difflib/GenerateUnifiedDiffTest.java b/java-diff-utils/src/test/java/com/github/difflib/GenerateUnifiedDiffTest.java similarity index 92% rename from src/test/java/com/github/difflib/GenerateUnifiedDiffTest.java rename to java-diff-utils/src/test/java/com/github/difflib/GenerateUnifiedDiffTest.java index 89ab32f65575341eb91eb8cdff1aeab7fd6ee97f..c6bfc4eca2f546eb11e5680f4ab113b343cf8f71 100644 --- a/src/test/java/com/github/difflib/GenerateUnifiedDiffTest.java +++ b/java-diff-utils/src/test/java/com/github/difflib/GenerateUnifiedDiffTest.java @@ -10,13 +10,14 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.junit.Assert.assertTrue; +import static java.util.stream.Collectors.joining; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import org.junit.Test; public class GenerateUnifiedDiffTest { - private static List<String> fileToLines(String filename) throws FileNotFoundException, IOException { + public static List<String> fileToLines(String filename) throws FileNotFoundException, IOException { List<String> lines = new ArrayList<>(); String line = ""; try (BufferedReader in = new BufferedReader(new FileReader(filename))) { @@ -110,11 +111,13 @@ public class GenerateUnifiedDiffTest { List<String> unifiedDiff = UnifiedDiffUtils.generateUnifiedDiff(originalFile, revisedFile, origLines, patch, 10); + System.out.println(unifiedDiff.stream().collect(joining("\n"))); + Patch<String> fromUnifiedPatch = UnifiedDiffUtils.parseUnifiedDiff(unifiedDiff); List<String> patchedLines; try { - patchedLines = (List<String>) fromUnifiedPatch.applyTo(origLines); - assertTrue(revLines.size() == patchedLines.size()); + patchedLines = fromUnifiedPatch.applyTo(origLines); + assertEquals(revLines.size(), patchedLines.size()); for (int i = 0; i < revLines.size(); i++) { String l1 = revLines.get(i); String l2 = patchedLines.get(i); diff --git a/src/test/java/com/github/difflib/TestConstants.java b/java-diff-utils/src/test/java/com/github/difflib/TestConstants.java similarity index 82% rename from src/test/java/com/github/difflib/TestConstants.java rename to java-diff-utils/src/test/java/com/github/difflib/TestConstants.java index 56f5bf665b34ac78030c3de79bcca5fe6a62e256..ba6d754e5ce9df5a12eabe77a6560dc019d2bd46 100644 --- a/src/test/java/com/github/difflib/TestConstants.java +++ b/java-diff-utils/src/test/java/com/github/difflib/TestConstants.java @@ -10,7 +10,7 @@ public final class TestConstants { public static final String BASE_FOLDER_RESOURCES = "target/test-classes/"; /** - * The base folder containing the test files. Ends with {@link #FS}. + * The base folder containing the test files. */ public static final String MOCK_FOLDER = BASE_FOLDER_RESOURCES + "/mocks/"; diff --git a/src/test/java/com/github/difflib/algorithm/myers/MyersDiffTest.java b/java-diff-utils/src/test/java/com/github/difflib/algorithm/myers/MyersDiffTest.java similarity index 100% rename from src/test/java/com/github/difflib/algorithm/myers/MyersDiffTest.java rename to java-diff-utils/src/test/java/com/github/difflib/algorithm/myers/MyersDiffTest.java diff --git a/src/test/java/com/github/difflib/examples/ApplyPatch.java b/java-diff-utils/src/test/java/com/github/difflib/examples/ApplyPatch.java similarity index 100% rename from src/test/java/com/github/difflib/examples/ApplyPatch.java rename to java-diff-utils/src/test/java/com/github/difflib/examples/ApplyPatch.java diff --git a/src/test/java/com/github/difflib/examples/ComputeDifference.java b/java-diff-utils/src/test/java/com/github/difflib/examples/ComputeDifference.java similarity index 100% rename from src/test/java/com/github/difflib/examples/ComputeDifference.java rename to java-diff-utils/src/test/java/com/github/difflib/examples/ComputeDifference.java diff --git a/src/test/java/com/github/difflib/patch/PatchTest.java b/java-diff-utils/src/test/java/com/github/difflib/patch/PatchTest.java similarity index 100% rename from src/test/java/com/github/difflib/patch/PatchTest.java rename to java-diff-utils/src/test/java/com/github/difflib/patch/PatchTest.java diff --git a/src/test/java/com/github/difflib/text/DiffRowGeneratorTest.java b/java-diff-utils/src/test/java/com/github/difflib/text/DiffRowGeneratorTest.java similarity index 89% rename from src/test/java/com/github/difflib/text/DiffRowGeneratorTest.java rename to java-diff-utils/src/test/java/com/github/difflib/text/DiffRowGeneratorTest.java index f9e5c710a5a756d21943bafe8675b889131954ca..c667b251885acee8b119f01fab94e9c00992b90d 100644 --- a/src/test/java/com/github/difflib/text/DiffRowGeneratorTest.java +++ b/java-diff-utils/src/test/java/com/github/difflib/text/DiffRowGeneratorTest.java @@ -5,6 +5,7 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.regex.Pattern; import static java.util.stream.Collectors.toList; @@ -28,6 +29,16 @@ public class DiffRowGeneratorTest { assertEquals(3, rows.size()); } + /** + * Test of normalize method, of class StringUtils. + */ + @Test + public void testNormalize_List() { + DiffRowGenerator generator = DiffRowGenerator.create() + .build(); + assertEquals(Collections.singletonList(" test"), generator.normalizeLines(Collections.singletonList("\ttest"))); + } + @Test public void testGenerator_Default2() throws DiffException { String first = "anything \n \nother"; @@ -375,4 +386,35 @@ public class DiffRowGeneratorTest { assertEquals("[[CHANGE,This is a test ~senctence~.,This is a test **for diffutils**.], [CHANGE,,**This is the second line.**], [CHANGE,,**And one more.**]]", rows.toString()); } + + @Test + public void testGeneratorIssue41DefaultNormalizer() throws DiffException { + DiffRowGenerator generator = DiffRowGenerator.create() + .build(); + List<DiffRow> rows = generator.generateDiffRows(Arrays.asList("<"), Arrays.asList("<")); + assertEquals("[[EQUAL,<,<]]", rows.toString()); + } + + @Test + public void testGeneratorIssue41UserNormalizer() throws DiffException { + DiffRowGenerator generator = DiffRowGenerator.create() + .lineNormalizer(str -> str.replace("\t", " ")) + .build(); + List<DiffRow> rows = generator.generateDiffRows(Arrays.asList("<"), Arrays.asList("<")); + assertEquals("[[EQUAL,<,<]]", rows.toString()); + rows = generator.generateDiffRows(Arrays.asList("\t<"), Arrays.asList("<")); + assertEquals("[[CHANGE, <,<]]", rows.toString()); + } + + @Test + public void testGenerationIssue44reportLinesUnchangedProblem() throws DiffException { + DiffRowGenerator generator = DiffRowGenerator.create() + .showInlineDiffs(true) + .reportLinesUnchanged(true) + .oldTag(f -> "~~") + .newTag(f -> "**") + .build(); + List<DiffRow> rows = generator.generateDiffRows(Arrays.asList("<dt>To do</dt>"), Arrays.asList("<dt>Done</dt>")); + assertEquals("[[CHANGE,<dt>~~T~~o~~ do~~</dt>,<dt>**D**o**ne**</dt>]]", rows.toString()); + } } diff --git a/src/test/java/com/github/difflib/text/StringUtilsTest.java b/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java similarity index 85% rename from src/test/java/com/github/difflib/text/StringUtilsTest.java rename to java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java index 2b120d09e871fd0e1d67788af0c2363cab008573..93076cc1d6df8609886395d467f0443ea0f575a3 100644 --- a/src/test/java/com/github/difflib/text/StringUtilsTest.java +++ b/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java @@ -15,7 +15,6 @@ */ package com.github.difflib.text; -import java.util.Collections; import static org.junit.Assert.*; import org.junit.Test; @@ -41,14 +40,6 @@ public class StringUtilsTest { assertEquals(" test", StringUtils.normalize("\ttest")); } - /** - * Test of normalize method, of class StringUtils. - */ - @Test - public void testNormalize_List() { - assertEquals(Collections.singletonList(" test"), StringUtils.normalize(Collections.singletonList("\ttest"))); - } - /** * Test of wrapText method, of class StringUtils. */ diff --git a/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffReaderTest.java b/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffReaderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..eb0280db458adfef173db0df31a406eec6b3b2bf --- /dev/null +++ b/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffReaderTest.java @@ -0,0 +1,144 @@ +/* + * Copyright 2019 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.AbstractDelta; +import java.io.IOException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import static org.assertj.core.api.Java6Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import org.junit.Test; + +/** + * + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public class UnifiedDiffReaderTest { + + @Test + public void testSimpleParse() throws IOException { + UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(UnifiedDiffReaderTest.class.getResourceAsStream("jsqlparser_patch_1.diff")); + + System.out.println(diff); + + assertThat(diff.getFiles().size()).isEqualTo(2); + + UnifiedDiffFile file1 = diff.getFiles().get(0); + assertThat(file1.getFromFile()).isEqualTo("src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt"); + assertThat(file1.getPatch().getDeltas().size()).isEqualTo(3); + + assertThat(diff.getTail()).isEqualTo("2.17.1.windows.2\n\n"); + } + + @Test + public void testParseDiffBlock() { + String[] files = UnifiedDiffReader.parseFileNames("diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java"); + assertThat(files).containsExactly("src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java", "src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java"); + } + + @Test + public void testChunkHeaderParsing() { + Pattern pattern = UnifiedDiffReader.UNIFIED_DIFF_CHUNK_REGEXP; + Matcher matcher = pattern.matcher("@@ -189,6 +189,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */"); + + assertTrue(matcher.find()); + assertEquals("189", matcher.group(1)); + assertEquals("189", matcher.group(3)); + } + + @Test + public void testChunkHeaderParsing2() { + //"^@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@.*$" + Pattern pattern = UnifiedDiffReader.UNIFIED_DIFF_CHUNK_REGEXP; + Matcher matcher = pattern.matcher("@@ -189,6 +189,7 @@"); + + assertTrue(matcher.find()); + assertEquals("189", matcher.group(1)); + assertEquals("189", matcher.group(3)); + } + + @Test + public void testChunkHeaderParsing3() { + //"^@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@.*$" + Pattern pattern = UnifiedDiffReader.UNIFIED_DIFF_CHUNK_REGEXP; + Matcher matcher = pattern.matcher("@@ -1,27 +1,27 @@"); + + assertTrue(matcher.find()); + assertEquals("1", matcher.group(1)); + assertEquals("1", matcher.group(3)); + } + + @Test + public void testSimpleParse2() throws IOException { + UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(UnifiedDiffReaderTest.class.getResourceAsStream("jsqlparser_patch_1.diff")); + + System.out.println(diff); + + assertThat(diff.getFiles().size()).isEqualTo(2); + + UnifiedDiffFile file1 = diff.getFiles().get(0); + assertThat(file1.getFromFile()).isEqualTo("src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt"); + assertThat(file1.getPatch().getDeltas().size()).isEqualTo(3); + + AbstractDelta<String> first = file1.getPatch().getDeltas().get(0); + + assertThat(first.getSource().size()).isGreaterThan(0); + assertThat(first.getTarget().size()).isGreaterThan(0); + + assertThat(diff.getTail()).isEqualTo("2.17.1.windows.2\n\n"); + } + + @Test + public void testSimplePattern() { + Pattern pattern = Pattern.compile("^\\+\\+\\+\\s"); + + Matcher m = pattern.matcher("+++ revised.txt"); + assertTrue(m.find()); + } + + @Test + public void testParseIssue46() throws IOException { + UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff( + UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue46.diff")); + + System.out.println(diff); + + assertThat(diff.getFiles().size()).isEqualTo(1); + + UnifiedDiffFile file1 = diff.getFiles().get(0); + assertThat(file1.getFromFile()).isEqualTo(".vhd"); + assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1); + + assertThat(diff.getTail()).isNull(); + } + + @Test + public void testParseIssue33() throws IOException { + UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff( + UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue33.diff")); + + assertThat(diff.getFiles().size()).isEqualTo(1); + + UnifiedDiffFile file1 = diff.getFiles().get(0); + assertThat(file1.getFromFile()).isEqualTo("Main.java"); + assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1); + + assertThat(diff.getTail()).isNull(); + assertThat(diff.getHeader()).isNull(); + } +} diff --git a/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffRoundTripTest.java b/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffRoundTripTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c8fc82fc632f486b2e7e59144cc369bd3aac23b5 --- /dev/null +++ b/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffRoundTripTest.java @@ -0,0 +1,167 @@ +package com.github.difflib.unifieddiff; + +import com.github.difflib.DiffUtils; +import com.github.difflib.TestConstants; +import com.github.difflib.algorithm.DiffException; +import com.github.difflib.patch.Patch; +import com.github.difflib.patch.PatchFailedException; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import static java.util.stream.Collectors.joining; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import org.junit.Ignore; +import org.junit.Test; + +public class UnifiedDiffRoundTripTest { + + public static List<String> fileToLines(String filename) throws FileNotFoundException, IOException { + List<String> lines = new ArrayList<>(); + String line = ""; + try (BufferedReader in = new BufferedReader(new FileReader(filename))) { + while ((line = in.readLine()) != null) { + lines.add(line); + } + } + return lines; + } + + @Test + public void testGenerateUnified() throws DiffException, IOException { + List<String> origLines = fileToLines(TestConstants.MOCK_FOLDER + "original.txt"); + List<String> revLines = fileToLines(TestConstants.MOCK_FOLDER + "revised.txt"); + + verify(origLines, revLines, "original.txt", "revised.txt"); + } + + @Test + public void testGenerateUnifiedWithOneDelta() throws DiffException, IOException { + List<String> origLines = fileToLines(TestConstants.MOCK_FOLDER + "one_delta_test_original.txt"); + List<String> revLines = fileToLines(TestConstants.MOCK_FOLDER + "one_delta_test_revised.txt"); + + verify(origLines, revLines, "one_delta_test_original.txt", "one_delta_test_revised.txt"); + } + + @Test + public void testGenerateUnifiedDiffWithoutAnyDeltas() throws DiffException, IOException { + List<String> test = Arrays.asList("abc"); + Patch<String> patch = DiffUtils.diff(test, test); + StringWriter writer = new StringWriter(); + + UnifiedDiffWriter.write( + UnifiedDiff.from("header", "tail", UnifiedDiffFile.from("abc", "abc", patch)), + name -> test, + writer, 0); + + System.out.println(writer); + } + + @Test + public void testDiff_Issue10() throws IOException { + final List<String> baseLines = fileToLines(TestConstants.MOCK_FOLDER + "issue10_base.txt"); + final List<String> patchLines = fileToLines(TestConstants.MOCK_FOLDER + "issue10_patch.txt"); + + UnifiedDiff unifiedDiff = UnifiedDiffReader.parseUnifiedDiff( + new ByteArrayInputStream(patchLines.stream().collect(joining("\n")).getBytes()) + ); + + final Patch<String> p = unifiedDiff.getFiles().get(0).getPatch(); + try { + DiffUtils.patch(baseLines, p); + } catch (PatchFailedException e) { + fail(e.getMessage()); + } + } + + /** + * Issue 12 + */ + @Test + @Ignore + public void testPatchWithNoDeltas() throws DiffException, IOException { + final List<String> lines1 = fileToLines(TestConstants.MOCK_FOLDER + "issue11_1.txt"); + final List<String> lines2 = fileToLines(TestConstants.MOCK_FOLDER + "issue11_2.txt"); + verify(lines1, lines2, "issue11_1.txt", "issue11_2.txt"); + } + + @Test + public void testDiff5() throws DiffException, IOException { + final List<String> lines1 = fileToLines(TestConstants.MOCK_FOLDER + "5A.txt"); + final List<String> lines2 = fileToLines(TestConstants.MOCK_FOLDER + "5B.txt"); + verify(lines1, lines2, "5A.txt", "5B.txt"); + } + + /** + * Issue 19 + */ + @Test + public void testDiffWithHeaderLineInText() throws DiffException, IOException { + List<String> original = new ArrayList<>(); + List<String> revised = new ArrayList<>(); + + original.add("test line1"); + original.add("test line2"); + original.add("test line 4"); + original.add("test line 5"); + + revised.add("test line1"); + revised.add("test line2"); + revised.add("@@ -2,6 +2,7 @@"); + revised.add("test line 4"); + revised.add("test line 5"); + + Patch<String> patch = DiffUtils.diff(original, revised); + StringWriter writer = new StringWriter(); + UnifiedDiffWriter.write( + UnifiedDiff.from("header", "tail", UnifiedDiffFile.from("original", "revised", patch)), + name -> original, + writer, 10); + + System.out.println(writer.toString()); + + UnifiedDiff unifiedDiff = UnifiedDiffReader.parseUnifiedDiff(new ByteArrayInputStream(writer.toString().getBytes())); + } + + private void verify(List<String> origLines, List<String> revLines, + String originalFile, String revisedFile) throws DiffException, IOException { + Patch<String> patch = DiffUtils.diff(origLines, revLines); + + StringWriter writer = new StringWriter(); + UnifiedDiffWriter.write( + UnifiedDiff.from("header", "tail", UnifiedDiffFile.from(originalFile, revisedFile, patch)), + name -> origLines, + writer, 10); + + System.out.println(writer.toString()); + + UnifiedDiff unifiedDiff = UnifiedDiffReader.parseUnifiedDiff(new ByteArrayInputStream(writer.toString().getBytes())); + + List<String> patchedLines; + try { +// if (unifiedDiff.getFiles().isEmpty()) { +// patchedLines = new ArrayList<>(origLines); +// } else { +// Patch<String> fromUnifiedPatch = unifiedDiff.getFiles().get(0).getPatch(); +// patchedLines = fromUnifiedPatch.applyTo(origLines); +// } + patchedLines = unifiedDiff.spplyPatchTo(file -> originalFile.equals(file), origLines); + assertEquals(revLines.size(), patchedLines.size()); + for (int i = 0; i < revLines.size(); i++) { + String l1 = revLines.get(i); + String l2 = patchedLines.get(i); + if (!l1.equals(l2)) { + fail("Line " + (i + 1) + " of the patched file did not match the revised original"); + } + } + } catch (PatchFailedException e) { + fail(e.getMessage()); + } + } +} diff --git a/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffWriterTest.java b/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffWriterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1972ab3978d85a8e0ed341b11e5e1637d1afce8d --- /dev/null +++ b/java-diff-utils/src/test/java/com/github/difflib/unifieddiff/UnifiedDiffWriterTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2019 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 java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; +import org.junit.Test; + +/** + * + * @author Tobias Warneke (t.warneke@gmx.net) + */ +public class UnifiedDiffWriterTest { + + public UnifiedDiffWriterTest() { + } + + @Test + public void testWrite() throws URISyntaxException, IOException { + String str = readFile(UnifiedDiffReaderTest.class.getResource("jsqlparser_patch_1.diff").toURI(), Charset.defaultCharset()); + UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(new ByteArrayInputStream(str.getBytes())); + + StringWriter writer = new StringWriter(); +// UnifiedDiffWriter.write(diff, writer); +// System.out.println(writer.toString()); + } + + static String readFile(URI path, Charset encoding) + throws IOException { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + return new String(encoded, encoding); + } +} diff --git a/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/jsqlparser_patch_1.diff b/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/jsqlparser_patch_1.diff new file mode 100644 index 0000000000000000000000000000000000000000..c868759e9f9fafc70588ed4cf1adcc92e68e0270 --- /dev/null +++ b/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/jsqlparser_patch_1.diff @@ -0,0 +1,61 @@ +From 3209a16c55c1976d5b772c607fd4b9d5fb9f9483 Mon Sep 17 00:00:00 2001 +From: wumpz <t.warneke@gmx.net> +Date: Tue, 19 Feb 2019 01:35:14 +0100 +Subject: [PATCH] fixes #753 + +--- + src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt | 5 +++-- + .../net/sf/jsqlparser/statement/select/SelectTest.java | 7 +++++++ + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +index cd9bcd1..5f4b2b7 100644 +--- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt ++++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +@@ -189,6 +189,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ + | <K_JOIN:"JOIN"> + | <K_KEEP:"KEEP"> + | <K_KEY:"KEY"> ++| <K_FN:"FN"> + | <K_LAST: "LAST"> + | <K_LATERAL:"LATERAL"> + | <K_LEADING:"LEADING"> +@@ -1039,7 +1040,7 @@ String RelObjectNameWithoutValue() : + | tk=<K_INSERT> | tk=<K_INDEX> | tk=<K_PRIMARY> | tk=<K_ENABLE> + | tk=<K_UNSIGNED> + | tk=<K_TEMP> | tk=<K_TEMPORARY> | tk=<K_TYPE> | tk=<K_ISNULL> +- | tk=<K_ZONE> | tk=<K_COLUMNS> | tk=<K_DESCRIBE> ++ | tk=<K_ZONE> | tk=<K_COLUMNS> | tk=<K_DESCRIBE> | tk=<K_FN> + /* | tk=<K_PLACING> | tk=<K_BOTH> | tk=<K_LEADING> | tk=<K_TRAILING> */ + ) + +@@ -3118,7 +3119,7 @@ Function Function() #Function: + Expression expr1 = null; + } + { +- ["{fn" { retval.setEscaped(true); } ] ++ ["{" <K_FN> { retval.setEscaped(true); } ] + + funcName=RelObjectNameExt() + +diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +index 7ee9b38..d39bfd3 100644 +--- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java ++++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +@@ -1063,6 +1063,13 @@ public class SelectTest { + assertSqlCanBeParsedAndDeparsed("SELECT {fn concat(a, b)} AS COL"); + } + ++ @Test ++ public void testEscapedFunctionsIssue753() throws JSQLParserException { ++ Statement stmt = CCJSqlParserUtil.parse("SELECT { fn test(0)} AS COL"); ++ assertEquals("SELECT {fn test(0)} AS COL", stmt.toString()); ++ assertSqlCanBeParsedAndDeparsed("SELECT fn FROM fn"); ++ } ++ + @Test + public void testNamedParametersPR702() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed("SELECT substring(id, 2, 3), substring(id from 2 for 3), substring(id from 2), trim(BOTH ' ' from 'foo bar '), trim(LEADING ' ' from 'foo bar '), trim(TRAILING ' ' from 'foo bar '), trim(' ' from 'foo bar '), position('foo' in 'bar'), overlay('foo' placing 'bar' from 1), overlay('foo' placing 'bar' from 1 for 2) FROM my table"); +-- +2.17.1.windows.2 + diff --git a/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/problem_diff_issue33.diff b/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/problem_diff_issue33.diff new file mode 100644 index 0000000000000000000000000000000000000000..a78344dd283cb20c4836d0295d1cb330a48ef2fc --- /dev/null +++ b/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/problem_diff_issue33.diff @@ -0,0 +1,6 @@ +--- a/Main.java ++++ b/Main.java +@@ -2,2 +2,3 @@ public class Main { + public static void main(String[] args) { ++ System.out.println("Hello, world!"); + } \ No newline at end of file diff --git a/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/problem_diff_issue46.diff b/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/problem_diff_issue46.diff new file mode 100644 index 0000000000000000000000000000000000000000..ef6886948940080ff82c2bd79cca71e5c75ea753 --- /dev/null +++ b/java-diff-utils/src/test/resources/com/github/difflib/unifieddiff/problem_diff_issue46.diff @@ -0,0 +1,8 @@ +--- a.vhd 2019-04-18 13:49:39.516149751 +0200 ++++ b.vhd 2019-04-18 11:33:08.372563078 +0200 +@@ -2819,3 +2819,2 @@ +--- some comment +-bla +-bla ++ ++ \ No newline at end of file diff --git a/src/test/resources/mocks/5A.txt b/java-diff-utils/src/test/resources/mocks/5A.txt similarity index 96% rename from src/test/resources/mocks/5A.txt rename to java-diff-utils/src/test/resources/mocks/5A.txt index 96e51b80277cf159e72ee0dbf76a7e870df6a0f2..69eafd8b445e35da2ba5d64d18adad49d1e81479 100644 --- a/src/test/resources/mocks/5A.txt +++ b/java-diff-utils/src/test/resources/mocks/5A.txt @@ -1,372 +1,372 @@ -#!/bin/sh -# -# Copyright (c) 2006 Johannes E. Schindelin -# - -test_description='Test special whitespace in diff engine. - -' -. ./test-lib.sh -. ../diff-lib.sh - -# Ray Lehtiniemi's example - -cat << EOF > x -do { - nothing; -} while (0); -EOF - -git update-index --add x - -cat << EOF > x -do -{ - nothing; -} -while (0); -EOF - -cat << EOF > expect -diff --git a/x b/x -index adf3937..6edc172 100644 ---- a/x -+++ b/x -@@ -1,3 +1,5 @@ --do { -+do -+{ - nothing; --} while (0); -+} -+while (0); -EOF - -git diff > out -test_expect_success "Ray's example without options" 'test_cmp expect out' - -git diff -w > out -test_expect_success "Ray's example with -w" 'test_cmp expect out' - -git diff -b > out -test_expect_success "Ray's example with -b" 'test_cmp expect out' - -tr 'Q' '\015' << EOF > x -whitespace at beginning -whitespace change -whitespace in the middle -whitespace at end -unchanged line -CR at endQ -EOF - -git update-index x - -tr '_' ' ' << EOF > x - whitespace at beginning -whitespace change -white space in the middle -whitespace at end__ -unchanged line -CR at end -EOF - -tr 'Q_' '\015 ' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning --whitespace change --whitespace in the middle --whitespace at end -+ whitespace at beginning -+whitespace change -+white space in the middle -+whitespace at end__ -unchanged line --CR at endQ -+CR at end -EOF -git diff > out -test_expect_success 'another test, without options' 'test_cmp expect out' - -cat << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 -EOF -git diff -w > out -test_expect_success 'another test, with -w' 'test_cmp expect out' - -tr 'Q' '\015' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning -+ whitespace at beginning -whitespace change --whitespace in the middle -+white space in the middle -whitespace at end -unchanged line -CR at endQ -EOF -git diff -b > out -test_expect_success 'another test, with -b' 'test_cmp expect out' - -test_expect_success 'check mixed spaces and tabs in indent' ' - - # This is indented with SP HT SP. - echo " foo();" > x && - git diff --check | grep "space before tab in indent" - -' - -test_expect_success 'check mixed tabs and spaces in indent' ' - - # This is indented with HT SP HT. - echo " foo();" > x && - git diff --check | grep "space before tab in indent" - -' - -test_expect_success 'check with no whitespace errors' ' - - git commit -m "snapshot" && - echo "foo();" > x && - git diff --check - -' - -test_expect_success 'check with trailing whitespace' ' - - echo "foo(); " > x && - test_must_fail git diff --check - -' - -test_expect_success 'check with space before tab in indent' ' - - # indent has space followed by hard tab - echo " foo();" > x && - test_must_fail git diff --check - -' - -test_expect_success '--check and --exit-code are not exclusive' ' - - git checkout x && - git diff --check --exit-code - -' - -test_expect_success '--check and --quiet are not exclusive' ' - - git diff --check --quiet - -' - -test_expect_success 'check staged with no whitespace errors' ' - - echo "foo();" > x && - git add x && - git diff --cached --check - -' - -test_expect_success 'check staged with trailing whitespace' ' - - echo "foo(); " > x && - git add x && - test_must_fail git diff --cached --check - -' - -test_expect_success 'check staged with space before tab in indent' ' - - # indent has space followed by hard tab - echo " foo();" > x && - git add x && - test_must_fail git diff --cached --check - -' - -test_expect_success 'check with no whitespace errors (diff-index)' ' - - echo "foo();" > x && - git add x && - git diff-index --check HEAD - -' - -test_expect_success 'check with trailing whitespace (diff-index)' ' - - echo "foo(); " > x && - git add x && - test_must_fail git diff-index --check HEAD - -' - -test_expect_success 'check with space before tab in indent (diff-index)' ' - - # indent has space followed by hard tab - echo " foo();" > x && - git add x && - test_must_fail git diff-index --check HEAD - -' - -test_expect_success 'check staged with no whitespace errors (diff-index)' ' - - echo "foo();" > x && - git add x && - git diff-index --cached --check HEAD - -' - -test_expect_success 'check staged with trailing whitespace (diff-index)' ' - - echo "foo(); " > x && - git add x && - test_must_fail git diff-index --cached --check HEAD - -' - -test_expect_success 'check staged with space before tab in indent (diff-index)' ' - - # indent has space followed by hard tab - echo " foo();" > x && - git add x && - test_must_fail git diff-index --cached --check HEAD - -' - -test_expect_success 'check with no whitespace errors (diff-tree)' ' - - echo "foo();" > x && - git commit -m "new commit" x && - git diff-tree --check HEAD^ HEAD - -' - -test_expect_success 'check with trailing whitespace (diff-tree)' ' - - echo "foo(); " > x && - git commit -m "another commit" x && - test_must_fail git diff-tree --check HEAD^ HEAD - -' - -test_expect_success 'check with space before tab in indent (diff-tree)' ' - - # indent has space followed by hard tab - echo " foo();" > x && - git commit -m "yet another" x && - test_must_fail git diff-tree --check HEAD^ HEAD - -' - -test_expect_success 'check trailing whitespace (trailing-space: off)' ' - - git config core.whitespace "-trailing-space" && - echo "foo (); " > x && - git diff --check - -' - -test_expect_success 'check trailing whitespace (trailing-space: on)' ' - - git config core.whitespace "trailing-space" && - echo "foo (); " > x && - test_must_fail git diff --check - -' - -test_expect_success 'check space before tab in indent (space-before-tab: off)' ' - - # indent contains space followed by HT - git config core.whitespace "-space-before-tab" && - echo " foo ();" > x && - git diff --check - -' - -test_expect_success 'check space before tab in indent (space-before-tab: on)' ' - - # indent contains space followed by HT - git config core.whitespace "space-before-tab" && - echo " foo (); " > x && - test_must_fail git diff --check - -' - -test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' - - git config core.whitespace "-indent-with-non-tab" - echo " foo ();" > x && - git diff --check - -' - -test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' - - git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && - test_must_fail git diff --check - -' - -test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' ' - - git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && - test_must_fail git diff --check - -' - -test_expect_success 'line numbers in --check output are correct' ' - - echo "" > x && - echo "foo(); " >> x && - git diff --check | grep "x:2:" - -' - -test_expect_success 'checkdiff detects trailing blank lines' ' - echo "foo();" >x && - echo "" >>x && - git diff --check | grep "ends with blank" -' - -test_expect_success 'checkdiff allows new blank lines' ' - git checkout x && - mv x y && - ( - echo "/* This is new */" && - echo "" && - cat y - ) >x && - git diff --check -' - -test_expect_success 'combined diff with autocrlf conversion' ' - - git reset --hard && - echo >x hello && - git commit -m "one side" x && - git checkout HEAD^ && - echo >x goodbye && - git commit -m "the other side" x && - git config core.autocrlf true && - test_must_fail git merge master && - - git diff | sed -e "1,/^@@@/d" >actual && - ! grep "^-" actual - -' - -test_done - +#!/bin/sh +# +# Copyright (c) 2006 Johannes E. Schindelin +# + +test_description='Test special whitespace in diff engine. + +' +. ./test-lib.sh +. ../diff-lib.sh + +# Ray Lehtiniemi's example + +cat << EOF > x +do { + nothing; +} while (0); +EOF + +git update-index --add x + +cat << EOF > x +do +{ + nothing; +} +while (0); +EOF + +cat << EOF > expect +diff --git a/x b/x +index adf3937..6edc172 100644 +--- a/x ++++ b/x +@@ -1,3 +1,5 @@ +-do { ++do ++{ + nothing; +-} while (0); ++} ++while (0); +EOF + +git diff > out +test_expect_success "Ray's example without options" 'test_cmp expect out' + +git diff -w > out +test_expect_success "Ray's example with -w" 'test_cmp expect out' + +git diff -b > out +test_expect_success "Ray's example with -b" 'test_cmp expect out' + +tr 'Q' '\015' << EOF > x +whitespace at beginning +whitespace change +whitespace in the middle +whitespace at end +unchanged line +CR at endQ +EOF + +git update-index x + +tr '_' ' ' << EOF > x + whitespace at beginning +whitespace change +white space in the middle +whitespace at end__ +unchanged line +CR at end +EOF + +tr 'Q_' '\015 ' << EOF > expect +diff --git a/x b/x +index d99af23..8b32fb5 100644 +--- a/x ++++ b/x +@@ -1,6 +1,6 @@ +-whitespace at beginning +-whitespace change +-whitespace in the middle +-whitespace at end ++ whitespace at beginning ++whitespace change ++white space in the middle ++whitespace at end__ +unchanged line +-CR at endQ ++CR at end +EOF +git diff > out +test_expect_success 'another test, without options' 'test_cmp expect out' + +cat << EOF > expect +diff --git a/x b/x +index d99af23..8b32fb5 100644 +EOF +git diff -w > out +test_expect_success 'another test, with -w' 'test_cmp expect out' + +tr 'Q' '\015' << EOF > expect +diff --git a/x b/x +index d99af23..8b32fb5 100644 +--- a/x ++++ b/x +@@ -1,6 +1,6 @@ +-whitespace at beginning ++ whitespace at beginning +whitespace change +-whitespace in the middle ++white space in the middle +whitespace at end +unchanged line +CR at endQ +EOF +git diff -b > out +test_expect_success 'another test, with -b' 'test_cmp expect out' + +test_expect_success 'check mixed spaces and tabs in indent' ' + + # This is indented with SP HT SP. + echo " foo();" > x && + git diff --check | grep "space before tab in indent" + +' + +test_expect_success 'check mixed tabs and spaces in indent' ' + + # This is indented with HT SP HT. + echo " foo();" > x && + git diff --check | grep "space before tab in indent" + +' + +test_expect_success 'check with no whitespace errors' ' + + git commit -m "snapshot" && + echo "foo();" > x && + git diff --check + +' + +test_expect_success 'check with trailing whitespace' ' + + echo "foo(); " > x && + test_must_fail git diff --check + +' + +test_expect_success 'check with space before tab in indent' ' + + # indent has space followed by hard tab + echo " foo();" > x && + test_must_fail git diff --check + +' + +test_expect_success '--check and --exit-code are not exclusive' ' + + git checkout x && + git diff --check --exit-code + +' + +test_expect_success '--check and --quiet are not exclusive' ' + + git diff --check --quiet + +' + +test_expect_success 'check staged with no whitespace errors' ' + + echo "foo();" > x && + git add x && + git diff --cached --check + +' + +test_expect_success 'check staged with trailing whitespace' ' + + echo "foo(); " > x && + git add x && + test_must_fail git diff --cached --check + +' + +test_expect_success 'check staged with space before tab in indent' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + test_must_fail git diff --cached --check + +' + +test_expect_success 'check with no whitespace errors (diff-index)' ' + + echo "foo();" > x && + git add x && + git diff-index --check HEAD + +' + +test_expect_success 'check with trailing whitespace (diff-index)' ' + + echo "foo(); " > x && + git add x && + test_must_fail git diff-index --check HEAD + +' + +test_expect_success 'check with space before tab in indent (diff-index)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + test_must_fail git diff-index --check HEAD + +' + +test_expect_success 'check staged with no whitespace errors (diff-index)' ' + + echo "foo();" > x && + git add x && + git diff-index --cached --check HEAD + +' + +test_expect_success 'check staged with trailing whitespace (diff-index)' ' + + echo "foo(); " > x && + git add x && + test_must_fail git diff-index --cached --check HEAD + +' + +test_expect_success 'check staged with space before tab in indent (diff-index)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + test_must_fail git diff-index --cached --check HEAD + +' + +test_expect_success 'check with no whitespace errors (diff-tree)' ' + + echo "foo();" > x && + git commit -m "new commit" x && + git diff-tree --check HEAD^ HEAD + +' + +test_expect_success 'check with trailing whitespace (diff-tree)' ' + + echo "foo(); " > x && + git commit -m "another commit" x && + test_must_fail git diff-tree --check HEAD^ HEAD + +' + +test_expect_success 'check with space before tab in indent (diff-tree)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git commit -m "yet another" x && + test_must_fail git diff-tree --check HEAD^ HEAD + +' + +test_expect_success 'check trailing whitespace (trailing-space: off)' ' + + git config core.whitespace "-trailing-space" && + echo "foo (); " > x && + git diff --check + +' + +test_expect_success 'check trailing whitespace (trailing-space: on)' ' + + git config core.whitespace "trailing-space" && + echo "foo (); " > x && + test_must_fail git diff --check + +' + +test_expect_success 'check space before tab in indent (space-before-tab: off)' ' + + # indent contains space followed by HT + git config core.whitespace "-space-before-tab" && + echo " foo ();" > x && + git diff --check + +' + +test_expect_success 'check space before tab in indent (space-before-tab: on)' ' + + # indent contains space followed by HT + git config core.whitespace "space-before-tab" && + echo " foo (); " > x && + test_must_fail git diff --check + +' + +test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' + + git config core.whitespace "-indent-with-non-tab" + echo " foo ();" > x && + git diff --check + +' + +test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' + + git config core.whitespace "indent-with-non-tab" && + echo " foo ();" > x && + test_must_fail git diff --check + +' + +test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' ' + + git config core.whitespace "indent-with-non-tab" && + echo " foo ();" > x && + test_must_fail git diff --check + +' + +test_expect_success 'line numbers in --check output are correct' ' + + echo "" > x && + echo "foo(); " >> x && + git diff --check | grep "x:2:" + +' + +test_expect_success 'checkdiff detects trailing blank lines' ' + echo "foo();" >x && + echo "" >>x && + git diff --check | grep "ends with blank" +' + +test_expect_success 'checkdiff allows new blank lines' ' + git checkout x && + mv x y && + ( + echo "/* This is new */" && + echo "" && + cat y + ) >x && + git diff --check +' + +test_expect_success 'combined diff with autocrlf conversion' ' + + git reset --hard && + echo >x hello && + git commit -m "one side" x && + git checkout HEAD^ && + echo >x goodbye && + git commit -m "the other side" x && + git config core.autocrlf true && + test_must_fail git merge master && + + git diff | sed -e "1,/^@@@/d" >actual && + ! grep "^-" actual + +' + +test_done + diff --git a/src/test/resources/mocks/5B.txt b/java-diff-utils/src/test/resources/mocks/5B.txt similarity index 96% rename from src/test/resources/mocks/5B.txt rename to java-diff-utils/src/test/resources/mocks/5B.txt index dd12cf4f7db49f8224556b693b4de32a89a5bfbf..112cff5af638f24044b54805cd94aff7fd8082e8 100644 --- a/src/test/resources/mocks/5B.txt +++ b/java-diff-utils/src/test/resources/mocks/5B.txt @@ -1,381 +1,381 @@ -#!/bin/sh -# -# Copyright (c) 2006 Johannes E. Schindelin -# - -test_description='Test special whitespace in diff engine. - -' -. ./test-lib.sh -. ../diff-lib.sh - -# Ray Lehtiniemi's example - -cat << EOF > x -do { - nothing; -} while (0); -EOF - -git update-index --add x - -cat << EOF > x -do -{ - nothing; -} -while (0); -EOF - -cat << EOF > expect -diff --git a/x b/x -index adf3937..6edc172 100644 ---- a/x -+++ b/x -@@ -1,3 +1,5 @@ --do { -+do -+{ - nothing; --} while (0); -+} -+while (0); -EOF - -git diff > out -test_expect_success "Ray's example without options" 'test_cmp expect out' - -git diff -w > out -test_expect_success "Ray's example with -w" 'test_cmp expect out' - -git diff -b > out -test_expect_success "Ray's example with -b" 'test_cmp expect out' - -tr 'Q' '\015' << EOF > x -whitespace at beginning -whitespace change -whitespace in the middle -whitespace at end -unchanged line -CR at endQ -EOF - -git update-index x - -tr '_' ' ' << EOF > x - whitespace at beginning -whitespace change -white space in the middle -whitespace at end__ -unchanged line -CR at end -EOF - -tr 'Q_' '\015 ' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning --whitespace change --whitespace in the middle --whitespace at end -+ whitespace at beginning -+whitespace change -+white space in the middle -+whitespace at end__ -unchanged line --CR at endQ -+CR at end -EOF -git diff > out -test_expect_success 'another test, without options' 'test_cmp expect out' - -cat << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 -EOF -git diff -w > out -test_expect_success 'another test, with -w' 'test_cmp expect out' - -tr 'Q' '\015' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -@@ -1,6 +1,6 @@ --whitespace at beginning -+ whitespace at beginning -whitespace change --whitespace in the middle -+white space in the middle -whitespace at end -unchanged line -CR at endQ -git diff -b --ignore-space-at-eol > out -test_expect_failure 'another test, with -b --ignore-space-at-eol' 'test_cmp expect out' - -tr 'Q' '\015' << EOF > expect -diff --git a/x b/x -index d99af23..8b32fb5 100644 ---- a/x -+++ b/x -EOF -git diff -b > out -test_expect_success 'another test, with -b' 'test_cmp expect out' - -test_expect_success 'check mixed spaces and tabs in indent' ' - - # This is indented with SP HT SP. - echo " foo();" > x && - git diff --check | grep "space before tab in indent" - -' - -test_expect_success 'check mixed tabs and spaces in indent' ' - - # This is indented with HT SP HT. - echo " foo();" > x && - git diff --check | grep "space before tab in indent" - -' - -test_expect_success 'check with no whitespace errors' ' - - git commit -m "snapshot" && - echo "foo();" > x && - git diff --check - -' - -test_expect_success 'check with trailing whitespace' ' - - echo "foo(); " > x && - test_must_fail git diff --check - -' - -test_expect_success 'check with space before tab in indent' ' - - # indent has space followed by hard tab - echo " foo();" > x && - test_must_fail git diff --check - -' - -test_expect_success '--check and --exit-code are not exclusive' ' - - git checkout x && - git diff --check --exit-code - -' - -test_expect_success '--check and --quiet are not exclusive' ' - - git diff --check --quiet - -' - -test_expect_success 'check staged with no whitespace errors' ' - - echo "foo();" > x && - git add x && - git diff --cached --check - -' - -test_expect_success 'check staged with trailing whitespace' ' - - echo "foo(); " > x && - git add x && - test_must_fail git diff --cached --check - -' - -test_expect_success 'check staged with space before tab in indent' ' - - # indent has space followed by hard tab - echo " foo();" > x && - git add x && - test_must_fail git diff --cached --check - -' - -test_expect_success 'check with no whitespace errors (diff-index)' ' - - echo "foo();" > x && - git add x && - git diff-index --check HEAD - -' - -test_expect_success 'check with trailing whitespace (diff-index)' ' - - echo "foo(); " > x && - git add x && - test_must_fail git diff-index --check HEAD - -' - -test_expect_success 'check with space before tab in indent (diff-index)' ' - - # indent has space followed by hard tab - echo " foo();" > x && - git add x && - test_must_fail git diff-index --check HEAD - -' - -test_expect_success 'check staged with no whitespace errors (diff-index)' ' - - echo "foo();" > x && - git add x && - git diff-index --cached --check HEAD - -' - -test_expect_success 'check staged with trailing whitespace (diff-index)' ' - - echo "foo(); " > x && - git add x && - test_must_fail git diff-index --cached --check HEAD - -' - -test_expect_success 'check staged with space before tab in indent (diff-index)' ' - - # indent has space followed by hard tab - echo " foo();" > x && - git add x && - test_must_fail git diff-index --cached --check HEAD - -' - -test_expect_success 'check with no whitespace errors (diff-tree)' ' - - echo "foo();" > x && - git commit -m "new commit" x && - git diff-tree --check HEAD^ HEAD - -' - -test_expect_success 'check with trailing whitespace (diff-tree)' ' - - echo "foo(); " > x && - git commit -m "another commit" x && - test_must_fail git diff-tree --check HEAD^ HEAD - -' - -test_expect_success 'check with space before tab in indent (diff-tree)' ' - - # indent has space followed by hard tab - echo " foo();" > x && - git commit -m "yet another" x && - test_must_fail git diff-tree --check HEAD^ HEAD - -' - -test_expect_success 'check trailing whitespace (trailing-space: off)' ' - - git config core.whitespace "-trailing-space" && - echo "foo (); " > x && - git diff --check - -' - -test_expect_success 'check trailing whitespace (trailing-space: on)' ' - - git config core.whitespace "trailing-space" && - echo "foo (); " > x && - test_must_fail git diff --check - -' - -test_expect_success 'check space before tab in indent (space-before-tab: off)' ' - - # indent contains space followed by HT - git config core.whitespace "-space-before-tab" && - echo " foo ();" > x && - git diff --check - -' - -test_expect_success 'check space before tab in indent (space-before-tab: on)' ' - - # indent contains space followed by HT - git config core.whitespace "space-before-tab" && - echo " foo (); " > x && - test_must_fail git diff --check - -' - -test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' - - git config core.whitespace "-indent-with-non-tab" - echo " foo ();" > x && - git diff --check - -' - -test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' - - git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && - test_must_fail git diff --check - -' - -test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' ' - - git config core.whitespace "indent-with-non-tab" && - echo " foo ();" > x && - test_must_fail git diff --check - -' - -test_expect_success 'line numbers in --check output are correct' ' - - echo "" > x && - echo "foo(); " >> x && - git diff --check | grep "x:2:" - -' - -test_expect_success 'checkdiff detects trailing blank lines' ' - echo "foo();" >x && - echo "" >>x && - git diff --check | grep "ends with blank" -' - -test_expect_success 'checkdiff allows new blank lines' ' - git checkout x && - mv x y && - ( - echo "/* This is new */" && - echo "" && - cat y - ) >x && - git diff --check -' - -test_expect_success 'combined diff with autocrlf conversion' ' - - git reset --hard && - echo >x hello && - git commit -m "one side" x && - git checkout HEAD^ && - echo >x goodbye && - git commit -m "the other side" x && - git config core.autocrlf true && - test_must_fail git merge master && - - git diff | sed -e "1,/^@@@/d" >actual && - ! grep "^-" actual - -' - -test_done - - +#!/bin/sh +# +# Copyright (c) 2006 Johannes E. Schindelin +# + +test_description='Test special whitespace in diff engine. + +' +. ./test-lib.sh +. ../diff-lib.sh + +# Ray Lehtiniemi's example + +cat << EOF > x +do { + nothing; +} while (0); +EOF + +git update-index --add x + +cat << EOF > x +do +{ + nothing; +} +while (0); +EOF + +cat << EOF > expect +diff --git a/x b/x +index adf3937..6edc172 100644 +--- a/x ++++ b/x +@@ -1,3 +1,5 @@ +-do { ++do ++{ + nothing; +-} while (0); ++} ++while (0); +EOF + +git diff > out +test_expect_success "Ray's example without options" 'test_cmp expect out' + +git diff -w > out +test_expect_success "Ray's example with -w" 'test_cmp expect out' + +git diff -b > out +test_expect_success "Ray's example with -b" 'test_cmp expect out' + +tr 'Q' '\015' << EOF > x +whitespace at beginning +whitespace change +whitespace in the middle +whitespace at end +unchanged line +CR at endQ +EOF + +git update-index x + +tr '_' ' ' << EOF > x + whitespace at beginning +whitespace change +white space in the middle +whitespace at end__ +unchanged line +CR at end +EOF + +tr 'Q_' '\015 ' << EOF > expect +diff --git a/x b/x +index d99af23..8b32fb5 100644 +--- a/x ++++ b/x +@@ -1,6 +1,6 @@ +-whitespace at beginning +-whitespace change +-whitespace in the middle +-whitespace at end ++ whitespace at beginning ++whitespace change ++white space in the middle ++whitespace at end__ +unchanged line +-CR at endQ ++CR at end +EOF +git diff > out +test_expect_success 'another test, without options' 'test_cmp expect out' + +cat << EOF > expect +diff --git a/x b/x +index d99af23..8b32fb5 100644 +EOF +git diff -w > out +test_expect_success 'another test, with -w' 'test_cmp expect out' + +tr 'Q' '\015' << EOF > expect +diff --git a/x b/x +index d99af23..8b32fb5 100644 +--- a/x ++++ b/x +@@ -1,6 +1,6 @@ +-whitespace at beginning ++ whitespace at beginning +whitespace change +-whitespace in the middle ++white space in the middle +whitespace at end +unchanged line +CR at endQ +git diff -b --ignore-space-at-eol > out +test_expect_failure 'another test, with -b --ignore-space-at-eol' 'test_cmp expect out' + +tr 'Q' '\015' << EOF > expect +diff --git a/x b/x +index d99af23..8b32fb5 100644 +--- a/x ++++ b/x +EOF +git diff -b > out +test_expect_success 'another test, with -b' 'test_cmp expect out' + +test_expect_success 'check mixed spaces and tabs in indent' ' + + # This is indented with SP HT SP. + echo " foo();" > x && + git diff --check | grep "space before tab in indent" + +' + +test_expect_success 'check mixed tabs and spaces in indent' ' + + # This is indented with HT SP HT. + echo " foo();" > x && + git diff --check | grep "space before tab in indent" + +' + +test_expect_success 'check with no whitespace errors' ' + + git commit -m "snapshot" && + echo "foo();" > x && + git diff --check + +' + +test_expect_success 'check with trailing whitespace' ' + + echo "foo(); " > x && + test_must_fail git diff --check + +' + +test_expect_success 'check with space before tab in indent' ' + + # indent has space followed by hard tab + echo " foo();" > x && + test_must_fail git diff --check + +' + +test_expect_success '--check and --exit-code are not exclusive' ' + + git checkout x && + git diff --check --exit-code + +' + +test_expect_success '--check and --quiet are not exclusive' ' + + git diff --check --quiet + +' + +test_expect_success 'check staged with no whitespace errors' ' + + echo "foo();" > x && + git add x && + git diff --cached --check + +' + +test_expect_success 'check staged with trailing whitespace' ' + + echo "foo(); " > x && + git add x && + test_must_fail git diff --cached --check + +' + +test_expect_success 'check staged with space before tab in indent' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + test_must_fail git diff --cached --check + +' + +test_expect_success 'check with no whitespace errors (diff-index)' ' + + echo "foo();" > x && + git add x && + git diff-index --check HEAD + +' + +test_expect_success 'check with trailing whitespace (diff-index)' ' + + echo "foo(); " > x && + git add x && + test_must_fail git diff-index --check HEAD + +' + +test_expect_success 'check with space before tab in indent (diff-index)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + test_must_fail git diff-index --check HEAD + +' + +test_expect_success 'check staged with no whitespace errors (diff-index)' ' + + echo "foo();" > x && + git add x && + git diff-index --cached --check HEAD + +' + +test_expect_success 'check staged with trailing whitespace (diff-index)' ' + + echo "foo(); " > x && + git add x && + test_must_fail git diff-index --cached --check HEAD + +' + +test_expect_success 'check staged with space before tab in indent (diff-index)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git add x && + test_must_fail git diff-index --cached --check HEAD + +' + +test_expect_success 'check with no whitespace errors (diff-tree)' ' + + echo "foo();" > x && + git commit -m "new commit" x && + git diff-tree --check HEAD^ HEAD + +' + +test_expect_success 'check with trailing whitespace (diff-tree)' ' + + echo "foo(); " > x && + git commit -m "another commit" x && + test_must_fail git diff-tree --check HEAD^ HEAD + +' + +test_expect_success 'check with space before tab in indent (diff-tree)' ' + + # indent has space followed by hard tab + echo " foo();" > x && + git commit -m "yet another" x && + test_must_fail git diff-tree --check HEAD^ HEAD + +' + +test_expect_success 'check trailing whitespace (trailing-space: off)' ' + + git config core.whitespace "-trailing-space" && + echo "foo (); " > x && + git diff --check + +' + +test_expect_success 'check trailing whitespace (trailing-space: on)' ' + + git config core.whitespace "trailing-space" && + echo "foo (); " > x && + test_must_fail git diff --check + +' + +test_expect_success 'check space before tab in indent (space-before-tab: off)' ' + + # indent contains space followed by HT + git config core.whitespace "-space-before-tab" && + echo " foo ();" > x && + git diff --check + +' + +test_expect_success 'check space before tab in indent (space-before-tab: on)' ' + + # indent contains space followed by HT + git config core.whitespace "space-before-tab" && + echo " foo (); " > x && + test_must_fail git diff --check + +' + +test_expect_success 'check spaces as indentation (indent-with-non-tab: off)' ' + + git config core.whitespace "-indent-with-non-tab" + echo " foo ();" > x && + git diff --check + +' + +test_expect_success 'check spaces as indentation (indent-with-non-tab: on)' ' + + git config core.whitespace "indent-with-non-tab" && + echo " foo ();" > x && + test_must_fail git diff --check + +' + +test_expect_success 'check tabs and spaces as indentation (indent-with-non-tab: on)' ' + + git config core.whitespace "indent-with-non-tab" && + echo " foo ();" > x && + test_must_fail git diff --check + +' + +test_expect_success 'line numbers in --check output are correct' ' + + echo "" > x && + echo "foo(); " >> x && + git diff --check | grep "x:2:" + +' + +test_expect_success 'checkdiff detects trailing blank lines' ' + echo "foo();" >x && + echo "" >>x && + git diff --check | grep "ends with blank" +' + +test_expect_success 'checkdiff allows new blank lines' ' + git checkout x && + mv x y && + ( + echo "/* This is new */" && + echo "" && + cat y + ) >x && + git diff --check +' + +test_expect_success 'combined diff with autocrlf conversion' ' + + git reset --hard && + echo >x hello && + git commit -m "one side" x && + git checkout HEAD^ && + echo >x goodbye && + git commit -m "the other side" x && + git config core.autocrlf true && + test_must_fail git merge master && + + git diff | sed -e "1,/^@@@/d" >actual && + ! grep "^-" actual + +' + +test_done + + diff --git a/src/test/resources/mocks/issue10_base.txt b/java-diff-utils/src/test/resources/mocks/issue10_base.txt similarity index 100% rename from src/test/resources/mocks/issue10_base.txt rename to java-diff-utils/src/test/resources/mocks/issue10_base.txt diff --git a/src/test/resources/mocks/issue10_patch.txt b/java-diff-utils/src/test/resources/mocks/issue10_patch.txt similarity index 100% rename from src/test/resources/mocks/issue10_patch.txt rename to java-diff-utils/src/test/resources/mocks/issue10_patch.txt diff --git a/src/test/resources/mocks/issue11_1.txt b/java-diff-utils/src/test/resources/mocks/issue11_1.txt similarity index 100% rename from src/test/resources/mocks/issue11_1.txt rename to java-diff-utils/src/test/resources/mocks/issue11_1.txt diff --git a/src/test/resources/mocks/issue11_2.txt b/java-diff-utils/src/test/resources/mocks/issue11_2.txt similarity index 100% rename from src/test/resources/mocks/issue11_2.txt rename to java-diff-utils/src/test/resources/mocks/issue11_2.txt diff --git a/src/test/resources/mocks/issue15_1.txt b/java-diff-utils/src/test/resources/mocks/issue15_1.txt similarity index 100% rename from src/test/resources/mocks/issue15_1.txt rename to java-diff-utils/src/test/resources/mocks/issue15_1.txt diff --git a/src/test/resources/mocks/issue15_2.txt b/java-diff-utils/src/test/resources/mocks/issue15_2.txt similarity index 100% rename from src/test/resources/mocks/issue15_2.txt rename to java-diff-utils/src/test/resources/mocks/issue15_2.txt diff --git a/src/test/resources/mocks/one_delta_test_original.txt b/java-diff-utils/src/test/resources/mocks/one_delta_test_original.txt similarity index 100% rename from src/test/resources/mocks/one_delta_test_original.txt rename to java-diff-utils/src/test/resources/mocks/one_delta_test_original.txt diff --git a/src/test/resources/mocks/one_delta_test_revised.txt b/java-diff-utils/src/test/resources/mocks/one_delta_test_revised.txt similarity index 100% rename from src/test/resources/mocks/one_delta_test_revised.txt rename to java-diff-utils/src/test/resources/mocks/one_delta_test_revised.txt diff --git a/src/test/resources/mocks/original.txt b/java-diff-utils/src/test/resources/mocks/original.txt similarity index 100% rename from src/test/resources/mocks/original.txt rename to java-diff-utils/src/test/resources/mocks/original.txt diff --git a/src/test/resources/mocks/revised.txt b/java-diff-utils/src/test/resources/mocks/revised.txt similarity index 100% rename from src/test/resources/mocks/revised.txt rename to java-diff-utils/src/test/resources/mocks/revised.txt diff --git a/pom.xml b/pom.xml index 5a85f49f48ec9346654e761bc375a0e657028b56..467e46b8987f02d2c39d7674c6d8f8381bfa7da2 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,15 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>io.github.java-diff-utils</groupId> - <artifactId>java-diff-utils</artifactId> - <packaging>jar</packaging> - <version>4.0</version> - <name>java-diff-utils</name> + <artifactId>java-diff-utils-parent</artifactId> + <version>4.4</version> + <name>java-diff-utils-parent</name> + <packaging>pom</packaging> + <modules> + <module>java-diff-utils</module> + <module>java-diff-utils-jgit</module> + </modules> <description>The DiffUtils library for computing diffs, applying patches, generationg side-by-side view in Java.</description> <url>https://github.com/java-diff-utils/java-diff-utils</url> <inceptionYear>2009</inceptionYear> @@ -24,9 +29,8 @@ <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> <url>https://github.com/java-diff-utils/java-diff-utils.git</url> - <tag>java-diff-utils-4.0</tag> + <tag>java-diff-utils-parent-4.4</tag> </scm> - <issueManagement> <system>GitHub Issues</system> <url>https://github.com/java-diff-utils/java-diff-utils/issues</url> @@ -41,16 +45,6 @@ <name>Tobias Warneke</name> <email>t.warneke@gmx.net</email> </developer> - <!-- - <developer> - <name>Dmitry Naumenko</name> - <email>dm.naumenko@gmail.com</email> - </developer> - <developer> - <name>Juanco Anez</name> - <email>juanco@suigeneris.org</email> - </developer> - --> </developers> <licenses> @@ -61,81 +55,21 @@ <comments>A business-friendly OSS license</comments> </license> </licenses> - <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>1.8</maven.compiler.source> + <maven.compiler.target>1.8</maven.compiler.target> </properties> - - <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - <type>jar</type> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.eclipse.jgit</groupId> - <artifactId>org.eclipse.jgit</artifactId> - <version>4.4.1.201607150455-r</version> - <exclusions> - <exclusion> - <groupId>com.googlecode.javaewah</groupId> - <artifactId>JavaEWAH</artifactId> - </exclusion> - <exclusion> - <groupId>commons-codec</groupId> - <artifactId>commons-codec</artifactId> - </exclusion> - <exclusion> - <groupId>commons-logging</groupId> - <artifactId>commons-logging</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - </exclusion> - <exclusion> - <groupId>com.jcraft</groupId> - <artifactId>jsch</artifactId> - </exclusion> - <exclusion> - <groupId>org.slf4j</groupId> - <artifactId>slf4j-api</artifactId> - </exclusion> - </exclusions> - </dependency> - </dependencies> - <build> <plugins> - <plugin> <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.6.1</version> - <configuration> - <source>1.8</source> - <target>1.8</target> - <encoding>UTF-8</encoding> - </configuration> - </plugin> - - <!-- Make this JAR OSGi ready --> - <!-- We want to keep packaging type as jar. Therefore we need to customize the MANIFEST.MF. - See http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html - --> - <plugin> - <artifactId>maven-jar-plugin</artifactId> - <version>3.0.2</version> + <artifactId>maven-release-plugin</artifactId> + <version>2.5.3</version> <configuration> - <archive> - <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> - <manifestEntries> - <!-- identical to OSGI name --> - <Automatic-Module-Name>com.github.wumpz.diffutils</Automatic-Module-Name> - </manifestEntries> - </archive> + <localCheckout>true</localCheckout> + <pushChanges>false</pushChanges> + <mavenExecutorId>forked-path</mavenExecutorId> </configuration> </plugin> <plugin> @@ -168,26 +102,6 @@ </execution> </executions> </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <version>2.19.1</version> - <configuration> - <excludes> - <exclude>**/LR*.java</exclude> - </excludes> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-release-plugin</artifactId> - <version>2.5.3</version> - <configuration> - <localCheckout>true</localCheckout> - <pushChanges>false</pushChanges> - <mavenExecutorId>forked-path</mavenExecutorId> - </configuration> - </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId> @@ -209,12 +123,6 @@ <module name="Checker"> <module name="SuppressWarningsFilter" /> <module name="FileTabCharacter" /> - <!-- git checkout may change linefeeds on the fly - <module name="RegexpMultiline"> - <property name="format" value="(?s:(\r\n|\r).*)" /> - <property name="message" value="CRLF and CR line endings are prohibited, but this file uses them." /> - </module> - --> <module name="TreeWalker"> <module name="AvoidNestedBlocks" /> <module name="ConstantName" /> @@ -243,10 +151,20 @@ <dependency> <groupId>com.puppycrawl.tools</groupId> <artifactId>checkstyle</artifactId> - <version>6.19</version> + <version>8.18</version> </dependency> </dependencies> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.22.1</version> + <configuration> + <excludes> + <exclude>**/LR*.java</exclude> + </excludes> + </configuration> + </plugin> </plugins> </build> <profiles> @@ -306,5 +224,4 @@ </build> </profile> </profiles> -</project> - +</project> \ No newline at end of file