You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2017/07/11 07:42:30 UTC

[05/22] lucenenet git commit: Added lucene-cli + tests - a wrapper console application so we can run the various utilities and demos in .NET on the command line.

Added lucene-cli + tests - a wrapper console application so we can run the various utilities and demos in .NET on the command line.


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/9e389540
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/9e389540
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/9e389540

Branch: refs/heads/master
Commit: 9e38954039ccf941cf0dc0c19b0d180341fb8c8e
Parents: f0b56fd
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Jul 6 19:42:54 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Jul 6 19:42:54 2017 +0700

----------------------------------------------------------------------
 Lucene.Net.Portable.sln                         |  26 +
 .../Commands/Analysis/AnalysisCommandTest.cs    |  48 +
 .../AnalysisStempelCompileStemsCommandTest.cs   |  58 ++
 .../AnalysisStempelPatchStemsCommandTest.cs     |  57 ++
 .../Commands/CommandTestCase.cs                 | 170 ++++
 .../Commands/Demo/DemoCommandTest.cs            |  48 +
 .../Commands/Index/IndexCheckCommandTest.cs     | 109 +++
 .../Commands/Index/IndexCommandTest.cs          |  56 ++
 .../Commands/Index/IndexCopySegmentsTest.cs     |  58 ++
 .../Index/IndexDeleteSegmentsCommandTest.cs     |  58 ++
 .../Index/IndexExtractCfsCommandTest.cs         |  56 ++
 .../Commands/Index/IndexFixCommandTest.cs       |  70 ++
 .../Commands/Index/IndexListCfsCommandTest.cs   |  69 ++
 .../Index/IndexListHighFreqTermsCommandTest.cs  |  67 ++
 .../Index/IndexListSegmentsCommandTest.cs       |  63 ++
 .../Index/IndexListTaxonomyStatsCommandTest.cs  |  65 ++
 .../Index/IndexListTermInfoCommandTest.cs       |  61 ++
 .../Commands/Index/IndexMergeCommandTest.cs     |  57 ++
 .../Commands/Index/IndexSplitCommandTest.cs     |  62 ++
 .../Commands/Index/IndexUpgradeCommandTest.cs   |  67 ++
 .../Commands/Lock/LockCommandTest.cs            |  56 ++
 .../Commands/Lock/LockStressTestCommandTest.cs  |  64 ++
 .../Lock/LockVerifyServerCommandTest.cs         |  59 ++
 .../Commands/RootCommandTest.cs                 |  48 +
 .../EnumerableExtensions.cs                     |  60 ++
 .../Lucene.Net.Tests.Cli.xproj                  |  22 +
 .../Properties/AssemblyInfo.cs                  |  36 +
 .../SourceCode/SourceCodeParserTest.cs          |  72 ++
 .../SourceCode/TestInputForParser.cs            |  53 +
 .../Lucene.Net.Tests.Cli/StringExtensions.cs    |  68 ++
 src/tools/Lucene.Net.Tests.Cli/project.json     |  35 +
 .../lucene-cli/CommandLine/CommandArgument.cs   |  30 +
 .../CommandLine/CommandLineApplication.cs       | 563 +++++++++++
 .../lucene-cli/CommandLine/CommandOption.cs     | 112 +++
 .../lucene-cli/CommandLine/CommandOptionType.cs |  12 +
 .../CommandLine/CommandParsingException.cs      |  18 +
 src/tools/lucene-cli/CommandLineOptions.cs      |  74 ++
 src/tools/lucene-cli/ConfigurationBase.cs       | 130 +++
 src/tools/lucene-cli/ICommand.cs                |  27 +
 src/tools/lucene-cli/Program.cs                 |  35 +
 src/tools/lucene-cli/Properties/AssemblyInfo.cs |  37 +
 .../lucene-cli/Properties/launchSettings.json   |   7 +
 .../lucene-cli/Resources/Strings.Designer.cs    | 962 +++++++++++++++++++
 src/tools/lucene-cli/Resources/Strings.resx     | 420 ++++++++
 src/tools/lucene-cli/SourceCode/ConsolePager.cs | 198 ++++
 .../lucene-cli/SourceCode/SourceCodeExporter.cs |  59 ++
 .../SourceCode/SourceCodeSectionParser.cs       | 100 ++
 .../SourceCode/SourceCodeSectionReader.cs       | 157 +++
 .../arguments/IndexDirectoryArgument.cs         |  57 ++
 .../lucene-cli/arguments/SegmentsArgument.cs    |  31 +
 src/tools/lucene-cli/commands/RootCommand.cs    |  46 +
 .../commands/analysis/AnalysisCommand.cs        |  45 +
 .../AnalysisStempelCompileStemsCommand.cs       |  77 ++
 .../AnalysisStempelPatchStemsCommand.cs         |  70 ++
 .../lucene-cli/commands/demo/DemoCommand.cs     |  49 +
 .../commands/demo/DemoConfiguration.cs          |  90 ++
 .../DemoAssociationsFacetsCommand.cs            |  53 +
 .../DemoDistanceFacetsCommand.cs                |  53 +
 .../DemoExpressionAggregationFacetsCommand.cs   |  53 +
 .../demo-index-files/DemoIndexFilesCommand.cs   |  85 ++
 .../DemoMultiCategoryListsFacetsCommand.cs      |  53 +
 .../demo-range-facets/DemoRangeFacetsCommand.cs |  53 +
 .../demo-search-files/DemoSearchFilesCommand.cs | 134 +++
 .../DemoSimpleFacetsCommand.cs                  |  53 +
 .../DemoSimpleSortedSetFacetsCommand.cs         |  53 +
 .../lucene-cli/commands/index/IndexCommand.cs   |  53 +
 .../index/index-check/IndexCheckCommand.cs      | 103 ++
 .../IndexCopySegmentsCommand.cs                 |  54 ++
 .../IndexDeleteSegmentsCommand.cs               |  66 ++
 .../index-extract-cfs/IndexExtractCfsCommand.cs |  47 +
 .../commands/index/index-fix/IndexFixCommand.cs |  50 +
 .../index/index-list-cfs/IndexListCfsCommand.cs |  72 ++
 .../IndexListHighFreqTerms.cs                   |  86 ++
 .../IndexSegmentListCommand.cs                  |  51 +
 .../IndexListTaxonomyStatsCommand.cs            |  62 ++
 .../IndexListTermInfoCommand.cs                 |  52 +
 .../index/index-merge/IndexMergeCommand.cs      |  51 +
 .../index/index-split/IndexSplitCommand.cs      |  78 ++
 .../index/index-upgrade/IndexUpgradeCommand.cs  |  83 ++
 .../lucene-cli/commands/lock/LockCommand.cs     |  42 +
 .../lock-stress-test/LockStressTestCommand.cs   |  58 ++
 .../LockVerifyServerCommand.cs                  |  51 +
 src/tools/lucene-cli/lucene-cli.xproj           |  19 +
 .../options/CrossCheckTermVectorsOption.cs      |  31 +
 .../lucene-cli/options/DirectoryTypeOption.cs   |  30 +
 src/tools/lucene-cli/options/SegmentOption.cs   |  31 +
 src/tools/lucene-cli/options/VerboseOption.cs   |  30 +
 src/tools/lucene-cli/project.json               |  39 +
 88 files changed, 7133 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/Lucene.Net.Portable.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.Portable.sln b/Lucene.Net.Portable.sln
