blob: fa7f5ab522fc34dd908f0424ad00569bda48a1b3 [file] [log] [blame]
/*
* Copyright (C) 2014, Christian Halstrick <christian.halstrick@sap.com>
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.lib;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Set;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.submodule.SubmoduleWalk.IgnoreSubmoduleMode;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.junit.Before;
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;
@RunWith(Theories.class)
public class IndexDiffSubmoduleTest extends RepositoryTestCase {
/** a submodule repository inside a root repository */
protected FileRepository submodule_db;
/** Working directory of the submodule repository */
protected File submodule_trash;
@DataPoints
public static IgnoreSubmoduleMode allModes[] = IgnoreSubmoduleMode.values();
@Override
@Before
public void setUp() throws Exception {
super.setUp();
FileRepository submoduleStandalone = createWorkRepository();
JGitTestUtil.writeTrashFile(submoduleStandalone, "fileInSubmodule",
"submodule");
Git submoduleStandaloneGit = Git.wrap(submoduleStandalone);
submoduleStandaloneGit.add().addFilepattern("fileInSubmodule").call();
submoduleStandaloneGit.commit().setMessage("add file to submodule")
.call();
submodule_db = (FileRepository) Git.wrap(db).submoduleAdd()
.setPath("modules/submodule")
.setURI(submoduleStandalone.getDirectory().toURI().toString())
.call();
submodule_trash = submodule_db.getWorkTree();
addRepoToClose(submodule_db);
writeTrashFile("fileInRoot", "root");
Git rootGit = Git.wrap(db);
rootGit.add().addFilepattern("fileInRoot").call();
rootGit.commit().setMessage("add submodule and root file").call();
}
@Theory
public void testInitiallyClean(IgnoreSubmoduleMode mode)
throws IOException {
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertFalse(indexDiff.diff());
}
private Repository cloneWithoutCloningSubmodule() throws Exception {
File directory = createTempDirectory(
"testCloneWithoutCloningSubmodules");
CloneCommand clone = Git.cloneRepository();
clone.setDirectory(directory);
clone.setCloneSubmodules(false);
clone.setURI(db.getDirectory().toURI().toString());
Git git2 = clone.call();
addRepoToClose(git2.getRepository());
return git2.getRepository();
}
@Theory
public void testCleanAfterClone(IgnoreSubmoduleMode mode) throws Exception {
Repository db2 = cloneWithoutCloningSubmodule();
IndexDiff indexDiff = new IndexDiff(db2, Constants.HEAD,
new FileTreeIterator(db2));
indexDiff.setIgnoreSubmoduleMode(mode);
boolean changed = indexDiff.diff();
assertFalse(changed);
}
@Theory
public void testMissingIfDirectoryGone(IgnoreSubmoduleMode mode)
throws Exception {
recursiveDelete(submodule_trash);
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
boolean hasChanges = indexDiff.diff();
if (mode != IgnoreSubmoduleMode.ALL) {
assertTrue(hasChanges);
assertEquals("[modules/submodule]",
indexDiff.getMissing().toString());
} else {
assertFalse(hasChanges);
}
}
@Theory
public void testSubmoduleReplacedByFile(IgnoreSubmoduleMode mode)
throws Exception {
recursiveDelete(submodule_trash);
writeTrashFile("modules/submodule", "nonsense");
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertTrue(indexDiff.diff());
assertEquals("[]", indexDiff.getMissing().toString());
assertEquals("[]", indexDiff.getUntracked().toString());
assertEquals("[modules/submodule]", indexDiff.getModified().toString());
}
@Theory
public void testDirtyRootWorktree(IgnoreSubmoduleMode mode)
throws IOException {
writeTrashFile("fileInRoot", "2");
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertTrue(indexDiff.diff());
}
private void assertDiff(IndexDiff indexDiff, IgnoreSubmoduleMode mode,
IgnoreSubmoduleMode... expectedEmptyModes) throws IOException {
boolean diffResult = indexDiff.diff();
Set<String> submodulePaths = indexDiff
.getPathsWithIndexMode(FileMode.GITLINK);
boolean emptyExpected = false;
for (IgnoreSubmoduleMode empty : expectedEmptyModes) {
if (mode.equals(empty)) {
emptyExpected = true;
break;
}
}
if (emptyExpected) {
assertFalse("diff should be false with mode=" + mode,
diffResult);
assertEquals("should have no paths with FileMode.GITLINK", 0,
submodulePaths.size());
} else {
assertTrue("diff should be true with mode=" + mode,
diffResult);
assertTrue("submodule path should have FileMode.GITLINK",
submodulePaths.contains("modules/submodule"));
}
}
@Theory
public void testDirtySubmoduleWorktree(IgnoreSubmoduleMode mode)
throws IOException {
JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
IgnoreSubmoduleMode.DIRTY);
}
@Theory
public void testDirtySubmoduleHEAD(IgnoreSubmoduleMode mode)
throws IOException, GitAPIException {
JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
Git submoduleGit = Git.wrap(submodule_db);
submoduleGit.add().addFilepattern("fileInSubmodule").call();
submoduleGit.commit().setMessage("Modified fileInSubmodule").call();
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL);
}
@Theory
public void testDirtySubmoduleIndex(IgnoreSubmoduleMode mode)
throws IOException, GitAPIException {
JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
Git submoduleGit = Git.wrap(submodule_db);
submoduleGit.add().addFilepattern("fileInSubmodule").call();
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
IgnoreSubmoduleMode.DIRTY);
}
@Theory
public void testDirtySubmoduleIndexAndWorktree(IgnoreSubmoduleMode mode)
throws IOException, GitAPIException, NoWorkTreeException {
JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "2");
Git submoduleGit = Git.wrap(submodule_db);
submoduleGit.add().addFilepattern("fileInSubmodule").call();
JGitTestUtil.writeTrashFile(submodule_db, "fileInSubmodule", "3");
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
IgnoreSubmoduleMode.DIRTY);
}
@Theory
public void testDirtySubmoduleWorktreeUntracked(IgnoreSubmoduleMode mode)
throws IOException {
JGitTestUtil.writeTrashFile(submodule_db, "additionalFileInSubmodule",
"2");
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertDiff(indexDiff, mode, IgnoreSubmoduleMode.ALL,
IgnoreSubmoduleMode.DIRTY, IgnoreSubmoduleMode.UNTRACKED);
}
@Theory
public void testSubmoduleReplacedByMovedFile(IgnoreSubmoduleMode mode)
throws Exception {
Git git = Git.wrap(db);
git.rm().setCached(true).addFilepattern("modules/submodule").call();
recursiveDelete(submodule_trash);
JGitTestUtil.deleteTrashFile(db, "fileInRoot");
// Move the fileInRoot file
writeTrashFile("modules/submodule/fileInRoot", "root");
git.rm().addFilepattern("fileInRoot").addFilepattern("modules/").call();
git.add().addFilepattern("modules/").call();
IndexDiff indexDiff = new IndexDiff(db, Constants.HEAD,
new FileTreeIterator(db));
indexDiff.setIgnoreSubmoduleMode(mode);
assertTrue(indexDiff.diff());
String[] removed = indexDiff.getRemoved().toArray(new String[0]);
Arrays.sort(removed);
if (IgnoreSubmoduleMode.ALL.equals(mode)) {
assertArrayEquals(new String[] { "fileInRoot" }, removed);
} else {
assertArrayEquals(
new String[] { "fileInRoot", "modules/submodule" },
removed);
}
assertEquals("[modules/submodule/fileInRoot]",
indexDiff.getAdded().toString());
}
}