View Javadoc
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  
12  import static org.junit.Assert.assertFalse;
13  import static org.junit.Assert.assertTrue;
14  import static org.junit.Assume.assumeFalse;
15  import static org.junit.Assume.assumeTrue;
16  
17  import org.eclipse.jgit.junit.Assert;
18  import org.junit.Test;
19  
20  /**
21   * Tests ignore pattern matches
22   */
23  public class IgnoreMatcherParametrizedTest {
24  
25  	@Test
26  	public void testBasic() {
27  		String pattern = "/test.stp";
28  		assertMatched(pattern, "/test.stp");
29  
30  		pattern = "#/test.stp";
31  		assertNotMatched(pattern, "/test.stp");
32  	}
33  
34  	@Test
35  	public void testFileNameWildcards() {
36  		// Test basic * and ? for any pattern + any character
37  		String pattern = "*.st?";
38  		assertMatched(pattern, "/test.stp");
39  		assertMatched(pattern, "/anothertest.stg");
40  		assertMatched(pattern, "/anothertest.st0");
41  		assertNotMatched(pattern, "/anothertest.sta1");
42  		// Check that asterisk does not expand to "/"
43  		assertNotMatched(pattern, "/another/test.sta1");
44  
45  		// Same as above, with a leading slash to ensure that doesn't cause
46  		// problems
47  		pattern = "/*.st?";
48  		assertMatched(pattern, "/test.stp");
49  		assertMatched(pattern, "/anothertest.stg");
50  		assertMatched(pattern, "/anothertest.st0");
51  		assertNotMatched(pattern, "/anothertest.sta1");
52  		// Check that asterisk does not expand to "/"
53  		assertNotMatched(pattern, "/another/test.sta1");
54  
55  		// Test for numbers
56  		pattern = "*.sta[0-5]";
57  		assertMatched(pattern, "/test.sta5");
58  		assertMatched(pattern, "/test.sta4");
59  		assertMatched(pattern, "/test.sta3");
60  		assertMatched(pattern, "/test.sta2");
61  		assertMatched(pattern, "/test.sta1");
62  		assertMatched(pattern, "/test.sta0");
63  		assertMatched(pattern, "/anothertest.sta2");
64  		assertNotMatched(pattern, "test.stag");
65  		assertNotMatched(pattern, "test.sta6");
66  
67  		// Test for letters
68  		pattern = "/[tv]est.sta[a-d]";
69  		assertMatched(pattern, "/test.staa");
70  		assertMatched(pattern, "/test.stab");
71  		assertMatched(pattern, "/test.stac");
72  		assertMatched(pattern, "/test.stad");
73  		assertMatched(pattern, "/vest.stac");
74  		assertNotMatched(pattern, "test.stae");
75  		assertNotMatched(pattern, "test.sta9");
76  
77  		// Test child directory/file is matched
78  		pattern = "/src/ne?";
79  		assertMatched(pattern, "/src/new/");
80  		assertMatched(pattern, "/src/new");
81  		assertMatched(pattern, "/src/new/a.c");
82  		assertMatched(pattern, "/src/new/a/a.c");
83  		assertNotMatched(pattern, "/src/new.c");
84  
85  		// Test name-only fnmatcher matches
86  		pattern = "ne?";
87  		assertMatched(pattern, "/src/new/");
88  		assertMatched(pattern, "/src/new");
89  		assertMatched(pattern, "/src/new/a.c");
90  		assertMatched(pattern, "/src/new/a/a.c");
91  		assertMatched(pattern, "/neb");
92  		assertNotMatched(pattern, "/src/new.c");
93  	}
94  
95  	@Test
96  	public void testTargetWithoutLeadingSlash() {
97  		// Test basic * and ? for any pattern + any character
98  		String pattern = "/*.st?";
99  		assertMatched(pattern, "test.stp");
100 		assertMatched(pattern, "anothertest.stg");
101 		assertMatched(pattern, "anothertest.st0");
102 		assertNotMatched(pattern, "anothertest.sta1");
103 		// Check that asterisk does not expand to ""
104 		assertNotMatched(pattern, "another/test.sta1");
105 
106 		// Same as above, with a leading slash to ensure that doesn't cause
107 		// problems
108 		pattern = "/*.st?";
109 		assertMatched(pattern, "test.stp");
110 		assertMatched(pattern, "anothertest.stg");
111 		assertMatched(pattern, "anothertest.st0");
112 		assertNotMatched(pattern, "anothertest.sta1");
113 		// Check that asterisk does not expand to ""
114 		assertNotMatched(pattern, "another/test.sta1");
115 
116 		// Test for numbers
117 		pattern = "/*.sta[0-5]";
118 		assertMatched(pattern, "test.sta5");
119 		assertMatched(pattern, "test.sta4");
120 		assertMatched(pattern, "test.sta3");
121 		assertMatched(pattern, "test.sta2");
122 		assertMatched(pattern, "test.sta1");
123 		assertMatched(pattern, "test.sta0");
124 		assertMatched(pattern, "anothertest.sta2");
125 		assertNotMatched(pattern, "test.stag");
126 		assertNotMatched(pattern, "test.sta6");
127 
128 		// Test for letters
129 		pattern = "/[tv]est.sta[a-d]";
130 		assertMatched(pattern, "test.staa");
131 		assertMatched(pattern, "test.stab");
132 		assertMatched(pattern, "test.stac");
133 		assertMatched(pattern, "test.stad");
134 		assertMatched(pattern, "vest.stac");
135 		assertNotMatched(pattern, "test.stae");
136 		assertNotMatched(pattern, "test.sta9");
137 
138 		// Test child directory/file is matched
139 		pattern = "/src/ne?";
140 		assertMatched(pattern, "src/new/");
141 		assertMatched(pattern, "src/new");
142 		assertMatched(pattern, "src/new/a.c");
143 		assertMatched(pattern, "src/new/a/a.c");
144 		assertNotMatched(pattern, "src/new.c");
145 
146 		// Test name-only fnmatcher matches
147 		pattern = "ne?";
148 		assertMatched(pattern, "src/new/");
149 		assertMatched(pattern, "src/new");
150 		assertMatched(pattern, "src/new/a.c");
151 		assertMatched(pattern, "src/new/a/a.c");
152 		assertMatched(pattern, "neb");
153 		assertNotMatched(pattern, "src/new.c");
154 	}
155 
156 	@Test
157 	public void testParentDirectoryGitIgnores() {
158 		// Contains git ignore patterns such as might be seen in a parent
159 		// directory
160 
161 		// Test for wildcards
162 		String pattern = "/*/*.c";
163 		assertMatched(pattern, "/file/a.c");
164 		assertMatched(pattern, "/src/a.c");
165 		assertNotMatched(pattern, "/src/new/a.c");
166 
167 		// Test child directory/file is matched
168 		pattern = "/src/new";
169 		assertMatched(pattern, "/src/new/");
170 		assertMatched(pattern, "/src/new");
171 		assertMatched(pattern, "/src/new/a.c");
172 		assertMatched(pattern, "/src/new/a/a.c");
173 		assertNotMatched(pattern, "/src/new.c");
174 
175 		// Test child directory is matched, slash after name
176 		pattern = "/src/new/";
177 		assertMatched(pattern, "/src/new/");
178 		assertMatched(pattern, "/src/new/a.c");
179 		assertMatched(pattern, "/src/new/a/a.c");
180 		assertNotMatched(pattern, "/src/new");
181 		assertNotMatched(pattern, "/src/new.c");
182 
183 		// Test directory is matched by name only
184 		pattern = "b1";
185 		assertMatched(pattern, "/src/new/a/b1/a.c");
186 		assertNotMatched(pattern, "/src/new/a/b2/file.c");
187 		assertNotMatched(pattern, "/src/new/a/bb1/file.c");
188 		assertNotMatched(pattern, "/src/new/a/file.c");
189 	}
190 
191 	@Test
192 	public void testDirModeAndNoRegex() {
193 		String pattern = "/src/";
194 		assertMatched(pattern, "/src/");
195 		assertMatched(pattern, "/src/new");
196 		assertMatched(pattern, "/src/new/a.c");
197 		assertMatched(pattern, "/src/a.c");
198 		// no match as a "file" pattern, because rule is for directories only
199 		assertNotMatched(pattern, "/src");
200 		assertNotMatched(pattern, "/srcA/");
201 	}
202 
203 	@Test
204 	public void testDirModeAndRegex1() {
205 		String pattern = "a/*/src/";
206 		assertMatched(pattern, "a/b/src/");
207 		assertMatched(pattern, "a/b/src/new");
208 		assertMatched(pattern, "a/b/src/new/a.c");
209 		assertMatched(pattern, "a/b/src/a.c");
210 		// no match as a "file" pattern, because rule is for directories only
211 		assertNotMatched(pattern, "a/b/src");
212 		assertNotMatched(pattern, "a/b/srcA/");
213 	}
214 
215 	@Test
216 	public void testDirModeAndRegex2() {
217 		String pattern = "a/[a-b]/src/";
218 		assertMatched(pattern, "a/b/src/");
219 		assertMatched(pattern, "a/b/src/new");
220 		assertMatched(pattern, "a/b/src/new/a.c");
221 		assertMatched(pattern, "a/b/src/a.c");
222 		// no match as a "file" pattern, because rule is for directories only
223 		assertNotMatched(pattern, "a/b/src");
224 		assertNotMatched(pattern, "a/b/srcA/");
225 	}
226 
227 	@Test
228 	public void testDirModeAndRegex3() {
229 		String pattern = "**/src/";
230 		assertMatched(pattern, "a/b/src/");
231 		assertMatched(pattern, "a/b/src/new");
232 		assertMatched(pattern, "a/b/src/new/a.c");
233 		assertMatched(pattern, "a/b/src/a.c");
234 		// no match as a "file" pattern, because rule is for directories only
235 		assertNotMatched(pattern, "a/b/src");
236 		assertNotMatched(pattern, "a/b/srcA/");
237 	}
238 
239 	@Test
240 	public void testNameOnlyMatches() {
241 		/*
242 		 * Name-only matches do not contain any path separators
243 		 */
244 		// Test matches for file extension
245 		String pattern = "*.stp";
246 		assertMatched(pattern, "/test.stp");
247 		assertMatched(pattern, "/src/test.stp");
248 		assertNotMatched(pattern, "/test.stp1");
249 		assertNotMatched(pattern, "/test.astp");
250 
251 		// Test matches for name-only, applies to file name or folder name
252 		pattern = "src";
253 		assertMatched(pattern, "/src");
254 		assertMatched(pattern, "/src/");
255 		assertMatched(pattern, "/src/a.c");
256 		assertMatched(pattern, "/src/new/a.c");
257 		assertMatched(pattern, "/new/src/a.c");
258 		assertMatched(pattern, "/file/src");
259 
260 		// Test matches for name-only, applies only to folder names
261 		pattern = "src/";
262 		assertMatched(pattern, "/src/");
263 		assertMatched(pattern, "/src/a.c");
264 		assertMatched(pattern, "/src/new/a.c");
265 		assertMatched(pattern, "/new/src/a.c");
266 		assertNotMatched(pattern, "/src");
267 		assertNotMatched(pattern, "/file/src");
268 
269 		// Test matches for name-only, applies to file name or folder name
270 		// With a small wildcard
271 		pattern = "?rc";
272 		assertMatched(pattern, "/src/a.c");
273 		assertMatched(pattern, "/src/new/a.c");
274 		assertMatched(pattern, "/new/src/a.c");
275 		assertMatched(pattern, "/file/src");
276 		assertMatched(pattern, "/src/");
277 
278 		// Test matches for name-only, applies to file name or folder name
279 		// With a small wildcard
280 		pattern = "?r[a-c]";
281 		assertMatched(pattern, "/src/a.c");
282 		assertMatched(pattern, "/src/new/a.c");
283 		assertMatched(pattern, "/new/src/a.c");
284 		assertMatched(pattern, "/file/src");
285 		assertMatched(pattern, "/src/");
286 		assertMatched(pattern, "/srb/a.c");
287 		assertMatched(pattern, "/grb/new/a.c");
288 		assertMatched(pattern, "/new/crb/a.c");
289 		assertMatched(pattern, "/file/3rb");
290 		assertMatched(pattern, "/xrb/");
291 		assertMatched(pattern, "/3ra/a.c");
292 		assertMatched(pattern, "/5ra/new/a.c");
293 		assertMatched(pattern, "/new/1ra/a.c");
294 		assertMatched(pattern, "/file/dra");
295 		assertMatched(pattern, "/era/");
296 		assertNotMatched(pattern, "/crg");
297 		assertNotMatched(pattern, "/cr3");
298 	}
299 
300 	@Test
301 	public void testNegation() {
302 		String pattern = "!/test.stp";
303 		assertMatched(pattern, "/test.stp");
304 	}
305 
306 	/**
307 	 * Check for a match. If target ends with "/", match will assume that the
308 	 * target is meant to be a directory.
309 	 *
310 	 * @param pattern
311 	 *            Pattern as it would appear in a .gitignore file
312 	 * @param target
313 	 *            Target file path relative to repository's GIT_DIR
314 	 * @param assume
315 	 */
316 	private void assertMatched(String pattern, String target, Boolean... assume) {
317 		boolean value = match(pattern, target);
318 		if (assume.length == 0 || !assume[0].booleanValue())
319 			assertTrue("Expected a match for: " + pattern + " with: " + target,
320 					value);
321 		else
322 			assumeTrue("Expected a match for: " + pattern + " with: " + target,
323 					value);
324 	}
325 
326 	/**
327 	 * Check for a match. If target ends with "/", match will assume that the
328 	 * target is meant to be a directory.
329 	 *
330 	 * @param pattern
331 	 *            Pattern as it would appear in a .gitignore file
332 	 * @param target
333 	 *            Target file path relative to repository's GIT_DIR
334 	 * @param assume
335 	 */
336 	private void assertNotMatched(String pattern, String target,
337 			Boolean... assume) {
338 		boolean value = match(pattern, target);
339 		if (assume.length == 0 || !assume[0].booleanValue())
340 			assertFalse("Expected no match for: " + pattern + " with: "
341 					+ target, value);
342 		else
343 			assumeFalse("Expected no match for: " + pattern + " with: "
344 					+ target, value);
345 	}
346 
347 	/**
348 	 * Check for a match. If target ends with "/", match will assume that the
349 	 * target is meant to be a directory.
350 	 *
351 	 * @param pattern
352 	 *            Pattern as it would appear in a .gitignore file
353 	 * @param target
354 	 *            Target file path relative to repository's GIT_DIR
355 	 * @return Result of {@link FastIgnoreRule#isMatch(String, boolean)}
356 	 */
357 	private boolean match(String pattern, String target) {
358 		boolean isDirectory = target.endsWith("/");
359 		boolean match;
360 		FastIgnoreRule r = new FastIgnoreRule(pattern);
361 		match = r.isMatch(target, isDirectory);
362 
363 		if (isDirectory) {
364 			boolean noTrailingSlash = matchAsDir(pattern,
365 					target.substring(0, target.length() - 1));
366 			if (match != noTrailingSlash) {
367 				String message = "Difference in result for directory pattern: "
368 						+ pattern + " with: " + target
369 						+ " if target is given without trailing slash";
370 				Assert.assertEquals(message, match, noTrailingSlash);
371 			}
372 		}
373 		return match;
374 	}
375 
376 	/**
377 	 *
378 	 * @param target
379 	 *            must not ends with a slash!
380 	 * @param pattern
381 	 *            same as {@link #match(String, String)}
382 	 * @return same as {@link #match(String, String)}
383 	 */
384 	private boolean matchAsDir(String pattern, String target) {
385 		assertFalse(target.endsWith("/"));
386 		FastIgnoreRule r = new FastIgnoreRule(pattern);
387 		return r.isMatch(target, true);
388 	}
389 }