1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 package org.eclipse.jgit.ignore;
44
45 import static org.eclipse.jgit.junit.Assert.assertEquals;
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertTrue;
48 import static org.junit.Assert.assertFalse;
49 import static org.junit.Assert.assertNotNull;
50
51 import java.io.File;
52 import java.io.IOException;
53 import java.util.Arrays;
54
55 import org.eclipse.jgit.errors.CorruptObjectException;
56 import org.eclipse.jgit.ignore.IgnoreNode.MatchResult;
57 import org.eclipse.jgit.junit.RepositoryTestCase;
58 import org.eclipse.jgit.lib.FileMode;
59 import org.eclipse.jgit.treewalk.FileTreeIterator;
60 import org.eclipse.jgit.treewalk.TreeWalk;
61 import org.eclipse.jgit.treewalk.WorkingTreeIterator;
62 import org.eclipse.jgit.util.FileUtils;
63 import org.junit.Test;
64
65
66
67
68 public class IgnoreNodeTest extends RepositoryTestCase {
69 private static final FileMode D = FileMode.TREE;
70
71 private static final FileMode F = FileMode.REGULAR_FILE;
72
73 private static final boolean ignored = true;
74
75 private static final boolean tracked = false;
76
77 private TreeWalk walk;
78
79 @Test
80 public void testRules() throws IOException {
81 writeIgnoreFile(".git/info/exclude", "*~", "/out");
82
83 writeIgnoreFile(".gitignore", "*.o", "/config");
84 writeTrashFile("config/secret", "");
85 writeTrashFile("mylib.c", "");
86 writeTrashFile("mylib.c~", "");
87 writeTrashFile("mylib.o", "");
88
89 writeTrashFile("out/object/foo.exe", "");
90 writeIgnoreFile("src/config/.gitignore", "lex.out");
91 writeTrashFile("src/config/lex.out", "");
92 writeTrashFile("src/config/config.c", "");
93 writeTrashFile("src/config/config.c~", "");
94 writeTrashFile("src/config/old/lex.out", "");
95
96 beginWalk();
97 assertEntry(F, tracked, ".gitignore");
98 assertEntry(D, ignored, "config");
99 assertEntry(F, ignored, "config/secret");
100 assertEntry(F, tracked, "mylib.c");
101 assertEntry(F, ignored, "mylib.c~");
102 assertEntry(F, ignored, "mylib.o");
103
104 assertEntry(D, ignored, "out");
105 assertEntry(D, ignored, "out/object");
106 assertEntry(F, ignored, "out/object/foo.exe");
107
108 assertEntry(D, tracked, "src");
109 assertEntry(D, tracked, "src/config");
110 assertEntry(F, tracked, "src/config/.gitignore");
111 assertEntry(F, tracked, "src/config/config.c");
112 assertEntry(F, ignored, "src/config/config.c~");
113 assertEntry(F, ignored, "src/config/lex.out");
114 assertEntry(D, tracked, "src/config/old");
115 assertEntry(F, ignored, "src/config/old/lex.out");
116 endWalk();
117 }
118
119 @Test
120 public void testNegation() throws IOException {
121
122 writeIgnoreFile(".gitignore", "*.o", "d");
123
124
125 writeIgnoreFile("src/a/b/.gitignore", "!keep.o");
126 writeTrashFile("src/a/b/keep.o", "");
127 writeTrashFile("src/a/b/nothere.o", "");
128
129
130 writeIgnoreFile("src/c/.gitignore", "!d");
131
132 writeIgnoreFile("src/c/d/.gitignore", "!keep.o");
133 writeTrashFile("src/c/d/keep.o", "");
134 writeTrashFile("src/c/d/nothere.o", "");
135
136 beginWalk();
137 assertEntry(F, tracked, ".gitignore");
138 assertEntry(D, tracked, "src");
139 assertEntry(D, tracked, "src/a");
140 assertEntry(D, tracked, "src/a/b");
141 assertEntry(F, tracked, "src/a/b/.gitignore");
142 assertEntry(F, tracked, "src/a/b/keep.o");
143 assertEntry(F, ignored, "src/a/b/nothere.o");
144
145 assertEntry(D, tracked, "src/c");
146 assertEntry(F, tracked, "src/c/.gitignore");
147 assertEntry(D, tracked, "src/c/d");
148 assertEntry(F, tracked, "src/c/d/.gitignore");
149 assertEntry(F, tracked, "src/c/d/keep.o");
150
151 assertEntry(F, ignored, "src/c/d/nothere.o");
152 endWalk();
153 }
154
155
156
157
158 @Test
159 public void testNegateAllExceptJavaInSrc() throws IOException {
160
161 writeIgnoreFile(".gitignore", "/*", "!/src/");
162 writeTrashFile("nothere.o", "");
163
164
165 writeIgnoreFile("src/.gitignore", "*", "!*.java");
166
167 writeTrashFile("src/keep.java", "");
168 writeTrashFile("src/nothere.o", "");
169 writeTrashFile("src/a/nothere.o", "");
170
171 beginWalk();
172 assertEntry(F, ignored, ".gitignore");
173 assertEntry(F, ignored, "nothere.o");
174 assertEntry(D, tracked, "src");
175 assertEntry(F, ignored, "src/.gitignore");
176 assertEntry(D, ignored, "src/a");
177 assertEntry(F, ignored, "src/a/nothere.o");
178 assertEntry(F, tracked, "src/keep.java");
179 assertEntry(F, ignored, "src/nothere.o");
180 endWalk();
181 }
182
183
184
185
186 @Test
187 public void testNegationAllExceptJavaInSrcAndExceptChildDirInSrc()
188 throws IOException {
189
190 writeIgnoreFile(".gitignore", "/*", "!/src/");
191 writeTrashFile("nothere.o", "");
192
193
194
195 writeIgnoreFile("src/.gitignore", "*", "!*.java", "!*/");
196
197 writeTrashFile("src/keep.java", "");
198 writeTrashFile("src/nothere.o", "");
199 writeTrashFile("src/a/keep.java", "");
200 writeTrashFile("src/a/keep.o", "");
201
202 beginWalk();
203 assertEntry(F, ignored, ".gitignore");
204 assertEntry(F, ignored, "nothere.o");
205 assertEntry(D, tracked, "src");
206 assertEntry(F, ignored, "src/.gitignore");
207 assertEntry(D, tracked, "src/a");
208 assertEntry(F, tracked, "src/a/keep.java");
209 assertEntry(F, tracked, "src/a/keep.o");
210 assertEntry(F, tracked, "src/keep.java");
211 assertEntry(F, ignored, "src/nothere.o");
212 endWalk();
213 }
214
215
216
217
218 @Test
219 public void testRepeatedNegation() throws IOException {
220 writeIgnoreFile(".gitignore", "e", "!e", "e", "!e", "e");
221
222 writeTrashFile("e/nothere.o", "");
223
224 beginWalk();
225 assertEntry(F, tracked, ".gitignore");
226 assertEntry(D, ignored, "e");
227 assertEntry(F, ignored, "e/nothere.o");
228 endWalk();
229 }
230
231
232
233
234 @Test
235 public void testRepeatedNegationInDifferentFiles1() throws IOException {
236 writeIgnoreFile(".gitignore", "*.o", "e");
237
238 writeIgnoreFile("e/.gitignore", "!e");
239 writeTrashFile("e/nothere.o", "");
240
241 beginWalk();
242 assertEntry(F, tracked, ".gitignore");
243 assertEntry(D, ignored, "e");
244 assertEntry(F, ignored, "e/.gitignore");
245 assertEntry(F, ignored, "e/nothere.o");
246 endWalk();
247 }
248
249
250
251
252 @Test
253 public void testRepeatedNegationInDifferentFiles2() throws IOException {
254 writeIgnoreFile(".gitignore", "*.o", "e");
255
256 writeIgnoreFile("a/.gitignore", "!e");
257 writeTrashFile("a/e/nothere.o", "");
258
259 beginWalk();
260 assertEntry(F, tracked, ".gitignore");
261 assertEntry(D, tracked, "a");
262 assertEntry(F, tracked, "a/.gitignore");
263 assertEntry(D, tracked, "a/e");
264 assertEntry(F, ignored, "a/e/nothere.o");
265 endWalk();
266 }
267
268
269
270
271 @Test
272 public void testRepeatedNegationInDifferentFiles3() throws IOException {
273 writeIgnoreFile(".gitignore", "*.o");
274
275 writeIgnoreFile("a/.gitignore", "e");
276 writeIgnoreFile("a/b/.gitignore", "!e");
277 writeTrashFile("a/b/e/nothere.o", "");
278
279 beginWalk();
280 assertEntry(F, tracked, ".gitignore");
281 assertEntry(D, tracked, "a");
282 assertEntry(F, tracked, "a/.gitignore");
283 assertEntry(D, tracked, "a/b");
284 assertEntry(F, tracked, "a/b/.gitignore");
285 assertEntry(D, tracked, "a/b/e");
286 assertEntry(F, ignored, "a/b/e/nothere.o");
287 endWalk();
288 }
289
290 @Test
291 public void testRepeatedNegationInDifferentFiles4() throws IOException {
292 writeIgnoreFile(".gitignore", "*.o");
293
294 writeIgnoreFile("a/.gitignore", "e");
295
296
297 writeIgnoreFile("a/b/.gitignore", "#");
298 writeIgnoreFile("a/b/c/.gitignore", "!e");
299 writeTrashFile("a/b/c/e/nothere.o", "");
300
301 beginWalk();
302 assertEntry(F, tracked, ".gitignore");
303 assertEntry(D, tracked, "a");
304 assertEntry(F, tracked, "a/.gitignore");
305 assertEntry(D, tracked, "a/b");
306 assertEntry(F, tracked, "a/b/.gitignore");
307 assertEntry(D, tracked, "a/b/c");
308 assertEntry(F, tracked, "a/b/c/.gitignore");
309 assertEntry(D, tracked, "a/b/c/e");
310 assertEntry(F, ignored, "a/b/c/e/nothere.o");
311 endWalk();
312 }
313
314 @Test
315 public void testEmptyIgnoreNode() {
316
317
318
319 IgnoreNode node = new IgnoreNode();
320 assertEquals(MatchResult.CHECK_PARENT, node.isIgnored("", false));
321 assertEquals(MatchResult.CHECK_PARENT, node.isIgnored("", false, false));
322 assertEquals(MatchResult.CHECK_PARENT_NEGATE_FIRST_MATCH,
323 node.isIgnored("", false, true));
324 }
325
326 @Test
327 public void testSlashOnlyMatchesDirectory() throws IOException {
328 writeIgnoreFile(".gitignore", "out/");
329 writeTrashFile("out", "");
330
331 beginWalk();
332 assertEntry(F, tracked, ".gitignore");
333 assertEntry(F, tracked, "out");
334
335 FileUtils.delete(new File(trash, "out"));
336 writeTrashFile("out/foo", "");
337
338 beginWalk();
339 assertEntry(F, tracked, ".gitignore");
340 assertEntry(D, ignored, "out");
341 assertEntry(F, ignored, "out/foo");
342 endWalk();
343 }
344
345 @Test
346 public void testWithSlashDoesNotMatchInSubDirectory() throws IOException {
347 writeIgnoreFile(".gitignore", "a/b");
348 writeTrashFile("a/a", "");
349 writeTrashFile("a/b", "");
350 writeTrashFile("src/a/a", "");
351 writeTrashFile("src/a/b", "");
352
353 beginWalk();
354 assertEntry(F, tracked, ".gitignore");
355 assertEntry(D, tracked, "a");
356 assertEntry(F, tracked, "a/a");
357 assertEntry(F, ignored, "a/b");
358 assertEntry(D, tracked, "src");
359 assertEntry(D, tracked, "src/a");
360 assertEntry(F, tracked, "src/a/a");
361 assertEntry(F, tracked, "src/a/b");
362 endWalk();
363 }
364
365 @Test
366 public void testNoPatterns() throws IOException {
367 writeIgnoreFile(".gitignore", "", " ", "# comment", "/");
368 writeTrashFile("a/a", "");
369
370 beginWalk();
371 assertEntry(F, tracked, ".gitignore");
372 assertEntry(D, tracked, "a");
373 assertEntry(F, tracked, "a/a");
374 endWalk();
375 }
376
377 @Test
378 public void testToString() throws Exception {
379 assertEquals(Arrays.asList("").toString(), new IgnoreNode().toString());
380 assertEquals(Arrays.asList("hello").toString(),
381 new IgnoreNode(Arrays.asList(new FastIgnoreRule("hello")))
382 .toString());
383 }
384
385 private void beginWalk() throws CorruptObjectException {
386 walk = new TreeWalk(db);
387 walk.addTree(new FileTreeIterator(db));
388 }
389
390 private void endWalk() throws IOException {
391 assertFalse("Not all files tested", walk.next());
392 }
393
394 private void assertEntry(FileMode type, boolean entryIgnored,
395 String pathName) throws IOException {
396 assertTrue("walk has entry", walk.next());
397 assertEquals(pathName, walk.getPathString());
398 assertEquals(type, walk.getFileMode(0));
399
400 WorkingTreeIterator itr = walk.getTree(0, WorkingTreeIterator.class);
401 assertNotNull("has tree", itr);
402 assertEquals("is ignored", entryIgnored, itr.isEntryIgnored());
403 if (D.equals(type))
404 walk.enterSubtree();
405 }
406
407 private void writeIgnoreFile(String name, String... rules)
408 throws IOException {
409 StringBuilder data = new StringBuilder();
410 for (String line : rules)
411 data.append(line + "\n");
412 writeTrashFile(name, data.toString());
413 }
414 }