From 3438dd6b4cbc42178fc9e48f937f10ee9b0c5827 Mon Sep 17 00:00:00 2001 From: felmer <felmer> Date: Wed, 4 Nov 2009 08:46:34 +0000 Subject: [PATCH] LMS-1249 allow-empty-values property added for Validator Factories. Validator Factories tested. SVN: 13214 --- .../validation/AbstractValidator.java | 54 ++++++++++ .../validation/AbstractValidatorFactory.java | 39 +++++++ .../validation/ColumnDefinition.java | 4 +- .../validation/NumericValidatorFactory.java | 21 ++-- .../validation/RegExBasedValidator.java | 12 ++- .../validation/StringValidatorFactory.java | 5 +- .../validation/UniqueValidatorFactory.java | 2 +- .../NumericValidatorFactoryTest.java | 90 ++++++++++++++-- .../StringValidatorFactoryTest.java | 101 ++++++++++++++++++ .../UniqueValidatorFactoryTest.java | 84 +++++++++++++++ 10 files changed, 390 insertions(+), 22 deletions(-) create mode 100644 datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/AbstractValidator.java create mode 100644 datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/AbstractValidatorFactory.java create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/StringValidatorFactoryTest.java create mode 100644 datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/UniqueValidatorFactoryTest.java diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/AbstractValidator.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/AbstractValidator.java new file mode 100644 index 00000000000..35b0d85f594 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/AbstractValidator.java @@ -0,0 +1,54 @@ +/* + * Copyright 2009 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.etlserver.validation; + +import org.apache.commons.lang.StringUtils; + +import ch.systemsx.cisd.common.exceptions.UserFailureException; + +/** + * + * + * @author Franz-Josef Elmer + */ +abstract class AbstractValidator implements IValidator +{ + private final boolean allowEmptyValues; + + AbstractValidator(boolean allowEmptyValues) + { + this.allowEmptyValues = allowEmptyValues; + } + + public final void assertValid(String value) + { + if (allowEmptyValues) + { + if (StringUtils.isBlank(value)) + { + return; + } + } else if (StringUtils.isBlank(value)) + { + throw new UserFailureException("Empty value is not allowed."); + } + assertValidNonEmptyValue(value); + } + + protected abstract void assertValidNonEmptyValue(String value); + +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/AbstractValidatorFactory.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/AbstractValidatorFactory.java new file mode 100644 index 00000000000..3195ff3c9f7 --- /dev/null +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/AbstractValidatorFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 2009 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.etlserver.validation; + +import java.util.Properties; + +import ch.systemsx.cisd.common.utilities.PropertyUtils; + +/** + * + * + * @author Franz-Josef Elmer + */ +abstract class AbstractValidatorFactory implements IValidatorFactory +{ + static final String ALLOW_EMPTY_VALUES_KEY = "allow-empty-values"; + + protected final boolean allowEmptyValues; + + AbstractValidatorFactory(Properties properties) + { + allowEmptyValues = PropertyUtils.getBoolean(properties, ALLOW_EMPTY_VALUES_KEY, false); + } + +} diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/ColumnDefinition.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/ColumnDefinition.java index a38ddad28ba..ba470d65bac 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/ColumnDefinition.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/ColumnDefinition.java @@ -58,8 +58,8 @@ class ColumnDefinition IColumnHeaderValidator headerValidator; if (headerValidatorName == null) { - headerValidator = - new RegExBasedValidator(properties.getProperty(HEADER_PATTERN_KEY, ".*")); + String headerPattern = properties.getProperty(HEADER_PATTERN_KEY, ".*"); + headerValidator = new RegExBasedValidator(false, headerPattern); } else { headerValidator = diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/NumericValidatorFactory.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/NumericValidatorFactory.java index 281505896de..0a95611fed9 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/NumericValidatorFactory.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/NumericValidatorFactory.java @@ -22,11 +22,11 @@ import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * + * Factory for validators of numeric values. * * @author Franz-Josef Elmer */ -class NumericValidatorFactory implements IValidatorFactory +class NumericValidatorFactory extends AbstractValidatorFactory { static final String VALUE_RANGE_KEY = "value-range"; @@ -91,6 +91,11 @@ class NumericValidatorFactory implements IValidatorFactory throw new ConfigurationFailureException("Invalid maximum in range definition: " + rangeDescription); } + if (maximum < minimum) + { + throw new ConfigurationFailureException( + "Minimum is larger than maximum in range description: " + rangeDescription); + } } void assertInRange(double number) @@ -108,16 +113,18 @@ class NumericValidatorFactory implements IValidatorFactory } } - private final static class NumericValidator implements IValidator + private final static class NumericValidator extends AbstractValidator { private final Range rangeOrNull; - NumericValidator(Range rangeOrNull) + NumericValidator(boolean allowEmptyValues, Range rangeOrNull) { + super(allowEmptyValues); this.rangeOrNull = rangeOrNull; } - public void assertValid(String value) + @Override + protected void assertValidNonEmptyValue(String value) { double number = Double.parseDouble(value); if (rangeOrNull != null) @@ -132,8 +139,10 @@ class NumericValidatorFactory implements IValidatorFactory NumericValidatorFactory(Properties properties) { + super(properties); String valueRange = properties.getProperty(VALUE_RANGE_KEY); - validator = new NumericValidator(valueRange == null ? null : new Range(valueRange)); + Range rangeOrNull = valueRange == null ? null : new Range(valueRange); + validator = new NumericValidator(allowEmptyValues, rangeOrNull); } public IValidator createValidator() diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/RegExBasedValidator.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/RegExBasedValidator.java index 0b05ceeaeb0..d17c224d737 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/RegExBasedValidator.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/RegExBasedValidator.java @@ -21,25 +21,27 @@ import java.util.regex.Pattern; import ch.systemsx.cisd.common.exceptions.UserFailureException; /** - * + * Validator based on a regular expression. * * @author Franz-Josef Elmer */ -class RegExBasedValidator implements IValidator, IColumnHeaderValidator +class RegExBasedValidator extends AbstractValidator implements IColumnHeaderValidator { private final Pattern pattern; - RegExBasedValidator(String regularExpression) + RegExBasedValidator(boolean allowEmptyValues, String regularExpression) { + super(allowEmptyValues); pattern = Pattern.compile(regularExpression); } - public void assertValid(String value) + @Override + protected void assertValidNonEmptyValue(String value) { if (isValidHeader(value) == false) { throw new UserFailureException("'" + value - + "' dosn't match the following regular expression: " + pattern); + + "' doesn't match the following regular expression: " + pattern); } } diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/StringValidatorFactory.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/StringValidatorFactory.java index 5c64afb0bb1..3241e22e92c 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/StringValidatorFactory.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/StringValidatorFactory.java @@ -25,7 +25,7 @@ import ch.systemsx.cisd.common.utilities.PropertyUtils; * * @author Franz-Josef Elmer */ -class StringValidatorFactory implements IValidatorFactory +class StringValidatorFactory extends AbstractValidatorFactory { static final String VALUE_PATTERN_KEY = "value-pattern"; @@ -33,8 +33,9 @@ class StringValidatorFactory implements IValidatorFactory StringValidatorFactory(Properties properties) { + super(properties); String regex = PropertyUtils.getMandatoryProperty(properties, VALUE_PATTERN_KEY); - validator = new RegExBasedValidator(regex); + validator = new RegExBasedValidator(allowEmptyValues, regex); } public IValidator createValidator() diff --git a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/UniqueValidatorFactory.java b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/UniqueValidatorFactory.java index 8022f812693..2685e2c86b6 100644 --- a/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/UniqueValidatorFactory.java +++ b/datastore_server/source/java/ch/systemsx/cisd/etlserver/validation/UniqueValidatorFactory.java @@ -39,7 +39,7 @@ class UniqueValidatorFactory implements IValidatorFactory validator = AnyValidatorFactory.INSTANCE.createValidator(); } else { - validator = new RegExBasedValidator(regex); + validator = new RegExBasedValidator(false, regex); } } diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/NumericValidatorFactoryTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/NumericValidatorFactoryTest.java index 19c7f130fe5..42f9c19d4b6 100644 --- a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/NumericValidatorFactoryTest.java +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/NumericValidatorFactoryTest.java @@ -47,7 +47,7 @@ public class NumericValidatorFactoryTest extends AssertJUnit } @Test - public void testMissingOpeningBracket() + public void testMissingOpeningBracketInRangeDescription() { try { @@ -60,7 +60,7 @@ public class NumericValidatorFactoryTest extends AssertJUnit } @Test - public void testMissingClosingBracket() + public void testMissingClosingBracketInRangeDescription() { try { @@ -73,7 +73,7 @@ public class NumericValidatorFactoryTest extends AssertJUnit } @Test - public void testMissingComma() + public void testMissingCommaInRangeDescription() { try { @@ -85,6 +85,45 @@ public class NumericValidatorFactoryTest extends AssertJUnit } } + @Test + public void testInvalidMinimumInRangeDescription() + { + try + { + createValidator("(abc,3)"); + fail("ConfigurationFailureException expected"); + } catch (ConfigurationFailureException ex) + { + assertEquals("Invalid minimum in range definition: (abc,3)", ex.getMessage()); + } + } + + @Test + public void testInvalidMaximumInRangeDescription() + { + try + { + createValidator("(1,abc)"); + fail("ConfigurationFailureException expected"); + } catch (ConfigurationFailureException ex) + { + assertEquals("Invalid maximum in range definition: (1,abc)", ex.getMessage()); + } + } + + @Test + public void testMinLargerThanMaxInRangeDescription() + { + try + { + createValidator("(1,0.999)"); + fail("ConfigurationFailureException expected"); + } catch (ConfigurationFailureException ex) + { + assertEquals("Minimum is larger than maximum in range description: (1,0.999)", ex.getMessage()); + } + } + @Test public void testInvalidNumber() { @@ -92,8 +131,35 @@ public class NumericValidatorFactoryTest extends AssertJUnit IValidator validator = validatorFactory.createValidator(); assertNotANumber(validator, "abc"); - assertNotANumber(validator, "-0-"); - assertNotANumber(validator, ""); + assertNotANumber(validator, " -0-"); + } + + @Test + public void testEmptyValue() + { + NumericValidatorFactory validatorFactory = new NumericValidatorFactory(new Properties()); + IValidator validator = validatorFactory.createValidator(); + + assertFailingOnBlankValue(validator, null); + assertFailingOnBlankValue(validator, ""); + assertFailingOnBlankValue(validator, " "); + } + + @Test + public void testAllowEmptyValues() + { + Properties properties = new Properties(); + properties.setProperty(NumericValidatorFactory.ALLOW_EMPTY_VALUES_KEY, "true"); + properties.setProperty(NumericValidatorFactory.VALUE_RANGE_KEY, "(0,1]"); + NumericValidatorFactory validatorFactory = new NumericValidatorFactory(properties); + IValidator validator = validatorFactory.createValidator(); + + validator.assertValid(null); + validator.assertValid(""); + validator.assertValid(" "); + validator.assertValid(" 0.9999"); + assertFailingToLarge("> 1.0", validator, "1.25"); + assertFailingToSmall("<= 0.0", validator, "0.0"); } @Test @@ -144,6 +210,18 @@ public class NumericValidatorFactoryTest extends AssertJUnit return validatorFactory.createValidator(); } + private void assertFailingOnBlankValue(IValidator validator, String value) + { + try + { + validator.assertValid(value); + fail("UserFailureException expected"); + } catch (UserFailureException ex) + { + assertEquals("Empty value is not allowed.", ex.getMessage()); + } + } + private void assertNotANumber(IValidator validator, String string) { try @@ -152,7 +230,7 @@ public class NumericValidatorFactoryTest extends AssertJUnit fail("NumberFormatException expected"); } catch (NumberFormatException ex) { - AssertionUtil.assertContains(string, ex.getMessage()); + AssertionUtil.assertContains(string.trim(), ex.getMessage()); } } diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/StringValidatorFactoryTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/StringValidatorFactoryTest.java new file mode 100644 index 00000000000..5f1c06b796b --- /dev/null +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/StringValidatorFactoryTest.java @@ -0,0 +1,101 @@ +/* + * Copyright 2009 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.etlserver.validation; + +import java.util.Properties; + +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.common.exceptions.ConfigurationFailureException; +import ch.systemsx.cisd.common.exceptions.UserFailureException; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class StringValidatorFactoryTest extends AssertJUnit +{ + @Test + public void testMissingPattern() + { + try + { + new StringValidatorFactory(new Properties()); + fail("ConfigurationFailureException expected"); + } catch (ConfigurationFailureException ex) + { + assertEquals("Given key '" + StringValidatorFactory.VALUE_PATTERN_KEY + + "' not found in properties '[]'", ex.getMessage()); + } + } + + @Test + public void testEmptyValuesNotAllowed() + { + Properties properties = new Properties(); + properties.setProperty(StringValidatorFactory.VALUE_PATTERN_KEY, "a.*"); + StringValidatorFactory factory = new StringValidatorFactory(properties); + IValidator validator = factory.createValidator(); + + validator.assertValid("a"); + validator.assertValid("a1"); + validator.assertValid("abc"); + try + { + validator.assertValid("bc"); + fail("UserFailureException expected"); + } catch (UserFailureException ex) + { + assertEquals("'bc' doesn't match the following regular expression: a.*", ex.getMessage()); + } + try + { + validator.assertValid(" "); + fail("UserFailureException expected"); + } catch (UserFailureException ex) + { + assertEquals("Empty value is not allowed.", ex.getMessage()); + } + } + + @Test + public void testEmptyValuesAllowed() + { + Properties properties = new Properties(); + properties.setProperty(StringValidatorFactory.VALUE_PATTERN_KEY, "a.*"); + properties.setProperty(StringValidatorFactory.ALLOW_EMPTY_VALUES_KEY, "yes"); + StringValidatorFactory factory = new StringValidatorFactory(properties); + IValidator validator = factory.createValidator(); + + validator.assertValid("a"); + validator.assertValid("a1"); + validator.assertValid("abc"); + validator.assertValid(null); + validator.assertValid(""); + validator.assertValid(" "); + try + { + validator.assertValid("bc"); + fail("UserFailureException expected"); + } catch (UserFailureException ex) + { + assertEquals("'bc' doesn't match the following regular expression: a.*", ex.getMessage()); + } + } +} diff --git a/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/UniqueValidatorFactoryTest.java b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/UniqueValidatorFactoryTest.java new file mode 100644 index 00000000000..d62579727c9 --- /dev/null +++ b/datastore_server/sourceTest/java/ch/systemsx/cisd/etlserver/validation/UniqueValidatorFactoryTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2009 ETH Zuerich, CISD + * + * 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 ch.systemsx.cisd.etlserver.validation; + +import java.util.Properties; + +import org.testng.AssertJUnit; +import org.testng.annotations.Test; + +import ch.systemsx.cisd.common.exceptions.UserFailureException; + +/** + * + * + * @author Franz-Josef Elmer + */ +public class UniqueValidatorFactoryTest extends AssertJUnit +{ + @Test + public void testNoPattern() + { + UniqueValidatorFactory factory = new UniqueValidatorFactory(new Properties()); + IValidator validator = factory.createValidator(); + + validator.assertValid("a"); + validator.assertValid("b"); + try + { + validator.assertValid("a"); + fail("UserFailureException expected"); + } catch (UserFailureException ex) + { + assertEquals("The following value is not unique: a", ex.getMessage()); + } + } + + @Test + public void testWithPattern() + { + Properties properties = new Properties(); + properties.setProperty(StringValidatorFactory.VALUE_PATTERN_KEY, "a[0-9]*"); + UniqueValidatorFactory factory = new UniqueValidatorFactory(properties); + IValidator validator = factory.createValidator(); + + validator.assertValid("a"); + validator.assertValid("a1"); + validator.assertValid("a123"); + try + { + validator.assertValid("ab"); + fail("UserFailureException expected"); + } catch (UserFailureException ex) + { + assertEquals("'ab' doesn't match the following regular expression: a[0-9]*", ex.getMessage()); + } + } + + @Test + public void testCreateValidatorReturnsFreshValidator() + { + UniqueValidatorFactory factory = new UniqueValidatorFactory(new Properties()); + IValidator validator = factory.createValidator(); + + validator.assertValid("a"); + + validator = factory.createValidator(); + + validator.assertValid("a"); + } +} -- GitLab