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