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 }