Skip to content

Commit

Permalink
Re #9731. Setting property values from aliases.
Browse files Browse the repository at this point in the history
  • Loading branch information
mantid-roman committed Jul 25, 2014
1 parent fbd39ac commit ea6c2bc
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 12 deletions.
8 changes: 8 additions & 0 deletions Code/Mantid/Framework/Kernel/inc/MantidKernel/IValidator.h
Expand Up @@ -107,6 +107,14 @@ class DLLExport IValidator
* @return The set of allowed values that this validator may have or an empty set
*/
virtual std::vector<std::string> allowedValues() const { return std::vector<std::string>(); }

/**
* Implement this method for validators which wish to support aliasing for alloeed values.
* @param alias :: A string representation of an alias.
* @return :: A string representation of an aliased value. Should throw std::invalid_argument
* is the given alias is invalid.
*/
virtual std::string getValueForAlias(const std::string& alias) const { throw std::invalid_argument("Validator does'n support value aliasing.") ;}

/// Make a copy of the present type of validator
virtual IValidator_sptr clone() const = 0;
Expand Down
54 changes: 51 additions & 3 deletions Code/Mantid/Framework/Kernel/inc/MantidKernel/ListValidator.h
Expand Up @@ -57,10 +57,19 @@ class ListValidator : public TypedValidator<TYPE>
}

/** Constructor
* @param values :: A vector of the valid values */
explicit ListValidator(const std::vector<TYPE>& values, const std::map<std::string,TYPE>& aliases = std::map<std::string,TYPE>()):
* @param values :: A vector of the valid values
* @param aliases :: Optional aliases for the valid values.
*/
explicit ListValidator(const std::vector<TYPE>& values, const std::map<std::string,std::string>& aliases = std::map<std::string,std::string>()):
TypedValidator<TYPE>(), m_allowedValues(values.begin(), values.end()), m_aliases(aliases.begin(),aliases.end())
{
for(auto aliasIt = m_aliases.begin(); aliasIt != m_aliases.end(); ++aliasIt)
{
if ( values.end() == std::find( values.begin(), values.end(), boost::lexical_cast<TYPE>(aliasIt->second) ) )
{
throw std::invalid_argument("Alias " + aliasIt->first + " referes to invalid value " + aliasIt->second);
}
}
}
/// Destructor
virtual ~ListValidator(){};
Expand Down Expand Up @@ -95,6 +104,22 @@ class ListValidator : public TypedValidator<TYPE>
m_allowedValues.push_back(value);
}
}

/**
* Return an allowed value (as a string) given an alias.
* @param alias :: An alias string.
* @return :: Allowed value or throw if alias is unknown.
*/
std::string getValueForAlias(const std::string& alias) const
{
auto aliasIt = m_aliases.find( alias );
if ( aliasIt == m_aliases.end() )
{
throw std::invalid_argument("Unknown alias found " + alias);
}
return aliasIt->second;
}

protected:
/** Checks if the string passed is in the list
* @param value :: The value to test
Expand All @@ -109,6 +134,7 @@ class ListValidator : public TypedValidator<TYPE>
else
{
if ( isEmpty(value) ) return "Select a value";
if ( isAlias(value) ) return "_alias";
std::ostringstream os;
os << "The value \"" << value << "\" is not in the list of allowed values";
return os.str();
Expand All @@ -129,10 +155,32 @@ class ListValidator : public TypedValidator<TYPE>
*/
bool isEmpty(const std::string & value) const { return value.empty(); }

/**
* Test if a value is an alias of an alowed value.
* @param value :: Value to test.
* @return :: True if it's an alias.
*/
template<typename T>
bool isAlias(const T& value) const
{
std::string strValue = boost::lexical_cast<std::string>( value );
return m_aliases.find( strValue ) != m_aliases.end();
}

/**
* Test if a value is an alias of an alowed value.
* @param value :: Value to test.
* @return :: True if it's an alias.
*/
bool isAlias(const std::string & value) const
{
return m_aliases.find( value ) != m_aliases.end();
}

/// The set of valid values
std::vector<TYPE> m_allowedValues;
/// The optional aliases for the allowed values.
std::map<std::string,TYPE> m_aliases;
std::map<std::string,std::string> m_aliases;
};

/// ListValidator<std::string> is used heavily
Expand Down
18 changes: 18 additions & 0 deletions Code/Mantid/Framework/Kernel/inc/MantidKernel/PropertyWithValue.h
Expand Up @@ -439,6 +439,11 @@ class DLLExport PropertyWithValue : public Property
{
return m_value;
}
else if ( problem == "_alias" )
{
m_value = getValueForAlias( value );
return m_value;
}
else
{
m_value = oldValue;
Expand Down Expand Up @@ -565,6 +570,19 @@ class DLLExport PropertyWithValue : public Property
return "Attempt to assign object of type DataItem to property (" + name() + ") of incorrect type";
}

/** Return value for a given alias.
* @param alias :: An alias for a value. If a value cannot be found throw an invalid_argument exception.
* @return :: A value.
*/
const TYPE getValueForAlias(const TYPE& alias) const
{
std::string strAlias = toString( alias );
std::string strValue = m_validator->getValueForAlias( strAlias );
TYPE value;
toValue( strValue, value );
return value;
}

