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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. /*
  2. * Copyright (C) 2010, Red Hat Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.ignore;
  11. import static java.nio.charset.StandardCharsets.UTF_8;
  12. import static org.eclipse.jgit.junit.Assert.assertEquals;
  13. import static org.junit.Assert.assertEquals;
  14. import static org.junit.Assert.assertFalse;
  15. import static org.junit.Assert.assertNotNull;
  16. import static org.junit.Assert.assertTrue;
  17. import java.io.ByteArrayInputStream;
  18. import java.io.File;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.util.ArrayList;
  22. import java.util.Arrays;
  23. import org.eclipse.jgit.junit.RepositoryTestCase;
  24. import org.eclipse.jgit.lib.FileMode;
  25. import org.eclipse.jgit.treewalk.FileTreeIterator;
  26. import org.eclipse.jgit.treewalk.TreeWalk;
  27. import org.eclipse.jgit.treewalk.WorkingTreeIterator;
  28. import org.eclipse.jgit.util.FileUtils;
  29. import org.eclipse.jgit.util.SystemReader;
  30. import org.junit.After;
  31. import org.junit.Test;
  32. /**
  33. * Tests ignore node behavior on the local filesystem.
  34. */
  35. public class IgnoreNodeTest extends RepositoryTestCase {
  36. private static final FileMode D = FileMode.TREE;
  37. private static final FileMode F = FileMode.REGULAR_FILE;
  38. private static final boolean ignored = true;
  39. private static final boolean tracked = false;
  40. private TreeWalk walk;
  41. @After
  42. public void closeWalk() {
  43. if (walk != null) {
  44. walk.close();
  45. }
  46. }
  47. @Test
  48. public void testSimpleRootGitIgnoreGlobalIgnore() throws IOException {
  49. writeIgnoreFile(".gitignore", "x");
  50. writeTrashFile("a/x/file", "");
  51. writeTrashFile("b/x", "");
  52. writeTrashFile("x/file", "");
  53. beginWalk();
  54. assertEntry(F, tracked, ".gitignore");
  55. assertEntry(D, tracked, "a");
  56. assertEntry(D, ignored, "a/x");
  57. assertEntry(F, ignored, "a/x/file");
  58. assertEntry(D, tracked, "b");
  59. assertEntry(F, ignored, "b/x");
  60. assertEntry(D, ignored, "x");
  61. assertEntry(F, ignored, "x/file");
  62. endWalk();
  63. }
  64. @Test
  65. public void testSimpleRootGitIgnoreGlobalDirIgnore() throws IOException {
  66. writeIgnoreFile(".gitignore", "x/");
  67. writeTrashFile("a/x/file", "");
  68. writeTrashFile("x/file", "");
  69. beginWalk();
  70. assertEntry(F, tracked, ".gitignore");
  71. assertEntry(D, tracked, "a");
  72. assertEntry(D, ignored, "a/x");
  73. assertEntry(F, ignored, "a/x/file");
  74. assertEntry(D, ignored, "x");
  75. assertEntry(F, ignored, "x/file");
  76. endWalk();
  77. }
  78. @Test
  79. public void testSimpleRootGitIgnoreWildMatcher() throws IOException {
  80. writeIgnoreFile(".gitignore", "**");
  81. writeTrashFile("a/x", "");
  82. writeTrashFile("y", "");
  83. beginWalk();
  84. assertEntry(F, ignored, ".gitignore");
  85. assertEntry(D, ignored, "a");
  86. assertEntry(F, ignored, "a/x");
  87. assertEntry(F, ignored, "y");
  88. endWalk();
  89. }
  90. @Test
  91. public void testSimpleRootGitIgnoreWildMatcherDirOnly() throws IOException {
  92. writeIgnoreFile(".gitignore", "**/");
  93. writeTrashFile("a/x", "");
  94. writeTrashFile("y", "");
  95. beginWalk();
  96. assertEntry(F, tracked, ".gitignore");
  97. assertEntry(D, ignored, "a");
  98. assertEntry(F, ignored, "a/x");
  99. assertEntry(F, tracked, "y");
  100. endWalk();
  101. }
  102. @Test
  103. public void testSimpleRootGitIgnoreGlobalNegation1() throws IOException {
  104. writeIgnoreFile(".gitignore", "*", "!x*");
  105. writeTrashFile("x1", "");
  106. writeTrashFile("a/x2", "");
  107. writeTrashFile("x3/y", "");
  108. beginWalk();
  109. assertEntry(F, ignored, ".gitignore");
  110. assertEntry(D, ignored, "a");
  111. assertEntry(F, ignored, "a/x2");
  112. assertEntry(F, tracked, "x1");
  113. assertEntry(D, tracked, "x3");
  114. assertEntry(F, ignored, "x3/y");
  115. endWalk();
  116. }
  117. @Test
  118. public void testSimpleRootGitIgnoreGlobalNegation2() throws IOException {
  119. writeIgnoreFile(".gitignore", "*", "!x*", "!/a");
  120. writeTrashFile("x1", "");
  121. writeTrashFile("a/x2", "");
  122. writeTrashFile("x3/y", "");
  123. beginWalk();
  124. assertEntry(F, ignored, ".gitignore");
  125. assertEntry(D, tracked, "a");
  126. assertEntry(F, tracked, "a/x2");
  127. assertEntry(F, tracked, "x1");
  128. assertEntry(D, tracked, "x3");
  129. assertEntry(F, ignored, "x3/y");
  130. endWalk();
  131. }
  132. @Test
  133. public void testSimpleRootGitIgnoreGlobalNegation3() throws IOException {
  134. writeIgnoreFile(".gitignore", "*", "!x*", "!x*/**");
  135. writeTrashFile("x1", "");
  136. writeTrashFile("a/x2", "");
  137. writeTrashFile("x3/y", "");
  138. beginWalk();
  139. assertEntry(F, ignored, ".gitignore");
  140. assertEntry(D, ignored, "a");
  141. assertEntry(F, ignored, "a/x2");
  142. assertEntry(F, tracked, "x1");
  143. assertEntry(D, tracked, "x3");
  144. assertEntry(F, tracked, "x3/y");
  145. endWalk();
  146. }
  147. @Test
  148. public void testSimpleRootGitIgnoreGlobalNegation4() throws IOException {
  149. writeIgnoreFile(".gitignore", "*", "!**/");
  150. writeTrashFile("x1", "");
  151. writeTrashFile("a/x2", "");
  152. writeTrashFile("x3/y", "");
  153. beginWalk();
  154. assertEntry(F, ignored, ".gitignore");
  155. assertEntry(D, tracked, "a");
  156. assertEntry(F, ignored, "a/x2");
  157. assertEntry(F, ignored, "x1");
  158. assertEntry(D, tracked, "x3");
  159. assertEntry(F, ignored, "x3/y");
  160. endWalk();
  161. }
  162. @Test
  163. public void testRules() throws IOException {
  164. writeIgnoreFile(".git/info/exclude", "*~", "/out");
  165. writeIgnoreFile(".gitignore", "*.o", "/config");
  166. writeTrashFile("config/secret", "");
  167. writeTrashFile("mylib.c", "");
  168. writeTrashFile("mylib.c~", "");
  169. writeTrashFile("mylib.o", "");
  170. writeTrashFile("out/object/foo.exe", "");
  171. writeIgnoreFile("src/config/.gitignore", "lex.out");
  172. writeTrashFile("src/config/lex.out", "");
  173. writeTrashFile("src/config/config.c", "");
  174. writeTrashFile("src/config/config.c~", "");
  175. writeTrashFile("src/config/old/lex.out", "");
  176. beginWalk();
  177. assertEntry(F, tracked, ".gitignore");
  178. assertEntry(D, ignored, "config");
  179. assertEntry(F, ignored, "config/secret");
  180. assertEntry(F, tracked, "mylib.c");
  181. assertEntry(F, ignored, "mylib.c~");
  182. assertEntry(F, ignored, "mylib.o");
  183. assertEntry(D, ignored, "out");
  184. assertEntry(D, ignored, "out/object");
  185. assertEntry(F, ignored, "out/object/foo.exe");
  186. assertEntry(D, tracked, "src");
  187. assertEntry(D, tracked, "src/config");
  188. assertEntry(F, tracked, "src/config/.gitignore");
  189. assertEntry(F, tracked, "src/config/config.c");
  190. assertEntry(F, ignored, "src/config/config.c~");
  191. assertEntry(F, ignored, "src/config/lex.out");
  192. assertEntry(D, tracked, "src/config/old");
  193. assertEntry(F, ignored, "src/config/old/lex.out");
  194. endWalk();
  195. }
  196. @Test
  197. public void testNegation() throws IOException {
  198. // ignore all *.o files and ignore all "d" directories
  199. writeIgnoreFile(".gitignore", "*.o", "d");
  200. // negate "ignore" for a/b/keep.o file only
  201. writeIgnoreFile("src/a/b/.gitignore", "!keep.o");
  202. writeTrashFile("src/a/b/keep.o", "");
  203. writeTrashFile("src/a/b/nothere.o", "");
  204. // negate "ignore" for "d"
  205. writeIgnoreFile("src/c/.gitignore", "!d");
  206. // negate "ignore" for c/d/keep.o file only
  207. writeIgnoreFile("src/c/d/.gitignore", "!keep.o");
  208. writeTrashFile("src/c/d/keep.o", "");
  209. writeTrashFile("src/c/d/nothere.o", "");
  210. beginWalk();
  211. assertEntry(F, tracked, ".gitignore");
  212. assertEntry(D, tracked, "src");
  213. assertEntry(D, tracked, "src/a");
  214. assertEntry(D, tracked, "src/a/b");
  215. assertEntry(F, tracked, "src/a/b/.gitignore");
  216. assertEntry(F, tracked, "src/a/b/keep.o");
  217. assertEntry(F, ignored, "src/a/b/nothere.o");
  218. assertEntry(D, tracked, "src/c");
  219. assertEntry(F, tracked, "src/c/.gitignore");
  220. assertEntry(D, tracked, "src/c/d");
  221. assertEntry(F, tracked, "src/c/d/.gitignore");
  222. assertEntry(F, tracked, "src/c/d/keep.o");
  223. // must be ignored: "!d" should not negate *both* "d" and *.o rules!
  224. assertEntry(F, ignored, "src/c/d/nothere.o");
  225. endWalk();
  226. }
  227. /*
  228. * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=407475
  229. */
  230. @Test
  231. public void testNegateAllExceptJavaInSrc() throws IOException {
  232. // ignore all files except from src directory
  233. writeIgnoreFile(".gitignore", "/*", "!/src/");
  234. writeTrashFile("nothere.o", "");
  235. // ignore all files except java
  236. writeIgnoreFile("src/.gitignore", "*", "!*.java");
  237. writeTrashFile("src/keep.java", "");
  238. writeTrashFile("src/nothere.o", "");
  239. writeTrashFile("src/a/nothere.o", "");
  240. beginWalk();
  241. assertEntry(F, ignored, ".gitignore");
  242. assertEntry(F, ignored, "nothere.o");
  243. assertEntry(D, tracked, "src");
  244. assertEntry(F, ignored, "src/.gitignore");
  245. assertEntry(D, ignored, "src/a");
  246. assertEntry(F, ignored, "src/a/nothere.o");
  247. assertEntry(F, tracked, "src/keep.java");
  248. assertEntry(F, ignored, "src/nothere.o");
  249. endWalk();
  250. }
  251. /*
  252. * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=407475
  253. */
  254. @Test
  255. public void testNegationAllExceptJavaInSrcAndExceptChildDirInSrc()
  256. throws IOException {
  257. // ignore all files except from src directory
  258. writeIgnoreFile(".gitignore", "/*", "!/src/");
  259. writeTrashFile("nothere.o", "");
  260. // ignore all files except java in src folder and all children folders.
  261. // Last ignore rule breaks old jgit via bug 407475
  262. writeIgnoreFile("src/.gitignore", "*", "!*.java", "!*/");
  263. writeTrashFile("src/keep.java", "");
  264. writeTrashFile("src/nothere.o", "");
  265. writeTrashFile("src/a/keep.java", "");
  266. writeTrashFile("src/a/keep.o", "");
  267. beginWalk();
  268. assertEntry(F, ignored, ".gitignore");
  269. assertEntry(F, ignored, "nothere.o");
  270. assertEntry(D, tracked, "src");
  271. assertEntry(F, ignored, "src/.gitignore");
  272. assertEntry(D, tracked, "src/a");
  273. assertEntry(F, tracked, "src/a/keep.java");
  274. assertEntry(F, ignored, "src/a/keep.o");
  275. assertEntry(F, tracked, "src/keep.java");
  276. assertEntry(F, ignored, "src/nothere.o");
  277. endWalk();
  278. }
  279. /*
  280. * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=448094
  281. */
  282. @Test
  283. public void testRepeatedNegation() throws IOException {
  284. writeIgnoreFile(".gitignore", "e", "!e", "e", "!e", "e");
  285. writeTrashFile("e/nothere.o", "");
  286. beginWalk();
  287. assertEntry(F, tracked, ".gitignore");
  288. assertEntry(D, ignored, "e");
  289. assertEntry(F, ignored, "e/nothere.o");
  290. endWalk();
  291. }
  292. /*
  293. * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=448094
  294. */
  295. @Test
  296. public void testRepeatedNegationInDifferentFiles1() throws IOException {
  297. writeIgnoreFile(".gitignore", "*.o", "e");
  298. writeIgnoreFile("e/.gitignore", "!e");
  299. writeTrashFile("e/nothere.o", "");
  300. beginWalk();
  301. assertEntry(F, tracked, ".gitignore");
  302. assertEntry(D, ignored, "e");
  303. assertEntry(F, ignored, "e/.gitignore");
  304. assertEntry(F, ignored, "e/nothere.o");
  305. endWalk();
  306. }
  307. /*
  308. * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=448094
  309. */
  310. @Test
  311. public void testRepeatedNegationInDifferentFiles2() throws IOException {
  312. writeIgnoreFile(".gitignore", "*.o", "e");
  313. writeIgnoreFile("a/.gitignore", "!e");
  314. writeTrashFile("a/e/nothere.o", "");
  315. beginWalk();
  316. assertEntry(F, tracked, ".gitignore");
  317. assertEntry(D, tracked, "a");
  318. assertEntry(F, tracked, "a/.gitignore");
  319. assertEntry(D, tracked, "a/e");
  320. assertEntry(F, ignored, "a/e/nothere.o");
  321. endWalk();
  322. }
  323. /*
  324. * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=448094
  325. */
  326. @Test
  327. public void testRepeatedNegationInDifferentFiles3() throws IOException {
  328. writeIgnoreFile(".gitignore", "*.o");
  329. writeIgnoreFile("a/.gitignore", "e");
  330. writeIgnoreFile("a/b/.gitignore", "!e");
  331. writeTrashFile("a/b/e/nothere.o", "");
  332. beginWalk();
  333. assertEntry(F, tracked, ".gitignore");
  334. assertEntry(D, tracked, "a");
  335. assertEntry(F, tracked, "a/.gitignore");
  336. assertEntry(D, tracked, "a/b");
  337. assertEntry(F, tracked, "a/b/.gitignore");
  338. assertEntry(D, tracked, "a/b/e");
  339. assertEntry(F, ignored, "a/b/e/nothere.o");
  340. endWalk();
  341. }
  342. @Test
  343. public void testRepeatedNegationInDifferentFiles4() throws IOException {
  344. writeIgnoreFile(".gitignore", "*.o");
  345. writeIgnoreFile("a/.gitignore", "e");
  346. // Rules are never empty: WorkingTreeIterator optimizes empty rules away
  347. // paranoia check in case this optimization will be removed
  348. writeIgnoreFile("a/b/.gitignore", "#");
  349. writeIgnoreFile("a/b/c/.gitignore", "!e");
  350. writeTrashFile("a/b/c/e/nothere.o", "");
  351. beginWalk();
  352. assertEntry(F, tracked, ".gitignore");
  353. assertEntry(D, tracked, "a");
  354. assertEntry(F, tracked, "a/.gitignore");
  355. assertEntry(D, tracked, "a/b");
  356. assertEntry(F, tracked, "a/b/.gitignore");
  357. assertEntry(D, tracked, "a/b/c");
  358. assertEntry(F, tracked, "a/b/c/.gitignore");
  359. assertEntry(D, tracked, "a/b/c/e");
  360. assertEntry(F, ignored, "a/b/c/e/nothere.o");
  361. endWalk();
  362. }
  363. @Test
  364. public void testRepeatedNegationInDifferentFiles5() throws IOException {
  365. writeIgnoreFile(".gitignore", "e");
  366. writeIgnoreFile("a/.gitignore", "e");
  367. writeIgnoreFile("a/b/.gitignore", "!e");
  368. writeTrashFile("a/b/e/nothere.o", "");
  369. beginWalk();
  370. assertEntry(F, tracked, ".gitignore");
  371. assertEntry(D, tracked, "a");
  372. assertEntry(F, tracked, "a/.gitignore");
  373. assertEntry(D, tracked, "a/b");
  374. assertEntry(F, tracked, "a/b/.gitignore");
  375. assertEntry(D, tracked, "a/b/e");
  376. assertEntry(F, tracked, "a/b/e/nothere.o");
  377. endWalk();
  378. }
  379. @Test
  380. public void testIneffectiveNegationDifferentLevels1() throws IOException {
  381. writeIgnoreFile(".gitignore", "a/b/e/", "!a/b/e/*");
  382. writeTrashFile("a/b/e/nothere.o", "");
  383. beginWalk();
  384. assertEntry(F, tracked, ".gitignore");
  385. assertEntry(D, tracked, "a");
  386. assertEntry(D, tracked, "a/b");
  387. assertEntry(D, ignored, "a/b/e");
  388. assertEntry(F, ignored, "a/b/e/nothere.o");
  389. endWalk();
  390. }
  391. @Test
  392. public void testIneffectiveNegationDifferentLevels2() throws IOException {
  393. writeIgnoreFile(".gitignore", "a/b/e/");
  394. writeIgnoreFile("a/.gitignore", "!b/e/*");
  395. writeTrashFile("a/b/e/nothere.o", "");
  396. beginWalk();
  397. assertEntry(F, tracked, ".gitignore");
  398. assertEntry(D, tracked, "a");
  399. assertEntry(F, tracked, "a/.gitignore");
  400. assertEntry(D, tracked, "a/b");
  401. assertEntry(D, ignored, "a/b/e");
  402. assertEntry(F, ignored, "a/b/e/nothere.o");
  403. endWalk();
  404. }
  405. @Test
  406. public void testIneffectiveNegationDifferentLevels3() throws IOException {
  407. writeIgnoreFile(".gitignore", "a/b/e/");
  408. writeIgnoreFile("a/b/.gitignore", "!e/*");
  409. writeTrashFile("a/b/e/nothere.o", "");
  410. beginWalk();
  411. assertEntry(F, tracked, ".gitignore");
  412. assertEntry(D, tracked, "a");
  413. assertEntry(D, tracked, "a/b");
  414. assertEntry(F, tracked, "a/b/.gitignore");
  415. assertEntry(D, ignored, "a/b/e");
  416. assertEntry(F, ignored, "a/b/e/nothere.o");
  417. endWalk();
  418. }
  419. @Test
  420. public void testIneffectiveNegationDifferentLevels4() throws IOException {
  421. writeIgnoreFile(".gitignore", "a/b/e/");
  422. writeIgnoreFile("a/b/e/.gitignore", "!*");
  423. writeTrashFile("a/b/e/nothere.o", "");
  424. beginWalk();
  425. assertEntry(F, tracked, ".gitignore");
  426. assertEntry(D, tracked, "a");
  427. assertEntry(D, tracked, "a/b");
  428. assertEntry(D, ignored, "a/b/e");
  429. assertEntry(F, ignored, "a/b/e/.gitignore");
  430. assertEntry(F, ignored, "a/b/e/nothere.o");
  431. endWalk();
  432. }
  433. @Test
  434. public void testIneffectiveNegationDifferentLevels5() throws IOException {
  435. writeIgnoreFile("a/.gitignore", "b/e/");
  436. writeIgnoreFile("a/b/.gitignore", "!e/*");
  437. writeTrashFile("a/b/e/nothere.o", "");
  438. beginWalk();
  439. assertEntry(D, tracked, "a");
  440. assertEntry(F, tracked, "a/.gitignore");
  441. assertEntry(D, tracked, "a/b");
  442. assertEntry(F, tracked, "a/b/.gitignore");
  443. assertEntry(D, ignored, "a/b/e");
  444. assertEntry(F, ignored, "a/b/e/nothere.o");
  445. endWalk();
  446. }
  447. @Test
  448. public void testEmptyIgnoreRules() throws IOException {
  449. IgnoreNode node = new IgnoreNode();
  450. node.parse(writeToString("", "#", "!", "[[=a=]]"));
  451. assertEquals(new ArrayList<>(), node.getRules());
  452. node.parse(writeToString(" ", " / "));
  453. assertEquals(2, node.getRules().size());
  454. }
  455. @Test
  456. public void testSlashOnlyMatchesDirectory() throws IOException {
  457. writeIgnoreFile(".gitignore", "out/");
  458. writeTrashFile("out", "");
  459. beginWalk();
  460. assertEntry(F, tracked, ".gitignore");
  461. assertEntry(F, tracked, "out");
  462. FileUtils.delete(new File(trash, "out"));
  463. writeTrashFile("out/foo", "");
  464. beginWalk();
  465. assertEntry(F, tracked, ".gitignore");
  466. assertEntry(D, ignored, "out");
  467. assertEntry(F, ignored, "out/foo");
  468. endWalk();
  469. }
  470. @Test
  471. public void testSlashMatchesDirectory() throws IOException {
  472. writeIgnoreFile(".gitignore", "out2/");
  473. writeTrashFile("out1/out1", "");
  474. writeTrashFile("out1/out2", "");
  475. writeTrashFile("out2/out1", "");
  476. writeTrashFile("out2/out2", "");
  477. beginWalk();
  478. assertEntry(F, tracked, ".gitignore");
  479. assertEntry(D, tracked, "out1");
  480. assertEntry(F, tracked, "out1/out1");
  481. assertEntry(F, tracked, "out1/out2");
  482. assertEntry(D, ignored, "out2");
  483. assertEntry(F, ignored, "out2/out1");
  484. assertEntry(F, ignored, "out2/out2");
  485. endWalk();
  486. }
  487. @Test
  488. public void testWildcardWithSlashMatchesDirectory() throws IOException {
  489. writeIgnoreFile(".gitignore", "out2*/");
  490. writeTrashFile("out1/out1.txt", "");
  491. writeTrashFile("out1/out2", "");
  492. writeTrashFile("out1/out2.txt", "");
  493. writeTrashFile("out1/out2x/a", "");
  494. writeTrashFile("out2/out1.txt", "");
  495. writeTrashFile("out2/out2.txt", "");
  496. writeTrashFile("out2x/out1.txt", "");
  497. writeTrashFile("out2x/out2.txt", "");
  498. beginWalk();
  499. assertEntry(F, tracked, ".gitignore");
  500. assertEntry(D, tracked, "out1");
  501. assertEntry(F, tracked, "out1/out1.txt");
  502. assertEntry(F, tracked, "out1/out2");
  503. assertEntry(F, tracked, "out1/out2.txt");
  504. assertEntry(D, ignored, "out1/out2x");
  505. assertEntry(F, ignored, "out1/out2x/a");
  506. assertEntry(D, ignored, "out2");
  507. assertEntry(F, ignored, "out2/out1.txt");
  508. assertEntry(F, ignored, "out2/out2.txt");
  509. assertEntry(D, ignored, "out2x");
  510. assertEntry(F, ignored, "out2x/out1.txt");
  511. assertEntry(F, ignored, "out2x/out2.txt");
  512. endWalk();
  513. }
  514. @Test
  515. public void testWithSlashDoesNotMatchInSubDirectory() throws IOException {
  516. writeIgnoreFile(".gitignore", "a/b");
  517. writeTrashFile("a/a", "");
  518. writeTrashFile("a/b", "");
  519. writeTrashFile("src/a/a", "");
  520. writeTrashFile("src/a/b", "");
  521. beginWalk();
  522. assertEntry(F, tracked, ".gitignore");
  523. assertEntry(D, tracked, "a");
  524. assertEntry(F, tracked, "a/a");
  525. assertEntry(F, ignored, "a/b");
  526. assertEntry(D, tracked, "src");
  527. assertEntry(D, tracked, "src/a");
  528. assertEntry(F, tracked, "src/a/a");
  529. assertEntry(F, tracked, "src/a/b");
  530. endWalk();
  531. }
  532. @Test
  533. public void testNoPatterns() throws IOException {
  534. writeIgnoreFile(".gitignore", "", " ", "# comment", "/");
  535. writeTrashFile("a/a", "");
  536. beginWalk();
  537. assertEntry(F, tracked, ".gitignore");
  538. assertEntry(D, tracked, "a");
  539. assertEntry(F, tracked, "a/a");
  540. endWalk();
  541. }
  542. @Test
  543. public void testLeadingSpaces() throws IOException {
  544. writeTrashFile(" a/ a", "");
  545. writeTrashFile(" a/ a", "");
  546. writeTrashFile(" a/a", "");
  547. writeTrashFile(" a/ a", "");
  548. writeTrashFile(" a/ a", "");
  549. writeTrashFile(" a/a", "");
  550. writeIgnoreFile(".gitignore", " a", " a");
  551. writeTrashFile("a/ a", "");
  552. writeTrashFile("a/ a", "");
  553. writeTrashFile("a/a", "");
  554. beginWalk();
  555. assertEntry(D, ignored, " a");
  556. assertEntry(F, ignored, " a/ a");
  557. assertEntry(F, ignored, " a/ a");
  558. assertEntry(F, ignored, " a/a");
  559. assertEntry(D, ignored, " a");
  560. assertEntry(F, ignored, " a/ a");
  561. assertEntry(F, ignored, " a/ a");
  562. assertEntry(F, ignored, " a/a");
  563. assertEntry(F, tracked, ".gitignore");
  564. assertEntry(D, tracked, "a");
  565. assertEntry(F, ignored, "a/ a");
  566. assertEntry(F, ignored, "a/ a");
  567. assertEntry(F, tracked, "a/a");
  568. endWalk();
  569. }
  570. @Test
  571. public void testTrailingSpaces() throws IOException {
  572. // Windows can't create files with trailing spaces
  573. // If this assumption fails the test is halted and ignored.
  574. org.junit.Assume.assumeFalse(SystemReader.getInstance().isWindows());
  575. writeTrashFile("a /a", "");
  576. writeTrashFile("a /a ", "");
  577. writeTrashFile("a /a ", "");
  578. writeTrashFile("a /a", "");
  579. writeTrashFile("a /a ", "");
  580. writeTrashFile("a /a ", "");
  581. writeTrashFile("a/a", "");
  582. writeTrashFile("a/a ", "");
  583. writeTrashFile("a/a ", "");
  584. writeTrashFile("b/c", "");
  585. writeIgnoreFile(".gitignore", "a\\ ", "a \\ ", "b/ ");
  586. beginWalk();
  587. assertEntry(F, tracked, ".gitignore");
  588. assertEntry(D, ignored, "a ");
  589. assertEntry(F, ignored, "a /a");
  590. assertEntry(F, ignored, "a /a ");
  591. assertEntry(F, ignored, "a /a ");
  592. assertEntry(D, ignored, "a ");
  593. assertEntry(F, ignored, "a /a");
  594. assertEntry(F, ignored, "a /a ");
  595. assertEntry(F, ignored, "a /a ");
  596. assertEntry(D, tracked, "a");
  597. assertEntry(F, tracked, "a/a");
  598. assertEntry(F, ignored, "a/a ");
  599. assertEntry(F, ignored, "a/a ");
  600. assertEntry(D, ignored, "b");
  601. assertEntry(F, ignored, "b/c");
  602. endWalk();
  603. }
  604. @Test
  605. public void testToString() throws Exception {
  606. assertEquals(Arrays.asList("").toString(), new IgnoreNode().toString());
  607. assertEquals(Arrays.asList("hello").toString(),
  608. new IgnoreNode(Arrays.asList(new FastIgnoreRule("hello")))
  609. .toString());
  610. }
  611. private void beginWalk() {
  612. walk = new TreeWalk(db);
  613. FileTreeIterator iter = new FileTreeIterator(db);
  614. iter.setWalkIgnoredDirectories(true);
  615. walk.addTree(iter);
  616. }
  617. private void endWalk() throws IOException {
  618. assertFalse("Not all files tested", walk.next());
  619. }
  620. private void assertEntry(FileMode type, boolean entryIgnored,
  621. String pathName) throws IOException {
  622. assertTrue("walk has entry", walk.next());
  623. assertEquals(pathName, walk.getPathString());
  624. assertEquals(type, walk.getFileMode(0));
  625. WorkingTreeIterator itr = walk.getTree(0, WorkingTreeIterator.class);
  626. assertNotNull("has tree", itr);
  627. assertEquals("is ignored", entryIgnored, itr.isEntryIgnored());
  628. if (D.equals(type))
  629. walk.enterSubtree();
  630. }
  631. private void writeIgnoreFile(String name, String... rules)
  632. throws IOException {
  633. StringBuilder data = new StringBuilder();
  634. for (String line : rules)
  635. data.append(line + "\n");
  636. writeTrashFile(name, data.toString());
  637. }
  638. private InputStream writeToString(String... rules) {
  639. StringBuilder data = new StringBuilder();
  640. for (String line : rules) {
  641. data.append(line + "\n");
  642. }
  643. return new ByteArrayInputStream(data.toString().getBytes(UTF_8));
  644. }
  645. }