From 79f6bdce2b788c84e9962f9ae4f41b57919a4412 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Mon, 21 May 2007 10:27:41 +0000
Subject: [PATCH] Add support for trailing arguments in sub-command argument parser (includes unit tests).

---
 opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommand.java                                           |  175 +++++++++++-
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/TestSubCommand.java               |  297 +++++++++++++++++++++
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/TestSubCommandArgumentParser.java |  165 +++++++++++
 opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java                             |  102 ++++++-
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/ArgsTestCase.java                 |   42 +++
 5 files changed, 746 insertions(+), 35 deletions(-)

diff --git a/opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommand.java b/opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommand.java
index 4d3a274..55a63f1 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommand.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommand.java
@@ -28,6 +28,7 @@
 
 
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 
@@ -67,30 +68,95 @@
   // The argument parser with which this subcommand is associated.
   private SubCommandArgumentParser parser;
 
+  // Indicates whether this parser will allow additional unnamed
+  // arguments at the end of the list.
+  private boolean allowsTrailingArguments;
+
+  // The maximum number of unnamed trailing arguments that may be
+  // provided.
+  private int maxTrailingArguments;
+
+  // The minimum number of unnamed trailing arguments that may be
+  // provided.
+  private int minTrailingArguments;
+
+  // The display name that will be used for the trailing arguments in
+  // the usage information.
+  private String trailingArgsDisplayName;
+
+  /**
+   * Creates a new subcommand with the provided information. The
+   * subcommand will be automatically registered with the associated
+   * parser.
+   *
+   * @param parser
+   *          The argument parser with which this subcommand is
+   *          associated.
+   * @param name
+   *          The name of this subcommand.
+   * @param descriptionID
+   *          The unique ID for the description of this subcommand.
+   * @param descriptionArgs
+   *          The arguments to use to generate the description string
+   *          for this subcommand.
+   * @throws ArgumentException
+   *           If the associated argument parser already has a
+   *           subcommand with the same name.
+   */
+  public SubCommand(SubCommandArgumentParser parser, String name,
+      int descriptionID, Object... descriptionArgs) throws ArgumentException
+  {
+    this(parser, name, false, 0, 0, null, descriptionID, descriptionArgs);
+  }
+
 
 
   /**
-   * Creates a new subcommand with the provided information.  The subcommand
-   * will be automatically registered with the associated parser.
+   * Creates a new subcommand with the provided information. The
+   * subcommand will be automatically registered with the associated
+   * parser.
    *
-   * @param  parser           The argument parser with which this subcommand is
-   *                          associated.
-   * @param  name             The name of this subcommand.
-   * @param  descriptionID    The unique ID for the description of this
-   *                          subcommand.
-   * @param  descriptionArgs  The arguments to use to generate the description
-   *                          string for this subcommand.
-   *
-   * @throws  ArgumentException  If the associated argument parser already has a
-   *                             subcommand with the same name.
+   * @param parser
+   *          The argument parser with which this subcommand is
+   *          associated.
+   * @param name
+   *          The name of this subcommand.
+   * @param allowsTrailingArguments
+   *          Indicates whether this parser allows unnamed trailing
+   *          arguments to be provided.
+   * @param minTrailingArguments
+   *          The minimum number of unnamed trailing arguments that
+   *          must be provided. A value less than or equal to zero
+   *          indicates that no minimum will be enforced.
+   * @param maxTrailingArguments
+   *          The maximum number of unnamed trailing arguments that
+   *          may be provided. A value less than or equal to zero
+   *          indicates that no maximum will be enforced.
+   * @param trailingArgsDisplayName
+   *          The display name that should be used as a placeholder
+   *          for unnamed trailing arguments in the generated usage
+   *          information.
+   * @param descriptionID
+   *          The unique ID for the description of this subcommand.
+   * @param descriptionArgs
+   *          The arguments to use to generate the description string
+   *          for this subcommand.
+   * @throws ArgumentException
+   *           If the associated argument parser already has a
+   *           subcommand with the same name.
    */
   public SubCommand(SubCommandArgumentParser parser, String name,
-                    int descriptionID, Object... descriptionArgs)
-         throws ArgumentException
+      boolean allowsTrailingArguments, int minTrailingArguments,
+      int maxTrailingArguments, String trailingArgsDisplayName,
+      int descriptionID, Object... descriptionArgs) throws ArgumentException
   {
-    this.parser        = parser;
-    this.name          = name;
+    this.parser = parser;
+    this.name = name;
     this.descriptionID = descriptionID;
+    this.allowsTrailingArguments = allowsTrailingArguments;
+    this.minTrailingArguments = minTrailingArguments;
+    this.maxTrailingArguments = maxTrailingArguments;
+    this.trailingArgsDisplayName = trailingArgsDisplayName;
 
     String nameToCheck = name;
     if (parser.longArgumentsCaseSensitive())
@@ -117,7 +183,7 @@
   /**
    * Retrieves the name of this subcommand.
    *
-   * @return  The name of this subcommand.
+   * @return The name of this subcommand.
    */
   public String getName()
   {
@@ -309,5 +375,80 @@
       longIDMap.put(longID, argument);
     }
   }
