001    // Copyright 2005, 2006 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.form.validator;
016    
017    import org.apache.hivemind.ApplicationRuntimeException;
018    import org.apache.tapestry.IBeanProvider;
019    import org.apache.tapestry.IComponent;
020    import org.apache.tapestry.form.IFormComponent;
021    import org.apache.tapestry.form.ValidationMessages;
022    import org.apache.tapestry.junit.TapestryTestCase;
023    import static org.easymock.EasyMock.checkOrder;
024    import static org.easymock.EasyMock.expect;
025    import org.testng.annotations.Test;
026    
027    import java.util.Collections;
028    import java.util.HashMap;
029    import java.util.List;
030    import java.util.Map;
031    
032    /**
033     * Tests for {@link org.apache.tapestry.form.validator.ValidatorFactoryImpl}.
034     * 
035     * @author Howard Lewis Ship
036     * @since 4.0
037     */
038    @Test
039    public class TestValidatorFactory extends TapestryTestCase
040    {
041    
042        private Map buildContributions(String name, boolean configurable)
043        {
044            ValidatorContribution vc = newContribution(configurable, ValidatorFixture.class);
045    
046            return Collections.singletonMap(name, vc);
047        }
048    
049        private ValidatorContribution newContribution(boolean configurable, Class validatorClass)
050        {
051            ValidatorContribution vc = new ValidatorContribution();
052            vc.setConfigurable(configurable);
053            vc.setValidatorClass(validatorClass);
054    
055            return vc;
056        }
057    
058        public void test_Empty()
059        {
060            IComponent component = newComponent();
061            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
062    
063            replay();
064    
065            List result = vf.constructValidatorList(component, "");
066    
067            assertTrue(result.isEmpty());
068    
069            verify();
070        }
071    
072        public void test_Single()
073        {
074            IComponent component = newComponent();
075    
076            replay();
077    
078            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
079            vf.setValidators(buildContributions("value", true));
080    
081            List result = vf.constructValidatorList(component, "value=foo");
082    
083            ValidatorFixture fixture = (ValidatorFixture) result.get(0);
084    
085            assertEquals("foo", fixture.getValue());
086    
087            verify();
088        }
089    
090        public void test_Message()
091        {
092            IComponent component = newComponent();
093    
094            replay();
095    
096            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
097            vf.setValidators(buildContributions("fred", false));
098    
099            List result = vf.constructValidatorList(component, "fred[fred's message]");
100    
101            ValidatorFixture fixture = (ValidatorFixture) result.get(0);
102    
103            assertEquals("fred's message", fixture.getMessage());
104    
105            verify();
106        }
107    
108        public void test_Localized_Message()
109        {
110            IComponent component = newComponent();
111    
112            replay();
113    
114            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
115            vf.setValidators(buildContributions("value", true));
116    
117            List result = vf.constructValidatorList(component, "value=199.9999999999999[%defaultProb-interestRate]");
118    
119            ValidatorFixture fixture = (ValidatorFixture) result.get(0);
120    
121            assertEquals(fixture.getMessage(), "%defaultProb-interestRate");
122    
123            verify();
124        }
125    
126        public void test_Configure_And_Message()
127        {
128            IComponent component = newComponent();
129    
130            replay();
131    
132            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
133            vf.setValidators(buildContributions("value", true));
134    
135            List result = vf.constructValidatorList(component, "value=biff[fred's message]");
136    
137            ValidatorFixture fixture = (ValidatorFixture) result.get(0);
138    
139            assertEquals(fixture.getValue(), "biff");
140            assertEquals(fixture.getMessage(), "fred's message");
141    
142            verify();
143        }
144    
145        public void test_Missing_Configuration()
146        {
147            IComponent component = newComponent();
148    
149            replay();
150    
151            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
152            vf.setValidators(buildContributions("fred", true));
153    
154            try
155            {
156                vf.constructValidatorList(component, "fred");
157                unreachable();
158            }
159            catch (ApplicationRuntimeException ex)
160            {
161                assertEquals("Validator 'name' must be configured in order to be used. "
162                        + "The value is configured by changing 'name' to 'name=value'.", ex.getMessage());
163            }
164    
165            verify();
166        }
167    
168        public void test_Multiple()
169        {
170            IComponent component = newComponent();
171    
172            replay();
173    
174            Map map = new HashMap();
175            map.put("required", newContribution(false, Required.class));
176            map.put("email", newContribution(false, Email.class));
177            map.put("minLength", newContribution(true, MinLength.class));
178    
179            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
180            vf.setValidators(map);
181    
182            List result = vf.constructValidatorList(component,
183                    "required[EMail is required],email,minLength=10[EMail must be at least ten characters long]");
184    
185            assertEquals(3, result.size());
186    
187            Required r = (Required) result.get(0);
188            assertEquals("EMail is required", r.getMessage());
189    
190            assertTrue(result.get(1) instanceof Email);
191    
192            MinLength minLength = (MinLength) result.get(2);
193    
194            assertEquals(10, minLength.getMinLength());
195            assertEquals("EMail must be at least ten characters long", minLength.getMessage());
196    
197            verify();
198        }
199    
200        public void test_Multiple_Localized()
201        {
202            IComponent component = newComponent();
203    
204            replay();
205    
206            Map map = new HashMap();
207            map.put("required", newContribution(false, Required.class));
208            map.put("min", newContribution(true, Min.class));
209            map.put("max", newContribution(true, Max.class));
210    
211            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
212            vf.setValidators(map);
213    
214            List result = vf.constructValidatorList(component,
215                    "required,min=0.000000000001[%defaultProbInterestRate],\n" +
216                    "max=199.9999999999999[%defaultProb-interestRate]");
217    
218            assertEquals(3, result.size());
219    
220            Required r = (Required) result.get(0);
221            assert r.getMessage() == null;
222            assert r.isRequired();
223    
224            Min min = (Min) result.get(1);
225            assertEquals(min.getMessage(), "%defaultProbInterestRate");
226            assertEquals(min.getMin(), 0.000000000001);
227    
228            Max max = (Max) result.get(2);
229            assertEquals(max.getMessage(), "%defaultProb-interestRate");
230            assertEquals(max.getMax(), 199.9999999999999);
231           
232            verify();
233        }
234    
235        public void test_Unparseable()
236        {
237            IComponent component = newComponent();
238    
239            replay();
240    
241            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
242            vf.setValidators(buildContributions("fred", false));
243    
244            try
245            {
246                vf.constructValidatorList(component, "fred,=foo");
247            }
248            catch (ApplicationRuntimeException ex)
249            {
250                assertEquals("Unable to parse 'fred,=foo' into a list of validators.", ex.getMessage());
251            }
252    
253            verify();
254        }
255    
256        public void test_Unwanted_Configuration()
257        {
258            IComponent component = newComponent();
259    
260            replay();
261    
262            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
263            vf.setValidators(buildContributions("fred", false));
264    
265            try
266            {
267                vf.constructValidatorList(component, "fred=biff");
268                unreachable();
269            }
270            catch (ApplicationRuntimeException ex)
271            {
272                assertEquals("Validator 'fred' is not configurable, " + "'fred=biff' should be changed to just 'fred'.", ex
273                        .getMessage());
274            }
275    
276            verify();
277        }
278    
279        public void test_Missing_Validator()
280        {
281            IComponent component = newComponent();
282    
283            replay();
284    
285            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
286            vf.setValidators(Collections.EMPTY_MAP);
287    
288            try
289            {
290                vf.constructValidatorList(component, "missing");
291                unreachable();
292            }
293            catch (ApplicationRuntimeException ex)
294            {
295                assertEquals("No validator named 'missing' has been defined.", ex.getMessage());
296            }
297    
298            verify();
299        }
300    
301        public void test_Instantiate_Failure()
302        {
303            IComponent component = newComponent();
304    
305            replay();
306    
307            Map map = new HashMap();
308    
309            map.put("fred", newContribution(false, Object.class));
310    
311            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
312            vf.setValidators(map);
313    
314            try
315            {
316                vf.constructValidatorList(component, "fred");
317                unreachable();
318            }
319            catch (ApplicationRuntimeException ex)
320            {
321                assertTrue(ex.getMessage().startsWith(
322                        "Error initializing validator 'fred' (class java.lang.Object): java.lang.Object"));
323            }
324    
325            verify();
326        }
327    
328        private Validator newValidator()
329        {
330            return newMock(Validator.class);
331        }
332    
333        private IBeanProvider newBeanProvider(String beanName, Object bean)
334        {
335            IBeanProvider provider = newMock(IBeanProvider.class);
336            checkOrder(provider, false);
337            
338            expect(provider.getBean(beanName)).andReturn(bean);
339    
340            return provider;
341        }
342    
343        private IComponent newComponent(IBeanProvider provider)
344        {
345            IComponent component = newComponent();
346    
347            expect(component.getBeans()).andReturn(provider);
348    
349            return component;
350        }
351    
352        public void test_Bean_Reference()
353            throws Exception
354        {
355            Validator validator = newValidator();
356            IBeanProvider provider = newBeanProvider("fred", validator);
357            IComponent component = newComponent(provider);
358    
359            IFormComponent field = newField();
360            ValidationMessages messages = newMessages();
361            Object value = new Object();
362    
363            validator.validate(field, messages, value);
364    
365            replay();
366    
367            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
368            vf.setValidators(Collections.EMPTY_MAP);
369    
370            List validators = vf.constructValidatorList(component, "$fred");
371    
372            assertEquals(1, validators.size());
373    
374            Validator wrapper = (Validator) validators.get(0);
375    
376            wrapper.validate(field, messages, value);
377    
378            verify();
379        }
380    
381        private ValidationMessages newMessages()
382        {
383            return newMock(ValidationMessages.class);
384        }
385    
386        private IFormComponent newField()
387        {
388            return newMock(IFormComponent.class);
389        }
390    
391        public void test_Bean_Reference_Not_Validator()
392        {
393            Object bean = new Object();
394            IBeanProvider provider = newBeanProvider("fred", bean);
395            IComponent component = newComponent(provider);
396    
397            replay();
398    
399            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
400            vf.setValidators(Collections.EMPTY_MAP);
401    
402            try
403            {
404                List l = vf.constructValidatorList(component, "$fred");
405    
406                Validator wrapper = (Validator) l.get(0);
407    
408                wrapper.getAcceptsNull();
409    
410                unreachable();
411            }
412            catch (ApplicationRuntimeException ex)
413            {
414                assertEquals("Bean 'fred' does not implement the org.apache.tapestry.form.validator.Validator interface.",
415                        ex.getMessage());
416                assertSame(bean, ex.getComponent());
417            }
418    
419            verify();
420        }
421    
422        public void test_Bean_Reference_With_Value()
423        {
424            IComponent component = newComponent();
425    
426            replay();
427    
428            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
429            vf.setValidators(Collections.EMPTY_MAP);
430    
431            try
432            {
433                vf.constructValidatorList(component, "$fred=10");
434                unreachable();
435            }
436            catch (ApplicationRuntimeException ex)
437            {
438                assertEquals(
439                        "Validator 'fred' is a reference to a managed bean of the component, and may not have a value or a message override specified.",
440                        ex.getMessage());
441            }
442    
443            verify();
444        }
445    
446        public void test_Bean_Reference_With_Message()
447        {
448            IComponent component = newComponent();
449    
450            replay();
451    
452            ValidatorFactoryImpl vf = new ValidatorFactoryImpl();
453            vf.setValidators(Collections.EMPTY_MAP);
454    
455            try
456            {
457                vf.constructValidatorList(component, "$fred[custom message]");
458                unreachable();
459            }
460            catch (ApplicationRuntimeException ex)
461            {
462                assertEquals(
463                        "Validator 'fred' is a reference to a managed bean of the component, and may not have a value or a message override specified.",
464                        ex.getMessage());
465            }
466    
467            verify();
468        }
469    }