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    }