+
+
+
+  /**
+   * Indicates whether this sub-command will allow unnamed trailing
+   * arguments. These will be arguments at the end of the list that
+   * are not preceded by either a long or short identifier and will
+   * need to be manually parsed by the application using this parser.
+   * Note that once an unnamed trailing argument has been identified,
+   * all remaining arguments will be classified as such.
+   *
+   * @return <CODE>true</CODE> if this sub-command allows unnamed
+   *         trailing arguments, or <CODE>false</CODE> if it does
+   *         not.
+   */
+  public boolean allowsTrailingArguments()
+  {
+    return allowsTrailingArguments;
+  }
+
+
+
+  /**
+   * Retrieves the minimum number of unnamed trailing arguments that
+   * must be provided.
+   *
+   * @return The minimum number of unnamed trailing arguments that
+   *         must be provided, or a value less than or equal to zero
+   *         if no minimum will be enforced.
+   */
+  public int getMinTrailingArguments()
+  {
+    return minTrailingArguments;
+  }
+
+
+
+  /**
+   * Retrieves the maximum number of unnamed trailing arguments that
+   * may be provided.
+   *
+   * @return The maximum number of unnamed trailing arguments that may
+   *         be provided, or a value less than or equal to zero if no
+   *         maximum will be enforced.
+   */
+  public int getMaxTrailingArguments()
+  {
+    return maxTrailingArguments;
+  }
+
+
+
+  /**
+   * Retrieves the trailing arguments display name.
+   *
+   * @return Returns the trailing arguments display name.
+   */
+  public String getTrailingArgumentsDisplayName()
+  {
+    return trailingArgsDisplayName;
+  }
+
+
+
+  /**
+   * Retrieves the set of unnamed trailing arguments that were provided on the
+   * command line.
+   *
+   * @return  The set of unnamed trailing arguments that were provided on the
+   *          command line.
+   */
+  public ArrayList<String> getTrailingArguments()
+  {
+    return parser.getTrailingArguments();
+  }
 }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java b/opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
index f006681..72bcea9 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
@@ -31,9 +31,12 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Properties;
+import java.util.SortedMap;
+import java.util.TreeMap;
 
 import org.opends.server.core.DirectoryServer;
 
@@ -61,6 +64,9 @@
   // The argument that will be used to trigger the display of usage information.
   private Argument usageArgument;
 
+  // The set of unnamed trailing arguments that were provided for this parser.
+  private ArrayList<String> trailingArguments;
+
   // Indicates whether subcommand and long argument names should be treated in a
   // case-sensitive manner.
   private boolean longArgumentsCaseSensitive;
@@ -82,7 +88,7 @@
 
   // The set of subcommands defined for this parser, referenced by subcommand
   // name.
-  private HashMap<String,SubCommand> subCommands;
+  private SortedMap<String,SubCommand> subCommands;
 
   // The total set of global arguments defined for this parser.
   private LinkedList<Argument> globalArgumentList;
@@ -128,11 +134,12 @@
     this.toolDescription            = toolDescription;
     this.longArgumentsCaseSensitive = longArgumentsCaseSensitive;
 
+    trailingArguments  = new ArrayList<String>();
     globalArgumentList = new LinkedList<Argument>();
     globalArgumentMap  = new HashMap<String,Argument>();
     globalShortIDMap   = new HashMap<Character,Argument>();
     globalLongIDMap    = new HashMap<String,Argument>();
-    subCommands        = new HashMap<String,SubCommand>();
+    subCommands        = new TreeMap<String,SubCommand>();
     usageDisplayed     = false;
     rawArguments       = null;
     subCommand         = null;
@@ -331,7 +338,7 @@
    * @return  The set of subcommands defined for this argument parser,
    *          referenced by subcommand name.
    */
-  public HashMap<String,SubCommand> getSubCommands()
+  public SortedMap<String,SubCommand> getSubCommands()
   {
     return subCommands;
   }
