001 /* 002 * Copyright 2002-2004 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.binding.form.support; 017 018 import org.springframework.binding.convert.ConversionContext; 019 import org.springframework.binding.convert.ConversionException; 020 import org.springframework.binding.convert.ConversionExecutor; 021 import org.springframework.binding.convert.Converter; 022 import org.springframework.binding.form.BindingErrorMessageProvider; 023 import org.springframework.binding.form.FormModel; 024 import org.springframework.binding.form.ValidatingFormModel; 025 import org.springframework.binding.support.BeanPropertyAccessStrategy; 026 import org.springframework.binding.support.TestBean; 027 import org.springframework.binding.support.TestPropertyChangeListener; 028 import org.springframework.binding.validation.ValidationMessage; 029 import org.springframework.binding.validation.ValidationResults; 030 import org.springframework.binding.validation.ValidationResultsModel; 031 import org.springframework.binding.validation.Validator; 032 import org.springframework.binding.validation.support.DefaultValidationMessage; 033 import org.springframework.binding.validation.support.DefaultValidationResults; 034 import org.springframework.binding.value.ValueModel; 035 import org.springframework.binding.value.support.ValueHolder; 036 import org.springframework.richclient.core.Severity; 037 038 import java.util.Set; 039 040 /** 041 * Tests for @link DefaultFormModel 042 * 043 * @author Oliver Hutchison 044 */ 045 public class DefaultFormModelTests extends AbstractFormModelTests { 046 047 protected AbstractFormModel getFormModel(Object formObject) { 048 return new TestDefaultFormModel(formObject); 049 } 050 051 protected AbstractFormModel getFormModel(BeanPropertyAccessStrategy pas, boolean buffering) { 052 return new TestDefaultFormModel(pas, buffering); 053 } 054 055 public void testPropertyChangeCausesValidation() { 056 DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); 057 TestValidator v = new TestValidator(); 058 fm.setValidator(v); 059 TestConversionService cs = new TestConversionService(); 060 cs.executer = new ConversionExecutor(String.class, String.class, new CopiedPublicNoOpConverter(String.class, String.class)); 061 fm.setConversionService(cs); 062 ValueModel vm = fm.getValueModel("simpleProperty"); 063 // starting at 2: constructing a formmodel + creating valueModel 064 int expectedCount = 2; 065 assertEquals(expectedCount++, v.count); 066 067 vm.setValue("1"); 068 assertEquals(expectedCount, v.count); 069 070 // no change in value, no validation triggered. 071 vm.setValue("1"); 072 assertEquals(expectedCount++, v.count); 073 074 vm.setValue(null); 075 assertEquals(expectedCount++, v.count); 076 077 vm = fm.getValueModel("simpleProperty", Integer.class); 078 vm.setValue("1"); 079 assertEquals(expectedCount++, v.count); 080 081 vm.setValue("2"); 082 assertEquals(expectedCount++, v.count); 083 } 084 085 public void testValidationMessages() { 086 DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); 087 ValidationResultsModel r = fm.getValidationResults(); 088 TestValidator v = new TestValidator(); 089 fm.setValidator(v); 090 ValueModel vm = fm.getValueModel("simpleProperty"); 091 // starting at 2: constructing a formmodel + creating valueModel 092 int expectedCount = 2; 093 094 assertEquals(expectedCount++, v.count); 095 assertEquals(0, r.getMessageCount()); 096 097 v.results = getValidationResults("message1"); 098 vm.setValue("1"); 099 assertEquals(expectedCount++, v.count); 100 assertEquals(1, r.getMessageCount()); 101 assertContainsMessage("message1", r.getMessages()); 102 103 v.results = getValidationResults("message2"); 104 vm.setValue("2"); 105 assertEquals(expectedCount, v.count); 106 assertEquals(1, r.getMessageCount()); 107 assertContainsMessage("message2", r.getMessages()); 108 // this will cause a binding exception 109 vm.setValue(new Object()); 110 assertEquals(expectedCount++, v.count); 111 assertEquals(2, r.getMessageCount()); 112 assertContainsMessage("message2", r.getMessages()); 113 114 // this will clear the binding exception 115 vm.setValue("3"); 116 assertEquals(expectedCount++, v.count); 117 assertEquals(1, r.getMessageCount()); 118 assertContainsMessage("message2", r.getMessages()); 119 120 fm.validate(); 121 assertEquals(expectedCount++, v.count); 122 assertEquals(1, r.getMessageCount()); 123 assertContainsMessage("message2", r.getMessages()); 124 } 125 126 public void testRaiseClearValidationMessage() { 127 DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); 128 ValidationResultsModel r = fm.getValidationResults(); 129 TestValidator v = new TestValidator(); 130 fm.setValidator(v); 131 ValueModel vm = fm.getValueModel("simpleProperty"); 132 // starting at 2: constructing a formmodel + creating valueModel 133 int expectedCount = 2; 134 135 final DefaultValidationMessage message1 = new DefaultValidationMessage("simpleProperty", Severity.ERROR, "1"); 136 137 fm.raiseValidationMessage(message1); 138 assertEquals(expectedCount++, v.count); 139 assertEquals(1, r.getMessageCount()); 140 assertContainsMessage("1", r.getMessages()); 141 142 fm.clearValidationMessage(message1); 143 assertEquals(0, r.getMessageCount()); 144 145 fm.raiseValidationMessage(message1); 146 fm.setValidating(false); 147 assertEquals(0, r.getMessageCount()); 148 149 fm.setValidating(true); 150 assertEquals(expectedCount++, v.count); 151 assertEquals(1, r.getMessageCount()); 152 153 v.results = getValidationResults("2"); 154 vm.setValue("3"); 155 assertEquals(expectedCount++, v.count); 156 assertEquals(2, r.getMessageCount()); 157 158 fm.clearValidationMessage(message1); 159 assertEquals(1, r.getMessageCount()); 160 } 161 162 public void testChangingValidatingClearsMessagesOrValidates() { 163 DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); 164 ValidationResultsModel r = fm.getValidationResults(); 165 TestValidator v = new TestValidator(); 166 // starting at 2: constructing a formmodel + creating valueModel 167 int expectedCount = 2; 168 v.results = getValidationResults("message1"); 169 fm.setValidator(v); 170 171 ValueModel vm = fm.getValueModel("simpleProperty"); 172 assertEquals(expectedCount, v.count); 173 assertEquals(1, r.getMessageCount()); 174 175 fm.setValidating(false); 176 assertEquals(expectedCount++, v.count); 177 assertEquals(0, r.getMessageCount()); 178 179 fm.setValidating(true); 180 assertEquals(expectedCount, v.count); 181 assertEquals(1, r.getMessageCount()); 182 183 // this will cause a binding exception 184 vm.setValue(new Object()); 185 assertEquals(expectedCount, v.count); 186 assertEquals(2, r.getMessageCount()); 187 188 fm.setValidating(false); 189 assertEquals(expectedCount, v.count); 190 assertEquals(0, r.getMessageCount()); 191 192 // this will cause a another binding exception 193 fm.getValueModel("listProperty").setValue(new Object()); 194 assertEquals(expectedCount, v.count); 195 assertEquals(0, r.getMessageCount()); 196 197 vm.setValue("test"); 198 assertEquals(expectedCount++, v.count); 199 assertEquals(0, r.getMessageCount()); 200 201 fm.setValidating(true); 202 assertEquals(expectedCount++, v.count); 203 assertEquals(2, r.getMessageCount()); 204 } 205 206 public void testSetThrowsExceptionRaisesValidationMessage() { 207 final ErrorBean errorBean = new ErrorBean(); 208 DefaultFormModel fm = (DefaultFormModel) getFormModel(errorBean); 209 final ValueModel vm = fm.getValueModel("error"); 210 211 vm.setValue("test"); 212 assertEquals(1, fm.getValidationResults().getMessageCount()); 213 214 errorBean.errorToThrow = null; 215 vm.setValue("test"); 216 assertEquals(0, fm.getValidationResults().getMessageCount()); 217 } 218 219 public void testTypeConversionThrowsExceptionRaisesValidationMessage() { 220 DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); 221 TestConversionService cs = new TestConversionService(); 222 cs.executer = new ConversionExecutor(String.class, Integer.class, new ExceptionConverter(String.class, 223 Integer.class)); 224 fm.setConversionService(cs); 225 final ValueModel vm = fm.getValueModel("simpleProperty", Integer.class); 226 227 vm.setValue("test"); 228 assertEquals(1, fm.getValidationResults().getMessageCount()); 229 } 230 231 public void testValidatingEvents() { 232 TestPropertyChangeListener pcl = new TestPropertyChangeListener(ValidatingFormModel.VALIDATING_PROPERTY); 233 DefaultFormModel fm = (DefaultFormModel) getFormModel(new TestBean()); 234 fm.addPropertyChangeListener(ValidatingFormModel.VALIDATING_PROPERTY, pcl); 235 assertTrue(fm.isEnabled()); 236 237 fm.setValidating(false); 238 assertTrue(!fm.isValidating()); 239 assertEquals(1, pcl.eventCount()); 240 241 fm.setValidating(false); 242 assertTrue(!fm.isValidating()); 243 assertEquals(1, pcl.eventCount()); 244 245 fm.setValidating(true); 246 assertTrue(fm.isValidating()); 247 assertEquals(2, pcl.eventCount()); 248 249 fm.setEnabled(true); 250 assertTrue(fm.isValidating()); 251 assertEquals(2, pcl.eventCount()); 252 } 253 254 public void testReadOnlyRevert() { 255 FormModel fm = getFormModel(new TestBean()); 256 fm.getValueModel("readOnly"); 257 fm.revert(); 258 259 // no additional asserts, this test should just not throw an exception! 260 } 261 262 public void testDefaultFormModelFromValueModel() throws Exception { 263 TestBean testBean = new TestBean(); 264 ValueModel valueModel = new ValueHolder(testBean); 265 DefaultFormModel model = new DefaultFormModel(valueModel); 266 assertEquals(testBean, model.getFormObject()); 267 } 268 269 private DefaultValidationResults getValidationResults(String message) { 270 DefaultValidationResults res = new DefaultValidationResults(); 271 res.addMessage("simpleProperty", Severity.ERROR, message); 272 return res; 273 } 274 275 private void assertContainsMessage(String message, Set messages) { 276 assertTrue("Set of messages does not contain expected message '" + message + "'", messages 277 .contains(new DefaultValidationMessage("simpleProperty", Severity.ERROR, message))); 278 } 279 280 public static class TestValidator implements Validator { 281 282 public ValidationResults results = new DefaultValidationResults(); 283 284 public int count; 285 286 public ValidationResults validate(Object object) { 287 count++; 288 return results; 289 } 290 } 291 292 public class ErrorBean { 293 public RuntimeException errorToThrow = new UnsupportedOperationException(); 294 295 public Object getError() { 296 return null; 297 } 298 299 public void setError(Object error) { 300 if (errorToThrow != null) { 301 throw errorToThrow; 302 } 303 } 304 } 305 306 private static class TestDefaultFormModel extends DefaultFormModel { 307 public TestDefaultFormModel(Object bean) { 308 super(bean, false); 309 } 310 311 public TestDefaultFormModel(BeanPropertyAccessStrategy pas, boolean buffering) { 312 super(pas, buffering); 313 } 314 315 public void init() { 316 super.init(); 317 setValidator(new TestValidator()); 318 setBindingErrorMessageProvider(new BindingErrorMessageProvider() { 319 320 public ValidationMessage getErrorMessage(FormModel formModel, String propertyName, 321 Object valueBeingSet, Exception e) { 322 return new DefaultValidationMessage(propertyName, Severity.ERROR, ""); 323 } 324 325 }); 326 } 327 } 328 329 private static class ExceptionConverter implements Converter { 330 331 private final Class sourceClass; 332 333 private final Class targetClass; 334 335 public ExceptionConverter(Class sourceClass, Class targetClass) { 336 this.sourceClass = sourceClass; 337 this.targetClass = targetClass; 338 } 339 340 public Object convert(Object source, Class targetClass, ConversionContext context) throws ConversionException { 341 throw new ConversionException("test", targetClass); 342 } 343 344 public Class[] getSourceClasses() { 345 return new Class[] { sourceClass }; 346 } 347 348 public Class[] getTargetClasses() { 349 return new Class[] { targetClass }; 350 } 351 352 } 353 }