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.

FastIgnoreRuleTest.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. /*
  2. * Copyright (C) 2014, Andrey Loskutov <loskutov@gmx.de> 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 org.eclipse.jgit.ignore.internal.Strings.split;
  12. import static org.junit.Assert.assertArrayEquals;
  13. import static org.junit.Assert.assertFalse;
  14. import static org.junit.Assert.assertTrue;
  15. import static org.junit.Assert.fail;
  16. import org.junit.Before;
  17. import org.junit.Test;
  18. public class FastIgnoreRuleTest {
  19. private boolean pathMatch;
  20. @Before
  21. public void setup() {
  22. pathMatch = false;
  23. }
  24. @Test
  25. public void testSimpleCharClass() {
  26. assertMatched("][a]", "]a");
  27. assertMatched("[a]", "a");
  28. assertMatched("][a]", "]a");
  29. assertMatched("[a]", "a/");
  30. assertMatched("[a]", "a/b");
  31. assertMatched("[a]", "b/a");
  32. assertMatched("[a]", "b/a/");
  33. assertMatched("[a]", "b/a/b");
  34. assertMatched("[a]", "/a/");
  35. assertMatched("[a]", "/a/b");
  36. assertMatched("[a]", "c/a/b");
  37. assertMatched("[a]", "c/b/a");
  38. assertMatched("/[a]", "a");
  39. assertMatched("/[a]", "a/");
  40. assertMatched("/[a]", "a/b");
  41. assertMatched("/[a]", "/a");
  42. assertMatched("/[a]", "/a/");
  43. assertMatched("/[a]", "/a/b");
  44. assertMatched("[a]/", "a/");
  45. assertMatched("[a]/", "a/b");
  46. assertMatched("[a]/", "/a/");
  47. assertMatched("[a]/", "/a/b");
  48. assertMatched("/[a]/", "a/");
  49. assertMatched("/[a]/", "a/b");
  50. assertMatched("/[a]/", "/a/");
  51. assertMatched("/[a]/", "/a/b");
  52. }
  53. @Test
  54. public void testCharClass() {
  55. assertMatched("[v-z]", "x");
  56. assertMatched("[v-z]", "x/");
  57. assertMatched("[v-z]", "x/b");
  58. assertMatched("[v-z]", "b/x");
  59. assertMatched("[v-z]", "b/x/");
  60. assertMatched("[v-z]", "b/x/b");
  61. assertMatched("[v-z]", "/x/");
  62. assertMatched("[v-z]", "/x/b");
  63. assertMatched("[v-z]", "c/x/b");
  64. assertMatched("[v-z]", "c/b/x");
  65. assertMatched("/[v-z]", "x");
  66. assertMatched("/[v-z]", "x/");
  67. assertMatched("/[v-z]", "x/b");
  68. assertMatched("/[v-z]", "/x");
  69. assertMatched("/[v-z]", "/x/");
  70. assertMatched("/[v-z]", "/x/b");
  71. assertMatched("[v-z]/", "x/");
  72. assertMatched("[v-z]/", "x/b");
  73. assertMatched("[v-z]/", "/x/");
  74. assertMatched("[v-z]/", "/x/b");
  75. assertMatched("/[v-z]/", "x/");
  76. assertMatched("/[v-z]/", "x/b");
  77. assertMatched("/[v-z]/", "/x/");
  78. assertMatched("/[v-z]/", "/x/b");
  79. }
  80. @Test
  81. public void testTrailingSpaces() {
  82. assertMatched("a ", "a");
  83. assertMatched("a/ ", "a/");
  84. assertMatched("a/ ", "a/b");
  85. assertMatched("a/\\ ", "a/ ");
  86. assertNotMatched("a/\\ ", "a/");
  87. assertNotMatched("a/\\ ", "a/b");
  88. assertNotMatched("/ ", "a");
  89. }
  90. @Test
  91. public void testAsteriskDot() {
  92. assertMatched("*.a", ".a");
  93. assertMatched("*.a", "/.a");
  94. assertMatched("*.a", "a.a");
  95. assertMatched("*.a", "/b.a");
  96. assertMatched("*.a", "b.a");
  97. assertMatched("*.a", "/a/b.a");
  98. assertMatched("*.a", "/b/.a");
  99. }
  100. @Test
  101. public void testAsteriskDotDoNotMatch() {
  102. assertNotMatched("*.a", ".ab");
  103. assertNotMatched("*.a", "/.ab");
  104. assertNotMatched("*.a", "/b.ba");
  105. assertNotMatched("*.a", "a.ab");
  106. assertNotMatched("*.a", "/b.ab");
  107. assertNotMatched("*.a", "b.ab");
  108. assertNotMatched("*.a", "/a/b.ab");
  109. assertNotMatched("*.a", "/b/.ab");
  110. }
  111. @Test
  112. public void testDotAsteriskMatch() {
  113. assertMatched("a.*", "a.");
  114. assertMatched("a.*", "a./");
  115. assertMatched("a.*", "a.b");
  116. assertMatched("a.*", "b/a.b");
  117. assertMatched("a.*", "b/a.b/");
  118. assertMatched("a.*", "b/a.b/b");
  119. assertMatched("a.*", "/a.b/");
  120. assertMatched("a.*", "/a.b/b");
  121. assertMatched("a.*", "c/a.b/b");
  122. assertMatched("a.*", "c/b/a.b");
  123. assertMatched("/a.*", "a.b");
  124. assertMatched("/a.*", "a.b/");
  125. assertMatched("/a.*", "a.b/b");
  126. assertMatched("/a.*", "/a.b");
  127. assertMatched("/a.*", "/a.b/");
  128. assertMatched("/a.*", "/a.b/b");
  129. assertMatched("/a.*/b", "a.b/b");
  130. assertMatched("/a.*/b", "/a.b/b");
  131. assertMatched("/a.*/b", "/a.bc/b");
  132. assertMatched("/a.*/b", "/a./b");
  133. }
  134. @Test
  135. public void testAsterisk() {
  136. assertMatched("a*", "a");
  137. assertMatched("a*", "a/");
  138. assertMatched("a*", "ab");
  139. assertMatched("a*", "b/ab");
  140. assertMatched("a*", "b/ab/");
  141. assertMatched("a*", "b/ab/b");
  142. assertMatched("a*", "b/abc");
  143. assertMatched("a*", "b/abc/");
  144. assertMatched("a*", "b/abc/b");
  145. assertMatched("a*", "/abc/");
  146. assertMatched("a*", "/abc/b");
  147. assertMatched("a*", "c/abc/b");
  148. assertMatched("a*", "c/b/abc");
  149. assertMatched("/a*", "abc");
  150. assertMatched("/a*", "abc/");
  151. assertMatched("/a*", "abc/b");
  152. assertMatched("/a*", "/abc");
  153. assertMatched("/a*", "/abc/");
  154. assertMatched("/a*", "/abc/b");
  155. assertMatched("/a*/b", "abc/b");
  156. assertMatched("/a*/b", "/abc/b");
  157. assertMatched("/a*/b", "/abcd/b");
  158. assertMatched("/a*/b", "/a/b");
  159. }
  160. @Test
  161. public void testQuestionmark() {
  162. assertMatched("a?", "ab");
  163. assertMatched("a?", "ab/");
  164. assertMatched("a?", "b/ab");
  165. assertMatched("a?", "b/ab/");
  166. assertMatched("a?", "b/ab/b");
  167. assertMatched("a?", "/ab/");
  168. assertMatched("a?", "/ab/b");
  169. assertMatched("a?", "c/ab/b");
  170. assertMatched("a?", "c/b/ab");
  171. assertMatched("/a?", "ab");
  172. assertMatched("/a?", "ab/");
  173. assertMatched("/a?", "ab/b");
  174. assertMatched("/a?", "/ab");
  175. assertMatched("/a?", "/ab/");
  176. assertMatched("/a?", "/ab/b");
  177. assertMatched("/a?/b", "ab/b");
  178. assertMatched("/a?/b", "/ab/b");
  179. }
  180. @Test
  181. public void testQuestionmarkDoNotMatch() {
  182. assertNotMatched("a?", "a/");
  183. assertNotMatched("a?", "abc");
  184. assertNotMatched("a?", "abc/");
  185. assertNotMatched("a?", "b/abc");
  186. assertNotMatched("a?", "b/abc/");
  187. assertNotMatched("a?", "/abc/");
  188. assertNotMatched("a?", "/abc/b");
  189. assertNotMatched("a?", "c/abc/b");
  190. assertNotMatched("a?", "c/b/abc");
  191. assertNotMatched("/a?", "abc");
  192. assertNotMatched("/a?", "abc/");
  193. assertNotMatched("/a?", "abc/b");
  194. assertNotMatched("/a?", "/abc");
  195. assertNotMatched("/a?", "/abc/");
  196. assertNotMatched("/a?", "/abc/b");
  197. assertNotMatched("/a?/b", "abc/b");
  198. assertNotMatched("/a?/b", "/abc/b");
  199. assertNotMatched("/a?/b", "/a/b");
  200. }
  201. @Test
  202. public void testSimplePatterns() {
  203. assertMatched("a", "a");
  204. assertMatched("a", "a/");
  205. assertMatched("a", "a/b");
  206. assertMatched("a", "b/a");
  207. assertMatched("a", "b/a/");
  208. assertMatched("a", "b/a/b");
  209. assertMatched("a", "/a/");
  210. assertMatched("a", "/a/b");
  211. assertMatched("a", "c/a/b");
  212. assertMatched("a", "c/b/a");
  213. assertMatched("/a", "a");
  214. assertMatched("/a", "a/");
  215. assertMatched("/a", "a/b");
  216. assertMatched("/a", "/a");
  217. assertMatched("/a", "/a/");
  218. assertMatched("/a", "/a/b");
  219. assertMatched("a/", "a/");
  220. assertMatched("a/", "a/b");
  221. assertMatched("a/", "/a/");
  222. assertMatched("a/", "/a/b");
  223. assertMatched("/a/", "a/");
  224. assertMatched("/a/", "a/b");
  225. assertMatched("/a/", "/a/");
  226. assertMatched("/a/", "/a/b");
  227. }
  228. @Test
  229. public void testSimplePatternsDoNotMatch() {
  230. assertNotMatched("ab", "a");
  231. assertNotMatched("abc", "a/");
  232. assertNotMatched("abc", "a/b");
  233. assertNotMatched("a", "ab");
  234. assertNotMatched("a", "ba");
  235. assertNotMatched("a", "aa");
  236. assertNotMatched("a", "b/ab");
  237. assertNotMatched("a", "b/ba");
  238. assertNotMatched("a", "b/ba");
  239. assertNotMatched("a", "b/ab");
  240. assertNotMatched("a", "b/ba/");
  241. assertNotMatched("a", "b/ba/b");
  242. assertNotMatched("a", "/aa");
  243. assertNotMatched("a", "aa/");
  244. assertNotMatched("a", "/aa/");
  245. assertNotMatched("/a", "b/a");
  246. assertNotMatched("/a", "/b/a/");
  247. assertNotMatched("a/", "a");
  248. assertNotMatched("a/", "b/a");
  249. assertNotMatched("/a/", "a");
  250. assertNotMatched("/a/", "/a");
  251. assertNotMatched("/a/", "b/a");
  252. }
  253. @Test
  254. public void testSegments() {
  255. assertMatched("/a/b", "a/b");
  256. assertMatched("/a/b", "/a/b");
  257. assertMatched("/a/b", "/a/b/");
  258. assertMatched("/a/b", "/a/b/c");
  259. assertMatched("a/b", "a/b");
  260. assertMatched("a/b", "/a/b");
  261. assertMatched("a/b", "/a/b/");
  262. assertMatched("a/b", "/a/b/c");
  263. assertMatched("a/b/", "a/b/");
  264. assertMatched("a/b/", "/a/b/");
  265. assertMatched("a/b/", "/a/b/c");
  266. }
  267. @Test
  268. public void testSegmentsDoNotMatch() {
  269. assertNotMatched("a/b", "/a/bb");
  270. assertNotMatched("a/b", "/aa/b");
  271. assertNotMatched("a/b", "a/bb");
  272. assertNotMatched("a/b", "aa/b");
  273. assertNotMatched("a/b", "c/aa/b");
  274. assertNotMatched("a/b", "c/a/bb");
  275. assertNotMatched("a/b/", "/a/b");
  276. assertNotMatched("/a/b/", "/a/b");
  277. assertNotMatched("/a/b", "c/a/b");
  278. assertNotMatched("/a/b/", "c/a/b");
  279. assertNotMatched("/a/b/", "c/a/b/");
  280. // XXX why is it like this????
  281. assertNotMatched("a/b", "c/a/b");
  282. assertNotMatched("a/b", "c/a/b/");
  283. assertNotMatched("a/b", "c/a/b/c");
  284. assertNotMatched("a/b/", "c/a/b/");
  285. assertNotMatched("a/b/", "c/a/b/c");
  286. }
  287. @Test
  288. public void testWildmatch() {
  289. assertMatched("**/a/b", "a/b");
  290. assertMatched("**/a/b", "c/a/b");
  291. assertMatched("**/a/b", "c/d/a/b");
  292. assertMatched("**/**/a/b", "c/d/a/b");
  293. assertMatched("/**/a/b", "a/b");
  294. assertMatched("/**/a/b", "c/a/b");
  295. assertMatched("/**/a/b", "c/d/a/b");
  296. assertMatched("/**/**/a/b", "c/d/a/b");
  297. assertMatched("a/b/**", "a/b/c");
  298. assertMatched("a/b/**", "a/b/c/d/");
  299. assertMatched("a/b/**/**", "a/b/c/d");
  300. assertMatched("**/a/**/b", "c/d/a/b");
  301. assertMatched("**/a/**/b", "c/d/a/e/b");
  302. assertMatched("**/**/a/**/**/b", "c/d/a/e/b");
  303. assertMatched("/**/a/**/b", "c/d/a/b");
  304. assertMatched("/**/a/**/b", "c/d/a/e/b");
  305. assertMatched("/**/**/a/**/**/b", "c/d/a/e/b");
  306. assertMatched("a/**/b", "a/b");
  307. assertMatched("a/**/b", "a/c/b");
  308. assertMatched("a/**/b", "a/c/d/b");
  309. assertMatched("a/**/**/b", "a/c/d/b");
  310. assertMatched("a/**/b/**/c", "a/c/b/d/c");
  311. assertMatched("a/**/**/b/**/**/c", "a/c/b/d/c");
  312. assertMatched("**/", "a/");
  313. assertMatched("**/", "a/b");
  314. assertMatched("**/", "a/b/c");
  315. assertMatched("**/**/", "a/");
  316. assertMatched("**/**/", "a/b");
  317. assertMatched("**/**/", "a/b/");
  318. assertMatched("**/**/", "a/b/c");
  319. assertMatched("x/**/", "x/a/");
  320. assertMatched("x/**/", "x/a/b");
  321. assertMatched("x/**/", "x/a/b/");
  322. assertMatched("**/x/", "a/x/");
  323. assertMatched("**/x/", "a/b/x/");
  324. }
  325. @Test
  326. public void testWildmatchDoNotMatch() {
  327. assertNotMatched("a/**", "a/");
  328. assertNotMatched("a/b/**", "a/b/");
  329. assertNotMatched("a/**", "a");
  330. assertNotMatched("a/b/**", "a/b");
  331. assertNotMatched("a/b/**/", "a/b");
  332. assertNotMatched("a/b/**/**", "a/b");
  333. assertNotMatched("**/a/b", "a/c/b");
  334. assertNotMatched("!/**/*.zip", "c/a/b.zip");
  335. assertNotMatched("!**/*.zip", "c/a/b.zip");
  336. assertNotMatched("a/**/b", "a/c/bb");
  337. assertNotMatched("**/", "a");
  338. assertNotMatched("**/**/", "a");
  339. assertNotMatched("**/x/", "a/b/x");
  340. }
  341. @SuppressWarnings("unused")
  342. @Test
  343. public void testSimpleRules() {
  344. try {
  345. new FastIgnoreRule(null);
  346. fail("Illegal input allowed!");
  347. } catch (IllegalArgumentException e) {
  348. // expected
  349. }
  350. assertFalse(new FastIgnoreRule("/").isMatch("/", false));
  351. assertFalse(new FastIgnoreRule("//").isMatch("//", false));
  352. assertFalse(new FastIgnoreRule("#").isMatch("#", false));
  353. assertFalse(new FastIgnoreRule("").isMatch("", false));
  354. assertFalse(new FastIgnoreRule(" ").isMatch(" ", false));
  355. }
  356. @Test
  357. public void testSplit() {
  358. try {
  359. split("/", '/').toArray();
  360. fail("should not allow single slash");
  361. } catch (IllegalStateException e) {
  362. // expected
  363. }
  364. assertArrayEquals(new String[] { "a", "b" }, split("a/b", '/')
  365. .toArray());
  366. assertArrayEquals(new String[] { "a", "b/" }, split("a/b/", '/')
  367. .toArray());
  368. assertArrayEquals(new String[] { "/a", "b" }, split("/a/b", '/')
  369. .toArray());
  370. assertArrayEquals(new String[] { "/a", "b/" }, split("/a/b/", '/')
  371. .toArray());
  372. assertArrayEquals(new String[] { "/a", "b", "c" }, split("/a/b/c", '/')
  373. .toArray());
  374. assertArrayEquals(new String[] { "/a", "b", "c/" },
  375. split("/a/b/c/", '/').toArray());
  376. }
  377. @Test
  378. public void testPathMatch() {
  379. pathMatch = true;
  380. assertMatched("a", "a");
  381. assertMatched("a/", "a/");
  382. assertNotMatched("a/", "a/b");
  383. assertMatched("**", "a");
  384. assertMatched("**", "a/");
  385. assertMatched("**", "a/b");
  386. assertNotMatched("**/", "a");
  387. assertNotMatched("**/", "a/b");
  388. assertMatched("**/", "a/");
  389. assertMatched("**/", "a/b/");
  390. assertNotMatched("x/**/", "x/a");
  391. assertNotMatched("x/**/", "x/a/b");
  392. assertMatched("x/**/", "x/a/");
  393. assertMatched("x/**/", "x/y/a/");
  394. }
  395. @Test
  396. public void testFileNameWithLineTerminator() {
  397. assertMatched("a?", "a\r");
  398. assertMatched("a?", "dir/a\r");
  399. assertMatched("a?", "a\r/file");
  400. assertMatched("*a", "\ra");
  401. assertMatched("dir/*a*", "dir/\ra\r");
  402. }
  403. private void assertMatched(String pattern, String path) {
  404. boolean match = match(pattern, path);
  405. String result = path + " is " + (match ? "ignored" : "not ignored")
  406. + " via '" + pattern + "' rule";
  407. if (!match) {
  408. System.err.println(result);
  409. }
  410. assertTrue("Expected a match for: " + pattern + " with: " + path,
  411. match);
  412. if (pattern.startsWith("!")) {
  413. pattern = pattern.substring(1);
  414. } else {
  415. pattern = "!" + pattern;
  416. }
  417. match = match(pattern, path);
  418. assertFalse("Expected no match for: " + pattern + " with: " + path,
  419. match);
  420. }
  421. private void assertNotMatched(String pattern, String path) {
  422. boolean match = match(pattern, path);
  423. String result = path + " is " + (match ? "ignored" : "not ignored")
  424. + " via '" + pattern + "' rule";
  425. if (match) {
  426. System.err.println(result);
  427. }
  428. assertFalse("Expected no match for: " + pattern + " with: " + path,
  429. match);
  430. if (pattern.startsWith("!")) {
  431. pattern = pattern.substring(1);
  432. } else {
  433. pattern = "!" + pattern;
  434. }
  435. match = match(pattern, path);
  436. assertTrue("Expected a match for: " + pattern + " with: " + path,
  437. match);
  438. }
  439. /**
  440. * Check for a match. If target ends with "/", match will assume that the
  441. * target is meant to be a directory.
  442. *
  443. * @param pattern
  444. * Pattern as it would appear in a .gitignore file
  445. * @param target
  446. * Target file path relative to repository's GIT_DIR
  447. * @return Result of {@link FastIgnoreRule#isMatch(String, boolean)}
  448. */
  449. private boolean match(String pattern, String target) {
  450. boolean isDirectory = target.endsWith("/");
  451. FastIgnoreRule r = new FastIgnoreRule(pattern);
  452. // If speed of this test is ever an issue, we can use a presetRule field
  453. // to avoid recompiling a pattern each time.
  454. boolean match = r.isMatch(target, isDirectory, pathMatch);
  455. if (r.getNegation())
  456. match = !match;
  457. return match;
  458. }
  459. }