You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EolRepositoryTest.java 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /*
  2. * Copyright (C) 2015, Ivan Motsch <ivan.motsch@bsiag.com>
  3. *
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Distribution License v1.0 which
  6. * accompanies this distribution, is reproduced below, and is
  7. * available at http://www.eclipse.org/org/documents/edl-v10.php
  8. *
  9. * All rights reserved.
  10. *
  11. * Redistribution and use in source and binary forms, with or
  12. * without modification, are permitted provided that the following
  13. * conditions are met:
  14. *
  15. * - Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. *
  18. * - Redistributions in binary form must reproduce the above
  19. * copyright notice, this list of conditions and the following
  20. * disclaimer in the documentation and/or other materials provided
  21. * with the distribution.
  22. *
  23. * - Neither the name of the Eclipse Foundation, Inc. nor the
  24. * names of its contributors may be used to endorse or promote
  25. * products derived from this software without specific prior
  26. * written permission.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  29. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  31. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  32. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  33. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  34. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  35. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  37. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. */
  39. package org.eclipse.jgit.api;
  40. import static org.junit.Assert.assertEquals;
  41. import static org.junit.Assert.assertFalse;
  42. import static org.junit.Assert.assertTrue;
  43. import java.io.File;
  44. import java.io.IOException;
  45. import org.eclipse.jgit.api.ResetCommand.ResetType;
  46. import org.eclipse.jgit.api.errors.CheckoutConflictException;
  47. import org.eclipse.jgit.api.errors.GitAPIException;
  48. import org.eclipse.jgit.api.errors.NoFilepatternException;
  49. import org.eclipse.jgit.attributes.Attribute;
  50. import org.eclipse.jgit.dircache.DirCache;
  51. import org.eclipse.jgit.dircache.DirCacheEditor;
  52. import org.eclipse.jgit.dircache.DirCacheEntry;
  53. import org.eclipse.jgit.dircache.DirCacheIterator;
  54. import org.eclipse.jgit.errors.RevisionSyntaxException;
  55. import org.eclipse.jgit.junit.RepositoryTestCase;
  56. import org.eclipse.jgit.lib.ConfigConstants;
  57. import org.eclipse.jgit.lib.Constants;
  58. import org.eclipse.jgit.lib.CoreConfig.AutoCRLF;
  59. import org.eclipse.jgit.lib.CoreConfig.EOL;
  60. import org.eclipse.jgit.lib.FileMode;
  61. import org.eclipse.jgit.lib.ObjectLoader;
  62. import org.eclipse.jgit.revwalk.RevCommit;
  63. import org.eclipse.jgit.storage.file.FileBasedConfig;
  64. import org.eclipse.jgit.treewalk.FileTreeIterator;
  65. import org.eclipse.jgit.treewalk.TreeWalk;
  66. import org.eclipse.jgit.util.FS;
  67. import org.eclipse.jgit.util.IO;
  68. import org.junit.Assert;
  69. import org.junit.Test;
  70. import org.junit.experimental.theories.DataPoint;
  71. import org.junit.experimental.theories.Theories;
  72. import org.junit.runner.RunWith;
  73. /**
  74. * Unit tests for end-of-line conversion and settings using core.autocrlf, *
  75. * core.eol and the .gitattributes eol, text, binary (macro for -diff -merge
  76. * -text)
  77. */
  78. @RunWith(Theories.class)
  79. public class EolRepositoryTest extends RepositoryTestCase {
  80. private static final FileMode D = FileMode.TREE;
  81. private static final FileMode F = FileMode.REGULAR_FILE;
  82. @DataPoint
  83. public static boolean doSmudgeEntries = true;
  84. @DataPoint
  85. public static boolean dontSmudgeEntries = false;
  86. private boolean smudge;
  87. @DataPoint
  88. public static String smallContents[] = {
  89. generateTestData(3, 1, true, false),
  90. generateTestData(3, 1, false, true),
  91. generateTestData(3, 1, true, true) };
  92. @DataPoint
  93. public static String hugeContents[] = {
  94. generateTestData(1000000, 17, true, false),
  95. generateTestData(1000000, 17, false, true),
  96. generateTestData(1000000, 17, true, true) };
  97. static String generateTestData(int size, int lineSize, boolean withCRLF,
  98. boolean withLF) {
  99. StringBuilder sb = new StringBuilder();
  100. for (int i = 0; i < size; i++) {
  101. if (i > 0 && i % lineSize == 0) {
  102. // newline
  103. if (withCRLF && withLF) {
  104. // mixed
  105. if (i % 2 == 0)
  106. sb.append("\r\n");
  107. else
  108. sb.append("\n");
  109. } else if (withCRLF) {
  110. sb.append("\r\n");
  111. } else if (withLF) {
  112. sb.append("\n");
  113. }
  114. }
  115. sb.append("A");
  116. }
  117. return sb.toString();
  118. }
  119. public EolRepositoryTest(String[] testContent, boolean smudgeEntries) {
  120. CONTENT_CRLF = testContent[0];
  121. CONTENT_LF = testContent[1];
  122. CONTENT_MIXED = testContent[2];
  123. this.smudge = smudgeEntries;
  124. }
  125. protected String CONTENT_CRLF;
  126. protected String CONTENT_LF;
  127. protected String CONTENT_MIXED;
  128. private TreeWalk walk;
  129. /** work tree root .gitattributes */
  130. private File dotGitattributes;
  131. /** file containing CRLF */
  132. private File fileCRLF;
  133. /** file containing LF */
  134. private File fileLF;
  135. /** file containing mixed CRLF and LF */
  136. private File fileMixed;
  137. /** this values are set in {@link #collectRepositoryState()} */
  138. private static class ActualEntry {
  139. private String attrs;
  140. private String file;
  141. private String index;
  142. private int indexContentLength;
  143. }
  144. private ActualEntry entryCRLF = new ActualEntry();
  145. private ActualEntry entryLF = new ActualEntry();
  146. private ActualEntry entryMixed = new ActualEntry();
  147. private DirCache dirCache;
  148. @Test
  149. public void testDefaultSetup() throws Exception {
  150. // for EOL to work, the text attribute must be set
  151. setupGitAndDoHardReset(null, null, null, null, "* text=auto");
  152. collectRepositoryState();
  153. assertEquals("text=auto", entryCRLF.attrs);
  154. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  155. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  156. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  157. }
  158. public void checkEntryContent(ActualEntry entry, String fileContent,
  159. String indexContent) {
  160. assertEquals(fileContent, entry.file);
  161. assertEquals(indexContent, entry.index);
  162. if (entry.indexContentLength != 0) {
  163. assertEquals(fileContent.length(), entry.indexContentLength);
  164. }
  165. }
  166. @Test
  167. public void test_ConfigAutoCRLF_false() throws Exception {
  168. // for EOL to work, the text attribute must be set
  169. setupGitAndDoHardReset(AutoCRLF.FALSE, null, null, null, "* text=auto");
  170. collectRepositoryState();
  171. assertEquals("text=auto", entryCRLF.attrs);
  172. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  173. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  174. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  175. }
  176. @Test
  177. public void test_ConfigAutoCRLF_true() throws Exception {
  178. // for EOL to work, the text attribute must be set
  179. setupGitAndDoHardReset(AutoCRLF.TRUE, null, null, null, "* text=auto");
  180. collectRepositoryState();
  181. assertEquals("text=auto", entryCRLF.attrs);
  182. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  183. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  184. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  185. }
  186. @Test
  187. public void test_ConfigAutoCRLF_input() throws Exception {
  188. // for EOL to work, the text attribute must be set
  189. setupGitAndDoHardReset(AutoCRLF.INPUT, null, null, null, "* text=auto");
  190. collectRepositoryState();
  191. assertEquals("text=auto", entryCRLF.attrs);
  192. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  193. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  194. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  195. }
  196. @Test
  197. public void test_ConfigEOL_lf() throws Exception {
  198. // for EOL to work, the text attribute must be set
  199. setupGitAndDoHardReset(null, EOL.LF, "*.txt text", null, null);
  200. collectRepositoryState();
  201. assertEquals("text", entryCRLF.attrs);
  202. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  203. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  204. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  205. }
  206. @Test
  207. public void test_ConfigEOL_crlf() throws Exception {
  208. // for EOL to work, the text attribute must be set
  209. setupGitAndDoHardReset(null, EOL.CRLF, "*.txt text", null, null);
  210. collectRepositoryState();
  211. assertEquals("text", entryCRLF.attrs);
  212. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  213. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  214. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  215. }
  216. @Test
  217. public void test_ConfigEOL_native_windows() throws Exception {
  218. String origLineSeparator = System.getProperty("line.separator", "\n");
  219. System.setProperty("line.separator", "\r\n");
  220. try {
  221. // for EOL to work, the text attribute must be set
  222. setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null);
  223. collectRepositoryState();
  224. assertEquals("text", entryCRLF.attrs);
  225. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  226. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  227. } finally {
  228. System.setProperty("line.separator", origLineSeparator);
  229. }
  230. }
  231. @Test
  232. public void test_ConfigEOL_native_xnix() throws Exception {
  233. String origLineSeparator = System.getProperty("line.separator", "\n");
  234. System.setProperty("line.separator", "\n");
  235. try {
  236. // for EOL to work, the text attribute must be set
  237. setupGitAndDoHardReset(null, EOL.NATIVE, "*.txt text", null, null);
  238. collectRepositoryState();
  239. assertEquals("text", entryCRLF.attrs);
  240. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  241. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  242. } finally {
  243. System.setProperty("line.separator", origLineSeparator);
  244. }
  245. }
  246. @Test
  247. public void test_ConfigAutoCRLF_false_ConfigEOL_lf() throws Exception {
  248. // for EOL to work, the text attribute must be set
  249. setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt text", null, null);
  250. collectRepositoryState();
  251. assertEquals("text", entryCRLF.attrs);
  252. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  253. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  254. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  255. }
  256. @Test
  257. public void test_ConfigAutoCRLF_false_ConfigEOL_native() throws Exception {
  258. // for EOL to work, the text attribute must be set
  259. setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.NATIVE, "*.txt text", null, null);
  260. collectRepositoryState();
  261. assertEquals("text", entryCRLF.attrs);
  262. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  263. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  264. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  265. }
  266. @Test
  267. public void test_ConfigAutoCRLF_true_ConfigEOL_lf() throws Exception {
  268. // for EOL to work, the text attribute must be set
  269. setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt text", null, null);
  270. collectRepositoryState();
  271. assertEquals("text", entryCRLF.attrs);
  272. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  273. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  274. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  275. }
  276. @Test
  277. public void test_switchToBranchWithTextAttributes()
  278. throws Exception {
  279. Git git = Git.wrap(db);
  280. // for EOL to work, the text attribute must be set
  281. setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.CRLF, null, null,
  282. "file1.txt text\nfile2.txt text\nfile3.txt text");
  283. collectRepositoryState();
  284. assertEquals("text", entryCRLF.attrs);
  285. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  286. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  287. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  288. // switch to binary for file1
  289. dotGitattributes = createAndAddFile(git, Constants.DOT_GIT_ATTRIBUTES,
  290. "file1.txt binary\nfile2.txt text\nfile3.txt text");
  291. gitCommit(git, "switchedToBinaryFor1");
  292. recreateWorktree(git);
  293. collectRepositoryState();
  294. assertEquals("binary -diff -merge -text", entryCRLF.attrs);
  295. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  296. assertEquals("text", entryLF.attrs);
  297. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  298. assertEquals("text", entryMixed.attrs);
  299. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  300. // checkout the commit which has text for file1
  301. gitCheckout(git, "HEAD^");
  302. recreateWorktree(git);
  303. collectRepositoryState();
  304. assertEquals("text", entryCRLF.attrs);
  305. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  306. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  307. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  308. }
  309. @Test
  310. public void test_switchToBranchWithBinaryAttributes() throws Exception {
  311. Git git = Git.wrap(db);
  312. // for EOL to work, the text attribute must be set
  313. setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, null, null,
  314. "file1.txt binary\nfile2.txt binary\nfile3.txt binary");
  315. collectRepositoryState();
  316. assertEquals("binary -diff -merge -text", entryCRLF.attrs);
  317. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF);
  318. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  319. checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
  320. // switch to text for file1
  321. dotGitattributes = createAndAddFile(git, Constants.DOT_GIT_ATTRIBUTES,
  322. "file1.txt text\nfile2.txt binary\nfile3.txt binary");
  323. gitCommit(git, "switchedToTextFor1");
  324. recreateWorktree(git);
  325. collectRepositoryState();
  326. assertEquals("text", entryCRLF.attrs);
  327. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  328. assertEquals("binary -diff -merge -text", entryLF.attrs);
  329. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  330. assertEquals("binary -diff -merge -text", entryMixed.attrs);
  331. checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
  332. // checkout the commit which has text for file1
  333. gitCheckout(git, "HEAD^");
  334. recreateWorktree(git);
  335. collectRepositoryState();
  336. assertEquals("binary -diff -merge -text", entryCRLF.attrs);
  337. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF);
  338. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  339. checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
  340. }
  341. @Test
  342. public void test_ConfigAutoCRLF_input_ConfigEOL_lf() throws Exception {
  343. // for EOL to work, the text attribute must be set
  344. setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt text", null, null);
  345. collectRepositoryState();
  346. assertEquals("text", entryCRLF.attrs);
  347. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  348. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  349. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  350. }
  351. @Test
  352. public void test_ConfigAutoCRLF_true_GlobalEOL_lf() throws Exception {
  353. setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt eol=lf", null, null);
  354. collectRepositoryState();
  355. assertEquals("eol=lf", entryCRLF.attrs);
  356. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  357. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  358. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  359. }
  360. @Test
  361. public void test_ConfigAutoCRLF_false_GlobalEOL_lf() throws Exception {
  362. setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt eol=lf", null, null);
  363. collectRepositoryState();
  364. assertEquals("eol=lf", entryCRLF.attrs);
  365. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  366. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  367. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  368. }
  369. @Test
  370. public void test_ConfigAutoCRLF_input_GlobalEOL_lf() throws Exception {
  371. setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt eol=lf", null, null);
  372. collectRepositoryState();
  373. assertEquals("eol=lf", entryCRLF.attrs);
  374. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  375. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  376. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  377. }
  378. @Test
  379. public void test_ConfigAutoCRLF_true_GlobalEOL_crlf() throws Exception {
  380. setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.LF, "*.txt eol=crlf", null, null);
  381. collectRepositoryState();
  382. assertEquals("eol=crlf", entryCRLF.attrs);
  383. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  384. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  385. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  386. }
  387. @Test
  388. public void test_ConfigAutoCRLF_false_GlobalEOL_crlf() throws Exception {
  389. setupGitAndDoHardReset(AutoCRLF.FALSE, EOL.LF, "*.txt eol=crlf", null, null);
  390. collectRepositoryState();
  391. assertEquals("eol=crlf", entryCRLF.attrs);
  392. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  393. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  394. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  395. }
  396. @Test
  397. public void test_ConfigAutoCRLF_input_GlobalEOL_crlf() throws Exception {
  398. setupGitAndDoHardReset(AutoCRLF.INPUT, EOL.LF, "*.txt eol=crlf", null, null);
  399. collectRepositoryState();
  400. assertEquals("eol=crlf", entryCRLF.attrs);
  401. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  402. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  403. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  404. }
  405. @Test
  406. public void test_ConfigAutoCRLF_true_GlobalEOL_lf_InfoEOL_crlf()
  407. throws Exception {
  408. setupGitAndDoHardReset(AutoCRLF.TRUE, null, "*.txt eol=lf", "*.txt eol=crlf", null);
  409. // info decides
  410. collectRepositoryState();
  411. assertEquals("eol=crlf", entryCRLF.attrs);
  412. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  413. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  414. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  415. }
  416. @Test
  417. public void test_ConfigAutoCRLF_false_GlobalEOL_crlf_InfoEOL_lf()
  418. throws Exception {
  419. setupGitAndDoHardReset(AutoCRLF.FALSE, null, "*.txt eol=crlf", "*.txt eol=lf", null);
  420. // info decides
  421. collectRepositoryState();
  422. assertEquals("eol=lf", entryCRLF.attrs);
  423. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  424. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  425. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  426. }
  427. @Test
  428. public void test_GlobalEOL_lf_RootEOL_crlf() throws Exception {
  429. setupGitAndDoHardReset(null, null, "*.txt eol=lf", null, "*.txt eol=crlf");
  430. // root over global
  431. collectRepositoryState();
  432. assertEquals("eol=crlf", entryCRLF.attrs);
  433. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  434. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  435. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  436. }
  437. @Test
  438. public void test_GlobalEOL_lf_InfoEOL_crlf_RootEOL_lf() throws Exception {
  439. setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt eol=crlf", "*.txt eol=lf");
  440. // info overrides all
  441. collectRepositoryState();
  442. assertEquals("eol=crlf", entryCRLF.attrs);
  443. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  444. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  445. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  446. }
  447. @Test
  448. public void test_GlobalEOL_lf_InfoEOL_crlf_RootEOL_unspec()
  449. throws Exception {
  450. setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt eol=crlf",
  451. "*.txt text !eol");
  452. // info overrides all
  453. collectRepositoryState();
  454. assertEquals("eol=crlf text", entryCRLF.attrs);
  455. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_LF);
  456. checkEntryContent(entryLF, CONTENT_CRLF, CONTENT_LF);
  457. checkEntryContent(entryMixed, CONTENT_CRLF, CONTENT_LF);
  458. }
  459. @Test
  460. public void test_GlobalEOL_lf_InfoEOL_unspec_RootEOL_crlf()
  461. throws Exception {
  462. setupGitAndDoHardReset(null, null, "*.txt eol=lf", "*.txt !eol",
  463. "*.txt text eol=crlf");
  464. // info overrides all
  465. collectRepositoryState();
  466. assertEquals("text", entryCRLF.attrs);
  467. checkEntryContent(entryCRLF, CONTENT_LF, CONTENT_LF);
  468. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  469. checkEntryContent(entryMixed, CONTENT_LF, CONTENT_LF);
  470. }
  471. @Test
  472. public void testBinary1() throws Exception {
  473. setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.CRLF, "*.txt text", "*.txt binary",
  474. "*.txt eol=crlf");
  475. // info overrides all
  476. collectRepositoryState();
  477. assertEquals("binary -diff -merge -text eol=crlf", entryCRLF.attrs);
  478. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF);
  479. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  480. checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
  481. }
  482. @Test
  483. public void testBinary2() throws Exception {
  484. setupGitAndDoHardReset(AutoCRLF.TRUE, EOL.CRLF, "*.txt text eol=crlf", null,
  485. "*.txt binary");
  486. // root over global
  487. collectRepositoryState();
  488. assertEquals("binary -diff -merge -text eol=crlf", entryCRLF.attrs);
  489. checkEntryContent(entryCRLF, CONTENT_CRLF, CONTENT_CRLF);
  490. checkEntryContent(entryLF, CONTENT_LF, CONTENT_LF);
  491. checkEntryContent(entryMixed, CONTENT_MIXED, CONTENT_MIXED);
  492. }
  493. // create new repo with
  494. // global .gitattributes
  495. // info .git/config/info/.gitattributes
  496. // workdir root .gitattributes
  497. // text file lf.txt CONTENT_LF
  498. // text file crlf.txt CONTENT_CRLF
  499. //
  500. // commit files (checkin)
  501. // delete working dir files
  502. // reset hard (checkout)
  503. private void setupGitAndDoHardReset(AutoCRLF autoCRLF, EOL eol,
  504. String globalAttributesContent, String infoAttributesContent,
  505. String workDirRootAttributesContent) throws Exception {
  506. Git git = new Git(db);
  507. FileBasedConfig config = db.getConfig();
  508. if (autoCRLF != null) {
  509. config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
  510. ConfigConstants.CONFIG_KEY_AUTOCRLF, autoCRLF);
  511. }
  512. if (eol != null) {
  513. config.setEnum(ConfigConstants.CONFIG_CORE_SECTION, null,
  514. ConfigConstants.CONFIG_KEY_EOL, eol);
  515. }
  516. if (globalAttributesContent != null) {
  517. File f = new File(db.getDirectory(), "global/attrs");
  518. write(f, globalAttributesContent);
  519. config.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
  520. ConfigConstants.CONFIG_KEY_ATTRIBUTESFILE,
  521. f.getAbsolutePath());
  522. }
  523. if (infoAttributesContent != null) {
  524. File f = new File(db.getDirectory(), Constants.INFO_ATTRIBUTES);
  525. write(f, infoAttributesContent);
  526. }
  527. config.save();
  528. if (workDirRootAttributesContent != null) {
  529. dotGitattributes = createAndAddFile(git,
  530. Constants.DOT_GIT_ATTRIBUTES, workDirRootAttributesContent);
  531. } else {
  532. dotGitattributes = null;
  533. }
  534. fileCRLF = createAndAddFile(git, "file1.txt", "a");
  535. fileLF = createAndAddFile(git, "file2.txt", "a");
  536. fileMixed = createAndAddFile(git, "file3.txt", "a");
  537. RevCommit c = gitCommit(git, "create files");
  538. fileCRLF = createAndAddFile(git, "file1.txt", CONTENT_CRLF);
  539. fileLF = createAndAddFile(git, "file2.txt", CONTENT_LF);
  540. fileMixed = createAndAddFile(git, "file3.txt", CONTENT_MIXED);
  541. gitCommit(git, "addFiles");
  542. recreateWorktree(git);
  543. if (smudge) {
  544. DirCache dc = DirCache.lock(git.getRepository().getIndexFile(),
  545. FS.detect());
  546. DirCacheEditor editor = dc.editor();
  547. for (int i = 0; i < dc.getEntryCount(); i++) {
  548. editor.add(new DirCacheEditor.PathEdit(
  549. dc.getEntry(i).getPathString()) {
  550. public void apply(DirCacheEntry ent) {
  551. ent.smudgeRacilyClean();
  552. }
  553. });
  554. }
  555. editor.commit();
  556. }
  557. // @TODO: find out why the following assertion would break the tests
  558. // assertTrue(git.status().call().isClean());
  559. git.checkout().setName(c.getName()).call();
  560. git.checkout().setName("master").call();
  561. }
  562. private void recreateWorktree(Git git)
  563. throws GitAPIException, CheckoutConflictException,
  564. InterruptedException, IOException, NoFilepatternException {
  565. // re-create file from the repo
  566. for (File f : new File[] { dotGitattributes, fileCRLF, fileLF, fileMixed }) {
  567. if (f == null)
  568. continue;
  569. f.delete();
  570. Assert.assertFalse(f.exists());
  571. }
  572. gitResetHard(git);
  573. fsTick(db.getIndexFile());
  574. gitAdd(git, ".");
  575. }
  576. protected RevCommit gitCommit(Git git, String msg) throws GitAPIException {
  577. return git.commit().setMessage(msg).call();
  578. }
  579. protected void gitAdd(Git git, String path) throws GitAPIException {
  580. git.add().addFilepattern(path).call();
  581. }
  582. protected void gitResetHard(Git git) throws GitAPIException {
  583. git.reset().setMode(ResetType.HARD).call();
  584. }
  585. protected void gitCheckout(Git git, String revstr)
  586. throws GitAPIException, RevisionSyntaxException, IOException {
  587. git.checkout().setName(db.resolve(revstr).getName()).call();
  588. }
  589. // create a file and add it to the repo
  590. private File createAndAddFile(Git git, String path, String content)
  591. throws Exception {
  592. File f;
  593. int pos = path.lastIndexOf('/');
  594. if (pos < 0) {
  595. f = writeTrashFile(path, content);
  596. } else {
  597. f = writeTrashFile(path.substring(0, pos), path.substring(pos + 1),
  598. content);
  599. }
  600. gitAdd(git, path);
  601. Assert.assertTrue(f.exists());
  602. return f;
  603. }
  604. private void collectRepositoryState() throws Exception {
  605. dirCache = db.readDirCache();
  606. walk = beginWalk();
  607. if (dotGitattributes != null)
  608. collectEntryContentAndAttributes(F, ".gitattributes", null);
  609. collectEntryContentAndAttributes(F, fileCRLF.getName(), entryCRLF);
  610. collectEntryContentAndAttributes(F, fileLF.getName(), entryLF);
  611. collectEntryContentAndAttributes(F, fileMixed.getName(), entryMixed);
  612. endWalk();
  613. }
  614. private TreeWalk beginWalk() throws Exception {
  615. TreeWalk newWalk = new TreeWalk(db);
  616. newWalk.addTree(new FileTreeIterator(db));
  617. newWalk.addTree(new DirCacheIterator(db.readDirCache()));
  618. return newWalk;
  619. }
  620. private void endWalk() throws IOException {
  621. assertFalse("Not all files tested", walk.next());
  622. }
  623. private void collectEntryContentAndAttributes(FileMode type, String pathName,
  624. ActualEntry e) throws IOException {
  625. assertTrue("walk has entry", walk.next());
  626. assertEquals(pathName, walk.getPathString());
  627. assertEquals(type, walk.getFileMode(0));
  628. if (e != null) {
  629. e.attrs = "";
  630. for (Attribute a : walk.getAttributes().getAll()) {
  631. e.attrs += " " + a.toString();
  632. }
  633. e.attrs = e.attrs.trim();
  634. e.file = new String(
  635. IO.readFully(new File(db.getWorkTree(), pathName)));
  636. DirCacheEntry dce = dirCache.getEntry(pathName);
  637. ObjectLoader open = walk.getObjectReader().open(dce.getObjectId());
  638. e.index = new String(open.getBytes());
  639. e.indexContentLength = dce.getLength();
  640. }
  641. if (D.equals(type))
  642. walk.enterSubtree();
  643. }
  644. }