blob: b937b1f6a9ffdc0cb752cee79b039996e3aa07f2 [file] [log] [blame]
/*
* Copyright (C) 2015, 2022 Ivan Motsch <ivan.motsch@bsiag.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.api;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.eclipse.jgit.attributes.Attribute;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEditor;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
import org.eclipse.jgit.lib.CoreConfig.EOL;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.runner.RunWith;
/**
* Unit tests for end-of-line conversion and settings using core.autocrlf, *
* core.eol and the .gitattributes eol, text, binary (macro for -diff -merge
* -text)
*/
@RunWith(Theories.class)
public class EolRepositoryTest extends RepositoryTestCase {
private static final FileMode D = FileMode.TREE;
private static final FileMode F = FileMode.REGULAR_FILE;
@DataPoint
public static boolean doSmudgeEntries = true;
@DataPoint
public static boolean dontSmudgeEntries = false;
private boolean smudge;
@DataPoint
public static String smallContents[] = {
generateTestData(3, 1, true, false),
generateTestData(3, 1, false, true),
generateTestData(3, 1, true, true) };
@DataPoint
public static String hugeContents[] = {
generateTestData(1000000, 17, true, false),
generateTestData(1000000, 17, false, true),
generateTestData(1000000, 17, true, true) };
static String generateTestData(int size, int lineSize, boolean withCRLF,
boolean withLF) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < size; i++) {
if (i > 0 && i % lineSize == 0) {
// newline
if (withCRLF && withLF) {
// mixed
if (i % 2 == 0)
sb.append("\r\n");
else
sb.append("\n");
} else if (withCRLF) {
sb.append("\r\n");
} else if (withLF) {
sb.append("\n");
}
}
sb.append("A");
}
return sb.toString();
}
public EolRepositoryTest(String[] testContent, boolean smudgeEntries) {
CONTENT_CRLF = testContent[0];
CONTENT_LF = testContent[1];
CONTENT_MIXED = testContent[2];
this.smudge = smudgeEntries;
}
protected String CONTENT_CRLF;
protected String CONTENT_LF;
protected String CONTENT_MIXED;
/** work tree root .gitattributes */
private File dotGitattributes;
/** file containing CRLF */
private File fileCRLF;
/** file containing LF */
private File fileLF;
/** file containing mixed CRLF and LF */
private File fileMixed;
/** this values are set in {@link #collectRepositoryState()} */
private static class ActualEntry {
private String attrs;
private String file;
private String index;
private int indexContentLength;
}
private ActualEntry entryCRLF = new ActualEntry();
private ActualEntry entryLF = new ActualEntry();
private ActualEntry entryMixed = new ActualEntry();
private DirCache dirCache;
private boolean isDefaultCrLf() {
String eol = mockSystemReader.getProperty("line.separator");
return "\r\n".equals(eol);
}
@Test
public void testDefaultSetup() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(null, null, null, null, "* text=auto");
collectRepositoryState();
assertEquals("text=auto", entryCRLF.attrs);
// eol=native is the default!
String expected = isDefaultCrLf() ? CONTENT_CRLF : CONTENT_LF;
checkEntryContent(entryCRLF, expected, CONTENT_LF);
checkEntryContent(entryLF, expected, CONTENT_LF);
checkEntryContent(entryMixed, expected, CONTENT_LF);
}
public void checkEntryContent(ActualEntry entry, String fileContent,
String indexContent) {
assertEquals(fileContent, entry.file);
assertEquals(indexContent, entry.index);
if (entry.indexContentLength != 0) {
assertEquals(fileContent.length(), entry.indexContentLength);
}
}
@Test
public void test_ConfigAutoCRLF_false() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.FALSE, null, null, null, "* text=auto");
collectRepositoryState();
assertEquals("text=auto", entryCRLF.attrs);
// eol=native is the default!
String expected = isDefaultCrLf() ? CONTENT_CRLF : CONTENT_LF;
checkEntryContent(entryCRLF, expected, CONTENT_LF);
checkEntryContent(entryLF, expected, CONTENT_LF);
checkEntryContent(entryMixed, expected, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_true() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.TRUE, null, null, null, "* text=auto");
collectRepositoryState();
assertEquals("text=auto", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_input() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.INPUT, null, null, null, "* text=auto");
collectRepositoryState();
assertEquals("text=auto", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_ConfigEOL_lf() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(null, EOL.LF, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_ConfigEOL_crlf() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(null, EOL.CRLF, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_ConfigEOL_native_windows() throws Exception {
mockSystemReader.setWindows();
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_ConfigEOL_native_xnix() throws Exception {
mockSystemReader.setUnix();
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_false_ConfigEOL_lf() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_false_ConfigEOL_native() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.NATIVE, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
String expected = isDefaultCrLf() ? CONTENT_CRLF : CONTENT_LF;
checkEntryContent(entryCRLF, expected, CONTENT_LF);
checkEntryContent(entryLF, expected, CONTENT_LF);
checkEntryContent(entryMixed, expected, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_true_ConfigEOL_lf() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_switchToBranchWithTextAttributes()
throws Exception {
Git git = Git.wrap(db);
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.CRLF, null, null,
"file1.txt text\nfile2.txt text\nfile3.txt text");
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
// switch to binary for file1
dotGitattributes = createAndAddFile(git, Constants.DOT_GIT_ATTRIBUTES,
"file1.txt binary\nfile2.txt text\nfile3.txt text");
gitCommit(git, "switchedToBinaryFor1");
recreateWorktree(git);
collectRepositoryState();
assertEquals("binary -diff -merge -text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
assertEquals("text", entryLF.attrs);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
assertEquals("text", entryMixed.attrs);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
// checkout the commit which has text for file1
gitCheckout(git, "HEAD^");
recreateWorktree(git);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_switchToBranchWithBinaryAttributes() throws Exception {
Git git = Git.wrap(db);
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, null, null,
"file1.txt binary\nfile2.txt binary\nfile3.txt binary");
collectRepositoryState();
assertEquals("binary -diff -merge -text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
// switch to text for file1
dotGitattributes = createAndAddFile(git, Constants.DOT_GIT_ATTRIBUTES,
"file1.txt text\nfile2.txt binary\nfile3.txt binary");
gitCommit(git, "switchedToTextFor1");
recreateWorktree(git);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
assertEquals("binary -diff -merge -text", entryLF.attrs);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
assertEquals("binary -diff -merge -text", entryMixed.attrs);
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
// checkout the commit which has text for file1
gitCheckout(git, "HEAD^");
recreateWorktree(git);
collectRepositoryState();
assertEquals("binary -diff -merge -text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
}
@Test
public void test_ConfigAutoCRLF_input_ConfigEOL_lf() throws Exception {
// for EOL to work, the text attribute must be set
setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt text", null, null);
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_true_GlobalEOL_lf() throws Exception {
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt eol=lf", null, null);
collectRepositoryState();
assertEquals("eol=lf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_false_GlobalEOL_lf() throws Exception {
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt eol=lf", null, null);
collectRepositoryState();
assertEquals("eol=lf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_input_GlobalEOL_lf() throws Exception {
setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt eol=lf", null, null);
collectRepositoryState();
assertEquals("eol=lf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_true_GlobalEOL_crlf() throws Exception {
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt eol=crlf", null, null);
collectRepositoryState();
assertEquals("eol=crlf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_false_GlobalEOL_crlf() throws Exception {
setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt eol=crlf", null, null);
collectRepositoryState();
assertEquals("eol=crlf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_input_GlobalEOL_crlf() throws Exception {
setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt eol=crlf", null, null);
collectRepositoryState();
assertEquals("eol=crlf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_true_GlobalEOL_lf_InfoEOL_crlf()
throws Exception {
setupGitAndDoHardReset(AutoCRLF.TRUE, null, "*.txt eol=lf", "*.txt eol=crlf", null);
// info decides
collectRepositoryState();
assertEquals("eol=crlf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_ConfigAutoCRLF_false_GlobalEOL_crlf_InfoEOL_lf()
throws Exception {
setupGitAndDoHardReset(AutoCRLF.FALSE, null, "*.txt eol=crlf", "*.txt eol=lf", null);
// info decides
collectRepositoryState();
assertEquals("eol=lf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
}
@Test
public void test_GlobalEOL_lf_RootEOL_crlf() throws Exception {
setupGitAndDoHardReset(null, null, "*.txt eol=lf", null, "*.txt eol=crlf");
// root over global
collectRepositoryState();
assertEquals("eol=crlf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_GlobalEOL_lf_InfoEOL_crlf_RootEOL_lf() throws Exception {
setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt eol=crlf", "*.txt eol=lf");
// info overrides all
collectRepositoryState();
assertEquals("eol=crlf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_GlobalEOL_lf_InfoEOL_crlf_RootEOL_unspec()
throws Exception {
setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt eol=crlf",
"*.txt text !eol");
// info overrides all
collectRepositoryState();
assertEquals("eol=crlf text", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
}
@Test
public void test_GlobalEOL_lf_InfoEOL_unspec_RootEOL_crlf()
throws Exception {
setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt !eol",
"*.txt text eol=crlf");
// info overrides all
collectRepositoryState();
assertEquals("text", entryCRLF.attrs);
// !eol means unspecified, so use the default of core.eol, which is
// native.
String expected = isDefaultCrLf() ? CONTENT_CRLF : CONTENT_LF;
checkEntryContent(entryCRLF, expected, CONTENT_LF);
checkEntryContent(entryLF, expected, CONTENT_LF);
checkEntryContent(entryMixed, expected, CONTENT_LF);
}
@Test
public void testBinary1() throws Exception {
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.CRLF, "*.txt text", "*.txt binary",
"*.txt eol=crlf");
// info overrides all
collectRepositoryState();
assertEquals("binary -diff -merge -text eol=crlf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
}
@Test
public void testBinary2() throws Exception {
setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.CRLF, "*.txt text eol=crlf", null,
"*.txt binary");
// root over global
collectRepositoryState();
assertEquals("binary -diff -merge -text eol=crlf", entryCRLF.attrs);
checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF);
checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
}
// create new repo with
// global .gitattributes
// info .git/config/info/.gitattributes
// workdir root .gitattributes
// text file lf.txt CONTENT_LF
// text file crlf.txt CONTENT_CRLF
//
// commit files (checkin)
// delete working dir files
// reset hard (checkout)
private void setupGitAndDoHardReset(AutoCRLF autoCRLF, EOL eol,
String globalAttributesContent, String infoAttributesContent,
String workDirRootAttributesContent) throws Exception {
Git git = new Git(db);
FileBasedConfig config = db.getConfig();
if (autoCRLF != null) {
config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_AUTOCRLF, autoCRLF);
}
if (eol != null) {
config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_EOL, eol);
}
if (globalAttributesContent != null) {
File f = new File(db.getDirectory(), "global/attrs");
write(f, globalAttributesContent);
config.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_ATTRIBUTESFILE,
f.getAbsolutePath());
}
if (infoAttributesContent != null) {
File f = new File(db.getDirectory(), Constants.INFO_ATTRIBUTES);
write(f, infoAttributesContent);
}
config.save();
if (workDirRootAttributesContent != null) {
dotGitattributes = createAndAddFile(git,
Constants.DOT_GIT_ATTRIBUTES, workDirRootAttributesContent);
} else {
dotGitattributes = null;
}
fileCRLF = createAndAddFile(git, "file1.txt", "a");
fileLF = createAndAddFile(git, "file2.txt", "a");
fileMixed = createAndAddFile(git, "file3.txt", "a");
RevCommit c = gitCommit(git, "create files");
fileCRLF = createAndAddFile(git, "file1.txt", CONTENT_CRLF);
fileLF = createAndAddFile(git, "file2.txt", CONTENT_LF);
fileMixed = createAndAddFile(git, "file3.txt", CONTENT_MIXED);
gitCommit(git, "addFiles");
recreateWorktree(git);
if (smudge) {
DirCache dc = DirCache.lock(git.getRepository().getIndexFile(),
FS.detect());
DirCacheEditor editor = dc.editor();
for (int i = 0; i < dc.getEntryCount(); i++) {
editor.add(new DirCacheEditor.PathEdit(
dc.getEntry(i).getPathString()) {
@Override
public void apply(DirCacheEntry ent) {
ent.smudgeRacilyClean();
}
});
}
editor.commit();
}
// @TODO: find out why the following assertion would break the tests
// assertTrue(git.status().call().isClean());
git.checkout().setName(c.getName()).call();
git.checkout().setName("master").call();
}
private void recreateWorktree(Git git)
throws GitAPIException, CheckoutConflictException,
InterruptedException, IOException, NoFilepatternException {
// re-create file from the repo
for (File f : new File[] { dotGitattributes, fileCRLF, fileLF, fileMixed }) {
if (f == null)
continue;
f.delete();
Assert.assertFalse(f.exists());
}
gitResetHard(git);
fsTick(db.getIndexFile());
gitAdd(git, ".");
}
protected RevCommit gitCommit(Git git, String msg) throws GitAPIException {
return git.commit().setMessage(msg).call();
}
protected void gitAdd(Git git, String path) throws GitAPIException {
git.add().addFilepattern(path).call();
}
protected void gitResetHard(Git git) throws GitAPIException {
git.reset().setMode(ResetType.HARD).call();
}
protected void gitCheckout(Git git, String revstr)
throws GitAPIException, RevisionSyntaxException, IOException {
git.checkout().setName(db.resolve(revstr).getName()).call();
}
// create a file and add it to the repo
private File createAndAddFile(Git git, String path, String content)
throws Exception {
File f;
int pos = path.lastIndexOf('/');
if (pos < 0) {
f = writeTrashFile(path, content);
} else {
f = writeTrashFile(path.substring(0, pos), path.substring(pos + 1),
content);
}
gitAdd(git, path);
Assert.assertTrue(f.exists());
return f;
}
private void collectRepositoryState() throws Exception {
dirCache = db.readDirCache();
try (TreeWalk walk = new TreeWalk(db)) {
walk.addTree(new FileTreeIterator(db));
walk.addTree(new DirCacheIterator(db.readDirCache()));
if (dotGitattributes != null) {
collectEntryContentAndAttributes(walk, F, ".gitattributes",
null);
}
collectEntryContentAndAttributes(walk, F, fileCRLF.getName(),
entryCRLF);
collectEntryContentAndAttributes(walk, F, fileLF.getName(),
entryLF);
collectEntryContentAndAttributes(walk, F, fileMixed.getName(),
entryMixed);
assertFalse("Not all files tested", walk.next());
}
}
private void collectEntryContentAndAttributes(TreeWalk walk, FileMode type,
String pathName,
ActualEntry e) throws IOException {
assertTrue("walk has entry", walk.next());
assertEquals(pathName, walk.getPathString());
assertEquals(type, walk.getFileMode(0));
if (e != null) {
e.attrs = "";
for (Attribute a : walk.getAttributes().getAll()) {
e.attrs += " " + a.toString();
}
e.attrs = e.attrs.trim();
e.file = new String(
IO.readFully(new File(db.getWorkTree(), pathName)), UTF_8);
DirCacheEntry dce = dirCache.getEntry(pathName);
ObjectLoader open = walk.getObjectReader().open(dce.getObjectId());
e.index = new String(open.getBytes(), UTF_8);
e.indexContentLength = dce.getLength();
}
if (D.equals(type))
walk.enterSubtree();
}
}