View Javadoc
1   /*
2    * Copyright (C) 2011, Abhishek Bhatnagar <abhatnag@redhat.com>
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.api;
44  
45  import static org.eclipse.jgit.lib.Constants.DOT_GIT_MODULES;
46  import static org.junit.Assert.assertEquals;
47  import static org.junit.Assert.assertFalse;
48  import static org.junit.Assert.assertTrue;
49  
50  import java.io.File;
51  import java.io.IOException;
52  import java.util.Set;
53  import java.util.TreeSet;
54  
55  import org.eclipse.jgit.api.errors.GitAPIException;
56  import org.eclipse.jgit.api.errors.NoFilepatternException;
57  import org.eclipse.jgit.errors.NoWorkTreeException;
58  import org.eclipse.jgit.junit.RepositoryTestCase;
59  import org.eclipse.jgit.lib.Repository;
60  import org.junit.Before;
61  import org.junit.Test;
62  
63  /**
64   * Tests for CleanCommand
65   */
66  public class CleanCommandTest extends RepositoryTestCase {
67  	private Git git;
68  
69  	@Override
70  	@Before
71  	public void setUp() throws Exception {
72  		super.setUp();
73  		git = new Git(db);
74  
75  		// create test files
76  		writeTrashFile("File1.txt", "Hello world");
77  		writeTrashFile("File2.txt", "Delete Me");
78  		writeTrashFile("File3.txt", "Delete Me");
79  
80  		// create files in sub-directories.
81  		writeTrashFile("sub-noclean/File1.txt", "Hello world");
82  		writeTrashFile("sub-noclean/File2.txt", "Delete Me");
83  		writeTrashFile("sub-clean/File4.txt", "Delete Me");
84  		writeTrashFile("sub-noclean/Ignored.txt", "Ignored");
85  		writeTrashFile(".gitignore", "/ignored-dir\n/sub-noclean/Ignored.txt");
86  		writeTrashFile("ignored-dir/Ignored2.txt", "Ignored");
87  
88  		// add and commit first file
89  		git.add().addFilepattern("File1.txt").call();
90  		git.add().addFilepattern("sub-noclean/File1.txt").call();
91  		git.add().addFilepattern(".gitignore").call();
92  		git.commit().setMessage("Initial commit").call();
93  	}
94  
95  	@Test
96  	public void testClean() throws NoWorkTreeException, GitAPIException {
97  		// create status
98  		StatusCommand command = git.status();
99  		Status status = command.call();
100 		Set<String> files = status.getUntracked();
101 		assertTrue(files.size() > 0);
102 
103 		// run clean
104 		Set<String> cleanedFiles = git.clean().call();
105 
106 		status = git.status().call();
107 		files = status.getUntracked();
108 
109 		assertTrue(files.size() == 1); // one remains (directories not cleaned)
110 		assertTrue(cleanedFiles.contains("File2.txt"));
111 		assertTrue(cleanedFiles.contains("File3.txt"));
112 		assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
113 		assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
114 		assertTrue(!cleanedFiles.contains("sub-clean/File4.txt"));
115 	}
116 
117 	@Test
118 	public void testCleanDirs() throws NoWorkTreeException, GitAPIException {
119 		// create status
120 		StatusCommand command = git.status();
121 		Status status = command.call();
122 		Set<String> files = status.getUntracked();
123 		assertTrue(files.size() > 0);
124 
125 		// run clean
126 		Set<String> cleanedFiles = git.clean().setCleanDirectories(true).call();
127 
128 		status = git.status().call();
129 		files = status.getUntracked();
130 
131 		assertTrue(files.size() == 0);
132 		assertTrue(cleanedFiles.contains("File2.txt"));
133 		assertTrue(cleanedFiles.contains("File3.txt"));
134 		assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
135 		assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
136 		assertTrue(cleanedFiles.contains("sub-clean/"));
137 	}
138 
139 	@Test
140 	public void testCleanWithPaths() throws NoWorkTreeException,
141 			GitAPIException {
142 		// create status
143 		StatusCommand command = git.status();
144 		Status status = command.call();
145 		Set<String> files = status.getUntracked();
146 		assertTrue(files.size() > 0);
147 
148 		// run clean with setPaths
149 		Set<String> paths = new TreeSet<>();
150 		paths.add("File3.txt");
151 		Set<String> cleanedFiles = git.clean().setPaths(paths).call();
152 
153 		status = git.status().call();
154 		files = status.getUntracked();
155 		assertTrue(files.size() == 3);
156 		assertTrue(cleanedFiles.contains("File3.txt"));
157 		assertFalse(cleanedFiles.contains("File2.txt"));
158 	}
159 
160 	@Test
161 	public void testCleanWithDryRun() throws NoWorkTreeException,
162 			GitAPIException {
163 		// create status
164 		StatusCommand command = git.status();
165 		Status status = command.call();
166 		Set<String> files = status.getUntracked();
167 		assertTrue(files.size() > 0);
168 
169 		// run clean
170 		Set<String> cleanedFiles = git.clean().setDryRun(true).call();
171 
172 		status = git.status().call();
173 		files = status.getUntracked();
174 
175 		assertEquals(4, files.size());
176 		assertTrue(cleanedFiles.contains("File2.txt"));
177 		assertTrue(cleanedFiles.contains("File3.txt"));
178 		assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
179 		assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
180 	}
181 
182 	@Test
183 	public void testCleanDirsWithDryRun() throws NoWorkTreeException,
184 			GitAPIException {
185 		// create status
186 		StatusCommand command = git.status();
187 		Status status = command.call();
188 		Set<String> files = status.getUntracked();
189 		assertTrue(files.size() > 0);
190 
191 		// run clean
192 		Set<String> cleanedFiles = git.clean().setDryRun(true)
193 				.setCleanDirectories(true).call();
194 
195 		status = git.status().call();
196 		files = status.getUntracked();
197 
198 		assertTrue(files.size() == 4);
199 		assertTrue(cleanedFiles.contains("File2.txt"));
200 		assertTrue(cleanedFiles.contains("File3.txt"));
201 		assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
202 		assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
203 		assertTrue(cleanedFiles.contains("sub-clean/"));
204 	}
205 
206 	@Test
207 	public void testCleanWithDryRunAndNoIgnore() throws NoWorkTreeException,
208 			GitAPIException {
209 		// run clean
210 		Set<String> cleanedFiles = git.clean().setDryRun(true).setIgnore(false)
211 				.call();
212 
213 		Status status = git.status().call();
214 		Set<String> files = status.getIgnoredNotInIndex();
215 
216 		assertTrue(files.size() == 2);
217 		assertTrue(cleanedFiles.contains("sub-noclean/Ignored.txt"));
218 		assertTrue(!cleanedFiles.contains("ignored-dir/"));
219 	}
220 
221 	@Test
222 	public void testCleanDirsWithDryRunAndNoIgnore()
223 			throws NoWorkTreeException, GitAPIException {
224 		// run clean
225 		Set<String> cleanedFiles = git.clean().setDryRun(true).setIgnore(false)
226 				.setCleanDirectories(true).call();
227 
228 		Status status = git.status().call();
229 		Set<String> files = status.getIgnoredNotInIndex();
230 
231 		assertTrue(files.size() == 2);
232 		assertTrue(cleanedFiles.contains("sub-noclean/Ignored.txt"));
233 		assertTrue(cleanedFiles.contains("ignored-dir/"));
234 	}
235 
236 	@Test
237 	public void testCleanDirsWithPrefixFolder() throws Exception {
238 		String path = "sub/foo.txt";
239 		writeTrashFile(path, "sub is a prefix of sub-noclean");
240 		git.add().addFilepattern(path).call();
241 		Status beforeCleanStatus = git.status().call();
242 		assertTrue(beforeCleanStatus.getAdded().contains(path));
243 
244 		Set<String> cleanedFiles = git.clean().setCleanDirectories(true).call();
245 
246 		// The "sub" directory should not be cleaned.
247 		assertTrue(!cleanedFiles.contains(path + "/"));
248 
249 		assertTrue(cleanedFiles.contains("File2.txt"));
250 		assertTrue(cleanedFiles.contains("File3.txt"));
251 		assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
252 		assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
253 		assertTrue(cleanedFiles.contains("sub-clean/"));
254 		assertTrue(cleanedFiles.size() == 4);
255 	}
256 
257 	@Test
258 	public void testCleanDirsWithSubmodule() throws Exception {
259 		SubmoduleAddCommand command = new SubmoduleAddCommand(db);
260 		String path = "sub";
261 		command.setPath(path);
262 		String uri = db.getDirectory().toURI().toString();
263 		command.setURI(uri);
264 		try (Repository repo = command.call()) {
265 			// Unused
266 		}
267 
268 		Status beforeCleanStatus = git.status().call();
269 		assertTrue(beforeCleanStatus.getAdded().contains(DOT_GIT_MODULES));
270 		assertTrue(beforeCleanStatus.getAdded().contains(path));
271 
272 		Set<String> cleanedFiles = git.clean().setCleanDirectories(true).call();
273 
274 		// The submodule should not be cleaned.
275 		assertTrue(!cleanedFiles.contains(path + "/"));
276 
277 		assertTrue(cleanedFiles.contains("File2.txt"));
278 		assertTrue(cleanedFiles.contains("File3.txt"));
279 		assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
280 		assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
281 		assertTrue(cleanedFiles.contains("sub-clean/"));
282 		assertTrue(cleanedFiles.size() == 4);
283 	}
284 
285 	@Test
286 	public void testCleanDirsWithRepository() throws Exception {
287 		// Set up a repository inside the outer repository
288 		String innerRepoName = "inner-repo";
289 		File innerDir = new File(trash, innerRepoName);
290 		innerDir.mkdir();
291 		InitCommand initRepoCommand = new InitCommand();
292 		initRepoCommand.setDirectory(innerDir);
293 		initRepoCommand.call();
294 
295 		Status beforeCleanStatus = git.status().call();
296 		Set<String> untrackedFolders = beforeCleanStatus.getUntrackedFolders();
297 		Set<String> untrackedFiles = beforeCleanStatus.getUntracked();
298 
299 		// The inner repository should be listed as an untracked file
300 		assertTrue(untrackedFiles.contains(innerRepoName));
301 
302 		// The inner repository should not be listed as an untracked folder
303 		assertTrue(!untrackedFolders.contains(innerRepoName));
304 
305 		Set<String> cleanedFiles = git.clean().setCleanDirectories(true).call();
306 
307 		// The inner repository should not be cleaned.
308 		assertTrue(!cleanedFiles.contains(innerRepoName + "/"));
309 
310 		assertTrue(cleanedFiles.contains("File2.txt"));
311 		assertTrue(cleanedFiles.contains("File3.txt"));
312 		assertTrue(!cleanedFiles.contains("sub-noclean/File1.txt"));
313 		assertTrue(cleanedFiles.contains("sub-noclean/File2.txt"));
314 		assertTrue(cleanedFiles.contains("sub-clean/"));
315 		assertTrue(cleanedFiles.size() == 4);
316 
317 		Set<String> forceCleanedFiles = git.clean().setCleanDirectories(true)
318 				.setForce(true).call();
319 
320 		// The inner repository should be cleaned this time
321 		assertTrue(forceCleanedFiles.contains(innerRepoName + "/"));
322 	}
323 
324 	@Test
325 	// To proof Bug 514434. No assertions, but before the bugfix
326 	// this test was throwing Exceptions
327 	public void testFilesShouldBeCleanedInSubSubFolders()
328 			throws IOException, NoFilepatternException, GitAPIException {
329 		writeTrashFile(".gitignore",
330 				"/ignored-dir\n/sub-noclean/Ignored.txt\n/this_is_ok\n/this_is/not_ok\n");
331 		git.add().addFilepattern(".gitignore").call();
332 		git.commit().setMessage("adding .gitignore").call();
333 		writeTrashFile("this_is_ok/more/subdirs/file.txt", "1");
334 		writeTrashFile("this_is/not_ok/more/subdirs/file.txt", "2");
335 		git.clean().setCleanDirectories(true).setIgnore(false).call();
336 	}
337 }