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