/*
* #%L
* JavaHg
* %%
* Copyright (C) 2011 aragost Trifork ag
* %%
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
* #L%
*/
package com.aragost.javahg.commands;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import com.aragost.javahg.Changeset;
import com.aragost.javahg.Repository;
import com.aragost.javahg.internals.Utils;
import com.aragost.javahg.merge.ConflictResolvingContext;
import com.aragost.javahg.merge.KeepDeleteConflict;
import com.aragost.javahg.merge.MergeConflict;
import com.aragost.javahg.test.AbstractTestCase;
public class MergeCommandTest extends AbstractTestCase {
@Test
public void testManifestConflict() throws IOException {
Repository repo = getTestRepository();
CommitCommand commitCmd = CommitCommand.on(repo).message("m").user("user");
writeFile("a", "boo");
writeFile("b", "boo");
AddCommand.on(repo).execute();
Changeset baseCs = commitCmd.execute();
writeFile("a", "bar");
writeFile("b", "bar");
AddCommand.on(repo).execute();
commitCmd.execute();
update(baseCs);
RemoveCommand.on(repo).execute("a", "b");
commitCmd.execute();
MergeCommand mergeCmd = MergeCommand.on(repo);
ManifestMergeOracle oracle = new ManifestMergeOracle();
oracle.delete("a");
mergeCmd.execute(oracle);
Assert.assertEquals(1, oracle.getMissingAnswers().size());
Assert.assertTrue(oracle.getMissingAnswers().contains("b"));
Assert.assertTrue(new File(repo.getDirectory(), "b").exists());
Assert.assertFalse(new File(repo.getDirectory(), "a").exists());
}
@Test
public void testMergeConlict() throws IOException {
Repository repo = getTestRepository();
CommitCommand commitCmd = CommitCommand.on(repo).message("m").user("user");
writeFile("a", "boo");
writeFile("b", "boo");
AddCommand.on(repo).execute();
Changeset baseCs = commitCmd.execute();
writeFile("a", "bar");
writeFile("b", "bar");
commitCmd.execute();
update(baseCs);
writeFile("a", "foo");
writeFile("b", "foo");
commitCmd.execute();
MergeCommand mergeCmd = MergeCommand.on(repo);
ManifestMergeOracle oracle = new ManifestMergeOracle();
boolean flag = mergeCmd.execute(oracle);
Assert.assertFalse(flag);
Assert.assertTrue(oracle.getMissingAnswers().isEmpty());
commitCmd = CommitCommand.on(repo).user("user").message("m");
try {
commitCmd.execute();
assertFailedExecution(commitCmd);
} catch (ExecutionException e) {
// expected unresolved conflicts
}
}
@Test
public void testMergeCtxAncestor() throws IOException {
Repository repo = getTestRepository();
Changeset base = createChangeset();
Changeset parent2 = createChangeset();
update(base);
Changeset parent1 = createChangeset();
ConflictResolvingContext ms = repo.workingCopy().merge(parent2);
Assert.assertEquals(parent1, ms.getLocal());
Assert.assertEquals(parent2, ms.getRemote());
Assert.assertEquals(base, ms.getBase());
}
@Test
public void testMergeCtxKeepDeleteConflict() throws IOException {
Repository repo = getTestRepository();
writeFile("a", "");
Changeset base = commit();
writeFile("a", "a");
Changeset p2 = commit();
update(base);
repo.workingCopy().remove("a");
Changeset p1 = commit();
ConflictResolvingContext ms = repo.workingCopy().merge(p2);
Assert.assertEquals(1, ms.getKeepDeleteConflicts().size());
KeepDeleteConflict keepDeleteConflict = ms.getKeepDeleteConflicts().iterator().next();
Assert.assertEquals(KeepDeleteConflict.State.KEEP, keepDeleteConflict.getState());
Assert.assertEquals("a", keepDeleteConflict.getFilename());
Assert.assertEquals(p2, keepDeleteConflict.getKeepParent());
update(p2);
ms = repo.workingCopy().merge(p1);
Assert.assertEquals(1, ms.getKeepDeleteConflicts().size());
keepDeleteConflict = ms.getKeepDeleteConflicts().iterator().next();
Assert.assertEquals(KeepDeleteConflict.State.KEEP, keepDeleteConflict.getState());
Assert.assertEquals("a", keepDeleteConflict.getFilename());
Assert.assertEquals(p2, keepDeleteConflict.getKeepParent());
File a = getTestRepository().file("a");
Assert.assertTrue(a.exists());
keepDeleteConflict.delete();
Assert.assertFalse(a.exists());
StatusResult status1 = repo.workingCopy().status();
Assert.assertArrayEquals(new String[] { "a" }, status1.getRemoved().toArray());
StatusResult status2 = repo.workingCopy().parent2Status();
Assert.assertTrue(status2.getRemoved().isEmpty());
keepDeleteConflict.keep();
Assert.assertTrue(a.exists());
status1 = repo.workingCopy().status();
Assert.assertTrue(status1.getRemoved().isEmpty());
status2 = repo.workingCopy().parent2Status();
Assert.assertTrue(status2.getRemoved().isEmpty());
}
@Test
public void testMergeCtxFlagConflict() throws IOException, InterruptedException {
// Windows does not (in the Mercurial world) support symlinks
Assume.assumeTrue(!Utils.isWindows());
Repository repo = getTestRepository();
writeFile("x", "");
Changeset base = commit();
writeFile("a", "");
setExecutable(repo.file("a"));
Changeset parent2 = commit();
update(base);
createSymlink(repo.file("b"), repo.file("a"));
commit();
ConflictResolvingContext mergeCtx = repo.workingCopy().merge(parent2);
//Assert.assertEquals(1, mergeCtx.getFlagConflicts().size());
//Assert.assertEquals("a", mergeCtx.getFlagConflicts().iterator().next().getFilename());
Assert.assertEquals(1, mergeCtx.getMergeConflicts().size());
Assert.assertEquals("a", mergeCtx.getMergeConflicts().iterator().next().getFilename());
}
private void createSymlink(File oldName, File newName) throws IOException, InterruptedException {
String[] cmd = new String[] { "ln", "-s", oldName.getAbsolutePath(), newName.getAbsolutePath() };
exec(cmd);
}
private void setExecutable(File file) throws InterruptedException, IOException {
String[] cmd = new String[] { "chmod", "+x", file.getAbsolutePath() };
exec(cmd);
}
private void exec(String[] cmd) throws InterruptedException, IOException {
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
process.destroy();
}
@Test
public void testMergeConflict() throws IOException {
Repository repo = getTestRepository();
// Merge conflict in a can not be resolved with internal:merge
// in b the conflict can
writeFile("a");
writeFile("b", "a\na\na\na\na\n");
Changeset base = commit();
writeFile("a", "XX");
writeFile("b", "X\na\na\na\na\n");
Changeset parent2 = commit();
update(base);
writeFile("a", "YY");
writeFile("b", "a\na\na\nY\na\n");
commit();
ConflictResolvingContext mergeState = repo.workingCopy().merge(parent2);
List<MergeConflict> mergeConflicts = mergeState.getMergeConflicts();
Assert.assertEquals(2, mergeConflicts.size());
MergeConflict mca = mergeConflicts.get(0);
MergeConflict mcb = mergeConflicts.get(1);
Assert.assertEquals("a", mca.getFilename());
Assert.assertEquals("b", mcb.getFilename());
Assert.assertFalse(mca.isResolved());
Assert.assertFalse(mcb.isResolved());
mca.resolveWithInternalMerge();
mcb.resolveWithInternalMerge();
Assert.assertFalse(mca.isResolved());
Assert.assertTrue(mcb.isResolved());
}
}