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