@@ -649,19 +656,35 @@
          throws ArgumentException
   {
     this.rawArguments = rawArguments;
+    this.subCommand = null;
+    this.trailingArguments = new ArrayList<String>();
+    this.usageDisplayed = false;
+
+    boolean inTrailingArgs = false;
 
     int numArguments = rawArguments.length;
     for (int i=0; i < numArguments; i++)
     {
       String arg = rawArguments[i];
 
+      if (inTrailingArgs)
+      {
+        trailingArguments.add(arg);
+        if ((subCommand.getMaxTrailingArguments() > 0) &&
+            (trailingArguments.size() > subCommand.getMaxTrailingArguments()))
+        {
+          int    msgID   = MSGID_ARGPARSER_TOO_MANY_TRAILING_ARGS;
+          String message = getMessage(msgID, subCommand
+              .getMaxTrailingArguments());
+          throw new ArgumentException(msgID, message);
+        }
+
+        continue;
+      }
+
       if (arg.equals("--"))
       {
-        // This is not legal because we don't allow unnamed trailing arguments
-        // in this parser.
-        int    msgID   = MSGID_SUBCMDPARSER_LONG_ARG_WITHOUT_NAME;
-        String message = getMessage(msgID, arg);
-        throw new ArgumentException(msgID, message);
+        inTrailingArgs = true;
       }
       else if (arg.startsWith("--"))
       {
@@ -1056,11 +1079,26 @@
           }
         }
       }
+      else if (subCommand != null)
+      {
+        // It's not a short or long identifier and the sub-command has
+        // already been specified, so it must be the first trailing argument.
+        if (subCommand.allowsTrailingArguments())
+        {
+          trailingArguments.add(arg);
+          inTrailingArgs = true;
+        }
+        else
+        {
+          // Trailing arguments are not allowed for this sub-command.
+          int    msgID   = MSGID_ARGPARSER_DISALLOWED_TRAILING_ARGUMENT;
+          String message = getMessage(msgID, arg);
+          throw new ArgumentException(msgID, message);
+        }
+      }
       else
       {
-        // It's not a short or long identifier, so check to see if it is a
-        // subcommand name.  If not, then it's invalid.  If so, then make sure
-        // that it was the only subcommand provided.
+        // It must be the sub-command.
         String nameToCheck = arg;
         if (! longArgumentsCaseSensitive)
         {
@@ -1074,19 +1112,29 @@
           String message = getMessage(msgID, arg);
           throw new ArgumentException(msgID, message);
         }
-        else if (subCommand == null)
-        {
-          subCommand = sc;
-        }
         else
         {
-          int    msgID   = MSGID_SUBCMDPARSER_MULTIPLE_SUBCOMMANDS;
-          String message = getMessage(msgID, arg, subCommand.getName());
-          throw new ArgumentException(msgID, message);
+          subCommand = sc;
         }
       }
     }
 
+    // If we have a sub-command and it allows trailing arguments and
+    // there is a minimum number, then make sure at least that many
+    // were provided.
+    if (subCommand != null)
+    {
+      int minTrailingArguments = subCommand.getMinTrailingArguments();
+      if (subCommand.allowsTrailingArguments() && (minTrailingArguments > 0))
+      {
+        if (trailingArguments.size() < minTrailingArguments)
+        {
+          int msgID = MSGID_ARGPARSER_TOO_FEW_TRAILING_ARGUMENTS;
+          String message = getMessage(msgID, minTrailingArguments);
+          throw new ArgumentException(msgID, message);
+        }
+      }
+    }
 
     // Iterate through all the global arguments and make sure that they have
     // values or a suitable default is available.
@@ -1321,6 +1369,10 @@
     buffer.append(" ");
     buffer.append(subCommand.getName());
     buffer.append(" {options}");
+    if (subCommand.allowsTrailingArguments()) {
+      buffer.append(' ');
+      buffer.append(subCommand.getTrailingArgumentsDisplayName());
+    }
     buffer.append(EOL);
     buffer.append(subCommand.getDescription());
     buffer.append(EOL);
