Argument validation.

git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@631 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
hanna 2009-05-07 20:28:56 +00:00
parent a3d8febbf2
commit 7f8850a8a2
5 changed files with 93 additions and 10 deletions

View File

@ -35,7 +35,6 @@ public abstract class Walker<MapType, ReduceType> {
protected Walker() {
if( GenomeAnalysisTK.Instance != null ) {
GenomeAnalysisTK gatk = GenomeAnalysisTK.Instance;
gatk.loadArgumentsIntoObject(this);
out = new PrintStream( gatk.getOutputTracker().getOutStream() );
err = new PrintStream( gatk.getOutputTracker().getErrStream() );
}

View File

@ -59,4 +59,10 @@ public @interface Argument {
* argument should be independent.
*/
String exclusiveOf() default "";
/**
* Provide a regexp-based validation string.
* @return Non-empty regexp for validation, blank otherwise.
*/
String validation() default "";
}

View File

@ -152,6 +152,12 @@ class ArgumentDefinitions implements Iterable<ArgumentDefinition> {
return definition.required == (Boolean)key;
}
};
static DefinitionMatcher VerifiableDefinitionMatcher = new DefinitionMatcher() {
public boolean matches( ArgumentDefinition definition, Object key ) {
return definition.validation != null;
}
};
}
/**
@ -211,6 +217,11 @@ class ArgumentDefinition {
*/
public final String exclusiveOf;
/**
* Can we validate this regular expression?
*/
public final String validation;
public final Class sourceClass;
public final Field sourceField;
@ -229,6 +240,7 @@ class ArgumentDefinition {
doc = argument.doc();
required = argument.required() && !isFlag();
exclusiveOf = argument.exclusiveOf().trim().length() > 0 ? argument.exclusiveOf().trim() : null;
validation = argument.validation().trim().length() > 0 ? argument.validation().trim() : null;
}
/**

View File

@ -108,6 +108,7 @@ public class ParsingEngine {
public enum ValidationType { MissingRequiredArgument,
InvalidArgument,
InvalidArgumentValue,
ValueMissingArgument,
TooManyValuesForArgument,
MutuallyExclusive };
@ -146,10 +147,29 @@ public class ParsingEngine {
throw new InvalidArgumentException( invalidArguments );
}
// Find invalid argument values (arguments that fail the regexp test.
if( !skipValidationOf.contains(ValidationType.InvalidArgumentValue) ) {
Collection<ArgumentDefinition> verifiableArguments =
argumentDefinitions.findArgumentDefinitions( null, ArgumentDefinitions.VerifiableDefinitionMatcher );
Collection<Pair<ArgumentDefinition,String>> invalidValues = new ArrayList<Pair<ArgumentDefinition,String>>();
for( ArgumentDefinition verifiableArgument: verifiableArguments ) {
Collection<ArgumentMatch> verifiableMatches = argumentMatches.findMatches( verifiableArgument );
for( ArgumentMatch verifiableMatch: verifiableMatches ) {
for( String value: verifiableMatch.values() ) {
if( !value.matches(verifiableArgument.validation) )
invalidValues.add( new Pair<ArgumentDefinition,String>(verifiableArgument, value) );
}
}
}
if( invalidValues.size() > 0 )
throw new InvalidArgumentValueException( invalidValues );
}
// Find values without an associated mate.
if( !skipValidationOf.contains(ValidationType.ValueMissingArgument) ) {
if( argumentMatches.MissingArgument.values().size() > 0 )
throw new InvalidArgumentValueException( argumentMatches.MissingArgument );
throw new UnmatchedArgumentException( argumentMatches.MissingArgument );
}
// Find arguments with too many values.
@ -457,10 +477,31 @@ class InvalidArgumentException extends ParseException {
}
/**
* An exception for values that can't be mated with any argument.
* An exception for values whose format is invalid.
*/
class InvalidArgumentValueException extends ParseException {
public InvalidArgumentValueException( ArgumentMatch invalidValues ) {
public InvalidArgumentValueException( Collection<Pair<ArgumentDefinition,String>> invalidArgumentValues ) {
super( formatArguments(invalidArgumentValues) );
}
private static String formatArguments( Collection<Pair<ArgumentDefinition,String>> invalidArgumentValues ) {
StringBuilder sb = new StringBuilder();
for( Pair<ArgumentDefinition,String> invalidValue: invalidArgumentValues ) {
sb.append( String.format("%nArgument '--%s' has value of incorrect format: %s (should match %s)",
invalidValue.first.fullName,
invalidValue.second,
invalidValue.first.validation) );
}
return sb.toString();
}
}
/**
* An exception for values that can't be mated with any argument.
*/
class UnmatchedArgumentException extends ParseException {
public UnmatchedArgumentException( ArgumentMatch invalidValues ) {
super( formatArguments(invalidValues) );
}

View File

@ -350,7 +350,7 @@ public class ParsingEngineTest extends BaseTest {
public Integer bar;
}
@Test(expected=InvalidArgumentValueException.class)
@Test(expected=UnmatchedArgumentException.class)
public void missingArgumentNameTest() {
final String[] commandLine = new String[] {"foo.txt"};
@ -363,7 +363,7 @@ public class ParsingEngineTest extends BaseTest {
}
@Test(expected=InvalidArgumentValueException.class)
@Test(expected=UnmatchedArgumentException.class)
public void extraValueTest() {
final String[] commandLine = new String[] {"-Ifoo.txt", "bar.txt"};
@ -446,7 +446,7 @@ public class ParsingEngineTest extends BaseTest {
Integer myArg;
}
@Test(expected=InvalidArgumentValueException.class)
@Test(expected=UnmatchedArgumentException.class)
public void booleanWithParameterTest() {
final String[] commandLine = new String[] {"--mybool", "true"};
@ -461,7 +461,7 @@ public class ParsingEngineTest extends BaseTest {
}
@Test
public void testValidParseForAnalysisType() {
public void validParseForAnalysisTypeTest() {
final String[] commandLine = new String[] {"--analysis_type", "Pileup" };
parsingEngine.addArgumentSource( AnalysisTypeArgProvider.class );
@ -480,7 +480,7 @@ public class ParsingEngineTest extends BaseTest {
}
@Test(expected=TooManyValuesForArgumentException.class)
public void testInvalidParseForAnalysisType() {
public void invalidParseForAnalysisTypeTest() {
final String[] commandLine = new String[] {"--analysis_type", "Pileup", "-TCountReads" };
parsingEngine.addArgumentSource( AnalysisTypeArgProvider.class );
@ -489,7 +489,7 @@ public class ParsingEngineTest extends BaseTest {
}
@Test(expected=ArgumentsAreMutuallyExclusiveException.class)
public void testMutuallyExclusiveArguments() {
public void mutuallyExclusiveArgumentsTest() {
// Passing only foo should work fine...
String[] commandLine = new String[] {"--foo","5"};
@ -516,4 +516,29 @@ public class ParsingEngineTest extends BaseTest {
@Argument(doc="bar",required=false)
Integer bar;
}
@Test(expected=InvalidArgumentValueException.class)
public void argumentValidationTest() {
// Passing only foo should work fine...
String[] commandLine = new String[] {"--value","521"};
parsingEngine.addArgumentSource( ValidatingArgProvider.class );
parsingEngine.parse( commandLine );
parsingEngine.validate();
ValidatingArgProvider argProvider = new ValidatingArgProvider();
parsingEngine.loadArgumentsIntoObject( argProvider );
Assert.assertEquals("Argument is not correctly initialized", 521, argProvider.value.intValue() );
// Try some invalid arguments
commandLine = new String[] {"--value","foo"};
parsingEngine.parse( commandLine );
parsingEngine.validate();
}
private class ValidatingArgProvider {
@Argument(doc="value",validation="\\d+")
Integer value;
}
}