aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java')
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java988
1 files changed, 988 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java
new file mode 100644
index 0000000000..5507f8572d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchApplierTest.java
@@ -0,0 +1,988 @@
+/*
+ * Copyright (C) 2022, Google Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.patch;
+
+import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
+import org.eclipse.jgit.annotations.Nullable;
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.attributes.FilterCommand;
+import org.eclipse.jgit.attributes.FilterCommandFactory;
+import org.eclipse.jgit.attributes.FilterCommandRegistry;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.patch.PatchApplier.Result;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.IO;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+
+@RunWith(Suite.class)
+@Suite.SuiteClasses({ PatchApplierTest.WithWorktree.class, //
+ PatchApplierTest.InCore.class, //
+})
+public class PatchApplierTest {
+
+ public abstract static class Base extends RepositoryTestCase {
+
+ protected String name;
+
+ /** data before patching. */
+ protected byte[] preImage;
+ /** expected data after patching. */
+ protected byte[] postImage;
+
+ protected String expectedText;
+ protected RevTree baseTip;
+ public boolean inCore;
+
+ Base(boolean inCore) {
+ this.inCore = inCore;
+ }
+
+ void init(final String aName) throws Exception {
+ init(aName, true, true);
+ }
+
+ protected void init(String aName, boolean preExists, boolean postExists)
+ throws Exception {
+ // Patch and pre/postimage are read from data
+ // org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/
+ this.name = aName;
+ if (postExists) {
+ expectedText = initPostImage(aName);
+ }
+
+ if (preExists) {
+ initPreImage(aName);
+ }
+ try (Git git = new Git(db)) {
+ RevCommit base = git.commit().setMessage("PreImage").call();
+ baseTip = base.getTree();
+ }
+ }
+
+ protected void initPreImage(String aName) throws Exception {
+ preImage = IO
+ .readWholeStream(getTestResource(aName + "_PreImage"), 0)
+ .array();
+ addFile(aName, preImage);
+ }
+
+ protected void addFile(String aName, byte[] b) throws Exception {
+ File f = new File(db.getWorkTree(), aName);
+ Files.write(f.toPath(), b);
+ try (Git git = new Git(db)) {
+ git.add().addFilepattern(aName).call();
+ }
+ }
+
+ protected String initPostImage(String aName) throws Exception {
+ postImage = IO
+ .readWholeStream(getTestResource(aName + "_PostImage"), 0)
+ .array();
+ return new String(postImage, StandardCharsets.UTF_8);
+ }
+
+ protected Result applyPatch() throws IOException {
+ try (InputStream patchStream = getTestResource(name + ".patch")) {
+ Patch patch = new Patch();
+ patch.parse(patchStream);
+ if (inCore) {
+ try (ObjectInserter oi = db.newObjectInserter()) {
+ return new PatchApplier(db, baseTip, oi).applyPatch(patch);
+ }
+ }
+ return new PatchApplier(db).applyPatch(patch);
+ }
+ }
+
+ protected Result applyPatchAllowConflicts() throws IOException {
+ InputStream patchStream = getTestResource(name + ".patch");
+ Patch patch = new Patch();
+ patch.parse(patchStream);
+ if (inCore) {
+ try (ObjectInserter oi = db.newObjectInserter()) {
+ return new PatchApplier(db, baseTip, oi).allowConflicts()
+ .applyPatch(patch);
+ }
+ }
+ return new PatchApplier(db).allowConflicts()
+ .applyPatch(patch);
+ }
+
+ protected static InputStream getTestResource(String patchFile) {
+ return PatchApplierTest.class.getClassLoader()
+ .getResourceAsStream("org/eclipse/jgit/diff/" + patchFile);
+ }
+
+ void verifyChange(Result result, String aName) throws Exception {
+ verifyChange(result, aName, true);
+ }
+
+ protected void verifyContent(Result result, String path, boolean exists)
+ throws Exception {
+ verifyContent(result, path, exists ? expectedText : null);
+ }
+
+ protected void verifyContent(Result result, String path,
+ @Nullable String expectedContent) throws Exception {
+ if (inCore) {
+ byte[] output = readBlob(result.getTreeId(), path);
+ if (expectedContent == null)
+ assertNull(output);
+ else {
+ assertNotNull(output);
+ assertEquals(expectedContent,
+ new String(output, StandardCharsets.UTF_8));
+ }
+ } else {
+ File f = new File(db.getWorkTree(), path);
+ if (expectedContent == null)
+ assertFalse(f.exists());
+ else
+ checkFile(f, expectedContent);
+ }
+ }
+
+ void verifyChange(Result result, String aName, boolean exists)
+ throws Exception {
+ assertEquals(0, result.getErrors().size());
+ assertEquals(1, result.getPaths().size());
+ verifyContent(result, aName, exists);
+ }
+
+ void verifyChange(Result result, String aName, boolean exists,
+ int numConflicts) throws Exception {
+ assertEquals(numConflicts, result.getErrors().size());
+ assertEquals(1, result.getPaths().size());
+ verifyContent(result, aName, exists);
+ }
+
+ protected byte[] readBlob(ObjectId treeish, String path)
+ throws Exception {
+ try (TestRepository<?> tr = new TestRepository<>(db);
+ RevWalk rw = tr.getRevWalk()) {
+ db.incrementOpen();
+ RevTree tree = rw.parseTree(treeish);
+ try (TreeWalk tw = TreeWalk.forPath(db, path, tree)) {
+ if (tw == null) {
+ return null;
+ }
+ return tw.getObjectReader()
+ .open(tw.getObjectId(0), OBJ_BLOB).getBytes();
+ }
+ }
+ }
+
+ protected void checkBinary(Result result, int numberOfFiles)
+ throws Exception {
+ assertEquals(0, result.getErrors().size());
+ assertEquals(numberOfFiles, result.getPaths().size());
+ if (inCore) {
+ assertArrayEquals(postImage,
+ readBlob(result.getTreeId(), result.getPaths().get(0)));
+ } else {
+ File f = new File(db.getWorkTree(), name);
+ assertArrayEquals(postImage, Files.readAllBytes(f.toPath()));
+ }
+ }
+
+ /* tests */
+
+ @Test
+ public void testBinaryDelta() throws Exception {
+ init("delta");
+ checkBinary(applyPatch(), 1);
+ }
+
+ @Test
+ public void testBinaryLiteral() throws Exception {
+ init("literal");
+ checkBinary(applyPatch(), 1);
+ }
+
+ @Test
+ public void testBinaryLiteralAdd() throws Exception {
+ init("literal_add", false, true);
+ checkBinary(applyPatch(), 1);
+ }
+
+ @Test
+ public void testModifyM2() throws Exception {
+ init("M2", true, true);
+
+ Result result = applyPatch();
+
+ if (!inCore && FS.DETECTED.supportsExecute()) {
+ assertEquals(1, result.getPaths().size());
+ File f = new File(db.getWorkTree(), result.getPaths().get(0));
+ assertTrue(FS.DETECTED.canExecute(f));
+ }
+
+ verifyChange(result, "M2");
+ }
+
+ @Test
+ public void testModifyM3() throws Exception {
+ init("M3", true, true);
+
+ Result result = applyPatch();
+
+ verifyChange(result, "M3");
+ if (!inCore && FS.DETECTED.supportsExecute()) {
+ File f = new File(db.getWorkTree(), result.getPaths().get(0));
+ assertFalse(FS.DETECTED.canExecute(f));
+ }
+ }
+
+ @Test
+ public void testModifyX() throws Exception {
+ init("X");
+
+ Result result = applyPatch();
+ verifyChange(result, "X");
+ }
+
+ @Test
+ public void testModifyY() throws Exception {
+ init("Y");
+
+ Result result = applyPatch();
+
+ verifyChange(result, "Y");
+ }
+
+ @Test
+ public void testModifyZ() throws Exception {
+ init("Z");
+
+ Result result = applyPatch();
+ verifyChange(result, "Z");
+ }
+
+ @Test
+ public void testNonASCII() throws Exception {
+ init("NonASCII");
+
+ Result result = applyPatch();
+ verifyChange(result, "NonASCII");
+ }
+
+ @Test
+ public void testNonASCII2() throws Exception {
+ init("NonASCII2");
+
+ Result result = applyPatch();
+ verifyChange(result, "NonASCII2");
+ }
+
+ @Test
+ public void testNonASCIIAdd() throws Exception {
+ init("NonASCIIAdd");
+
+ Result result = applyPatch();
+ verifyChange(result, "NonASCIIAdd");
+ }
+
+ @Test
+ public void testNonASCIIAdd2() throws Exception {
+ init("NonASCIIAdd2", false, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "NonASCIIAdd2");
+ }
+
+ @Test
+ public void testNonASCIIDel() throws Exception {
+ init("NonASCIIDel", true, false);
+
+ Result result = applyPatch();
+ verifyChange(result, "NonASCIIDel", false);
+ assertEquals("NonASCIIDel", result.getPaths().get(0));
+ }
+
+ @Test
+ public void testRenameNoHunks() throws Exception {
+ init("RenameNoHunks", true, true);
+
+ Result result = applyPatch();
+
+ assertEquals(2, result.getPaths().size());
+ assertTrue(result.getPaths().contains("RenameNoHunks"));
+ assertTrue(result.getPaths().contains("nested/subdir/Renamed"));
+
+ verifyContent(result, "nested/subdir/Renamed", true);
+ }
+
+ @Test
+ public void testRenameWithHunks() throws Exception {
+ init("RenameWithHunks", true, true);
+
+ Result result = applyPatch();
+ assertEquals(2, result.getPaths().size());
+ assertTrue(result.getPaths().contains("RenameWithHunks"));
+ assertTrue(result.getPaths().contains("nested/subdir/Renamed"));
+
+ verifyContent(result, "nested/subdir/Renamed", true);
+ }
+
+ @Test
+ public void testCopyWithHunks() throws Exception {
+ init("CopyWithHunks", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "CopyResult", true);
+ }
+
+ @Test
+ public void testConflictMarkers() throws Exception {
+ init("allowconflict", true, true);
+
+ Result result = applyPatchAllowConflicts();
+
+ assertEquals(result.getErrors().size(), 1);
+ PatchApplier.Result.Error error = result.getErrors().get(0);
+ assertEquals("cannot apply hunk", error.msg);
+ assertEquals("allowconflict", error.oldFileName);
+ assertTrue(error.isGitConflict());
+ verifyChange(result, "allowconflict", true, 1);
+ }
+
+ @Test
+ public void testConflictMarkersOutOfBounds() throws Exception {
+ init("ConflictOutOfBounds", true, true);
+
+ Result result = applyPatchAllowConflicts();
+
+ assertEquals(result.getErrors().size(), 1);
+ PatchApplier.Result.Error error = result.getErrors().get(0);
+ assertEquals("cannot apply hunk", error.msg);
+ assertEquals("ConflictOutOfBounds", error.oldFileName);
+ assertTrue(error.isGitConflict());
+ verifyChange(result, "ConflictOutOfBounds", true, 1);
+ }
+
+ @Test
+ public void testConflictMarkersFileDeleted() throws Exception {
+ init("allowconflict_file_deleted", false, false);
+
+ Result result = applyPatchAllowConflicts();
+
+ assertEquals(1, result.getErrors().size());
+ assertEquals(0, result.getPaths().size());
+ }
+
+ @Test
+ public void testShiftUp() throws Exception {
+ init("ShiftUp");
+
+ Result result = applyPatch();
+ verifyChange(result, "ShiftUp");
+ }
+
+ @Test
+ public void testShiftUp2() throws Exception {
+ init("ShiftUp2");
+
+ Result result = applyPatch();
+ verifyChange(result, "ShiftUp2");
+ }
+
+ @Test
+ public void testShiftDown() throws Exception {
+ init("ShiftDown");
+
+ Result result = applyPatch();
+ verifyChange(result, "ShiftDown");
+ }
+
+ @Test
+ public void testShiftDown2() throws Exception {
+ init("ShiftDown2");
+
+ Result result = applyPatch();
+ verifyChange(result, "ShiftDown2");
+ }
+
+ @Test
+ public void testAddAlreadyExistingFile() throws Exception {
+ addFile("M1", "existing content".getBytes(StandardCharsets.UTF_8));
+ init("M1", false, false);
+
+ Result result = applyPatch();
+
+ assertEquals(1, result.getErrors().size());
+ assertEquals(0, result.getPaths().size());
+ }
+
+ @Test
+ public void testDeleteNonexistentFile() throws Exception {
+ init("NonASCIIDel", false, false);
+
+ Result result = applyPatch();
+
+ assertEquals(1, result.getErrors().size());
+ assertEquals(0, result.getPaths().size());
+ }
+
+ @Test
+ public void testModifyNonexistentFile() throws Exception {
+ init("ShiftDown", false, true);
+
+ Result result = applyPatch();
+
+ assertEquals(1, result.getErrors().size());
+ assertEquals(0, result.getPaths().size());
+ }
+
+ @Test
+ public void testRenameNonexistentFile() throws Exception {
+ init("RenameNoHunks", false, true);
+
+ Result result = applyPatch();
+
+ assertEquals(1, result.getErrors().size());
+ assertEquals(0, result.getPaths().size());
+ }
+
+ @Test
+ public void testCopyNonexistentFile() throws Exception {
+ init("CopyWithHunks", false, true);
+
+ Result result = applyPatch();
+
+ assertEquals(1, result.getErrors().size());
+ assertEquals(0, result.getPaths().size());
+ }
+
+ @Test
+ public void testCopyOnTopAlreadyExistingFile() throws Exception {
+ addFile("CopyResult", "existing content".getBytes(StandardCharsets.UTF_8));
+ init("CopyWithHunks", true, false);
+
+ Result result = applyPatch();
+
+ assertEquals(1, result.getErrors().size());
+ assertEquals(0, result.getPaths().size());
+ }
+
+ @Test
+ public void testDoesNotAffectUnrelatedFiles() throws Exception {
+ initPreImage("Unaffected");
+ String expectedUnaffectedText = initPostImage("Unaffected");
+ init("X");
+
+ Result result = applyPatch();
+ verifyChange(result, "X");
+ verifyContent(result, "Unaffected", expectedUnaffectedText);
+ }
+
+ @Test
+ public void testConflictFails() throws Exception {
+ init("conflict");
+
+ Result result = applyPatch();
+ assertEquals(1, result.getErrors().size());
+ }
+ }
+
+ public static class InCore extends Base {
+
+ public InCore() {
+ super(true);
+ }
+
+ @Test
+ public void testNoNewlineAtEnd() throws Exception {
+ init("x_d");
+
+ Result result = applyPatch();
+ verifyChange(result, "x_d");
+ }
+
+ @Test
+ public void testNoNewlineAtEndInHunk() throws Exception {
+ init("x_e");
+
+ Result result = applyPatch();
+ verifyChange(result, "x_e");
+ }
+
+ @Test
+ public void testAddNewlineAtEnd() throws Exception {
+ init("x_add_nl");
+
+ Result result = applyPatch();
+ verifyChange(result, "x_add_nl");
+ }
+
+ @Test
+ public void testRemoveNewlineAtEnd() throws Exception {
+ init("x_last_rm_nl");
+
+ Result result = applyPatch();
+ verifyChange(result, "x_last_rm_nl");
+ }
+
+ @Test
+ public void testVeryLongFile() throws Exception {
+ init("very_long_file");
+
+ Result result = applyPatch();
+ verifyChange(result, "very_long_file");
+ }
+ }
+
+ public static class WithWorktree extends Base {
+ public WithWorktree() {
+ super(false);
+ }
+
+ @Test
+ public void testModifyNL1() throws Exception {
+ init("NL1");
+
+ Result result = applyPatch();
+ verifyChange(result, "NL1");
+ }
+
+ @Test
+ public void testCrLf() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+ init("crlf", true, true);
+
+ Result result = applyPatch();
+
+ verifyChange(result, "crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testCrLfOff() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+ init("crlf", true, true);
+
+ Result result = applyPatch();
+
+ verifyChange(result, "crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testCrLfEmptyCommitted() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+ init("crlf3", true, true);
+
+ Result result = applyPatch();
+
+ verifyChange(result, "crlf3");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testCrLfNewFile() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+ init("crlf4", false, true);
+
+ Result result = applyPatch();
+
+ verifyChange(result, "crlf4");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testPatchWithCrLf() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+ init("crlf2", true, true);
+
+ Result result = applyPatch();
+
+ verifyChange(result, "crlf2");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testPatchWithCrLf2() throws Exception {
+ String aName = "crlf2";
+ try (Git git = new Git(db)) {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+ init(aName, true, true);
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ Result result = applyPatch();
+
+ verifyChange(result, aName);
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndAutoCRLF_true() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ init("x_d_crlf", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_d_crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndAutoCRLF_false() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+
+ init("x_d", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_d");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndAutoCRLF_input() throws Exception {
+ try {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input");
+
+ init("x_d", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_d");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndInHunkAutoCRLF_true() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ init("x_e_crlf", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_e_crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndInHunkAutoCRLF_false() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+
+ init("x_e", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_e");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testNoNewlineAtEndInHunkAutoCRLF_input() throws Exception {
+ try {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input");
+
+ init("x_e", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_e");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testAddNewlineAtEndAutoCRLF_true() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ init("x_add_nl_crlf", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_add_nl_crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testAddNewlineAtEndAutoCRLF_false() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+
+ init("x_add_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_add_nl");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testAddNewlineAtEndAutoCRLF_input() throws Exception {
+ try {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input");
+
+ init("x_add_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_add_nl");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testRemoveNewlineAtEndAutoCRLF_true() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
+
+ init("x_last_rm_nl_crlf", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_last_rm_nl_crlf");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testRemoveNewlineAtEndAutoCRLF_false() throws Exception {
+ try {
+ db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+
+ init("x_last_rm_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_last_rm_nl");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testRemoveNewlineAtEndAutoCRLF_input() throws Exception {
+ try {
+ db.getConfig().setString(ConfigConstants.CONFIG_CORE_SECTION,
+ null, ConfigConstants.CONFIG_KEY_AUTOCRLF, "input");
+
+ init("x_last_rm_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "x_last_rm_nl");
+ } finally {
+ db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF);
+ }
+ }
+
+ @Test
+ public void testEditNoNewline() throws Exception {
+ init("z_e_no_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "z_e_no_nl");
+ }
+
+ @Test
+ public void testEditAddNewline() throws Exception {
+ init("z_e_add_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "z_e_add_nl");
+ }
+
+ @Test
+ public void testEditRemoveNewline() throws Exception {
+ init("z_e_rm_nl", true, true);
+
+ Result result = applyPatch();
+ verifyChange(result, "z_e_rm_nl");
+ }
+
+ // Clean/smudge filter for testFiltering. The smudgetest test resources
+ // were created with C git using a clean filter sed -e "s/A/E/g" and the
+ // smudge filter sed -e "s/E/A/g". To keep the test independent of the
+ // presence of sed, implement this with a built-in filter.
+ private static class ReplaceFilter extends FilterCommand {
+
+ private final char toReplace;
+
+ private final char replacement;
+
+ ReplaceFilter(InputStream in, OutputStream out, char toReplace,
+ char replacement) {
+ super(in, out);
+ this.toReplace = toReplace;
+ this.replacement = replacement;
+ }
+
+ @Override
+ public int run() throws IOException {
+ int b = in.read();
+ if (b < 0) {
+ in.close();
+ out.close();
+ return -1;
+ }
+ if ((b & 0xFF) == toReplace) {
+ b = replacement;
+ }
+ out.write(b);
+ return 1;
+ }
+ }
+
+ @Test
+ public void testFiltering() throws Exception {
+ // Set up filter
+ FilterCommandFactory clean =
+ (repo, in, out) -> new ReplaceFilter(in, out, 'A', 'E');
+ FilterCommandFactory smudge =
+ (repo, in, out) -> new ReplaceFilter(in, out, 'E', 'A');
+ FilterCommandRegistry.register("jgit://builtin/a2e/clean", clean);
+ FilterCommandRegistry.register("jgit://builtin/a2e/smudge", smudge);
+ Config config = db.getConfig();
+ try (Git git = new Git(db)) {
+ config.setString(ConfigConstants.CONFIG_FILTER_SECTION, "a2e",
+ "clean", "jgit://builtin/a2e/clean");
+ config.setString(ConfigConstants.CONFIG_FILTER_SECTION, "a2e",
+ "smudge", "jgit://builtin/a2e/smudge");
+ write(new File(db.getWorkTree(), ".gitattributes"),
+ "smudgetest filter=a2e");
+ git.add().addFilepattern(".gitattributes").call();
+ git.commit().setMessage("Attributes").call();
+ init("smudgetest", true, true);
+
+ Result result = applyPatch();
+
+ verifyChange(result, name);
+ } finally {
+ config.unset(ConfigConstants.CONFIG_FILTER_SECTION, "a2e",
+ "clean");
+ config.unset(ConfigConstants.CONFIG_FILTER_SECTION, "a2e",
+ "smudge");
+ // Tear down filter
+ FilterCommandRegistry.unregister("jgit://builtin/a2e/clean");
+ FilterCommandRegistry.unregister("jgit://builtin/a2e/smudge");
+ }
+ }
+
+ private void dotGitTest(String fileName) throws Exception {
+ init(fileName, false, false);
+ Result result = null;
+ IOException ex = null;
+ try {
+ result = applyPatch();
+ } catch (IOException e) {
+ ex = e;
+ }
+ assertTrue(ex != null
+ || (result != null && !result.getErrors().isEmpty()));
+ File b = new File(new File(trash, ".git"), "b");
+ assertFalse(".git/b should not exist", b.exists());
+ }
+
+ @Test
+ public void testDotGit() throws Exception {
+ dotGitTest("dotgit");
+ }
+
+ @Test
+ public void testDotGit2() throws Exception {
+ dotGitTest("dotgit2");
+ }
+ }
+}