@@ -1479,6 +1531,20 @@
 
 
   /**
+   * Retrieves the set of unnamed trailing arguments that were provided on the
+   * command line.
+   *
+   * @return  The set of unnamed trailing arguments that were provided on the
+   *          command line.
+   */
+  public ArrayList<String> getTrailingArguments()
+  {
+    return trailingArguments;
+  }
+
+
+
+  /**
    * Indicates whether the usage information has been displayed to the end user
    * either by an explicit argument like "-H" or "--help", or by a built-in
    * argument like "-?".
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/ArgsTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/ArgsTestCase.java
new file mode 100644
index 0000000..55e1daf
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/ArgsTestCase.java
@@ -0,0 +1,42 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.util.args;
+
+
+
+import org.opends.server.DirectoryServerTestCase;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * An abstract class that all args unit tests should extend.
+ */
+@Test(groups = { "precommit", "util" })
+public abstract class ArgsTestCase extends DirectoryServerTestCase {
+  // No implementation required.
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/TestSubCommand.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/TestSubCommand.java
new file mode 100644
index 0000000..95dc903
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/TestSubCommand.java
@@ -0,0 +1,297 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.util.args;
+
+
+
+import java.util.Arrays;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Unit tests for the SubCommand class.
+ */
+public final class TestSubCommand extends ArgsTestCase {
+
+  /**
+   * Tests that allowsTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testAllowsTrailingArgumentsFalse1() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command1", 1000);
+    Assert.assertFalse(sc.allowsTrailingArguments());
+  }
+
+
+
+  /**
+   * Tests that allowsTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testAllowsTrailingArgumentsFalse2() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", false, 0, 0, null,
+        2000);
+    Assert.assertFalse(sc.allowsTrailingArguments());
+  }
+
+
+
+  /**
+   * Tests that allowsTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testAllowsTrailingArgumentsTrue() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", true, 2, 4,
+        "args1 arg2 [arg3 arg4]", 2000);
+    Assert.assertTrue(sc.allowsTrailingArguments());
+  }
+
+
+
+  /**
+   * Tests that getMaxTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetMaxTrailingArguments1() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command1", 1000);
+    Assert.assertEquals(sc.getMaxTrailingArguments(), 0);
+  }
+
+
+
+  /**
+   * Tests that getMaxTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetMaxTrailingArguments2() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", false, 0, 0, null,
+        2000);
+    Assert.assertEquals(sc.getMaxTrailingArguments(), 0);
+  }
+
+
+
+  /**
+   * Tests that getMaxTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetMaxTrailingArguments3() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", true, 2, 4,
+        "args1 arg2 [arg3 arg4]", 2000);
+    Assert.assertEquals(sc.getMaxTrailingArguments(), 4);
+  }
+
+
+
+  /**
+   * Tests that getMinTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetMinTrailingArguments1() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command1", 1000);
+    Assert.assertEquals(sc.getMinTrailingArguments(), 0);
+  }
+
+
+
+  /**
+   * Tests that getMinTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetMinTrailingArguments2() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", false, 0, 0, null,
+        2000);
+    Assert.assertEquals(sc.getMinTrailingArguments(), 0);
+  }
+
+
+
+  /**
+   * Tests that getMinTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetMinTrailingArguments3() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", true, 2, 4,
+        "args1 arg2 [arg3 arg4]", 2000);
+    Assert.assertEquals(sc.getMinTrailingArguments(), 2);
+  }
+
+
+
+  /**
+   * Tests that getTrailingArgumentsDisplayName works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetTrailingArgumentsDisplayName1() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command1", 1000);
+    Assert.assertNull(sc.getTrailingArgumentsDisplayName());
+  }
+
+
+
+  /**
+   * Tests that getTrailingArgumentsDisplayName works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetTrailingArgumentsDisplayName2() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", false, 0, 0, null,
+        2000);
+    Assert.assertNull(sc.getTrailingArgumentsDisplayName());
+  }
+
+
+
+  /**
+   * Tests that getTrailingArgumentsDisplayName works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetTrailingArgumentsDisplayName3() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", true, 2, 4,
+        "args1 arg2 [arg3 arg4]", 2000);
+    Assert.assertEquals(sc.getTrailingArgumentsDisplayName(),
+        "args1 arg2 [arg3 arg4]");
+  }
+
+
+
+  /**
+   * Tests that getTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetTrailingArguments1() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command1", 1000);
+    parser.parseArguments(new String[] { "sub-command1" });
+    Assert.assertTrue(sc.getTrailingArguments().isEmpty());
+  }
+
+
+
+  /**
+   * Tests that getTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetTrailingArguments2() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", false, 0, 0, null,
+        2000);
+    parser.parseArguments(new String[] { "sub-command2" });
+    Assert.assertTrue(sc.getTrailingArguments().isEmpty());
+  }
+
+
+
+  /**
+   * Tests that getTrailingArguments works correctly.
+   *
+   * @throws Exception
+   *           If an unexpected problem occurred.
+   */
+  @Test
+  public void testGetTrailingArguments3() throws Exception {
+    SubCommandArgumentParser parser = new SubCommandArgumentParser(this
+        .getClass().getName(), "test description", true);
+    SubCommand sc = new SubCommand(parser, "sub-command2", true, 2, 4,
+        "args1 arg2 [arg3 arg4]", 2000);
+    parser
+        .parseArguments(new String[] { "sub-command2", "arg1", "arg2", "arg3" });
+    Assert.assertEquals(sc.getTrailingArguments(), Arrays.asList(new String[] {
+        "arg1", "arg2", "arg3" }));
+  }
+
+}
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/TestSubCommandArgumentParser.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/TestSubCommandArgumentParser.java
new file mode 100644
index 0000000..d08b896
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/util/args/TestSubCommandArgumentParser.java
@@ -0,0 +1,165 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.util.args;
+
+
+
+import java.util.Arrays;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+
+
+/**
+ * Unit tests for the SubCommand class.
+ */
+public final class TestSubCommandArgumentParser extends ArgsTestCase {
+
+  // The sub-command parser.
+  private SubCommandArgumentParser parser;
+
+  // First sub-command.
+  private SubCommand sc1;
+
+  // Second sub-command.
+  private SubCommand sc2;
+
+
+
+  /**
+   * Create the sub-commands and parser.
+   *
+   * @throws Exception
+   *           If something unexpected happened.
+   */
+  @BeforeClass
+  public void setup() throws Exception {
+    parser = new SubCommandArgumentParser(this.getClass().getName(),
+        "test description", true);
+
+    sc1 = new SubCommand(parser, "sub-command1", 1000);
+    sc2 = new SubCommand(parser, "sub-command2", true, 2, 4,
+        "args1 arg2 [arg3 arg4]", 2000);
+  }
+
+
+
+  /**
+   * Test the getSubCommand method.
+   *
+   * @throws Exception
+   *           If something unexpected happened.
+   */
+  @Test
+  public void testGetSubCommand() throws Exception {
+    Assert.assertSame(parser.getSubCommand("sub-command1"), sc1);
+    Assert.assertSame(parser.getSubCommand("sub-command2"), sc2);
+    Assert.assertNull(parser.getSubCommand("sub-command3"));
+  }
+
+
+
+  /**
+   * Provide valid command line args.
+   *
+   * @return Array of valid command line args.
+   */
+  @DataProvider(name = "validCommandLineArgs")
+  public Object[][] createValidCommandLineArgs() {
+    return new Object[][] {
+        { new String[] {}, null },
+        { new String[] { "sub-command1" }, sc1 },
+        { new String[] { "sub-command2", "one", "two" }, sc2 },
+        { new String[] { "sub-command2", "one", "two", "three" }, sc2 },
+        { new String[] { "sub-command2", "one", "two", "three", "four" }, sc2 }, };
+  }
+
+
+
+  /**
+   * Test the parseArguments method with valid args.
+   *
+   * @param args
+   *          The command line args.
+   * @param sc
+   *          The expected sub-command.
+   * @throws Exception
+   *           If something unexpected happened.
+   */
+  @Test(dataProvider = "validCommandLineArgs")
+  public void testParseArgumentsWithValidArgs(String[] args, SubCommand sc)
+      throws Exception {
+    parser.parseArguments(args);
+
+    // Check the correct sub-command was parsed.
+    Assert.assertEquals(parser.getSubCommand(), sc);
+
+    // Check that the trailing arguments were retrieved correctly and
+    // in the right order.
+    if (args.length > 1) {
+      Assert.assertEquals(parser.getTrailingArguments(), Arrays.asList(Arrays
+          .copyOfRange(args, 1, args.length)));
+    } else {
+      Assert.assertTrue(parser.getTrailingArguments().isEmpty());
+    }
+  }
+
+
+
+  /**
+   * Provide invalid command line args.
+   *
+   * @return Array of invalid command line args.
+   */
+  @DataProvider(name = "invalidCommandLineArgs")
+  public Object[][] createInvalidCommandLineArgs() {
+    return new Object[][] {
+        { new String[] { "sub-command1", "one" } },
+        { new String[] { "sub-command1", "one", "two" } },
+        { new String[] { "sub-command2" } },
+        { new String[] { "sub-command2", "one" } },
+        { new String[] { "sub-command2", "one", "two", "three", "four", "five" } }, };
+  }
+
+
+
+  /**
+   * Test the parseArguments method with invalid args.
+   *
+   * @param args
+   *          The command line args.
+   * @throws Exception
+   *           If something unexpected happened.
+   */
+  @Test(dataProvider = "invalidCommandLineArgs", expectedExceptions = ArgumentException.class)
+  public void testParseArgumentsWithInvalidArgs(String[] args) throws Exception {
+    parser.parseArguments(args);
+  }
+}

--
Gitblit v1.10.0