/* * 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); error.hh = null; // We don't assert the hunk header as it is a // complex object with lots of internal state. assertEquals(error, new PatchApplier.Result.Error( "cannot apply hunk", "allowconflict", null, true)); 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); error.hh = null; // We don't assert the hunk header as it is a // complex object with lots of internal state. assertEquals(error, new PatchApplier.Result.Error( "cannot apply hunk", "ConflictOutOfBounds", null, true)); 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"); } } }