blob: 967aaa8c33c81a14f0fa9e8dcea7ea9ec1e5b712 [file] [log] [blame]
/*
* Copyright (C) 2010 The Android Open Source Project
*
* 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 com.android.tradefed.config;
import com.android.tradefed.config.Option.Importance;
import junit.framework.TestCase;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Unit tests for {@link ArgsOptionParser}.
*/
public class ArgsOptionParserTest extends TestCase {
/**
* An option source with one {@link Option} specified.
*/
private static class OneOptionSource {
private static final String DEFAULT_VALUE = "default";
private static final String OPTION_NAME = "my_option";
private static final String OPTION_DESC = "option description";
@Option(name=OPTION_NAME, shortName='o', description=OPTION_DESC)
private String mMyOption = DEFAULT_VALUE;
}
/**
* An option source with one {@link Option} specified.
*/
private static class MapOptionSource {
private static final String OPTION_NAME = "my_option";
private static final String OPTION_DESC = "option description";
@Option(name=OPTION_NAME, shortName='o', description=OPTION_DESC)
private Map<Integer, Boolean> mMyOption = new HashMap<Integer, Boolean>();
}
/**
* An option source with boolean {@link Option} specified.
*/
private static class BooleanOptionSource {
private static final boolean DEFAULT_BOOL = false;
private static final String DEFAULT_VALUE = "default";
@Option(name="my_boolean", shortName='b')
private boolean mMyBool = DEFAULT_BOOL;
@Option(name="my_option", shortName='o')
protected String mMyOption = DEFAULT_VALUE;
}
/**
* An option source with boolean {@link Option} specified with default = true.
*/
private static class BooleanTrueOptionSource {
private static final boolean DEFAULT_BOOL = true;
@Option(name="my_boolean", shortName='b')
private boolean mMyBool = DEFAULT_BOOL;
}
/**
* An option source that has a superclass with options
*/
private static class InheritedOptionSource extends OneOptionSource {
private static final String OPTION_NAME = "my_sub_option";
private static final String OPTION_DESC = "sub description";
@SuppressWarnings("unused")
@Option(name=OPTION_NAME, description=OPTION_DESC)
private String mMySubOption = "";
}
/**
* An option source for testing the {@link Option#importance()} settings
*/
private static class ImportantOptionSource {
private static final String IMPORTANT_OPTION_NAME = "important_option";
private static final String IMPORTANT_UNSET_OPTION_NAME = "unset_important_option";
private static final String UNIMPORTANT_OPTION_NAME = "unimportant_option";
@SuppressWarnings("unused")
@Option(name = IMPORTANT_OPTION_NAME, description = IMPORTANT_OPTION_NAME,
importance = Importance.ALWAYS)
private String mImportantOption = "foo";
@SuppressWarnings("unused")
@Option(name = IMPORTANT_UNSET_OPTION_NAME, description = IMPORTANT_UNSET_OPTION_NAME,
importance = Importance.IF_UNSET)
private String mImportantUnsetOption = null;
@SuppressWarnings("unused")
@Option(name = UNIMPORTANT_OPTION_NAME, description = UNIMPORTANT_OPTION_NAME,
importance = Importance.NEVER)
private String mUnimportantOption = null;
ImportantOptionSource(String setOption) {
mImportantUnsetOption = setOption;
}
ImportantOptionSource() {
}
}
/**
* Option source with mandatory options
*/
private static class MandatoryOptionSourceNoDefault {
@Option(name = "no-default", mandatory = true)
private String mNoDefaultOption;
}
/**
* Option source with mandatory options
*/
private static class MandatoryOptionSourceNull {
@Option(name = "null", mandatory = true)
private String mNullOption = null;
}
/**
* Option source with mandatory options
*/
private static class MandatoryOptionSourceEmptyCollection {
@Option(name = "empty-collection", mandatory = true)
private Collection<String> mEmptyCollection = new ArrayList<String>(0);
}
/**
* Option source with mandatory options
*/
private static class MandatoryOptionSourceEmptyMap {
@Option(name = "empty-map", mandatory = true)
private Map<String, String> mEmptyMap = new HashMap<String, String>();
}
/**
* Test passing an empty argument list for an object that has one option specified.
* <p/>
* Expected that the option field should retain its default value.
*/
public void testParse_noArg() throws ConfigurationException {
OneOptionSource object = new OneOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
parser.parse(new String[] {});
assertEquals(OneOptionSource.DEFAULT_VALUE, object.mMyOption);
}
/**
* Test passing an single argument for an object that has one option specified.
*/
public void testParse_oneArg() throws ConfigurationException {
OneOptionSource object = new OneOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final String expectedValue = "set";
parser.parse(new String[] {"--my_option", expectedValue});
assertEquals(expectedValue, object.mMyOption);
}
/**
* Test passing an single argument for an object that has one option specified.
*/
public void testParse_oneMapArg() throws ConfigurationException {
MapOptionSource object = new MapOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final int expectedKey = 13;
final boolean expectedValue = true;
parser.parse(new String[] {"--my_option", Integer.toString(expectedKey),
Boolean.toString(expectedValue)});
assertNotNull(object.mMyOption);
assertEquals(1, object.mMyOption.size());
assertEquals(expectedValue, (boolean) object.mMyOption.get(expectedKey));
}
/**
* Test passing an single argument for an object that has one option specified.
*/
public void testParseMapArg_mismatchKeyType() throws ConfigurationException {
MapOptionSource object = new MapOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final String expectedKey = "istanbul";
final boolean expectedValue = true;
try {
parser.parse(new String[] {"--my_option", expectedKey, Boolean.toString(expectedValue)});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expect an exception that explicitly mentions that the "key" is incorrect
assertTrue(String.format("Expected exception message to contain 'key': %s",
e.getMessage()), e.getMessage().contains("key"));
assertTrue(String.format("Expected exception message to contain '%s': %s",
expectedKey, e.getMessage()), e.getMessage().contains(expectedKey));
}
}
/**
* Test passing an single argument for an object that has one option specified.
*/
public void testParseMapArg_mismatchValueType() throws ConfigurationException {
MapOptionSource object = new MapOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final int expectedKey = 13;
final String expectedValue = "notconstantinople";
try {
parser.parse(new String[] {"--my_option", Integer.toString(expectedKey), expectedValue});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expect an exception that explicitly mentions that the "value" is incorrect
assertTrue(String.format("Expected exception message to contain 'value': '%s'",
e.getMessage()), e.getMessage().contains("value"));
assertTrue(String.format("Expected exception message to contain '%s': %s",
expectedValue, e.getMessage()), e.getMessage().contains(expectedValue));
}
}
/**
* Test passing an single argument for an object that has one option specified.
*/
public void testParseMapArg_missingKey() throws ConfigurationException {
MapOptionSource object = new MapOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
try {
parser.parse(new String[] {"--my_option"});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expect an exception that explicitly mentions that the "key" is incorrect
assertTrue(String.format("Expected exception message to contain 'key': '%s'",
e.getMessage()), e.getMessage().contains("key"));
}
}
/**
* Test passing an single argument for an object that has one option specified.
*/
public void testParseMapArg_missingValue() throws ConfigurationException {
MapOptionSource object = new MapOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final int expectedKey = 13;
try {
parser.parse(new String[] {"--my_option", Integer.toString(expectedKey)});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expect an exception that explicitly mentions that the "value" is incorrect
assertTrue(String.format("Expected exception message to contain 'value': '%s'",
e.getMessage()), e.getMessage().contains("value"));
}
}
/**
* Test passing an single argument for an object that has one option specified, using the
* option=value notation.
*/
public void testParse_oneArgEquals() throws ConfigurationException {
OneOptionSource object = new OneOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final String expectedValue = "set";
parser.parse(new String[] {String.format("--my_option=%s", expectedValue)});
assertEquals(expectedValue, object.mMyOption);
}
/**
* Test passing a single argument for an object that has one option specified, using the
* short option notation.
*/
public void testParse_oneShortArg() throws ConfigurationException {
OneOptionSource object = new OneOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final String expectedValue = "set";
parser.parse(new String[] {"-o", expectedValue});
assertEquals(expectedValue, object.mMyOption);
}
/**
* Test that "--" marks the beginning of positional arguments
*/
public void testParse_posArgs() throws ConfigurationException {
OneOptionSource object = new OneOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final String expectedValue = "set";
// have a position argument with a long option prefix, to try to confuse the parser
final String posArg = "--unused";
List<String> leftOver = parser.parse(new String[] {"-o", expectedValue, "--", posArg});
assertEquals(expectedValue, object.mMyOption);
assertTrue(leftOver.contains(posArg));
}
/**
* Test passing a single boolean argument.
*/
public void testParse_boolArg() throws ConfigurationException {
BooleanOptionSource object = new BooleanOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
parser.parse(new String[] {"-b"});
assertTrue(object.mMyBool);
}
/**
* Test passing a boolean argument with another short argument.
*/
public void testParse_boolTwoArg() throws ConfigurationException {
BooleanOptionSource object = new BooleanOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final String expectedValue = "set";
parser.parse(new String[] {"-bo", expectedValue});
assertTrue(object.mMyBool);
assertEquals(expectedValue, object.mMyOption);
}
/**
* Test passing a boolean argument with another short argument, with value concatenated.
* e.g -bovalue
*/
public void testParse_boolTwoArgValue() throws ConfigurationException {
BooleanOptionSource object = new BooleanOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
final String expectedValue = "set";
parser.parse(new String[] {String.format("-bo%s", expectedValue)});
assertTrue(object.mMyBool);
assertEquals(expectedValue, object.mMyOption);
}
/**
* Test the "--no-<bool option>" syntax
*/
public void testParse_boolFalse() throws ConfigurationException {
BooleanTrueOptionSource object = new BooleanTrueOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
parser.parse(new String[] {"--no-my_boolean"});
assertFalse(object.mMyBool);
}
/**
* Test the boolean long option syntax
*/
public void testParse_boolLong() throws ConfigurationException {
BooleanOptionSource object = new BooleanOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
parser.parse(new String[] {"--my_boolean"});
assertTrue(object.mMyBool);
}
/**
* Test passing arg string where value is missing
*/
public void testParse_missingValue() throws ConfigurationException {
OneOptionSource object = new OneOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
try {
parser.parse(new String[] {"--my_option"});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expected
}
}
/**
* Test parsing args for an option that does not exist.
*/
public void testParse_optionNotPresent() throws ConfigurationException {
OneOptionSource object = new OneOptionSource();
ArgsOptionParser parser = new ArgsOptionParser(object);
try {
parser.parse(new String[] {"--my_option", "set", "--not_here", "value"});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expected
}
}
/**
* Test that help text is displayed for all fields
*/
public void testGetOptionHelp() {
String help = ArgsOptionParser.getOptionHelp(false, new InheritedOptionSource());
assertTrue(help.contains(InheritedOptionSource.OPTION_NAME));
assertTrue(help.contains(InheritedOptionSource.OPTION_DESC));
assertTrue(help.contains(OneOptionSource.OPTION_NAME));
assertTrue(help.contains(OneOptionSource.OPTION_DESC));
assertTrue(help.contains(OneOptionSource.DEFAULT_VALUE));
}
/**
* Test displaying important only help text
*/
public void testGetOptionHelp_important() {
String help = ArgsOptionParser.getOptionHelp(true, new ImportantOptionSource());
assertTrue(help.contains(ImportantOptionSource.IMPORTANT_OPTION_NAME));
assertTrue(help.contains(ImportantOptionSource.IMPORTANT_UNSET_OPTION_NAME));
assertFalse(help.contains(ImportantOptionSource.UNIMPORTANT_OPTION_NAME));
}
/**
* Test that {@link Importance#IF_UNSET} {@link Option}s are hidden from help if set.
*/
public void testGetOptionHelp_importantUnset() {
String help = ArgsOptionParser.getOptionHelp(true, new ImportantOptionSource("foo"));
assertTrue(help.contains(ImportantOptionSource.IMPORTANT_OPTION_NAME));
assertFalse(help.contains(ImportantOptionSource.IMPORTANT_UNSET_OPTION_NAME));
assertFalse(help.contains(ImportantOptionSource.UNIMPORTANT_OPTION_NAME));
}
public void testMandatoryOption_noDefault() throws Exception {
MandatoryOptionSourceNoDefault object = new MandatoryOptionSourceNoDefault();
ArgsOptionParser parser = new ArgsOptionParser(object);
try {
parser.parse(new String[] {});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expected
}
}
public void testMandatoryOption_null() throws Exception {
MandatoryOptionSourceNull object = new MandatoryOptionSourceNull();
ArgsOptionParser parser = new ArgsOptionParser(object);
try {
parser.parse(new String[] {});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expected
}
}
public void testMandatoryOption_emptyCollection() throws Exception {
MandatoryOptionSourceEmptyCollection object = new MandatoryOptionSourceEmptyCollection();
ArgsOptionParser parser = new ArgsOptionParser(object);
try {
parser.parse(new String[] {});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expected
}
}
public void testMandatoryOption_emptyMap() throws Exception {
MandatoryOptionSourceEmptyMap object = new MandatoryOptionSourceEmptyMap();
ArgsOptionParser parser = new ArgsOptionParser(object);
try {
parser.parse(new String[] {});
fail("ConfigurationException not thrown");
} catch (ConfigurationException e) {
// expected
}
}
}