View Javadoc
1   /*
2    * This program and the accompanying materials are made available
3    * under the terms of the Eclipse Distribution License v1.0 which
4    * accompanies this distribution, is reproduced below, and is
5    * available at http://www.eclipse.org/org/documents/edl-v10.php
6    *
7    * All rights reserved.
8    *
9    * Redistribution and use in source and binary forms, with or
10   * without modification, are permitted provided that the following
11   * conditions are met:
12   *
13   * - Redistributions of source code must retain the above copyright
14   *   notice, this list of conditions and the following disclaimer.
15   *
16   * - Redistributions in binary form must reproduce the above
17   *   copyright notice, this list of conditions and the following
18   *   disclaimer in the documentation and/or other materials provided
19   *   with the distribution.
20   *
21   * - Neither the name of the Eclipse Foundation, Inc. nor the
22   *   names of its contributors may be used to endorse or promote
23   *   products derived from this software without specific prior
24   *   written permission.
25   *
26   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
27   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
28   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
38   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39   */
40  package org.eclipse.jgit.attributes;
41  
42  import static org.junit.Assert.assertEquals;
43  import static org.junit.Assert.assertFalse;
44  import static org.junit.Assert.assertTrue;
45  
46  import java.io.File;
47  import java.io.IOException;
48  import java.util.ArrayList;
49  import java.util.Collection;
50  import java.util.Collections;
51  
52  import org.eclipse.jgit.junit.RepositoryTestCase;
53  import org.eclipse.jgit.lib.ConfigConstants;
54  import org.eclipse.jgit.lib.Constants;
55  import org.eclipse.jgit.lib.FileMode;
56  import org.eclipse.jgit.storage.file.FileBasedConfig;
57  import org.eclipse.jgit.treewalk.FileTreeIterator;
58  import org.eclipse.jgit.treewalk.TreeWalk;
59  import org.junit.Test;
60  
61  /**
62   * Tests {@link AttributesHandler}
63   */
64  public class AttributesHandlerTest extends RepositoryTestCase {
65  	private static final FileMode D = FileMode.TREE;
66  
67  	private static final FileMode F = FileMode.REGULAR_FILE;
68  
69  	private TreeWalk walk;
70  
71  	@Test
72  	public void testExpandNonMacro1() throws Exception {
73  		setupRepo(null, null, null, "*.txt text");
74  
75  		walk = beginWalk();
76  		assertIteration(D, "sub");
77  		assertIteration(F, "sub/.gitattributes");
78  		assertIteration(F, "sub/a.txt", attrs("text"));
79  		endWalk();
80  	}
81  
82  	@Test
83  	public void testExpandNonMacro2() throws Exception {
84  		setupRepo(null, null, null, "*.txt -text");
85  
86  		walk = beginWalk();
87  		assertIteration(D, "sub");
88  		assertIteration(F, "sub/.gitattributes");
89  		assertIteration(F, "sub/a.txt", attrs("-text"));
90  		endWalk();
91  	}
92  
93  	@Test
94  	public void testExpandNonMacro3() throws Exception {
95  		setupRepo(null, null, null, "*.txt !text");
96  
97  		walk = beginWalk();
98  		assertIteration(D, "sub");
99  		assertIteration(F, "sub/.gitattributes");
100 		assertIteration(F, "sub/a.txt", attrs(""));
101 		endWalk();
102 	}
103 
104 	@Test
105 	public void testExpandNonMacro4() throws Exception {
106 		setupRepo(null, null, null, "*.txt text=auto");
107 
108 		walk = beginWalk();
109 		assertIteration(D, "sub");
110 		assertIteration(F, "sub/.gitattributes");
111 		assertIteration(F, "sub/a.txt", attrs("text=auto"));
112 		endWalk();
113 	}
114 
115 	@Test
116 	public void testExpandBuiltInMacro1() throws Exception {
117 		setupRepo(null, null, null, "*.txt binary");
118 
119 		walk = beginWalk();
120 		assertIteration(D, "sub");
121 		assertIteration(F, "sub/.gitattributes");
122 		assertIteration(F, "sub/a.txt", attrs("binary -diff -merge -text"));
123 		endWalk();
124 	}
125 
126 	@Test
127 	public void testExpandBuiltInMacro2() throws Exception {
128 		setupRepo(null, null, null, "*.txt -binary");
129 
130 		walk = beginWalk();
131 		assertIteration(D, "sub");
132 		assertIteration(F, "sub/.gitattributes");
133 		assertIteration(F, "sub/a.txt", attrs("-binary diff merge text"));
134 		endWalk();
135 	}
136 
137 	@Test
138 	public void testExpandBuiltInMacro3() throws Exception {
139 		setupRepo(null, null, null, "*.txt !binary");
140 
141 		walk = beginWalk();
142 		assertIteration(D, "sub");
143 		assertIteration(F, "sub/.gitattributes");
144 		assertIteration(F, "sub/a.txt", attrs(""));
145 		endWalk();
146 	}
147 
148 	@Test
149 	public void testCustomGlobalMacro1() throws Exception {
150 		setupRepo(
151 				"[attr]foo a -b !c d=e", null, null, "*.txt foo");
152 
153 		walk = beginWalk();
154 		assertIteration(D, "sub");
155 		assertIteration(F, "sub/.gitattributes");
156 		assertIteration(F, "sub/a.txt", attrs("foo a -b d=e"));
157 		endWalk();
158 	}
159 
160 	@Test
161 	public void testCustomGlobalMacro2() throws Exception {
162 		setupRepo("[attr]foo a -b !c d=e", null, null, "*.txt -foo");
163 
164 		walk = beginWalk();
165 		assertIteration(D, "sub");
166 		assertIteration(F, "sub/.gitattributes");
167 		assertIteration(F, "sub/a.txt", attrs("-foo -a b d=e"));
168 		endWalk();
169 	}
170 
171 	@Test
172 	public void testCustomGlobalMacro3() throws Exception {
173 		setupRepo("[attr]foo a -b !c d=e", null, null, "*.txt !foo");
174 
175 		walk = beginWalk();
176 		assertIteration(D, "sub");
177 		assertIteration(F, "sub/.gitattributes");
178 		assertIteration(F, "sub/a.txt", attrs(""));
179 		endWalk();
180 	}
181 
182 	@Test
183 	public void testCustomGlobalMacro4() throws Exception {
184 		setupRepo("[attr]foo a -b !c d=e", null, null, "*.txt foo=bar");
185 
186 		walk = beginWalk();
187 		assertIteration(D, "sub");
188 		assertIteration(F, "sub/.gitattributes");
189 		assertIteration(F, "sub/a.txt", attrs("foo=bar a -b d=bar"));
190 		endWalk();
191 	}
192 
193 	@Test
194 	public void testInfoOverridesGlobal() throws Exception {
195 		setupRepo("[attr]foo bar1",
196 				"[attr]foo bar2", null, "*.txt foo");
197 
198 		walk = beginWalk();
199 		assertIteration(D, "sub");
200 		assertIteration(F, "sub/.gitattributes");
201 		assertIteration(F, "sub/a.txt", attrs("foo bar2"));
202 		endWalk();
203 	}
204 
205 	@Test
206 	public void testWorkDirRootOverridesGlobal() throws Exception {
207 		setupRepo("[attr]foo bar1",
208 				null,
209 				"[attr]foo bar3", "*.txt foo");
210 
211 		walk = beginWalk();
212 		assertIteration(F, ".gitattributes");
213 		assertIteration(D, "sub");
214 		assertIteration(F, "sub/.gitattributes");
215 		assertIteration(F, "sub/a.txt", attrs("foo bar3"));
216 		endWalk();
217 	}
218 
219 	@Test
220 	public void testInfoOverridesWorkDirRoot() throws Exception {
221 		setupRepo("[attr]foo bar1",
222 				"[attr]foo bar2", "[attr]foo bar3", "*.txt foo");
223 
224 		walk = beginWalk();
225 		assertIteration(F, ".gitattributes");
226 		assertIteration(D, "sub");
227 		assertIteration(F, "sub/.gitattributes");
228 		assertIteration(F, "sub/a.txt", attrs("foo bar2"));
229 		endWalk();
230 	}
231 
232 	@Test
233 	public void testRecursiveMacro() throws Exception {
234 		setupRepo(
235 				"[attr]foo x bar -foo",
236 				null, null, "*.txt foo");
237 
238 		walk = beginWalk();
239 		assertIteration(D, "sub");
240 		assertIteration(F, "sub/.gitattributes");
241 		assertIteration(F, "sub/a.txt", attrs("foo x bar"));
242 		endWalk();
243 	}
244 
245 	@Test
246 	public void testCyclicMacros() throws Exception {
247 		setupRepo(
248 				"[attr]foo x -bar\n[attr]bar y -foo", null, null, "*.txt foo");
249 
250 		walk = beginWalk();
251 		assertIteration(D, "sub");
252 		assertIteration(F, "sub/.gitattributes");
253 		assertIteration(F, "sub/a.txt", attrs("foo x -bar -y"));
254 		endWalk();
255 	}
256 
257 	private static Collection<Attribute> attrs(String s) {
258 		return new AttributesRule("*", s).getAttributes();
259 	}
260 
261 	private void assertIteration(FileMode type, String pathName)
262 			throws IOException {
263 		assertIteration(type, pathName, Collections.<Attribute> emptyList());
264 	}
265 
266 	private void assertIteration(FileMode type, String pathName,
267 			Collection<Attribute> expectedAttrs) throws IOException {
268 		assertTrue("walk has entry", walk.next());
269 		assertEquals(pathName, walk.getPathString());
270 		assertEquals(type, walk.getFileMode(0));
271 
272 		if (expectedAttrs != null) {
273 			assertEquals(new ArrayList<>(expectedAttrs),
274 					new ArrayList<>(walk.getAttributes().getAll()));
275 		}
276 
277 		if (D.equals(type))
278 			walk.enterSubtree();
279 	}
280 
281 	/**
282 	 * @param globalAttributesContent
283 	 * @param infoAttributesContent
284 	 * @param rootAttributesContent
285 	 * @param subDirAttributesContent
286 	 * @throws Exception
287 	 *             Setup a repo with .gitattributes files and a test file
288 	 *             sub/a.txt
289 	 */
290 	private void setupRepo(
291 			String globalAttributesContent,
292 			String infoAttributesContent, String rootAttributesContent, String subDirAttributesContent)
293 					throws Exception {
294 		FileBasedConfig config = db.getConfig();
295 		if (globalAttributesContent != null) {
296 			File f = new File(db.getDirectory(), "global/attributes");
297 			write(f, globalAttributesContent);
298 			config.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
299 					ConfigConstants.CONFIG_KEY_ATTRIBUTESFILE,
300 					f.getAbsolutePath());
301 
302 		}
303 		if (infoAttributesContent != null) {
304 			File f = new File(db.getDirectory(), Constants.INFO_ATTRIBUTES);
305 			write(f, infoAttributesContent);
306 		}
307 		config.save();
308 
309 		if (rootAttributesContent != null) {
310 			writeAttributesFile(Constants.DOT_GIT_ATTRIBUTES,
311 					rootAttributesContent);
312 		}
313 
314 		if (subDirAttributesContent != null) {
315 			writeAttributesFile("sub/" + Constants.DOT_GIT_ATTRIBUTES,
316 					subDirAttributesContent);
317 		}
318 
319 		writeTrashFile("sub/a.txt", "a");
320 	}
321 
322 	private void writeAttributesFile(String name, String... rules)
323 			throws IOException {
324 		StringBuilder data = new StringBuilder();
325 		for (String line : rules)
326 			data.append(line + "\n");
327 		writeTrashFile(name, data.toString());
328 	}
329 
330 	private TreeWalk beginWalk() {
331 		TreeWalk newWalk = new TreeWalk(db);
332 		newWalk.addTree(new FileTreeIterator(db));
333 		return newWalk;
334 	}
335 
336 	private void endWalk() throws IOException {
337 		assertFalse("Not all files tested", walk.next());
338 	}
339 }