aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java')
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java346
1 files changed, 346 insertions, 0 deletions
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java
new file mode 100644
index 0000000000..f0908cebc4
--- /dev/null
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2021-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.pgm;
+
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT;
+import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+import org.eclipse.jgit.internal.diffmergetool.DiffTools;
+import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool;
+import org.eclipse.jgit.lib.StoredConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Testing the {@code difftool} command.
+ */
+public class DiffToolTest extends ToolTestCase {
+
+ private static final String DIFF_TOOL = CONFIG_DIFFTOOL_SECTION;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ configureEchoTool(TOOL_NAME);
+ }
+
+ @Test(expected = Die.class)
+ public void testUndefinedTool() throws Exception {
+ String toolName = "undefined";
+ String[] conflictingFilenames = createUnstagedChanges();
+
+ List<String> expectedErrors = new ArrayList<>();
+ for (String changedFilename : conflictingFilenames) {
+ expectedErrors.add("External diff tool is not defined: " + toolName);
+ expectedErrors.add("compare of " + changedFilename + " failed");
+ }
+
+ runAndCaptureUsingInitRaw(expectedErrors, DIFF_TOOL, "--no-prompt",
+ "--tool", toolName);
+ fail("Expected exception to be thrown due to undefined external tool");
+ }
+
+ @Test(expected = Die.class)
+ public void testUserToolWithCommandNotFoundError() throws Exception {
+ String toolName = "customTool";
+
+ int errorReturnCode = 127; // command not found
+ String command = "exit " + errorReturnCode;
+
+ StoredConfig config = db.getConfig();
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+
+ createMergeConflict();
+ runAndCaptureUsingInitRaw(DIFF_TOOL, "--no-prompt", "--tool", toolName);
+
+ fail("Expected exception to be thrown due to external tool exiting with error code: "
+ + errorReturnCode);
+ }
+
+ @Test(expected = Die.class)
+ public void testEmptyToolName() throws Exception {
+ assumeLinuxPlatform();
+
+ String emptyToolName = "";
+
+ StoredConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
+ emptyToolName);
+
+ createUnstagedChanges();
+
+ String araxisErrorLine = "compare: unrecognized option `-wait' @ error/compare.c/CompareImageCommand/1123.";
+ String[] expectedErrorOutput = { araxisErrorLine, araxisErrorLine, };
+ runAndCaptureUsingInitRaw(Arrays.asList(expectedErrorOutput), DIFF_TOOL,
+ "--no-prompt");
+ fail("Expected exception to be thrown due to external tool exiting with an error");
+ }
+
+ @Test
+ public void testToolWithPrompt() throws Exception {
+ String[] inputLines = {
+ "y", // accept launching diff tool
+ "y", // accept launching diff tool
+ };
+
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedCompareOutput(conflictingFilenames);
+
+ String option = "--tool";
+
+ InputStream inputStream = createInputStream(inputLines);
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(inputStream,
+ DIFF_TOOL, "--prompt", option, TOOL_NAME));
+ }
+
+ @Test
+ public void testToolAbortLaunch() throws Exception {
+ String[] inputLines = {
+ "y", // accept launching diff tool
+ "n", // don't launch diff tool
+ };
+
+ String[] conflictingFilenames = createUnstagedChanges();
+ int abortIndex = 1;
+ String[] expectedOutput = getExpectedAbortOutput(conflictingFilenames, abortIndex);
+
+ String option = "--tool";
+
+ InputStream inputStream = createInputStream(inputLines);
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput,
+ runAndCaptureUsingInitRaw(inputStream, DIFF_TOOL, "--prompt", option,
+ TOOL_NAME));
+ }
+
+ @Test(expected = Die.class)
+ public void testNotDefinedTool() throws Exception {
+ createUnstagedChanges();
+
+ runAndCaptureUsingInitRaw(DIFF_TOOL, "--tool", "undefined");
+ fail("Expected exception when trying to run undefined tool");
+ }
+
+ @Test
+ public void testTool() throws Exception {
+ String[] conflictFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictFilenames);
+
+ String[] options = {
+ "--tool",
+ "-t",
+ };
+
+ for (String option : options) {
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput,
+ runAndCaptureUsingInitRaw(DIFF_TOOL, option,
+ TOOL_NAME));
+ }
+ }
+
+ @Test
+ public void testToolTrustExitCode() throws Exception {
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictingFilenames);
+
+ String[] options = { "--tool", "-t", };
+
+ for (String option : options) {
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL,
+ "--trust-exit-code", option, TOOL_NAME));
+ }
+ }
+
+ @Test
+ public void testToolNoGuiNoPromptNoTrustExitcode() throws Exception {
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictingFilenames);
+
+ String[] options = { "--tool", "-t", };
+
+ for (String option : options) {
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL,
+ "--no-gui", "--no-prompt", "--no-trust-exit-code",
+ option, TOOL_NAME));
+ }
+ }
+
+ @Test
+ public void testToolCached() throws Exception {
+ String[] conflictingFilenames = createStagedChanges();
+ Pattern[] expectedOutput = getExpectedCachedToolOutputNoPrompt(conflictingFilenames);
+
+ String[] options = { "--cached", "--staged", };
+
+ for (String option : options) {
+ assertArrayOfMatchingLines("Incorrect output for option: " + option,
+ expectedOutput, runAndCaptureUsingInitRaw(DIFF_TOOL,
+ option, "--tool", TOOL_NAME));
+ }
+ }
+
+ @Test
+ public void testToolHelp() throws Exception {
+ List<String> expectedOutput = new ArrayList<>();
+
+ DiffTools diffTools = new DiffTools(db);
+ Map<String, ExternalDiffTool> predefinedTools = diffTools
+ .getPredefinedTools(true);
+ List<ExternalDiffTool> availableTools = new ArrayList<>();
+ List<ExternalDiffTool> notAvailableTools = new ArrayList<>();
+ for (ExternalDiffTool tool : predefinedTools.values()) {
+ if (tool.isAvailable()) {
+ availableTools.add(tool);
+ } else {
+ notAvailableTools.add(tool);
+ }
+ }
+
+ expectedOutput.add(
+ "'git difftool --tool=<tool>' may be set to one of the following:");
+ for (ExternalDiffTool tool : availableTools) {
+ String toolName = tool.getName();
+ expectedOutput.add(toolName);
+ }
+ String customToolHelpLine = TOOL_NAME + "." + CONFIG_KEY_CMD + " "
+ + getEchoCommand();
+ expectedOutput.add("user-defined:");
+ expectedOutput.add(customToolHelpLine);
+ expectedOutput.add(
+ "The following tools are valid, but not currently available:");
+ for (ExternalDiffTool tool : notAvailableTools) {
+ String toolName = tool.getName();
+ expectedOutput.add(toolName);
+ }
+ String[] userDefinedToolsHelp = {
+ "Some of the tools listed above only work in a windowed",
+ "environment. If run in a terminal-only session, they will fail.",
+ };
+ expectedOutput.addAll(Arrays.asList(userDefinedToolsHelp));
+
+ String option = "--tool-help";
+ assertArrayOfLinesEquals("Incorrect output for option: " + option,
+ expectedOutput.toArray(new String[0]),
+ runAndCaptureUsingInitRaw(DIFF_TOOL, option));
+ }
+
+ private void configureEchoTool(String toolName) {
+ StoredConfig config = db.getConfig();
+ // the default diff tool is configured without a subsection
+ String subsection = null;
+ config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
+ toolName);
+
+ String command = getEchoCommand();
+
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
+ command);
+ /*
+ * prevent prompts as we are running in tests and there is no user to
+ * interact with on the command line
+ */
+ config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_PROMPT,
+ String.valueOf(false));
+ }
+
+ private String[] getExpectedToolOutputNoPrompt(String[] conflictingFilenames) {
+ String[] expectedToolOutput = new String[conflictingFilenames.length];
+ for (int i = 0; i < conflictingFilenames.length; ++i) {
+ String newPath = conflictingFilenames[i];
+ Path fullPath = getFullPath(newPath);
+ expectedToolOutput[i] = fullPath.toString();
+ }
+ return expectedToolOutput;
+ }
+
+ private Pattern[] getExpectedCachedToolOutputNoPrompt(String[] conflictingFilenames) {
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ if (tmpDir.endsWith(File.separator)) {
+ tmpDir = tmpDir.substring(0, tmpDir.length() - 1);
+ }
+ Pattern emptyPattern = Pattern.compile("");
+ List<Pattern> expectedToolOutput = new ArrayList<>();
+ for (int i = 0; i < conflictingFilenames.length; ++i) {
+ String changedFilename = conflictingFilenames[i];
+ Path fullPath = getFullPath(changedFilename);
+ String filename = fullPath.getFileName().toString();
+ String regexp = tmpDir + File.separatorChar + filename
+ + "_REMOTE_.*";
+ Pattern pattern = Pattern.compile(regexp);
+ expectedToolOutput.add(pattern);
+ expectedToolOutput.add(emptyPattern);
+ }
+ expectedToolOutput.add(emptyPattern);
+ return expectedToolOutput.toArray(new Pattern[0]);
+ }
+
+ private String[] getExpectedCompareOutput(String[] conflictingFilenames) {
+ List<String> expected = new ArrayList<>();
+ int n = conflictingFilenames.length;
+ for (int i = 0; i < n; ++i) {
+ String changedFilename = conflictingFilenames[i];
+ expected.add(
+ "Viewing (" + (i + 1) + "/" + n + "): '" + changedFilename
+ + "'");
+ expected.add("Launch '" + TOOL_NAME + "' [Y/n]?");
+ Path fullPath = getFullPath(changedFilename);
+ expected.add(fullPath.toString());
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private String[] getExpectedAbortOutput(String[] conflictingFilenames,
+ int abortIndex) {
+ List<String> expected = new ArrayList<>();
+ int n = conflictingFilenames.length;
+ for (int i = 0; i < n; ++i) {
+ String changedFilename = conflictingFilenames[i];
+ expected.add(
+ "Viewing (" + (i + 1) + "/" + n + "): '" + changedFilename
+ + "'");
+ expected.add("Launch '" + TOOL_NAME + "' [Y/n]?");
+ if (i == abortIndex) {
+ break;
+ }
+ Path fullPath = getFullPath(changedFilename);
+ expected.add(fullPath.toString());
+ }
+ return expected.toArray(new String[0]);
+ }
+
+ private static String getEchoCommand() {
+ /*
+ * use 'REMOTE' placeholder, as it will be replaced by a file path
+ * within the repository.
+ */
+ return "(echo \"$REMOTE\")";
+ }
+}