/// Visitor validator class
IValidator_sptr m_validator;

Expand Down
81 changes: 81 additions & 0 deletions Code/Mantid/Framework/Kernel/test/ListValidatorTest.h
Expand Up @@ -77,6 +77,87 @@ class ListValidatorTest : public CxxTest::TestSuite
TS_ASSERT_DIFFERS( v, vv );
TS_ASSERT( boost::dynamic_pointer_cast<StringListValidator>(vv) );
}

void testAliasString()
{
std::vector<std::string> values;
values.push_back("one");
values.push_back("three");
values.push_back("two");
std::map<std::string,std::string> aliases;
aliases["1"] = "one";
aliases["2"] = "two";
aliases["3"] = "three";
StringListValidator validator(values, aliases);
TS_ASSERT_EQUALS( validator.isValid("one"), "" )
TS_ASSERT_EQUALS( validator.isValid("two"), "" )
TS_ASSERT_EQUALS( validator.isValid("three"), "" )

TS_ASSERT_EQUALS( validator.isValid("1"), "_alias" )
TS_ASSERT_EQUALS( validator.isValid("2"), "_alias" )
TS_ASSERT_EQUALS( validator.isValid("3"), "_alias" )
TS_ASSERT_EQUALS( validator.isValid("4"), "The value \"4\" is not in the list of allowed values" )

TS_ASSERT_EQUALS( validator.getValueForAlias("1"), "one" )
TS_ASSERT_EQUALS( validator.getValueForAlias("2"), "two" )
TS_ASSERT_EQUALS( validator.getValueForAlias("3"), "three" )

TS_ASSERT_THROWS( validator.getValueForAlias("4"), std::invalid_argument )
}

void testAliasInt()
{
std::vector<int> values;
values.push_back(1);
values.push_back(5);
values.push_back(3);
std::map<std::string,std::string> aliases;
aliases["11"] = "1";
aliases["33"] = "3";
aliases["55"] = "5";
ListValidator<int> validator(values, aliases);
TS_ASSERT_EQUALS( validator.isValid(1), "" )
TS_ASSERT_EQUALS( validator.isValid(3), "" )
TS_ASSERT_EQUALS( validator.isValid(5), "" )

TS_ASSERT_EQUALS( validator.isValid(11), "_alias" )
TS_ASSERT_EQUALS( validator.isValid(33), "_alias" )
TS_ASSERT_EQUALS( validator.isValid(55), "_alias" )
TS_ASSERT_EQUALS( validator.isValid(4), "The value \"4\" is not in the list of allowed values" )

TS_ASSERT_EQUALS( validator.getValueForAlias("11"), "1" )
TS_ASSERT_EQUALS( validator.getValueForAlias("33"), "3" )
TS_ASSERT_EQUALS( validator.getValueForAlias("55"), "5" )

TS_ASSERT_THROWS( validator.getValueForAlias("13"), std::invalid_argument )
}

void test_wrong_alias()
{
std::vector<std::string> values;
values.push_back("one");
values.push_back("three");
std::map<std::string,std::string> aliases;
aliases["1"] = "one";
aliases["2"] = "two";
TS_ASSERT_THROWS( StringListValidator validator(values, aliases), std::invalid_argument );
}

void test_self_alias()
{
std::vector<std::string> values;
values.push_back("one");
values.push_back("three");
std::map<std::string,std::string> aliases;
aliases["1"] = "one";
aliases["three"] = "three";
aliases["one"] = "three";
StringListValidator validator(values, aliases);

TS_ASSERT_EQUALS( validator.isValid("one"), "" )
TS_ASSERT_EQUALS( validator.isValid("three"), "" )
TS_ASSERT_EQUALS( validator.isValid("1"), "_alias" )
}

};

Expand Down
18 changes: 9 additions & 9 deletions Code/Mantid/Framework/Kernel/test/PropertyWithValueTest.h
Expand Up @@ -611,8 +611,8 @@ class PropertyWithValueTest : public CxxTest::TestSuite
allowedValues.push_back( "Hello");
allowedValues.push_back( "World");
std::map<std::string,std::string> alias;
alias["Hello"] = "1";
alias["World"] = "0";
alias["1"] = "Hello";
alias["0"] = "World";
auto validator = boost::make_shared<ListValidator<std::string>>(allowedValues,alias);
PropertyWithValue<std::string> prop("String","",validator);
TS_ASSERT_THROWS_NOTHING( prop = "Hello" );
Expand All @@ -621,13 +621,13 @@ class PropertyWithValueTest : public CxxTest::TestSuite

TS_ASSERT_THROWS( prop = "Mantid", std::invalid_argument );

//TS_ASSERT_THROWS_NOTHING( prop = "1" );
//value = prop;
//TS_ASSERT_EQUALS( value, "Hello" );
//
//TS_ASSERT_THROWS_NOTHING( prop = "0" );
//value = prop;
//TS_ASSERT_EQUALS( value, "World" );
TS_ASSERT_THROWS_NOTHING( prop = "1" );
value = prop;
TS_ASSERT_EQUALS( value, "Hello" );

TS_ASSERT_THROWS_NOTHING( prop = "0" );
value = prop;
TS_ASSERT_EQUALS( value, "World" );
}

private:
Expand Down

0 comments on commit ea6c2bc

Please sign in to comment.