133 Commits

Author SHA1 Message Date
Tobias Warneke
0fd3bd8e06 [maven-release-plugin] prepare release java-diff-utils-parent-4.12 2022-07-23 01:33:40 +02:00
Tobias Warneke
eeb819cad4 Merge origin/master 2022-07-23 01:29:58 +02:00
Tobias Warneke
e73742c4fc 2022-07-23 01:29:37 +02:00
Tobias Warneke
0545519fc3 included some more tests 2022-05-15 00:17:49 +02:00
Okue
bc65f9703c Update version in gradle example of README (#145) 2022-04-10 00:25:45 +02:00
Hussein Kasem
ea9942da12 Fix for #141 (#144)
* Add test to reproduce issue #141

* Fix assumption on test to match expected behaviour expressed on #141

* Make "/" after "virtual" directories mandatory

Now the regex only matches with "a/", "b/", "new/" and "old/", previously the slash was taken as optional.
fixes #141
2022-04-10 00:20:37 +02:00
Sebastian
8fdd239961 Fix a typo in ComputeDifference.java (#140) 2022-02-21 09:00:27 +01:00
anatawa12
37f9eafaa9 Fizzy apply (#125)
* add applyFuzzyTo and restoreFuzzy

* implement applyFuzzyTo and restoreFuzzy for EqualDelta

* add verifyChunk with fuzzy and delta

* implement fuzzy apply and add tests

* fix style

* extract method

* fix: assign lastPatchDelta and lastPatchEnd

* fix use explict import

* document EqualDelta#applyFuzzyToAt

* set access modifiers

* change test method name

* document empty method

* apply from first

* add more tests

* add more documentation about fuzz parameter

* fix documentation about fizzy patch

Co-authored-by: cowwoc <cowwoc2020@gmail.com>

Co-authored-by: cowwoc <cowwoc2020@gmail.com>
2021-11-28 23:10:52 +01:00
Tobias Warneke
0fd38db8ae fixes #129 - added the possibility to skip delta decompression 2021-10-21 23:17:04 +02:00
Tobias Warneke
3663cb5d87 changed gpg plugin version 2021-09-08 12:37:20 +02:00
Tobias Warneke
8ae1f6cbbf [maven-release-plugin] prepare for next development iteration 2021-09-08 12:28:14 +02:00
Tobias Warneke
ab1e38c57b [maven-release-plugin] prepare release java-diff-utils-parent-4.11 2021-09-08 12:28:13 +02:00
Tobias Warneke
286e807232 Merge origin/master 2021-09-08 12:25:34 +02:00
Jerry James
c85296b63d Javadoc warning fixes (#109)
Co-authored-by: Tobias <t.warneke@gmx.net>
2021-09-08 12:21:50 +02:00
Tobias Warneke
4c457b39dc 2021-09-08 12:19:53 +02:00
Tobias Warneke
7dea4e2298 2021-09-08 12:16:50 +02:00
Tobias Warneke
2b02951e89 Merge introduce-optimized-meyers-algorithm 2021-09-08 12:11:12 +02:00
Tobias Warneke
894b8ba300 implemented multi algorithm patch test 2021-08-15 00:52:08 +02:00
Tobias Warneke
2294c5be7b implemented multi algorithm patch test 2021-08-15 00:51:24 +02:00
Tobias Warneke
7203d4890f mmoved header to inner processing to allow a header for each diff block 2021-07-19 00:15:39 +02:00
Tobias Warneke
e413d79ecd attached logging to new meyer diff algorithm 2021-07-18 01:30:44 +02:00
Tobias Warneke
c765616957 attached logging to new meyer diff algorithm 2021-07-18 01:20:25 +02:00
Tobias Warneke
24c3df1f39 2021-07-09 18:27:52 +02:00
Tobias Warneke
9765052226 first implementation of meyers diff with linear space 2021-07-08 22:42:53 +02:00
Tobias Warneke
8bb4a9a8b1 first implementation of meyers diff with linear space 2021-07-08 21:01:10 +02:00
Ilari Suhonen
89ce301123 Fix typo in UnifiedDiff#spplyPatchTo(Predicate<String>, List<String>) (#127)
* Fix typo in UnifiedDiff.java

Changes UnifiedDiff#spplyPatchTo to UnifiedDiff#applyPatchTo

* Fix typo in test

Fixes the method invocation in the UnifiedDiff roundtrip test to account for the typo fix in UnifiedDiff
2021-07-07 07:15:55 +02:00
Tobias Warneke
3d5343c283 fixes #107 refinement 2021-05-05 22:14:56 +02:00
Tobias Warneke
d384ab6178 2021-04-28 23:33:53 +02:00
Tobias Warneke
f03df6cf38 [maven-release-plugin] prepare for next development iteration 2021-04-28 23:21:52 +02:00
Tobias Warneke
5a11752126 [maven-release-plugin] prepare release java-diff-utils-parent-4.10 2021-04-28 23:21:51 +02:00
Tobias Warneke
94674a0ad7 fixes #119 2021-04-28 22:00:20 +02:00
Tobias Warneke
91a42b2793 fixes #120 2021-04-28 21:14:32 +02:00
Tobias Warneke
bf4ec94cc9 fixes #117 2021-03-14 23:42:10 +01:00
Tobias Warneke
df27b689f3 Merge origin/master into introduce-conflict-patching 2021-03-14 22:45:22 +01:00
Tobias Warneke
2a1239b3a2 fixes #117 2021-03-14 22:44:20 +01:00
Tobias Warneke
8d38e1012e first test with conflict output 2021-02-27 01:32:45 +01:00
Tobias Warneke
8880ec545b introduced conflict processing 2021-02-21 23:04:17 +01:00
Tobias Warneke
ce05cbf9c9 2021-02-10 07:34:55 +01:00
Tobias Warneke
f71275de08 upgraded some versions 2021-02-07 13:22:52 +01:00
Tobias Warneke
307574225a remove verification from applyTo 2021-02-07 13:22:34 +01:00
Tobias Warneke
b9fea86e43 remove verification from applyTo 2021-02-07 13:22:20 +01:00
Tobias Warneke
b17bbb12c3 fixes #115 2021-02-07 00:47:27 +01:00
Tobias
0905d0e5f7 Update issue templates 2021-02-06 23:35:55 +01:00
Tobias Warneke
57df629662 2021-02-06 21:41:11 +01:00
Tobias Warneke
73ec9e9320 fixes #114 - decompressing deltas - refactoring 2021-01-16 23:21:01 +01:00
Tobias Warneke
507ced4493 fixes #114 - decompressing deltas 2021-01-16 02:30:04 +01:00
Tobias Warneke
7e8d2867ad fixes #114 - decompressing deltas 2021-01-16 02:22:47 +01:00
Tobias Warneke
ffd14fb67d started decompression idea 2021-01-16 00:08:19 +01:00
Tobias Warneke
04b5c7e167 started decompression idea 2021-01-16 00:05:09 +01:00
Tobias Warneke
a9b5e5fa88 fixes #111 - replaced some GNU license including files 2020-12-30 22:30:50 +01:00
Tobias Warneke
4061ab6c57 fixes #110 support for similarity index, rename from, rename to 2020-12-24 00:51:29 +01:00
Tobias Warneke
7da297322b fixes #110 support for similarity index, rename from, rename to 2020-12-24 00:49:10 +01:00
Tobias Warneke
fb0837fd73 fixes #107 process "\ No newline at end of file" 2020-12-19 00:21:09 +01:00
Tobias Warneke
642dc659f1 fixes #107 process "\ No newline at end of file" 2020-12-19 00:17:54 +01:00
Tobias Warneke
e59e9e8379 fixes #107 process "\ No newline at end of file" 2020-12-19 00:12:55 +01:00
Tobias Warneke
6748451e94 Merge origin/master 2020-12-19 00:12:35 +01:00
Tobias Warneke
445381b277 fixes #107 process "\ No newline at end of file" 2020-12-19 00:11:32 +01:00
Jerry James
ab76d7229a Eliminate most unchecked and unsafe operation warnings (#108)
Thx for improving java-diff-utils.
2020-12-17 23:08:59 +01:00
Tobias Warneke
7647c0a39e removed author entry that was accidently introduced into the new implementation of UnifiedDiff tools 2020-12-17 23:02:05 +01:00
Tobias Warneke
759a2ba67a changed action to matrix build project using java 8 and 11 2020-12-17 22:55:11 +01:00
Tobias Warneke
270754fb8c 2020-12-13 23:54:12 +01:00
Tobias Warneke
06f1e0593e 2020-12-13 23:48:24 +01:00
Tobias
26be87091b Update README.md 2020-12-13 23:12:31 +01:00
Tobias
b927e6f477 Update README.md 2020-12-13 23:02:54 +01:00
Tobias
ba3c313440 Update README.md 2020-12-13 23:01:23 +01:00
Tobias
d62e9a9fb6 Update README.md 2020-12-13 23:00:10 +01:00
Tobias Warneke
d7a5247b1d 2020-12-13 22:58:42 +01:00
Tobias Warneke
b8aef6a3da 2020-12-13 22:47:15 +01:00
Tobias
7d8b87a0ec Create maven.yml 2020-12-13 22:41:38 +01:00
Tobias
1fdea352ad Create stale.yml 2020-12-13 22:34:53 +01:00
Tobias Warneke
c6d3f73d22 fixes #104 2020-12-12 00:35:11 +01:00
Mike Samuel
5338313a54 StringUtils.wrapText will not split surrogate pair. (#103)
Previously,

    StringUtils.wrapText(".\uD800\uDC00.", 2)
    //                           ^ index 2 points here

would insert a `<br/>` between two paired surrogates.

Now, it shifts the insertion point to a whole code-point boundary.
2020-11-22 19:48:05 +01:00
Tobias Warneke
55d71fea71 2020-11-01 22:06:19 +01:00
Tobias Warneke
e4ab41bf04 [maven-release-plugin] prepare for next development iteration 2020-11-01 21:32:22 +01:00
Tobias Warneke
1ec708fe30 [maven-release-plugin] prepare release java-diff-utils-parent-4.9 2020-11-01 21:32:21 +01:00
Tobias Warneke
fcf83e918f 2020-11-01 20:03:18 +01:00
Alon Harel
4ee56d2554 make patch serializable (#101) 2020-10-26 13:34:23 +01:00
Tobias Warneke
21f9e9d415 [maven-release-plugin] prepare for next development iteration 2020-09-27 22:08:04 +02:00
Tobias Warneke
76ae5f3b6f [maven-release-plugin] prepare release java-diff-utils-parent-4.8 2020-09-27 22:07:59 +02:00
Tobias Warneke
7d88486bdc 2020-09-27 22:04:44 +02:00
Tobias Warneke
694e93143d 2020-09-27 22:03:18 +02:00
Tobias Warneke
dac751bf73 fixes #98 - deleted file mode 2020-09-27 21:48:59 +02:00
Tobias Warneke
f76abb58f6 improved the documentation of DeltyType a bit
fixed #99
2020-09-27 18:13:03 +02:00
Tobias Warneke
de04bd688a 2020-08-09 21:44:28 +02:00
Tobias Warneke
e38cd3a99f 2020-08-09 21:38:16 +02:00
Tobias Warneke
96f7fbdebd finishes pull request #93 2020-08-04 07:35:09 +02:00
Morten Telling
d3524314eb Mark no file with /dev/null to align with git diff (#93)
If you run git diff locally with a staged new file the diff will indicate that the file did not exist before with `--- /dev/null`.
I believe this should align with this?
2020-08-04 07:29:55 +02:00
Tobias Warneke
85c3199570 changes jgit version 2020-08-04 07:27:41 +02:00
Tobias Warneke
dbe601c2fc fixes #83 2020-07-03 23:44:48 +02:00
Tobias Warneke
fc7c714264 Merge origin/master 2020-07-03 22:59:18 +02:00
Tobias Warneke
dcc29eee7e fixes #84 Seems to be solved by a previous issue. A test case was included from issue 84. 2020-07-03 22:59:04 +02:00
iamhlbx
f0f5d241c7 fixes #89 to get exact add/remove lines'positions (#90) 2020-07-03 16:58:44 +02:00
iamhlbx
e11c1599ee update .gitignore to ignore *.iml files (#88) 2020-07-01 14:25:54 +02:00
Tobias
73c4c307a9 Update CHANGELOG.md 2020-06-21 22:38:11 +02:00
Tobias Warneke
8006986dd8 fixes #85 2020-06-21 02:04:14 +02:00
Tobias Warneke
f292c97dae fixes #79
open #85
2020-06-21 01:29:57 +02:00
Tobias Warneke
7620f919c2 fixes #80 2020-05-24 22:56:28 +02:00
Tobias Warneke
a8e4ce2eff fixes #65 2020-05-17 17:16:14 +02:00
Tobias
9bd7aaa0f2 Update README.md 2020-04-23 23:47:42 +02:00
Tobias
80c17a30d9 Update README.md 2020-04-23 23:21:18 +02:00
Tobias Warneke
b5569703c8 2020-04-23 23:18:28 +02:00
Tobias Warneke
47fe8e0ea6 [maven-release-plugin] prepare for next development iteration 2020-04-23 22:19:33 +02:00
Tobias Warneke
ba4bd7ff03 [maven-release-plugin] prepare release java-diff-utils-parent-4.7 2020-04-23 22:19:31 +02:00
Tobias Warneke
ea8d442d28 fixes #75 2020-04-22 22:26:25 +02:00
Tobias Warneke
fbb51d28c7 2020-04-22 22:24:49 +02:00
Tobias Warneke
5781cc5178 2020-04-19 23:51:23 +02:00
Tobias Warneke
37310e1628 working on issue #75 2020-04-18 22:59:50 +02:00
Tobias
ccfc40234a Update CHANGELOG.md 2020-04-18 22:58:56 +02:00
Tobias Warneke
1e7d96e056 Merge origin/master 2020-04-18 22:32:34 +02:00
Tobias Warneke
f0fc883485 first try of implementing issue #42 2020-04-18 22:31:50 +02:00
Tobias
3bc40a14f3 Merge pull request #76 from sullis/junit-5.6.2
junit 5.6.2
2020-04-12 00:33:26 +02:00
Sean C. Sullivan
29de84cd96 junit 5.6.2 2020-04-10 16:35:57 -07:00
Tobias Warneke
11b3c53d2b fixes #52
fixes #53
2020-03-08 23:01:13 +01:00
Tobias Warneke
d34591ed13 removed diff exception 2020-03-07 00:36:15 +01:00
Tobias Warneke
89c9f94aef removed diff exception 2020-03-07 00:31:21 +01:00
Tobias Warneke
9a39411ee8 removed diff exception 2020-03-07 00:27:39 +01:00
Tobias Warneke
ae23408748 fixes #47 2020-02-23 23:51:28 +01:00
Tobias Warneke
923918a53e fixes #63 2020-02-23 23:16:39 +01:00
Tobias Warneke
21d2cbbcdd fixes #63 2020-02-23 23:13:39 +01:00
Tobias Warneke
fe6dbe243a fixes #63 2020-02-23 23:10:06 +01:00
Tobias Warneke
df01ef67e3 fixes #63 2020-02-23 23:07:02 +01:00
Tobias Warneke
dbd0b8f72e fixes #64 2020-02-20 00:53:35 +01:00
Tobias Warneke
e37a52395a fixes #66 2020-02-20 00:31:24 +01:00
Tobias Warneke
fb7fca643b fixes #69 2020-02-19 23:03:34 +01:00
Tobias Warneke
94ffdab46f included new file diff capability to new unified diff parser 2020-01-04 23:45:25 +01:00
Tobias Warneke
ca0959a0a1 included new file diff capability to new unified diff parser 2020-01-04 01:20:57 +01:00
Tobias Warneke
3b23656260 included new file diff capability to new unified diff parser 2020-01-04 01:18:22 +01:00
Tobias Warneke
39efdd5143 Merge origin/master 2019-12-25 23:36:15 +01:00
Tobias Warneke
7dec3fef40 fixes #47 2019-12-25 23:35:47 +01:00
Ibrahim ali abdelghany
81085d368c Extract duplicate code into method. (#58)
* Extract duplicate code into method.

* fix conflicts.
2019-11-18 16:29:31 +01:00
Oliver Kopp
15a5f060b3 Fix links in CHANGELOG.md (#61) 2019-11-18 11:11:53 +01:00
Oliver Kopp
93334b5da7 Update release version in README.md (#62) 2019-11-18 11:10:41 +01:00
Tobias Warneke
3c6fa5f4fe [maven-release-plugin] prepare for next development iteration 2019-11-17 22:07:32 +01:00
83 changed files with 62897 additions and 1042 deletions

10
.github/ISSUE_TEMPLATE/simple.md vendored Normal file
View File

@@ -0,0 +1,10 @@
---
name: Simple
about: just a simple issue
title: ''
labels: ''
assignees: ''
---

8
.github/release.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
changelog:
categories:
- title: Bugs solved
labels:
- "bug"
- title: Changes and new Features
labels:
- "*"

26
.github/workflows/maven.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
# This workflow will build a Java project with Maven
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: Java CI with Maven
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
java: [8, 11]
name: Java ${{ matrix.java }} building ...
steps:
- uses: actions/checkout@v2
- name: Set up Java ${{ matrix.java }}
uses: actions/setup-java@v1
with:
java-version: ${{ matrix.java }}
- name: Build with Maven
run: mvn -B package --file pom.xml

19
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Mark stale issues and pull requests
on:
schedule:
- cron: "30 1 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Stale issue message'
stale-pr-message: 'Stale pull request message'
stale-issue-label: 'no-issue-activity'
stale-pr-label: 'no-pr-activity'

2
.gitignore vendored
View File

@@ -2,3 +2,5 @@
build/
nbproject/
target/
*.iml

View File

@@ -5,7 +5,53 @@ 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]
## [unreleased]
### Changed
## [4.11]
### Changed
* bugfixing new UnifiedDiff reader
* header for each file
* skip empty lines
* introduction of Meyers Diff Algorithm with Linear Space improvment (until matured this will not be the default diff algorithm)
* introduction of DiffAlgorithmFactory to set the default diff algorithm DiffUtils use (`DiffUtils.withDefaultDiffAlgorithmFactory(MeyersDiffWithLinearSpace.factory());`)
## [4.10]
### Changed
* bugfixing on new UnifiedDiff reader / writer for multifile usage
* bugfix for wrong DiffRow type while transforming from a patch that removed a line in one changeset
* introduced change position into UnifiedDiff reader
* introduced first version of conflict output possibility (like GIT merge conflict)
* moved verification to `AbstractDelta`
* introduced `ConflictOutput` to `Patch` to add optional behaviour to patch conflicts
## [4.9]
### Changed
* make patch serializable
## [4.8]
### Changed
* some bugfixes regarding unified diff writer
* UnifiedDiffReader improved for **deleted file mode** and better timestamp recognition
* UnifiedDiffReader improved for **new file mode** and better timestamp recognition
## [4.7]
### Changed
* minor bug fixes
* optional include equal parts of original and revised data
* **API** change: removed DiffException completely
* added possibility to **process diffs** to for instance show whitespace characters
## [4.4] 2019-11-06
@@ -82,8 +128,10 @@ This project uses a custom versioning scheme (and not [Semantic Versioning](http
* 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
[Unreleased]: https://github.com/java-diff-utils/java-diff-utils/compare/java-diff-utils-parent-4.5...HEAD
[4.5]: https://github.com/java-diff-utils/java-diff-utils/compare/java-diff-utils-parent-4.4...java-diff-utils-parent-4.5
[4.4]: https://github.com/java-diff-utils/java-diff-utils/compare/java-diff-utils-4.0...java-diff-utils-parent-4.4
[4.0]: https://github.com/java-diff-utils/java-diff-utils/compare/diffutils-3.0...java-diff-utils-4.0
[3.0]: https://github.com/java-diff-utils/java-diff-utils/compare/diffutils-2.2...diffutils-3.0
[2.2]: https://github.com/java-diff-utils/java-diff-utils/compare/diffutils-2.0...diffutils-2.2

View File

@@ -3,7 +3,11 @@
## Status
[![Build Status](https://travis-ci.org/java-diff-utils/java-diff-utils.svg?branch=master)](https://travis-ci.org/java-diff-utils/java-diff-utils)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/7eba77f10bed4c2a8d08ac8dc8da4a86)](https://www.codacy.com/app/wumpz/java-diff-utils?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=java-diff-utils/java-diff-utils&amp;utm_campaign=Badge_Grade)
[![Build Status using Github Actions](https://github.com/java-diff-utils/java-diff-utils/workflows/Java%20CI%20with%20Maven/badge.svg)](https://github.com/java-diff-utils/java-diff-utils/actions?query=workflow%3A%22Java+CI+with+Maven%22)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/002c53aa0c924f71ac80a2f65446dfdd)](https://www.codacy.com/gh/java-diff-utils/java-diff-utils/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=java-diff-utils/java-diff-utils&amp;utm_campaign=Badge_Grade)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.github.java-diff-utils/java-diff-utils/badge.svg)](http://maven-badges.herokuapp.com/maven-central/io.github.java-diff-utils/java-diff-utils)
## Intro
@@ -14,9 +18,13 @@ Main reason to build this library was the lack of easy-to-use libraries with all
**This is originally a fork of java-diff-utils from Google Code Archive.**
## API
Javadocs of the actual release version: [JavaDocs java-diff-utils](https://java-diff-utils.github.io/java-diff-utils/4.7/docs/api/)
## Examples
Look [here](https://github.com/wumpz/java-diff-utils/wiki) to find more helpful informations and examples.
Look [here](https://github.com/java-diff-utils/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:
@@ -41,12 +49,13 @@ This is a test ~senctence~**for diffutils**.
* producing human-readable differences
* inline difference construction
* Algorithms:
* Myer
* Meyers Standard Algorithm
* Meyers with linear space improvement
* HistogramDiff using JGit Library
### Algorithms
* Myer's diff
* Meyer's diff
* 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.
@@ -80,7 +89,7 @@ Just add the code below to your maven dependencies:
<dependency>
<groupId>io.github.java-diff-utils</groupId>
<artifactId>java-diff-utils</artifactId>
<version>4.4</version>
<version>4.11</version>
</dependency>
```
@@ -88,5 +97,5 @@ or using gradle:
```groovy
// https://mvnrepository.com/artifact/io.github.java-diff-utils/java-diff-utils
implementation "io.github.java-diff-utils:java-diff-utils:4.4"
implementation "io.github.java-diff-utils:java-diff-utils:4.11"
```

View File

@@ -1 +0,0 @@
theme: jekyll-theme-minimal

View File

@@ -0,0 +1,18 @@
<?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>
</properties>
</project-shared-configuration>

View File

@@ -4,25 +4,23 @@
<parent>
<groupId>io.github.java-diff-utils</groupId>
<artifactId>java-diff-utils-parent</artifactId>
<version>4.5</version>
<version>4.12</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>
some difference algorithms.</description>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<type>jar</type>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>4.4.1.201607150455-r</version>
<version>5.8.1.202007141445-r</version>
<exclusions>
<exclusion>
<groupId>com.googlecode.javaewah</groupId>

View File

@@ -21,12 +21,9 @@ import com.github.difflib.patch.PatchFailedException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
/**
*
@@ -37,22 +34,6 @@ public class HistogramDiffTest {
public HistogramDiffTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
/**
* Test of diff method, of class HistogramDiff.
*/
@@ -60,7 +41,7 @@ public class HistogramDiffTest {
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));
final Patch<String> patch = Patch.generate(orgList, revList, new HistogramDiff<String>().computeDiff(orgList, revList, null));
System.out.println(patch);
assertNotNull(patch);
assertEquals(3, patch.getDeltas().size());
@@ -76,7 +57,7 @@ public class HistogramDiffTest {
List<String> revList = Arrays.asList("C", "B", "A", "B", "A", "C");
List<String> logdata = new ArrayList<>();
final Patch<String> patch = Patch.generate(orgList, revList, new HistogramDiff().computeDiff(orgList, revList, new DiffAlgorithmListener() {
final Patch<String> patch = Patch.generate(orgList, revList, new HistogramDiff<String>().computeDiff(orgList, revList, new DiffAlgorithmListener() {
@Override
public void diffStart() {
logdata.add("start");
@@ -101,6 +82,6 @@ public class HistogramDiffTest {
assertEquals(revList, patched);
System.out.println(logdata);
assertEquals(17, logdata.size());
assertEquals(19, logdata.size());
}
}

View File

@@ -28,12 +28,9 @@ 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;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
/**
*
@@ -41,25 +38,6 @@ import org.junit.Test;
*/
public class LRHistogramDiffTest {
public LRHistogramDiffTest() {
}
@BeforeClass
public static void setUpClass() {
}
@AfterClass
public static void tearDownClass() {
}
@Before
public void setUp() {
}
@After
public void tearDown() {
}
@Test
public void testPossibleDiffHangOnLargeDatasetDnaumenkoIssue26() throws IOException, PatchFailedException {
ZipFile zip = new ZipFile("target/test-classes/mocks/large_dataset1.zip");
@@ -67,7 +45,7 @@ public class LRHistogramDiffTest {
List<String> revised = readStringListFromInputStream(zip.getInputStream(zip.getEntry("tb")));
List<String> logdata = new ArrayList<>();
Patch<String> patch = Patch.generate(original, revised, new HistogramDiff().computeDiff(original, revised, new DiffAlgorithmListener() {
Patch<String> patch = Patch.generate(original, revised, new HistogramDiff<String>().computeDiff(original, revised, new DiffAlgorithmListener() {
@Override
public void diffStart() {
logdata.add("start");

View File

@@ -14,5 +14,6 @@ That way multiple projects can share the same settings (useful for formatting ru
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<netbeans.hint.jdkPlatform>JDK_1.8</netbeans.hint.jdkPlatform>
<netbeans.compile.on.save>none</netbeans.compile.on.save>
</properties>
</project-shared-configuration>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>io.github.java-diff-utils</groupId>
<artifactId>java-diff-utils-parent</artifactId>
<version>4.5</version>
<version>4.12</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -15,16 +15,13 @@
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<type>jar</type>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.11.1</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -54,6 +51,16 @@
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<trimStackTrace>false</trimStackTrace>
<systemPropertyVariables>
<java.util.logging.config.file>target/test-classes/logging.properties</java.util.logging.config.file>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -15,10 +15,10 @@
*/
package com.github.difflib;
import com.github.difflib.algorithm.DiffAlgorithmFactory;
import com.github.difflib.algorithm.DiffAlgorithmI;
import com.github.difflib.algorithm.DiffAlgorithmListener;
import com.github.difflib.algorithm.DiffException;
import com.github.difflib.algorithm.myers.MyersDiff;
import com.github.difflib.algorithm.myers.MeyersDiff;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.Patch;
import com.github.difflib.patch.PatchFailedException;
@@ -31,97 +31,124 @@ import java.util.function.BiPredicate;
/**
* Implements the difference and patching engine
*
* @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a>
*/
public final class DiffUtils {
/**
* Computes the difference between the original and revised list of elements with default diff algorithm
* This factory generates the DEFAULT_DIFF algorithm for all these routines.
*/
static DiffAlgorithmFactory DEFAULT_DIFF = MeyersDiff.factory();
public static void withDefaultDiffAlgorithmFactory(DiffAlgorithmFactory factory) {
DEFAULT_DIFF = factory;
}
/**
* Computes the difference between the original and revised list of elements
* with default diff algorithm
*
* @param <T> types to be diffed
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param progress progress listener
* @return The patch describing the difference between the original and revised sequences. Never {@code null}.
* @throws com.github.difflib.algorithm.DiffException
* @return The patch describing the difference between the original and
* revised sequences. Never {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmListener progress) throws DiffException {
return DiffUtils.diff(original, revised, new MyersDiff<>(), progress);
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmListener progress) {
return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), progress);
}
public static <T> Patch<T> diff(List<T> original, List<T> revised) throws DiffException {
return DiffUtils.diff(original, revised, new MyersDiff<>(), null);
public static <T> Patch<T> diff(List<T> original, List<T> revised) {
return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), null);
}
public static <T> Patch<T> diff(List<T> original, List<T> revised, boolean includeEqualParts) {
return DiffUtils.diff(original, revised, DEFAULT_DIFF.create(), null, includeEqualParts);
}
/**
* Computes the difference between the original and revised text.
*/
public static Patch<String> diff(String sourceText, String targetText,
DiffAlgorithmListener progress) throws DiffException {
DiffAlgorithmListener progress) {
return DiffUtils.diff(
Arrays.asList(sourceText.split("\n")),
Arrays.asList(targetText.split("\n")), progress);
Arrays.asList(sourceText.split("\n")),
Arrays.asList(targetText.split("\n")), progress);
}
/**
* Computes the difference between the original and revised list of elements with default diff algorithm
* Computes the difference between the original and revised list of elements
* with default diff algorithm
*
* @param source The original text. Must not be {@code null}.
* @param target The revised text. Must not be {@code null}.
*
* @param equalizer the equalizer object to replace the default compare algorithm (Object.equals). If {@code null}
* the default equalizer of the default algorithm is used..
* @return The patch describing the difference between the original and revised sequences. Never {@code null}.
* @param equalizer the equalizer object to replace the default compare
* algorithm (Object.equals). If {@code null} the default equalizer of the
* default algorithm is used..
* @return The patch describing the difference between the original and
* revised sequences. Never {@code null}.
*/
public static <T> Patch<T> diff(List<T> source, List<T> target,
BiPredicate<T, T> equalizer) throws DiffException {
BiPredicate<T, T> equalizer) {
if (equalizer != null) {
return DiffUtils.diff(source, target,
new MyersDiff<>(equalizer));
DEFAULT_DIFF.create(equalizer));
}
return DiffUtils.diff(source, target, new MyersDiff<>());
return DiffUtils.diff(source, target, new MeyersDiff<>());
}
public static <T> Patch<T> diff(List<T> original, List<T> revised,
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress) {
return diff(original, revised, algorithm, progress, false);
}
/**
* Computes the difference between the original and revised list of elements with default diff algorithm
* Computes the difference between the original and revised list of elements
* with default diff algorithm
*
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param algorithm The diff algorithm. Must not be {@code null}.
* @param progress The diff algorithm listener.
* @return The patch describing the difference between the original and revised sequences. Never {@code null}.
* @param includeEqualParts Include equal data parts into the patch.
* @return The patch describing the difference between the original and
* revised sequences. Never {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised,
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress) throws DiffException {
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress,
boolean includeEqualParts) {
Objects.requireNonNull(original, "original must not be null");
Objects.requireNonNull(revised, "revised must not be null");
Objects.requireNonNull(algorithm, "algorithm must not be null");
return Patch.generate(original, revised, algorithm.computeDiff(original, revised, progress));
return Patch.generate(original, revised, algorithm.computeDiff(original, revised, progress), includeEqualParts);
}
/**
* Computes the difference between the original and revised list of elements with default diff algorithm
* Computes the difference between the original and revised list of elements
* with default diff algorithm
*
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param algorithm The diff algorithm. Must not be {@code null}.
* @return The patch describing the difference between the original and revised sequences. Never {@code null}.
* @return The patch describing the difference between the original and
* revised sequences. Never {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised,
DiffAlgorithmI<T> algorithm) throws DiffException {
return diff(original, revised, algorithm, null);
}
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmI<T> algorithm) {
return diff(original, revised, algorithm, null);
}
/**
* Computes the difference between the given texts inline. This one uses the "trick" to make out of texts lists of
* characters, like DiffRowGenerator does and merges those changes at the end together again.
* Computes the difference between the given texts inline. This one uses the
* "trick" to make out of texts lists of characters, like DiffRowGenerator
* does and merges those changes at the end together again.
*
* @param original
* @param revised
* @return
*/
public static Patch<String> diffInline(String original, String revised) throws DiffException {
public static Patch<String> diffInline(String original, String revised) {
List<String> origList = new ArrayList<>();
List<String> revList = new ArrayList<>();
for (Character character : original.toCharArray()) {

View File

@@ -21,6 +21,7 @@ import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.Patch;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -32,6 +33,7 @@ public final class UnifiedDiffUtils {
private static final Pattern UNIFIED_DIFF_CHUNK_REGEXP = Pattern
.compile("^@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@$");
private static final String NULL_FILE_INDICATOR = "/dev/null";
/**
* Parse the given text in unified format and creates the list of deltas for it.
@@ -59,25 +61,7 @@ public final class UnifiedDiffUtils {
Matcher m = UNIFIED_DIFF_CHUNK_REGEXP.matcher(line);
if (m.find()) {
// Process the lines in the previous chunk
if (!rawChunk.isEmpty()) {
List<String> oldChunkLines = new ArrayList<>();
List<String> newChunkLines = new ArrayList<>();
for (String[] raw_line : rawChunk) {
tag = raw_line[0];
rest = raw_line[1];
if (" ".equals(tag) || "-".equals(tag)) {
oldChunkLines.add(rest);
}
if (" ".equals(tag) || "+".equals(tag)) {
newChunkLines.add(rest);
}
}
patch.addDelta(new ChangeDelta<>(new Chunk<>(
old_ln - 1, oldChunkLines), new Chunk<>(
new_ln - 1, newChunkLines)));
rawChunk.clear();
}
processLinesInPrevChunk(rawChunk, patch, old_ln, new_ln);
// Parse the @@ header
old_ln = m.group(1) == null ? 1 : Integer.parseInt(m.group(1));
new_ln = m.group(3) == null ? 1 : Integer.parseInt(m.group(3));
@@ -102,33 +86,50 @@ public final class UnifiedDiffUtils {
}
// Process the lines in the last chunk
if (!rawChunk.isEmpty()) {
List<String> oldChunkLines = new ArrayList<>();
List<String> newChunkLines = new ArrayList<>();
for (String[] raw_line : rawChunk) {
tag = raw_line[0];
rest = raw_line[1];
if (" ".equals(tag) || "-".equals(tag)) {
oldChunkLines.add(rest);
}
if (" ".equals(tag) || "+".equals(tag)) {
newChunkLines.add(rest);
}
}
patch.addDelta(new ChangeDelta<>(new Chunk<>(
old_ln - 1, oldChunkLines), new Chunk<>(new_ln - 1,
newChunkLines)));
rawChunk.clear();
}
processLinesInPrevChunk(rawChunk, patch, old_ln, new_ln);
return patch;
}
private static void processLinesInPrevChunk(List<String[]> rawChunk, Patch<String> patch, int old_ln, int new_ln) {
String tag;
String rest;
if (!rawChunk.isEmpty()) {
List<String> oldChunkLines = new ArrayList<>();
List<String> newChunkLines = new ArrayList<>();
List<Integer> removePosition = new ArrayList<>();
List<Integer> addPosition = new ArrayList<>();
int removeNum = 0;
int addNum = 0;
for (String[] raw_line : rawChunk) {
tag = raw_line[0];
rest = raw_line[1];
if (" ".equals(tag) || "-".equals(tag)) {
removeNum++;
oldChunkLines.add(rest);
if ("-".equals(tag)) {
removePosition.add(old_ln - 1 + removeNum);
}
}
if (" ".equals(tag) || "+".equals(tag)) {
addNum++;
newChunkLines.add(rest);
if ("+".equals(tag)) {
addPosition.add(new_ln - 1 + addNum);
}
}
}
patch.addDelta(new ChangeDelta<>(new Chunk<>(
old_ln - 1, oldChunkLines, removePosition), new Chunk<>(
new_ln - 1, newChunkLines, addPosition)));
rawChunk.clear();
}
}
/**
* generateUnifiedDiff takes a Patch and some other arguments, returning the Unified Diff format text representing
* the Patch.
* generateUnifiedDiff takes a Patch and some other arguments, returning the Unified Diff format
* text representing the Patch. Author: Bill James (tankerbay@gmail.com).
*
* @param originalFileName - Filename of the original (unrevised file)
* @param revisedFileName - Filename of the revised file
@@ -136,15 +137,14 @@ public final class UnifiedDiffUtils {
* @param patch - Patch created by the diff() function
* @param contextSize - number of lines of context output around each difference in the file.
* @return List of strings representing the Unified Diff representation of the Patch argument.
* @author Bill James (tankerbay@gmail.com)
*/
public static List<String> generateUnifiedDiff(String originalFileName,
String revisedFileName, List<String> originalLines, Patch<String> patch,
int contextSize) {
if (!patch.getDeltas().isEmpty()) {
List<String> ret = new ArrayList<>();
ret.add("--- " + originalFileName);
ret.add("+++ " + revisedFileName);
ret.add("--- " + Optional.ofNullable(originalFileName).orElse(NULL_FILE_INDICATOR));
ret.add("+++ " + Optional.ofNullable(revisedFileName).orElse(NULL_FILE_INDICATOR));
List<AbstractDelta<String>> patchDeltas = new ArrayList<>(
patch.getDeltas());
@@ -179,7 +179,7 @@ public final class UnifiedDiffUtils {
// then create a new set and add the current Delta to
// it.
List<String> curBlock = processDeltas(originalLines,
deltas, contextSize);
deltas, contextSize, false);
ret.addAll(curBlock);
deltas.clear();
deltas.add(nextDelta);
@@ -190,7 +190,7 @@ public final class UnifiedDiffUtils {
}
// don't forget to process the last set of Deltas
List<String> curBlock = processDeltas(originalLines, deltas,
contextSize);
contextSize, patchDeltas.size() == 1 && originalFileName == null);
ret.addAll(curBlock);
return ret;
}
@@ -198,27 +198,31 @@ public final class UnifiedDiffUtils {
}
/**
* processDeltas takes a list of Deltas and outputs them together in a single block of Unified-Diff-format text.
* processDeltas takes a list of Deltas and outputs them together in a single block of
* Unified-Diff-format text. Author: Bill James (tankerbay@gmail.com).
*
* @param origLines - the lines of the original file
* @param deltas - the Deltas to be output as a single block
* @param contextSize - the number of lines of context to place around block
* @return
* @author Bill James (tankerbay@gmail.com)
*/
private static List<String> processDeltas(List<String> origLines,
List<AbstractDelta<String>> deltas, int contextSize) {
List<AbstractDelta<String>> deltas, int contextSize, boolean newFile) {
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 origStart;
if (newFile) {
origStart = 0;
} else {
// NOTE: +1 to overcome the 0-offset Position
origStart = curDelta.getSource().getPosition() + 1 - contextSize;
if (origStart < 1) {
origStart = 1;
}
}
int revStart = curDelta.getTarget().getPosition() + 1 - contextSize;
@@ -291,11 +295,10 @@ public final class UnifiedDiffUtils {
}
/**
* getDeltaText returns the lines to be added to the Unified Diff text from the Delta parameter
* getDeltaText returns the lines to be added to the Unified Diff text from the Delta parameter. Author: Bill James (tankerbay@gmail.com).
*
* @param delta - the Delta to output
* @return list of String lines of code.
* @author Bill James (tankerbay@gmail.com)
*/
private static List<String> getDeltaText(AbstractDelta<String> delta) {
List<String> buffer = new ArrayList<>();

View File

@@ -36,4 +36,12 @@ public class Change {
this.startRevised = startRevised;
this.endRevised = endRevised;
}
public Change withEndOriginal(int endOriginal) {
return new Change(deltaType, startOriginal, endOriginal, startRevised, endRevised);
}
public Change withEndRevised(int endRevised) {
return new Change(deltaType, startOriginal, endOriginal, startRevised, endRevised);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2009-2017 java-diff-utils.
* Copyright 2021 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,20 +15,15 @@
*/
package com.github.difflib.algorithm;
import java.util.function.BiPredicate;
/**
* Thrown whenever the differencing engine cannot produce the differences between two revisions of ta text.
*
* @see com.github.difflib.algorithm.myers.MyersDiff
* @see DiffAlgorithmI
* Tool to create new instances of a diff algorithm. This one is only needed at the moment to
* set DiffUtils default diff algorithm.
* @author tw
*/
public class DifferentiationFailedException extends DiffException {
private static final long serialVersionUID = 1L;
public DifferentiationFailedException() {
}
public DifferentiationFailedException(String msg) {
super(msg);
}
public interface DiffAlgorithmFactory {
<T> DiffAlgorithmI<T> create();
<T> DiffAlgorithmI<T> create(BiPredicate<T, T> equalizer);
}

View File

@@ -22,6 +22,7 @@ import java.util.List;
* Interface of a diff algorithm.
*
* @author Tobias Warneke (t.warneke@gmx.net)
* @param <T> type of data that is diffed.
*/
public interface DiffAlgorithmI<T> {
@@ -32,9 +33,8 @@ public interface DiffAlgorithmI<T> {
* @param target target data
* @param progress progress listener
* @return
* @throws DiffException
*/
List<Change> computeDiff(List<T> source, List<T> target, DiffAlgorithmListener progress) throws DiffException;
List<Change> computeDiff(List<T> source, List<T> target, DiffAlgorithmListener progress);
/**
* Simple extension to compute a changeset using arrays.
@@ -43,9 +43,8 @@ public interface DiffAlgorithmI<T> {
* @param target
* @param progress
* @return
* @throws com.github.difflib.algorithm.DiffException
*/
default List<Change> computeDiff(T[] source, T[] target, DiffAlgorithmListener progress) throws DiffException {
default List<Change> computeDiff(T[] source, T[] target, DiffAlgorithmListener progress) {
return computeDiff(Arrays.asList(source), Arrays.asList(target), progress);
}
}

View File

@@ -16,10 +16,9 @@
package com.github.difflib.algorithm.myers;
import com.github.difflib.algorithm.Change;
import com.github.difflib.algorithm.DiffAlgorithmFactory;
import com.github.difflib.algorithm.DiffAlgorithmI;
import com.github.difflib.algorithm.DiffAlgorithmListener;
import com.github.difflib.algorithm.DiffException;
import com.github.difflib.algorithm.DifferentiationFailedException;
import com.github.difflib.patch.DeltaType;
import com.github.difflib.patch.Patch;
import java.util.ArrayList;
@@ -28,18 +27,17 @@ import java.util.Objects;
import java.util.function.BiPredicate;
/**
* A clean-room implementation of Eugene Myers greedy differencing algorithm.
* A clean-room implementation of Eugene Meyers greedy differencing algorithm.
*/
public final class MyersDiff<T> implements DiffAlgorithmI<T> {
public final class MeyersDiff<T> implements DiffAlgorithmI<T> {
private final BiPredicate<T, T> DEFAULT_EQUALIZER = Object::equals;
private final BiPredicate<T, T> equalizer;
public MyersDiff() {
equalizer = DEFAULT_EQUALIZER;
public MeyersDiff() {
equalizer = Object::equals;
}
public MyersDiff(final BiPredicate<T, T> equalizer) {
public MeyersDiff(final BiPredicate<T, T> equalizer) {
Objects.requireNonNull(equalizer, "equalizer must not be null");
this.equalizer = equalizer;
}
@@ -50,7 +48,7 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> {
* Return empty diff if get the error while procession the difference.
*/
@Override
public List<Change> computeDiff(final List<T> source, final List<T> target, DiffAlgorithmListener progress) throws DiffException {
public List<Change> computeDiff(final List<T> source, final List<T> target, DiffAlgorithmListener progress) {
Objects.requireNonNull(source, "source list must not be null");
Objects.requireNonNull(target, "target list must not be null");
@@ -66,16 +64,16 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> {
}
/**
* Computes the minimum diffpath that expresses de differences between the original and revised
* sequences, according to Gene Myers differencing algorithm.
* Computes the minimum diffpath that expresses de differences between the
* original and revised sequences, according to Gene Myers differencing
* algorithm.
*
* @param orig The original sequence.
* @param rev The revised sequence.
* @return A minimum {@link PathNode Path} accross the differences graph.
* @throws DifferentiationFailedException if a diff path could not be found.
*/
private PathNode buildPath(final List<T> orig, final List<T> rev, DiffAlgorithmListener progress)
throws DifferentiationFailedException {
private PathNode buildPath(final List<T> orig, final List<T> rev, DiffAlgorithmListener progress) {
Objects.requireNonNull(orig, "original sequence is null");
Objects.requireNonNull(rev, "revised sequence is null");
@@ -132,7 +130,7 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> {
diagonal[middle + d - 1] = null;
}
// According to Myers, this cannot happen
throw new DifferentiationFailedException("could not find a diff path");
throw new IllegalStateException("could not find a diff path");
}
/**
@@ -142,8 +140,8 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> {
* @param orig The original sequence.
* @param rev The revised sequence.
* @return A {@link Patch} script corresponding to the path.
* @throws DifferentiationFailedException if a {@link Patch} could not be built from the given
* path.
* @throws DifferentiationFailedException if a {@link Patch} could not be
* built from the given path.
*/
private List<Change> buildRevision(PathNode actualPath, List<T> orig, List<T> rev) {
Objects.requireNonNull(actualPath, "path is null");
@@ -180,4 +178,23 @@ public final class MyersDiff<T> implements DiffAlgorithmI<T> {
}
return changes;
}
/**
* Factory to create instances of this specific diff algorithm.
*/
public static DiffAlgorithmFactory factory() {
return new DiffAlgorithmFactory() {
@Override
public <T> DiffAlgorithmI<T>
create() {
return new MeyersDiff<T>();
}
@Override
public <T> DiffAlgorithmI<T>
create(BiPredicate < T, T > equalizer) {
return new MeyersDiff<T>(equalizer);
}
};
}
}

View File

@@ -0,0 +1,244 @@
/*
* Copyright 2021 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.difflib.algorithm.myers;
import com.github.difflib.algorithm.Change;
import com.github.difflib.algorithm.DiffAlgorithmFactory;
import com.github.difflib.algorithm.DiffAlgorithmI;
import com.github.difflib.algorithm.DiffAlgorithmListener;
import com.github.difflib.patch.DeltaType;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
/**
*
* @author tw
*/
public class MeyersDiffWithLinearSpace<T> implements DiffAlgorithmI<T> {
private final BiPredicate<T, T> equalizer;
public MeyersDiffWithLinearSpace() {
equalizer = Object::equals;
}
public MeyersDiffWithLinearSpace(final BiPredicate<T, T> equalizer) {
Objects.requireNonNull(equalizer, "equalizer must not be null");
this.equalizer = equalizer;
}
@Override
public List<Change> computeDiff(List<T> source, List<T> target, DiffAlgorithmListener progress) {
Objects.requireNonNull(source, "source list must not be null");
Objects.requireNonNull(target, "target list must not be null");
if (progress != null) {
progress.diffStart();
}
DiffData data = new DiffData(source, target);
int maxIdx = source.size() + target.size();
buildScript(data, 0, source.size(), 0, target.size(), idx -> {
if (progress != null) {
progress.diffStep(idx, maxIdx);
}
});
if (progress != null) {
progress.diffEnd();
}
return data.script;
}
private void buildScript(DiffData data, int start1, int end1, int start2, int end2, Consumer<Integer> progress) {
if (progress != null) {
progress.accept((end1 - start1) / 2 + (end2 - start2) / 2);
}
final Snake middle = getMiddleSnake(data, start1, end1, start2, end2);
if (middle == null
|| middle.start == end1 && middle.diag == end1 - end2
|| middle.end == start1 && middle.diag == start1 - start2) {
int i = start1;
int j = start2;
while (i < end1 || j < end2) {
if (i < end1 && j < end2 && equalizer.test(data.source.get(i), data.target.get(j))) {
//script.append(new KeepCommand<>(left.charAt(i)));
++i;
++j;
} else {
//TODO: compress these commands.
if (end1 - start1 > end2 - start2) {
//script.append(new DeleteCommand<>(left.charAt(i)));
if (data.script.isEmpty()
|| data.script.get(data.script.size() - 1).endOriginal != i
|| data.script.get(data.script.size() - 1).deltaType != DeltaType.DELETE) {
data.script.add(new Change(DeltaType.DELETE, i, i + 1, j, j));
} else {
data.script.set(data.script.size() - 1, data.script.get(data.script.size() - 1).withEndOriginal(i + 1));
}
++i;
} else {
if (data.script.isEmpty()
|| data.script.get(data.script.size() - 1).endRevised != j
|| data.script.get(data.script.size() - 1).deltaType != DeltaType.INSERT) {
data.script.add(new Change(DeltaType.INSERT, i, i, j, j + 1));
} else {
data.script.set(data.script.size() - 1, data.script.get(data.script.size() - 1).withEndRevised(j + 1));
}
++j;
}
}
}
} else {
buildScript(data, start1, middle.start, start2, middle.start - middle.diag, progress);
buildScript(data, middle.end, end1, middle.end - middle.diag, end2, progress);
}
}
private Snake getMiddleSnake(DiffData data, int start1, int end1, int start2, int end2) {
final int m = end1 - start1;
final int n = end2 - start2;
if (m == 0 || n == 0) {
return null;
}
final int delta = m - n;
final int sum = n + m;
final int offset = (sum % 2 == 0 ? sum : sum + 1) / 2;
data.vDown[1 + offset] = start1;
data.vUp[1 + offset] = end1 + 1;
for (int d = 0; d <= offset; ++d) {
// Down
for (int k = -d; k <= d; k += 2) {
// First step
final int i = k + offset;
if (k == -d || k != d && data.vDown[i - 1] < data.vDown[i + 1]) {
data.vDown[i] = data.vDown[i + 1];
} else {
data.vDown[i] = data.vDown[i - 1] + 1;
}
int x = data.vDown[i];
int y = x - start1 + start2 - k;
while (x < end1 && y < end2 && equalizer.test(data.source.get(x), data.target.get(y))) {
data.vDown[i] = ++x;
++y;
}
// Second step
if (delta % 2 != 0 && delta - d <= k && k <= delta + d) {
if (data.vUp[i - delta] <= data.vDown[i]) {
return buildSnake(data, data.vUp[i - delta], k + start1 - start2, end1, end2);
}
}
}
// Up
for (int k = delta - d; k <= delta + d; k += 2) {
// First step
final int i = k + offset - delta;
if (k == delta - d
|| k != delta + d && data.vUp[i + 1] <= data.vUp[i - 1]) {
data.vUp[i] = data.vUp[i + 1] - 1;
} else {
data.vUp[i] = data.vUp[i - 1];
}
int x = data.vUp[i] - 1;
int y = x - start1 + start2 - k;
while (x >= start1 && y >= start2 && equalizer.test(data.source.get(x), data.target.get(y))) {
data.vUp[i] = x--;
y--;
}
// Second step
if (delta % 2 == 0 && -d <= k && k <= d) {
if (data.vUp[i] <= data.vDown[i + delta]) {
return buildSnake(data, data.vUp[i], k + start1 - start2, end1, end2);
}
}
}
}
// According to Myers, this cannot happen
throw new IllegalStateException("could not find a diff path");
}
private Snake buildSnake(DiffData data, final int start, final int diag, final int end1, final int end2) {
int end = start;
while (end - diag < end2 && end < end1 && equalizer.test(data.source.get(end), data.target.get(end - diag))) {
++end;
}
return new Snake(start, end, diag);
}
private class DiffData {
final int size;
final int[] vDown;
final int[] vUp;
final List<Change> script;
final List<T> source;
final List<T> target;
public DiffData(List<T> source, List<T> target) {
this.source = source;
this.target = target;
size = source.size() + target.size() + 2;
vDown = new int[size];
vUp = new int[size];
script = new ArrayList<>();
}
}
private class Snake {
final int start;
final int end;
final int diag;
public Snake(final int start, final int end, final int diag) {
this.start = start;
this.end = end;
this.diag = diag;
}
}
/**
* Factory to create instances of this specific diff algorithm.
*/
public static DiffAlgorithmFactory factory() {
return new DiffAlgorithmFactory() {
@Override
public <T> DiffAlgorithmI<T>
create() {
return new MeyersDiffWithLinearSpace<T>();
}
@Override
public <T> DiffAlgorithmI<T>
create(BiPredicate < T, T > equalizer) {
return new MeyersDiffWithLinearSpace<T>(equalizer);
}
};
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.github.difflib.patch;
import java.io.Serializable;
import java.util.List;
import java.util.Objects;
@@ -22,7 +23,7 @@ import java.util.Objects;
* Abstract delta between a source and a target.
* @author Tobias Warneke (t.warneke@gmx.net)
*/
public abstract class AbstractDelta<T> {
public abstract class AbstractDelta<T> implements Serializable {
private final Chunk<T> source;
private final Chunk<T> target;
private final DeltaType type;
@@ -53,13 +54,39 @@ public abstract class AbstractDelta<T> {
* @param target
* @throws PatchFailedException
*/
protected void verifyChunk(List<T> target) throws PatchFailedException {
getSource().verify(target);
protected VerifyChunk verifyChunkToFitTarget(List<T> target) throws PatchFailedException {
return getSource().verifyChunk(target);
}
protected VerifyChunk verifyAntApplyTo(List<T> target) throws PatchFailedException {
final VerifyChunk verify = verifyChunkToFitTarget(target);
if (verify == VerifyChunk.OK) {
applyTo(target);
}
return verify;
}
public abstract void applyTo(List<T> target) throws PatchFailedException;
protected abstract void applyTo(List<T> target) throws PatchFailedException;
public abstract void restore(List<T> target);
protected abstract void restore(List<T> target);
/**
* Apply patch fuzzy.
*
* @param target the list this patch will be applied to
* @param fuzz the number of elements to ignore before/after the patched elements
* @param position the position this patch will be applied to. ignores {@code source.getPosition()}
* @see <a href="https://www.gnu.org/software/diffutils/manual/html_node/Inexact.html">Description of Fuzzy Patch</a> for more information.
*/
@SuppressWarnings("RedundantThrows")
protected void applyFuzzyToAt(List<T> target, int fuzz, int position) throws PatchFailedException {
throw new UnsupportedOperationException(this.getClass().getSimpleName() + " does not supports applying patch fuzzy");
}
/**
* Create a new delta of the actual instance with customized chunk data.
*/
public abstract AbstractDelta<T> withChunks(Chunk<T> original, Chunk<T> revised);
@Override
public int hashCode() {
@@ -84,9 +111,6 @@ public abstract class AbstractDelta<T> {
if (!Objects.equals(this.target, other.target)) {
return false;
}
if (this.type != other.type) {
return false;
}
return true;
return this.type == other.type;
}
}

View File

@@ -39,8 +39,7 @@ public final class ChangeDelta<T> extends AbstractDelta<T> {
}
@Override
public void applyTo(List<T> target) throws PatchFailedException {
verifyChunk(target);
protected void applyTo(List<T> target) throws PatchFailedException {
int position = getSource().getPosition();
int size = getSource().size();
for (int i = 0; i < size; i++) {
@@ -54,7 +53,7 @@ public final class ChangeDelta<T> extends AbstractDelta<T> {
}
@Override
public void restore(List<T> target) {
protected void restore(List<T> target) {
int position = getTarget().getPosition();
int size = getTarget().size();
for (int i = 0; i < size; i++) {
@@ -67,9 +66,27 @@ public final class ChangeDelta<T> extends AbstractDelta<T> {
}
}
protected void applyFuzzyToAt(List<T> target, int fuzz, int position) throws PatchFailedException {
int size = getSource().size();
for (int i = fuzz; i < size - fuzz; i++) {
target.remove(position + fuzz);
}
int i = fuzz;
for (T line : getTarget().getLines().subList(fuzz, getTarget().size() - fuzz)) {
target.add(position + i, line);
i++;
}
}
@Override
public String toString() {
return "[ChangeDelta, position: " + getSource().getPosition() + ", lines: "
+ getSource().getLines() + " to " + getTarget().getLines() + "]";
}
@Override
public AbstractDelta<T> withChunks(Chunk<T> original, Chunk<T> revised) {
return new ChangeDelta<T>(original, revised);
}
}

View File

@@ -15,6 +15,7 @@
*/
package com.github.difflib.patch;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -24,19 +25,34 @@ 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'.
*/
public final class Chunk<T> {
public final class Chunk<T> implements Serializable {
private final int position;
private List<T> lines;
private final List<Integer> changePosition;
/**
* Creates a chunk and saves a copy of affected lines
*
* @param position the start position
* @param lines the affected lines
* @param changePosition the positions of changed lines
*/
public Chunk(int position, List<T> lines, List<Integer> changePosition) {
this.position = position;
this.lines = new ArrayList<>(lines);
this.changePosition = changePosition != null ? new ArrayList<>(changePosition) : null;
}
/**
* Creates a chunk and saves a copy of affected lines
@@ -45,8 +61,20 @@ public final class Chunk<T> {
* @param lines the affected lines
*/
public Chunk(int position, List<T> lines) {
this(position, lines, null);
}
/**
* Creates a chunk and saves a copy of affected lines
*
* @param position the start position
* @param lines the affected lines
* @param changePosition the positions of changed lines
*/
public Chunk(int position, T[] lines, List<Integer> changePosition) {
this.position = position;
this.lines = new ArrayList<>(lines);
this.lines = Arrays.asList(lines);
this.changePosition = changePosition != null ? new ArrayList<>(changePosition) : null;
}
/**
@@ -56,26 +84,44 @@ public final class Chunk<T> {
* @param lines the affected lines
*/
public Chunk(int position, T[] lines) {
this.position = position;
this.lines = Arrays.asList(lines);
this(position, lines, null);
}
/**
* Verifies that this chunk's saved text matches the corresponding text in the given sequence.
* Verifies that this chunk's saved text matches the corresponding text in
* the given sequence.
*
* @param target the sequence to verify against.
* @throws com.github.difflib.patch.PatchFailedException
*/
public void verify(List<T> target) throws PatchFailedException {
if (position > target.size() || last() > target.size()) {
throw new PatchFailedException("Incorrect Chunk: the position of chunk > target size");
public VerifyChunk verifyChunk(List<T> target) throws PatchFailedException {
return verifyChunk(target, 0, getPosition());
}
/**
* Verifies that this chunk's saved text matches the corresponding text in
* the given sequence.
*
* @param target the sequence to verify against.
* @param fuzz the count of ignored prefix/suffix
* @param position the position of target
* @throws com.github.difflib.patch.PatchFailedException
*/
public VerifyChunk verifyChunk(List<T> target, int fuzz, int position) throws PatchFailedException {
//noinspection UnnecessaryLocalVariable
int startIndex = fuzz;
int lastIndex = size() - fuzz;
int last = position + size() - 1;
if (position + fuzz > target.size() || last - fuzz > target.size()) {
return VerifyChunk.POSITION_OUT_OF_TARGET;
}
for (int i = 0; i < size(); i++) {
for (int i = startIndex; i < lastIndex; i++) {
if (!target.get(position + i).equals(lines.get(i))) {
throw new PatchFailedException(
"Incorrect Chunk: the chunk content doesn't match the target");
return VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET;
}
}
return VerifyChunk.OK;
}
/**
@@ -96,6 +142,13 @@ public final class Chunk<T> {
return lines;
}
/**
* @return the positions of changed lines of chunk in the text
*/
public List<Integer> getChangePosition() {
return changePosition;
}
public int size() {
return lines.size();
}
@@ -123,7 +176,7 @@ public final class Chunk<T> {
if (getClass() != obj.getClass()) {
return false;
}
Chunk<T> other = (Chunk) obj;
Chunk<?> other = (Chunk<?>) obj;
if (lines == null) {
if (other.lines != null) {
return false;

View File

@@ -0,0 +1,33 @@
/*-
* #%L
* java-diff-utils
* %%
* Copyright (C) 2009 - 2017 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.
* #L%
*/
package com.github.difflib.patch;
import java.io.Serializable;
import java.util.List;
/**
*
* @author tw
*/
@FunctionalInterface
public interface ConflictOutput<T> extends Serializable {
public void processConflict(VerifyChunk verifyChunk, AbstractDelta<T> delta, List<T> result) throws PatchFailedException;
}

View File

@@ -36,8 +36,7 @@ public final class DeleteDelta<T> extends AbstractDelta<T> {
}
@Override
public void applyTo(List<T> target) throws PatchFailedException {
verifyChunk(target);
protected void applyTo(List<T> target) throws PatchFailedException {
int position = getSource().getPosition();
int size = getSource().size();
for (int i = 0; i < size; i++) {
@@ -46,7 +45,7 @@ public final class DeleteDelta<T> extends AbstractDelta<T> {
}
@Override
public void restore(List<T> target) {
protected void restore(List<T> target) {
int position = this.getTarget().getPosition();
List<T> lines = this.getSource().getLines();
for (int i = 0; i < lines.size(); i++) {
@@ -59,4 +58,9 @@ public final class DeleteDelta<T> extends AbstractDelta<T> {
return "[DeleteDelta, position: " + getSource().getPosition() + ", lines: "
+ getSource().getLines() + "]";
}
@Override
public AbstractDelta<T> withChunks(Chunk<T> original, Chunk<T> revised) {
return new DeleteDelta<T>(original, revised);
}
}

View File

@@ -16,7 +16,18 @@
package com.github.difflib.patch;
/**
* Specifies the type of the delta.
* Specifies the type of the delta. There are three types of modifications from
* the original to get the revised text.
*
* CHANGE: a block of data of the original is replaced by another block of data.
* DELETE: a block of data of the original is removed
* INSERT: at a position of the original a block of data is inserted
*
* to be complete there is also
*
* EQUAL: a block of data of original and the revised text is equal
*
* which is no change at all.
*
*/
public enum DeltaType {

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2020 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.difflib.patch;
import java.util.List;
/**
* This delta contains equal lines of data. Therefore nothing is to do in applyTo and restore.
* @author tobens
*/
public class EqualDelta<T> extends AbstractDelta<T> {
public EqualDelta(Chunk<T> source, Chunk<T> target) {
super(DeltaType.EQUAL, source, target);
}
@Override
protected void applyTo(List<T> target) throws PatchFailedException {
}
@Override
protected void restore(List<T> target) {
}
/**
* {@inheritDoc}
*/
@Override
protected void applyFuzzyToAt(List<T> target, int fuzz, int delta) {
// equals so no operations
}
@Override
public String toString() {
return "[EqualDelta, position: " + getSource().getPosition() + ", lines: "
+ getSource().getLines() + "]";
}
@Override
public AbstractDelta<T> withChunks(Chunk<T> original, Chunk<T> revised) {
return new EqualDelta<T>(original, revised);
}
}

View File

@@ -36,8 +36,7 @@ public final class InsertDelta<T> extends AbstractDelta<T> {
}
@Override
public void applyTo(List<T> target) throws PatchFailedException {
verifyChunk(target);
protected void applyTo(List<T> target) throws PatchFailedException {
int position = this.getSource().getPosition();
List<T> lines = this.getTarget().getLines();
for (int i = 0; i < lines.size(); i++) {
@@ -46,7 +45,7 @@ public final class InsertDelta<T> extends AbstractDelta<T> {
}
@Override
public void restore(List<T> target) {
protected void restore(List<T> target) {
int position = getTarget().getPosition();
int size = getTarget().size();
for (int i = 0; i < size; i++) {
@@ -59,4 +58,9 @@ public final class InsertDelta<T> extends AbstractDelta<T> {
return "[InsertDelta, position: " + getSource().getPosition()
+ ", lines: " + getTarget().getLines() + "]";
}
@Override
public AbstractDelta<T> withChunks(Chunk<T> original, Chunk<T> revised) {
return new InsertDelta<T>(original, revised);
}
}

View File

@@ -21,17 +21,21 @@ package com.github.difflib.patch;
import static java.util.Comparator.comparing;
import com.github.difflib.algorithm.Change;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
/**
* Describes the patch holding all deltas between the original and revised texts.
* 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'.
*/
public final class Patch<T> {
public final class Patch<T> implements Serializable {
private final List<AbstractDelta<T>> deltas;
@@ -54,11 +58,167 @@ public final class Patch<T> {
ListIterator<AbstractDelta<T>> it = getDeltas().listIterator(deltas.size());
while (it.hasPrevious()) {
AbstractDelta<T> delta = it.previous();
delta.applyTo(result);
VerifyChunk valid = delta.verifyAntApplyTo(result);
if (valid != VerifyChunk.OK) {
conflictOutput.processConflict(valid, delta, result);
}
}
return result;
}
private static class PatchApplyingContext<T> {
public final List<T> result;
public final int maxFuzz;
// the position last patch applied to.
public int lastPatchEnd = -1;
///// passing values from find to apply
public int currentFuzz = 0;
public int defaultPosition;
public boolean beforeOutRange = false;
public boolean afterOutRange = false;
private PatchApplyingContext(List<T> result, int maxFuzz) {
this.result = result;
this.maxFuzz = maxFuzz;
}
}
public List<T> applyFuzzy(List<T> target, int maxFuzz) throws PatchFailedException {
PatchApplyingContext<T> ctx = new PatchApplyingContext<>(new ArrayList<>(target), maxFuzz);
// the difference between patch's position and actually applied position
int lastPatchDelta = 0;
for (AbstractDelta<T> delta : getDeltas()) {
ctx.defaultPosition = delta.getSource().getPosition() + lastPatchDelta;
int patchPosition = findPositionFuzzy(ctx, delta);
if (0 <= patchPosition) {
delta.applyFuzzyToAt(ctx.result, ctx.currentFuzz, patchPosition);
lastPatchDelta = patchPosition - delta.getSource().getPosition();
ctx.lastPatchEnd = delta.getSource().last() + lastPatchDelta;
} else {
conflictOutput.processConflict(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET, delta, ctx.result);
}
}
return ctx.result;
}
// negative for not found
private int findPositionFuzzy(PatchApplyingContext<T> ctx, AbstractDelta<T> delta) throws PatchFailedException {
for (int fuzz = 0; fuzz <= ctx.maxFuzz; fuzz++) {
ctx.currentFuzz = fuzz;
int foundPosition = findPositionWithFuzz(ctx, delta, fuzz);
if (foundPosition >= 0) {
return foundPosition;
}
}
return -1;
}
// negative for not found
private int findPositionWithFuzz(PatchApplyingContext<T> ctx, AbstractDelta<T> delta, int fuzz) throws PatchFailedException {
if (delta.getSource().verifyChunk(ctx.result, fuzz, ctx.defaultPosition) == VerifyChunk.OK) {
return ctx.defaultPosition;
}
ctx.beforeOutRange = false;
ctx.afterOutRange = false;
// moreDelta >= 0: just for overflow guard, not a normal condition
//noinspection OverflowingLoopIndex
for (int moreDelta = 0; moreDelta >= 0; moreDelta++) {
int pos = findPositionWithFuzzAndMoreDelta(ctx, delta, fuzz, moreDelta);
if (pos >= 0) {
return pos;
}
if (ctx.beforeOutRange && ctx.afterOutRange) {
break;
}
}
return -1;
}
// negative for not found
private int findPositionWithFuzzAndMoreDelta(PatchApplyingContext<T> ctx, AbstractDelta<T> delta, int fuzz, int moreDelta) throws PatchFailedException {
// range check: can't apply before end of last patch
if (!ctx.beforeOutRange) {
int beginAt = ctx.defaultPosition - moreDelta + fuzz;
// We can't apply patch before end of last patch.
if (beginAt <= ctx.lastPatchEnd) {
ctx.beforeOutRange = true;
}
}
// range check: can't apply after end of result
if (!ctx.afterOutRange) {
int beginAt = ctx.defaultPosition + moreDelta + delta.getSource().size() - fuzz;
// We can't apply patch before end of last patch.
if (ctx.result.size() < beginAt) {
ctx.afterOutRange = true;
}
}
if (!ctx.beforeOutRange) {
VerifyChunk before = delta.getSource().verifyChunk(ctx.result, fuzz, ctx.defaultPosition - moreDelta);
if (before == VerifyChunk.OK) {
return ctx.defaultPosition - moreDelta;
}
}
if (!ctx.afterOutRange) {
VerifyChunk after = delta.getSource().verifyChunk(ctx.result, fuzz, ctx.defaultPosition + moreDelta);
if (after == VerifyChunk.OK) {
return ctx.defaultPosition + moreDelta;
}
}
return -1;
}
/**
* Standard Patch behaviour to throw an exception for pathching conflicts.
*/
public final ConflictOutput<T> CONFLICT_PRODUCES_EXCEPTION = (VerifyChunk verifyChunk, AbstractDelta<T> delta, List<T> result) -> {
throw new PatchFailedException("could not apply patch due to " + verifyChunk.toString());
};
/**
* Git like merge conflict output.
*/
public static final ConflictOutput<String> CONFLICT_PRODUCES_MERGE_CONFLICT = (VerifyChunk verifyChunk, AbstractDelta<String> delta, List<String> result) -> {
if (result.size() > delta.getSource().getPosition()) {
List<String> orgData = new ArrayList<>();
for (int i = 0; i < delta.getSource().size(); i++) {
orgData.add(result.get(delta.getSource().getPosition()));
result.remove(delta.getSource().getPosition());
}
orgData.add(0, "<<<<<< HEAD");
orgData.add("======");
orgData.addAll(delta.getSource().getLines());
orgData.add(">>>>>>> PATCH");
result.addAll(delta.getSource().getPosition(), orgData);
} else {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
};
private ConflictOutput<T> conflictOutput = CONFLICT_PRODUCES_EXCEPTION;
/**
* Alter normal conflict output behaviour to e.g. inclide some conflict
* statements in the result, like git does it.
*/
public Patch withConflictOutput(ConflictOutput<T> conflictOutput) {
this.conflictOutput = conflictOutput;
return this;
}
/**
* Restore the text to original. Opposite to applyTo() method.
*
@@ -100,10 +260,35 @@ public final class Patch<T> {
}
public static <T> Patch<T> generate(List<T> original, List<T> revised, List<Change> changes) {
Patch<T> patch = new Patch<>(changes.size());
return generate(original, revised, changes, false);
}
private static <T> Chunk<T> buildChunk(int start, int end, List<T> data) {
return new Chunk<>(start, new ArrayList<>(data.subList(start, end)));
}
public static <T> Patch<T> generate(List<T> original, List<T> revised, List<Change> _changes, boolean includeEquals) {
Patch<T> patch = new Patch<>(_changes.size());
int startOriginal = 0;
int startRevised = 0;
List<Change> changes = _changes;
if (includeEquals) {
changes = new ArrayList<Change>(_changes);
Collections.sort(changes, comparing(d -> d.startOriginal));
}
for (Change change : changes) {
Chunk<T> orgChunk = new Chunk<>(change.startOriginal, new ArrayList<>(original.subList(change.startOriginal, change.endOriginal)));
Chunk<T> revChunk = new Chunk<>(change.startRevised, new ArrayList<>(revised.subList(change.startRevised, change.endRevised)));
if (includeEquals && startOriginal < change.startOriginal) {
patch.addDelta(new EqualDelta<T>(
buildChunk(startOriginal, change.startOriginal, original),
buildChunk(startRevised, change.startRevised, revised)));
}
Chunk<T> orgChunk = buildChunk(change.startOriginal, change.endOriginal, original);
Chunk<T> revChunk = buildChunk(change.startRevised, change.endRevised, revised);
switch (change.deltaType) {
case DELETE:
patch.addDelta(new DeleteDelta<>(orgChunk, revChunk));
@@ -114,8 +299,19 @@ public final class Patch<T> {
case CHANGE:
patch.addDelta(new ChangeDelta<>(orgChunk, revChunk));
break;
default:
}
startOriginal = change.endOriginal;
startRevised = change.endRevised;
}
if (includeEquals && startOriginal < original.size()) {
patch.addDelta(new EqualDelta<T>(
buildChunk(startOriginal, original.size(), original),
buildChunk(startRevised, revised.size(), revised)));
}
return patch;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2009-2017 java-diff-utils.
* Copyright 2021 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,16 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.difflib.algorithm;
package com.github.difflib.patch;
public class DiffException extends Exception {
private static final long serialVersionUID = 1L;
public DiffException() {
}
public DiffException(String msg) {
super(msg);
}
/**
*
* @author tw
*/
public enum VerifyChunk {
OK,
POSITION_OUT_OF_TARGET,
CONTENT_DOES_NOT_MATCH_TARGET
}

View File

@@ -16,15 +16,16 @@
package com.github.difflib.text;
import com.github.difflib.DiffUtils;
import com.github.difflib.algorithm.DiffException;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.ChangeDelta;
import com.github.difflib.patch.Chunk;
import com.github.difflib.patch.DeleteDelta;
import com.github.difflib.patch.DeltaType;
import com.github.difflib.patch.InsertDelta;
import com.github.difflib.patch.Patch;
import com.github.difflib.text.DiffRow.Tag;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.regex.Matcher;
@@ -32,13 +33,16 @@ 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
* inline diffs on not, ignoring white spaces or/and blank lines and so on. All parameters for generating are optional.
* If you do not specify them, the class will use the default values.
* This class for generating DiffRows for side-by-sidy view. You can customize
* the way of generating. For example, show inline diffs on not, ignoring white
* spaces or/and blank lines and so on. All parameters for generating are
* optional. If you do not specify them, the class will use the default values.
*
* These values are: showInlineDiffs = false; ignoreWhiteSpaces = true; ignoreBlankLines = true; ...
* These values are: showInlineDiffs = false; ignoreWhiteSpaces = true;
* ignoreBlankLines = true; ...
*
* For instantiating the DiffRowGenerator you should use the its builder. Like in example <code>
* For instantiating the DiffRowGenerator you should use the its builder. Like
* in example <code>
* DiffRowGenerator generator = new DiffRowGenerator.Builder().showInlineDiffs(true).
* ignoreWhiteSpaces(true).columnWidth(100).build();
* </code>
@@ -52,7 +56,6 @@ public final class DiffRowGenerator {
public static final Function<String, String> LINE_NORMALIZER_FOR_HTML = StringUtils::normalize;
/**
* Splitting lines by character to achieve char by char diff checking.
*/
@@ -63,6 +66,7 @@ public final class DiffRowGenerator {
}
return list;
};
public static final Pattern SPLIT_BY_WORD_PATTERN = Pattern.compile("\\s+|[,.\\[\\](){}/\\\\*+\\-#]");
/**
@@ -101,12 +105,14 @@ public final class DiffRowGenerator {
/**
* Wrap the elements in the sequence with the given tag
*
* @param startPosition the position from which tag should start. The counting start from a zero.
* @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 tagGenerator the tag generator
*/
static void wrapInTag(List<String> sequence, int startPosition,
int endPosition, Function<Boolean, String> tagGenerator) {
int endPosition, Tag tag, BiFunction<Tag, Boolean, String> tagGenerator,
Function<String, String> processDiffs, boolean replaceLinefeedWithSpace) {
int endPos = endPosition;
while (endPos >= startPosition) {
@@ -115,6 +121,9 @@ public final class DiffRowGenerator {
while (endPos > startPosition) {
if (!"\n".equals(sequence.get(endPos - 1))) {
break;
} else if (replaceLinefeedWithSpace) {
sequence.set(endPos - 1, " ");
break;
}
endPos--;
}
@@ -123,35 +132,48 @@ public final class DiffRowGenerator {
break;
}
sequence.add(endPos, tagGenerator.apply(false));
sequence.add(endPos, tagGenerator.apply(tag, false));
if (processDiffs != null) {
sequence.set(endPos - 1,
processDiffs.apply(sequence.get(endPos - 1)));
}
endPos--;
//search position for end tag
while (endPos > startPosition) {
if ("\n".equals(sequence.get(endPos - 1))) {
break;
if (replaceLinefeedWithSpace) {
sequence.set(endPos - 1, " ");
} else {
break;
}
}
if (processDiffs != null) {
sequence.set(endPos - 1,
processDiffs.apply(sequence.get(endPos - 1)));
}
endPos--;
}
sequence.add(endPos, tagGenerator.apply(true));
sequence.add(endPos, tagGenerator.apply(tag, true));
endPos--;
}
// sequence.add(endPosition, tagGenerator.apply(false));
// sequence.add(startPosition, tagGenerator.apply(true));
}
private final int columnWidth;
private final BiPredicate<String, String> equalizer;
private final boolean ignoreWhiteSpaces;
private final Function<String, List<String>> inlineDiffSplitter;
private final boolean mergeOriginalRevised;
private final Function<Boolean, String> newTag;
private final Function<Boolean, String> oldTag;
private final BiFunction<Tag, Boolean, String> newTag;
private final BiFunction<Tag, Boolean, String> oldTag;
private final boolean reportLinesUnchanged;
private final Function<String, String> lineNormalizer;
private final Function<String, String> processDiffs;
private final boolean showInlineDiffs;
private final boolean replaceOriginalLinefeedInChangesWithSpaces;
private final boolean decompressDeltas;
private DiffRowGenerator(Builder builder) {
showInlineDiffs = builder.showInlineDiffs;
@@ -161,74 +183,60 @@ public final class DiffRowGenerator {
columnWidth = builder.columnWidth;
mergeOriginalRevised = builder.mergeOriginalRevised;
inlineDiffSplitter = builder.inlineDiffSplitter;
equalizer = ignoreWhiteSpaces ? IGNORE_WHITESPACE_EQUALIZER : DEFAULT_EQUALIZER;
decompressDeltas = builder.decompressDeltas;
if (builder.equalizer != null) {
equalizer = builder.equalizer;
} else {
equalizer = ignoreWhiteSpaces ? IGNORE_WHITESPACE_EQUALIZER : DEFAULT_EQUALIZER;
}
reportLinesUnchanged = builder.reportLinesUnchanged;
lineNormalizer = builder.lineNormalizer;
processDiffs = builder.processDiffs;
replaceOriginalLinefeedInChangesWithSpaces = builder.replaceOriginalLinefeedInChangesWithSpaces;
Objects.requireNonNull(inlineDiffSplitter);
Objects.requireNonNull(lineNormalizer);
}
/**
* Get the DiffRows describing the difference between original and revised texts using the given patch. Useful for
* displaying side-by-side diff.
* Get the DiffRows describing the difference between original and revised
* texts using the given patch. Useful for displaying side-by-side diff.
*
* @param original the original text
* @param revised the revised text
* @return the DiffRows between original and revised texts
*/
public List<DiffRow> generateDiffRows(List<String> original, List<String> revised) throws DiffException {
public List<DiffRow> generateDiffRows(List<String> original, List<String> revised) {
return generateDiffRows(original, DiffUtils.diff(original, revised, equalizer));
}
/**
* Generates the DiffRows describing the difference between original and revised texts using the given patch. Useful
* for displaying side-by-side diff.
* Generates the DiffRows describing the difference between original and
* revised texts using the given patch. Useful for displaying side-by-side
* diff.
*
* @param original the original text
* @param patch the given patch
* @return the DiffRows between original and revised texts
*/
public List<DiffRow> generateDiffRows(final List<String> original, Patch<String> patch) throws DiffException {
public List<DiffRow> generateDiffRows(final List<String> original, Patch<String> patch) {
List<DiffRow> diffRows = new ArrayList<>();
int endPos = 0;
final List<AbstractDelta<String>> deltaList = patch.getDeltas();
for (AbstractDelta<String> delta : deltaList) {
Chunk<String> orig = delta.getSource();
Chunk<String> rev = delta.getTarget();
for (String line : original.subList(endPos, orig.getPosition())) {
diffRows.add(buildDiffRow(Tag.EQUAL, line, line));
}
// Inserted DiffRow
if (delta instanceof InsertDelta) {
endPos = orig.last() + 1;
for (String line : rev.getLines()) {
diffRows.add(buildDiffRow(Tag.INSERT, "", line));
}
continue;
}
// Deleted DiffRow
if (delta instanceof DeleteDelta) {
endPos = orig.last() + 1;
for (String line : orig.getLines()) {
diffRows.add(buildDiffRow(Tag.DELETE, line, ""));
}
continue;
}
if (showInlineDiffs) {
diffRows.addAll(generateInlineDiffs(delta));
} else {
for (int j = 0; j < Math.max(orig.size(), rev.size()); j++) {
diffRows.add(buildDiffRow(Tag.CHANGE,
orig.getLines().size() > j ? orig.getLines().get(j) : "",
rev.getLines().size() > j ? rev.getLines().get(j) : ""));
if (decompressDeltas) {
for (AbstractDelta<String> originalDelta : deltaList) {
for (AbstractDelta<String> delta : decompressDeltas(originalDelta)) {
endPos = transformDeltaIntoDiffRow(original, endPos, diffRows, delta);
}
}
endPos = orig.last() + 1;
} else {
for (AbstractDelta<String> delta : deltaList) {
endPos = transformDeltaIntoDiffRow(original, endPos, diffRows, delta);
}
}
// Copy the final matching chunk if any.
@@ -238,6 +246,78 @@ public final class DiffRowGenerator {
return diffRows;
}
/**
* Transforms one patch delta into a DiffRow object.
*/
private int transformDeltaIntoDiffRow(final List<String> original, int endPos, List<DiffRow> diffRows, AbstractDelta<String> delta) {
Chunk<String> orig = delta.getSource();
Chunk<String> rev = delta.getTarget();
for (String line : original.subList(endPos, orig.getPosition())) {
diffRows.add(buildDiffRow(Tag.EQUAL, line, line));
}
switch (delta.getType()) {
case INSERT:
for (String line : rev.getLines()) {
diffRows.add(buildDiffRow(Tag.INSERT, "", line));
}
break;
case DELETE:
for (String line : orig.getLines()) {
diffRows.add(buildDiffRow(Tag.DELETE, line, ""));
}
break;
default:
if (showInlineDiffs) {
diffRows.addAll(generateInlineDiffs(delta));
} else {
for (int j = 0; j < Math.max(orig.size(), rev.size()); j++) {
diffRows.add(buildDiffRow(Tag.CHANGE,
orig.getLines().size() > j ? orig.getLines().get(j) : "",
rev.getLines().size() > j ? rev.getLines().get(j) : ""));
}
}
}
return orig.last() + 1;
}
/**
* Decompresses ChangeDeltas with different source and target size to a
* ChangeDelta with same size and a following InsertDelta or DeleteDelta.
* With this problems of building DiffRows getting smaller.
*
* @param deltaList
*/
private List<AbstractDelta<String>> decompressDeltas(AbstractDelta<String> delta) {
if (delta.getType() == DeltaType.CHANGE && delta.getSource().size() != delta.getTarget().size()) {
List<AbstractDelta<String>> deltas = new ArrayList<>();
//System.out.println("decompress this " + delta);
int minSize = Math.min(delta.getSource().size(), delta.getTarget().size());
Chunk<String> orig = delta.getSource();
Chunk<String> rev = delta.getTarget();
deltas.add(new ChangeDelta<String>(
new Chunk<>(orig.getPosition(), orig.getLines().subList(0, minSize)),
new Chunk<>(rev.getPosition(), rev.getLines().subList(0, minSize))));
if (orig.getLines().size() < rev.getLines().size()) {
deltas.add(new InsertDelta<String>(
new Chunk<>(orig.getPosition() + minSize, Collections.emptyList()),
new Chunk<>(rev.getPosition() + minSize, rev.getLines().subList(minSize, rev.getLines().size()))));
} else {
deltas.add(new DeleteDelta<String>(
new Chunk<>(orig.getPosition() + minSize, orig.getLines().subList(minSize, orig.getLines().size())),
new Chunk<>(rev.getPosition() + minSize, Collections.emptyList())));
}
return deltas;
}
return Collections.singletonList(delta);
}
private DiffRow buildDiffRow(Tag type, String orgline, String newline) {
if (reportLinesUnchanged) {
return new DiffRow(type, orgline, newline);
@@ -245,15 +325,15 @@ public final class DiffRowGenerator {
String wrapOrg = preprocessLine(orgline);
if (Tag.DELETE == type) {
if (mergeOriginalRevised || showInlineDiffs) {
wrapOrg = oldTag.apply(true) + wrapOrg + oldTag.apply(false);
wrapOrg = oldTag.apply(type, true) + wrapOrg + oldTag.apply(type, false);
}
}
String wrapNew = preprocessLine(newline);
if (Tag.INSERT == type) {
if (mergeOriginalRevised) {
wrapOrg = newTag.apply(true) + wrapNew + newTag.apply(false);
wrapOrg = newTag.apply(type, true) + wrapNew + newTag.apply(type, false);
} else if (showInlineDiffs) {
wrapNew = newTag.apply(true) + wrapNew + newTag.apply(false);
wrapNew = newTag.apply(type, true) + wrapNew + newTag.apply(type, false);
}
}
return new DiffRow(type, wrapOrg, wrapNew);
@@ -279,7 +359,7 @@ public final class DiffRowGenerator {
*
* @param delta the given delta
*/
private List<DiffRow> generateInlineDiffs(AbstractDelta<String> delta) throws DiffException {
private List<DiffRow> generateInlineDiffs(AbstractDelta<String> delta) {
List<String> orig = normalizeLines(delta.getSource().getLines());
List<String> rev = normalizeLines(delta.getTarget().getLines());
List<String> origList;
@@ -290,41 +370,45 @@ public final class DiffRowGenerator {
origList = inlineDiffSplitter.apply(joinedOrig);
revList = inlineDiffSplitter.apply(joinedRev);
List<AbstractDelta<String>> inlineDeltas = DiffUtils.diff(origList, revList).getDeltas();
List<AbstractDelta<String>> inlineDeltas = DiffUtils.diff(origList, revList, equalizer).getDeltas();
Collections.reverse(inlineDeltas);
for (AbstractDelta<String> inlineDelta : inlineDeltas) {
Chunk<String> inlineOrig = inlineDelta.getSource();
Chunk<String> inlineRev = inlineDelta.getTarget();
if (inlineDelta instanceof DeleteDelta) {
if (inlineDelta.getType() == DeltaType.DELETE) {
wrapInTag(origList, inlineOrig.getPosition(), inlineOrig
.getPosition()
+ inlineOrig.size(), oldTag);
} else if (inlineDelta instanceof InsertDelta) {
+ inlineOrig.size(), Tag.DELETE, oldTag, processDiffs, replaceOriginalLinefeedInChangesWithSpaces && mergeOriginalRevised);
} else if (inlineDelta.getType() == DeltaType.INSERT) {
if (mergeOriginalRevised) {
origList.addAll(inlineOrig.getPosition(),
revList.subList(inlineRev.getPosition(), inlineRev.getPosition()
+ inlineRev.size()));
wrapInTag(origList, inlineOrig.getPosition(), inlineOrig.getPosition()
+ inlineRev.size(), newTag);
revList.subList(inlineRev.getPosition(),
inlineRev.getPosition() + inlineRev.size()));
wrapInTag(origList, inlineOrig.getPosition(),
inlineOrig.getPosition() + inlineRev.size(),
Tag.INSERT, newTag, processDiffs, false);
} else {
wrapInTag(revList, inlineRev.getPosition(), inlineRev.getPosition()
+ inlineRev.size(), newTag);
wrapInTag(revList, inlineRev.getPosition(),
inlineRev.getPosition() + inlineRev.size(),
Tag.INSERT, newTag, processDiffs, false);
}
} else if (inlineDelta instanceof ChangeDelta) {
} else if (inlineDelta.getType() == DeltaType.CHANGE) {
if (mergeOriginalRevised) {
origList.addAll(inlineOrig.getPosition() + inlineOrig.size(),
revList.subList(inlineRev.getPosition(), inlineRev.getPosition()
+ inlineRev.size()));
wrapInTag(origList, inlineOrig.getPosition() + inlineOrig.size(), inlineOrig.getPosition() + inlineOrig.size()
+ inlineRev.size(), newTag);
revList.subList(inlineRev.getPosition(),
inlineRev.getPosition() + inlineRev.size()));
wrapInTag(origList, inlineOrig.getPosition() + inlineOrig.size(),
inlineOrig.getPosition() + inlineOrig.size() + inlineRev.size(),
Tag.CHANGE, newTag, processDiffs, false);
} else {
wrapInTag(revList, inlineRev.getPosition(), inlineRev.getPosition()
+ inlineRev.size(), newTag);
wrapInTag(revList, inlineRev.getPosition(),
inlineRev.getPosition() + inlineRev.size(),
Tag.CHANGE, newTag, processDiffs, false);
}
wrapInTag(origList, inlineOrig.getPosition(), inlineOrig
.getPosition()
+ inlineOrig.size(), oldTag);
wrapInTag(origList, inlineOrig.getPosition(),
inlineOrig.getPosition() + inlineOrig.size(),
Tag.CHANGE, oldTag, processDiffs, replaceOriginalLinefeedInChangesWithSpaces && mergeOriginalRevised);
}
}
StringBuilder origResult = new StringBuilder();
@@ -366,15 +450,21 @@ public final class DiffRowGenerator {
private boolean showInlineDiffs = false;
private boolean ignoreWhiteSpaces = false;
private boolean decompressDeltas = true;
private Function<Boolean, String> oldTag = f -> f ? "<span class=\"editOldInline\">" : "</span>";
private Function<Boolean, String> newTag = f -> f ? "<span class=\"editNewInline\">" : "</span>";
private BiFunction<Tag, Boolean, String> oldTag
= (tag, f) -> f ? "<span class=\"editOldInline\">" : "</span>";
private BiFunction<Tag, Boolean, String> newTag
= (tag, f) -> f ? "<span class=\"editNewInline\">" : "</span>";
private int columnWidth = 0;
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 Function<String, String> processDiffs = null;
private BiPredicate<String, String> equalizer = null;
private boolean replaceOriginalLinefeedInChangesWithSpaces = false;
private Builder() {
}
@@ -402,8 +492,8 @@ public final class DiffRowGenerator {
}
/**
* Give the originial old and new text lines to Diffrow without any additional processing and without any tags to
* highlight the change.
* 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
@@ -419,11 +509,33 @@ public final class DiffRowGenerator {
* @param generator the tag generator
* @return builder with configured ignoreBlankLines parameter
*/
public Builder oldTag(Function<Boolean, String> generator) {
public Builder oldTag(BiFunction<Tag, Boolean, String> generator) {
this.oldTag = generator;
return this;
}
/**
* Generator for Old-Text-Tags.
*
* @param generator the tag generator
* @return builder with configured ignoreBlankLines parameter
*/
public Builder oldTag(Function<Boolean, String> generator) {
this.oldTag = (tag, f) -> generator.apply(f);
return this;
}
/**
* Generator for New-Text-Tags.
*
* @param generator
* @return
*/
public Builder newTag(BiFunction<Tag, Boolean, String> generator) {
this.newTag = generator;
return this;
}
/**
* Generator for New-Text-Tags.
*
@@ -431,15 +543,29 @@ public final class DiffRowGenerator {
* @return
*/
public Builder newTag(Function<Boolean, String> generator) {
this.newTag = generator;
this.newTag = (tag, f) -> generator.apply(f);
return this;
}
/**
* Set the column width of generated lines of original and revised texts.
* Processor for diffed text parts. Here e.g. whitecharacters could be
* replaced by something visible.
*
* @param width the width to set. Making it < 0 doesn't have any sense. Default 80. @return builder with config
* ured ignoreBlankLines parameter
* @param processDiffs
* @return
*/
public Builder processDiffs(Function<String, String> processDiffs) {
this.processDiffs = processDiffs;
return this;
}
/**
* Set the column width of generated lines of original and revised
* texts.
*
* @param width the width to set. Making it &lt; 0 doesn't make any
* sense. Default 80.
* @return builder with config of column width
*/
public Builder columnWidth(int width) {
if (width >= 0) {
@@ -449,7 +575,8 @@ public final class DiffRowGenerator {
}
/**
* Build the DiffRowGenerator. If some parameters is not set, the default values are used.
* Build the DiffRowGenerator. If some parameters is not set, the
* default values are used.
*
* @return the customized DiffRowGenerator
*/
@@ -458,7 +585,8 @@ public final class DiffRowGenerator {
}
/**
* Merge the complete result within the original text. This makes sense for one line display.
* Merge the complete result within the original text. This makes sense
* for one line display.
*
* @param mergeOriginalRevised
* @return
@@ -469,8 +597,22 @@ public final class DiffRowGenerator {
}
/**
* 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:
* Deltas could be in a state, that would produce some unreasonable
* results within an inline diff. So the deltas are decompressed into
* smaller parts and rebuild. But this could result in more differences.
*
* @param decompressDeltas
* @return
*/
public Builder decompressDeltas(boolean decompressDeltas) {
this.decompressDeltas = decompressDeltas;
return this;
}
/**
* Per default each character is separatly processed. This variant
* 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
@@ -483,8 +625,9 @@ public final class DiffRowGenerator {
}
/**
* To provide some customized splitting a splitter can be provided. Here someone could think about sentence splitter,
* comma splitter or stuff like that.
* 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
@@ -495,8 +638,10 @@ public final class DiffRowGenerator {
}
/**
* By default DiffRowGenerator preprocesses lines for HTML output. Tabs and special HTML characters like "&lt;"
* are replaced with its encoded value. To change this you can provide a customized line normalizer here.
* By default DiffRowGenerator preprocesses lines for HTML output. Tabs
* and special HTML characters like "&lt;" are replaced with its encoded
* value. To change this you can provide a customized line normalizer
* here.
*
* @param lineNormalizer
* @return
@@ -505,5 +650,29 @@ public final class DiffRowGenerator {
this.lineNormalizer = lineNormalizer;
return this;
}
/**
* Provide an equalizer for diff processing.
*
* @param equalizer equalizer for diff processing.
* @return builder with configured equalizer parameter
*/
public Builder equalizer(BiPredicate<String, String> equalizer) {
this.equalizer = equalizer;
return this;
}
/**
* Sometimes it happens that a change contains multiple lines. If there
* is no correspondence in old and new. To keep the merged line more
* readable the linefeeds could be replaced by spaces.
*
* @param replace
* @return
*/
public Builder replaceOriginalLinefeedInChangesWithSpaces(boolean replace) {
this.replaceOriginalLinefeedInChangesWithSpaces = replace;
return this;
}
}
}

View File

@@ -21,10 +21,10 @@ import static java.util.stream.Collectors.toList;
final class StringUtils {
/**
* Replaces all opening an closing tags with <code>&lt;</code> or <code>&gt;</code>.
* Replaces all opening and closing tags with <code>&lt;</code> or <code>&gt;</code>.
*
* @param str
* @return
* @return str with some HTML meta characters escaped.
*/
public static String htmlEntites(String str) {
return str.replace("<", "&lt;").replace(">", "&gt;");
@@ -61,7 +61,17 @@ final class StringUtils {
StringBuilder b = new StringBuilder(line);
for (int count = 0; length > widthIndex; count++) {
b.insert(widthIndex + delimiter * count, "<br/>");
int breakPoint = widthIndex + delimiter * count;
if (Character.isHighSurrogate(b.charAt(breakPoint - 1)) &&
Character.isLowSurrogate(b.charAt(breakPoint))) {
// Shift a breakpoint that would split a supplemental code-point.
breakPoint += 1;
if (breakPoint == b.length()) {
// Break before instead of after if this is the last code-point.
breakPoint -= 2;
}
}
b.insert(breakPoint, "<br/>");
widthIndex += columnWidth;
}

View File

@@ -55,7 +55,7 @@ public final class UnifiedDiff {
return tail;
}
public List<String> spplyPatchTo(Predicate<String> findFile, List<String> originalLines) throws PatchFailedException {
public List<String> applyPatchTo(Predicate<String> findFile, List<String> originalLines) throws PatchFailedException {
UnifiedDiffFile file = files.stream()
.filter(diff -> findFile.test(diff.getFromFile()))
.findFirst().orElse(null);

View File

@@ -18,7 +18,8 @@ package com.github.difflib.unifieddiff;
import com.github.difflib.patch.Patch;
/**
*
* Data structure for one patched file from a unified diff file.
*
* @author Tobias Warneke (t.warneke@gmx.net)
*/
public final class UnifiedDiffFile {
@@ -27,9 +28,15 @@ public final class UnifiedDiffFile {
private String fromFile;
private String fromTimestamp;
private String toFile;
private String renameFrom;
private String renameTo;
private String toTimestamp;
private String index;
private String newFileMode;
private String deletedFileMode;
private Patch<String> patch = new Patch<>();
private boolean noNewLineAtTheEndOfTheFile = false;
private Integer similarityIndex;
public String getDiffCommand() {
return diffCommand;
@@ -82,8 +89,30 @@ public final class UnifiedDiffFile {
public void setToTimestamp(String toTimestamp) {
this.toTimestamp = toTimestamp;
}
public Integer getSimilarityIndex() {
return similarityIndex;
}
public void setSimilarityIndex(Integer similarityIndex) {
this.similarityIndex = similarityIndex;
}
public String getRenameFrom() {
return renameFrom;
}
public void setRenameFrom(String renameFrom) {
this.renameFrom = renameFrom;
}
public String getRenameTo() {
return renameTo;
}
public void setRenameTo(String renameTo) {
this.renameTo = renameTo;
}
public static UnifiedDiffFile from(String fromFile, String toFile, Patch<String> patch) {
UnifiedDiffFile file = new UnifiedDiffFile();
@@ -92,4 +121,28 @@ public final class UnifiedDiffFile {
file.patch = patch;
return file;
}
public void setNewFileMode(String newFileMode) {
this.newFileMode = newFileMode;
}
public String getNewFileMode() {
return newFileMode;
}
public String getDeletedFileMode() {
return deletedFileMode;
}
public void setDeletedFileMode(String deletedFileMode) {
this.deletedFileMode = deletedFileMode;
}
public boolean isNoNewLineAtTheEndOfTheFile() {
return noNewLineAtTheEndOfTheFile;
}
public void setNoNewLineAtTheEndOfTheFile(boolean noNewLineAtTheEndOfTheFile) {
this.noNewLineAtTheEndOfTheFile = noNewLineAtTheEndOfTheFile;
}
}

View File

@@ -39,15 +39,22 @@ import java.util.regex.Pattern;
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,})");
static final Pattern TIMESTAMP_REGEXP = Pattern.compile("(\\d{4}-\\d{2}-\\d{2}[T ]\\d{2}:\\d{2}:\\d{2}\\.\\d{3,})(?: [+-]\\d+)?");
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 SIMILARITY_INDEX = new UnifiedDiffLine(true, "^similarity index (\\d+)%$", this::processSimilarityIndex);
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 RENAME_FROM = new UnifiedDiffLine(true, "^rename\\sfrom\\s(.+)$", this::processRenameFrom);
private final UnifiedDiffLine RENAME_TO = new UnifiedDiffLine(true, "^rename\\sto\\s(.+)$", this::processRenameTo);
private final UnifiedDiffLine NEW_FILE_MODE = new UnifiedDiffLine(true, "^new\\sfile\\smode\\s(\\d+)", this::processNewFileMode);
private final UnifiedDiffLine DELETED_FILE_MODE = new UnifiedDiffLine(true, "^deleted\\sfile\\smode\\s(\\d+)", this::processDeletedFileMode);
private final UnifiedDiffLine CHUNK = new UnifiedDiffLine(false, UNIFIED_DIFF_CHUNK_REGEXP, this::processChunk);
private final UnifiedDiffLine LINE_NORMAL = new UnifiedDiffLine("^\\s", this::processNormalLine);
@@ -65,47 +72,76 @@ public final class UnifiedDiffReader {
// [/^---\s/, from_file], [/^\+\+\+\s/, to_file], [/^@@\s+\-(\d+),?(\d+)?\s+\+(\d+),?(\d+)?\s@@/, chunk],
// [/^-/, del], [/^\+/, add], [/^\\ No newline at end of file$/, eof]];
private UnifiedDiff parse() throws IOException, UnifiedDiffParserException {
String headerTxt = "";
LOG.log(Level.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);
}
// String headerTxt = "";
// LOG.log(Level.FINE, "header parsing");
// String line = null;
// while (READER.ready()) {
// line = READER.readLine();
// LOG.log(Level.FINE, "parsing line {0}", line);
// if (DIFF_COMMAND.validLine(line) || INDEX.validLine(line)
// || FROM_FILE.validLine(line) || TO_FILE.validLine(line)
// || NEW_FILE_MODE.validLine(line)) {
// break;
// } else {
// headerTxt += line + "\n";
// }
// }
// if (!"".equals(headerTxt)) {
// data.setHeader(headerTxt);
// }
String line = READER.readLine();
while (line != null) {
if (!CHUNK.validLine(line)) {
String headerTxt = "";
LOG.log(Level.FINE, "header parsing");
while (line != null) {
LOG.log(Level.FINE, "parsing line {0}", line);
if (validLine(line, DIFF_COMMAND, SIMILARITY_INDEX, INDEX,
FROM_FILE, TO_FILE,
RENAME_FROM, RENAME_TO,
NEW_FILE_MODE, DELETED_FILE_MODE,
CHUNK)) {
break;
} else {
headerTxt += line + "\n";
}
line = READER.readLine();
}
if (!"".equals(headerTxt)) {
data.setHeader(headerTxt);
}
if (line != null && !CHUNK.validLine(line)) {
initFileIfNecessary();
while (!CHUNK.validLine(line)) {
if (processLine(line, DIFF_COMMAND, INDEX, FROM_FILE, TO_FILE) == false) {
while (line != null && !CHUNK.validLine(line)) {
if (!processLine(line, DIFF_COMMAND, SIMILARITY_INDEX, INDEX,
FROM_FILE, TO_FILE,
RENAME_FROM, RENAME_TO,
NEW_FILE_MODE, DELETED_FILE_MODE)) {
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)
|| (old_size==0 && new_size==0 && originalTxt.size() == this.old_ln
if (line != null) {
processLine(line, CHUNK);
while ((line = READER.readLine()) != null) {
line = checkForNoNewLineAtTheEndOfTheFile(line);
if (!processLine(line, LINE_NORMAL, LINE_ADD, LINE_DEL)) {
throw new UnifiedDiffParserException("expected data line not found");
}
if ((originalTxt.size() == old_size && revisedTxt.size() == new_size)
|| (old_size == 0 && new_size == 0 && originalTxt.size() == this.old_ln
&& revisedTxt.size() == this.new_ln)) {
finalizeChunk();
break;
finalizeChunk();
break;
}
}
line = READER.readLine();
line = checkForNoNewLineAtTheEndOfTheFile(line);
}
line = READER.readLine();
if (line == null || line.startsWith("--")) {
if (line == null || (line.startsWith("--") && !line.startsWith("---"))) {
break;
}
}
@@ -113,7 +149,10 @@ public final class UnifiedDiffReader {
if (READER.ready()) {
String tailTxt = "";
while (READER.ready()) {
tailTxt += READER.readLine() + "\n";
if (tailTxt.length() > 0) {
tailTxt += "\n";
}
tailTxt += READER.readLine();
}
data.setTailTxt(tailTxt);
}
@@ -121,6 +160,14 @@ public final class UnifiedDiffReader {
return data;
}
private String checkForNoNewLineAtTheEndOfTheFile(String line) throws IOException {
if ("\\ No newline at end of file".equals(line)) {
actualFile.setNoNewLineAtTheEndOfTheFile(true);
return READER.readLine();
}
return line;
}
static String[] parseFileNames(String line) {
String[] split = line.split(" ");
return new String[]{
@@ -131,22 +178,46 @@ public final class UnifiedDiffReader {
private static final Logger LOG = Logger.getLogger(UnifiedDiffReader.class.getName());
/**
* To parse a diff file use this method.
*
* @param stream This is the diff file data.
* @return In a UnifiedDiff structure this diff file data is returned.
* @throws IOException
* @throws UnifiedDiffParserException
*/
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 {
if (line == null) {
return false;
}
for (UnifiedDiffLine rule : rules) {
if (rule.processLine(line)) {
LOG.info(" >>> processed rule " + rule.toString());
LOG.fine(" >>> processed rule " + rule.toString());
return true;
}
}
LOG.info(" >>> no rule matched " + line);
LOG.warning(" >>> no rule matched " + line);
return false;
//throw new UnifiedDiffParserException("parsing error at line " + line);
}
private boolean validLine(String line, UnifiedDiffLine ... rules) {
if (line == null) {
return false;
}
for (UnifiedDiffLine rule : rules) {
if (rule.validLine(line)) {
LOG.fine(" >>> accepted rule " + rule.toString());
return true;
}
}
return false;
}
private void initFileIfNecessary() {
if (!originalTxt.isEmpty() || !revisedTxt.isEmpty()) {
@@ -161,29 +232,41 @@ public final class UnifiedDiffReader {
private void processDiff(MatchResult match, String line) {
//initFileIfNecessary();
LOG.log(Level.INFO, "start {0}", line);
LOG.log(Level.FINE, "start {0}", line);
String[] fromTo = parseFileNames(READER.lastLine());
actualFile.setFromFile(fromTo[0]);
actualFile.setToFile(fromTo[1]);
actualFile.setDiffCommand(line);
}
private void processSimilarityIndex(MatchResult match, String line) {
actualFile.setSimilarityIndex(Integer.valueOf(match.group(1)));
}
private List<String> originalTxt = new ArrayList<>();
private List<String> revisedTxt = new ArrayList<>();
private List<Integer> addLineIdxList = new ArrayList<>();
private List<Integer> delLineIdxList = new ArrayList<>();
private int old_ln;
private int old_size;
private int new_ln;
private int new_size;
private int delLineIdx = 0;
private int addLineIdx = 0;
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 - 1, originalTxt, delLineIdxList), new Chunk<>(
new_ln - 1, revisedTxt, addLineIdxList)));
old_ln = 0;
new_ln = 0;
originalTxt.clear();
revisedTxt.clear();
addLineIdxList.clear();
delLineIdxList.clear();
delLineIdx = 0;
addLineIdx = 0;
}
}
@@ -191,24 +274,30 @@ public final class UnifiedDiffReader {
String cline = line.substring(1);
originalTxt.add(cline);
revisedTxt.add(cline);
delLineIdx++;
addLineIdx++;
}
private void processAddLine(MatchResult match, String line) {
String cline = line.substring(1);
revisedTxt.add(cline);
addLineIdx++;
addLineIdxList.add(new_ln - 1 + addLineIdx);
}
private void processDelLine(MatchResult match, String line) {
String cline = line.substring(1);
originalTxt.add(cline);
delLineIdx++;
delLineIdxList.add(old_ln - 1 + delLineIdx);
}
private void processChunk(MatchResult match, String chunkStart) {
// finalizeChunk();
old_ln = toInteger(match, 1, 1);
old_size = toInteger(match, 2, 0);
old_size = toInteger(match, 2, 1);
new_ln = toInteger(match, 3, 1);
new_size = toInteger(match, 4, 0);
new_size = toInteger(match, 4, 1);
if (old_ln == 0) {
old_ln = 1;
}
@@ -223,7 +312,7 @@ public final class UnifiedDiffReader {
private void processIndex(MatchResult match, String line) {
//initFileIfNecessary();
LOG.log(Level.INFO, "index {0}", line);
LOG.log(Level.FINE, "index {0}", line);
actualFile.setIndex(line.substring(6));
}
@@ -239,14 +328,33 @@ public final class UnifiedDiffReader {
actualFile.setToTimestamp(extractTimestamp(line));
}
private void processRenameFrom(MatchResult match, String line) {
actualFile.setRenameFrom(match.group(1));
}
private void processRenameTo(MatchResult match, String line) {
actualFile.setRenameTo(match.group(1));
}
private void processNewFileMode(MatchResult match, String line) {
//initFileIfNecessary();
actualFile.setNewFileMode(match.group(1));
}
private void processDeletedFileMode(MatchResult match, String line) {
//initFileIfNecessary();
actualFile.setDeletedFileMode(match.group(1));
}
private String extractFileName(String _line) {
Matcher matcher = TIMESTAMP_REGEXP.matcher(_line);
String line = _line;
if (matcher.find()) {
line = line.substring(0, matcher.start());
}
return line.substring(4).replaceFirst("^(a|b|old|new)(\\/)?", "")
.replace(TIMESTAMP_REGEXP.toString(), "").trim();
line = line.split("\t")[0];
return line.substring(4).replaceFirst("^(a|b|old|new)/", "")
.trim();
}
private String extractTimestamp(String line) {

View File

@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Level;
@@ -34,6 +35,7 @@ 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 {
Objects.requireNonNull(originalLinesProvider, "original lines provider needs to be specified");
write(diff, originalLinesProvider, line -> {
try {
writer.append(line).append("\n");
@@ -44,7 +46,9 @@ public class UnifiedDiffWriter {
}
public static void write(UnifiedDiff diff, Function<String, List<String>> originalLinesProvider, Consumer<String> writer, int contextSize) throws IOException {
writer.accept(diff.getHeader());
if (diff.getHeader() != null) {
writer.accept(diff.getHeader());
}
for (UnifiedDiffFile file : diff.getFiles()) {
List<AbstractDelta<String>> patchDeltas = new ArrayList<>(
@@ -54,9 +58,9 @@ public class UnifiedDiffWriter {
if (file.getIndex() != null) {
writer.accept("index " + file.getIndex());
}
if (file.getFromFile() != null) {
writer.accept("--- " + file.getFromFile());
}
writer.accept("--- " + (file.getFromFile() == null ? "/dev/null" : file.getFromFile()));
if (file.getToFile() != null) {
writer.accept("+++ " + file.getToFile());
}
@@ -83,7 +87,7 @@ public class UnifiedDiffWriter {
// 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);
processDeltas(writer, originalLines, deltas, contextSize, false);
deltas.clear();
deltas.add(nextDelta);
}
@@ -92,7 +96,8 @@ public class UnifiedDiffWriter {
}
// don't forget to process the last set of Deltas
processDeltas(writer, originalLines, deltas, contextSize);
processDeltas(writer, originalLines, deltas, contextSize,
patchDeltas.size() == 1 && file.getFromFile() == null);
}
}
@@ -104,7 +109,7 @@ public class UnifiedDiffWriter {
private static void processDeltas(Consumer<String> writer,
List<String> origLines, List<AbstractDelta<String>> deltas,
int contextSize) {
int contextSize, boolean newFile) {
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
@@ -112,10 +117,15 @@ public class UnifiedDiffWriter {
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 origStart;
if (newFile) {
origStart = 0;
} else {
// NOTE: +1 to overcome the 0-offset Position
origStart = curDelta.getSource().getPosition() + 1 - contextSize;
if (origStart < 1) {
origStart = 1;
}
}
int revStart = curDelta.getTarget().getPosition() + 1 - contextSize;
@@ -130,7 +140,8 @@ public class UnifiedDiffWriter {
}
// output the context before the first Delta
for (line = contextStart; line < curDelta.getSource().getPosition(); line++) { //
for (line = contextStart; line < curDelta.getSource().getPosition()
&& line < origLines.size(); line++) { //
buffer.add(" " + origLines.get(line));
origTotal++;
revTotal++;
@@ -145,8 +156,8 @@ public class UnifiedDiffWriter {
AbstractDelta<String> nextDelta = deltas.get(deltaIndex);
int intermediateStart = curDelta.getSource().getPosition()
+ curDelta.getSource().getLines().size();
for (line = intermediateStart; line < nextDelta.getSource()
.getPosition(); line++) {
for (line = intermediateStart; line < nextDelta.getSource().getPosition()
&& line < origLines.size(); line++) {
// output the code between the last Delta and this one
buffer.add(" " + origLines.get(line));
origTotal++;
@@ -178,11 +189,10 @@ public class UnifiedDiffWriter {
}
/**
* getDeltaText returns the lines to be added to the Unified Diff text from the Delta parameter
* 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)
* @param writer consumer for the list of String lines of code
* @param delta the Delta to output
*/
private static void getDeltaText(Consumer<String> writer, AbstractDelta<String> delta) {
for (String line : delta.getSource().getLines()) {

View File

@@ -14,7 +14,12 @@
* limitations under the License.
*/
/**
* This is the first test version of a multifile diff parser. The Api is still subject
* of change.
* This is the new implementation of UnifiedDiff Tools. This version is multi file aware.
* <p/>
* To read a unified diff file you should use {@link UnifiedDiffReader#parseUnifiedDiff}.
* You will get a {@link UnifiedDiff} that holds all informations about the
* diffs and the files.
* <p/>
* To process the UnifiedDiff use {@link UnifiedDiffWriter#write}.
*/
package com.github.difflib.unifieddiff;

View File

@@ -1,10 +1,10 @@
package com.github.difflib;
import com.github.difflib.algorithm.DiffException;
import com.github.difflib.patch.ChangeDelta;
import com.github.difflib.patch.Chunk;
import com.github.difflib.patch.DeleteDelta;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.EqualDelta;
import com.github.difflib.patch.InsertDelta;
import com.github.difflib.patch.Patch;
import java.io.BufferedReader;
@@ -19,16 +19,17 @@ import java.util.Collections;
import java.util.List;
import static java.util.stream.Collectors.toList;
import java.util.zip.ZipFile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Ignore;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class DiffUtilsTest {
@Test
public void testDiff_Insert() throws DiffException {
public void testDiff_Insert() {
final Patch<String> patch = DiffUtils.diff(Arrays.asList("hhh"), Arrays.
asList("hhh", "jjj", "kkk"));
assertNotNull(patch);
@@ -40,7 +41,7 @@ public class DiffUtilsTest {
}
@Test
public void testDiff_Delete() throws DiffException {
public void testDiff_Delete() {
final Patch<String> patch = DiffUtils.diff(Arrays.asList("ddd", "fff", "ggg"), Arrays.
asList("ggg"));
assertNotNull(patch);
@@ -52,7 +53,7 @@ public class DiffUtilsTest {
}
@Test
public void testDiff_Change() throws DiffException {
public void testDiff_Change() {
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc");
final List<String> changeTest_to = Arrays.asList("aaa", "zzz", "ccc");
@@ -66,14 +67,14 @@ public class DiffUtilsTest {
}
@Test
public void testDiff_EmptyList() throws DiffException {
public void testDiff_EmptyList() {
final Patch<String> patch = DiffUtils.diff(new ArrayList<>(), new ArrayList<>());
assertNotNull(patch);
assertEquals(0, patch.getDeltas().size());
}
@Test
public void testDiff_EmptyListWithNonEmpty() throws DiffException {
public void testDiff_EmptyListWithNonEmpty() {
final Patch<String> patch = DiffUtils.diff(new ArrayList<>(), Arrays.asList("aaa"));
assertNotNull(patch);
assertEquals(1, patch.getDeltas().size());
@@ -82,7 +83,7 @@ public class DiffUtilsTest {
}
@Test
public void testDiffInline() throws DiffException {
public void testDiffInline() {
final Patch<String> patch = DiffUtils.diffInline("", "test");
assertEquals(1, patch.getDeltas().size());
assertTrue(patch.getDeltas().get(0) instanceof InsertDelta);
@@ -92,7 +93,7 @@ public class DiffUtilsTest {
}
@Test
public void testDiffInline2() throws DiffException {
public void testDiffInline2() {
final Patch<String> patch = DiffUtils.diffInline("es", "fest");
assertEquals(2, patch.getDeltas().size());
assertTrue(patch.getDeltas().get(0) instanceof InsertDelta);
@@ -105,13 +106,13 @@ public class DiffUtilsTest {
}
@Test
public void testDiffIntegerList() throws DiffException {
public void testDiffIntegerList() {
List<Integer> original = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> revised = Arrays.asList(2, 3, 4, 6);
final Patch<Integer> patch = DiffUtils.diff(original, revised);
for (AbstractDelta delta : patch.getDeltas()) {
for (AbstractDelta<Integer> delta : patch.getDeltas()) {
System.out.println(delta);
}
@@ -121,7 +122,7 @@ public class DiffUtilsTest {
}
@Test
public void testDiffMissesChangeForkDnaumenkoIssue31() throws DiffException {
public void testDiffMissesChangeForkDnaumenkoIssue31() {
List<String> original = Arrays.asList("line1", "line2", "line3");
List<String> revised = Arrays.asList("line1", "line2-2", "line4");
@@ -134,8 +135,8 @@ public class DiffUtilsTest {
* To test this, the greedy meyer algorithm is not suitable.
*/
@Test
@Ignore
public void testPossibleDiffHangOnLargeDatasetDnaumenkoIssue26() throws IOException, DiffException {
@Disabled
public void testPossibleDiffHangOnLargeDatasetDnaumenkoIssue26() throws IOException {
ZipFile zip = new ZipFile(TestConstants.MOCK_FOLDER + "/large_dataset1.zip");
Patch<String> patch = DiffUtils.diff(
@@ -154,10 +155,76 @@ public class DiffUtilsTest {
}
@Test
public void testDiffMyersExample1() throws DiffException {
public void testDiffMyersExample1() {
final Patch<String> patch = DiffUtils.diff(Arrays.asList("A", "B", "C", "A", "B", "B", "A"), Arrays.asList("C", "B", "A", "B", "A", "C"));
assertNotNull(patch);
assertEquals(4, patch.getDeltas().size());
assertEquals("Patch{deltas=[[DeleteDelta, position: 0, lines: [A, B]], [InsertDelta, position: 3, lines: [B]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
}
@Test
public void testDiff_Equal() {
final Patch<String> patch = DiffUtils.diff(
Arrays.asList("hhh", "jjj", "kkk"),
Arrays.asList("hhh", "jjj", "kkk"), true);
assertNotNull(patch);
assertEquals(1, patch.getDeltas().size());
final AbstractDelta<String> delta = patch.getDeltas().get(0);
assertTrue(delta instanceof EqualDelta);
assertEquals(new Chunk<>(0, Arrays.asList("hhh", "jjj", "kkk")), delta.getSource());
assertEquals(new Chunk<>(0, Arrays.asList("hhh", "jjj", "kkk")), delta.getTarget());
}
@Test
public void testDiff_InsertWithEqual() {
final Patch<String> patch = DiffUtils.diff(Arrays.asList("hhh"), Arrays.
asList("hhh", "jjj", "kkk"), true);
assertNotNull(patch);
assertEquals(2, patch.getDeltas().size());
AbstractDelta<String> delta = patch.getDeltas().get(0);
assertTrue(delta instanceof EqualDelta);
assertEquals(new Chunk<>(0, Arrays.asList("hhh")), delta.getSource());
assertEquals(new Chunk<>(0, Arrays.asList("hhh")), delta.getTarget());
delta = patch.getDeltas().get(1);
assertTrue(delta instanceof InsertDelta);
assertEquals(new Chunk<>(1, Collections.<String>emptyList()), delta.getSource());
assertEquals(new Chunk<>(1, Arrays.asList("jjj", "kkk")), delta.getTarget());
}
@Test
public void testDiff_ProblemIssue42() {
final Patch<String> patch = DiffUtils.diff(
Arrays.asList("The", "dog", "is", "brown"),
Arrays.asList("The", "fox", "is", "down"), true);
System.out.println(patch);
assertNotNull(patch);
assertEquals(4, patch.getDeltas().size());
assertThat(patch.getDeltas()).extracting(d -> d.getType().name())
.containsExactly("EQUAL", "CHANGE", "EQUAL", "CHANGE");
AbstractDelta<String> delta = patch.getDeltas().get(0);
assertTrue(delta instanceof EqualDelta);
assertEquals(new Chunk<>(0, Arrays.asList("The")), delta.getSource());
assertEquals(new Chunk<>(0, Arrays.asList("The")), delta.getTarget());
delta = patch.getDeltas().get(1);
assertTrue(delta instanceof ChangeDelta);
assertEquals(new Chunk<>(1, Arrays.asList("dog")), delta.getSource());
assertEquals(new Chunk<>(1, Arrays.asList("fox")), delta.getTarget());
delta = patch.getDeltas().get(2);
assertTrue(delta instanceof EqualDelta);
assertEquals(new Chunk<>(2, Arrays.asList("is")), delta.getSource());
assertEquals(new Chunk<>(2, Arrays.asList("is")), delta.getTarget());
delta = patch.getDeltas().get(3);
assertTrue(delta instanceof ChangeDelta);
assertEquals(new Chunk<>(3, Arrays.asList("brown")), delta.getSource());
assertEquals(new Chunk<>(3, Arrays.asList("down")), delta.getTarget());
}
}

View File

@@ -1,6 +1,6 @@
package com.github.difflib;
import com.github.difflib.algorithm.DiffException;
import com.github.difflib.patch.Chunk;
import com.github.difflib.patch.Patch;
import com.github.difflib.patch.PatchFailedException;
import java.io.BufferedReader;
@@ -9,11 +9,15 @@ import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
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.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
public class GenerateUnifiedDiffTest {
@@ -29,7 +33,7 @@ public class GenerateUnifiedDiffTest {
}
@Test
public void testGenerateUnified() throws DiffException, IOException {
public void testGenerateUnified() throws IOException {
List<String> origLines = fileToLines(TestConstants.MOCK_FOLDER + "original.txt");
List<String> revLines = fileToLines(TestConstants.MOCK_FOLDER + "revised.txt");
@@ -37,7 +41,7 @@ public class GenerateUnifiedDiffTest {
}
@Test
public void testGenerateUnifiedWithOneDelta() throws DiffException, IOException {
public void testGenerateUnifiedWithOneDelta() throws 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");
@@ -45,7 +49,7 @@ public class GenerateUnifiedDiffTest {
}
@Test
public void testGenerateUnifiedDiffWithoutAnyDeltas() throws DiffException {
public void testGenerateUnifiedDiffWithoutAnyDeltas() {
List<String> test = Arrays.asList("abc");
Patch<String> patch = DiffUtils.diff(test, test);
UnifiedDiffUtils.generateUnifiedDiff("abc", "abc", test, patch, 0);
@@ -67,14 +71,14 @@ public class GenerateUnifiedDiffTest {
* Issue 12
*/
@Test
public void testPatchWithNoDeltas() throws DiffException, IOException {
public void testPatchWithNoDeltas() throws 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 {
public void testDiff5() throws 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");
@@ -84,7 +88,7 @@ public class GenerateUnifiedDiffTest {
* Issue 19
*/
@Test
public void testDiffWithHeaderLineInText() throws DiffException {
public void testDiffWithHeaderLineInText() {
List<String> original = new ArrayList<>();
List<String> revised = new ArrayList<>();
@@ -104,9 +108,69 @@ public class GenerateUnifiedDiffTest {
original, patch, 10);
UnifiedDiffUtils.parseUnifiedDiff(udiff);
}
/**
* Issue 47
*/
@Test
public void testNewFileCreation() {
List<String> original = new ArrayList<>();
List<String> revised = new ArrayList<>();
revised.add("line1");
revised.add("line2");
Patch<String> patch = DiffUtils.diff(original, revised);
List<String> udiff = UnifiedDiffUtils.generateUnifiedDiff(null, "revised",
original, patch, 10);
assertEquals("--- /dev/null", udiff.get(0));
assertEquals("+++ revised", udiff.get(1));
assertEquals("@@ -0,0 +1,2 @@", udiff.get(2));
UnifiedDiffUtils.parseUnifiedDiff(udiff);
}
/**
* Issue 89
*/
@Test
public void testChangePosition() throws IOException {
final List<String> patchLines = fileToLines(TestConstants.MOCK_FOLDER + "issue89_patch.txt");
final Patch<String> patch = UnifiedDiffUtils.parseUnifiedDiff(patchLines);
List<Integer> realRemoveListOne = Collections.singletonList(3);
List<Integer> realAddListOne = Arrays.asList(3, 7, 8, 9, 10, 11, 12, 13, 14);
validateChangePosition(patch, 0, realRemoveListOne, realAddListOne);
List<Integer> realRemoveListTwo = new ArrayList<>();
List<Integer> realAddListTwo = Arrays.asList(27, 28);
validateChangePosition(patch, 1, realRemoveListTwo, realAddListTwo);
}
private void validateChangePosition(Patch<String> patch, int index, List<Integer> realRemoveList,
List<Integer> realAddList ) {
final Chunk<String> originChunk = patch.getDeltas().get(index).getSource();
List<Integer> removeList = originChunk.getChangePosition();
assertEquals(realRemoveList.size(), removeList.size());
for (Integer ele: realRemoveList) {
assertTrue(realRemoveList.contains(ele));
}
for (Integer ele: removeList) {
assertTrue(realAddList.contains(ele));
}
final Chunk<String> targetChunk = patch.getDeltas().get(index).getTarget();
List<Integer> addList = targetChunk.getChangePosition();
assertEquals(realAddList.size(), addList.size());
for (Integer ele: realAddList) {
assertTrue(addList.contains(ele));
}
for (Integer ele: addList) {
assertTrue(realAddList.contains(ele));
}
}
private void verify(List<String> origLines, List<String> revLines,
String originalFile, String revisedFile) throws DiffException {
String originalFile, String revisedFile) {
Patch<String> patch = DiffUtils.diff(origLines, revLines);
List<String> unifiedDiff = UnifiedDiffUtils.generateUnifiedDiff(originalFile, revisedFile,
origLines, patch, 10);
@@ -129,4 +193,31 @@ public class GenerateUnifiedDiffTest {
fail(e.getMessage());
}
}
@Test
public void testFailingPatchByException() throws IOException {
final List<String> baseLines = fileToLines(TestConstants.MOCK_FOLDER + "issue10_base.txt");
final List<String> patchLines = fileToLines(TestConstants.MOCK_FOLDER + "issue10_patch.txt");
final Patch<String> p = UnifiedDiffUtils.parseUnifiedDiff(patchLines);
//make original not fitting
baseLines.set(40, baseLines.get(40) + " corrupted ");
assertThrows(PatchFailedException.class, () -> DiffUtils.patch(baseLines, p));
}
@Test
public void testWrongContextLength() throws IOException {
List<String> original = fileToLines(TestConstants.BASE_FOLDER_RESOURCES + "com/github/difflib/text/issue_119_original.txt");
List<String> revised = fileToLines(TestConstants.BASE_FOLDER_RESOURCES + "com/github/difflib/text/issue_119_revised.txt");
Patch<String> patch = DiffUtils.diff(original, revised);
List<String> udiff = UnifiedDiffUtils.generateUnifiedDiff("a/$filename", "b/$filename",
original, patch, 3);
//System.out.println(udiff.stream().collect(joining("\n")));
assertThat(udiff).contains("@@ -1,4 +1,4 @@");
}
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright 2021 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.difflib.algorithm.myers;
import com.github.difflib.DiffUtils;
import com.github.difflib.algorithm.DiffAlgorithmListener;
import com.github.difflib.patch.Patch;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static java.util.stream.Collectors.toList;
import java.util.stream.IntStream;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
/**
*
* @author tw
*/
public class MeyersDiffWithLinearSpaceTest {
@Test
public void testDiffMyersExample1Forward() {
List<String> original = Arrays.asList("A", "B", "C", "A", "B", "B", "A");
List<String> revised = Arrays.asList("C", "B", "A", "B", "A", "C");
final Patch<String> patch = Patch.generate(original, revised, new MeyersDiffWithLinearSpace<String>().computeDiff(original, revised, null));
assertNotNull(patch);
System.out.println(patch);
assertEquals(5, patch.getDeltas().size());
assertEquals("Patch{deltas=[[InsertDelta, position: 0, lines: [C]], [DeleteDelta, position: 0, lines: [A]], [DeleteDelta, position: 2, lines: [C]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
}
@Test
public void testDiffMyersExample1ForwardWithListener() {
List<String> original = Arrays.asList("A", "B", "C", "A", "B", "B", "A");
List<String> revised = Arrays.asList("C", "B", "A", "B", "A", "C");
List<String> logdata = new ArrayList<>();
final Patch<String> patch = Patch.generate(original, revised,
new MeyersDiffWithLinearSpace<String>().computeDiff(original, revised, new DiffAlgorithmListener() {
@Override
public void diffStart() {
logdata.add("start");
}
@Override
public void diffStep(int value, int max) {
logdata.add(value + " - " + max);
}
@Override
public void diffEnd() {
logdata.add("end");
}
}));
assertNotNull(patch);
System.out.println(patch);
assertEquals(5, patch.getDeltas().size());
assertEquals("Patch{deltas=[[InsertDelta, position: 0, lines: [C]], [DeleteDelta, position: 0, lines: [A]], [DeleteDelta, position: 2, lines: [C]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
System.out.println(logdata);
assertEquals(11, logdata.size());
}
@Test
public void testPerformanceProblemsIssue124() {
List<String> old = Arrays.asList("abcd");
List<String> newl = IntStream.range(0, 90000)
.boxed()
.map(i -> i.toString())
.collect(toList());
long start = System.currentTimeMillis();
Patch<String> diff = DiffUtils.diff(old, newl, new MeyersDiffWithLinearSpace<String>());
long end = System.currentTimeMillis();
System.out.println("Finished in " + (end - start) + "ms and resulted " + diff.getDeltas().size() + " deltas");
}
}

View File

@@ -16,13 +16,13 @@
package com.github.difflib.algorithm.myers;
import com.github.difflib.algorithm.DiffAlgorithmListener;
import com.github.difflib.algorithm.DiffException;
import com.github.difflib.patch.Patch;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.*;
import org.junit.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import org.junit.jupiter.api.Test;
/**
*
@@ -31,23 +31,23 @@ import org.junit.Test;
public class MyersDiffTest {
@Test
public void testDiffMyersExample1Forward() throws DiffException {
public void testDiffMyersExample1Forward() {
List<String> original = Arrays.asList("A", "B", "C", "A", "B", "B", "A");
List<String> revised = Arrays.asList("C", "B", "A", "B", "A", "C");
final Patch<String> patch = Patch.generate(original, revised, new MyersDiff<String>().computeDiff(original, revised, null));
final Patch<String> patch = Patch.generate(original, revised, new MeyersDiff<String>().computeDiff(original, revised, null));
assertNotNull(patch);
assertEquals(4, patch.getDeltas().size());
assertEquals("Patch{deltas=[[DeleteDelta, position: 0, lines: [A, B]], [InsertDelta, position: 3, lines: [B]], [DeleteDelta, position: 5, lines: [B]], [InsertDelta, position: 7, lines: [C]]]}", patch.toString());
}
@Test
public void testDiffMyersExample1ForwardWithListener() throws DiffException {
public void testDiffMyersExample1ForwardWithListener() {
List<String> original = Arrays.asList("A", "B", "C", "A", "B", "B", "A");
List<String> revised = Arrays.asList("C", "B", "A", "B", "A", "C");
List<String> logdata = new ArrayList<>();
final Patch<String> patch = Patch.generate(original, revised,
new MyersDiff<String>().computeDiff(original, revised, new DiffAlgorithmListener() {
new MeyersDiff<String>().computeDiff(original, revised, new DiffAlgorithmListener() {
@Override
public void diffStart() {
logdata.add("start");
@@ -69,5 +69,4 @@ public class MyersDiffTest {
System.out.println(logdata);
assertEquals(8, logdata.size());
}
}

View File

@@ -0,0 +1,394 @@
package com.github.difflib.algorithm.myers;
import com.github.difflib.patch.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.junit.jupiter.api.Test;
import com.github.difflib.DiffUtils;
public class WithMeyersDiffWithLinearSpacePatchTest {
@Test
public void testPatch_Insert() {
final List<String> insertTest_from = Arrays.asList("hhh");
final List<String> insertTest_to = Arrays.asList("hhh", "jjj", "kkk", "lll");
final Patch<String> patch = DiffUtils.diff(insertTest_from, insertTest_to, new MeyersDiffWithLinearSpace<String>());
try {
assertEquals(insertTest_to, DiffUtils.patch(insertTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@Test
public void testPatch_Delete() {
final List<String> deleteTest_from = Arrays.asList("ddd", "fff", "ggg", "hhh");
final List<String> deleteTest_to = Arrays.asList("ggg");
final Patch<String> patch = DiffUtils.diff(deleteTest_from, deleteTest_to, new MeyersDiffWithLinearSpace<String>());
try {
assertEquals(deleteTest_to, DiffUtils.patch(deleteTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@Test
public void testPatch_Change() {
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to, new MeyersDiffWithLinearSpace<String>());
try {
assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
// region testPatch_fuzzyApply utils
private List<String> intRange(int count) {
return IntStream.range(0, count)
.mapToObj(Integer::toString)
.collect(Collectors.toList());
}
@SafeVarargs
private final List<String> join(List<String>... lists) {
return Arrays.stream(lists).flatMap(Collection::stream).collect(Collectors.toList());
}
private static class FuzzyApplyTestPair {
public final List<String> from;
public final List<String> to;
public final int requiredFuzz;
private FuzzyApplyTestPair(List<String> from, List<String> to, int requiredFuzz) {
this.from = from;
this.to = to;
this.requiredFuzz = requiredFuzz;
}
}
// endregion
@Test
public void fuzzyApply() throws PatchFailedException {
Patch<String> patch = new Patch<>();
List<String> deltaFrom = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff");
List<String> deltaTo = Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fff");
patch.addDelta(new ChangeDelta<>(
new Chunk<>(6, deltaFrom),
new Chunk<>(6, deltaTo)));
//noinspection unchecked
List<String>[] moves = new List[] {
intRange(6), // no patch move
intRange(3), // forward patch move
intRange(9), // backward patch move
intRange(0), // apply to the first
};
for (FuzzyApplyTestPair pair : FUZZY_APPLY_TEST_PAIRS) {
for (List<String> move : moves) {
List<String> from = join(move, pair.from);
List<String> to = join(move, pair.to);
for (int i = 0; i < pair.requiredFuzz; i++) {
int maxFuzz = i;
assertThrows(PatchFailedException.class, () ->
patch.applyFuzzy(from, maxFuzz),
() -> "fail for " + from + " -> " + to + " for fuzz " + maxFuzz + " required " + pair.requiredFuzz);
}
for (int i = pair.requiredFuzz; i < 4; i++) {
int maxFuzz = i;
assertEquals(to, patch.applyFuzzy(from, maxFuzz),
() -> "with " + maxFuzz);
}
}
}
}
@Test
public void fuzzyApplyTwoSideBySidePatches() throws PatchFailedException {
Patch<String> patch = new Patch<>();
List<String> deltaFrom = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff");
List<String> deltaTo = Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fff");
patch.addDelta(new ChangeDelta<>(
new Chunk<>(0, deltaFrom),
new Chunk<>(0, deltaTo)));
patch.addDelta(new ChangeDelta<>(
new Chunk<>(6, deltaFrom),
new Chunk<>(6, deltaTo)));
assertEquals(join(deltaTo, deltaTo), patch.applyFuzzy(join(deltaFrom, deltaFrom), 0));
}
@Test
public void fuzzyApplyToNearest() throws PatchFailedException {
Patch<String> patch = new Patch<>();
List<String> deltaFrom = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff");
List<String> deltaTo = Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fff");
patch.addDelta(new ChangeDelta<>(
new Chunk<>(0, deltaFrom),
new Chunk<>(0, deltaTo)));
patch.addDelta(new ChangeDelta<>(
new Chunk<>(10, deltaFrom),
new Chunk<>(10, deltaTo)));
assertEquals(join(deltaTo, deltaFrom, deltaTo),
patch.applyFuzzy(join(deltaFrom, deltaFrom, deltaFrom), 0));
assertEquals(join(intRange(1), deltaTo, deltaFrom, deltaTo),
patch.applyFuzzy(join(intRange(1), deltaFrom, deltaFrom, deltaFrom), 0));
}
@Test
public void testPatch_Serializable() throws IOException, ClassNotFoundException {
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to, new MeyersDiffWithLinearSpace<String>());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(patch);
out.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bais);
Patch<String> result = (Patch<String>) in.readObject();
in.close();
try {
assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, result));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@Test
public void testPatch_Change_withExceptionProcessor() {
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to, new MeyersDiffWithLinearSpace<String>());
changeTest_from.set(2, "CDC");
patch.withConflictOutput(Patch.CONFLICT_PRODUCES_MERGE_CONFLICT);
try {
List<String> data = DiffUtils.patch(changeTest_from, patch);
assertEquals(11, data.size());
assertEquals(Arrays.asList("aaa", "bxb", "cxc", "<<<<<< HEAD", "bbb", "CDC", "======", "bbb", "ccc", ">>>>>>> PATCH", "ddd"), data);
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
static class FuzzyApplyTestDataGenerator {
private static String createList(List<String> values) {
return values.stream()
.map(x -> '"' + x + '"')
.collect(Collectors.joining(", ", "Arrays.asList(", ")"));
}
public static void main(String[] args) {
String[] deltaFrom = new String[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
String[] deltaTo = new String[] { "aaa", "bbb", "cxc", "dxd", "eee", "fff" };
List<FuzzyApplyTestPair> pairs = new ArrayList<>();
// create test data.
// Brute-force search
String[] changedValue = new String[]{"axa", "bxb", "czc", "dzd", "exe", "fxf"};
for (int i = 0; i < 1 << 6; i++) {
if ((i & 0b001100) != 0 && (i & 0b001100) != 0b001100) {
continue;
}
String[] from = deltaFrom.clone();
String[] to = deltaTo.clone();
for (int j = 0; j < 6; j++) {
if ((i & (1 << j)) != 0) {
from[j] = changedValue[j];
to[j] = changedValue[j];
}
}
int requiredFuzz;
if ((i & 0b001100) != 0) {
requiredFuzz = 3;
} else if ((i & 0b010010) != 0) {
requiredFuzz = 2;
} else if ((i & 0b100001) != 0) {
requiredFuzz = 1;
} else {
requiredFuzz = 0;
}
pairs.add(new FuzzyApplyTestPair(Arrays.asList(from), Arrays.asList(to), requiredFuzz));
}
pairs.sort(Comparator.comparingInt(a -> a.requiredFuzz));
System.out.println("FuzzyApplyTestPair[] pairs = new FuzzyApplyTestPair[] {");
for (FuzzyApplyTestPair pair : pairs) {
System.out.println(" new FuzzyApplyTestPair(");
System.out.println(" " + createList(pair.from) + ",");
System.out.println(" " + createList(pair.to) + ",");
System.out.println(" " + pair.requiredFuzz + "),");
}
System.out.println("};");
}
}
private static final FuzzyApplyTestPair[] FUZZY_APPLY_TEST_PAIRS = new FuzzyApplyTestPair[] {
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fff"),
Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fff"),
0),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bbb", "ccc", "ddd", "eee", "fff"),
Arrays.asList("axa", "bbb", "cxc", "dxd", "eee", "fff"),
1),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee", "fxf"),
Arrays.asList("aaa", "bbb", "cxc", "dxd", "eee", "fxf"),
1),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bbb", "ccc", "ddd", "eee", "fxf"),
Arrays.asList("axa", "bbb", "cxc", "dxd", "eee", "fxf"),
1),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bxb", "ccc", "ddd", "eee", "fff"),
Arrays.asList("aaa", "bxb", "cxc", "dxd", "eee", "fff"),
2),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bxb", "ccc", "ddd", "eee", "fff"),
Arrays.asList("axa", "bxb", "cxc", "dxd", "eee", "fff"),
2),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bbb", "ccc", "ddd", "exe", "fff"),
Arrays.asList("aaa", "bbb", "cxc", "dxd", "exe", "fff"),
2),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bbb", "ccc", "ddd", "exe", "fff"),
Arrays.asList("axa", "bbb", "cxc", "dxd", "exe", "fff"),
2),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bxb", "ccc", "ddd", "exe", "fff"),
Arrays.asList("aaa", "bxb", "cxc", "dxd", "exe", "fff"),
2),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bxb", "ccc", "ddd", "exe", "fff"),
Arrays.asList("axa", "bxb", "cxc", "dxd", "exe", "fff"),
2),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bxb", "ccc", "ddd", "eee", "fxf"),
Arrays.asList("aaa", "bxb", "cxc", "dxd", "eee", "fxf"),
2),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bxb", "ccc", "ddd", "eee", "fxf"),
Arrays.asList("axa", "bxb", "cxc", "dxd", "eee", "fxf"),
2),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bbb", "ccc", "ddd", "exe", "fxf"),
Arrays.asList("aaa", "bbb", "cxc", "dxd", "exe", "fxf"),
2),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bbb", "ccc", "ddd", "exe", "fxf"),
Arrays.asList("axa", "bbb", "cxc", "dxd", "exe", "fxf"),
2),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bxb", "ccc", "ddd", "exe", "fxf"),
Arrays.asList("aaa", "bxb", "cxc", "dxd", "exe", "fxf"),
2),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bxb", "ccc", "ddd", "exe", "fxf"),
Arrays.asList("axa", "bxb", "cxc", "dxd", "exe", "fxf"),
2),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bbb", "czc", "dzd", "eee", "fff"),
Arrays.asList("aaa", "bbb", "czc", "dzd", "eee", "fff"),
3),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bbb", "czc", "dzd", "eee", "fff"),
Arrays.asList("axa", "bbb", "czc", "dzd", "eee", "fff"),
3),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bxb", "czc", "dzd", "eee", "fff"),
Arrays.asList("aaa", "bxb", "czc", "dzd", "eee", "fff"),
3),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bxb", "czc", "dzd", "eee", "fff"),
Arrays.asList("axa", "bxb", "czc", "dzd", "eee", "fff"),
3),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bbb", "czc", "dzd", "exe", "fff"),
Arrays.asList("aaa", "bbb", "czc", "dzd", "exe", "fff"),
3),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bbb", "czc", "dzd", "exe", "fff"),
Arrays.asList("axa", "bbb", "czc", "dzd", "exe", "fff"),
3),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bxb", "czc", "dzd", "exe", "fff"),
Arrays.asList("aaa", "bxb", "czc", "dzd", "exe", "fff"),
3),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bxb", "czc", "dzd", "exe", "fff"),
Arrays.asList("axa", "bxb", "czc", "dzd", "exe", "fff"),
3),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bbb", "czc", "dzd", "eee", "fxf"),
Arrays.asList("aaa", "bbb", "czc", "dzd", "eee", "fxf"),
3),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bbb", "czc", "dzd", "eee", "fxf"),
Arrays.asList("axa", "bbb", "czc", "dzd", "eee", "fxf"),
3),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bxb", "czc", "dzd", "eee", "fxf"),
Arrays.asList("aaa", "bxb", "czc", "dzd", "eee", "fxf"),
3),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bxb", "czc", "dzd", "eee", "fxf"),
Arrays.asList("axa", "bxb", "czc", "dzd", "eee", "fxf"),
3),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bbb", "czc", "dzd", "exe", "fxf"),
Arrays.asList("aaa", "bbb", "czc", "dzd", "exe", "fxf"),
3),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bbb", "czc", "dzd", "exe", "fxf"),
Arrays.asList("axa", "bbb", "czc", "dzd", "exe", "fxf"),
3),
new FuzzyApplyTestPair(
Arrays.asList("aaa", "bxb", "czc", "dzd", "exe", "fxf"),
Arrays.asList("aaa", "bxb", "czc", "dzd", "exe", "fxf"),
3),
new FuzzyApplyTestPair(
Arrays.asList("axa", "bxb", "czc", "dzd", "exe", "fxf"),
Arrays.asList("axa", "bxb", "czc", "dzd", "exe", "fxf"),
3),
};
}

View File

@@ -2,7 +2,6 @@ package com.github.difflib.examples;
import com.github.difflib.DiffUtils;
import com.github.difflib.TestConstants;
import com.github.difflib.algorithm.DiffException;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.Patch;
import java.io.File;
@@ -13,11 +12,11 @@ import java.util.List;
public class ComputeDifference {
private static final String ORIGINAL = TestConstants.MOCK_FOLDER + "original.txt";
private static final String RIVISED = TestConstants.MOCK_FOLDER + "revised.txt";
private static final String REVISED = TestConstants.MOCK_FOLDER + "revised.txt";
public static void main(String[] args) throws DiffException, IOException {
public static void main(String[] args) throws IOException {
List<String> original = Files.readAllLines(new File(ORIGINAL).toPath());
List<String> revised = Files.readAllLines(new File(RIVISED).toPath());
List<String> revised = Files.readAllLines(new File(REVISED).toPath());
// Compute diff. Get the Patch object. Patch is the container for computed deltas.
Patch<String> patch = DiffUtils.diff(original, revised);

View File

@@ -0,0 +1,43 @@
package com.github.difflib.patch;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ChunkTest {
@Test
void verifyChunk() throws PatchFailedException {
Chunk<Character> chunk = new Chunk<>(7, toCharList("test"));
// normal check
assertEquals(VerifyChunk.OK,
chunk.verifyChunk(toCharList("prefix test suffix")));
assertEquals(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET,
chunk.verifyChunk(toCharList("prefix es suffix"), 0, 7));
// position
assertEquals(VerifyChunk.OK,
chunk.verifyChunk(toCharList("short test suffix"), 0, 6));
assertEquals(VerifyChunk.OK,
chunk.verifyChunk(toCharList("loonger test suffix"), 0, 8));
assertEquals(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET,
chunk.verifyChunk(toCharList("prefix test suffix"), 0, 6));
assertEquals(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET,
chunk.verifyChunk(toCharList("prefix test suffix"), 0, 8));
// fuzz
assertEquals(VerifyChunk.OK,
chunk.verifyChunk(toCharList("prefix test suffix"), 1, 7));
assertEquals(VerifyChunk.OK,
chunk.verifyChunk(toCharList("prefix es suffix"), 1, 7));
assertEquals(VerifyChunk.CONTENT_DOES_NOT_MATCH_TARGET,
chunk.verifyChunk(toCharList("prefix suffix"), 1, 7));
}
private List<Character> toCharList(String str) {
return str.chars().mapToObj(x -> (char) x).collect(Collectors.toList());
}
}

View File

@@ -1,51 +0,0 @@
package com.github.difflib.patch;
import com.github.difflib.DiffUtils;
import com.github.difflib.algorithm.DiffException;
import java.util.Arrays;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
public class PatchTest {
@Test
public void testPatch_Insert() throws DiffException {
final List<String> insertTest_from = Arrays.asList("hhh");
final List<String> insertTest_to = Arrays.asList("hhh", "jjj", "kkk", "lll");
final Patch<String> patch = DiffUtils.diff(insertTest_from, insertTest_to);
try {
assertEquals(insertTest_to, DiffUtils.patch(insertTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@Test
public void testPatch_Delete() throws DiffException {
final List<String> deleteTest_from = Arrays.asList("ddd", "fff", "ggg", "hhh");
final List<String> deleteTest_to = Arrays.asList("ggg");
final Patch<String> patch = DiffUtils.diff(deleteTest_from, deleteTest_to);
try {
assertEquals(deleteTest_to, DiffUtils.patch(deleteTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@Test
public void testPatch_Change() throws DiffException {
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
try {
assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
}

View File

@@ -0,0 +1,111 @@
package com.github.difflib.patch;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.util.List;
import com.github.difflib.DiffUtils;
import com.github.difflib.algorithm.DiffAlgorithmFactory;
import com.github.difflib.algorithm.myers.MeyersDiff;
import com.github.difflib.algorithm.myers.MeyersDiffWithLinearSpace;
import java.util.stream.Stream;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
public class PatchWithAllDiffAlgorithmsTest {
private static Stream<Arguments> provideAlgorithms() {
return Stream.of(
Arguments.of(MeyersDiff.factory()),
Arguments.of(MeyersDiffWithLinearSpace.factory()));
}
@AfterAll
public static void afterAll() {
DiffUtils.withDefaultDiffAlgorithmFactory(MeyersDiff.factory());
}
@ParameterizedTest
@MethodSource("provideAlgorithms")
public void testPatch_Insert(DiffAlgorithmFactory factory) {
DiffUtils.withDefaultDiffAlgorithmFactory(factory);
final List<String> insertTest_from = Arrays.asList("hhh");
final List<String> insertTest_to = Arrays.asList("hhh", "jjj", "kkk", "lll");
final Patch<String> patch = DiffUtils.diff(insertTest_from, insertTest_to);
try {
assertEquals(insertTest_to, DiffUtils.patch(insertTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@ParameterizedTest
@MethodSource("provideAlgorithms")
public void testPatch_Delete(DiffAlgorithmFactory factory) {
DiffUtils.withDefaultDiffAlgorithmFactory(factory);
final List<String> deleteTest_from = Arrays.asList("ddd", "fff", "ggg", "hhh");
final List<String> deleteTest_to = Arrays.asList("ggg");
final Patch<String> patch = DiffUtils.diff(deleteTest_from, deleteTest_to);
try {
assertEquals(deleteTest_to, DiffUtils.patch(deleteTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@ParameterizedTest
@MethodSource("provideAlgorithms")
public void testPatch_Change(DiffAlgorithmFactory factory) {
DiffUtils.withDefaultDiffAlgorithmFactory(factory);
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
try {
assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, patch));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@ParameterizedTest
@MethodSource("provideAlgorithms")
public void testPatch_Serializable(DiffAlgorithmFactory factory) throws IOException, ClassNotFoundException {
DiffUtils.withDefaultDiffAlgorithmFactory(factory);
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(baos);
out.writeObject(patch);
out.close();
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream in = new ObjectInputStream(bais);
Patch<String> result = (Patch<String>) in.readObject();
in.close();
try {
assertEquals(changeTest_to, DiffUtils.patch(changeTest_from, result));
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2021 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.difflib.patch;
import com.github.difflib.DiffUtils;
import static com.github.difflib.patch.Patch.CONFLICT_PRODUCES_MERGE_CONFLICT;
import java.util.Arrays;
import java.util.List;
import static java.util.stream.Collectors.joining;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Test;
/**
*
* @author tw
*/
public class PatchWithMeyerDiffTest {
@Test
public void testPatch_Change_withExceptionProcessor() {
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
changeTest_from.set(2, "CDC");
patch.withConflictOutput(Patch.CONFLICT_PRODUCES_MERGE_CONFLICT);
try {
List<String> data = DiffUtils.patch(changeTest_from, patch);
assertEquals(9, data.size());
assertEquals(Arrays.asList("aaa", "<<<<<< HEAD", "bbb", "CDC", "======", "bbb", "ccc", ">>>>>>> PATCH", "ddd"), data);
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
@Test
public void testPatchThreeWayIssue138() throws PatchFailedException {
List<String> base = Arrays.asList("Imagine there's no heaven".split("\\s+"));
List<String> left = Arrays.asList("Imagine there's no HEAVEN".split("\\s+"));
List<String> right = Arrays.asList("IMAGINE there's no heaven".split("\\s+"));
Patch<String> rightPatch = DiffUtils.diff(base, right)
.withConflictOutput(CONFLICT_PRODUCES_MERGE_CONFLICT);
List<String> applied = rightPatch.applyTo(left);
assertEquals("IMAGINE there's no HEAVEN", applied.stream().collect(joining(" ")));
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2021 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.difflib.patch;
import com.github.difflib.DiffUtils;
import com.github.difflib.algorithm.myers.MeyersDiff;
import com.github.difflib.algorithm.myers.MeyersDiffWithLinearSpace;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.AfterAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/**
*
* @author tw
*/
public class PatchWithMeyerDiffWithLinearSpaceTest {
@BeforeAll
public static void setupClass() {
DiffUtils.withDefaultDiffAlgorithmFactory(MeyersDiffWithLinearSpace.factory());
}
@AfterAll
public static void resetClass() {
DiffUtils.withDefaultDiffAlgorithmFactory(MeyersDiff.factory());
}
@Test
public void testPatch_Change_withExceptionProcessor() {
final List<String> changeTest_from = Arrays.asList("aaa", "bbb", "ccc", "ddd");
final List<String> changeTest_to = Arrays.asList("aaa", "bxb", "cxc", "ddd");
final Patch<String> patch = DiffUtils.diff(changeTest_from, changeTest_to);
changeTest_from.set(2, "CDC");
patch.withConflictOutput(Patch.CONFLICT_PRODUCES_MERGE_CONFLICT);
try {
List<String> data = DiffUtils.patch(changeTest_from, patch);
assertEquals(11, data.size());
assertEquals(Arrays.asList("aaa", "bxb", "cxc", "<<<<<< HEAD", "bbb", "CDC", "======", "bbb", "ccc", ">>>>>>> PATCH", "ddd"), data);
} catch (PatchFailedException e) {
fail(e.getMessage());
}
}
}

View File

@@ -1,22 +1,24 @@
package com.github.difflib.text;
import com.github.difflib.algorithm.DiffException;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
public class DiffRowGeneratorTest {
@Test
public void testGenerator_Default() throws DiffException {
public void testGenerator_Default() {
String first = "anything \n \nother";
String second = "anything\n\nother";
@@ -40,7 +42,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGenerator_Default2() throws DiffException {
public void testGenerator_Default2() {
String first = "anything \n \nother";
String second = "anything\n\nother";
@@ -54,7 +56,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGenerator_InlineDiff() throws DiffException {
public void testGenerator_InlineDiff() {
String first = "anything \n \nother";
String second = "anything\n\nother";
@@ -70,7 +72,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGenerator_IgnoreWhitespaces() throws DiffException {
public void testGenerator_IgnoreWhitespaces() {
String first = "anything \n \nother\nmore lines";
String second = "anything\n\nother\nsome more lines";
@@ -99,7 +101,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorWithWordWrap() throws DiffException {
public void testGeneratorWithWordWrap() {
String first = "anything \n \nother";
String second = "anything\n\nother";
@@ -116,7 +118,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorWithMerge() throws DiffException {
public void testGeneratorWithMerge() {
String first = "anything \n \nother";
String second = "anything\n\nother";
@@ -134,7 +136,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorWithMerge2() throws DiffException {
public void testGeneratorWithMerge2() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.mergeOriginalRevised(true)
@@ -147,7 +149,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorWithMerge3() throws DiffException {
public void testGeneratorWithMerge3() {
String first = "test\nanything \n \nother";
String second = "anything\n\nother\ntest\ntest2";
@@ -161,14 +163,14 @@ public class DiffRowGeneratorTest {
assertEquals(6, rows.size());
assertEquals("[CHANGE,<span class=\"editOldInline\">test</span>,anything]", rows.get(0).toString());
assertEquals("[CHANGE,anything<span class=\"editOldInline\"> </span>,]", rows.get(1).toString());
assertEquals("[CHANGE,<span class=\"editOldInline\"> </span>,]", rows.get(2).toString());
assertEquals("[DELETE,<span class=\"editOldInline\"> </span>,]", rows.get(2).toString());
assertEquals("[EQUAL,other,other]", rows.get(3).toString());
assertEquals("[INSERT,<span class=\"editNewInline\">test</span>,test]", rows.get(4).toString());
assertEquals("[INSERT,<span class=\"editNewInline\">test2</span>,test2]", rows.get(5).toString());
}
@Test
public void testGeneratorWithMergeByWord4() throws DiffException {
public void testGeneratorWithMergeByWord4() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.mergeOriginalRevised(true)
@@ -182,7 +184,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorWithMergeByWord5() throws DiffException {
public void testGeneratorWithMergeByWord5() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.mergeOriginalRevised(true)
@@ -220,7 +222,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorExample1() throws DiffException {
public void testGeneratorExample1() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.mergeOriginalRevised(true)
@@ -239,7 +241,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorExample2() throws DiffException {
public void testGeneratorExample2() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
@@ -262,7 +264,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorUnchanged() throws DiffException {
public void testGeneratorUnchanged() {
String first = "anything \n \nother";
String second = "anything\n\nother";
@@ -280,7 +282,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorIssue14() throws DiffException {
public void testGeneratorIssue14() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.mergeOriginalRevised(true)
@@ -299,7 +301,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorIssue15() throws DiffException, IOException {
public void testGeneratorIssue15() throws IOException {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true) //show the ~ ~ and ** ** symbols on each difference
.inlineDiffByWord(true) //show the ~ ~ and ** ** around each different word instead of each letter
@@ -328,7 +330,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorIssue22() throws DiffException {
public void testGeneratorIssue22() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
@@ -341,7 +343,7 @@ public class DiffRowGeneratorTest {
Arrays.asList(aa.split("\n")),
Arrays.asList(bb.split("\n")));
assertEquals("[[CHANGE,This is a test ~senctence~.,This is a test **for diffutils**.], [CHANGE,,**This is the second line.**]]",
assertEquals("[[CHANGE,This is a test ~senctence~.,This is a test **for diffutils**.], [INSERT,,**This is the second line.**]]",
rows.toString());
System.out.println("|original|new|");
@@ -352,7 +354,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorIssue22_2() throws DiffException {
public void testGeneratorIssue22_2() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
@@ -365,12 +367,12 @@ public class DiffRowGeneratorTest {
Arrays.asList(aa.split("\n")),
Arrays.asList(bb.split("\n")));
assertEquals("[[CHANGE,This is a test ~for diffutils~.,This is a test **senctence**.], [CHANGE,~This is the second line.~,]]",
assertEquals("[[CHANGE,This is a test ~for diffutils~.,This is a test **senctence**.], [DELETE,~This is the second line.~,]]",
rows.toString());
}
@Test
public void testGeneratorIssue22_3() throws DiffException {
public void testGeneratorIssue22_3() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
@@ -383,12 +385,12 @@ public class DiffRowGeneratorTest {
Arrays.asList(aa.split("\n")),
Arrays.asList(bb.split("\n")));
assertEquals("[[CHANGE,This is a test ~senctence~.,This is a test **for diffutils**.], [CHANGE,,**This is the second line.**], [CHANGE,,**And one more.**]]",
assertEquals("[[CHANGE,This is a test ~senctence~.,This is a test **for diffutils**.], [INSERT,,**This is the second line.**], [INSERT,,**And one more.**]]",
rows.toString());
}
@Test
public void testGeneratorIssue41DefaultNormalizer() throws DiffException {
public void testGeneratorIssue41DefaultNormalizer() {
DiffRowGenerator generator = DiffRowGenerator.create()
.build();
List<DiffRow> rows = generator.generateDiffRows(Arrays.asList("<"), Arrays.asList("<"));
@@ -396,7 +398,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGeneratorIssue41UserNormalizer() throws DiffException {
public void testGeneratorIssue41UserNormalizer() {
DiffRowGenerator generator = DiffRowGenerator.create()
.lineNormalizer(str -> str.replace("\t", " "))
.build();
@@ -407,7 +409,7 @@ public class DiffRowGeneratorTest {
}
@Test
public void testGenerationIssue44reportLinesUnchangedProblem() throws DiffException {
public void testGenerationIssue44reportLinesUnchangedProblem() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.reportLinesUnchanged(true)
@@ -417,4 +419,370 @@ public class DiffRowGeneratorTest {
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());
}
@Test
public void testIgnoreWhitespaceIssue66() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
.ignoreWhiteSpaces(true)
.mergeOriginalRevised(true)
.oldTag(f -> "~") //introduce markdown style for strikethrough
.newTag(f -> "**") //introduce markdown style for bold
.build();
//compute the differences for two test texts.
//CHECKSTYLE:OFF
List<DiffRow> rows = generator.generateDiffRows(
Arrays.asList("This\tis\ta\ttest."),
Arrays.asList("This is a test"));
//CHECKSTYLE:ON
assertEquals("This is a test~.~", rows.get(0).getOldLine());
}
@Test
public void testIgnoreWhitespaceIssue66_2() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
.ignoreWhiteSpaces(true)
.mergeOriginalRevised(true)
.oldTag(f -> "~") //introduce markdown style for strikethrough
.newTag(f -> "**") //introduce markdown style for bold
.build();
//compute the differences for two test texts.
List<DiffRow> rows = generator.generateDiffRows(
Arrays.asList("This is a test."),
Arrays.asList("This is a test"));
assertEquals("This is a test~.~", rows.get(0).getOldLine());
}
@Test
public void testIgnoreWhitespaceIssue64() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
.ignoreWhiteSpaces(true)
.mergeOriginalRevised(true)
.oldTag(f -> "~") //introduce markdown style for strikethrough
.newTag(f -> "**") //introduce markdown style for bold
.build();
//compute the differences for two test texts.
List<DiffRow> rows = generator.generateDiffRows(
Arrays.asList("test\n\ntestline".split("\n")),
Arrays.asList("A new text line\n\nanother one".split("\n")));
assertThat(rows).extracting(item -> item.getOldLine())
.containsExactly("~test~**A new text line**",
"",
"~testline~**another one**");
}
@Test
public void testReplaceDiffsIssue63() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
.mergeOriginalRevised(true)
.oldTag(f -> "~") //introduce markdown style for strikethrough
.newTag(f -> "**") //introduce markdown style for bold
.processDiffs(str -> str.replace(" ", "/"))
.build();
//compute the differences for two test texts.
List<DiffRow> rows = generator.generateDiffRows(
Arrays.asList("This is a test."),
Arrays.asList("This is a test"));
assertEquals("This~//~**/**is~//~**/**a~//~**/**test~.~", rows.get(0).getOldLine());
}
@Test
public void testProblemTooManyDiffRowsIssue65() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.reportLinesUnchanged(true)
.oldTag(f -> "~")
.newTag(f -> "**")
.mergeOriginalRevised(true)
.inlineDiffByWord(false)
.replaceOriginalLinefeedInChangesWithSpaces(true)
.build();
List<DiffRow> diffRows = generator.generateDiffRows(
Arrays.asList("Ich möchte nicht mit einem Bot sprechen.", "Ich soll das schon wieder wiederholen?"),
Arrays.asList("Ich möchte nicht mehr mit dir sprechen. Leite mich weiter.", "Kannst du mich zum Kundendienst weiterleiten?"));
print(diffRows);
assertThat(diffRows).hasSize(2);
}
@Test
public void testProblemTooManyDiffRowsIssue65_NoMerge() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.reportLinesUnchanged(true)
.oldTag(f -> "~")
.newTag(f -> "**")
.mergeOriginalRevised(false)
.inlineDiffByWord(false)
.build();
List<DiffRow> diffRows = generator.generateDiffRows(
Arrays.asList("Ich möchte nicht mit einem Bot sprechen.", "Ich soll das schon wieder wiederholen?"),
Arrays.asList("Ich möchte nicht mehr mit dir sprechen. Leite mich weiter.", "Kannst du mich zum Kundendienst weiterleiten?"));
System.out.println(diffRows);
assertThat(diffRows).hasSize(2);
}
@Test
public void testProblemTooManyDiffRowsIssue65_DiffByWord() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.reportLinesUnchanged(true)
.oldTag(f -> "~")
.newTag(f -> "**")
.mergeOriginalRevised(true)
.inlineDiffByWord(true)
.build();
List<DiffRow> diffRows = generator.generateDiffRows(
Arrays.asList("Ich möchte nicht mit einem Bot sprechen.", "Ich soll das schon wieder wiederholen?"),
Arrays.asList("Ich möchte nicht mehr mit dir sprechen. Leite mich weiter.", "Kannst du mich zum Kundendienst weiterleiten?"));
System.out.println(diffRows);
assertThat(diffRows).hasSize(2);
}
@Test
public void testProblemTooManyDiffRowsIssue65_NoInlineDiff() {
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(false)
.reportLinesUnchanged(true)
.oldTag(f -> "~")
.newTag(f -> "**")
.mergeOriginalRevised(true)
.inlineDiffByWord(false)
.build();
List<DiffRow> diffRows = generator.generateDiffRows(
Arrays.asList("Ich möchte nicht mit einem Bot sprechen.", "Ich soll das schon wieder wiederholen?"),
Arrays.asList("Ich möchte nicht mehr mit dir sprechen. Leite mich weiter.", "Kannst du mich zum Kundendienst weiterleiten?"));
System.out.println(diffRows);
assertThat(diffRows).hasSize(2);
}
@Test
public void testLinefeedInStandardTagsWithLineWidthIssue81() {
List<String> original = Arrays.asList(("American bobtail jaguar. American bobtail bombay but turkish angora and tomcat.\n"
+ "Russian blue leopard. Lion. Tabby scottish fold for russian blue, so savannah yet lynx. Tomcat singapura, cheetah.\n"
+ "Bengal tiger panther but singapura but bombay munchkin for cougar.").split("\n"));
List<String> revised = Arrays.asList(("bobtail jaguar. American bobtail turkish angora and tomcat.\n"
+ "Russian blue leopard. Lion. Tabby scottish folded for russian blue, so savannah yettie? lynx. Tomcat singapura, cheetah.\n"
+ "Bengal tiger panther but singapura but bombay munchkin for cougar. And more.").split("\n"));
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.ignoreWhiteSpaces(true)
.columnWidth(100)
.build();
List<DiffRow> deltas = generator.generateDiffRows(original, revised);
System.out.println(deltas);
}
@Test
public void testIssue86WrongInlineDiff() throws IOException {
String original = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue_86_original.txt")).collect(joining("\n"));
String revised = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue_86_revised.txt")).collect(joining("\n"));
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.mergeOriginalRevised(true)
.inlineDiffByWord(true)
.oldTag(f -> "~")
.newTag(f -> "**")
.build();
List<DiffRow> rows = generator.generateDiffRows(
Arrays.asList(original.split("\n")),
Arrays.asList(revised.split("\n")));
rows.stream()
.filter(item -> item.getTag() != DiffRow.Tag.EQUAL)
.forEach(System.out::println);
}
@Test
public void testCorrectChangeIssue114() throws IOException {
List<String> original = Arrays.asList("A", "B", "C", "D", "E");
List<String> revised = Arrays.asList("a", "C", "", "E");
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(false)
.inlineDiffByWord(true)
.oldTag(f -> "~")
.newTag(f -> "**")
.build();
List<DiffRow> rows = generator.generateDiffRows(original, revised);
for (DiffRow diff : rows) {
System.out.println(diff);
}
assertThat(rows).extracting(item -> item.getTag().name()).containsExactly("CHANGE", "DELETE", "EQUAL", "CHANGE", "EQUAL");
}
@Test
public void testCorrectChangeIssue114_2() throws IOException {
List<String> original = Arrays.asList("A", "B", "C", "D", "E");
List<String> revised = Arrays.asList("a", "C", "", "E");
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.inlineDiffByWord(true)
.oldTag(f -> "~")
.newTag(f -> "**")
.build();
List<DiffRow> rows = generator.generateDiffRows(original, revised);
for (DiffRow diff : rows) {
System.out.println(diff);
}
assertThat(rows).extracting(item -> item.getTag().name()).containsExactly("CHANGE", "DELETE", "EQUAL", "CHANGE", "EQUAL");
assertThat(rows.get(1).toString()).isEqualTo("[DELETE,~B~,]");
}
@Test
public void testIssue119WrongContextLength() throws IOException {
String original = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue_119_original.txt")).collect(joining("\n"));
String revised = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue_119_revised.txt")).collect(joining("\n"));
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.mergeOriginalRevised(true)
.inlineDiffByWord(true)
.oldTag(f -> "~")
.newTag(f -> "**")
.build();
List<DiffRow> rows = generator.generateDiffRows(
Arrays.asList(original.split("\n")),
Arrays.asList(revised.split("\n")));
rows.stream()
.filter(item -> item.getTag() != DiffRow.Tag.EQUAL)
.forEach(System.out::println);
}
@Test
public void testIssue129WithDeltaDecompression() {
List<String> lines1 = Arrays.asList(
"apple1",
"apple2",
"apple3",
"A man named Frankenstein abc to Switzerland for cookies!",
"banana1",
"banana2",
"banana3");
List<String> lines2 = Arrays.asList(
"apple1",
"apple2",
"apple3",
"A man named Frankenstein",
"xyz",
"to Switzerland for cookies!",
"banana1",
"banana2",
"banana3");
int[] entry = {1};
String txt = DiffRowGenerator.create()
.showInlineDiffs(true)
.oldTag((tag, isOpening) -> isOpening ? "==old" + tag + "==>" : "<==old==")
.newTag((tag, isOpening) -> isOpening ? "==new" + tag + "==>" : "<==new==")
.build()
.generateDiffRows(lines1, lines2)
.stream()
.map(row -> row.getTag().toString())
.collect(joining(" "));
// .forEachOrdered(row -> {
// System.out.printf("%4d %-8s %-80s %-80s\n", entry[0]++,
// row.getTag(), row.getOldLine(), row.getNewLine());
// });
assertThat(txt).isEqualTo("EQUAL EQUAL EQUAL CHANGE INSERT INSERT EQUAL EQUAL EQUAL");
}
@Test
public void testIssue129SkipDeltaDecompression() {
List<String> lines1 = Arrays.asList(
"apple1",
"apple2",
"apple3",
"A man named Frankenstein abc to Switzerland for cookies!",
"banana1",
"banana2",
"banana3");
List<String> lines2 = Arrays.asList(
"apple1",
"apple2",
"apple3",
"A man named Frankenstein",
"xyz",
"to Switzerland for cookies!",
"banana1",
"banana2",
"banana3");
int[] entry = {1};
String txt =
DiffRowGenerator.create()
.showInlineDiffs(true)
.decompressDeltas(false)
.oldTag((tag, isOpening) -> isOpening ? "==old" + tag + "==>" : "<==old==")
.newTag((tag, isOpening) -> isOpening ? "==new" + tag + "==>" : "<==new==")
.build()
.generateDiffRows(lines1, lines2)
.stream()
.map(row -> row.getTag().toString())
.collect(joining(" "));
// .forEachOrdered(row -> {
// System.out.printf("%4d %-8s %-80s %-80s\n", entry[0]++,
// row.getTag(), row.getOldLine(), row.getNewLine());
// });
assertThat(txt).isEqualTo("EQUAL EQUAL EQUAL CHANGE CHANGE CHANGE EQUAL EQUAL EQUAL");
}
@Test
public void testIssue129SkipWhitespaceChanges() throws IOException {
String original = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue129_1.txt")).collect(joining("\n"));
String revised = Files.lines(Paths.get("target/test-classes/com/github/difflib/text/issue129_2.txt")).collect(joining("\n"));
DiffRowGenerator generator = DiffRowGenerator.create()
.showInlineDiffs(true)
.mergeOriginalRevised(true)
.inlineDiffByWord(true)
.ignoreWhiteSpaces(true)
.oldTag((tag, isOpening) -> isOpening ? "==old" + tag + "==>" : "<==old==")
.newTag((tag, isOpening) -> isOpening ? "==new" + tag + "==>" : "<==new==")
.build();
List<DiffRow> rows = generator.generateDiffRows(
Arrays.asList(original.split("\n")),
Arrays.asList(revised.split("\n")));
assertThat(rows).hasSize(13);
rows.stream()
.filter(item -> item.getTag() != DiffRow.Tag.EQUAL)
.forEach(System.out::println);
}
}

View File

@@ -15,8 +15,9 @@
*/
package com.github.difflib.text;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
/**
*
@@ -48,11 +49,14 @@ public class StringUtilsTest {
assertEquals("te<br/>st", StringUtils.wrapText("test", 2));
assertEquals("tes<br/>t", StringUtils.wrapText("test", 3));
assertEquals("test", StringUtils.wrapText("test", 10));
assertEquals(".\uD800\uDC01<br/>.", StringUtils.wrapText(".\uD800\uDC01.", 2));
assertEquals("..<br/>\uD800\uDC01", StringUtils.wrapText("..\uD800\uDC01", 3));
}
@Test(expected = IllegalArgumentException.class)
@Test
public void testWrapText_String_int_zero() {
assertEquals("test", StringUtils.wrapText("test", -1));
Assertions.assertThrows(IllegalArgumentException.class,
() -> StringUtils.wrapText("test", -1));
}
}

View File

@@ -19,10 +19,11 @@ 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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
/**
*
@@ -42,7 +43,7 @@ public class UnifiedDiffReaderTest {
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");
assertThat(diff.getTail()).isEqualTo("2.17.1.windows.2\n");
}
@Test
@@ -100,7 +101,7 @@ public class UnifiedDiffReaderTest {
assertThat(first.getSource().size()).isGreaterThan(0);
assertThat(first.getTarget().size()).isGreaterThan(0);
assertThat(diff.getTail()).isEqualTo("2.17.1.windows.2\n\n");
assertThat(diff.getTail()).isEqualTo("2.17.1.windows.2\n");
}
@Test
@@ -121,7 +122,7 @@ public class UnifiedDiffReaderTest {
assertThat(diff.getFiles().size()).isEqualTo(1);
UnifiedDiffFile file1 = diff.getFiles().get(0);
assertThat(file1.getFromFile()).isEqualTo(".vhd");
assertThat(file1.getFromFile()).isEqualTo("a.vhd");
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1);
assertThat(diff.getTail()).isNull();
@@ -141,7 +142,7 @@ public class UnifiedDiffReaderTest {
assertThat(diff.getTail()).isNull();
assertThat(diff.getHeader()).isNull();
}
@Test
public void testParseIssue51() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
@@ -155,6 +156,242 @@ public class UnifiedDiffReaderTest {
assertThat(file1.getFromFile()).isEqualTo("f1");
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1);
UnifiedDiffFile file2 = diff.getFiles().get(1);
assertThat(file2.getFromFile()).isEqualTo("f2");
assertThat(file2.getPatch().getDeltas().size()).isEqualTo(1);
assertThat(diff.getTail()).isNull();
}
@Test
public void testParseIssue79() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue79.diff"));
assertThat(diff.getFiles().size()).isEqualTo(1);
UnifiedDiffFile file1 = diff.getFiles().get(0);
assertThat(file1.getFromFile()).isEqualTo("test/Issue.java");
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(0);
assertThat(diff.getTail()).isNull();
assertThat(diff.getHeader()).isNull();
}
@Test
public void testParseIssue84() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue84.diff"));
assertThat(diff.getFiles().size()).isEqualTo(2);
UnifiedDiffFile file1 = diff.getFiles().get(0);
assertThat(file1.getFromFile()).isEqualTo("config/ant-phase-verify.xml");
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1);
UnifiedDiffFile file2 = diff.getFiles().get(1);
assertThat(file2.getFromFile()).isEqualTo("/dev/null");
assertThat(file2.getPatch().getDeltas().size()).isEqualTo(1);
assertThat(diff.getTail()).isEqualTo("2.7.4");
assertThat(diff.getHeader()).startsWith("From b53e612a2ab5ff15d14860e252f84c0f343fe93a Mon Sep 17 00:00:00 2001");
}
@Test
public void testParseIssue85() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue85.diff"));
assertThat(diff.getFiles().size()).isEqualTo(1);
assertEquals(1, diff.getFiles().size());
final UnifiedDiffFile file1 = diff.getFiles().get(0);
assertEquals("diff -r 83e41b73d115 -r a4438263b228 tests/test-check-pyflakes.t",
file1.getDiffCommand());
assertEquals("tests/test-check-pyflakes.t", file1.getFromFile());
assertEquals("tests/test-check-pyflakes.t", file1.getToFile());
assertEquals(1, file1.getPatch().getDeltas().size());
assertNull(diff.getTail());
}
@Test
public void testTimeStampRegexp() {
assertThat("2019-04-18 13:49:39.516149751 +0200").matches(UnifiedDiffReader.TIMESTAMP_REGEXP);
}
@Test
public void testParseIssue98() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue98.diff"));
assertThat(diff.getFiles().size()).isEqualTo(1);
assertEquals(1, diff.getFiles().size());
final UnifiedDiffFile file1 = diff.getFiles().get(0);
assertEquals("100644",
file1.getDeletedFileMode());
assertEquals("src/test/java/se/bjurr/violations/lib/model/ViolationTest.java", file1.getFromFile());
assertThat(diff.getTail()).isEqualTo("2.25.1");
}
@Test
public void testParseIssue104() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_parsing_issue104.diff"));
assertThat(diff.getFiles().size()).isEqualTo(6);
final UnifiedDiffFile file = diff.getFiles().get(2);
assertThat(file.getFromFile()).isEqualTo("/dev/null");
assertThat(file.getToFile()).isEqualTo("doc/samba_data_tool_path.xml.in");
assertThat(file.getPatch().toString()).isEqualTo("Patch{deltas=[[ChangeDelta, position: 0, lines: [] to [@SAMBA_DATA_TOOL@]]]}");
assertThat(diff.getTail()).isEqualTo("2.14.4");
}
@Test
public void testParseIssue107BazelDiff() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("01-bazel-strip-unused.patch_issue107.diff"));
assertThat(diff.getFiles().size()).isEqualTo(450);
final UnifiedDiffFile file = diff.getFiles().get(0);
assertThat(file.getFromFile()).isEqualTo("./src/main/java/com/amazonaws/AbortedException.java");
assertThat(file.getToFile()).isEqualTo("/home/greg/projects/bazel/third_party/aws-sdk-auth-lite/src/main/java/com/amazonaws/AbortedException.java");
assertThat(diff.getFiles().stream()
.filter(f -> f.isNoNewLineAtTheEndOfTheFile())
.count())
.isEqualTo(48);
}
@Test
public void testParseIssue107_2() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue107.diff"));
assertThat(diff.getFiles().size()).isEqualTo(2);
UnifiedDiffFile file1 = diff.getFiles().get(0);
assertThat(file1.getFromFile()).isEqualTo("Main.java");
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1);
}
@Test
public void testParseIssue107_3() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue107_3.diff"));
assertThat(diff.getFiles().size()).isEqualTo(1);
UnifiedDiffFile file1 = diff.getFiles().get(0);
assertThat(file1.getFromFile()).isEqualTo("Billion laughs attack.md");
assertThat(file1.getPatch().getDeltas().size()).isEqualTo(1);
}
@Test
public void testParseIssue107_4() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue107_4.diff"));
assertThat(diff.getFiles().size()).isEqualTo(27);
assertThat(diff.getFiles()).extracting(f -> f.getFromFile()).contains("README.md");
}
@Test
public void testParseIssue107_5() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue107_5.diff"));
assertThat(diff.getFiles().size()).isEqualTo(22);
assertThat(diff.getFiles()).extracting(f -> f.getFromFile()).contains("rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorFactoryTest.java");
}
@Test
public void testParseIssue110() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("0001-avahi-python-Use-the-agnostic-DBM-interface.patch"));
assertThat(diff.getFiles().size()).isEqualTo(5);
final UnifiedDiffFile file = diff.getFiles().get(4);
assertThat(file.getSimilarityIndex()).isEqualTo(87);
assertThat(file.getRenameFrom()).isEqualTo("service-type-database/build-db.in");
assertThat(file.getRenameTo()).isEqualTo("service-type-database/build-db");
assertThat(file.getFromFile()).isEqualTo("service-type-database/build-db.in");
assertThat(file.getToFile()).isEqualTo("service-type-database/build-db");
}
@Test
public void testParseIssue117() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue117.diff"));
assertThat(diff.getFiles().size()).isEqualTo(2);
assertThat(diff.getFiles().get(0).getPatch().getDeltas().get(0).getSource().getChangePosition())
.containsExactly(24, 27);
assertThat(diff.getFiles().get(0).getPatch().getDeltas().get(0).getTarget().getChangePosition())
.containsExactly(24, 27);
assertThat(diff.getFiles().get(0).getPatch().getDeltas().get(1).getSource().getChangePosition())
.containsExactly(64);
assertThat(diff.getFiles().get(0).getPatch().getDeltas().get(1).getTarget().getChangePosition())
.containsExactly(64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74);
// diff.getFiles().forEach(f -> {
// System.out.println("File: " + f.getFromFile());
// f.getPatch().getDeltas().forEach(delta -> {
//
// System.out.println(delta);
// System.out.println("Source: ");
// System.out.println(delta.getSource().getPosition());
// System.out.println(delta.getSource().getChangePosition());
//
// System.out.println("Target: ");
// System.out.println(delta.getTarget().getPosition());
// System.out.println(delta.getTarget().getChangePosition());
// });
// });
}
@Test
public void testParseIssue122() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue122.diff"));
assertThat(diff.getFiles().size()).isEqualTo(1);
assertThat(diff.getFiles()).extracting(f -> f.getFromFile()).contains("coders/wpg.c");
}
@Test
public void testParseIssue123() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue123.diff"));
assertThat(diff.getFiles().size()).isEqualTo(2);
assertThat(diff.getFiles()).extracting(f -> f.getFromFile()).contains("src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java");
}
@Test
public void testParseIssue141() throws IOException {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(
UnifiedDiffReaderTest.class.getResourceAsStream("problem_diff_issue141.diff"));
UnifiedDiffFile file1 = diff.getFiles().get(0);
assertThat(file1.getFromFile()).isEqualTo("a.txt");
assertThat(file1.getToFile()).isEqualTo("a1.txt");
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2022 java-diff-utils.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.difflib.unifieddiff;
import com.github.difflib.patch.PatchFailedException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Arrays;
import static java.util.stream.Collectors.joining;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled("for next release")
public class UnifiedDiffRoundTripNewLineTest {
@Test
public void testIssue135MissingNoNewLineInPatched() throws IOException, PatchFailedException {
String beforeContent = "rootProject.name = \"sample-repo\"";
String afterContent = "rootProject.name = \"sample-repo\"\n";
String patch = "diff --git a/settings.gradle b/settings.gradle\n" +
"index ef3b8e2..ab30124 100644\n" +
"--- a/settings.gradle\n" +
"+++ b/settings.gradle\n" +
"@@ -1 +1 @@\n" +
"-rootProject.name = \"sample-repo\"\n" +
"\\ No newline at end of file\n" +
"+rootProject.name = \"sample-repo\"\n";
UnifiedDiff unifiedDiff = UnifiedDiffReader.parseUnifiedDiff(new ByteArrayInputStream(patch.getBytes()));
String unifiedAfterContent = unifiedDiff.getFiles().get(0).getPatch()
.applyTo(Arrays.asList(beforeContent.split("\n"))).stream().collect(joining("\n"));
assertEquals(afterContent, unifiedAfterContent);
}
}

View File

@@ -2,7 +2,6 @@ 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;
@@ -15,10 +14,10 @@ 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;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
public class UnifiedDiffRoundTripTest {
@@ -34,7 +33,7 @@ public class UnifiedDiffRoundTripTest {
}
@Test
public void testGenerateUnified() throws DiffException, IOException {
public void testGenerateUnified() throws IOException {
List<String> origLines = fileToLines(TestConstants.MOCK_FOLDER + "original.txt");
List<String> revLines = fileToLines(TestConstants.MOCK_FOLDER + "revised.txt");
@@ -42,7 +41,7 @@ public class UnifiedDiffRoundTripTest {
}
@Test
public void testGenerateUnifiedWithOneDelta() throws DiffException, IOException {
public void testGenerateUnifiedWithOneDelta() throws 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");
@@ -50,7 +49,7 @@ public class UnifiedDiffRoundTripTest {
}
@Test
public void testGenerateUnifiedDiffWithoutAnyDeltas() throws DiffException, IOException {
public void testGenerateUnifiedDiffWithoutAnyDeltas() throws IOException {
List<String> test = Arrays.asList("abc");
Patch<String> patch = DiffUtils.diff(test, test);
StringWriter writer = new StringWriter();
@@ -84,15 +83,15 @@ public class UnifiedDiffRoundTripTest {
* Issue 12
*/
@Test
@Ignore
public void testPatchWithNoDeltas() throws DiffException, IOException {
@Disabled
public void testPatchWithNoDeltas() throws 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 {
public void testDiff5() throws 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");
@@ -102,7 +101,7 @@ public class UnifiedDiffRoundTripTest {
* Issue 19
*/
@Test
public void testDiffWithHeaderLineInText() throws DiffException, IOException {
public void testDiffWithHeaderLineInText() throws IOException {
List<String> original = new ArrayList<>();
List<String> revised = new ArrayList<>();
@@ -130,7 +129,7 @@ public class UnifiedDiffRoundTripTest {
}
private void verify(List<String> origLines, List<String> revLines,
String originalFile, String revisedFile) throws DiffException, IOException {
String originalFile, String revisedFile) throws IOException {
Patch<String> patch = DiffUtils.diff(origLines, revLines);
StringWriter writer = new StringWriter();
@@ -151,7 +150,7 @@ public class UnifiedDiffRoundTripTest {
// Patch<String> fromUnifiedPatch = unifiedDiff.getFiles().get(0).getPatch();
// patchedLines = fromUnifiedPatch.applyTo(origLines);
// }
patchedLines = unifiedDiff.spplyPatchTo(file -> originalFile.equals(file), origLines);
patchedLines = unifiedDiff.applyPatchTo(file -> originalFile.equals(file), origLines);
assertEquals(revLines.size(), patchedLines.size());
for (int i = 0; i < revLines.size(); i++) {
String l1 = revLines.get(i);

View File

@@ -15,6 +15,8 @@
*/
package com.github.difflib.unifieddiff;
import com.github.difflib.DiffUtils;
import com.github.difflib.patch.Patch;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringWriter;
@@ -23,7 +25,11 @@ import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
/**
*
@@ -40,8 +46,35 @@ public class UnifiedDiffWriterTest {
UnifiedDiff diff = UnifiedDiffReader.parseUnifiedDiff(new ByteArrayInputStream(str.getBytes()));
StringWriter writer = new StringWriter();
// UnifiedDiffWriter.write(diff, writer);
// System.out.println(writer.toString());
UnifiedDiffWriter.write(diff, f -> Collections.emptyList(), writer, 5);
System.out.println(writer.toString());
}
/**
* Issue 47
*/
@Test
public void testWriteWithNewFile() throws URISyntaxException, IOException {
List<String> original = new ArrayList<>();
List<String> revised = new ArrayList<>();
revised.add("line1");
revised.add("line2");
Patch<String> patch = DiffUtils.diff(original, revised);
UnifiedDiff diff = new UnifiedDiff();
diff.addFile( UnifiedDiffFile.from(null, "revised", patch) );
StringWriter writer = new StringWriter();
UnifiedDiffWriter.write(diff, f -> original, writer, 5);
System.out.println(writer.toString());
String[] lines = writer.toString().split("\\n");
assertEquals("--- /dev/null", lines[0]);
assertEquals("+++ revised", lines[1]);
assertEquals("@@ -0,0 +1,2 @@", lines[2]);
}
static String readFile(URI path, Charset encoding)

View File

@@ -0,0 +1,12 @@
Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated
to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether that nation, or
any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to
dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live.
It is altogether fitting and proper that we should do this. But, in a larger sense, we can not dedicate -- we can not
consecrate -- we can not hallow -- this ground. The brave men, living and dead, who struggled here, have consecrated it,
far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never
forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought
here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us -- that
from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion -- that
we here highly resolve that these dead shall not have died in vain -- that this nation, under God, shall have a new birth of
freedom -- and that government of the people, by the people, for the people, shall not perish from the earth.

View File

@@ -0,0 +1,13 @@
Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and
dedicated to the proposition that all men are created equal. Now we are engaged in a great civil war, testing whether
that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that
war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives
that that nation might live. It is altogether fitting and proper that we should do this. But, in a larger sense, we
can not dedicate -- we can not consecrate -- we can not hallow -- this ground. The brave men, living and dead, who
struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long
remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated
here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here
dedicated to the great task remaining before us -- that from these honored dead we take increased devotion to that cause
for which they gave the last full measure of devotion -- that we here highly resolve that these dead shall not have died
in vain -- that this nation, under God, shall have a new birth of freedom -- and that government of the people, by the
people, for the people, shall not perish from the earth.

View File

@@ -0,0 +1,4 @@
const world: string = 'world',
p: number | undefined = 42;
console.log(`Hello, ${world}!`);

View File

@@ -0,0 +1,4 @@
const world: string = 'world';
const p: number | undefined = 42;
console.log(`Hello, ${world}!`);

View File

@@ -0,0 +1,7 @@
MessageTime,MessageType,Instrument,InstrumentState,TradePrice,TradeVolume,TradeCond,TradeId,AskPrice1,AskVol1,BidPrice1,BidVol1,AskPrice2,AskVol2,BidPrice2,BidVol2,AskPrice3,AskVol3,BidPrice3,BidVol3,AskPrice4,AskVol4,BidPrice4,BidVol4,AskPrice5,AskVol5,BidPrice5,BidVol5
2020-04-04T08:00:00.000Z,S,HHD_MAY20,Open,,,,,,,,,,,,,,,,,,,,,,,,
2020-04-04T08:00:00.000Z,S,FHK_C23.5_MAY20,Open,,,,,,,,,,,,,,,,,,,,,,,,
2020-04-04T13:49:11.522Z,Q,HHD_MAY20,,,,,,2.6,10,2.6,10,,,,,,,,,,,,,,,,
2020-04-04T13:49:18.210Z,T,HHD_MAY20,,2.6,1,Screen,0,,,,,,,,,,,,,,,,,,,,
2020-04-04T17:00:00.000Z,S,HHD_MAY20,Close,,,,,,,,,,,,,,,,,,,,,,,,
2020-04-04T17:00:00.000Z,S,FHK_C23.5_MAY20,Close,,,,,,,,,,,,,,,,,,,,,,,,

View File

@@ -0,0 +1,8 @@
MessageTime,MessageType,Instrument,InstrumentState,TradePrice,TradeVolume,TradeCond,TradeId,AskPrice1,AskVol1,BidPrice1,BidVol1,AskPrice2,AskVol2,BidPrice2,BidVol2,AskPrice3,AskVol3,BidPrice3,BidVol3,AskPrice4,AskVol4,BidPrice4,BidVol4,AskPrice5,AskVol5,BidPrice5,BidVol5
2020-04-02T08:00:00.000Z,S,HHD_MAY20,Open,,,,,,,,,,,,,,,,,,,,,,,,
2020-04-02T08:00:00.000Z,S,FHK_C23.5_MAY20,Open,,,,,,,,,,,,,,,,,,,,,,,,
2020-04-04T13:49:11.522Z,Q,HHD_MAY20,,,,,,2.6,10,2.6,10,,,,,,,,,,,,,,,,
2020-04xs-04T17dw:00:00.000Z,Sdwdw,HHD_MAY20dwdw,Closdwde,,,,,,,,,,,,,,,,,,,,,,,,
2020-04-04T13:49:18.210Z,T,HHD_MAY20,,2.6,2,Screen,0,,,,,,,,,,,,,,,,,,,,
2020-04-04T17:00:00.000Z,S,HHD_MAY20,Close,,,,,,,,,,,,,,,,,,,,,,,,
2020-04-04T17:00:00.000Z,S,FHK_C23.5_MAY20,Close,,,,,,,,,,,,,,,,,,,,,,,,

View File

@@ -0,0 +1,231 @@
From be7992f35ab4ed7ed9907319b429dc079c2b7285 Mon Sep 17 00:00:00 2001
From: "Jan Alexander Steffens (heftig)" <jan.steffens@gmail.com>
Date: Tue, 11 Jul 2017 21:52:37 +0200
Subject: [PATCH] avahi-python: Use the agnostic DBM interface
Also fixes configure failing if Python 3 is the build python and GDBM is
enabled, since Py3 only has anydbm under the name of 'dbm'.
Not enough to make ServiceTypeDatabase.py compatible with Py3, but it's
a start.
(cherry picked from commit 63750f1be96ad08c407193b08bf3b9ee74310e2d)
Related: #1561019
---
avahi-python/avahi/Makefile.am | 15 +----------
avahi-python/avahi/ServiceTypeDatabase.py.in | 33 ++++++++++++++++++-------
configure.ac | 9 +++----
service-type-database/Makefile.am | 18 +++-----------
service-type-database/{build-db.in => build-db} | 13 +++++++---
5 files changed, 42 insertions(+), 46 deletions(-)
rename service-type-database/{build-db.in => build-db} (87%)
diff --git a/avahi-python/avahi/Makefile.am b/avahi-python/avahi/Makefile.am
index 3eb67d0..c906b9b 100644
--- a/avahi-python/avahi/Makefile.am
+++ b/avahi-python/avahi/Makefile.am
@@ -25,29 +25,16 @@ avahidir = $(pythondir)/avahi
if HAVE_GDBM
nodist_avahi_SCRIPTS = ServiceTypeDatabase.py
-
-ServiceTypeDatabase.py: ServiceTypeDatabase.py.in
- $(AM_V_GEN)sed -e 's,@PYTHON\@,$(PYTHON),g' \
- -e 's,@DBM\@,gdbm,g' \
- -e 's,@FIRST_KEY\@,key = self.db.firstkey(),g' \
- -e 's,@CHECK_KEY\@,while key is not None:,g' \
- -e 's,@NEXT_KEY\@,key = self.db.nextkey(key),g' \
- -e 's,@pkglibdatadir\@,$(pkglibdatadir),g' $< > $@ && \
- chmod +x $@
endif
if HAVE_DBM
nodist_avahi_SCRIPTS = ServiceTypeDatabase.py
+endif
ServiceTypeDatabase.py: ServiceTypeDatabase.py.in
$(AM_V_GEN)sed -e 's,@PYTHON\@,$(PYTHON),g' \
- -e 's,@DBM\@,dbm,g' \
- -e 's,@FIRST_KEY\@,keys = self.db.keys(),g' \
- -e 's,@CHECK_KEY\@,for key in keys:,g' \
- -e 's,@NEXT_KEY\@,,g' \
-e 's,@pkglibdatadir\@,$(pkglibdatadir),g' $< > $@ && \
chmod +x $@
-endif
avahi_PYTHON = $(avahi_SCRIPTS)
diff --git a/avahi-python/avahi/ServiceTypeDatabase.py.in b/avahi-python/avahi/ServiceTypeDatabase.py.in
index 4ddd654..d7f9969 100644
--- a/avahi-python/avahi/ServiceTypeDatabase.py.in
+++ b/avahi-python/avahi/ServiceTypeDatabase.py.in
@@ -17,7 +17,11 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
-import @DBM@
+try:
+ import anydbm as dbm
+except ImportError:
+ import dbm
+
import locale
import re
@@ -28,7 +32,7 @@ class ServiceTypeDatabase:
def __init__(self, filename = "@pkglibdatadir@/service-types.db"):
- self.db = @DBM@.open(filename, "r")
+ self.db = dbm.open(filename, "r")
l = locale.getlocale(locale.LC_MESSAGES)
@@ -90,13 +94,24 @@ class ServiceTypeDatabase:
def __iter__(self):
- @FIRST_KEY@
- @CHECK_KEY@
-
- if re.search('_[a-zA-Z0-9-]+\._[a-zA-Z0-9-]+', key) and not re.search('_[a-zA-Z0-9-]+\._[a-zA-Z0-9-]+\[.*\]', key):
- yield key
-
- @NEXT_KEY@
+ def want_key(key):
+ if not re.search('_[a-zA-Z0-9-]+\._[a-zA-Z0-9-]+', key):
+ return False
+ if re.search('_[a-zA-Z0-9-]+\._[a-zA-Z0-9-]+\[.*\]', key):
+ return False
+ return True
+
+ try:
+ key = self.db.firstkey()
+ except AttributeError:
+ for key in self.db.keys():
+ if want_key(key):
+ yield key
+ else:
+ while key is not None:
+ if want_key(key):
+ yield key
+ key = self.db.nextkey(key)
def __len__(self):
diff --git a/configure.ac b/configure.ac
index 6678971..fbbf7cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -824,11 +824,10 @@ if test "x$HAVE_PYTHON" = "xyes" ; then
fi
AM_CHECK_PYMOD(socket,,,[AC_MSG_ERROR(Could not find Python module socket)])
- if test "x$HAVE_GDBM" = "xyes"; then
- AM_CHECK_PYMOD(gdbm,,,[AC_MSG_ERROR(Could not find Python module gdbm)])
- fi
- if test "x$HAVE_DBM" = "xyes"; then
- AM_CHECK_PYMOD(dbm,,,[AC_MSG_ERROR(Could not find Python module dbm)])
+ if test "x$HAVE_GDBM" = "xyes" || test "x$HAVE_DBM" = "xyes"; then
+ AM_CHECK_PYMOD(anydbm,,,[
+ AM_CHECK_PYMOD(dbm,,,[AC_MSG_ERROR(Could not find Python module dbm)])
+ ])
fi
fi
fi
diff --git a/service-type-database/Makefile.am b/service-type-database/Makefile.am
index d184fde..f9fa082 100644
--- a/service-type-database/Makefile.am
+++ b/service-type-database/Makefile.am
@@ -15,7 +15,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
-EXTRA_DIST=build-db.in service-types
+EXTRA_DIST=service-types
pkglibdatadir=$(libdir)/avahi
@@ -27,16 +27,11 @@ if HAVE_GDBM
noinst_SCRIPTS=build-db
pkglibdata_DATA+=service-types.db
-build-db: build-db.in
- $(AM_V_GEN)sed -e 's,@PYTHON\@,$(PYTHON),g' \
- -e 's,@DBM\@,gdbm,g' $< > $@ && \
- chmod +x $@
-
-service-types.db: service-types build-db
+service-types.db: service-types
$(AM_V_GEN)$(PYTHON) build-db $< $@.coming && \
mv $@.coming $@
-CLEANFILES = service-types.db build-db
+CLEANFILES = service-types.db
endif
if HAVE_DBM
@@ -44,11 +39,6 @@ if HAVE_DBM
noinst_SCRIPTS=build-db
pkglibdata_DATA+=service-types.db.pag service-types.db.dir
-build-db: build-db.in
- $(AM_V_GEN)sed -e 's,@PYTHON\@,$(PYTHON),g' \
- -e 's,@DBM\@,dbm,g' $< > $@ && \
- chmod +x $@
-
service-types.db.pag: service-types.db
$(AM_V_GEN)mv service-types.db.coming.pag service-types.db.pag
service-types.db.dir: service-types.db
@@ -57,7 +47,7 @@ service-types.db: service-types build-db
$(AM_V_GEN)$(PYTHON) build-db $< $@.coming && \
if test -f "$@.coming"; then mv $@.coming $@; fi
-CLEANFILES = service-types.db* build-db
+CLEANFILES = service-types.db*
endif
endif
diff --git a/service-type-database/build-db.in b/service-type-database/build-db
similarity index 87%
rename from service-type-database/build-db.in
rename to service-type-database/build-db
index 4cda425..78ee892 100755
--- a/service-type-database/build-db.in
+++ b/service-type-database/build-db
@@ -1,4 +1,4 @@
-#!@PYTHON@
+#!/usr/bin/env python
# -*-python-*-
# This file is part of avahi.
#
@@ -17,7 +17,12 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
-import @DBM@, sys
+try:
+ import anydbm as dbm
+except ImportError:
+ import dbm
+
+import sys
if len(sys.argv) > 1:
infn = sys.argv[1]
@@ -29,9 +34,9 @@ if len(sys.argv) > 2:
else:
outfn = infn + ".db"
-db = @DBM@.open(outfn, "n")
+db = dbm.open(outfn, "n")
-for ln in file(infn, "r"):
+for ln in open(infn, "r"):
ln = ln.strip(" \r\n\t")
if ln == "" or ln.startswith("#"):
--
2.14.3

View File

@@ -0,0 +1,13 @@
--- 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
--- a/Main2.java
+++ b/Main2.java
@@ -2,2 +2,3 @@ public class Main {
public static void main(String[] args) {
+ System.out.println("Hello, world!");
}

View File

@@ -0,0 +1,24 @@
diff -r 4d1de0a006b7 -r ace1482360cb Billion laughs attack.md
--- a/Billion laughs attack.md Mon Feb 24 13:37:17 2020 +0000
+++ b/Billion laughs attack.md Mon Feb 24 14:22:50 2020 +0000
@@ -11,14 +11,12 @@
*The problem is*: when you stay with the mouth open and eyes closed then they may throw trash and you get sick.
-
-SnakeYAML Engine [has a way to restrict the amount of aliases for collections](https://bitbucket.org/asomov/snakeyaml-engine/src/default/src/test/java/org/snakeyaml/engine/usecases/references/ReferencesTest.java) to fail early without allocation too much resources.
+SnakeYAML 1.26+ [has a way to restrict the amount of aliases for collections](https://bitbucket.org/asomov/snakeyaml/src/default/src/test/java/org/yaml/snakeyaml/issues/issue377/ReferencesTest.java) to fail early without allocation too much resources.
# Solution #
-1. If the YAML is not coming from untrusted source (it is merely a configuration file) then it is a false positive. Just ignore it. The quality of NVD database is very low and contains tons of issues which appear to be false positives.
-2. Migrate to [SnakeYAML Engine](https://bitbucket.org/asomov/snakeyaml-engine/src/default/). It has a configuration option to restrict aliases for collections (the aliases for scalars cannot grow and they are not restricted)
-3. Check how it is done in SnakeYAML Engine and build your own SnakeYAML version with the same change.
-4. Read the YAML and check its quality before giving the document to SnakeYAML (count `*` and `&` for instance)
+1. Update to SnakeYAML 1.26. It has a configuration option to restrict aliases for collections (the aliases for scalars cannot grow and they are not restricted)
+2. If the YAML is not coming from untrusted source (it is merely a configuration file) then it is a false positive. Just ignore it. The quality of NVD database is very low and contains tons of issues which appear to be false positives.
+3. Read the YAML and check its quality before giving the document to SnakeYAML (count `*` and `&` for instance)
-Enjoy.
\ No newline at end of file
+Enjoy.

View File

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,835 @@
diff --git a/distribution/src/main/release/samples/throttling/src/main/java/demo/throttling/client/Client.java b/distribution/src/main/release/samples/throttling/src/main/java/demo/throttling/client/Client.java
index 1f2a7c4baec..9d636200d61 100644
--- a/distribution/src/main/release/samples/throttling/src/main/java/demo/throttling/client/Client.java
+++ b/distribution/src/main/release/samples/throttling/src/main/java/demo/throttling/client/Client.java
@@ -112,7 +112,6 @@ public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<>();
properties.put("bus.jmx.usePlatformMBeanServer", Boolean.TRUE);
properties.put("bus.jmx.enabled", Boolean.TRUE);
- properties.put("bus.jmx.createMBServerConnectorFactory", Boolean.FALSE);
Bus b = new CXFBusFactory().createBus(null, properties);
MetricRegistry registry = new MetricRegistry();
CodahaleMetricsProvider.setupJMXReporter(b, registry);
diff --git a/distribution/src/main/release/samples/wsdl_first/src/main/resources/server-applicationContext.xml b/distribution/src/main/release/samples/wsdl_first/src/main/resources/server-applicationContext.xml
index 8bf5109ec95..391f97c624e 100644
--- a/distribution/src/main/release/samples/wsdl_first/src/main/resources/server-applicationContext.xml
+++ b/distribution/src/main/release/samples/wsdl_first/src/main/resources/server-applicationContext.xml
@@ -45,4 +45,4 @@
<bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
</jaxws:features>
</jaxws:endpoint>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/rt/management/pom.xml b/rt/management/pom.xml
index f63f3bfa6d7..19ccf6ada0c 100644
--- a/rt/management/pom.xml
+++ b/rt/management/pom.xml
@@ -34,8 +34,7 @@
<cxf.module.name>org.apache.cxf.management</cxf.module.name>
<cxf.osgi.import>
javax.xml.bind*;version="${cxf.osgi.javax.bind.version}",
- javax.annotation*;version="${cxf.osgi.javax.annotation.version}",
- sun.rmi*;resolution:=optional
+ javax.annotation*;version="${cxf.osgi.javax.annotation.version}"
</cxf.osgi.import>
</properties>
<dependencies>
diff --git a/rt/management/src/main/java/org/apache/cxf/management/jmx/InstrumentationManagerImpl.java b/rt/management/src/main/java/org/apache/cxf/management/jmx/InstrumentationManagerImpl.java
index ee7f0a71fee..d898a4b6f5f 100644
--- a/rt/management/src/main/java/org/apache/cxf/management/jmx/InstrumentationManagerImpl.java
+++ b/rt/management/src/main/java/org/apache/cxf/management/jmx/InstrumentationManagerImpl.java
@@ -19,7 +19,6 @@
package org.apache.cxf.management.jmx;
-import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.util.HashMap;
import java.util.HashSet;
@@ -53,31 +52,25 @@
import org.apache.cxf.management.ManagedComponent;
import org.apache.cxf.management.ManagementConstants;
import org.apache.cxf.management.jmx.export.runtime.ModelMBeanAssembler;
-import org.apache.cxf.management.jmx.type.JMXConnectorPolicyType;
/**
* The manager class for the JMXManagedComponent which hosts the JMXManagedComponents.
*/
-public class InstrumentationManagerImpl extends JMXConnectorPolicyType
+public class InstrumentationManagerImpl
implements InstrumentationManager, BusLifeCycleListener {
private static final Logger LOG = LogUtils.getL7dLogger(InstrumentationManagerImpl.class);
private static Map<String, String> mbeanServerIDMap = new HashMap<>();
private Bus bus;
- private MBServerConnectorFactory mcf;
private MBeanServer mbs;
private Set<ObjectName> busMBeans = new HashSet<>();
private boolean connectFailed;
private String persistentBusId;
- private Map<String, ?> environment;
- /**
- * For backward compatibility, {@link #createMBServerConnectorFactory} is <code>true</code> by default.
- */
- private boolean createMBServerConnectorFactory = true;
private String mbeanServerName = ManagementConstants.DEFAULT_DOMAIN_NAME;
private boolean usePlatformMBeanServer;
+ private boolean enabled;
public InstrumentationManagerImpl() {
super();
@@ -119,16 +112,16 @@ public void setServerName(String s) {
mbeanServerName = s;
}
- public void setCreateMBServerConnectorFactory(boolean createMBServerConnectorFactory) {
- this.createMBServerConnectorFactory = createMBServerConnectorFactory;
- }
-
public void setUsePlatformMBeanServer(Boolean flag) {
usePlatformMBeanServer = flag;
}
- public void setEnvironment(Map<String, ?> env) {
- environment = env;
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
}
@Deprecated
@@ -139,7 +132,6 @@ public void register() {
public void init() {
if (bus != null && bus.getExtension(MBeanServer.class) != null) {
enabled = true;
- createMBServerConnectorFactory = false;
mbs = bus.getExtension(MBeanServer.class);
}
if (isEnabled()) {
@@ -168,21 +160,6 @@ public void init() {
}
}
- if (createMBServerConnectorFactory) {
- mcf = MBServerConnectorFactory.getInstance();
- mcf.setMBeanServer(mbs);
- mcf.setThreaded(isThreaded());
- mcf.setDaemon(isDaemon());
- mcf.setServiceUrl(getJMXServiceURL());
- mcf.setEnvironment(environment);
- try {
- mcf.createConnector();
- } catch (IOException ex) {
- connectFailed = true;
- LOG.log(Level.SEVERE, "START_CONNECTOR_FAILURE_MSG", new Object[] {ex});
- }
- }
-
if (!connectFailed && null != bus) {
try {
//Register Bus here since we can guarantee that Instrumentation
@@ -282,14 +259,6 @@ public void shutdown() {
return;
}
- if (mcf != null) {
- try {
- mcf.destroy();
- } catch (IOException ex) {
- LOG.log(Level.SEVERE, "STOP_CONNECTOR_FAILURE_MSG", new Object[] {ex});
- }
- }
-
//Using the array to hold the busMBeans to avoid the CurrentModificationException
Object[] mBeans = busMBeans.toArray();
for (Object name : mBeans) {
@@ -400,12 +369,7 @@ private void readJMXProperties(Bus b) {
getBusProperty(b, "bus.jmx.serverName", mbeanServerName);
usePlatformMBeanServer =
getBusProperty(b, "bus.jmx.usePlatformMBeanServer", usePlatformMBeanServer);
- createMBServerConnectorFactory =
- getBusProperty(b, "bus.jmx.createMBServerConnectorFactory", createMBServerConnectorFactory);
- daemon = getBusProperty(b, "bus.jmx.daemon", daemon);
- threaded = getBusProperty(b, "bus.jmx.threaded", threaded);
enabled = getBusProperty(b, "bus.jmx.enabled", enabled);
- jmxServiceURL = getBusProperty(b, "bus.jmx.JMXServiceURL", jmxServiceURL);
}
}
diff --git a/rt/management/src/main/java/org/apache/cxf/management/jmx/MBServerConnectorFactory.java b/rt/management/src/main/java/org/apache/cxf/management/jmx/MBServerConnectorFactory.java
deleted file mode 100644
index 5eb7059b8fb..00000000000
--- a/rt/management/src/main/java/org/apache/cxf/management/jmx/MBServerConnectorFactory.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 org.apache.cxf.management.jmx;
-
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.rmi.AccessException;
-import java.rmi.AlreadyBoundException;
-import java.rmi.NotBoundException;
-import java.rmi.Remote;
-import java.rmi.RemoteException;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.management.MBeanServer;
-import javax.management.MBeanServerFactory;
-import javax.management.remote.JMXConnectorServer;
-import javax.management.remote.JMXServiceURL;
-import javax.management.remote.rmi.RMIConnectorServer;
-import javax.management.remote.rmi.RMIJRMPServerImpl;
-
-import org.apache.cxf.common.logging.LogUtils;
-
-
-
-/**
- * Deal with the MBeanServer Connections
- *
- */
-public final class MBServerConnectorFactory {
-
- public static final String DEFAULT_SERVICE_URL = "service:jmx:rmi:///jndi/rmi://localhost:9913/jmxrmi";
-
- private static final Logger LOG = LogUtils.getL7dLogger(MBServerConnectorFactory.class);
-
- private static MBeanServer server;
-
- private static String serviceUrl = DEFAULT_SERVICE_URL;
-
- private static Map<String, ?> environment;
-
- private static boolean threaded;
-
- private static boolean daemon;
-
- private static JMXConnectorServer connectorServer;
-
- private static Remote remoteServerStub;
-
- private static RMIJRMPServerImpl rmiServer;
-
- private static class MBServerConnectorFactoryHolder {
- private static final MBServerConnectorFactory INSTANCE =
- new MBServerConnectorFactory();
- }
-
- private static class MBeanServerHolder {
- private static final MBeanServer INSTANCE =
- MBeanServerFactory.createMBeanServer();
- }
-
- private MBServerConnectorFactory() {
-
- }
-
- static int getServerPort(final String url) {
- int portStart = url.indexOf("localhost") + 10;
- int portEnd;
- int port = 0;
- if (portStart > 0) {
- portEnd = indexNotOfNumber(url, portStart);
- if (portEnd > portStart) {
- final String portString = url.substring(portStart, portEnd);
- port = Integer.parseInt(portString);
- }
- }
- return port;
- }
-
- private static int indexNotOfNumber(String str, int index) {
- int i = 0;
- for (i = index; i < str.length(); i++) {
- if (str.charAt(i) < '0' || str.charAt(i) > '9') {
- return i;
- }
- }
- return -1;
- }
-
- public static MBServerConnectorFactory getInstance() {
- return MBServerConnectorFactoryHolder.INSTANCE;
- }
-
- public void setMBeanServer(MBeanServer ms) {
- server = ms;
- }
-
- public void setServiceUrl(String url) {
- serviceUrl = url;
- }
-
- public void setEnvironment(Map<String, ?> env) {
- environment = env;
- }
-
- public void setThreaded(boolean fthread) {
- threaded = fthread;
- }
-
- public void setDaemon(boolean fdaemon) {
- daemon = fdaemon;
- }
-
-
- public void createConnector() throws IOException {
-
- if (server == null) {
- server = MBeanServerHolder.INSTANCE;
- }
-
- // Create the JMX service URL.
- final JMXServiceURL url = new JMXServiceURL(serviceUrl);
-
- // if the URL is localhost, start up an Registry
- if (serviceUrl.indexOf("localhost") > -1
- && url.getProtocol().compareToIgnoreCase("rmi") == 0) {
- try {
- int port = getRegistryPort(serviceUrl);
- new JmxRegistry(port, getBindingName(url));
-
- } catch (Exception ex) {
- LOG.log(Level.SEVERE, "CREATE_REGISTRY_FAULT_MSG", new Object[]{ex});
- }
- }
-
- rmiServer = new RMIJRMPServerImpl(getServerPort(serviceUrl), null, null, environment);
-
- // Create the connector server now.
- connectorServer = new RMIConnectorServer(url, environment, rmiServer, server);
-
- if (threaded) {
- // Start the connector server asynchronously (in a separate thread).
- Thread connectorThread = new Thread() {
- public void run() {
- try {
- connectorServer.start();
- remoteServerStub = rmiServer.toStub();
- } catch (IOException ex) {
- LOG.log(Level.SEVERE, "START_CONNECTOR_FAILURE_MSG", new Object[]{ex});
- }
- }
- };
-
- connectorThread.setName("JMX Connector Thread [" + serviceUrl + "]");
- connectorThread.setDaemon(daemon);
- connectorThread.start();
- } else {
- // Start the connector server in the same thread.
- connectorServer.start();
- remoteServerStub = rmiServer.toStub();
- }
-
- if (LOG.isLoggable(Level.INFO)) {
- LOG.info("JMX connector server started: " + connectorServer);
- }
- }
-
- static int getRegistryPort(final String url) {
- int serverStart = url.indexOf("/jndi/rmi://");
- final String serverPart = url.substring(serverStart + 12);
- int portStart = serverPart.indexOf(':') + 1;
-
- int portEnd;
- int port = 0;
- if (portStart > 0) {
- portEnd = indexNotOfNumber(serverPart, portStart);
- if (portEnd > portStart) {
- final String portString = serverPart.substring(portStart, portEnd);
- port = Integer.parseInt(portString);
- }
- }
- return port;
- }
-
- protected static String getBindingName(final JMXServiceURL jmxServiceURL) {
- final String urlPath = jmxServiceURL.getURLPath();
-
- try {
- if (urlPath.startsWith("/jndi/")) {
- return new URI(urlPath.substring(6)).getPath()
- .replaceAll("^/+", "").replaceAll("/+$", "");
- }
- } catch (URISyntaxException e) {
- // ignore
- }
-
- return "jmxrmi"; // use the default
- }
-
- public void destroy() throws IOException {
- connectorServer.stop();
- if (LOG.isLoggable(Level.INFO)) {
- LOG.info("JMX connector server stopped: " + connectorServer);
- }
- }
-
- /*
- * Better to use the internal API than re-invent the wheel.
- */
- @SuppressWarnings("restriction")
- private class JmxRegistry extends sun.rmi.registry.RegistryImpl {
- private final String lookupName;
-
- JmxRegistry(final int port, final String lookupName) throws RemoteException {
- super(port);
- this.lookupName = lookupName;
- }
-
- @Override
- public Remote lookup(String s) throws RemoteException, NotBoundException {
- return lookupName.equals(s) ? remoteServerStub : null;
- }
-
- @Override
- public void bind(String s, Remote remote) throws RemoteException, AlreadyBoundException, AccessException {
- }
-
- @Override
- public void unbind(String s) throws RemoteException, NotBoundException, AccessException {
- }
-
- @Override
- public void rebind(String s, Remote remote) throws RemoteException, AccessException {
- }
-
- @Override
- public String[] list() throws RemoteException {
- return new String[] {lookupName};
- }
- }
-}
diff --git a/rt/management/src/main/java/org/apache/cxf/management/utils/ManagementConsole.java b/rt/management/src/main/java/org/apache/cxf/management/utils/ManagementConsole.java
index 3fa2fe2891c..3739ffaa915 100644
--- a/rt/management/src/main/java/org/apache/cxf/management/utils/ManagementConsole.java
+++ b/rt/management/src/main/java/org/apache/cxf/management/utils/ManagementConsole.java
@@ -42,7 +42,7 @@
public final class ManagementConsole {
private static MBeanServerConnection mbsc;
private static final String DEFAULT_JMXSERVICE_URL =
- "service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi";
+ "service:jmx:rmi:///jndi/rmi://localhost:9913/jmxrmi";
private static final Logger LOG = LogUtils.getL7dLogger(ManagementConsole.class);
String jmxServerURL;
diff --git a/rt/management/src/test/java/org/apache/cxf/management/InstrumentationManagerTest.java b/rt/management/src/test/java/org/apache/cxf/management/InstrumentationManagerTest.java
index 9ebc7ca4fe2..c505835d10a 100644
--- a/rt/management/src/test/java/org/apache/cxf/management/InstrumentationManagerTest.java
+++ b/rt/management/src/test/java/org/apache/cxf/management/InstrumentationManagerTest.java
@@ -158,7 +158,6 @@ public void testInstrumentBusWithBusProperties() {
assertNotNull("Instrumentation Manager of cxf1 should not be null", im1);
assertTrue(im1.isEnabled());
- assertEquals("service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi", im1.getJMXServiceURL());
cxf2 = (Bus)context.getBean("cxf2");
InstrumentationManagerImpl im2 =
@@ -166,7 +165,6 @@ public void testInstrumentBusWithBusProperties() {
assertNotNull("Instrumentation Manager of cxf2 should not be null", im2);
assertFalse(im2.isEnabled());
- assertEquals("service:jmx:rmi:///jndi/rmi://localhost:9913/jmxrmi", im2.getJMXServiceURL());
} finally {
if (cxf1 != null) {
diff --git a/rt/management/src/test/java/org/apache/cxf/management/jmx/BusRegistrationTest.java b/rt/management/src/test/java/org/apache/cxf/management/jmx/BusRegistrationTest.java
index e9f9308289a..6c458f3085b 100644
--- a/rt/management/src/test/java/org/apache/cxf/management/jmx/BusRegistrationTest.java
+++ b/rt/management/src/test/java/org/apache/cxf/management/jmx/BusRegistrationTest.java
@@ -64,12 +64,6 @@ public void tearDown() throws Exception {
}
}
- @Test
- public void testRegisterMultipleBuses() throws Exception {
- // classic external IM-bean
- testRegisterMultipleBuses("managed-spring.xml");
- }
-
@Test
public void testRegisterMultipleBuses2() throws Exception {
// integrated IM configuration in bus
diff --git a/rt/management/src/test/java/org/apache/cxf/management/jmx/JMXManagedComponentManagerTest.java b/rt/management/src/test/java/org/apache/cxf/management/jmx/JMXManagedComponentManagerTest.java
index d516da39c06..20a7b091435 100644
--- a/rt/management/src/test/java/org/apache/cxf/management/jmx/JMXManagedComponentManagerTest.java
+++ b/rt/management/src/test/java/org/apache/cxf/management/jmx/JMXManagedComponentManagerTest.java
@@ -28,7 +28,6 @@
import javax.management.ObjectName;
import org.apache.cxf.management.jmx.export.AnnotationTestInstrumentation;
-import org.apache.cxf.testutil.common.TestUtil;
import org.junit.After;
import org.junit.Before;
@@ -38,17 +37,13 @@
import static org.junit.Assert.fail;
public class JMXManagedComponentManagerTest {
- private static final String PORT = TestUtil.getPortNumber(JMXManagedComponentManagerTest.class);
private static final String NAME_ATTRIBUTE = "Name";
private InstrumentationManagerImpl manager;
@Before
public void setUp() throws Exception {
manager = new InstrumentationManagerImpl();
- manager.setDaemon(false);
- manager.setThreaded(true);
manager.setEnabled(true);
- manager.setJMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + PORT + "/jmxrmi");
manager.init();
//Wait for MBeanServer connector to be initialized on separate thread.
Thread.sleep(2000);
@@ -61,10 +56,6 @@ public void tearDown() throws Exception {
@Test
public void testRegisterInstrumentation() throws Exception {
- //manager.setDaemon(false);
- //manager.setThreaded(false);
- //manager.setJMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9913/jmxrmi");
- //manager.init();
AnnotationTestInstrumentation im = new AnnotationTestInstrumentation();
ObjectName name = new ObjectName("org.apache.cxf:type=foo,name=bar");
@@ -128,13 +119,7 @@ public void testBusLifecycleListener() throws Exception {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
this.manager = new InstrumentationManagerImpl();
- this.manager.setDaemon(false);
- // Turn threading off so that we get the exception in this thread
- // and the manager is set into a failed state if the connector
- // cannot be created.
- this.manager.setThreaded(false);
this.manager.setEnabled(true);
- this.manager.setJMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + PORT + "/jmxrmi");
this.manager.setServer(server);
this.manager.init();
@@ -161,13 +146,7 @@ public void testBusLifecycleListener() throws Exception {
}
this.manager = new InstrumentationManagerImpl();
- this.manager.setDaemon(false);
- // Turn threading off so that we get the exception in this thread
- // and the manager is set into a failed state if the connector
- // cannot be created.
- this.manager.setThreaded(false);
this.manager.setEnabled(true);
- this.manager.setJMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + PORT + "/jmxrmi");
this.manager.setServer(server);
this.manager.init();
@@ -183,4 +162,4 @@ private ObjectName registerStandardMBean(String name) throws Exception {
this.manager.register(hw, oName);
return oName;
}
-}
\ No newline at end of file
+}
diff --git a/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorFactoryTest.java b/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorFactoryTest.java
deleted file mode 100644
index 468ec0cbfaf..00000000000
--- a/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorFactoryTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 org.apache.cxf.management.jmx;
-
-import javax.management.remote.JMXServiceURL;
-
-import org.junit.Assert;
-import org.junit.Test;
-
-
-public class MBServerConnectorFactoryTest {
-
- @Test
- public void testGetServerPort() throws Exception {
- Assert.assertEquals(9914, MBServerConnectorFactory.getServerPort(
- "service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"));
-
- Assert.assertEquals(10002, MBServerConnectorFactory.getServerPort(
- "service:jmx:rmi://localhost:10002/jndi/rmi://localhost:10001/jmxrmi"));
- }
-
- @Test
- public void testGetRegistryPort() throws Exception {
- Assert.assertEquals(9914, MBServerConnectorFactory.getRegistryPort(
- "service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"));
-
- Assert.assertEquals(10001, MBServerConnectorFactory.getRegistryPort(
- "service:jmx:rmi://localhost:10002/jndi/rmi://localhost:10001/jmxrmi"));
- }
-
- @Test
- public void testGetBindingName() throws Exception {
- Assert.assertEquals("jmxrmi", MBServerConnectorFactory.getBindingName(
- new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9913/jmxrmi")));
-
- Assert.assertEquals("cxf-jmxrmi", MBServerConnectorFactory.getBindingName(
- new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:9913/cxf-jmxrmi")));
- }
-}
\ No newline at end of file
diff --git a/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorTest.java b/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorTest.java
deleted file mode 100644
index c01e10fc6f2..00000000000
--- a/rt/management/src/test/java/org/apache/cxf/management/jmx/MBServerConnectorTest.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you 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 org.apache.cxf.management.jmx;
-
-
-
-import javax.management.MBeanServer;
-import javax.management.MBeanServerFactory;
-
-import org.apache.cxf.testutil.common.TestUtil;
-
-import org.junit.Test;
-
-import static org.junit.Assert.fail;
-
-
-public class MBServerConnectorTest {
- private static final String PORT = TestUtil.getPortNumber(MBServerConnectorTest.class);
-
- @Test
- public void testMBServerConnector() {
- MBServerConnectorFactory mcf;
- MBeanServer mbs;
- mbs = MBeanServerFactory.createMBeanServer("test");
- mcf = MBServerConnectorFactory.getInstance();
- mcf.setMBeanServer(mbs);
- mcf.setThreaded(true);
- mcf.setDaemon(true);
- mcf.setServiceUrl("service:jmx:rmi:///jndi/rmi://localhost:" + PORT + "/jmxrmi");
- try {
- mcf.createConnector();
- Thread.sleep(1000);
- mcf.destroy();
- } catch (Exception ex) {
- ex.printStackTrace();
- fail("Some Exception happened to MBServerConnectorTest");
- }
- }
-
-}
diff --git a/rt/management/src/test/resources/managed-spring.xml b/rt/management/src/test/resources/managed-spring.xml
index 81808a54a5a..683c1b3ab32 100644
--- a/rt/management/src/test/resources/managed-spring.xml
+++ b/rt/management/src/test/resources/managed-spring.xml
@@ -24,11 +24,7 @@
xsi:schemaLocation="http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<cxf:bus id="CXF-Test-Bus" bus="cxf"/>
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
- <property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="threaded" value="false"/>
- <property name="daemon" value="false"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"/>
</bean>
<cxf:workqueue name="default" highWaterMark="15" lowWaterMark="5"/>
<cxf:workqueue name="test-wq" highWaterMark="10" lowWaterMark="2"/>
diff --git a/rt/management/src/test/resources/managed-spring3.xml b/rt/management/src/test/resources/managed-spring3.xml
index 83add997fe0..57009b7cf40 100644
--- a/rt/management/src/test/resources/managed-spring3.xml
+++ b/rt/management/src/test/resources/managed-spring3.xml
@@ -26,9 +26,5 @@
<!-- the bus setting at the end should not interfer with the other props -->
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="enabled" value="true"/>
- <property name="threaded" value="false"/>
- <property name="daemon" value="false"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"/>
- <property name="bus" ref="cxf"/>
</bean>
</beans>
\ No newline at end of file
diff --git a/rt/management/src/test/resources/no-connector-spring.xml b/rt/management/src/test/resources/no-connector-spring.xml
index f6c197d9a2c..565d92dffe0 100644
--- a/rt/management/src/test/resources/no-connector-spring.xml
+++ b/rt/management/src/test/resources/no-connector-spring.xml
@@ -24,6 +24,5 @@
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="createMBServerConnectorFactory" value="false"/>
</bean>
</beans>
\ No newline at end of file
diff --git a/rt/ws/rm/src/test/java/org/apache/cxf/ws/rm/managed-manager-bean.xml b/rt/ws/rm/src/test/java/org/apache/cxf/ws/rm/managed-manager-bean.xml
index 8e01539b360..7571a48693d 100644
--- a/rt/ws/rm/src/test/java/org/apache/cxf/ws/rm/managed-manager-bean.xml
+++ b/rt/ws/rm/src/test/java/org/apache/cxf/ws/rm/managed-manager-bean.xml
@@ -26,9 +26,6 @@
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="threaded" value="false"/>
- <property name="daemon" value="false"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"/>
</bean>
<cxf:bus>
<cxf:features>
diff --git a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/ManagedBusTest.java b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/ManagedBusTest.java
index dbde562570a..a40c61d394c 100644
--- a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/ManagedBusTest.java
+++ b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/ManagedBusTest.java
@@ -98,8 +98,6 @@ public void testManagedSpringBus() throws Exception {
assertNotNull(im);
InstrumentationManagerImpl imi = (InstrumentationManagerImpl)im;
- assertEquals("service:jmx:rmi:///jndi/rmi://localhost:9913/jmxrmi",
- imi.getJMXServiceURL());
assertFalse(imi.isEnabled());
assertNull(imi.getMBeanServer());
@@ -127,8 +125,6 @@ private void doManagedBusTest(Bus bus, String expect, String reject, int port) t
InstrumentationManager im = bus.getExtension(InstrumentationManager.class);
assertNotNull(im);
InstrumentationManagerImpl imi = (InstrumentationManagerImpl)im;
- assertEquals("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi",
- imi.getJMXServiceURL());
assertTrue(imi.isEnabled());
assertNotNull(imi.getMBeanServer());
diff --git a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/counter-spring.xml b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/counter-spring.xml
index e5cc90f9a17..b3d516022d9 100644
--- a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/counter-spring.xml
+++ b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/counter-spring.xml
@@ -24,7 +24,6 @@
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:${testutil.ports.CountersClientServerTest.1}/jmxrmi"/>
</bean>
<bean id="org.apache.cxf.management.counters.CounterRepository" class="org.apache.cxf.management.counters.CounterRepository">
<property name="bus" ref="cxf"/>
diff --git a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/managed-bus.xml b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/managed-bus.xml
index 7304a399d39..fed391b4a60 100644
--- a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/managed-bus.xml
+++ b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/managed-bus.xml
@@ -24,7 +24,6 @@
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:${testutil.ports.ManagedBusTest.1}/jmxrmi"/>
</bean>
<bean id="wq" class="org.apache.cxf.workqueue.AutomaticWorkQueueImpl">
<property name="name" value="testQueue"/>
diff --git a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/managed-spring.xml b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/managed-spring.xml
index 4beb120a457..fed391b4a60 100644
--- a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/managed-spring.xml
+++ b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/managed-spring.xml
@@ -24,7 +24,6 @@
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:${testutil.ports.ManagedClientServerTest.1}/jmxrmi"/>
</bean>
<bean id="wq" class="org.apache.cxf.workqueue.AutomaticWorkQueueImpl">
<property name="name" value="testQueue"/>
diff --git a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/persistent-id.xml b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/persistent-id.xml
index 118abfe7978..9219b56bcf3 100644
--- a/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/persistent-id.xml
+++ b/systests/uncategorized/src/test/java/org/apache/cxf/systest/management/persistent-id.xml
@@ -24,7 +24,6 @@
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:${testutil.ports.ManagedBusTest.3}/jmxrmi"/>
<property name="persistentBusId" value="cxf:managed,bus=test"/>
</bean>
<bean id="wq" class="org.apache.cxf.workqueue.AutomaticWorkQueueImpl">
diff --git a/systests/ws-rm/src/test/java/org/apache/cxf/systest/ws/rm/managed-client.xml b/systests/ws-rm/src/test/java/org/apache/cxf/systest/ws/rm/managed-client.xml
index c0cd5b2700a..514038f02b8 100644
--- a/systests/ws-rm/src/test/java/org/apache/cxf/systest/ws/rm/managed-client.xml
+++ b/systests/ws-rm/src/test/java/org/apache/cxf/systest/ws/rm/managed-client.xml
@@ -43,7 +43,5 @@
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="createMBServerConnectorFactory" value="false"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"/>
</bean>
-</beans>
\ No newline at end of file
+</beans>
diff --git a/systests/ws-rm/src/test/java/org/apache/cxf/systest/ws/rm/managed-server.xml b/systests/ws-rm/src/test/java/org/apache/cxf/systest/ws/rm/managed-server.xml
index 823d8f0622e..1ee90cfbae4 100644
--- a/systests/ws-rm/src/test/java/org/apache/cxf/systest/ws/rm/managed-server.xml
+++ b/systests/ws-rm/src/test/java/org/apache/cxf/systest/ws/rm/managed-server.xml
@@ -43,6 +43,5 @@
<bean id="org.apache.cxf.management.InstrumentationManager" class="org.apache.cxf.management.jmx.InstrumentationManagerImpl">
<property name="bus" ref="cxf"/>
<property name="enabled" value="true"/>
- <property name="JMXServiceURL" value="service:jmx:rmi:///jndi/rmi://localhost:9914/jmxrmi"/>
</bean>
-</beans>
\ No newline at end of file
+</beans>

View File

@@ -0,0 +1,49 @@
diff --git a/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java b/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java
index a142548..b7e3549 100644
--- a/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java
+++ b/java-diff-utils/src/main/java/com/github/difflib/text/StringUtils.java
@@ -21,10 +21,10 @@
final class StringUtils {
/**
- * Replaces all opening an closing tags with <code>&lt;</code> or <code>&gt;</code>.
+ * Replaces all opening and closing tags with <code>&lt;</code> or <code>&gt;</code>.
*
* @param str
- * @return
+ * @return str with some HTML meta characters escaped.
*/
public static String htmlEntites(String str) {
return str.replace("<", "&lt;").replace(">", "&gt;");
@@ -61,7 +61,17 @@ public static String wrapText(String line, int columnWidth) {
StringBuilder b = new StringBuilder(line);
for (int count = 0; length > widthIndex; count++) {
- b.insert(widthIndex + delimiter * count, "<br/>");
+ int breakPoint = widthIndex + delimiter * count;
+ if (Character.isHighSurrogate(b.charAt(breakPoint - 1)) &&
+ Character.isLowSurrogate(b.charAt(breakPoint))) {
+ // Shift a breakpoint that would split a supplemental code-point.
+ breakPoint += 1;
+ if (breakPoint == b.length()) {
+ // Break before instead of after if this is the last code-point.
+ breakPoint -= 2;
+ }
+ }
+ b.insert(breakPoint, "<br/>");
widthIndex += columnWidth;
}
diff --git a/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java b/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java
index c4b2acc..6867072 100644
--- a/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java
+++ b/java-diff-utils/src/test/java/com/github/difflib/text/StringUtilsTest.java
@@ -49,6 +49,8 @@ public void testWrapText_String_int() {
assertEquals("te<br/>st", StringUtils.wrapText("test", 2));
assertEquals("tes<br/>t", StringUtils.wrapText("test", 3));
assertEquals("test", StringUtils.wrapText("test", 10));
+ assertEquals(".\uD800\uDC01<br/>.", StringUtils.wrapText(".\uD800\uDC01.", 2));
+ assertEquals("..<br/>\uD800\uDC01", StringUtils.wrapText("..\uD800\uDC01", 3));
}
@Test

View File

@@ -0,0 +1,26 @@
diff -r fcd3ed3394f6 -r 135bdcb88b8d coders/wpg.c
--- a/coders/wpg.c Sun Nov 05 01:11:09 2017 +0100
+++ b/coders/wpg.c Sun Nov 05 01:35:28 2017 +0100
@@ -340,12 +340,15 @@
if(RetVal==MagickFail)
+ {
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"ImportImagePixelArea failed for row: %ld, bpp: %d", y, bpp);
+ return MagickFail;
+ }
- if (!SyncImagePixels(image))
+ if(!SyncImagePixels(image))
{
(void) LogMagickEvent(CoderEvent,GetMagickModule(),"SyncImagePixels failed for row: %ld, bpp: %d", y, bpp);
- RetVal = MagickFail;
+ return MagickFail;
}
return RetVal;

View File

@@ -0,0 +1,94 @@
Index: src/java/test/org/apache/zookeeper/test/ACLTest.java
===================================================================
--- src/java/test/org/apache/zookeeper/test/ACLTest.java (revision 1510080)
+++ src/java/test/org/apache/zookeeper/test/ACLTest.java (working copy)
@@ -28,6 +28,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.PortAssignment;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
@@ -35,8 +36,10 @@
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
+import org.apache.zookeeper.ZooDefs.Perms;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Id;
+import org.apache.zookeeper.data.Stat;
import org.apache.zookeeper.server.ServerCnxnFactory;
import org.apache.zookeeper.server.SyncRequestProcessor;
import org.apache.zookeeper.server.ZooKeeperServer;
@@ -77,6 +80,48 @@
ClientBase.CONNECTION_TIMEOUT));
}
}
+
+ /**
+ * Verify that getAcl should fail when there is not
+ * read permission to that node
+ */
+ @Test
+ public void testAclReadPermission() throws Exception {
+ File tmpDir = ClientBase.createTmpDir();
+ ClientBase.setupTestEnv();
+ ZooKeeperServer zks = new ZooKeeperServer(tmpDir, tmpDir, 3000);
+ SyncRequestProcessor.setSnapCount(1000);
+ final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
+ ServerCnxnFactory f = ServerCnxnFactory.createFactory(PORT, -1);
+ f.startup(zks);
+ ZooKeeper zk;
+ String path = "/node1";
+ boolean readPermLimitWorks = false;
+ try {
+ LOG.info("starting up the zookeeper server .. waiting");
+ Assert.assertTrue("waiting for server being up",
+ ClientBase.waitForServerUp(HOSTPORT, CONNECTION_TIMEOUT));
+ zk = new ZooKeeper(HOSTPORT, CONNECTION_TIMEOUT, this);
+ Id id = new Id("ip", "127.0.0.1");
+ ArrayList<ACL> acl = new ArrayList<ACL>(); // Not set read permission
+ acl.add(new ACL(Perms.CREATE, id));
+ acl.add(new ACL(Perms.DELETE, id));
+ acl.add(new ACL(Perms.WRITE, id));
+ acl.add(new ACL(Perms.ADMIN, id));
+ zk.create(path, path.getBytes(), acl, CreateMode.PERSISTENT);
+ Stat stat = new Stat();
+ zk.getACL(path, stat); // Should cause exception without read permission
+ } catch (KeeperException.NoAuthException e) {
+ readPermLimitWorks = true;
+ } finally {
+ f.shutdown();
+ Assert.assertTrue("waiting for server down",
+ ClientBase.waitForServerDown(HOSTPORT, CONNECTION_TIMEOUT));
+ }
+ if (!readPermLimitWorks) {
+ Assert.fail("Should not reach here as ACL has no read permission");
+ }
+ }
/**
* Verify that acl optimization of storing just
Index: src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java
===================================================================
--- src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java (revision 1510080)
+++ src/java/main/org/apache/zookeeper/server/FinalRequestProcessor.java (working copy)
@@ -324,6 +324,17 @@
GetACLRequest getACLRequest = new GetACLRequest();
ByteBufferInputStream.byteBuffer2Record(request.request,
getACLRequest);
+ DataNode n = zks.getZKDatabase().getNode(getACLRequest.getPath());
+ if (n == null) {
+ throw new KeeperException.NoNodeException();
+ }
+ Long aclL;
+ synchronized(n) {
+ aclL = n.acl;
+ }
+ PrepRequestProcessor.checkACL(zks, zks.getZKDatabase().convertLong(aclL),
+ ZooDefs.Perms.READ,
+ request.authInfo);
Stat stat = new Stat();
List<ACL> acl =
zks.getZKDatabase().getACL(getACLRequest.getPath(), stat);

View File

@@ -0,0 +1,11 @@
--- a.txt
+++ a1.txt
@@ -8,7 +8,7 @@
<Setting>
<Setting a>
<setting b>
- <value>23</value>
+ <value>24</value>
</setting b>
<setting c>
<value>1</value>

View File

@@ -8,4 +8,5 @@ diff -U0 old/f2 new/f2
--- old/f2 2019-09-25 14:38:14.000000000 +0200
+++ new/f2 2019-09-25 14:38:32.000000000 +0200
@@ -1 +1 @@
-a\nc
-a\nc
+a\nb\nd

View File

@@ -0,0 +1,3 @@
diff --git a/test/Issue.java b/test/Issue.java
new file mode 100644
index 00000000..9702606e

View File

@@ -0,0 +1,109 @@
From b53e612a2ab5ff15d14860e252f84c0f343fe93a Mon Sep 17 00:00:00 2001
From: nmancus1 <nmancus1
Date: Thu, 4 Jun 2020 11:46:34 -0400
Subject: [PATCH] minor: Add input file for Java14 instanceof with pattern
matching (#7290)
---
config/ant-phase-verify.xml | 2 +
.../InputJava14InstanceofWithPatternMatching.java | 76 ++++++++++++++++++++++
2 files changed, 78 insertions(+)
create mode 100644 src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/grammar/java14/InputJava14InstanceofWithPatternMatching.java
diff --git a/config/ant-phase-verify.xml b/config/ant-phase-verify.xml
index d27ffef..e0285ce 100644
--- a/config/ant-phase-verify.xml
+++ b/config/ant-phase-verify.xml
@@ -148,6 +148,8 @@
<exclude name="**/InputMainFrameModelIncorrectClass.java"/>
<exclude name="**/InputBeforeExecutionExclusionFileFilterIncorrectClass.java"/>
<exclude name="**/InputJavaParser.java"/>
+ <!-- until https://github.com/checkstyle/checkstyle/issues/7290 -->
+ <exclude name="**/InputJava14InstanceofWithPatternMatching.java"/>
<!-- Cannot parse until Java 14 support -->
<exclude name="**/InputJava14Records.java"/>
</fileset>
diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/grammar/java14/InputJava14InstanceofWithPatternMatching.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/grammar/java14/InputJava14InstanceofWithPatternMatching.java
new file mode 100644
index 0000000..8fa3eba
--- /dev/null
+++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/grammar/java14/InputJava14InstanceofWithPatternMatching.java
@@ -0,0 +1,76 @@
+//non-compiled with javac: Compilable with Java14
+package com.puppycrawl.tools.checkstyle.grammar.java14;
+
+import java.util.Arrays;
+import java.util.Locale;
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ ...... I removed it
+ }
+ }
+}
--
2.7.4

View File

@@ -0,0 +1,31 @@
# HG changeset patch
# User Anton Shestakov <av6@dwimlabs.net>
# Date 1591442367 -28800
# Node ID a4438263b228dd3e2983d59095c6180b1411f0e8
# Parent 83e41b73d115e3717943c2e5a83d36d05670384c
tests: skip pyflakes for mercurial/thirdparty/
The current version of pyflakes (2.2.0) correctly detects one issue:
mercurial/thirdparty/selectors2.py:335:40 '...'.format(...) has unused arguments at position(s): 1
But we're not interested in fixing lint errors in third-party code, so we need
to exclude at least selectors2.py. And in the discussion for this patch it was
decided to just skip the entire thirdparty directory.
Differential Revision: https://phab.mercurial-scm.org/D8619
diff -r 83e41b73d115 -r a4438263b228 tests/test-check-pyflakes.t
--- a/tests/test-check-pyflakes.t Tue Jun 09 17:13:26 2020 -0400
+++ b/tests/test-check-pyflakes.t Sat Jun 06 19:19:27 2020 +0800
@@ -16,9 +16,7 @@
$ testrepohg locate 'set:**.py or grep("^#!.*python")' \
> -X hgext/fsmonitor/pywatchman \
> -X mercurial/pycompat.py -X contrib/python-zstandard \
- > -X mercurial/thirdparty/cbor \
- > -X mercurial/thirdparty/concurrent \
- > -X mercurial/thirdparty/zope \
+ > -X mercurial/thirdparty \
> 2>/dev/null \
> | xargs $PYTHON -m pyflakes 2>/dev/null | "$TESTDIR/filterpyflakes.py"
contrib/perf.py:*:* undefined name 'xrange' (glob) (?)

View File

@@ -0,0 +1,55 @@
From fd940c6f66126734e82c00889e7c987e11deea91 Mon Sep 17 00:00:00 2001
From: Tomas Bjerre <tomas.bjerre85@gmail.com>
Date: Sun, 6 Sep 2020 11:20:34 +0200
Subject: [PATCH] removing file
---
.../violations/lib/model/ViolationTest.java | 37 -------------------
1 file changed, 37 deletions(-)
delete mode 100644 src/test/java/se/bjurr/violations/lib/model/ViolationTest.java
diff --git a/src/test/java/se/bjurr/violations/lib/model/ViolationTest.java b/src/test/java/se/bjurr/violations/lib/model/ViolationTest.java
deleted file mode 100644
index 3e40b52..0000000
--- a/src/test/java/se/bjurr/violations/lib/model/ViolationTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package se.bjurr.violations.lib.model;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static se.bjurr.violations.lib.model.SEVERITY.ERROR;
-import static se.bjurr.violations.lib.model.Violation.violationBuilder;
-import static se.bjurr.violations.lib.reports.Parser.CHECKSTYLE;
-
-import org.junit.Test;
-import se.bjurr.violations.lib.model.Violation.ViolationBuilder;
-import uk.co.jemos.podam.api.PodamFactoryImpl;
-
-public class ViolationTest {
-
- @Test
- public void testThatFilePathsAreAlwaysFronSlashes() {
- final Violation violation =
- violationBuilder() //
- .setParser(CHECKSTYLE) //
- .setFile("c:\\path\\to\\file.xml") //
- .setMessage("message") //
- .setSeverity(ERROR) //
- .setStartLine(1) //
- .build();
- assertThat(violation.getFile()) //
- .isEqualTo("c:/path/to/file.xml");
- }
-
- @Test
- public void testThatCopyConstructorWorks() {
- final ViolationBuilder originalBuilder =
- new PodamFactoryImpl().manufacturePojo(ViolationBuilder.class);
- final Violation original = originalBuilder.build();
- final Violation copied = new Violation(original);
- assertThat(copied) //
- .isEqualTo(original);
- }
-}
--
2.25.1

View File

@@ -0,0 +1,291 @@
From 9b73f79a2436760b8278377014bf78a144a427ae Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Thu, 1 Feb 2018 14:26:22 +0100
Subject: [PATCH 15/23] make Samba data tool configurable
Allow to specify an alternative path to Samba's net utility at configure
time and at run time.
https://bugs.freedesktop.org/show_bug.cgi?id=100118
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
---
configure.ac | 13 ++++++++++++
doc/adcli.xml | 21 ++++++++++++++++++-
doc/samba_data_tool_path.xml.in | 1 +
library/adenroll.c | 46 ++++++++++++++++++++++++++++++++++-------
library/adenroll.h | 5 +++++
tools/computer.c | 16 ++++++++++++++
7 files changed, 95 insertions(+), 8 deletions(-)
create mode 100644 doc/samba_data_tool_path.xml.in
diff --git a/configure.ac b/configure.ac
index fe86638..68877c7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -291,6 +291,18 @@ else
AC_DEFINE_UNQUOTED(BIN_ECHO, "$BIN_ECHO", [path to echo, used in unit test])
fi
+AC_MSG_CHECKING([where is Samba's net utility])
+AC_ARG_WITH([samba_data_tool],
+ AC_HELP_STRING([--with-samba-data-tool=/path],
+ [Path to Samba's net utility]),
+ [],
+ [with_samba_data_tool=/usr/bin/net])
+AC_MSG_RESULT([$with_samba_data_tool])
+
+AC_DEFINE_UNQUOTED(SAMBA_DATA_TOOL, "$with_samba_data_tool",
+ [Path to Samba's net utility])
+
+AC_SUBST(SAMBA_DATA_TOOL, [$with_samba_data_tool])
# ---------------------------------------------------------------------
ADCLI_LT_RELEASE=$ADCLI_CURRENT:$ADCLI_REVISION:$ADCLI_AGE
@@ -300,6 +312,7 @@ AC_CONFIG_FILES([Makefile
build/Makefile
doc/Makefile
doc/version.xml
+ doc/samba_data_tool_path.xml
library/Makefile
tools/Makefile
])
diff --git a/doc/adcli.xml b/doc/adcli.xml
index fbc6c63..c2b7760 100644
--- a/doc/adcli.xml
+++ b/doc/adcli.xml
@@ -1,6 +1,9 @@
<?xml version='1.0'?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
- "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+ "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd"
+[
+ <!ENTITY samba_data_tool SYSTEM "samba_data_tool_path.xml">
+]>
<refentry id="adcli">
@@ -307,6 +310,14 @@ Password for Administrator:
<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
+ <listitem><para>If Samba's <command>net</command>
+ cannot be found at
+ <filename>&samba_data_tool;</filename> this option can
+ be used to specific an alternative location with the
+ help of an absolute path.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -412,6 +423,14 @@ $ adcli update --login-ccache=/tmp/krbcc_123
<citerefentry><refentrytitle>smb.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--samba-data-tool=<parameter>/path/to/net</parameter></option></term>
+ <listitem><para>If Samba's <command>net</command>
+ cannot be found at
+ <filename>&samba_data_tool;</filename> this option can
+ be used to specific an alternative location with the
+ help of an absolute path.</para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/doc/samba_data_tool_path.xml.in b/doc/samba_data_tool_path.xml.in
new file mode 100644
index 0000000..a667c57
--- /dev/null
+++ b/doc/samba_data_tool_path.xml.in
@@ -0,0 +1 @@
+@SAMBA_DATA_TOOL@
diff --git a/library/adenroll.c b/library/adenroll.c
index 20731cd..a693049 100644
--- a/library/adenroll.c
+++ b/library/adenroll.c
@@ -42,6 +42,10 @@
#include <stdio.h>
#include <unistd.h>
+#ifndef SAMBA_DATA_TOOL
+#define SAMBA_DATA_TOOL "/usr/bin/net"
+#endif
+
static krb5_enctype v60_later_enctypes[] = {
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
@@ -100,6 +104,7 @@ struct _adcli_enroll {
int keytab_enctypes_explicit;
unsigned int computer_password_lifetime;
int computer_password_lifetime_explicit;
+ char *samba_data_tool;
};
static adcli_result
@@ -1537,26 +1542,33 @@ static adcli_result
update_samba_data (adcli_enroll *enroll)
{
int ret;
- char *argv_pw[] = { "/usr/bin/net", "changesecretpw", "-i", "-f", NULL };
- char *argv_sid[] = { "/usr/bin/net", "setdomainsid", NULL, NULL };
+ char *argv_pw[] = { NULL, "changesecretpw", "-i", "-f", NULL };
+ char *argv_sid[] = { NULL, "setdomainsid", NULL, NULL };
+
+ argv_pw[0] = (char *) adcli_enroll_get_samba_data_tool (enroll);
+ if (argv_pw[0] ==NULL) {
+ _adcli_err ("Samba data tool not available.");
+ return ADCLI_ERR_FAIL;
+ }
+ argv_sid[0] = argv_pw[0];
- _adcli_info ("Trying to set Samba secret.\n");
+ _adcli_info ("Trying to set Samba secret.");
ret = _adcli_call_external_program (argv_pw[0], argv_pw,
enroll->computer_password, NULL, NULL);
if (ret != ADCLI_SUCCESS) {
- _adcli_err ("Failed to set Samba computer account password.\n");
+ _adcli_err ("Failed to set Samba computer account password.");
}
argv_sid[2] = (char *) adcli_conn_get_domain_sid (enroll->conn);
if (argv_sid[2] == NULL) {
- _adcli_err ("Domain SID not available.\n");
+ _adcli_err ("Domain SID not available.");
} else {
- _adcli_info ("Trying to set domain SID %s for Samba.\n",
+ _adcli_info ("Trying to set domain SID %s for Samba.",
argv_sid[2]);
ret = _adcli_call_external_program (argv_sid[0], argv_sid,
NULL, NULL, NULL);
if (ret != ADCLI_SUCCESS) {
- _adcli_err ("Failed to set Samba domain SID.\n");
+ _adcli_err ("Failed to set Samba domain SID.");
}
}
@@ -1951,6 +1963,9 @@ adcli_enroll_new (adcli_conn *conn)
enroll->os_name = strdup (value);
return_val_if_fail (enroll->os_name != NULL, NULL);
+ enroll->samba_data_tool = strdup (SAMBA_DATA_TOOL);
+ return_val_if_fail (enroll->samba_data_tool != NULL, NULL);
+
return enroll;
}
@@ -1978,6 +1993,7 @@ enroll_free (adcli_enroll *enroll)
free (enroll->os_name);
free (enroll->os_version);
free (enroll->os_service_pack);
+ free (enroll->samba_data_tool);
free (enroll->user_principal);
_adcli_strv_free (enroll->service_names);
@@ -2343,3 +2359,19 @@ adcli_enroll_set_computer_password_lifetime (adcli_enroll *enroll,
enroll->computer_password_lifetime_explicit = 1;
}
+
+void
+adcli_enroll_set_samba_data_tool (adcli_enroll *enroll, const char *value)
+{
+ return_if_fail (enroll != NULL);
+ if (value != NULL && value[0] != '\0') {
+ _adcli_str_set (&enroll->samba_data_tool, value);
+ }
+}
+
+const char *
+adcli_enroll_get_samba_data_tool (adcli_enroll *enroll)
+{
+ return_val_if_fail (enroll != NULL, NULL);
+ return enroll->samba_data_tool;
+}
diff --git a/library/adenroll.h b/library/adenroll.h
index 32c9764..31ca0bc 100644
--- a/library/adenroll.h
+++ b/library/adenroll.h
@@ -141,4 +141,9 @@ const char * adcli_enroll_get_os_service_pack (adcli_enroll *enroll);
void adcli_enroll_set_os_service_pack (adcli_enroll *enroll,
const char *value);
+void adcli_enroll_set_samba_data_tool (adcli_enroll *enroll,
+ const char *value);
+
+const char * adcli_enroll_get_samba_data_tool (adcli_enroll *enroll);
+
#endif /* ADENROLL_H_ */
diff --git a/tools/computer.c b/tools/computer.c
index fc646f2..f86548b 100644
--- a/tools/computer.c
+++ b/tools/computer.c
@@ -30,6 +30,7 @@
#include <err.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
static void
dump_details (adcli_conn *conn,
@@ -107,6 +108,7 @@ typedef enum {
opt_user_principal,
opt_computer_password_lifetime,
opt_add_samba_data,
+ opt_samba_data_tool,
} Option;
static adcli_tool_desc common_usages[] = {
@@ -145,6 +147,7 @@ static adcli_tool_desc common_usages[] = {
"successful join" },
{ opt_add_samba_data, "add domain SID and computer account password\n"
"to the Samba specific configuration database" },
+ { opt_samba_data_tool, "Absolute path to the tool used for add-samba-data" },
{ opt_verbose, "show verbose progress and failure messages", },
{ 0 },
};
@@ -160,6 +163,7 @@ parse_option (Option opt,
static int stdin_password = 0;
char *endptr;
unsigned int lifetime;
+ int ret;
switch (opt) {
case opt_login_ccache:
@@ -265,6 +269,16 @@ parse_option (Option opt,
adcli_enroll_set_computer_password_lifetime (enroll, lifetime);
return;
+ case opt_samba_data_tool:
+ errno = 0;
+ ret = access (optarg, X_OK);
+ if (ret != 0) {
+ ret = errno;
+ errx (EUSAGE, "Failed to access tool to add Samba data: %s", strerror (ret));
+ } else {
+ adcli_enroll_set_samba_data_tool (enroll, optarg);
+ }
+ return;
case opt_verbose:
return;
@@ -331,6 +345,7 @@ adcli_tool_computer_join (adcli_conn *conn,
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+ { "samba-data-tool", no_argument, NULL, opt_samba_data_tool },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
{ 0 },
@@ -434,6 +449,7 @@ adcli_tool_computer_update (adcli_conn *conn,
{ "show-details", no_argument, NULL, opt_show_details },
{ "show-password", no_argument, NULL, opt_show_password },
{ "add-samba-data", no_argument, NULL, opt_add_samba_data },
+ { "samba-data-tool", no_argument, NULL, opt_samba_data_tool },
{ "verbose", no_argument, NULL, opt_verbose },
{ "help", no_argument, NULL, 'h' },
{ 0 },
--
2.14.4

View File

@@ -0,0 +1,8 @@
handlers=java.util.logging.ConsoleHandler
.level=INFO
com.github.difflib.unifieddiff.level=INFO
java.util.logging.ConsoleHandler.level=INFO
#java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter

View File

@@ -0,0 +1,29 @@
--- Origin.java 2020-06-11 11:06:21.000000000 +0800
+++ Update.java 2020-06-11 10:59:48.000000000 +0800
@@ -1,9 +1,17 @@
package checkstyle_demo.PatchSuppression.MultiChangeInOneFile;
-public class Origin {
+public class Update {
public void test1() {
}
+
+ public void test2() {
+
+ }
+
+ public void test3() {
+
+ }
}
class BasicTest {
@@ -16,5 +24,7 @@
class Test2 {
public void test1() {
System.out.println();
+ System.out.println();
+ System.out.println();
}
}

View File

@@ -0,0 +1,30 @@
package checkstyle_demo.PatchSuppression.MultiChangeInOneFile;
public class issue89_revised {
public void test1() {
}
public void test2() {
}
public void test3() {
}
}
class Test {
private int i;
void foo() {
i++;
}
}
class Test2 {
public void test1() {
System.out.println();
System.out.println();
System.out.println();
}
}

View File

@@ -1,174 +1,164 @@
/*
Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
This file is part of Java Diff Utills Library.
* Copyright 2009-2017 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;
Java Diff Utills Library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Java Diff Utills Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Java Diff Utills Library. If not, see <http://www.gnu.org/licenses/>.
*/
package difflib;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import difflib.myers.*;
import com.github.difflib.algorithm.DiffAlgorithmI;
import com.github.difflib.algorithm.DiffAlgorithmListener;
import com.github.difflib.algorithm.myers.MyersDiff;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.Patch;
import com.github.difflib.patch.PatchFailedException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.BiPredicate;
/**
* Implements the difference and patching engine
*
* @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a>
* @version 0.4.1
*/
public class DiffUtils {
private static DiffAlgorithm defaultDiffAlgorithm = new MyersDiff();
private static Pattern unifiedDiffChunkRe =
Pattern.compile("@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@");
/**
* Compute the difference between the original and revised texts with default diff algorithm
*
* @param original the original text
* @param revised the revised text
* @return the patch describing the difference between the original and revised texts
*/
public static Patch diff(List<?> original, List<?> revised) {
return DiffUtils.diff(original, revised, defaultDiffAlgorithm);
}
/**
* Compute the difference between the original and revised texts with given diff algorithm
*
* @param original the original text
* @param revised the revised text
* @param algorithm the given algorithm
* @return the patch describing the difference between the original and revised texts
*/
public static Patch diff(List<?> original, List<?> revised, DiffAlgorithm algorithm) {
return algorithm.diff(original, revised);
}
/**
* Patch the original text with given patch
*
* @param original the original text
* @param patch the given patch
* @return the revised text
* @throws PatchFailedException if can't apply patch
*/
public static List<?> patch(List<?> original, Patch patch) throws PatchFailedException {
return patch.applyTo(original);
}
/**
* Unpatch the revised text for a given patch
*
* @param revised the revised text
* @param patch the given patch
* @return the original text
*/
public static List<?> unpatch(List<?> revised, Patch patch) {
return patch.restore(revised);
}
/**
* Parse the given text in unified format and creates the list of deltas for it.
*
* @param diff the text in unified format
* @return the patch with deltas.
*/
public static Patch parseUnifiedDiff(List<String> diff) {
boolean inPrelude = true;
List<Object[]> rawChunk = new ArrayList<Object[]>();
Patch patch = new Patch();
int old_ln = 0, old_n = 0, new_ln = 0, new_n = 0;
String tag = "", rest = "";
for (String line: diff) {
// Skip leading lines until after we've seen one starting with '+++'
if (inPrelude) {
if (line.startsWith("+++")) {
inPrelude = false;
}
continue;
}
Matcher m = unifiedDiffChunkRe.matcher(line);
if (m.find()) {
// Process the lines in the previous chunk
if (rawChunk.size() != 0) {
List<String> oldChunkLines = new ArrayList<String>();
List<String> newChunkLines = new ArrayList<String>();
for (Object[] raw_line: rawChunk) {
tag = (String)raw_line[0];
rest = (String)raw_line[1];
if (tag.equals(" ") || tag.equals("-")) {
oldChunkLines.add(rest);
}
if (tag.equals(" ") || tag.equals("+")) {
newChunkLines.add(rest);
}
}
patch.addDelta(new ChangeDelta(new Chunk(old_ln - 1, old_n, oldChunkLines),
new Chunk(new_ln - 1, new_n, newChunkLines)));
rawChunk.clear();
}
// Parse the @@ header
old_ln = m.group(1) == null ? 1 : Integer.parseInt(m.group(1));
old_n = m.group(2) == null ? 1 : Integer.parseInt(m.group(2));
new_ln = m.group(3) == null ? 1 : Integer.parseInt(m.group(3));
new_n = m.group(4) == null ? 1 : Integer.parseInt(m.group(4));
old_ln = Integer.parseInt(m.group(1));
if (old_ln == 0) {
old_ln += 1;
}
if (new_ln == 0) {
new_ln += 1;
}
} else {
if (line.length() > 0) {
tag = line.substring(0, 1);
rest = line.substring(1);
if (tag.equals(" ") || tag.equals("+") || tag.equals("-")) {
rawChunk.add(new Object[] {tag, rest});
}
}
}
}
// Process the lines in the last chunk
if (rawChunk.size() != 0) {
List<String> oldChunkLines = new ArrayList<String>();
List<String> newChunkLines = new ArrayList<String>();
for (Object[] raw_line: rawChunk) {
tag = (String)raw_line[0];
rest = (String)raw_line[1];
if (tag.equals(" ") || tag.equals("-")) {
oldChunkLines.add(rest);
}
if (tag.equals(" ") || tag.equals("+")) {
newChunkLines.add(rest);
}
}
patch.addDelta(new ChangeDelta(new Chunk(old_ln - 1, old_n, oldChunkLines),
new Chunk(new_ln - 1, new_n, newChunkLines)));
rawChunk.clear();
}
return patch;
}
public final class DiffUtils {
/**
* Computes the difference between the original and revised list of elements with default diff
* algorithm
*
* @param <T> types to be diffed
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param progress progress listener
* @return The patch describing the difference between the original and revised sequences. Never
* {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmListener progress) {
return DiffUtils.diff(original, revised, new MyersDiff<>(), progress);
}
public static <T> Patch<T> diff(List<T> original, List<T> revised) {
return DiffUtils.diff(original, revised, new MyersDiff<>(), null);
}
public static <T> Patch<T> diff(List<T> original, List<T> revised, boolean includeEqualParts) {
return DiffUtils.diff(original, revised, new MyersDiff<>(), null, includeEqualParts);
}
/**
* Computes the difference between the original and revised text.
*/
public static Patch<String> diff(String sourceText, String targetText,
DiffAlgorithmListener progress) {
return DiffUtils.diff(
Arrays.asList(sourceText.split("\n")),
Arrays.asList(targetText.split("\n")), progress);
}
/**
* Computes the difference between the original and revised list of elements with default diff
* algorithm
*
* @param source The original text. Must not be {@code null}.
* @param target The revised text. Must not be {@code null}.
*
* @param equalizer the equalizer object to replace the default compare algorithm
* (Object.equals). If {@code null} the default equalizer of the default algorithm is used..
* @return The patch describing the difference between the original and revised sequences. Never
* {@code null}.
*/
public static <T> Patch<T> diff(List<T> source, List<T> target,
BiPredicate<T, T> equalizer) {
if (equalizer != null) {
return DiffUtils.diff(source, target,
new MyersDiff<>(equalizer));
}
return DiffUtils.diff(source, target, new MyersDiff<>());
}
public static <T> Patch<T> diff(List<T> original, List<T> revised,
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress) {
return diff(original, revised, algorithm, progress, false);
}
/**
* Computes the difference between the original and revised list of elements with default diff
* algorithm
*
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param algorithm The diff algorithm. Must not be {@code null}.
* @param progress The diff algorithm listener.
* @param includeEqualParts Include equal data parts into the patch.
* @return The patch describing the difference between the original and revised sequences. Never
* {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised,
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress,
boolean includeEqualParts) {
Objects.requireNonNull(original, "original must not be null");
Objects.requireNonNull(revised, "revised must not be null");
Objects.requireNonNull(algorithm, "algorithm must not be null");
return Patch.generate(original, revised, algorithm.computeDiff(original, revised, progress), includeEqualParts);
}
/**
* Computes the difference between the original and revised list of elements with default diff
* algorithm
*
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param algorithm The diff algorithm. Must not be {@code null}.
* @return The patch describing the difference between the original and revised sequences. Never
* {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmI<T> algorithm) {
return diff(original, revised, algorithm, null);
}
private static List<String> compressLines(List<String> lines, String delimiter) {
if (lines.isEmpty()) {
return Collections.emptyList();
}
return Collections.singletonList(String.join(delimiter, lines));
}
/**
* Patch the original text with given patch
*
* @param original the original text
* @param patch the given patch
* @return the revised text
* @throws PatchFailedException if can't apply patch
*/
public static <T> List<T> patch(List<T> original, Patch<T> patch)
throws PatchFailedException {
return patch.applyTo(original);
}
/**
* Unpatch the revised text for a given patch
*
* @param revised the revised text
* @param patch the given patch
* @return the original text
*/
public static <T> List<T> unpatch(List<T> revised, Patch<T> patch) {
return patch.restore(revised);
}
private DiffUtils() {
}
}

View File

@@ -1,308 +1,190 @@
/*
Copyright 2009 Dmitry Naumenko (dm.naumenko@gmail.com)
This file is part of Java Diff Utils Library.
* Copyright 2009-2017 java-diff-utills.
*
* 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;
Java Diff Utils Library is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Java Diff Utils Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Java Diff Utils Library. If not, see <http://www.gnu.org/licenses/>.
*/
package difflib;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import difflib.myers.*;
import com.github.difflib.algorithm.DiffAlgorithmI;
import com.github.difflib.algorithm.DiffAlgorithmListener;
import com.github.difflib.algorithm.myers.MyersDiff;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.Patch;
import com.github.difflib.patch.PatchFailedException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.BiPredicate;
/**
* Implements the difference and patching engine
*
* @author <a href="dm.naumenko@gmail.com">Dmitry Naumenko</a>
* @version 0.4.1
*/
public class DiffUtils {
private static DiffAlgorithm defaultDiffAlgorithm = new MyersDiff();
private static Pattern unifiedDiffChunkRe =
Pattern.compile("@@\\s+-(?:(\\d+)(?:,(\\d+))?)\\s+\\+(?:(\\d+)(?:,(\\d+))?)\\s+@@");
/**
* Compute the difference between the original and revised texts with default diff algorithm
*
* @param original the original text
* @param revised the revised text
* @return the patch describing the difference between the original and revised texts
*/
public static Patch diff(List<?> original, List<?> revised) {
return DiffUtils.diff(original, revised, defaultDiffAlgorithm);
}
/**
* Compute the difference between the original and revised texts with given diff algorithm
*
* @param original the original text
* @param revised the revised text
* @param algorithm the given algorithm
* @return the patch describing the difference between the original and revised texts
*/
public static Patch diff(List<?> original, List<?> revised, DiffAlgorithm algorithm) {
return algorithm.diff(original, revised);
}
/**
* Patch the original text with given patch
*
* @param original the original text
* @param patch the given patch
* @return the revised text
* @throws PatchFailedException if can't apply patch
*/
public static List<?> patch(List<?> original, Patch patch) throws PatchFailedException {
return patch.applyTo(original);
}
/**
* Unpatch the revised text for a given patch
*
* @param revised the revised text
* @param patch the given patch
* @return the original text
*/
public static List<?> unpatch(List<?> revised, Patch patch) {
return patch.restore(revised); // bla-bla-bla
}
/**
* Parse the given text in unified format and creates the list of deltas for it.
*
* @param diff the text in unified format
* @return the patch with deltas.
*/
public static Patch parseUnifiedDiff(List<String> diff) {
boolean inPrelude = true;
List<Object[]> rawChunk = new ArrayList<Object[]>();
Patch patch = new Patch();
int old_ln = 0, old_n = 0, new_ln = 0, new_n = 0;
String tag = "", rest = "";
for (String line: diff) {
// Skip leading lines until after we've seen one starting with '+++'
if (inPrelude) {
if (line.startsWith("+++")) {
inPrelude = false;
}
continue;
}
Matcher m = unifiedDiffChunkRe.matcher(line);
if (m.find()) {
// Process the lines in the previous chunk
if (rawChunk.size() != 0) {
List<String> oldChunkLines = new ArrayList<String>();
List<String> newChunkLines = new ArrayList<String>();
for (Object[] raw_line: rawChunk) {
tag = (String)raw_line[0];
rest = (String)raw_line[1];
if (tag.equals(" ") || tag.equals("-")) {
oldChunkLines.add(rest);
}
if (tag.equals(" ") || tag.equals("+")) {
newChunkLines.add(rest);
}
}
patch.addDelta(new ChangeDelta(new Chunk(old_ln - 1, old_n, oldChunkLines),
new Chunk(new_ln - 1, new_n, newChunkLines)));
rawChunk.clear();
}
// Parse the @@ header
old_ln = m.group(1) == null ? 1 : Integer.parseInt(m.group(1));
old_n = m.group(2) == null ? 1 : Integer.parseInt(m.group(2));
new_ln = m.group(3) == null ? 1 : Integer.parseInt(m.group(3));
new_n = m.group(4) == null ? 1 : Integer.parseInt(m.group(4));
old_ln = Integer.parseInt(m.group(1));
if (old_ln == 0) {
old_ln += 1;
}
if (new_ln == 0) {
new_ln += 1;
}
} else {
if (line.length() > 0) {
tag = line.substring(0, 1);
rest = line.substring(1);
if (tag.equals(" ") || tag.equals("+") || tag.equals("-")) {
rawChunk.add(new Object[] {tag, rest});
}
}
}
}
// Process the lines in the last chunk
if (rawChunk.size() != 0) {
List<String> oldChunkLines = new ArrayList<String>();
List<String> newChunkLines = new ArrayList<String>();
for (Object[] raw_line: rawChunk)
{
tag = (String)raw_line[0];
rest = (String)raw_line[1];
if (tag.equals(" ") || tag.equals("-"))
{
oldChunkLines.add(rest);
}
if (tag.equals(" ") || tag.equals("+"))
{
newChunkLines.add(rest);
}
}
patch.addDelta(new ChangeDelta(new Chunk(old_ln - 1, old_n, oldChunkLines),
new Chunk(new_ln - 1, new_n, newChunkLines)));
rawChunk.clear();
}
return patch;
}
public final class DiffUtills {
/**
* generateUnifiedDiff takes a Patch and some other arguments, returning the Unified Diff format text representing the Patch.
* @author Bill James (tankerbay@gmail.com)
*
* @param fname1 - Filename of the original (unrevised file)
* @param fname2 - Filename of the revised file
* @param originalLines - Lines of the original file
* @param patch - Patch created by the diff() function
* @param contextSize - number of lines of context output around each difference in the file.
* @return List of strings representing the Unified Diff representation of the Patch argument.
*/
public static List<String> generateUnifiedDiff(String fname1, String fname2, List<String> originalLines, Patch patch, int contextSize ) {
List<String> ret = new ArrayList<String>();
ret.add( "--- " + fname1 );
ret.add( "+++ " + fname2 );
List<Delta> cur = new ArrayList<Delta>(); // current list of Delta's to process
int deltact = patch.getDeltas().size();
// if there's more than 1 Delta, we may need to output them together
if ( deltact > 1 ) {
Delta curDelta = patch.getDelta(0);
cur.add( curDelta ); // add the first Delta to the current set
for ( int i = 1; i < deltact; i++ ) {
int curpos = curDelta.getOriginal().getPosition(); // store the current position of the first Delta
Delta nextDelta = patch.getDelta(i); // Check if the next Delta is too close to the current position
if ( (curpos + curDelta.getOriginal().getSize() + contextSize) >= ( nextDelta.getOriginal().getPosition()-contextSize ) ) {
cur.add( nextDelta ); // if it is, add it to the current set
} else {
List<String> curBlock = processDeltas( originalLines, cur, contextSize );
ret.addAll( curBlock ); // if it isn't, output the current set, then create a new
cur.clear(); // set and add the current Delta to it.
cur.add( nextDelta );
}
curDelta = nextDelta;
}
List<String> curBlock = processDeltas( originalLines, cur, contextSize ); // don't forget to process the last set of Deltas
ret.addAll( curBlock );
/**
* Computes the difference between the original and revised list of elements with default diff
* algorithm
*
* @param <T> types to be diffed
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param progress progress listener
* @return The patch describing the difference between the original and revised sequences. Never
* {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmListener progress) {
return DiffUtils.diff(original, revised, new MyersDiff<>(), progress);
}
public static <T> Patch<T> diff(List<T> original, List<T> revised) {
return DiffUtils.diff(original, revised, new MyersDiff<>(), null);
}
public static <T> Patch<T> diff(List<T> original, List<T> revised, boolean includeEqualParts) {
return DiffUtils.diff(original, revised, new MyersDiff<>(), null, includeEqualParts);
}
/**
* Computes the difference between the original and revised text.
*/
public static Patch<String> diff(String sourceText, String targetText,
DiffAlgorithmListener progress) {
return DiffUtils.diff(
Arrays.asList(sourceText.split("\n")),
Arrays.asList(targetText.split("\n")), progress);
}
/**
* Computes the difference between the original and revised list of elements with default diff
* algorithm
*
* @param source The original text. Must not be {@code null}.
* @param target The revised text. Must not be {@code null}.
*
* @param equalizer the equalizer object to replace the default compare algorithm
* (Object.equals). If {@code null} the default equalizer of the default algorithm is used..
* @return The patch describing the difference between the original and revised sequences. Never
* {@code null}.
*/
public static <T> Patch<T> diff(List<T> source, List<T> target,
BiPredicate<T, T> equalizer) {
if (equalizer != null) {
return DiffUtils.diff(source, target,
new MyersDiff<>(equalizer));
}
return DiffUtils.diff(source, target, new MyersDiff<>());
}
return ret;
}
public static <T> Patch<T> diff(List<T> original, List<T> revised,
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress) {
return diff(original, revised, algorithm, progress, false);
}
/**
* Computes the difference between the original and revised list of elements with default diff
* algorithm
*
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param algorithm The diff algorithm. Must not be {@code null}.
* @param progress The diff algorithm listener.
* @param includeEqualParts Include equal data parts into the patch.
* @return The patch describing the difference between the original and revised sequences. Never
* {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised,
DiffAlgorithmI<T> algorithm, DiffAlgorithmListener progress,
boolean includeEqualParts) {
Objects.requireNonNull(original, "original must not be null");
Objects.requireNonNull(revised, "revised must not be null");
Objects.requireNonNull(algorithm, "algorithm must not be null"); /* BLA BLA BLA */
/**
* processDeltas takes a list of Deltas and outputs them together in a single block of Unified-Diff-format text.
* @author Bill James (tankerbay@gmail.com)
*
* @param origLines - the lines of the original file
* @param deltas - the Deltas to be output as a single block
* @param contextSize - the number of lines of context to place around block
return Patch.generate(original, revised, algorithm.computeDiff(original, revised, progress), includeEqualParts);
}
/**
* Computes the difference between the original and revised list of elements with default diff
* algorithm
*
* @param original The original text. Must not be {@code null}.
* @param revised The revised text. Must not be {@code null}.
* @param algorithm The diff algorithm. Must not be {@code null}.
* @return The patch describing the difference between the original and revised sequences. Never
* {@code null}.
*/
public static <T> Patch<T> diff(List<T> original, List<T> revised, DiffAlgorithmI<T> algorithm) {
return diff(original, revised, algorithm, null);
}
/**
* Computes the difference between the given texts inline. This one uses the "trick" to make out
* of texts lists of characters, like DiffRowGenerator does and merges those changes at the end
* together again.
*
* @param original
* @param revised
* @return
*/
private static List<String> processDeltas( List<String> origLines, List<Delta> deltas, int contextSize ) {
List<String> buffer = new ArrayList<String>();
int origTotal = 0; // counter for total lines output from Original
int revTotal = 0; // counter for total lines output from Original
int line;
Delta curDelta = deltas.get(0); // start with the first Delta
int origStart = curDelta.getOriginal().getPosition()+1 - contextSize; // note the +1 to overcome the 0-offset Position
if ( origStart < 1 ) origStart = 1; // clamp to the start of the file
int revStart = curDelta.getRevised().getPosition()+1 - contextSize; // note the +1 to overcome the 0-offset Position
if ( revStart < 1 ) revStart = 1; // clamp to the start of the file
int contextStart = curDelta.getOriginal().getPosition() - contextSize; // find the start of the wrapper context code
if ( contextStart < 0 ) contextStart = 0; // clamp to the start of the file
for ( line = contextStart; line < curDelta.getOriginal().getPosition(); line++ ) { // output the context before the first Delta
buffer.add( " " + origLines.get( line ) );
origTotal++;
revTotal++;
public static Patch<String> diffInline(String original, String revised) {
List<String> origList = new ArrayList<>();
List<String> revList = new ArrayList<>();
for (Character character : original.toCharArray()) {
origList.add(character.toString());
}
buffer.addAll( getDeltaText( curDelta ) ); // output the first Delta
origTotal += curDelta.getOriginal().getLines().size();
revTotal += curDelta.getRevised().getLines().size();
int deltaIndex = 1;
while ( deltaIndex < deltas.size() ) { // for each of the other Deltas
Delta nextDelta = deltas.get( deltaIndex );
int intermediateStart = curDelta.getOriginal().getPosition() + curDelta.getOriginal().getLines().size();
for ( line = intermediateStart; line < nextDelta.getOriginal().getPosition(); line++ ) {
buffer.add( " " + origLines.get( line ) ); // output the code between the last Delta and this one
origTotal++;
revTotal++;
}
buffer.addAll( getDeltaText( nextDelta ) ); // output the Delta
origTotal += nextDelta.getOriginal().getLines().size();
revTotal += nextDelta.getRevised().getLines().size();
curDelta = nextDelta;
deltaIndex++; // increment the iterator
for (Character character : revised.toCharArray()) {
revList.add(character.toString());
}
// Now output the post-Delta context code, clamping the end of the file
contextStart = curDelta.getOriginal().getPosition() + curDelta.getOriginal().getLines().size();
for ( line = contextStart; ( line < (contextStart + contextSize )) && ( line < origLines.size() ); line++ ) {
buffer.add( " " + origLines.get( line ) );
origTotal++;
revTotal++;
Patch<String> patch = DiffUtils.diff(origList, revList);
for (AbstractDelta<String> delta : patch.getDeltas()) {
delta.getSource().setLines(compressLines(delta.getSource().getLines(), ""));
delta.getTarget().setLines(compressLines(delta.getTarget().getLines(), ""));
}
return patch;
}
// Create and insert the block header, conforming to the Unified Diff standard
StringBuffer header = new StringBuffer();
header.append( "@@ -" );
header.append( origStart );
header.append( "," );
header.append( origTotal );
header.append( " +" );
header.append( revStart );
header.append( "," );
header.append( revTotal );
header.append( " @@" );
buffer.add( 0, header.toString() );
return buffer;
}
/**
* getDeltaText returns the lines to be added to the Unified Diff text from the Delta parameter
* @author Bill James (tankerbay@gmail.com)
*
* @param delta - the Delta to output
* @return list of String lines of code.
*/
private static List<String> getDeltaText( Delta delta ) {
List<String> buffer = new ArrayList<String>();
for ( Object line: delta.getOriginal().getLines() ) {
buffer.add( "-" + line );
private static List<String> compressLines(List<String> lines, String delimiter) {
if (lines.isEmpty()) {
return Collections.emptyList();
}
for ( Object line: delta.getRevised().getLines() ) {
buffer.add( "+" + line );
}
return buffer;
}
return Collections.singletonList(String.join(delimiter, lines));
}
/**
* Patch the original text with given patch
*
* @param original the original text
* @param patch the given patch
* @return the revised text
* @throws PatchFailedException if can't apply patch
*/
public static <T> List<T> patch(List<T> original, Patch<T> patch)
throws PatchFailedException {
return patch.applyTo(original);
}
/**
* Unpatch the revised text for a given patch
*
* @param revised the revised text
* @param patch the given patch
* @return the original text
*/
public static <T> List<T> unpatch(List<T> revised, Patch<T> patch) {
return patch.restore(revised);
}
private DiffUtils() {
}
}

38
pom.xml
View File

@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.java-diff-utils</groupId>
<artifactId>java-diff-utils-parent</artifactId>
<version>4.5</version>
<version>4.12</version>
<name>java-diff-utils-parent</name>
<packaging>pom</packaging>
<modules>
@@ -12,7 +12,7 @@
</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>
<inceptionYear>2009</inceptionYear>
<distributionManagement>
<repository>
@@ -29,7 +29,7 @@
<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-parent-4.5</tag>
<tag>java-diff-utils-parent-4.12</tag>
</scm>
<issueManagement>
<system>GitHub Issues</system>
@@ -60,6 +60,22 @@
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.19.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
@@ -89,9 +105,10 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<version>3.1.1</version>
<configuration>
<additionalparam>${javadoc.opts}</additionalparam>
<doclint>none</doclint>
</configuration>
<executions>
<execution>
@@ -105,7 +122,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.17</version>
<version>3.1.0</version>
<executions>
<execution>
<id>verify-style</id>
@@ -118,12 +135,13 @@
<configuration>
<logViolationsToConsole>true</logViolationsToConsole>
<includeTestSourceDirectory>true</includeTestSourceDirectory>
<sourceDirectory>${project.build.sourceDirectory}</sourceDirectory>
<sourceDirectories>${project.build.sourceDirectory}</sourceDirectories>
<checkstyleRules>
<module name="Checker">
<module name="SuppressWarningsFilter" />
<module name="FileTabCharacter" />
<module name="TreeWalker">
<module name="SuppressionCommentFilter" />
<module name="AvoidNestedBlocks" />
<module name="ConstantName" />
<module name="EmptyCatchBlock" />
@@ -151,14 +169,14 @@
<dependency>
<groupId>com.puppycrawl.tools</groupId>
<artifactId>checkstyle</artifactId>
<version>8.18</version>
<version>8.29</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
<version>3.0.0-M4</version>
<configuration>
<excludes>
<exclude>**/LR*.java</exclude>
@@ -181,7 +199,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.4</version>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
@@ -224,4 +242,4 @@
</build>
</profile>
</profiles>
</project>
</project>