aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java')
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java706
1 files changed, 706 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
new file mode 100644
index 0000000000..4c971ffb6b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
@@ -0,0 +1,706 @@
+/*
+ * 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.getCommonDirectory(), 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();
+ }
+}