aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java')
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java433
1 files changed, 433 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java
new file mode 100644
index 0000000000..94b67b374b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2020-2022, Simeon Andreev <simeon.danailov.andreev@gmail.com> and others.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.diffmergetool;
+
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGETOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.junit.Test;
+
+/**
+ * Testing external merge tools.
+ */
+public class ExternalMergeToolTest extends ExternalToolTestCase {
+
+ @Test(expected = ToolException.class)
+ public void testUserToolWithError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 1;
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName,
+ CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(Boolean.TRUE));
+
+ invokeMerge(toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUserToolWithCommandNotFoundError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 127; // command not found
+ String command = "exit " + errorReturnCode;
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ invokeMerge(toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test
+ public void testKdiff3() throws Exception {
+ assumePosixPlatform();
+
+ CommandLineMergeTool autoMergingTool = CommandLineMergeTool.kdiff3;
+ assumeMergeToolIsAvailable(autoMergingTool);
+
+ CommandLineMergeTool tool = autoMergingTool;
+ PreDefinedMergeTool externalTool = new PreDefinedMergeTool(tool.name(),
+ tool.getPath(), tool.getParameters(true),
+ tool.getParameters(false),
+ tool.isExitCodeTrustable() ? BooleanTriState.TRUE
+ : BooleanTriState.FALSE);
+
+ MergeTools manager = new MergeTools(db);
+ ExecutionResult result = manager.merge(local, remote, merged, null,
+ null, externalTool);
+ assertEquals("Expected merge tool to succeed", 0, result.getRc());
+
+ List<String> actualLines = Files.readAllLines(mergedFile.toPath());
+ String actualMergeResult = String.join(System.lineSeparator(),
+ actualLines);
+ String expectedMergeResult = DEFAULT_CONTENT;
+ assertEquals(
+ "Failed to merge equal local and remote versions with pre-defined tool: "
+ + tool.getPath(),
+ expectedMergeResult, actualMergeResult);
+ }
+
+ @Test
+ public void testUserDefinedTool() throws Exception {
+ String customToolName = "customTool";
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> tools = manager.getUserDefinedTools();
+ ExternalMergeTool externalTool = tools.get(customToolName);
+ manager.merge(local, remote, merged, base, null, externalTool);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testUserDefinedToolWithPrompt() throws Exception {
+ String customToolName = "customTool";
+ String command = getEchoCommand();
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, command);
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.merge(local, remote, merged, base, null,
+ Optional.of(customToolName), BooleanTriState.TRUE, false,
+ promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+
+ List<String> actualToolPrompts = promptHandler.toolPrompts;
+ List<String> expectedToolPrompts = Arrays.asList("customTool");
+ assertEquals("Expected a user prompt for custom tool call",
+ expectedToolPrompts, actualToolPrompts);
+
+ assertEquals("Expected to no informing about missing tools",
+ Collections.EMPTY_LIST, noToolHandler.missingTools);
+ }
+
+ @Test
+ public void testUserDefinedToolWithCancelledPrompt() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.merge(local, remote, merged,
+ base, null, Optional.empty(), BooleanTriState.TRUE, false,
+ promptHandler, noToolHandler);
+ assertFalse("Expected no result if user cancels the operation",
+ result.isPresent());
+ }
+
+ @Test
+ public void testAllTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolName = "customTool";
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolName,
+ CONFIG_KEY_CMD, "echo");
+
+ MergeTools manager = new MergeTools(db);
+ Set<String> actualToolNames = manager.getAllToolNames();
+ Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolName);
+ CommandLineMergeTool[] defaultTools = CommandLineMergeTool.values();
+ for (CommandLineMergeTool defaultTool : defaultTools) {
+ String toolName = defaultTool.name();
+ expectedToolNames.add(toolName);
+ }
+ assertEquals("Incorrect set of external merge tools", expectedToolNames,
+ actualToolNames);
+ }
+
+ @Test
+ public void testOverridePredefinedToolPath() {
+ String toolName = CommandLineMergeTool.guiffy.name();
+ String customToolPath = "/usr/bin/echo";
+
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ "echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_PATH,
+ customToolPath);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> tools = manager.getUserDefinedTools();
+ ExternalMergeTool mergeTool = tools.get(toolName);
+ assertNotNull("Expected tool \"" + toolName + "\" to be user defined",
+ mergeTool);
+
+ String toolPath = mergeTool.getPath();
+ assertEquals("Expected external merge tool to have an overriden path",
+ customToolPath, toolPath);
+ }
+
+ @Test
+ public void testUserDefinedTools() {
+ FileBasedConfig config = db.getConfig();
+ String customToolname = "customTool";
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_CMD, "echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_PATH, "/usr/bin/echo");
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_PROMPT, String.valueOf(false));
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_GUITOOL, String.valueOf(false));
+ config.setString(CONFIG_MERGETOOL_SECTION, customToolname,
+ CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(false));
+ MergeTools manager = new MergeTools(db);
+ Set<String> actualToolNames = manager.getUserDefinedTools().keySet();
+ Set<String> expectedToolNames = new LinkedHashSet<>();
+ expectedToolNames.add(customToolname);
+ assertEquals("Incorrect set of external merge tools", expectedToolNames,
+ actualToolNames);
+ }
+
+ @Test
+ public void testCompare() throws ToolException {
+ String toolName = "customTool";
+
+ FileBasedConfig config = db.getConfig();
+ // the default merge tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ String command = getEchoCommand();
+
+ config.setString(CONFIG_MERGETOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ Optional<ExecutionResult> result = invokeMerge(toolName);
+ assertTrue("Expected external merge tool result to be available",
+ result.isPresent());
+ int expectedCompareResult = 0;
+ assertEquals("Incorrect compare result for external merge tool",
+ expectedCompareResult, result.get().getRc());
+ }
+
+ @Test
+ public void testDefaultTool() throws Exception {
+ String toolName = "customTool";
+ String guiToolName = "customGuiTool";
+
+ FileBasedConfig config = db.getConfig();
+ // the default merge tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ MergeTools manager = new MergeTools(db);
+ boolean gui = false;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured mergetool to be the default external merge tool",
+ toolName, defaultToolName);
+
+ gui = true;
+ String defaultGuiToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected default mergetool to not be set",
+ defaultGuiToolName);
+
+ config.setString(CONFIG_MERGE_SECTION, subsection, CONFIG_KEY_GUITOOL,
+ guiToolName);
+ manager = new MergeTools(db);
+ defaultGuiToolName = manager.getDefaultToolName(gui);
+ assertEquals(
+ "Expected configured mergetool to be the default external merge guitool",
+ guiToolName, defaultGuiToolName);
+ }
+
+ @Test
+ public void testOverridePreDefinedToolPath() {
+ String newToolPath = "/tmp/path/";
+
+ CommandLineMergeTool[] defaultTools = CommandLineMergeTool.values();
+ assertTrue("Expected to find pre-defined external merge tools",
+ defaultTools.length > 0);
+
+ CommandLineMergeTool overridenTool = defaultTools[0];
+ String overridenToolName = overridenTool.name();
+ String overridenToolPath = newToolPath + overridenToolName;
+ FileBasedConfig config = db.getConfig();
+ config.setString(CONFIG_MERGETOOL_SECTION, overridenToolName,
+ CONFIG_KEY_PATH, overridenToolPath);
+
+ MergeTools manager = new MergeTools(db);
+ Map<String, ExternalMergeTool> availableTools = manager
+ .getPredefinedTools(true);
+ ExternalMergeTool externalMergeTool = availableTools
+ .get(overridenToolName);
+ String actualMergeToolPath = externalMergeTool.getPath();
+ assertEquals(
+ "Expected pre-defined external merge tool to have overriden path",
+ overridenToolPath, actualMergeToolPath);
+ boolean withBase = true;
+ String expectedMergeToolCommand = overridenToolPath + " "
+ + overridenTool.getParameters(withBase);
+ String actualMergeToolCommand = externalMergeTool.getCommand();
+ assertEquals(
+ "Expected pre-defined external merge tool to have overriden command",
+ expectedMergeToolCommand, actualMergeToolCommand);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testUndefinedTool() throws Exception {
+ String toolName = "undefined";
+ invokeMerge(toolName);
+ fail("Expected exception to be thrown due to not defined external merge tool");
+ }
+
+ @Test
+ public void testDefaultToolExecutionWithPrompt() throws Exception {
+ FileBasedConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString("merge", subsection, "tool", "customTool");
+
+ String command = getEchoCommand();
+
+ config.setString("mergetool", "customTool", "cmd", command);
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ manager.merge(local, remote, merged, base, null, Optional.empty(),
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+
+ assertEchoCommandHasCorrectOutput();
+ }
+
+ @Test
+ public void testNoDefaultToolName() {
+ MergeTools manager = new MergeTools(db);
+ boolean gui = false;
+ String defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+
+ gui = true;
+ defaultToolName = manager.getDefaultToolName(gui);
+ assertNull("Expected no default tool when none is configured",
+ defaultToolName);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullTool() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = null;
+ MissingToolHandler noToolHandler = null;
+
+ Optional<String> tool = null;
+
+ manager.merge(local, remote, merged, base, null, tool,
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+ }
+
+ @Test(expected = ToolException.class)
+ public void testNullToolWithPrompt() throws Exception {
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.cancelPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<String> tool = null;
+
+ manager.merge(local, remote, merged, base, null, tool,
+ BooleanTriState.TRUE, false, promptHandler, noToolHandler);
+ }
+
+ private Optional<ExecutionResult> invokeMerge(String toolName)
+ throws ToolException {
+ BooleanTriState prompt = BooleanTriState.UNSET;
+ boolean gui = false;
+
+ MergeTools manager = new MergeTools(db);
+
+ PromptHandler promptHandler = PromptHandler.acceptPrompt();
+ MissingToolHandler noToolHandler = new MissingToolHandler();
+
+ Optional<ExecutionResult> result = manager.merge(local, remote, merged,
+ base, null, Optional.of(toolName), prompt, gui, promptHandler,
+ noToolHandler);
+ return result;
+ }
+
+ private void assumeMergeToolIsAvailable(
+ CommandLineMergeTool autoMergingTool) {
+ boolean isAvailable = ExternalToolUtils.isToolAvailable(db.getFS(),
+ db.getDirectory(), db.getWorkTree(), autoMergingTool.getPath());
+ assumeTrue("Assuming external tool is available: "
+ + autoMergingTool.name(), isAvailable);
+ }
+
+ private String getEchoCommand() {
+ return "(echo $LOCAL $REMOTE $MERGED $BASE) > "
+ + commandResult.getAbsolutePath();
+ }
+
+ private void assertEchoCommandHasCorrectOutput() throws IOException {
+ List<String> actualLines = Files.readAllLines(commandResult.toPath());
+ String actualContent = String.join(System.lineSeparator(), actualLines);
+ actualLines = Arrays.asList(actualContent.split(" "));
+ List<String> expectedLines = Arrays.asList(localFile.getAbsolutePath(),
+ remoteFile.getAbsolutePath(), mergedFile.getAbsolutePath(),
+ baseFile.getAbsolutePath());
+ assertEquals("Dummy test tool called with unexpected arguments",
+ expectedLines, actualLines);
+ }
+}