index 9e3b91d..bac9168 100644
--- a/Lucene.Net.Portable.sln
+++ b/Lucene.Net.Portable.sln
@@ -97,6 +97,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Demo", "src\Luce
 EndProject
 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Tests.Demo", "src\Lucene.Net.Tests.Demo\Lucene.Net.Tests.Demo.xproj", "{93DF8BAA-9CAA-4142-8E96-55481188C012}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tools", "tools", "{C8F207AE-DB35-4B14-966C-C1FADCC28DAE}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "lucene-cli", "src\tools\lucene-cli\lucene-cli.xproj", "{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Tests.Cli", "src\tools\Lucene.Net.Tests.Cli\Lucene.Net.Tests.Cli.xproj", "{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -449,8 +455,28 @@ Global
 		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Release|Any CPU.Build.0 = Release|Any CPU
 		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Release|x86.ActiveCfg = Release|Any CPU
 		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Release|x86.Build.0 = Release|Any CPU
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}.Debug|x86.Build.0 = Debug|Any CPU
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}.Release|x86.ActiveCfg = Release|Any CPU
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B}.Release|x86.Build.0 = Release|Any CPU
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}.Debug|x86.Build.0 = Debug|Any CPU
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}.Release|x86.ActiveCfg = Release|Any CPU
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{D5F3414E-E743-4DCA-A50A-DA3278A2BA2B} = {C8F207AE-DB35-4B14-966C-C1FADCC28DAE}
+		{495B65F0-0B01-40FE-9DC8-5A82C49E07EF} = {C8F207AE-DB35-4B14-966C-C1FADCC28DAE}
+	EndGlobalSection
 EndGlobal

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisCommandTest.cs
new file mode 100644
index 0000000..d05131b
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisCommandTest.cs
@@ -0,0 +1,48 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class AnalysisCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new AnalysisCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisStempelCompileStemsCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisStempelCompileStemsCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisStempelCompileStemsCommandTest.cs
new file mode 100644
index 0000000..951644f
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisStempelCompileStemsCommandTest.cs
@@ -0,0 +1,58 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class AnalysisStempelCompileStemsCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new AnalysisStempelCompileStemsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-e UTF-8|--encoding UTF-8", output: new string[] { "--encoding", "UTF-8" }) },
+            };
+        }
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "substitution", output: new string[] { @"substitution" }) },
+                new Arg[] {
+                    new Arg(inputPattern: @"C:\lucene-temp\foo.txt", output: new string[] { @"C:\lucene-temp\foo.txt" }),
+                    new Arg(inputPattern: @"C:\lucene-temp\foo.txt C:\lucene-temp\foo2.txt", output: new string[] { @"C:\lucene-temp\foo.txt", @"C:\lucene-temp\foo2.txt" }),
+                },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("one", FromResource("NotEnoughArguments", 2));
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisStempelPatchStemsCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisStempelPatchStemsCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisStempelPatchStemsCommandTest.cs
new file mode 100644
index 0000000..0a21a1f
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Analysis/AnalysisStempelPatchStemsCommandTest.cs
@@ -0,0 +1,57 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands.Analysis
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class AnalysisStempelPatchStemsCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new AnalysisStempelPatchStemsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-e UTF-8|--encoding UTF-8", output: new string[] { "--encoding", "UTF-8" }) },
+            };
+        }
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] {
+                    new Arg(inputPattern: @"C:\lucene-temp\foo.txt", output: new string[] { @"C:\lucene-temp\foo.txt" }),
+                    new Arg(inputPattern: @"C:\lucene-temp\foo.txt C:\lucene-temp\foo2.txt", output: new string[] { @"C:\lucene-temp\foo.txt", @"C:\lucene-temp\foo2.txt" }),
+                },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("", FromResource("NotEnoughArguments", 1));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/CommandTestCase.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/CommandTestCase.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/CommandTestCase.cs
new file mode 100644
index 0000000..0b1917d
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/CommandTestCase.cs
@@ -0,0 +1,170 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    // LUCENENET TODO: Move to TestFramework ?
+    public abstract class CommandTestCase
+    {
+        [SetUp]
+        protected virtual void SetUp()
+        {
+        }
+
+        [TearDown]
+        protected virtual void TearDown()
+        {
+        }
+
+        protected abstract ConfigurationBase CreateConfiguration(MockConsoleApp app);
+
+        protected abstract IList<Arg[]> GetRequiredArgs();
+        protected abstract IList<Arg[]> GetOptionalArgs();
+
+        protected virtual void AssertCommandTranslation(string command, string[] expectedResult)
+        {
+            var output = new MockConsoleApp();
+            var cmd = CreateConfiguration(output);
+            cmd.Execute(command.ToArgs());
+
+            Assert.AreEqual(expectedResult.Length, output.Args.Length);
+            for (int i = 0; i < output.Args.Length; i++)
+            {
+                Assert.AreEqual(expectedResult[i], output.Args[i], "Command: {0}, Expected: {1}, Actual {2}", command, string.Join(",", expectedResult), string.Join(",", output.Args[i]));
+            }
+        }
+
+        protected virtual void AssertConsoleOutput(string command, string expectedConsoleText)
+        {
+            var output = new MockConsoleApp();
+            var cmd = CreateConfiguration(output);
+
+            var console = new StringWriter();
+            cmd.Out = console;
+            cmd.Execute(command.ToArgs());
+
+            string consoleText = console.ToString();
+            Assert.True(consoleText.Contains(expectedConsoleText), "Expected output was {0}, actual console output was {1}", expectedConsoleText, consoleText);
+        }
+
+        protected virtual string FromResource(string resourceName)
+        {
+            return Resources.Strings.ResourceManager.GetString(resourceName);
+        }
+
+        protected virtual string FromResource(string resourceName, params object[] args)
+        {
+            return string.Format(Resources.Strings.ResourceManager.GetString(resourceName), args);
+        }
+
+        [Test]
+        public virtual void TestAllValidCombinations()
+        {
+            var requiredArgs = GetRequiredArgs().ExpandArgs().RequiredParameters();
+            var optionalArgs = GetOptionalArgs().ExpandArgs().OptionalParameters();
+
+            foreach (var requiredArg in requiredArgs)
+            {
+                AssertCommandTranslation(
+                    string.Join(" ", requiredArg.Select(x => x.InputPattern).ToArray()),
+                    requiredArg.SelectMany(x => x.Output).ToArray());
+            }
+
+            foreach (var requiredArg in requiredArgs)
+            {
+                foreach (var optionalArg in optionalArgs)
+                {
+                    string command = string.Join(" ", requiredArg.Select(x => x.InputPattern).Union(optionalArg.Select(x => x.InputPattern).ToArray()));
+                    string[] expected = requiredArg.SelectMany(x => x.Output).Concat(optionalArg.SelectMany(x => x.Output)).ToArray();
+                    AssertCommandTranslation(command, expected);
+                }
+            }
+        }
+
+        [Test]
+        public virtual void TestHelp()
+        {
+            AssertConsoleOutput("?", "Version");
+        }
+
+        public class MockConsoleApp
+        {
+            public void Main(string[] args)
+            {
+                this.Args = args;
+            }
+
+            public string[] Args { get; private set; }
+        }
+
+        public class Arg
+        {
+            public Arg(string inputPattern, string[] output)
+            {
+                InputPattern = inputPattern;
+                Output = output;
+            }
+
+            public string InputPattern { get; private set; }
+            public string[] Output { get; private set; }
+        }
+    }
+
+    public static class ListExtensions
+    {
+        // Breaks out any options based on logical OR | symbol
+        public static IList<CommandTestCase.Arg[]> ExpandArgs(this IList<CommandTestCase.Arg[]> args)
+        {
+            var result = new List<CommandTestCase.Arg[]>();
+            foreach (var arg in args)
+            {
+                result.Add(ExpandArgs(arg));
+            }
+
+            return result;
+        }
+
+        public static CommandTestCase.Arg[] ExpandArgs(this CommandTestCase.Arg[] args)
+        {
+            var result = new List<CommandTestCase.Arg>();
+            if (args != null)
+            {
+                foreach (var arg in args)
+                {
+                    if (arg.InputPattern.Contains("|"))
+                    {
+                        var options = arg.InputPattern.Split('|');
+                        foreach (var option in options)
+                        {
+                            result.Add(new CommandTestCase.Arg(option, (string[])arg.Output.Clone()));
+                        }
+                    }
+                    else
+                    {
+                        result.Add(arg);
+                    }
+                }
+            }
+            return result.ToArray();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Demo/DemoCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Demo/DemoCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Demo/DemoCommandTest.cs
new file mode 100644
index 0000000..4c57bbb
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Demo/DemoCommandTest.cs
@@ -0,0 +1,48 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class DemoCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new DemoCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCheckCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCheckCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCheckCommandTest.cs
new file mode 100644
index 0000000..0ec00ef
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCheckCommandTest.cs
@@ -0,0 +1,109 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    // LUCENENET TODO: Test to ensure all of the commands and arguments have a description (in all commands except for root)
+
+    public class IndexCheckCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexCheckCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-c|--cross-check-term-vectors", output: new string[] { "-crossCheckTermVectors" }) },
+                new Arg[] { new Arg(inputPattern: "--verbose", output: new string[] { "-verbose" }) },
+                new Arg[] {
+                    new Arg(inputPattern: "-s _seg1|--segment _seg1", output: new string[] { "-segment", "_seg1" }),
+                    new Arg(inputPattern: "-s _seg1 -s _seg2|--segment _seg1 --segment _seg2", output: new string[] { "-segment", "_seg1", "-segment", "_seg2" }),
+                    new Arg(inputPattern: "-s _seg1 -s _seg2 -s _seg3|--segment _seg1 --segment _seg2 --segment _seg3", output: new string[] { "-segment", "_seg1", "-segment", "_seg2", "-segment", "_seg3" })
+                },
+                new Arg[] { new Arg(inputPattern: "-dir SimpleFSDirectory|--directory-type SimpleFSDirectory", output: new string[] { "-dir-impl", "SimpleFSDirectory" }) },
+            };
+        }
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+            };
+        }
+
+        
+
+
+
+        //[Test]
+        //public void TestAllOptionsShort()
+        //{
+        //    AssertCommandTranslation(
+        //        @"C:\lucene-temp -v -c -dir SimpleFSDirectory -s _seg1 -s _seg2 -s _seg3",
+        //        new string[] {
+        //            @"C:\lucene-temp", "-crossCheckTermVectors", "-verbose",
+        //            "-segment", "_seg1", "-segment", "_seg2", "-segment", "_seg3",
+        //            "-dir-impl", "SimpleFSDirectory"
+        //        });
+
+        //    //var output = new MockConsoleApp();
+        //    //var cmd = new IndexCheckCommand.Configuration(new CommandLineOptions()) { Main = (args) => output.Main(args) };
+
+        //    //string input = @"C:\lucene-temp -v -c -dir SimpleFSDirectory -s _seg1 -s _seg2 -s _seg3";
+        //    //cmd.Execute(input.ToArgs());
+
+        //    //Assert.AreEqual(@"C:\lucene-temp", output.Args[0]);
+        //    //Assert.True(output.Args.Contains("-crossCheckTermVectors"));
+        //    //Assert.True(output.Args.Contains("-verbose"));
+        //    //Assert.AreEqual("SimpleFSDirectory", output.Args.OptionValue("-dir-impl"));
+        //    //Assert.True(new HashSet<string>(output.Args.OptionValues("-segment")).SetEquals(new HashSet<string>(new string[] { "_seg1", "_seg2", "_seg3" })));
+        //    //Assert.False(output.Args.Contains("-fix"));
+        //}
+
+        //[Test]
+        //public void TestAllOptionsLong()
+        //{
+        //    AssertCommandTranslation(
+        //        @"C:\lucene-temp --verbose --cross-check-term-vectors --directory-type SimpleFSDirectory --segment _seg1 --segment _seg2 --segment _seg3",
+        //        new string[] {
+        //            @"C:\lucene-temp", "-crossCheckTermVectors", "-verbose",
+        //            "-segment", "_seg1", "-segment", "_seg2", "-segment", "_seg3",
+        //            "-dir-impl", "SimpleFSDirectory"
+        //        });
+        //}
+
+        /// <summary>
+        /// Ensures the current working directory is used when index directory is not supplied. 
+        /// </summary>
+        [Test]
+        public void TestNoArguments()
+        {
+            System.IO.Directory.SetCurrentDirectory(@"C:\");
+            AssertCommandTranslation("", new string[] { @"C:\" });
+        }
+
+        
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCommandTest.cs
new file mode 100644
index 0000000..e110667
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCommandTest.cs
@@ -0,0 +1,56 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexCommand.Configuration(new CommandLineOptions());
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            return new List<Arg[]>();
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            return new List<Arg[]>();
+        }
+
+        /// <summary>
+        /// Ensures the current working directory is used when index directory is not supplied. 
+        /// </summary>
+        [Test]
+        public void TestNoArguments()
+        {
+            AssertConsoleOutput("", "Lucene.Net Command Line Utility, Version");
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCopySegmentsTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCopySegmentsTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCopySegmentsTest.cs
new file mode 100644
index 0000000..68b86c0
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexCopySegmentsTest.cs
@@ -0,0 +1,58 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexCopySegmentsTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexCopySegmentsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            return new List<Arg[]>();
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp2", output: new string[] { @"C:\lucene-temp2" }) },
+                new Arg[] {
+                    new Arg(inputPattern: "_seg1", output: new string[] { "_seg1" }),
+                    new Arg(inputPattern: "_seg1 _seg2", output: new string[] { "_seg1", "_seg2" }),
+                    new Arg(inputPattern: "_seg1 _seg2 _seg3", output: new string[] { "_seg1", "_seg2", "_seg3" }),
+                    new Arg(inputPattern: "_seg1 _seg2 _seg3 _seg4", output: new string[] { "_seg1", "_seg2", "_seg3", "_seg4" }),
+                },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("one two", FromResource("NotEnoughArguments", 3));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexDeleteSegmentsCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexDeleteSegmentsCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexDeleteSegmentsCommandTest.cs
new file mode 100644
index 0000000..42a2632
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexDeleteSegmentsCommandTest.cs
@@ -0,0 +1,58 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexDeleteSegmentsCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexDeleteSegmentsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            return new List<Arg[]>();
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+                new Arg[] {
+                    new Arg(inputPattern: "_seg1", output: new string[] { "_seg1" }),
+                    new Arg(inputPattern: "_seg1 _seg2", output: new string[] { "_seg1", "_seg2" }),
+                    new Arg(inputPattern: "_seg1 _seg2 _seg3", output: new string[] { "_seg1", "_seg2", "_seg3" }),
+                    new Arg(inputPattern: "_seg1 _seg2 _seg3 _seg4", output: new string[] { "_seg1", "_seg2", "_seg3", "_seg4" }),
+                },
+                new Arg[] { new Arg(inputPattern: "", output: new string[] { "-d"}) }
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("one", FromResource("NotEnoughArguments", 2));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexExtractCfsCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexExtractCfsCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexExtractCfsCommandTest.cs
new file mode 100644
index 0000000..a8ecd92
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexExtractCfsCommandTest.cs
@@ -0,0 +1,56 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexExtractCfsCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexExtractCfsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-dir SimpleFSDirectory|--directory-type SimpleFSDirectory", output: new string[] { "-dir-impl", "SimpleFSDirectory" }) },
+            };
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+                new Arg[] { new Arg(inputPattern: "", output: new string[] { "-extract" }) },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("", FromResource("NotEnoughArguments", 1));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexFixCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexFixCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexFixCommandTest.cs
new file mode 100644
index 0000000..105606d
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexFixCommandTest.cs
@@ -0,0 +1,70 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexFixCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexFixCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-c|--cross-check-term-vectors", output: new string[] { "-crossCheckTermVectors" }) },
+                new Arg[] { new Arg(inputPattern: "--verbose", output: new string[] { "-verbose" }) },
+                new Arg[] {
+                    new Arg(inputPattern: "-s _seg1|--segment _seg1", output: new string[] { "-segment", "_seg1" }),
+                    new Arg(inputPattern: "-s _seg1 -s _seg2|--segment _seg1 --segment _seg2", output: new string[] { "-segment", "_seg1", "-segment", "_seg2" }),
+                    new Arg(inputPattern: "-s _seg1 -s _seg2 -s _seg3|--segment _seg1 --segment _seg2 --segment _seg3", output: new string[] { "-segment", "_seg1", "-segment", "_seg2", "-segment", "_seg3" })
+                },
+                new Arg[] { new Arg(inputPattern: "-dir SimpleFSDirectory|--directory-type SimpleFSDirectory", output: new string[] { "-dir-impl", "SimpleFSDirectory" }) },
+            };
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+                new Arg[] { new Arg(inputPattern: "", output: new string[] { "-fix" }) },
+            };
+        }
+
+        [Test]
+        public void TestNoArguments()
+        {
+            System.IO.Directory.SetCurrentDirectory(@"C:\");
+            AssertCommandTranslation("", new string[] { @"C:\", "-fix" });
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListCfsCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListCfsCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListCfsCommandTest.cs
new file mode 100644
index 0000000..46b014c
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListCfsCommandTest.cs
@@ -0,0 +1,69 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexListCfsCommandTest : CommandTestCase
+    {
+        
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexListCfsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-dir SimpleFSDirectory|--directory-type SimpleFSDirectory", output: new string[] { "-dir-impl", "SimpleFSDirectory" }) },
+            };
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("", FromResource("NotEnoughArguments", 1));
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two", ""));
+        }
+
+        [Test]
+        public override void TestHelp()
+        {
+            base.TestHelp();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListHighFreqTermsCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListHighFreqTermsCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListHighFreqTermsCommandTest.cs
new file mode 100644
index 0000000..fc937ad
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListHighFreqTermsCommandTest.cs
@@ -0,0 +1,67 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexListHighFreqTermsCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexListHighFreqTermsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-t|--total-term-frequency", output: new string[] { "-t" }) },
+                new Arg[] { new Arg(inputPattern: "-n 20|--number-of-terms 20", output: new string[] { "20" }) },
+                new Arg[] { new Arg(inputPattern: "-f fieldName|--field fieldName", output: new string[] { "fieldName" }) },
+            };
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+            };
+        }
+
+        /// <summary>
+        /// Ensures the current working directory is used when index directory is not supplied. 
+        /// </summary>
+        [Test]
+        public void TestNoArguments()
+        {
+            System.IO.Directory.SetCurrentDirectory(@"C:\");
+            AssertCommandTranslation("", new string[] { @"C:\" });
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListSegmentsCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListSegmentsCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListSegmentsCommandTest.cs
new file mode 100644
index 0000000..c4297c7
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListSegmentsCommandTest.cs
@@ -0,0 +1,63 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexListSegmentsCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexListSegmentsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+                new Arg[] { new Arg(inputPattern: "", output: new string[] { "-l" }) },
+            };
+        }
+
+        /// <summary>
+        /// Ensures the current working directory is used when index directory is not supplied. 
+        /// </summary>
+        [Test]
+        public void TestNoArguments()
+        {
+            System.IO.Directory.SetCurrentDirectory(@"C:\");
+            AssertCommandTranslation("", new string[] { @"C:\", "-l" });
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListTaxonomyStatsCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListTaxonomyStatsCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListTaxonomyStatsCommandTest.cs
new file mode 100644
index 0000000..8539200
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListTaxonomyStatsCommandTest.cs
@@ -0,0 +1,65 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexListTaxonomyStatsCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexListTaxonomyStatsCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-tree|--show-tree", output: new string[] { "-printTree" }) },
+            };
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+            };
+        }
+
+        /// <summary>
+        /// Ensures the current working directory is used when index directory is not supplied. 
+        /// </summary>
+        [Test]
+        public void TestNoArguments()
+        {
+            System.IO.Directory.SetCurrentDirectory(@"C:\");
+            AssertCommandTranslation("", new string[] { @"C:\" });
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListTermInfoCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListTermInfoCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListTermInfoCommandTest.cs
new file mode 100644
index 0000000..09a536a
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexListTermInfoCommandTest.cs
@@ -0,0 +1,61 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexListTermInfoCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexListTermInfoCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+                new Arg[] { new Arg(inputPattern: "fieldName", output: new string[] { "fieldName" }) },
+                new Arg[] { new Arg(inputPattern: "termName", output: new string[] { "termName" }) },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("", FromResource("NotEnoughArguments", 3));
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two three four", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexMergeCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexMergeCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexMergeCommandTest.cs
new file mode 100644
index 0000000..f425eab
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexMergeCommandTest.cs
@@ -0,0 +1,57 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexMergeCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexMergeCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+                new Arg[] {
+                    new Arg(inputPattern: @"C:\lucene-temp2 C:\lucene-temp3", output: new string[] { @"C:\lucene-temp2", @"C:\lucene-temp3" }),
+                    new Arg(inputPattern: @"C:\lucene-temp2 C:\lucene-temp3 C:\lucene-temp4", output: new string[] { @"C:\lucene-temp2", @"C:\lucene-temp3", @"C:\lucene-temp4" }),
+                    new Arg(inputPattern: @"C:\lucene-temp2 C:\lucene-temp3 C:\lucene-temp4 C:\lucene-temp5", output: new string[] { @"C:\lucene-temp2", @"C:\lucene-temp3", @"C:\lucene-temp4", @"C:\lucene-temp5" }),
+                },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("", FromResource("NotEnoughArguments", 3));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexSplitCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexSplitCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexSplitCommandTest.cs
new file mode 100644
index 0000000..bf0ef31
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexSplitCommandTest.cs
@@ -0,0 +1,62 @@
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexSplitCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexSplitCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-n 20|--number-of-parts 20", output: new string[] { "-num", "20" }) },
+                new Arg[] { new Arg(inputPattern: "-s|--sequential", output: new string[] { "-seq" }) },
+            };
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { /*"-out", @"C:\lucene-temp"*/ }) },
+                new Arg[] {
+                    new Arg(inputPattern: @"C:\lucene-temp2 C:\lucene-temp3", output: new string[] { @"C:\lucene-temp2", @"C:\lucene-temp3" }),
+                    new Arg(inputPattern: @"C:\lucene-temp2 C:\lucene-temp3 C:\lucene-temp4", output: new string[] { @"C:\lucene-temp2", @"C:\lucene-temp3", @"C:\lucene-temp4" }),
+                    new Arg(inputPattern: @"C:\lucene-temp2 C:\lucene-temp3 C:\lucene-temp4 C:\lucene-temp5", output: new string[] { @"C:\lucene-temp2", @"C:\lucene-temp3", @"C:\lucene-temp4", @"C:\lucene-temp5" }),
+                },
+                new Arg[] { new Arg(inputPattern: "", output: new string[] { "-out", @"C:\lucene-temp" }) },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("", FromResource("NotEnoughArguments", 2));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexUpgradeCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexUpgradeCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexUpgradeCommandTest.cs
new file mode 100644
index 0000000..9b52235
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Index/IndexUpgradeCommandTest.cs
@@ -0,0 +1,67 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class IndexUpgradeCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new IndexUpgradeCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "-d|--delete-prior-commits", output: new string[] { "-delete-prior-commits" }) },
+                new Arg[] { new Arg(inputPattern: "-v|--verbose", output: new string[] { "-verbose" }) },
+                new Arg[] { new Arg(inputPattern: "-dir SimpleFSDirectory|--directory-type SimpleFSDirectory", output: new string[] { "-dir-impl", "SimpleFSDirectory" }) },
+            };
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: @"C:\lucene-temp", output: new string[] { @"C:\lucene-temp" }) },
+            };
+        }
+
+        /// <summary>
+        /// Ensures the current working directory is used when index directory is not supplied. 
+        /// </summary>
+        [Test]
+        public void TestNoArguments()
+        {
+            System.IO.Directory.SetCurrentDirectory(@"C:\");
+            AssertCommandTranslation("", new string[] { @"C:\" });
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockCommandTest.cs
new file mode 100644
index 0000000..d5c1f64
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockCommandTest.cs
@@ -0,0 +1,56 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class LockCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new LockCommand.Configuration(new CommandLineOptions());
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            return new List<Arg[]>();
+        }
+
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            return new List<Arg[]>();
+        }
+
+        /// <summary>
+        /// Ensures the current working directory is used when index directory is not supplied. 
+        /// </summary>
+        [Test]
+        public void TestNoArguments()
+        {
+            AssertConsoleOutput("", "Lucene.Net Command Line Utility, Version");
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockStressTestCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockStressTestCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockStressTestCommandTest.cs
new file mode 100644
index 0000000..462ebb2
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockStressTestCommandTest.cs
@@ -0,0 +1,64 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class LockStressTestCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new LockStressTestCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "12345", output: new string[] { "12345" }) },
+                new Arg[] { new Arg(inputPattern: "192.168.0.1", output: new string[] { "192.168.0.1" }) },
+                new Arg[] { new Arg(inputPattern: "9876", output: new string[] { "9876" }) },
+                new Arg[] { new Arg(inputPattern: "NativeFSLockFactory", output: new string[] { "NativeFSLockFactory" }) },
+                new Arg[] { new Arg(inputPattern: @"F:\temp2", output: new string[] { @"F:\temp2" }) },
+                new Arg[] { new Arg(inputPattern: "100", output: new string[] { "100" }) },
+                new Arg[] { new Arg(inputPattern: "10", output: new string[] { "10" }) },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("one two three four five six", FromResource("NotEnoughArguments", 7));
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two three four five six seven eight", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockVerifyServerCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockVerifyServerCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockVerifyServerCommandTest.cs
new file mode 100644
index 0000000..a76a99c
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/Lock/LockVerifyServerCommandTest.cs
@@ -0,0 +1,59 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class LockVerifyServerCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new LockVerifyServerCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>()
+            {
+                new Arg[] { new Arg(inputPattern: "192.168.0.1", output: new string[] { "192.168.0.1" }) },
+                new Arg[] { new Arg(inputPattern: "10", output: new string[] { "10" }) },
+            };
+        }
+
+        [Test]
+        public void TestNotEnoughArguments()
+        {
+            Assert.NotNull(FromResource("NotEnoughArguments"));
+            AssertConsoleOutput("one", FromResource("NotEnoughArguments", 2));
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one two three", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Commands/RootCommandTest.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Commands/RootCommandTest.cs b/src/tools/Lucene.Net.Tests.Cli/Commands/RootCommandTest.cs
new file mode 100644
index 0000000..543cf24
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Commands/RootCommandTest.cs
@@ -0,0 +1,48 @@
+using Lucene.Net.Cli.CommandLine;
+using NUnit.Framework;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Cli.Commands
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public class RootCommandTest : CommandTestCase
+    {
+        protected override ConfigurationBase CreateConfiguration(MockConsoleApp app)
+        {
+            return new RootCommand.Configuration(new CommandLineOptions()) { Main = (args) => app.Main(args) };
+        }
+
+        protected override IList<Arg[]> GetOptionalArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+        protected override IList<Arg[]> GetRequiredArgs()
+        {
+            // NOTE: We must order this in the sequence of the expected output.
+            return new List<Arg[]>();
+        }
+
+        [Test]
+        public void TestTooManyArguments()
+        {
+            Assert.Throws<CommandParsingException>(() => AssertConsoleOutput("one", ""));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/EnumerableExtensions.cs
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/EnumerableExtensions.cs b/src/tools/Lucene.Net.Tests.Cli/EnumerableExtensions.cs
new file mode 100644
index 0000000..95ad494
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/EnumerableExtensions.cs
@@ -0,0 +1,60 @@
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Lucene.Net.Cli
+{
+    /*
+     * Licensed to the Apache Software Foundation (ASF) under one or more
+     * contributor license agreements.  See the NOTICE file distributed with
+     * this work for additional information regarding copyright ownership.
+     * The ASF licenses this file to You under the Apache License, Version 2.0
+     * (the "License"); you may not use this file except in compliance with
+     * the License.  You may obtain a copy of the License at
+     *
+     *     http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing, software
+     * distributed under the License is distributed on an "AS IS" BASIS,
+     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     * See the License for the specific language governing permissions and
+     * limitations under the License.
+     */
+
+    public static class Extensions
+    {
+        public static IEnumerable<IEnumerable<T>> OptionalParameters<T>(this IEnumerable<IEnumerable<T>> input)
+        {
+            if (input.Count() == 0)
+                yield break;
+            else
+            {
+                var rest = OptionalParameters(input.Skip(1));
+                foreach (var p in input.First())
+                {
+                    yield return new[] { p };
+                    foreach (var r in rest)
+                        yield return r.Prepend(p);
+                }
+                foreach (var r in rest)
+                    yield return r;
+            }
+        }
+
+        public static IEnumerable<IEnumerable<T>> RequiredParameters<T>(this IEnumerable<IEnumerable<T>> input)
+        {
+            int count = input.Count();
+            if (count == 1)
+                foreach (var p in input.First())
+                    yield return new[] { p };
+            else if (count > 1)
+            {
+                var rest = RequiredParameters(input.Skip(1));
+                foreach (var p in input.First())
+                {
+                    foreach (var r in rest)
+                        yield return r.Prepend(p);
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/9e389540/src/tools/Lucene.Net.Tests.Cli/Lucene.Net.Tests.Cli.xproj
----------------------------------------------------------------------
diff --git a/src/tools/Lucene.Net.Tests.Cli/Lucene.Net.Tests.Cli.xproj b/src/tools/Lucene.Net.Tests.Cli/Lucene.Net.Tests.Cli.xproj
new file mode 100644
index 0000000..9554cd2
--- /dev/null
+++ b/src/tools/Lucene.Net.Tests.Cli/Lucene.Net.Tests.Cli.xproj
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>495b65f0-0b01-40fe-9dc8-5a82c49e07ef</ProjectGuid>
+    <RootNamespace>Lucene.Net.Cli</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <ItemGroup>
+    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
+  </ItemGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file