/* * Copyright 2015 herd contributors * * Licensed 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. */ package org.finra.herd.core; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.apache.commons.cli.MissingArgumentException; import org.apache.commons.cli.MissingOptionException; import org.apache.commons.cli.Option; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.UnrecognizedOptionException; import org.junit.Test; import org.springframework.beans.propertyeditors.CustomBooleanEditor; /** * Unit tests for ArgumentParser class. */ public class ArgumentParserTest extends AbstractCoreTest { @Test public void testGetApplicationName() { final String testApplicationName = "MY_TEST_APP"; ArgumentParser argParser = new ArgumentParser(testApplicationName); assertEquals(testApplicationName, argParser.getApplicationName()); } @Test public void testAddArgument() { Option opt1 = new Option("a", "some_flag", false, "Some flag parameter"); Option opt2 = new Option("b", "some_parameter", true, "Some parameter with an argument"); List<String> optionsIn = Arrays.asList(optionToString(opt1), optionToString(opt2)); ArgumentParser argParser = new ArgumentParser(""); argParser.addArgument(opt1, true); argParser.addArgument(opt2.getOpt(), opt2.getLongOpt(), opt2.hasArg(), opt2.getDescription(), false); Collection resultOptions = argParser.getConfiguredOptions(); List<String> optionsOut = new ArrayList<>(); for (Object obj : resultOptions) { assertTrue(obj instanceof Option); optionsOut.add(optionToString((Option) obj)); } optionsOut.containsAll(optionsIn); optionsIn.containsAll(optionsOut); } @Test(expected = UnrecognizedOptionException.class) public void testParseArgumentsUnrecognizedOptionException() throws ParseException { ArgumentParser argParser = new ArgumentParser(""); argParser.addArgument("a", "configured_option", false, "Some flag parameter", false); argParser.parseArguments(new String[] {"-b", "unrecognized_option"}); } @Test(expected = MissingArgumentException.class) public void testParseArgumentsMissingArgumentException() throws ParseException { ArgumentParser argParser = new ArgumentParser(""); argParser.addArgument("a", "some_optional_parameter", true, "Some optional parameter with an argument", false); argParser.parseArguments(new String[] {"-a"}); } @Test public void testParseArgumentsFailOnMissingArgumentFalse() throws ParseException { // Create an argument parser with a required "a" option. ArgumentParser argParser = new ArgumentParser(""); argParser.addArgument("a", "some_optional_parameter", false, "Some argument", true); // Parse the arguments with a missing argument, but this should not thrown an exception since we are passing the flag which WILL NOT fail on missing // arguments. argParser.parseArguments(new String[] {}, false); } @Test(expected = MissingOptionException.class) public void testParseArgumentsFailOnMissingArgumentTrue() throws ParseException { // Create an argument parser with a required "a" option. ArgumentParser argParser = new ArgumentParser(""); argParser.addArgument("a", "some_optional_parameter", false, "Some argument", true); // Parse the arguments with a missing argument which should thrown an exception since we are passing the flag which WILL fail on missing arguments. argParser.parseArguments(new String[] {}, true); } @Test(expected = MissingOptionException.class) public void testParseArguments() throws ParseException { // Create an argument parser with a required "a" option. ArgumentParser argParser = new ArgumentParser(""); argParser.addArgument("a", "some_required_parameter", true, "Some argument", true); // Parse the arguments with a missing argument which should thrown an exception since we are using the method that WILL fail on missing arguments. argParser.parseArguments(new String[] {}); } @Test public void testGetUsageInformation() { List<Option> optionsIn = new ArrayList<>(); optionsIn.add(new Option("a", "some_flag", false, "Some flag parameter")); optionsIn.add(new Option("b", "some_parameter", true, "Some parameter with an argument")); ArgumentParser argParser = new ArgumentParser("TestApp"); argParser.addArgument(optionsIn.get(0), false); argParser.addArgument(optionsIn.get(1), true); String usage = argParser.getUsageInformation(); assertNotNull(usage); assertTrue(usage.contains(String.format("usage: %s", argParser.getApplicationName()))); for (Option option : optionsIn) { assertTrue(usage.contains(String.format("-%s,", option.getOpt()))); assertTrue(usage.contains(String.format("--%s", option.getLongOpt()))); assertTrue(usage.contains(option.getDescription())); assertTrue(!option.hasArg() || usage.contains("<arg>")); } } @Test public void testGetBooleanValue() throws ParseException { ArgumentParser argParser = new ArgumentParser(""); Option boolOpt = argParser.addArgument("b", "bool", false, "Some optional configuration flag", false); Boolean resultValue; final String shortBoolOpt = String.format("-%s", boolOpt.getOpt()); final String longBoolOpt = String.format("--%s", boolOpt.getLongOpt()); argParser.parseArguments(new String[] {}); resultValue = argParser.getBooleanValue(boolOpt); assertNotNull(resultValue); assertFalse(resultValue); argParser.parseArguments(new String[] {shortBoolOpt}); resultValue = argParser.getBooleanValue(boolOpt); assertNotNull(resultValue); assertTrue(resultValue); argParser.parseArguments(new String[] {longBoolOpt}); resultValue = argParser.getBooleanValue(boolOpt); assertNotNull(resultValue); assertTrue(resultValue); } @Test public void testGetStringValueAsBoolean() throws ParseException { ArgumentParser argParser = new ArgumentParser(""); Option strOpt = argParser.addArgument("s", "str", true, "Some string input parameter to have a boolean value", false); final String shortStrOpt = String.format("-%s", strOpt.getOpt()); final String longStrOpt = String.format("--%s", strOpt.getLongOpt()); // Validate the default value - no option is specified. argParser.parseArguments(new String[] {}); assertFalse(argParser.getStringValueAsBoolean(strOpt, false)); assertTrue(argParser.getStringValueAsBoolean(strOpt, true)); // Validate all "true" boolean values using both short an long options. for (String inputValue : Arrays .asList(CustomBooleanEditor.VALUE_TRUE, CustomBooleanEditor.VALUE_YES, CustomBooleanEditor.VALUE_ON, CustomBooleanEditor.VALUE_1)) { argParser.parseArguments(new String[] {shortStrOpt, inputValue}); assertTrue(argParser.getStringValueAsBoolean(strOpt, false)); argParser.parseArguments(new String[] {longStrOpt, inputValue}); assertTrue(argParser.getStringValueAsBoolean(strOpt, false)); } // Validate all "false" boolean values. for (String inputValue : Arrays .asList(CustomBooleanEditor.VALUE_FALSE, CustomBooleanEditor.VALUE_NO, CustomBooleanEditor.VALUE_OFF, CustomBooleanEditor.VALUE_0)) { argParser.parseArguments(new String[] {shortStrOpt, inputValue}); assertFalse(argParser.getStringValueAsBoolean(strOpt, true)); } // Try to parse an invalid boolean value. argParser.parseArguments(new String[] {shortStrOpt, INVALID_BOOLEAN_VALUE}); try { argParser.getStringValueAsBoolean(strOpt, false); fail("Suppose to throw a ParseException when option has an invalid boolean value."); } catch (ParseException e) { assertEquals(String.format("Invalid boolean value [%s]", INVALID_BOOLEAN_VALUE), e.getMessage()); } } @Test public void testGetStringValue() throws ParseException { final String testDefaultValue = "default_str_value"; ArgumentParser argParser = new ArgumentParser(""); Option strOpt = argParser.addArgument("s", "str", true, "Some string input parameter", false); String inputValue; String resultValue; final String shortStrOpt = String.format("-%s", strOpt.getOpt()); final String longStrOpt = String.format("--%s", strOpt.getLongOpt()); argParser.parseArguments(new String[] {}); assertNull(argParser.getStringValue(strOpt)); assertEquals(testDefaultValue, argParser.getStringValue(strOpt, testDefaultValue)); inputValue = "my_string_value_1"; argParser.parseArguments(new String[] {shortStrOpt, inputValue}); resultValue = argParser.getStringValue(strOpt); assertNotNull(resultValue); assertEquals(inputValue, resultValue); inputValue = "my_string_value_2"; argParser.parseArguments(new String[] {shortStrOpt, inputValue}); resultValue = argParser.getStringValue(strOpt, testDefaultValue); assertNotNull(resultValue); assertEquals(inputValue, resultValue); inputValue = "my_string_value_3"; argParser.parseArguments(new String[] {longStrOpt, inputValue}); resultValue = argParser.getStringValue(strOpt); assertNotNull(resultValue); assertEquals(inputValue, resultValue); } @Test public void testGetIntegerValue() throws ParseException { final Integer testDefaultValue = 500; final Integer testMinValue = 0; final Integer testMaxValue = 1000; ArgumentParser argParser = new ArgumentParser(""); Option intOpt = argParser.addArgument("i", "int", true, "Some integer parameter", false); Integer inputValue; Integer resultValue; final String shortIntOpt = String.format("-%s", intOpt.getOpt()); final String longIntOpt = String.format("--%s", intOpt.getLongOpt()); argParser.parseArguments(new String[] {}); assertNull(argParser.getIntegerValue(intOpt)); assertEquals(testDefaultValue, argParser.getIntegerValue(intOpt, testDefaultValue)); inputValue = 123; argParser.parseArguments(new String[] {shortIntOpt, inputValue.toString()}); resultValue = argParser.getIntegerValue(intOpt); assertNotNull(resultValue); assertEquals(inputValue, resultValue); inputValue = 456; argParser.parseArguments(new String[] {shortIntOpt, inputValue.toString()}); resultValue = argParser.getIntegerValue(intOpt, testDefaultValue); assertNotNull(resultValue); assertEquals(inputValue, resultValue); inputValue = 789; argParser.parseArguments(new String[] {longIntOpt, inputValue.toString()}); resultValue = argParser.getIntegerValue(intOpt); assertNotNull(resultValue); assertEquals(inputValue, resultValue); // The "happy path" test case for the minimum and maximum allowed values. inputValue = 234; argParser.parseArguments(new String[] {longIntOpt, inputValue.toString()}); resultValue = argParser.getIntegerValue(intOpt, testDefaultValue, testMinValue, testMaxValue); assertNotNull(resultValue); assertEquals(inputValue, resultValue); // The default value test case the minimum and maximum allowed values. argParser.parseArguments(new String[] {}); resultValue = argParser.getIntegerValue(intOpt, testDefaultValue, testMinValue, testMaxValue); assertNotNull(resultValue); assertEquals(testDefaultValue, resultValue); // The edge test case for the minimum allowed value. argParser.parseArguments(new String[] {longIntOpt, testMinValue.toString()}); resultValue = argParser.getIntegerValue(intOpt, testDefaultValue, testMinValue, testMaxValue); assertNotNull(resultValue); assertEquals(testMinValue, resultValue); // The edge test case for the maximum allowed value. argParser.parseArguments(new String[] {longIntOpt, testMaxValue.toString()}); resultValue = argParser.getIntegerValue(intOpt, testDefaultValue, testMinValue, testMaxValue); assertNotNull(resultValue); assertEquals(testMaxValue, resultValue); // The edge test case for the minimum and maximum allowed values. argParser.parseArguments(new String[] {longIntOpt, testDefaultValue.toString()}); resultValue = argParser.getIntegerValue(intOpt, testDefaultValue, testDefaultValue, testDefaultValue); assertNotNull(resultValue); assertEquals(testDefaultValue, resultValue); // Try to get an option value what is less than the minimum allowed value. inputValue = testMinValue - 1; argParser.parseArguments(new String[] {longIntOpt, inputValue.toString()}); try { argParser.getIntegerValue(intOpt, testDefaultValue, testMinValue, testMaxValue); fail("Suppose to throw an IllegalArgumentException when option value is less than the minimum allowed value."); } catch (IllegalArgumentException e) { assertEquals(String.format("The %s option value %d is less than the minimum allowed value of %d.", intOpt.getLongOpt(), inputValue, testMinValue), e.getMessage()); } // Try to get an option value what is greater than the maximum allowed value. inputValue = testMaxValue + 1; argParser.parseArguments(new String[] {longIntOpt, inputValue.toString()}); try { argParser.getIntegerValue(intOpt, testDefaultValue, testMinValue, testMaxValue); fail("Suppose to throw an IllegalArgumentException when option value is greater than the maximum allowed value."); } catch (IllegalArgumentException e) { assertEquals(String.format("The %s option value %d is bigger than maximum allowed value of %d.", intOpt.getLongOpt(), inputValue, testMaxValue), e.getMessage()); } } @Test public void testGetIntegerNullValue() throws ParseException { // Create an argument parser with an optional "a" option. ArgumentParser argParser = new ArgumentParser(""); Option option = argParser.addArgument("a", "some_required_parameter", false, "Some required parameter with an argument", false); // Parse the arguments and get an integer value which wasn't specified which should return null. argParser.parseArguments(new String[] {}); Integer value = argParser.getIntegerValue(option, null, 0, 100); assertNull(value); } @Test public void testGetFileValue() throws ParseException { File testDefaultValue = new File("default_file_name"); ArgumentParser argParser = new ArgumentParser(""); Option fileOpt = argParser.addArgument("f", "file", true, "Source file name", false); File inputValue; File resultValue; final String shortFileOpt = String.format("-%s", fileOpt.getOpt()); final String longFileOpt = String.format("--%s", fileOpt.getLongOpt()); argParser.parseArguments(new String[] {""}); assertNull(argParser.getFileValue(fileOpt)); assertEquals(testDefaultValue, argParser.getFileValue(fileOpt, testDefaultValue)); inputValue = new File("folder/file_name_1"); argParser.parseArguments(new String[] {shortFileOpt, inputValue.toString()}); resultValue = argParser.getFileValue(fileOpt); assertNotNull(resultValue); assertEquals(inputValue, resultValue); inputValue = new File("folder/file_name_2"); argParser.parseArguments(new String[] {shortFileOpt, inputValue.toString()}); resultValue = argParser.getFileValue(fileOpt, testDefaultValue); assertNotNull(resultValue); assertEquals(inputValue, resultValue); inputValue = new File("file_name_3"); argParser.parseArguments(new String[] {longFileOpt, inputValue.toString()}); resultValue = argParser.getFileValue(fileOpt); assertNotNull(resultValue); assertEquals(inputValue, resultValue); } /** * Dump state of the Option object instance, suitable for debugging and comparing Options as Strings. * * @param option the Option object instance to dump the state of * * @return Stringified form of this Option object instance */ private String optionToString(Option option) { StringBuilder buf = new StringBuilder(); buf.append("[ option: "); buf.append(option.getOpt()); if (option.getLongOpt() != null) { buf.append(" ").append(option.getLongOpt()); } buf.append(" "); if (option.hasArg()) { buf.append(" [ARG]"); } buf.append(" :: ").append(option.getDescription()); if (option.isRequired()) { buf.append(" [REQUIRED]"); } buf.append(" ]"); return buf.toString(); } }