/* * Copyright 2004-2005 the original author or authors. * * 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.springmodules.validation.bean; import java.util.*; import junit.framework.TestCase; import org.easymock.MockControl; import org.springframework.beans.BeanWrapper; import org.springframework.validation.Errors; import org.springframework.validation.Validator; import org.springmodules.validation.bean.conf.BeanValidationConfiguration; import org.springmodules.validation.bean.conf.CascadeValidation; import org.springmodules.validation.bean.conf.loader.BeanValidationConfigurationLoader; import org.springmodules.validation.bean.converter.ErrorCodeConverter; import org.springmodules.validation.bean.rule.ValidationRule; import org.springmodules.validation.util.condition.common.AlwaysFalseCondition; import org.springmodules.validation.util.condition.common.AlwaysTrueCondition; /** * Tests for {@link org.springmodules.validation.bean.BeanValidator}. * * @author Uri Boness */ public class BeanValidatorTests extends TestCase { private BeanValidator validator; private MockControl errorsControl; private Errors errors; private MockControl configurationControl; private BeanValidationConfiguration configuration; private MockControl ruleControl1; private ValidationRule rule1; private MockControl ruleControl2; private ValidationRule rule2; private MockControl converterControl; private ErrorCodeConverter converter; private MockControl loaderControl; private BeanValidationConfigurationLoader loader; private MockControl wrapperControl = MockControl.createControl(BeanWrapper.class); private BeanWrapper wrapper = (BeanWrapper) wrapperControl.getMock(); protected void setUp() throws Exception { converterControl = MockControl.createControl(ErrorCodeConverter.class); converter = (ErrorCodeConverter) converterControl.getMock(); loaderControl = MockControl.createControl(BeanValidationConfigurationLoader.class); loader = (BeanValidationConfigurationLoader) loaderControl.getMock(); validator = new BeanValidator(loader); validator.setErrorCodeConverter(converter); errorsControl = MockControl.createControl(Errors.class); errors = (Errors) errorsControl.getMock(); configurationControl = MockControl.createControl(BeanValidationConfiguration.class); configuration = (BeanValidationConfiguration) configurationControl.getMock(); ruleControl1 = MockControl.createControl(ValidationRule.class); rule1 = (ValidationRule) ruleControl1.getMock(); ruleControl2 = MockControl.createControl(ValidationRule.class); rule2 = (ValidationRule) ruleControl2.getMock(); wrapperControl = MockControl.createControl(BeanWrapper.class); wrapper = (BeanWrapper) wrapperControl.getMock(); } public void testSupports_WhenLoaderSupports() throws Exception { loaderControl.expectAndReturn(loader.supports(Object.class), true); replay(); assertTrue(validator.supports(Object.class)); verify(); } public void testValidateObjectGraphConstraints_WithArrayProperty() throws Exception { final Object object = new Object(); final Object[] propertyValue = new Object[0]; final Set validatedObjects = new HashSet(); // creating the bean with stub methods BeanValidator validator = new BeanValidator(loader) { protected void applyBeanValidation(BeanValidationConfiguration conf, Object obj, Errors errors) { assertSame(configuration, conf); assertSame(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } protected BeanWrapper wrapBean(Object bean) { return wrapper; } protected void validateArrayProperty(Object root, Object array, String propertyName, Errors errors, Set validatedObjs) { assertSame(object, root); assertSame(propertyValue, array); assertEquals("array", propertyName); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); } }; validator.setErrorCodeConverter(converter); // configuring the expectations of the bean wrapper that will be used to extract the array property wrapperControl.expectAndReturn(wrapper.getPropertyType("array"), Object[].class); wrapperControl.expectAndReturn(wrapper.getPropertyValue("array"), propertyValue); CascadeValidation[] cascadeValidations = new CascadeValidation[]{new CascadeValidation("array")}; configurationControl.expectAndReturn(configuration.getCascadeValidations(), cascadeValidations); loaderControl.expectAndReturn(loader.loadConfiguration(Object.class), configuration); replay(); validator.validateObjectGraphConstraints(object, object, errors, validatedObjects); assertFalse(validatedObjects.isEmpty()); assertEquals(object, validatedObjects.iterator().next()); verify(); } public void testValidateObjectGraphConstraints_WithListProperty() throws Exception { final Object object = new Object(); final List propertyValue = new ArrayList(); final Set validatedObjects = new HashSet(); // creating the bean with stub methods BeanValidator validator = new BeanValidator(loader) { protected void applyBeanValidation(BeanValidationConfiguration conf, Object obj, Errors errors) { assertSame(configuration, conf); assertSame(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } protected BeanWrapper wrapBean(Object bean) { return wrapper; } protected void validateListOrSetProperty(Object root, Collection collection, String propertyName, Errors errors, Set validatedObjs) { assertSame(object, root); assertSame(propertyValue, collection); assertEquals("list", propertyName); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); } }; validator.setErrorCodeConverter(converter); // configuring the expectations of the bean wrapper that will be used to extract the array property wrapperControl.expectAndReturn(wrapper.getPropertyType("list"), List.class); wrapperControl.expectAndReturn(wrapper.getPropertyValue("list"), propertyValue); CascadeValidation[] cascadeValidations = new CascadeValidation[]{new CascadeValidation("list")}; configurationControl.expectAndReturn(configuration.getCascadeValidations(), cascadeValidations); loaderControl.expectAndReturn(loader.loadConfiguration(Object.class), configuration); replay(); validator.validateObjectGraphConstraints(object, object, errors, validatedObjects); assertFalse(validatedObjects.isEmpty()); assertEquals(object, validatedObjects.iterator().next()); verify(); } public void testValidateObjectGraphConstraints_WithSetProperty() throws Exception { final Object object = new Object(); final Set propertyValue = new HashSet(); final Set validatedObjects = new HashSet(); // creating the bean with stub methods BeanValidator validator = new BeanValidator(loader) { protected void applyBeanValidation(BeanValidationConfiguration conf, Object obj, Errors errors) { assertSame(configuration, conf); assertSame(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } protected BeanWrapper wrapBean(Object bean) { return wrapper; } protected void validateListOrSetProperty(Object root, Collection collection, String propertyName, Errors errors, Set validatedObjs) { assertSame(object, root); assertSame(propertyValue, collection); assertEquals("set", propertyName); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); } }; validator.setErrorCodeConverter(converter); // configuring the expectations of the bean wrapper that will be used to extract the array property wrapperControl.expectAndReturn(wrapper.getPropertyType("set"), Set.class); wrapperControl.expectAndReturn(wrapper.getPropertyValue("set"), propertyValue); CascadeValidation[] cascadeValidations = new CascadeValidation[]{new CascadeValidation("set")}; configurationControl.expectAndReturn(configuration.getCascadeValidations(), cascadeValidations); loaderControl.expectAndReturn(loader.loadConfiguration(Object.class), configuration); replay(); validator.validateObjectGraphConstraints(object, object, errors, validatedObjects); assertFalse(validatedObjects.isEmpty()); assertEquals(object, validatedObjects.iterator().next()); verify(); } public void testValidateObjectGraphConstraints_WithMapProperty() throws Exception { final Object object = new Object(); final Map propertyValue = new HashMap(); final Set validatedObjects = new HashSet(); // creating the bean with stub methods BeanValidator validator = new BeanValidator(loader) { protected void applyBeanValidation(BeanValidationConfiguration conf, Object obj, Errors errors) { assertSame(configuration, conf); assertSame(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } protected BeanWrapper wrapBean(Object bean) { return wrapper; } protected void validateMapProperty(Object root, Map map, String propertyName, Errors errors, Set validatedObjs) { assertSame(object, root); assertSame(propertyValue, map); assertEquals("map", propertyName); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); } }; validator.setErrorCodeConverter(converter); // configuring the expectations of the bean wrapper that will be used to extract the array property wrapperControl.expectAndReturn(wrapper.getPropertyType("map"), Map.class); wrapperControl.expectAndReturn(wrapper.getPropertyValue("map"), propertyValue); CascadeValidation[] cascadeValidations = new CascadeValidation[]{new CascadeValidation("map")}; configurationControl.expectAndReturn(configuration.getCascadeValidations(), cascadeValidations); loaderControl.expectAndReturn(loader.loadConfiguration(Object.class), configuration); replay(); validator.validateObjectGraphConstraints(object, object, errors, validatedObjects); assertFalse(validatedObjects.isEmpty()); assertEquals(object, validatedObjects.iterator().next()); verify(); } public void testValidateObjectGraphConstraints_WithSubBeanProperty() throws Exception { final Object object = new Object(); final Object propertyValue = new Object(); final Set validatedObjects = new HashSet(); // creating the bean with stub methods BeanValidator validator = new BeanValidator(loader) { protected void applyBeanValidation(BeanValidationConfiguration conf, Object obj, Errors errors) { assertSame(configuration, conf); assertSame(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } protected BeanWrapper wrapBean(Object bean) { return wrapper; } protected void validatedSubBean(Object root, Object subBean, String propertyName, Errors errors, Set validatedObjs) { assertSame(object, root); assertSame(propertyValue, subBean); assertEquals("subBean", propertyName); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); } }; validator.setErrorCodeConverter(converter); // configuring the expectations of the bean wrapper that will be used to extract the array property wrapperControl.expectAndReturn(wrapper.getPropertyType("subBean"), Object.class); wrapperControl.expectAndReturn(wrapper.getPropertyValue("subBean"), propertyValue); CascadeValidation[] cascadeValidations = new CascadeValidation[]{new CascadeValidation("subBean")}; configurationControl.expectAndReturn(configuration.getCascadeValidations(), cascadeValidations); loaderControl.expectAndReturn(loader.loadConfiguration(Object.class), configuration); replay(); validator.validateObjectGraphConstraints(object, object, errors, validatedObjects); assertFalse(validatedObjects.isEmpty()); assertEquals(object, validatedObjects.iterator().next()); verify(); } public void testValidateArrayProperty() throws Exception { final Object root = new Object(); final Object element1 = new Object(); final Object element2 = new Object(); final Object[] array = new Object[]{element1, element2}; final Set validatedObjects = new HashSet(); BeanValidator validator = new BeanValidator(loader) { private int runCount = 0; protected void validateObjectGraphConstraints(Object rootObject, Object obj, Errors errors, Set validatedObjs) { assertSame(root, rootObject); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); switch (runCount++) { case 0: assertSame(element1, obj); break; case 1: assertSame(element2, obj); } } }; validator.setErrorCodeConverter(converter); errors.pushNestedPath("array[0]"); errors.popNestedPath(); errors.pushNestedPath("array[1]"); errors.popNestedPath(); replay(); validator.validateArrayProperty(root, array, "array", errors, validatedObjects); verify(); } public void testValidateListOrSetProperty_WithList() throws Exception { final Object root = new Object(); final Object element1 = new Object(); final Object element2 = new Object(); final List list = new ArrayList(); list.add(element1); list.add(element2); final Set validatedObjects = new HashSet(); BeanValidator validator = new BeanValidator(loader) { private int runCount = 0; protected void validateObjectGraphConstraints(Object rootObject, Object obj, Errors errors, Set validatedObjs) { assertSame(root, rootObject); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); switch (runCount++) { case 0: assertSame(element1, obj); break; case 1: assertSame(element2, obj); } } }; validator.setErrorCodeConverter(converter); errors.pushNestedPath("list[0]"); errors.popNestedPath(); errors.pushNestedPath("list[1]"); errors.popNestedPath(); replay(); validator.validateListOrSetProperty(root, list, "list", errors, validatedObjects); verify(); } public void testValidateListOrSetProperty_WithSet() throws Exception { final Object root = new Object(); final Object element1 = new Integer(1); final Object element2 = new Integer(2); final Set set = new TreeSet(); set.add(element1); set.add(element2); final Set validatedObjects = new HashSet(); BeanValidator validator = new BeanValidator(loader) { private int runCount = 0; protected void validateObjectGraphConstraints(Object rootObject, Object obj, Errors errors, Set validatedObjs) { assertSame(root, rootObject); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); switch (runCount++) { case 0: assertSame(element1, obj); break; case 1: assertSame(element2, obj); } } }; validator.setErrorCodeConverter(converter); errors.pushNestedPath("set[0]"); errors.popNestedPath(); errors.pushNestedPath("set[1]"); errors.popNestedPath(); replay(); validator.validateListOrSetProperty(root, set, "set", errors, validatedObjects); verify(); } public void testValidateMapProperty() throws Exception { final Object root = new Object(); final Object element1 = new Object(); final Object element2 = new Object(); final Map map = new HashMap(); map.put("e1", element1); map.put("e2", element2); final Set validatedObjects = new HashSet(); BeanValidator validator = new BeanValidator(loader) { protected void validateObjectGraphConstraints(Object rootObject, Object obj, Errors errors, Set validatedObjs) { assertSame(root, rootObject); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); assertTrue(element1 == obj || element2 == obj); } }; validator.setErrorCodeConverter(converter); errors.pushNestedPath("map[e1]"); errors.popNestedPath(); errors.pushNestedPath("map[e2]"); errors.popNestedPath(); replay(); validator.validateMapProperty(root, map, "map", errors, validatedObjects); verify(); } public void testValidatedSubBean() throws Exception { final Object root = new Object(); final Object subBean = new Object(); final Set validatedObjects = new HashSet(); BeanValidator validator = new BeanValidator(loader) { protected void validateObjectGraphConstraints(Object rootObject, Object obj, Errors errors, Set validatedObjs) { assertSame(root, rootObject); assertSame(BeanValidatorTests.this.errors, errors); assertSame(validatedObjects, validatedObjs); assertSame(subBean, obj); } }; validator.setErrorCodeConverter(converter); errors.pushNestedPath("bean"); errors.popNestedPath(); replay(); validator.validatedSubBean(root, subBean, "bean", errors, validatedObjects); verify(); } public void testApplyBeanValidation() throws Exception { final Object object = new Object(); BeanValidator validator = new BeanValidator(loader) { protected void applyGlobalValidationRules(BeanValidationConfiguration conf, Object obj, Errors errors) { assertSame(configuration, conf); assertSame(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } protected void applyPropertiesValidationRules(BeanValidationConfiguration conf, Object obj, Errors errors) { assertSame(configuration, conf); assertSame(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } protected void applyCustomValidator(BeanValidationConfiguration conf, Object obj, Errors errors) { assertSame(configuration, conf); assertSame(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } }; replay(); validator.applyBeanValidation(configuration, object, errors); verify(); } public void testApplyGlobalValidationRules() throws Exception { Object object = new Object(); Object[] args = new Object[0]; ruleControl1.expectAndReturn(rule1.isApplicable(object), true); ruleControl1.expectAndReturn(rule1.getCondition(), new AlwaysFalseCondition()); ruleControl1.expectAndReturn(rule1.getErrorCode(), "errorCode1"); ruleControl1.expectAndReturn(rule1.getDefaultErrorMessage(), "message1"); ruleControl1.expectAndReturn(rule1.getErrorArguments(object), args); ruleControl2.expectAndReturn(rule2.isApplicable(object), true); ruleControl2.expectAndReturn(rule2.getCondition(), new AlwaysTrueCondition()); ValidationRule[] globalRules = new ValidationRule[]{rule1, rule2}; configurationControl.expectAndReturn(configuration.getGlobalRules(), globalRules); converterControl.expectAndReturn(converter.convertGlobalErrorCode("errorCode1", Object.class), "_errorCode1"); errorsControl.expectAndReturn(errors.getNestedPath(), ""); errors.reject("_errorCode1", args, "message1"); replay(); validator.applyGlobalValidationRules(configuration, object, errors); verify(); } public void testApplyPropertiesValidationRules() throws Exception { final Object object = new Object(); final ValidationRule[] rules = new ValidationRule[]{rule1, rule2}; configurationControl.expectAndReturn(configuration.getValidatedProperties(), new String[]{"name"}); configurationControl.expectAndReturn(configuration.getPropertyRules("name"), rules); BeanValidator validator = new BeanValidator() { protected void validateAndShortCircuitRules(ValidationRule[] validationRules, String propertyName, Object obj, Errors errors) { assertSame(rules, rules); assertEquals("name", propertyName); assertEquals(object, obj); assertSame(BeanValidatorTests.this.errors, errors); } }; validator.setErrorCodeConverter(converter); replay(); validator.applyPropertiesValidationRules(configuration, object, errors); verify(); } public void testValidateAndShortCircuitRules_WhenOnlyTheSecondFails() throws Exception { Object object = new Object(); ruleControl1.expectAndReturn(rule1.isApplicable(object), true); ruleControl1.expectAndReturn(rule1.getCondition(), new AlwaysTrueCondition()); Object[] args = new Object[0]; ruleControl2.expectAndReturn(rule2.isApplicable(object), true); ruleControl2.expectAndReturn(rule2.getCondition(), new AlwaysFalseCondition()); ruleControl2.expectAndReturn(rule2.getErrorCode(), "errorCode2"); ruleControl2.expectAndReturn(rule2.getDefaultErrorMessage(), "message2"); ruleControl2.expectAndReturn(rule2.getErrorArguments(object), args); ValidationRule[] rules = new ValidationRule[]{rule1, rule2}; converterControl.expectAndReturn(converter.convertPropertyErrorCode("errorCode2", Object.class, "name"), "_errorCode2"); errors.rejectValue("name", "_errorCode2", args, "message2"); replay(); validator.validateAndShortCircuitRules(rules, "name", object, errors); verify(); } public void testValidateAndShortCircuitRules_WhenTheFirstFails() throws Exception { Object object = new Object(); Object[] args = new Object[0]; ruleControl1.expectAndReturn(rule1.isApplicable(object), true); ruleControl1.expectAndReturn(rule1.getCondition(), new AlwaysFalseCondition()); ruleControl1.expectAndReturn(rule1.getErrorCode(), "errorCode1"); ruleControl1.expectAndReturn(rule1.getDefaultErrorMessage(), "message1"); ruleControl1.expectAndReturn(rule1.getErrorArguments(object), args); ValidationRule[] rules = new ValidationRule[]{rule1, rule2}; converterControl.expectAndReturn(converter.convertPropertyErrorCode("errorCode1", Object.class, "name"), "_errorCode1"); errors.rejectValue("name", "_errorCode1", args, "message1"); replay(); validator.validateAndShortCircuitRules(rules, "name", object, errors); verify(); } public void testValidateAndShortCircuitRules_WhenNoneFail() throws Exception { Object object = new Object(); ruleControl1.expectAndReturn(rule1.isApplicable(object), true); ruleControl1.expectAndReturn(rule1.getCondition(), new AlwaysTrueCondition()); ruleControl2.expectAndReturn(rule2.isApplicable(object), true); ruleControl2.expectAndReturn(rule2.getCondition(), new AlwaysTrueCondition()); ValidationRule[] rules = new ValidationRule[]{rule1, rule2}; replay(); validator.validateAndShortCircuitRules(rules, "name", object, errors); verify(); } public void testApplyCustomValidator() throws Exception { Object object = new Object(); MockControl customValidatorControl = MockControl.createControl(Validator.class); Validator customValidator = (Validator) customValidatorControl.getMock(); customValidator.validate(object, errors); configurationControl.expectAndReturn(configuration.getCustomValidator(), customValidator); replay(); validator.applyCustomValidator(configuration, object, errors); verify(); } public void testApplyCustomValidator_WhenThereIsNoCustomValidator() throws Exception { Object object = new Object(); configurationControl.expectAndReturn(configuration.getCustomValidator(), null); replay(); validator.applyCustomValidator(configuration, object, errors); verify(); } //=============================================== Helper Methods =================================================== protected void replay() { ruleControl1.replay(); ruleControl2.replay(); configurationControl.replay(); errorsControl.replay(); converterControl.replay(); loaderControl.replay(); wrapperControl.replay(); } protected void verify() { ruleControl1.verify(); ruleControl2.verify(); configurationControl.verify(); errorsControl.verify(); converterControl.verify(); loaderControl.verify(); wrapperControl.verify(); } }