blob: 0513da2d155674c1e8b00b9c5370d59d49d05277 [file] [log] [blame]
/*
* Copyright (C) 2016, 2022 Christian Halstrick <christian.halstrick@sap.com> 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.util;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.MergeResult;
import org.eclipse.jgit.api.errors.GitAPIException;
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.lib.Constants;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;
public class FilterCommandsTest extends RepositoryTestCase {
private Git git;
RevCommit initialCommit;
RevCommit secondCommit;
class TestCommandFactory implements FilterCommandFactory {
private int prefix;
public TestCommandFactory(int prefix) {
this.prefix = prefix;
}
@Override
public FilterCommand create(Repository repo, InputStream in,
final OutputStream out) {
FilterCommand cmd = new FilterCommand(in, out) {
@Override
public int run() throws IOException {
int b = in.read();
if (b == -1) {
in.close();
out.close();
return b;
}
out.write(prefix);
out.write(b);
return 1;
}
};
return cmd;
}
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
git = new Git(db);
// commit something
writeTrashFile("Test.txt", "Hello world");
git.add().addFilepattern("Test.txt").call();
initialCommit = git.commit().setMessage("Initial commit").call();
// create a master branch and switch to it
git.branchCreate().setName("test").call();
RefUpdate rup = db.updateRef(Constants.HEAD);
rup.link("refs/heads/test");
// commit something on the test branch
writeTrashFile("Test.txt", "Some change");
git.add().addFilepattern("Test.txt").call();
secondCommit = git.commit().setMessage("Second commit").call();
}
@Override
public void tearDown() throws Exception {
Set<String> existingFilters = new HashSet<>(
FilterCommandRegistry.getRegisteredFilterCommands());
existingFilters.forEach(FilterCommandRegistry::unregister);
super.tearDown();
}
@Test
public void testBuiltinCleanFilter() throws Exception {
String builtinCommandName = "jgit://builtin/test/clean";
FilterCommandRegistry.register(builtinCommandName,
new TestCommandFactory('c'));
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "test", "clean", builtinCommandName);
config.save();
writeTrashFile(".gitattributes", "*.txt filter=test");
git.add().addFilepattern(".gitattributes").call();
git.commit().setMessage("add filter").call();
File testFile = writeTrashFile("Test.txt", "Hello again");
// Wait a little bit to ensure that the call with setRenormalize(false)
// below doesn't consider the file "racily clean".
fsTick(testFile);
git.add().addFilepattern("Test.txt").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=test]"
+ "[Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
indexState(CONTENT));
writeTrashFile("Test.bin", "Hello again");
git.add().addFilepattern("Test.bin").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=test]"
+ "[Test.bin, mode:100644, content:Hello again]"
+ "[Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
indexState(CONTENT));
config.setString("filter", "test", "clean", null);
config.save();
git.add().addFilepattern("Test.txt").setRenormalize(false).call();
assertEquals("No index update expected with renormalize==false",
"[.gitattributes, mode:100644, content:*.txt filter=test]"
+ "[Test.bin, mode:100644, content:Hello again]"
+ "[Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
indexState(CONTENT));
git.add().addFilepattern("Test.txt").call();
assertEquals("Index update expected with renormalize==true",
"[.gitattributes, mode:100644, content:*.txt filter=test]"
+ "[Test.bin, mode:100644, content:Hello again]"
+ "[Test.txt, mode:100644, content:Hello again]",
indexState(CONTENT));
}
@Test
public void testBuiltinSmudgeFilter() throws IOException, GitAPIException {
String builtinCommandName = "jgit://builtin/test/smudge";
FilterCommandRegistry.register(builtinCommandName,
new TestCommandFactory('s'));
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "test", "smudge", builtinCommandName);
config.save();
writeTrashFile(".gitattributes", "*.txt filter=test");
git.add().addFilepattern(".gitattributes").call();
git.commit().setMessage("add filter").call();
writeTrashFile("Test.txt", "Hello again");
git.add().addFilepattern("Test.txt").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=test][Test.txt, mode:100644, content:Hello again]",
indexState(CONTENT));
assertEquals("Hello again", read("Test.txt"));
deleteTrashFile("Test.txt");
git.checkout().addPath("Test.txt").call();
assertEquals("sHseslslsos sasgsasisn", read("Test.txt"));
writeTrashFile("Test.bin", "Hello again");
git.add().addFilepattern("Test.bin").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:Hello again]",
indexState(CONTENT));
deleteTrashFile("Test.bin");
git.checkout().addPath("Test.bin").call();
assertEquals("Hello again", read("Test.bin"));
config.setString("filter", "test", "clean", null);
config.save();
git.add().addFilepattern("Test.txt").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:sHseslslsos sasgsasisn]",
indexState(CONTENT));
config.setString("filter", "test", "clean", null);
config.save();
}
@Test
public void testBuiltinCleanAndSmudgeFilter() throws IOException, GitAPIException {
String builtinCommandPrefix = "jgit://builtin/test/";
FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
new TestCommandFactory('s'));
FilterCommandRegistry.register(builtinCommandPrefix + "clean",
new TestCommandFactory('c'));
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "test", "smudge", builtinCommandPrefix+"smudge");
config.setString("filter", "test", "clean",
builtinCommandPrefix + "clean");
config.save();
writeTrashFile(".gitattributes", "*.txt filter=test");
git.add().addFilepattern(".gitattributes").call();
git.commit().setMessage("add filter").call();
writeTrashFile("Test.txt", "Hello again");
git.add().addFilepattern("Test.txt").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=test][Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
indexState(CONTENT));
assertEquals("Hello again", read("Test.txt"));
deleteTrashFile("Test.txt");
git.checkout().addPath("Test.txt").call();
assertEquals("scsHscsescslscslscsoscs scsascsgscsascsiscsn",
read("Test.txt"));
writeTrashFile("Test.bin", "Hello again");
git.add().addFilepattern("Test.bin").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:cHceclclcoc cacgcacicn]",
indexState(CONTENT));
deleteTrashFile("Test.bin");
git.checkout().addPath("Test.bin").call();
assertEquals("Hello again", read("Test.bin"));
config.setString("filter", "test", "clean", null);
config.save();
git.add().addFilepattern("Test.txt").call();
assertEquals(
"[.gitattributes, mode:100644, content:*.txt filter=test][Test.bin, mode:100644, content:Hello again][Test.txt, mode:100644, content:scsHscsescslscslscsoscs scsascsgscsascsiscsn]",
indexState(CONTENT));
config.setString("filter", "test", "clean", null);
config.save();
}
@Test
public void testBranchSwitch() throws Exception {
String builtinCommandPrefix = "jgit://builtin/test/";
FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
new TestCommandFactory('s'));
FilterCommandRegistry.register(builtinCommandPrefix + "clean",
new TestCommandFactory('c'));
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "test", "smudge",
builtinCommandPrefix + "smudge");
config.setString("filter", "test", "clean",
builtinCommandPrefix + "clean");
config.save();
// We're on the test branch
File aFile = writeTrashFile("a.txt", "a");
writeTrashFile(".gitattributes", "a.txt filter=test");
File cFile = writeTrashFile("cc/c.txt", "C");
writeTrashFile("cc/.gitattributes", "c.txt filter=test");
git.add().addFilepattern(".").call();
git.commit().setMessage("On test").call();
git.checkout().setName("master").call();
git.branchCreate().setName("other").call();
git.checkout().setName("other").call();
writeTrashFile("b.txt", "b");
writeTrashFile(".gitattributes", "b.txt filter=test");
git.add().addFilepattern(".").call();
git.commit().setMessage("On other").call();
git.checkout().setName("test").call();
checkFile(aFile, "scsa");
checkFile(cFile, "scsC");
}
@Test
public void testCheckoutSingleFile() throws Exception {
String builtinCommandPrefix = "jgit://builtin/test/";
FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
new TestCommandFactory('s'));
FilterCommandRegistry.register(builtinCommandPrefix + "clean",
new TestCommandFactory('c'));
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "test", "smudge",
builtinCommandPrefix + "smudge");
config.setString("filter", "test", "clean",
builtinCommandPrefix + "clean");
config.save();
// We're on the test branch
File aFile = writeTrashFile("a.txt", "a");
File attributes = writeTrashFile(".gitattributes", "a.txt filter=test");
git.add().addFilepattern(".").call();
git.commit().setMessage("On test").call();
git.checkout().setName("master").call();
git.branchCreate().setName("other").call();
git.checkout().setName("other").call();
writeTrashFile("b.txt", "b");
writeTrashFile(".gitattributes", "b.txt filter=test");
git.add().addFilepattern(".").call();
git.commit().setMessage("On other").call();
git.checkout().setName("master").call();
assertFalse(aFile.exists());
assertFalse(attributes.exists());
git.checkout().setStartPoint("test").addPath("a.txt").call();
checkFile(aFile, "scsa");
}
@Test
public void testCheckoutSingleFile2() throws Exception {
String builtinCommandPrefix = "jgit://builtin/test/";
FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
new TestCommandFactory('s'));
FilterCommandRegistry.register(builtinCommandPrefix + "clean",
new TestCommandFactory('c'));
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "test", "smudge",
builtinCommandPrefix + "smudge");
config.setString("filter", "test", "clean",
builtinCommandPrefix + "clean");
config.save();
// We're on the test branch
File aFile = writeTrashFile("a.txt", "a");
File attributes = writeTrashFile(".gitattributes", "a.txt filter=test");
git.add().addFilepattern(".").call();
git.commit().setMessage("On test").call();
git.checkout().setName("master").call();
git.branchCreate().setName("other").call();
git.checkout().setName("other").call();
writeTrashFile("b.txt", "b");
writeTrashFile(".gitattributes", "b.txt filter=test");
git.add().addFilepattern(".").call();
git.commit().setMessage("On other").call();
git.checkout().setName("master").call();
assertFalse(aFile.exists());
assertFalse(attributes.exists());
writeTrashFile(".gitattributes", "");
git.checkout().setStartPoint("test").addPath("a.txt").call();
checkFile(aFile, "scsa");
}
@Test
public void testMerge() throws Exception {
String builtinCommandPrefix = "jgit://builtin/test/";
FilterCommandRegistry.register(builtinCommandPrefix + "smudge",
new TestCommandFactory('s'));
FilterCommandRegistry.register(builtinCommandPrefix + "clean",
new TestCommandFactory('c'));
StoredConfig config = git.getRepository().getConfig();
config.setString("filter", "test", "smudge",
builtinCommandPrefix + "smudge");
config.setString("filter", "test", "clean",
builtinCommandPrefix + "clean");
config.save();
// We're on the test branch. Set up two branches that are expected to
// merge cleanly.
File aFile = writeTrashFile("a.txt", "a");
writeTrashFile(".gitattributes", "a.txt filter=test");
git.add().addFilepattern(".").call();
RevCommit aCommit = git.commit().setMessage("On test").call();
git.checkout().setName("master").call();
assertFalse(aFile.exists());
git.branchCreate().setName("other").call();
git.checkout().setName("other").call();
writeTrashFile("b/b.txt", "b");
writeTrashFile("b/.gitattributes", "b.txt filter=test");
git.add().addFilepattern(".").call();
git.commit().setMessage("On other").call();
MergeResult result = git.merge().include(aCommit).call();
assertEquals(MergeResult.MergeStatus.MERGED, result.getMergeStatus());
checkFile(aFile, "scsa");
}
}