diff options
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.java | 988 |
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"); + } + } +} |