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 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. /*
  2. * Copyright (C) 2014, Andrey Loskutov <loskutov@gmx.de>
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.ignore;
  44. import static org.eclipse.jgit.ignore.internal.Strings.split;
  45. import static org.junit.Assert.assertArrayEquals;
  46. import static org.junit.Assert.assertFalse;
  47. import static org.junit.Assert.assertTrue;
  48. import static org.junit.Assert.fail;
  49. import org.junit.Before;
  50. import org.junit.Test;
  51. public class FastIgnoreRuleTest {
  52. private boolean pathMatch;
  53. @Before
  54. public void setup() {
  55. pathMatch = false;
  56. }
  57. @Test
  58. public void testSimpleCharClass() {
  59. assertMatched("][a]", "]a");
  60. assertMatched("[a]", "a");
  61. assertMatched("][a]", "]a");
  62. assertMatched("[a]", "a/");
  63. assertMatched("[a]", "a/b");
  64. assertMatched("[a]", "b/a");
  65. assertMatched("[a]", "b/a/");
  66. assertMatched("[a]", "b/a/b");
  67. assertMatched("[a]", "/a/");
  68. assertMatched("[a]", "/a/b");
  69. assertMatched("[a]", "c/a/b");
  70. assertMatched("[a]", "c/b/a");
  71. assertMatched("/[a]", "a");
  72. assertMatched("/[a]", "a/");
  73. assertMatched("/[a]", "a/b");
  74. assertMatched("/[a]", "/a");
  75. assertMatched("/[a]", "/a/");
  76. assertMatched("/[a]", "/a/b");
  77. assertMatched("[a]/", "a/");
  78. assertMatched("[a]/", "a/b");
  79. assertMatched("[a]/", "/a/");
  80. assertMatched("[a]/", "/a/b");
  81. assertMatched("/[a]/", "a/");
  82. assertMatched("/[a]/", "a/b");
  83. assertMatched("/[a]/", "/a/");
  84. assertMatched("/[a]/", "/a/b");
  85. }
  86. @Test
  87. public void testCharClass() {
  88. assertMatched("[v-z]", "x");
  89. assertMatched("[v-z]", "x/");
  90. assertMatched("[v-z]", "x/b");
  91. assertMatched("[v-z]", "b/x");
  92. assertMatched("[v-z]", "b/x/");
  93. assertMatched("[v-z]", "b/x/b");
  94. assertMatched("[v-z]", "/x/");
  95. assertMatched("[v-z]", "/x/b");
  96. assertMatched("[v-z]", "c/x/b");
  97. assertMatched("[v-z]", "c/b/x");
  98. assertMatched("/[v-z]", "x");
  99. assertMatched("/[v-z]", "x/");
  100. assertMatched("/[v-z]", "x/b");
  101. assertMatched("/[v-z]", "/x");
  102. assertMatched("/[v-z]", "/x/");
  103. assertMatched("/[v-z]", "/x/b");
  104. assertMatched("[v-z]/", "x/");
  105. assertMatched("[v-z]/", "x/b");
  106. assertMatched("[v-z]/", "/x/");
  107. assertMatched("[v-z]/", "/x/b");
  108. assertMatched("/[v-z]/", "x/");
  109. assertMatched("/[v-z]/", "x/b");
  110. assertMatched("/[v-z]/", "/x/");
  111. assertMatched("/[v-z]/", "/x/b");
  112. }
  113. @Test
  114. public void testTrailingSpaces() {
  115. assertMatched("a ", "a");
  116. assertMatched("a/ ", "a/");
  117. assertMatched("a/ ", "a/b");
  118. assertMatched("a/\\ ", "a/ ");
  119. assertNotMatched("a/\\ ", "a/");
  120. assertNotMatched("a/\\ ", "a/b");
  121. assertNotMatched("/ ", "a");
  122. }
  123. @Test
  124. public void testAsteriskDot() {
  125. assertMatched("*.a", ".a");
  126. assertMatched("*.a", "/.a");
  127. assertMatched("*.a", "a.a");
  128. assertMatched("*.a", "/b.a");
  129. assertMatched("*.a", "b.a");
  130. assertMatched("*.a", "/a/b.a");
  131. assertMatched("*.a", "/b/.a");
  132. }
  133. @Test
  134. public void testAsteriskDotDoNotMatch() {
  135. assertNotMatched("*.a", ".ab");
  136. assertNotMatched("*.a", "/.ab");
  137. assertNotMatched("*.a", "/b.ba");
  138. assertNotMatched("*.a", "a.ab");
  139. assertNotMatched("*.a", "/b.ab");
  140. assertNotMatched("*.a", "b.ab");
  141. assertNotMatched("*.a", "/a/b.ab");
  142. assertNotMatched("*.a", "/b/.ab");
  143. }
  144. @Test
  145. public void testDotAsteriskMatch() {
  146. assertMatched("a.*", "a.");
  147. assertMatched("a.*", "a./");
  148. assertMatched("a.*", "a.b");
  149. assertMatched("a.*", "b/a.b");
  150. assertMatched("a.*", "b/a.b/");
  151. assertMatched("a.*", "b/a.b/b");
  152. assertMatched("a.*", "/a.b/");
  153. assertMatched("a.*", "/a.b/b");
  154. assertMatched("a.*", "c/a.b/b");
  155. assertMatched("a.*", "c/b/a.b");
  156. assertMatched("/a.*", "a.b");
  157. assertMatched("/a.*", "a.b/");
  158. assertMatched("/a.*", "a.b/b");
  159. assertMatched("/a.*", "/a.b");
  160. assertMatched("/a.*", "/a.b/");
  161. assertMatched("/a.*", "/a.b/b");
  162. assertMatched("/a.*/b", "a.b/b");
  163. assertMatched("/a.*/b", "/a.b/b");
  164. assertMatched("/a.*/b", "/a.bc/b");
  165. assertMatched("/a.*/b", "/a./b");
  166. }
  167. @Test
  168. public void testAsterisk() {
  169. assertMatched("a*", "a");
  170. assertMatched("a*", "a/");
  171. assertMatched("a*", "ab");
  172. assertMatched("a*", "b/ab");
  173. assertMatched("a*", "b/ab/");
  174. assertMatched("a*", "b/ab/b");
  175. assertMatched("a*", "b/abc");
  176. assertMatched("a*", "b/abc/");
  177. assertMatched("a*", "b/abc/b");
  178. assertMatched("a*", "/abc/");
  179. assertMatched("a*", "/abc/b");
  180. assertMatched("a*", "c/abc/b");
  181. assertMatched("a*", "c/b/abc");
  182. assertMatched("/a*", "abc");
  183. assertMatched("/a*", "abc/");
  184. assertMatched("/a*", "abc/b");
  185. assertMatched("/a*", "/abc");
  186. assertMatched("/a*", "/abc/");
  187. assertMatched("/a*", "/abc/b");
  188. assertMatched("/a*/b", "abc/b");
  189. assertMatched("/a*/b", "/abc/b");
  190. assertMatched("/a*/b", "/abcd/b");
  191. assertMatched("/a*/b", "/a/b");
  192. }
  193. @Test
  194. public void testQuestionmark() {
  195. assertMatched("a?", "ab");
  196. assertMatched("a?", "ab/");
  197. assertMatched("a?", "b/ab");
  198. assertMatched("a?", "b/ab/");
  199. assertMatched("a?", "b/ab/b");
  200. assertMatched("a?", "/ab/");
  201. assertMatched("a?", "/ab/b");
  202. assertMatched("a?", "c/ab/b");
  203. assertMatched("a?", "c/b/ab");
  204. assertMatched("/a?", "ab");
  205. assertMatched("/a?", "ab/");
  206. assertMatched("/a?", "ab/b");
  207. assertMatched("/a?", "/ab");
  208. assertMatched("/a?", "/ab/");
  209. assertMatched("/a?", "/ab/b");
  210. assertMatched("/a?/b", "ab/b");
  211. assertMatched("/a?/b", "/ab/b");
  212. }
  213. @Test
  214. public void testQuestionmarkDoNotMatch() {
  215. assertNotMatched("a?", "a/");
  216. assertNotMatched("a?", "abc");
  217. assertNotMatched("a?", "abc/");
  218. assertNotMatched("a?", "b/abc");
  219. assertNotMatched("a?", "b/abc/");
  220. assertNotMatched("a?", "/abc/");
  221. assertNotMatched("a?", "/abc/b");
  222. assertNotMatched("a?", "c/abc/b");
  223. assertNotMatched("a?", "c/b/abc");
  224. assertNotMatched("/a?", "abc");
  225. assertNotMatched("/a?", "abc/");
  226. assertNotMatched("/a?", "abc/b");
  227. assertNotMatched("/a?", "/abc");
  228. assertNotMatched("/a?", "/abc/");
  229. assertNotMatched("/a?", "/abc/b");
  230. assertNotMatched("/a?/b", "abc/b");
  231. assertNotMatched("/a?/b", "/abc/b");
  232. assertNotMatched("/a?/b", "/a/b");
  233. }
  234. @Test
  235. public void testSimplePatterns() {
  236. assertMatched("a", "a");
  237. assertMatched("a", "a/");
  238. assertMatched("a", "a/b");
  239. assertMatched("a", "b/a");
  240. assertMatched("a", "b/a/");
  241. assertMatched("a", "b/a/b");
  242. assertMatched("a", "/a/");
  243. assertMatched("a", "/a/b");
  244. assertMatched("a", "c/a/b");
  245. assertMatched("a", "c/b/a");
  246. assertMatched("/a", "a");
  247. assertMatched("/a", "a/");
  248. assertMatched("/a", "a/b");
  249. assertMatched("/a", "/a");
  250. assertMatched("/a", "/a/");
  251. assertMatched("/a", "/a/b");
  252. assertMatched("a/", "a/");
  253. assertMatched("a/", "a/b");
  254. assertMatched("a/", "/a/");
  255. assertMatched("a/", "/a/b");
  256. assertMatched("/a/", "a/");
  257. assertMatched("/a/", "a/b");
  258. assertMatched("/a/", "/a/");
  259. assertMatched("/a/", "/a/b");
  260. }
  261. @Test
  262. public void testSimplePatternsDoNotMatch() {
  263. assertNotMatched("ab", "a");
  264. assertNotMatched("abc", "a/");
  265. assertNotMatched("abc", "a/b");
  266. assertNotMatched("a", "ab");
  267. assertNotMatched("a", "ba");
  268. assertNotMatched("a", "aa");
  269. assertNotMatched("a", "b/ab");
  270. assertNotMatched("a", "b/ba");
  271. assertNotMatched("a", "b/ba");
  272. assertNotMatched("a", "b/ab");
  273. assertNotMatched("a", "b/ba/");
  274. assertNotMatched("a", "b/ba/b");
  275. assertNotMatched("a", "/aa");
  276. assertNotMatched("a", "aa/");
  277. assertNotMatched("a", "/aa/");
  278. assertNotMatched("/a", "b/a");
  279. assertNotMatched("/a", "/b/a/");
  280. assertNotMatched("a/", "a");
  281. assertNotMatched("a/", "b/a");
  282. assertNotMatched("/a/", "a");
  283. assertNotMatched("/a/", "/a");
  284. assertNotMatched("/a/", "b/a");
  285. }
  286. @Test
  287. public void testSegments() {
  288. assertMatched("/a/b", "a/b");
  289. assertMatched("/a/b", "/a/b");
  290. assertMatched("/a/b", "/a/b/");
  291. assertMatched("/a/b", "/a/b/c");
  292. assertMatched("a/b", "a/b");
  293. assertMatched("a/b", "/a/b");
  294. assertMatched("a/b", "/a/b/");
  295. assertMatched("a/b", "/a/b/c");
  296. assertMatched("a/b/", "a/b/");
  297. assertMatched("a/b/", "/a/b/");
  298. assertMatched("a/b/", "/a/b/c");
  299. }
  300. @Test
  301. public void testSegmentsDoNotMatch() {
  302. assertNotMatched("a/b", "/a/bb");
  303. assertNotMatched("a/b", "/aa/b");
  304. assertNotMatched("a/b", "a/bb");
  305. assertNotMatched("a/b", "aa/b");
  306. assertNotMatched("a/b", "c/aa/b");
  307. assertNotMatched("a/b", "c/a/bb");
  308. assertNotMatched("a/b/", "/a/b");
  309. assertNotMatched("/a/b/", "/a/b");
  310. assertNotMatched("/a/b", "c/a/b");
  311. assertNotMatched("/a/b/", "c/a/b");
  312. assertNotMatched("/a/b/", "c/a/b/");
  313. // XXX why is it like this????
  314. assertNotMatched("a/b", "c/a/b");
  315. assertNotMatched("a/b", "c/a/b/");
  316. assertNotMatched("a/b", "c/a/b/c");
  317. assertNotMatched("a/b/", "c/a/b/");
  318. assertNotMatched("a/b/", "c/a/b/c");
  319. }
  320. @Test
  321. public void testWildmatch() {
  322. assertMatched("**/a/b", "a/b");
  323. assertMatched("**/a/b", "c/a/b");
  324. assertMatched("**/a/b", "c/d/a/b");
  325. assertMatched("**/**/a/b", "c/d/a/b");
  326. assertMatched("/**/a/b", "a/b");
  327. assertMatched("/**/a/b", "c/a/b");
  328. assertMatched("/**/a/b", "c/d/a/b");
  329. assertMatched("/**/**/a/b", "c/d/a/b");
  330. assertMatched("a/b/**", "a/b/c");
  331. assertMatched("a/b/**", "a/b/c/d/");
  332. assertMatched("a/b/**/**", "a/b/c/d");
  333. assertMatched("**/a/**/b", "c/d/a/b");
  334. assertMatched("**/a/**/b", "c/d/a/e/b");
  335. assertMatched("**/**/a/**/**/b", "c/d/a/e/b");
  336. assertMatched("/**/a/**/b", "c/d/a/b");
  337. assertMatched("/**/a/**/b", "c/d/a/e/b");
  338. assertMatched("/**/**/a/**/**/b", "c/d/a/e/b");
  339. assertMatched("a/**/b", "a/b");
  340. assertMatched("a/**/b", "a/c/b");
  341. assertMatched("a/**/b", "a/c/d/b");
  342. assertMatched("a/**/**/b", "a/c/d/b");
  343. assertMatched("a/**/b/**/c", "a/c/b/d/c");
  344. assertMatched("a/**/**/b/**/**/c", "a/c/b/d/c");
  345. assertMatched("**/", "a/");
  346. assertMatched("**/", "a/b");
  347. assertMatched("**/", "a/b/c");
  348. assertMatched("**/**/", "a/");
  349. assertMatched("**/**/", "a/b");
  350. assertMatched("**/**/", "a/b/");
  351. assertMatched("**/**/", "a/b/c");
  352. assertMatched("x/**/", "x/a/");
  353. assertMatched("x/**/", "x/a/b");
  354. assertMatched("x/**/", "x/a/b/");
  355. assertMatched("**/x/", "a/x/");
  356. assertMatched("**/x/", "a/b/x/");
  357. }
  358. @Test
  359. public void testWildmatchDoNotMatch() {
  360. assertNotMatched("a/**", "a/");
  361. assertNotMatched("a/b/**", "a/b/");
  362. assertNotMatched("a/**", "a");
  363. assertNotMatched("a/b/**", "a/b");
  364. assertNotMatched("a/b/**/", "a/b");
  365. assertNotMatched("a/b/**/**", "a/b");
  366. assertNotMatched("**/a/b", "a/c/b");
  367. assertNotMatched("!/**/*.zip", "c/a/b.zip");
  368. assertNotMatched("!**/*.zip", "c/a/b.zip");
  369. assertNotMatched("a/**/b", "a/c/bb");
  370. assertNotMatched("**/", "a");
  371. assertNotMatched("**/**/", "a");
  372. assertNotMatched("**/x/", "a/b/x");
  373. }
  374. @SuppressWarnings("unused")
  375. @Test
  376. public void testSimpleRules() {
  377. try {
  378. new FastIgnoreRule(null);
  379. fail("Illegal input allowed!");
  380. } catch (IllegalArgumentException e) {
  381. // expected
  382. }
  383. assertFalse(new FastIgnoreRule("/").isMatch("/", false));
  384. assertFalse(new FastIgnoreRule("//").isMatch("//", false));
  385. assertFalse(new FastIgnoreRule("#").isMatch("#", false));
  386. assertFalse(new FastIgnoreRule("").isMatch("", false));
  387. assertFalse(new FastIgnoreRule(" ").isMatch(" ", false));
  388. }
  389. @Test
  390. public void testSplit() {
  391. try {
  392. split("/", '/').toArray();
  393. fail("should not allow single slash");
  394. } catch (IllegalStateException e) {
  395. // expected
  396. }
  397. assertArrayEquals(new String[] { "a", "b" }, split("a/b", '/')
  398. .toArray());
  399. assertArrayEquals(new String[] { "a", "b/" }, split("a/b/", '/')
  400. .toArray());
  401. assertArrayEquals(new String[] { "/a", "b" }, split("/a/b", '/')
  402. .toArray());
  403. assertArrayEquals(new String[] { "/a", "b/" }, split("/a/b/", '/')
  404. .toArray());
  405. assertArrayEquals(new String[] { "/a", "b", "c" }, split("/a/b/c", '/')
  406. .toArray());
  407. assertArrayEquals(new String[] { "/a", "b", "c/" },
  408. split("/a/b/c/", '/').toArray());
  409. }
  410. @Test
  411. public void testPathMatch() {
  412. pathMatch = true;
  413. assertMatched("a", "a");
  414. assertMatched("a/", "a/");
  415. assertNotMatched("a/", "a/b");
  416. assertMatched("**", "a");
  417. assertMatched("**", "a/");
  418. assertMatched("**", "a/b");
  419. assertNotMatched("**/", "a");
  420. assertNotMatched("**/", "a/b");
  421. assertMatched("**/", "a/");
  422. assertMatched("**/", "a/b/");
  423. assertNotMatched("x/**/", "x/a");
  424. assertNotMatched("x/**/", "x/a/b");
  425. assertMatched("x/**/", "x/a/");
  426. assertMatched("x/**/", "x/y/a/");
  427. }
  428. @Test
  429. public void testFileNameWithLineTerminator() {
  430. assertMatched("a?", "a\r");
  431. assertMatched("a?", "dir/a\r");
  432. assertMatched("a?", "a\r/file");
  433. assertMatched("*a", "\ra");
  434. assertMatched("dir/*a*", "dir/\ra\r");
  435. }
  436. private void assertMatched(String pattern, String path) {
  437. boolean match = match(pattern, path);
  438. String result = path + " is " + (match ? "ignored" : "not ignored")
  439. + " via '" + pattern + "' rule";
  440. if (!match) {
  441. System.err.println(result);
  442. }
  443. assertTrue("Expected a match for: " + pattern + " with: " + path,
  444. match);
  445. if (pattern.startsWith("!")) {
  446. pattern = pattern.substring(1);
  447. } else {
  448. pattern = "!" + pattern;
  449. }
  450. match = match(pattern, path);
  451. assertFalse("Expected no match for: " + pattern + " with: " + path,
  452. match);
  453. }
  454. private void assertNotMatched(String pattern, String path) {
  455. boolean match = match(pattern, path);
  456. String result = path + " is " + (match ? "ignored" : "not ignored")
  457. + " via '" + pattern + "' rule";
  458. if (match) {
  459. System.err.println(result);
  460. }
  461. assertFalse("Expected no match for: " + pattern + " with: " + path,
  462. match);
  463. if (pattern.startsWith("!")) {
  464. pattern = pattern.substring(1);
  465. } else {
  466. pattern = "!" + pattern;
  467. }
  468. match = match(pattern, path);
  469. assertTrue("Expected a match for: " + pattern + " with: " + path,
  470. match);
  471. }
  472. /**
  473. * Check for a match. If target ends with "/", match will assume that the
  474. * target is meant to be a directory.
  475. *
  476. * @param pattern
  477. * Pattern as it would appear in a .gitignore file
  478. * @param target
  479. * Target file path relative to repository's GIT_DIR
  480. * @return Result of {@link FastIgnoreRule#isMatch(String, boolean)}
  481. */
  482. private boolean match(String pattern, String target) {
  483. boolean isDirectory = target.endsWith("/");
  484. FastIgnoreRule r = new FastIgnoreRule(pattern);
  485. // If speed of this test is ever an issue, we can use a presetRule field
  486. // to avoid recompiling a pattern each time.
  487. boolean match = r.isMatch(target, isDirectory, pathMatch);
  488. if (r.getNegation())
  489. match = !match;
  490. return match;
  491. }
  492. }