001: // Copyright 2006, 2007 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.internal.services;
016:
017: import static java.util.Collections.singletonMap;
018: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
019:
020: import java.util.Arrays;
021: import java.util.List;
022: import java.util.Locale;
023: import java.util.Map;
024:
025: import org.apache.tapestry.ComponentResources;
026: import org.apache.tapestry.Field;
027: import org.apache.tapestry.FieldValidator;
028: import org.apache.tapestry.Validator;
029: import org.apache.tapestry.internal.test.InternalBaseTestCase;
030: import org.apache.tapestry.ioc.MessageFormatter;
031: import org.apache.tapestry.ioc.Messages;
032: import org.apache.tapestry.ioc.services.TypeCoercer;
033: import org.apache.tapestry.runtime.Component;
034: import org.apache.tapestry.services.FieldValidatorSource;
035: import org.apache.tapestry.services.ValidationMessagesSource;
036: import org.testng.annotations.Test;
037:
038: public class FieldValidatorSourceImplTest extends InternalBaseTestCase {
039: public interface FieldComponent extends Field, Component {
040:
041: };
042:
043: @Test
044: public void unknown_validator_type() {
045: ValidationMessagesSource messagesSource = mockValidationMessagesSource();
046: Validator validator = mockValidator();
047: TypeCoercer coercer = mockTypeCoercer();
048: FieldComponent field = newFieldComponent();
049: ComponentResources resources = mockComponentResources();
050: Messages containerMessages = mockMessages();
051: Map<String, Validator> map = newMap();
052:
053: train_getComponentResources(field, resources);
054: train_getId(resources, "fred");
055: train_getLocale(resources, Locale.ENGLISH);
056: train_getContainerMessages(resources, containerMessages);
057:
058: map.put("alpha", validator);
059: map.put("beta", validator);
060:
061: replay();
062:
063: FieldValidatorSource source = new FieldValidatorSourceImpl(
064: messagesSource, coercer, null, map);
065:
066: try {
067: source.createValidator(field, "foo", null);
068: unreachable();
069: } catch (IllegalArgumentException ex) {
070: assertEquals(ex.getMessage(),
071: "Unknown validator type 'foo'. Configured validators are alpha, beta.");
072: }
073:
074: verify();
075: }
076:
077: @SuppressWarnings("unchecked")
078: @Test
079: public void validator_with_no_constraint() throws Exception {
080: ValidationMessagesSource messagesSource = mockValidationMessagesSource();
081: Validator validator = mockValidator();
082: TypeCoercer coercer = mockTypeCoercer();
083: FieldComponent field = newFieldComponent();
084: Messages messages = mockMessages();
085: MessageFormatter formatter = mockMessageFormatter();
086: Object inputValue = new Object();
087: ComponentResources resources = mockComponentResources();
088: Messages containerMessages = mockMessages();
089:
090: Map<String, Validator> map = singletonMap("required", validator);
091:
092: train_getConstraintType(validator, null);
093:
094: train_getComponentResources(field, resources);
095:
096: train_getId(resources, "fred");
097: train_getContainerMessages(resources, containerMessages);
098: train_contains(containerMessages, "fred-required-message",
099: false);
100:
101: train_getLocale(resources, Locale.FRENCH);
102:
103: train_getValidationMessages(messagesSource, Locale.FRENCH,
104: messages);
105:
106: train_getMessageKey(validator, "key");
107: train_getMessageFormatter(messages, "key", formatter);
108:
109: train_invokeIfBlank(validator, false);
110: train_getValueType(validator, Object.class);
111: validator.validate(field, null, formatter, inputValue);
112:
113: replay();
114:
115: FieldValidatorSource source = new FieldValidatorSourceImpl(
116: messagesSource, coercer, null, map);
117:
118: FieldValidator fieldValidator = source.createValidator(field,
119: "required", null);
120:
121: fieldValidator.validate(inputValue);
122:
123: verify();
124: }
125:
126: @SuppressWarnings("unchecked")
127: @Test
128: public void component_messages_overrides_validator_messages()
129: throws Exception {
130: ValidationMessagesSource messagesSource = mockValidationMessagesSource();
131: Validator validator = mockValidator();
132: TypeCoercer coercer = mockTypeCoercer();
133: FieldComponent field = newFieldComponent();
134: MessageFormatter formatter = mockMessageFormatter();
135: Object inputValue = new Object();
136: ComponentResources resources = mockComponentResources();
137: Messages containerMessages = mockMessages();
138:
139: Map<String, Validator> map = singletonMap("required", validator);
140:
141: train_getConstraintType(validator, null);
142:
143: train_getComponentResources(field, resources);
144: train_getId(resources, "fred");
145: train_getLocale(resources, Locale.ENGLISH);
146: train_getContainerMessages(resources, containerMessages);
147: train_contains(containerMessages, "fred-required-message", true);
148:
149: train_getMessageFormatter(containerMessages,
150: "fred-required-message", formatter);
151:
152: train_invokeIfBlank(validator, false);
153: train_getValueType(validator, Object.class);
154: validator.validate(field, null, formatter, inputValue);
155:
156: replay();
157:
158: FieldValidatorSource source = new FieldValidatorSourceImpl(
159: messagesSource, coercer, null, map);
160:
161: FieldValidator fieldValidator = source.createValidator(field,
162: "required", null);
163:
164: fieldValidator.validate(inputValue);
165:
166: verify();
167: }
168:
169: @SuppressWarnings("unchecked")
170: @Test
171: public void constraint_value_from_message_catalog()
172: throws Exception {
173: ValidationMessagesSource messagesSource = mockValidationMessagesSource();
174: Validator validator = mockValidator();
175: TypeCoercer coercer = mockTypeCoercer();
176: FieldComponent field = newFieldComponent();
177: Messages messages = mockMessages();
178: MessageFormatter formatter = mockMessageFormatter();
179: Object inputValue = new Object();
180: ComponentResources resources = mockComponentResources();
181: Messages containerMessages = mockMessages();
182:
183: Map<String, Validator> map = singletonMap("minlength",
184: validator);
185:
186: train_getConstraintType(validator, Integer.class);
187:
188: train_getComponentResources(field, resources);
189: train_getId(resources, "fred");
190:
191: train_contains(containerMessages, "fred-minlength", true);
192: train_get(containerMessages, "fred-minlength", "5");
193:
194: train_coerce(coercer, "5", Integer.class, 5);
195:
196: train_getContainerMessages(resources, containerMessages);
197: train_contains(containerMessages, "fred-minlength-message",
198: false);
199:
200: train_getLocale(resources, Locale.FRENCH);
201:
202: train_getValidationMessages(messagesSource, Locale.FRENCH,
203: messages);
204:
205: train_getMessageKey(validator, "key");
206: train_getMessageFormatter(messages, "key", formatter);
207:
208: train_invokeIfBlank(validator, false);
209: train_getValueType(validator, Object.class);
210: validator.validate(field, 5, formatter, inputValue);
211:
212: replay();
213:
214: FieldValidatorSource source = new FieldValidatorSourceImpl(
215: messagesSource, coercer, null, map);
216:
217: FieldValidator fieldValidator = source.createValidators(field,
218: "minlength");
219:
220: fieldValidator.validate(inputValue);
221:
222: verify();
223: }
224:
225: @SuppressWarnings("unchecked")
226: @Test
227: public void missing_field_validator_constraint() throws Exception {
228: ValidationMessagesSource messagesSource = mockValidationMessagesSource();
229: Validator validator = mockValidator();
230: TypeCoercer coercer = mockTypeCoercer();
231: FieldComponent field = newFieldComponent();
232: ComponentResources resources = mockComponentResources();
233: Messages containerMessages = mockMessages();
234:
235: Map<String, Validator> map = singletonMap("minlength",
236: validator);
237:
238: train_getConstraintType(validator, Integer.class);
239:
240: train_getComponentResources(field, resources);
241: train_getId(resources, "fred");
242: train_getLocale(resources, Locale.GERMAN);
243: train_getContainerMessages(resources, containerMessages);
244:
245: train_contains(containerMessages, "fred-minlength", false);
246:
247: replay();
248:
249: FieldValidatorSource source = new FieldValidatorSourceImpl(
250: messagesSource, coercer, null, map);
251:
252: try {
253: source.createValidators(field, "minlength");
254: unreachable();
255: } catch (IllegalArgumentException ex) {
256: assertEquals(
257: ex.getMessage(),
258: "Validator \'minlength\' requires a validation constraint (of type java.lang.Integer) but none was provided.");
259: }
260:
261: verify();
262:
263: }
264:
265: @SuppressWarnings("unchecked")
266: @Test
267: public void single_validator_via_specification() throws Exception {
268: ValidationMessagesSource messagesSource = mockValidationMessagesSource();
269: Validator validator = mockValidator();
270: TypeCoercer coercer = mockTypeCoercer();
271: FieldComponent field = newFieldComponent();
272: Messages messages = mockMessages();
273: MessageFormatter formatter = mockMessageFormatter();
274: Object inputValue = new Object();
275: ComponentResources resources = mockComponentResources();
276: Messages containerMessages = mockMessages();
277:
278: Map<String, Validator> map = singletonMap("required", validator);
279:
280: train_getConstraintType(validator, null);
281:
282: train_getComponentResources(field, resources);
283: train_getId(resources, "fred");
284: train_getContainerMessages(resources, containerMessages);
285: train_contains(containerMessages, "fred-required-message",
286: false);
287:
288: train_getLocale(resources, Locale.FRENCH);
289:
290: train_getValidationMessages(messagesSource, Locale.FRENCH,
291: messages);
292:
293: train_getMessageKey(validator, "key");
294: train_getMessageFormatter(messages, "key", formatter);
295:
296: train_invokeIfBlank(validator, false);
297: train_getValueType(validator, Object.class);
298: validator.validate(field, null, formatter, inputValue);
299:
300: replay();
301:
302: FieldValidatorSource source = new FieldValidatorSourceImpl(
303: messagesSource, coercer, null, map);
304:
305: FieldValidator fieldValidator = source.createValidators(field,
306: "required");
307:
308: fieldValidator.validate(inputValue);
309:
310: verify();
311: }
312:
313: @SuppressWarnings("unchecked")
314: @Test
315: public void multiple_validators_via_specification()
316: throws Exception {
317: ValidationMessagesSource messagesSource = mockValidationMessagesSource();
318: Validator required = mockValidator();
319: Validator minLength = mockValidator();
320: TypeCoercer coercer = mockTypeCoercer();
321: FieldComponent field = newFieldComponent();
322: Messages messages = mockMessages();
323: MessageFormatter requiredFormatter = mockMessageFormatter();
324: MessageFormatter minLengthFormatter = mockMessageFormatter();
325: Object inputValue = "input value";
326: ComponentResources resources = mockComponentResources();
327: Messages containerMessages = mockMessages();
328: Integer fifteen = 15;
329:
330: Map<String, Validator> map = newMap();
331:
332: map.put("required", required);
333: map.put("minLength", minLength);
334:
335: train_getConstraintType(required, null);
336: train_getConstraintType(minLength, Integer.class);
337:
338: train_getComponentResources(field, resources);
339: train_getId(resources, "fred");
340: train_getContainerMessages(resources, containerMessages);
341: train_contains(containerMessages, "fred-required-message",
342: false);
343:
344: train_getLocale(resources, Locale.FRENCH);
345:
346: train_getValidationMessages(messagesSource, Locale.FRENCH,
347: messages);
348:
349: train_getMessageKey(required, "required");
350: train_getMessageFormatter(messages, "required",
351: requiredFormatter);
352:
353: train_contains(containerMessages, "fred-minLength-message",
354: false);
355:
356: train_getMessageKey(minLength, "min-length");
357: train_getMessageFormatter(messages, "min-length",
358: minLengthFormatter);
359:
360: train_coerce(coercer, "15", Integer.class, fifteen);
361:
362: train_invokeIfBlank(required, true);
363: train_getValueType(required, Object.class);
364: required.validate(field, null, requiredFormatter, inputValue);
365:
366: train_invokeIfBlank(minLength, false);
367: train_getValueType(minLength, String.class);
368: minLength.validate(field, fifteen, minLengthFormatter,
369: inputValue);
370:
371: replay();
372:
373: FieldValidatorSource source = new FieldValidatorSourceImpl(
374: messagesSource, coercer, null, map);
375:
376: FieldValidator fieldValidator = source.createValidators(field,
377: "required,minLength=15");
378:
379: fieldValidator.validate(inputValue);
380:
381: verify();
382: }
383:
384: @SuppressWarnings("unchecked")
385: @Test
386: public void validator_with_constraint() throws Exception {
387: ValidationMessagesSource messagesSource = mockValidationMessagesSource();
388: Validator validator = mockValidator();
389: TypeCoercer coercer = mockTypeCoercer();
390: FieldComponent field = newFieldComponent();
391: Messages messages = mockMessages();
392: MessageFormatter formatter = mockMessageFormatter();
393: Object inputValue = new Object();
394: ComponentResources resources = mockComponentResources();
395: Messages containerMessages = mockMessages();
396: Integer five = 5;
397:
398: Map<String, Validator> map = singletonMap("minLength",
399: validator);
400:
401: train_getConstraintType(validator, Integer.class);
402:
403: train_coerce(coercer, "5", Integer.class, five);
404:
405: train_getComponentResources(field, resources);
406: train_getId(resources, "fred");
407: train_getContainerMessages(resources, containerMessages);
408: train_contains(containerMessages, "fred-minLength-message",
409: false);
410:
411: train_getLocale(resources, Locale.FRENCH);
412:
413: train_getValidationMessages(messagesSource, Locale.FRENCH,
414: messages);
415:
416: train_getMessageKey(validator, "key");
417: train_getMessageFormatter(messages, "key", formatter);
418:
419: train_invokeIfBlank(validator, false);
420: train_getValueType(validator, Object.class);
421: validator.validate(field, five, formatter, inputValue);
422:
423: replay();
424:
425: FieldValidatorSource source = new FieldValidatorSourceImpl(
426: messagesSource, coercer, null, map);
427:
428: FieldValidator fieldValidator = source.createValidator(field,
429: "minLength", "5");
430:
431: fieldValidator.validate(inputValue);
432:
433: verify();
434: }
435:
436: private FieldComponent newFieldComponent() {
437: return newMock(FieldComponent.class);
438: }
439:
440: private void test(String specification,
441: ValidatorSpecification... expected) {
442: List<ValidatorSpecification> specs = FieldValidatorSourceImpl
443: .parse(specification);
444:
445: assertEquals(specs, Arrays.asList(expected));
446: }
447:
448: @Test
449: public void parse_simple_type_list() {
450: test("required,email", new ValidatorSpecification("required",
451: null), new ValidatorSpecification("email", null));
452: }
453:
454: @Test
455: public void parse_single_type() {
456: test("required", new ValidatorSpecification("required", null));
457: }
458:
459: @Test
460: public void ignore_whitespace_around_type_name() {
461: test(" required , email ", new ValidatorSpecification(
462: "required", null), new ValidatorSpecification("email",
463: null));
464: }
465:
466: @Test
467: public void parse_simple_type_with_value() {
468: test(
469: "minLength=5,sameAs=otherComponentId",
470: new ValidatorSpecification("minLength", "5"),
471: new ValidatorSpecification("sameAs", "otherComponentId"));
472: }
473:
474: @Test
475: public void whitespace_ignored_around_value() {
476: test(
477: "minLength= 5 , sameAs = otherComponentId ",
478: new ValidatorSpecification("minLength", "5"),
479: new ValidatorSpecification("sameAs", "otherComponentId"));
480: }
481:
482: @Test
483: public void dangling_equals_sign_is_empty_string_value() {
484: test("minLength= ",
485: new ValidatorSpecification("minLength", ""));
486: }
487:
488: @Test
489: public void unexpected_character_not_a_comma() {
490: try {
491: test("required.email");
492: unreachable();
493: } catch (RuntimeException ex) {
494: assertEquals(ex.getMessage(),
495: "Unexpected character '.' at position 9 of input string: required.email");
496: }
497: }
498:
499: @Test
500: public void unexpected_character_after_constraint_value() {
501: try {
502: test("minLength=3 . email");
503: unreachable();
504: } catch (RuntimeException ex) {
505: assertEquals(ex.getMessage(),
506: "Unexpected character '.' at position 13 of input string: minLength=3 . email");
507: }
508: }
509: }
|