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 }