/* * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com> * * This program and the accompanying materials are made available * under the terms of the Eclipse Distribution License v1.0 which * accompanies this distribution, is reproduced below, and is * available at http://www.eclipse.org/org/documents/edl-v10.php * * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of the Eclipse Foundation, Inc. nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.eclipse.jgit.api; 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; private TreeWalk walk; /** 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; @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); checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); checkEntryContent(entryMixed, CONTENT_LF, 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); checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); checkEntryContent(entryMixed, CONTENT_LF, 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 { String origLineSeparator = System.getProperty("line.separator", "\n"); System.setProperty("line.separator", "\r\n"); try { // 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); } finally { System.setProperty("line.separator", origLineSeparator); } } @Test public void test_ConfigEOL_native_xnix() throws Exception { String origLineSeparator = System.getProperty("line.separator", "\n"); System.setProperty("line.separator", "\n"); try { // 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); } finally { System.setProperty("line.separator", origLineSeparator); } } @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); checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); checkEntryContent(entryMixed, CONTENT_LF, 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); checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF); checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF); checkEntryContent(entryMixed, CONTENT_LF, 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()) { 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(); walk = beginWalk(); if (dotGitattributes != null) collectEntryContentAndAttributes(F, ".gitattributes", null); collectEntryContentAndAttributes(F, fileCRLF.getName(), entryCRLF); collectEntryContentAndAttributes(F, fileLF.getName(), entryLF); collectEntryContentAndAttributes(F, fileMixed.getName(), entryMixed); endWalk(); } private TreeWalk beginWalk() throws Exception { TreeWalk newWalk = new TreeWalk(db); newWalk.addTree(new FileTreeIterator(db)); newWalk.addTree(new DirCacheIterator(db.readDirCache())); return newWalk; } private void endWalk() throws IOException { assertFalse("Not all files tested", walk.next()); } private void collectEntryContentAndAttributes(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))); DirCacheEntry dce = dirCache.getEntry(pathName); ObjectLoader open = walk.getObjectReader().open(dce.getObjectId()); e.index = new String(open.getBytes()); e.indexContentLength = dce.getLength(); } if (D.equals(type)) walk.enterSubtree(); } }