Merge "Add additional FastForwardMode enums for different config contexts"
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
index 925976d..f074273 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConfigTest.java
@@ -63,6 +63,7 @@
 import java.util.LinkedList;
 import java.util.Set;
 
+import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.junit.MockSystemReader;
 import org.eclipse.jgit.util.FS;
@@ -321,6 +322,74 @@ public void testSetEnum() {
 	}
 
 	@Test
+	public void testGetFastForwardMergeoptions() throws ConfigInvalidException {
+		Config c = new Config(null); // not set
+		assertSame(FastForwardMode.FF, c.getEnum(
+				ConfigConstants.CONFIG_BRANCH_SECTION, "side",
+				ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.FF));
+		c = parse("[branch \"side\"]\n\tmergeoptions = --ff-only\n");
+		assertSame(FastForwardMode.FF_ONLY, c.getEnum(
+				ConfigConstants.CONFIG_BRANCH_SECTION, "side",
+				ConfigConstants.CONFIG_KEY_MERGEOPTIONS,
+				FastForwardMode.FF_ONLY));
+		c = parse("[branch \"side\"]\n\tmergeoptions = --ff\n");
+		assertSame(FastForwardMode.FF, c.getEnum(
+				ConfigConstants.CONFIG_BRANCH_SECTION, "side",
+				ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.FF));
+		c = parse("[branch \"side\"]\n\tmergeoptions = --no-ff\n");
+		assertSame(FastForwardMode.NO_FF, c.getEnum(
+				ConfigConstants.CONFIG_BRANCH_SECTION, "side",
+				ConfigConstants.CONFIG_KEY_MERGEOPTIONS, FastForwardMode.NO_FF));
+	}
+
+	@Test
+	public void testSetFastForwardMergeoptions() {
+		final Config c = new Config();
+		c.setEnum("branch", "side", "mergeoptions", FastForwardMode.FF);
+		assertEquals("[branch \"side\"]\n\tmergeoptions = --ff\n", c.toText());
+		c.setEnum("branch", "side", "mergeoptions", FastForwardMode.FF_ONLY);
+		assertEquals("[branch \"side\"]\n\tmergeoptions = --ff-only\n",
+				c.toText());
+		c.setEnum("branch", "side", "mergeoptions", FastForwardMode.NO_FF);
+		assertEquals("[branch \"side\"]\n\tmergeoptions = --no-ff\n",
+				c.toText());
+	}
+
+	@Test
+	public void testGetFastForwardMerge() throws ConfigInvalidException {
+		Config c = new Config(null); // not set
+		assertSame(FastForwardMode.Merge.TRUE, c.getEnum(
+				ConfigConstants.CONFIG_KEY_MERGE, null,
+				ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.TRUE));
+		c = parse("[merge]\n\tff = only\n");
+		assertSame(FastForwardMode.Merge.ONLY, c.getEnum(
+				ConfigConstants.CONFIG_KEY_MERGE, null,
+				ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.ONLY));
+		c = parse("[merge]\n\tff = true\n");
+		assertSame(FastForwardMode.Merge.TRUE, c.getEnum(
+				ConfigConstants.CONFIG_KEY_MERGE, null,
+				ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.TRUE));
+		c = parse("[merge]\n\tff = false\n");
+		assertSame(FastForwardMode.Merge.FALSE, c.getEnum(
+				ConfigConstants.CONFIG_KEY_MERGE, null,
+				ConfigConstants.CONFIG_KEY_FF, FastForwardMode.Merge.FALSE));
+	}
+
+	@Test
+	public void testSetFastForwardMerge() {
+		final Config c = new Config();
+		c.setEnum("merge", null, "ff",
+				FastForwardMode.Merge.valueOf(FastForwardMode.FF));
+		assertEquals("[merge]\n\tff = true\n", c.toText());
+		c.setEnum("merge", null, "ff",
+				FastForwardMode.Merge.valueOf(FastForwardMode.FF_ONLY));
+		assertEquals("[merge]\n\tff = only\n", c.toText());
+		c.setEnum("merge", null, "ff",
+				FastForwardMode.Merge.valueOf(FastForwardMode.NO_FF));
+		assertEquals("[merge]\n\tff = false\n", c.toText());
+	}
+
+	@Test
 	public void testReadLong() throws ConfigInvalidException {
 		assertReadLong(1L);
 		assertReadLong(-1L);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index 04d91af..2d3a6e1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -63,6 +63,7 @@
 import org.eclipse.jgit.dircache.DirCacheCheckout;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Config.ConfigEnum;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectIdRef;
@@ -81,6 +82,7 @@
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.revwalk.RevWalkUtils;
 import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.util.StringUtils;
 
 /**
  * A class used to execute a {@code Merge} command. It has setters for all
@@ -102,10 +104,11 @@ public class MergeCommand extends GitCommand<MergeResult> {
 	private FastForwardMode fastForwardMode = FastForwardMode.FF;
 
 	/**
-	 * The modes available for fast forward merges (corresponding to the --ff,
-	 * --no-ff and --ff-only options).
+	 * The modes available for fast forward merges corresponding to the
+	 * <code>--ff</code>, <code>--no-ff</code> and <code>--ff-only</code>
+	 * options under <code>branch.<name>.mergeoptions</code>.
 	 */
-	public enum FastForwardMode {
+	public enum FastForwardMode implements ConfigEnum {
 		/**
 		 * Corresponds to the default --ff option (for a fast forward update the
 		 * branch pointer only).
@@ -121,6 +124,75 @@ public enum FastForwardMode {
 		 * forward).
 		 */
 		FF_ONLY;
+
+		public String toConfigValue() {
+			return "--" + name().toLowerCase().replace('_', '-'); //$NON-NLS-1$
+		}
+
+		public boolean matchConfigValue(String in) {
+			if (StringUtils.isEmptyOrNull(in))
+				return false;
+			if (!in.startsWith("--")) //$NON-NLS-1$
+				return false;
+			return name().equalsIgnoreCase(in.substring(2).replace('-', '_'));
+		}
+
+		/**
+		 * The modes available for fast forward merges corresponding to the
+		 * options under <code>merge.ff</code>.
+		 */
+		public enum Merge {
+			/**
+			 * {@link FastForwardMode#FF}.
+			 */
+			TRUE,
+			/**
+			 * {@link FastForwardMode#NO_FF}.
+			 */
+			FALSE,
+			/**
+			 * {@link FastForwardMode#FF_ONLY}.
+			 */
+			ONLY;
+
+			/**
+			 * Map from <code>FastForwardMode</code> to
+			 * <code>FastForwardMode.Merge</code>.
+			 *
+			 * @param ffMode
+			 *            the <code>FastForwardMode</code> value to be mapped
+			 * @return the mapped code>FastForwardMode.Merge</code> value
+			 */
+			public static Merge valueOf(FastForwardMode ffMode) {
+				switch (ffMode) {
+				case NO_FF:
+					return FALSE;
+				case FF_ONLY:
+					return ONLY;
+				default:
+					return TRUE;
+				}
+			}
+		}
+
+		/**
+		 * Map from <code>FastForwardMode.Merge</code> to
+		 * <code>FastForwardMode</code>.
+		 *
+		 * @param ffMode
+		 *            the <code>FastForwardMode.Merge</code> value to be mapped
+		 * @return the mapped code>FastForwardMode</code> value
+		 */
+		public static FastForwardMode valueOf(FastForwardMode.Merge ffMode) {
+			switch (ffMode) {
+			case FALSE:
+				return NO_FF;
+			case ONLY:
+				return FF_ONLY;
+			default:
+				return FF;
+			}
+		}
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
index f882d49..af04b10 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java
@@ -387,6 +387,13 @@ public <T extends Enum<?>> T getEnum(final T[] all, final String section,
 		if (value == null)
 			return defaultValue;
 
+		if (all[0] instanceof ConfigEnum) {
+			for (T t : all) {
+				if (((ConfigEnum) t).matchConfigValue(value))
+					return t;
+			}
+		}
+
 		String n = value.replace(' ', '_');
 
 		// Because of c98abc9c0586c73ef7df4172644b7dd21c979e9d being used in
@@ -728,7 +735,11 @@ public void setBoolean(final String section, final String subsection,
 	 */
 	public <T extends Enum<?>> void setEnum(final String section,
 			final String subsection, final String name, final T value) {
-		String n = value.name().toLowerCase().replace('_', ' ');
+		String n;
+		if (value instanceof ConfigEnum)
+			n = ((ConfigEnum) value).toConfigValue();
+		else
+			n = value.name().toLowerCase().replace('_', ' ');
 		setString(section, subsection, name, n);
 	}
 
@@ -1275,4 +1286,27 @@ void reset() {
 			pos--;
 		}
 	}
+
+	/**
+	 * Converts enumeration values into configuration options and vice-versa,
+	 * allowing to match a config option with an enum value.
+	 *
+	 */
+	public static interface ConfigEnum {
+		/**
+		 * Converts enumeration value into a string to be save in config.
+		 *
+		 * @return the enum value as config string
+		 */
+		String toConfigValue();
+
+		/**
+		 * Checks if the given string matches with enum value.
+		 *
+		 * @param in
+		 *            the string to match
+		 * @return true if the given string matches enum value, false otherwise
+		 */
+		boolean matchConfigValue(String in);
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
index dbaa043..8fd84c8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java
@@ -191,4 +191,7 @@ public class ConfigConstants {
 
 	/** The "mergeoptions" key */
 	public static final String CONFIG_KEY_MERGEOPTIONS = "mergeoptions";
+
+	/** The "ff" key */
+	public static final String CONFIG_KEY_FF = "ff";
 }