/** * Copyright (C) 2015 Valkyrie RCP * * 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.valkyriercp.binding.form.support; import org.junit.Test; import org.springframework.binding.convert.ConversionExecutionException; import org.springframework.binding.convert.converters.Converter; import org.springframework.binding.convert.service.StaticConversionExecutor; import org.valkyriercp.binding.form.BindingErrorMessageProvider; import org.valkyriercp.binding.form.FormModel; import org.valkyriercp.binding.form.ValidatingFormModel; import org.valkyriercp.binding.support.BeanPropertyAccessStrategy; import org.valkyriercp.binding.validation.ValidationMessage; import org.valkyriercp.binding.validation.ValidationResults; import org.valkyriercp.binding.validation.ValidationResultsModel; import org.valkyriercp.binding.validation.Validator; import org.valkyriercp.binding.validation.support.DefaultValidationMessage; import org.valkyriercp.binding.validation.support.DefaultValidationResults; import org.valkyriercp.binding.value.ValueModel; import org.valkyriercp.binding.value.support.ValueHolder; import org.valkyriercp.core.Severity; import org.valkyriercp.test.TestBean; import org.valkyriercp.test.TestPropertyChangeListener; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * Tests for @link DefaultFormModel * * @author Oliver Hutchison */ public class DefaultFormModelTests extends AbstractFormModelTests { protected AbstractFormModel getFormModel(Object formObject) { return new TestDefaultFormModel(formObject); } protected AbstractFormModel getFormModel(BeanPropertyAccessStrategy pas, boolean buffering) { return new TestDefaultFormModel(pas, buffering); } @Test public void testPropertyChangeCausesValidation() { DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); TestValidator v = new TestValidator(); fm.setValidator(v); TestConversionService cs = new TestConversionService(); cs.executer = new StaticConversionExecutor(String.class, String.class, new CopiedPublicNoOpConverter(String.class, String.class)); fm.setConversionService(cs); ValueModel vm = fm.getValueModel("simpleProperty"); // starting at 2: constructing a formmodel + creating valueModel int expectedCount = 2; assertEquals(expectedCount++, v.count); vm.setValue("1"); assertEquals(expectedCount, v.count); // no change in value, no validation triggered. vm.setValue("1"); assertEquals(expectedCount++, v.count); vm.setValue(null); assertEquals(expectedCount++, v.count); vm = fm.getValueModel("simpleProperty", Integer.class); vm.setValue("1"); assertEquals(expectedCount++, v.count); vm.setValue("2"); assertEquals(expectedCount++, v.count); } @Test public void testValidationMessages() { DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); ValidationResultsModel r = fm.getValidationResults(); TestValidator v = new TestValidator(); fm.setValidator(v); ValueModel vm = fm.getValueModel("simpleProperty"); // starting at 2: constructing a formmodel + creating valueModel int expectedCount = 2; assertEquals(expectedCount++, v.count); assertEquals(0, r.getMessageCount()); v.results = getValidationResults("message1"); vm.setValue("1"); assertEquals(expectedCount++, v.count); assertEquals(1, r.getMessageCount()); assertContainsMessage("message1", r.getMessages()); v.results = getValidationResults("message2"); vm.setValue("2"); assertEquals(expectedCount, v.count); assertEquals(1, r.getMessageCount()); assertContainsMessage("message2", r.getMessages()); // this will cause a binding exception vm.setValue(new Object()); assertEquals(expectedCount++, v.count); assertEquals(2, r.getMessageCount()); assertContainsMessage("message2", r.getMessages()); // this will clear the binding exception vm.setValue("3"); assertEquals(expectedCount++, v.count); assertEquals(1, r.getMessageCount()); assertContainsMessage("message2", r.getMessages()); fm.validate(); assertEquals(expectedCount++, v.count); assertEquals(1, r.getMessageCount()); assertContainsMessage("message2", r.getMessages()); } @Test public void testRaiseClearValidationMessage() { DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); ValidationResultsModel r = fm.getValidationResults(); TestValidator v = new TestValidator(); fm.setValidator(v); ValueModel vm = fm.getValueModel("simpleProperty"); // starting at 2: constructing a formmodel + creating valueModel int expectedCount = 2; final DefaultValidationMessage message1 = new DefaultValidationMessage("simpleProperty", Severity.ERROR, "1"); fm.raiseValidationMessage(message1); assertEquals(expectedCount++, v.count); assertEquals(1, r.getMessageCount()); assertContainsMessage("1", r.getMessages()); fm.clearValidationMessage(message1); assertEquals(0, r.getMessageCount()); fm.raiseValidationMessage(message1); fm.setValidating(false); assertEquals(0, r.getMessageCount()); fm.setValidating(true); assertEquals(expectedCount++, v.count); assertEquals(1, r.getMessageCount()); v.results = getValidationResults("2"); vm.setValue("3"); assertEquals(expectedCount++, v.count); assertEquals(2, r.getMessageCount()); fm.clearValidationMessage(message1); assertEquals(1, r.getMessageCount()); } @Test public void testChangingValidatingClearsMessagesOrValidates() { DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); ValidationResultsModel r = fm.getValidationResults(); TestValidator v = new TestValidator(); // starting at 2: constructing a formmodel + creating valueModel int expectedCount = 2; v.results = getValidationResults("message1"); fm.setValidator(v); ValueModel vm = fm.getValueModel("simpleProperty"); assertEquals(expectedCount, v.count); assertEquals(1, r.getMessageCount()); fm.setValidating(false); assertEquals(expectedCount++, v.count); assertEquals(0, r.getMessageCount()); fm.setValidating(true); assertEquals(expectedCount, v.count); assertEquals(1, r.getMessageCount()); // this will cause a binding exception vm.setValue(new Object()); assertEquals(expectedCount, v.count); assertEquals(2, r.getMessageCount()); fm.setValidating(false); assertEquals(expectedCount, v.count); assertEquals(0, r.getMessageCount()); // this will cause a another binding exception fm.getValueModel("listProperty").setValue(new Object()); assertEquals(expectedCount, v.count); assertEquals(0, r.getMessageCount()); vm.setValue("test"); assertEquals(expectedCount++, v.count); assertEquals(0, r.getMessageCount()); fm.setValidating(true); assertEquals(expectedCount++, v.count); assertEquals(2, r.getMessageCount()); } @Test public void testSetThrowsExceptionRaisesValidationMessage() { final ErrorBean errorBean = new ErrorBean(); DefaultFormModel fm = (DefaultFormModel) getFormModel(errorBean); final ValueModel vm = fm.getValueModel("error"); vm.setValue("test"); assertEquals(1, fm.getValidationResults().getMessageCount()); errorBean.errorToThrow = null; vm.setValue("test"); assertEquals(0, fm.getValidationResults().getMessageCount()); } @Test public void testTypeConversionThrowsExceptionRaisesValidationMessage() { DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); TestConversionService cs = new TestConversionService(); cs.executer = new StaticConversionExecutor(String.class, Integer.class, new ExceptionConverter(String.class, Integer.class)); fm.setConversionService(cs); final ValueModel vm = fm.getValueModel("simpleProperty", Integer.class); vm.setValue("test"); assertEquals(1, fm.getValidationResults().getMessageCount()); } @Test public void testValidatingEvents() { TestPropertyChangeListener pcl = new TestPropertyChangeListener(ValidatingFormModel.VALIDATING_PROPERTY); DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); fm.addPropertyChangeListener(ValidatingFormModel.VALIDATING_PROPERTY, pcl); assertTrue(fm.isEnabled()); fm.setValidating(false); assertTrue(!fm.isValidating()); assertEquals(1, pcl.eventCount()); fm.setValidating(false); assertTrue(!fm.isValidating()); assertEquals(1, pcl.eventCount()); fm.setValidating(true); assertTrue(fm.isValidating()); assertEquals(2, pcl.eventCount()); fm.setEnabled(true); assertTrue(fm.isValidating()); assertEquals(2, pcl.eventCount()); } @Test public void testReadOnlyRevert() { FormModel fm = getFormModel(new TestBean()); fm.getValueModel("readOnly"); fm.revert(); // no additional asserts, this test should just not throw an exception! } @Test public void testDefaultFormModelFromValueModel() throws Exception { TestBean testBean = new TestBean(); ValueModel valueModel = new ValueHolder(testBean); DefaultFormModel model = new DefaultFormModel(valueModel); assertEquals(testBean, model.getFormObject()); } private DefaultValidationResults getValidationResults(String message) { DefaultValidationResults res = new DefaultValidationResults(); res.addMessage("simpleProperty", Severity.ERROR, message); return res; } private void assertContainsMessage(String message, Set messages) { assertTrue("Set of messages does not contain expected message '" + message + "'", messages .contains(new DefaultValidationMessage("simpleProperty", Severity.ERROR, message))); } public static class TestValidator implements Validator { public ValidationResults results = new DefaultValidationResults(); public int count; public ValidationResults validate(Object object) { count++; return results; } } public class ErrorBean { public RuntimeException errorToThrow = new UnsupportedOperationException(); public Object getError() { return null; } public void setError(Object error) { if (errorToThrow != null) { throw errorToThrow; } } } private static class TestDefaultFormModel extends DefaultFormModel { public TestDefaultFormModel(Object bean) { super(bean, false); } public TestDefaultFormModel(BeanPropertyAccessStrategy pas, boolean buffering) { super(pas, buffering); } public void init() { super.init(); setValidator(new TestValidator()); setBindingErrorMessageProvider(new BindingErrorMessageProvider() { public ValidationMessage getErrorMessage(FormModel formModel, String propertyName, Object valueBeingSet, Exception e) { return new DefaultValidationMessage(propertyName, Severity.ERROR, ""); } }); } } private static class ExceptionConverter implements Converter { private final Class sourceClass; private final Class targetClass; public ExceptionConverter(Class sourceClass, Class targetClass) { this.sourceClass = sourceClass; this.targetClass = targetClass; } @Override public Class getSourceClass() { return sourceClass; } @Override public Class getTargetClass() { return targetClass; } @Override public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception { throw new ConversionExecutionException(source, sourceClass, targetClass, "test"); } } }