1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.trinidad.component;
20
21 import java.beans.BeanInfo;
22 import java.beans.IntrospectionException;
23 import java.beans.Introspector;
24 import java.beans.PropertyDescriptor;
25 import java.io.IOException;
26
27 import java.lang.reflect.InvocationTargetException;
28 import java.lang.reflect.Method;
29 import java.util.Map;
30 import javax.faces.component.EditableValueHolder;
31 import javax.faces.component.UIComponent;
32 import javax.faces.component.UIViewRoot;
33 import javax.faces.component.ValueHolder;
34 import javax.faces.context.FacesContext;
35 import javax.faces.event.FacesEvent;
36 import javax.faces.event.ValueChangeListener;
37
38 import javax.faces.convert.Converter;
39 import javax.faces.el.ValueBinding;
40 import javax.faces.render.RenderKit;
41 import javax.faces.render.RenderKitFactory;
42 import javax.faces.render.Renderer;
43 import javax.faces.validator.Validator;
44
45 import junit.framework.Test;
46 import junit.framework.TestSuite;
47
48 import org.apache.myfaces.trinidad.component.UIXComponent;
49 import org.apache.myfaces.trinidad.event.AttributeChangeEvent;
50 import org.apache.myfaces.trinidadbuild.test.FacesTestCase;
51 import org.jmock.Mock;
52 import org.jmock.core.Constraint;
53
54
55
56
57
58 public class UIComponentTestCase extends FacesTestCase
59 {
60
61
62
63
64
65 public UIComponentTestCase(
66 String testName)
67 {
68 super(testName);
69 }
70
71 @Override
72 protected void setUp() throws Exception
73 {
74 super.setUp();
75 }
76
77 @Override
78 protected void tearDown() throws Exception
79 {
80 super.tearDown();
81 }
82
83 public static Test suite()
84 {
85 return new TestSuite(UIComponentTestCase.class);
86 }
87
88
89
90
91
92
93
94
95
96
97
98 @SuppressWarnings("unchecked")
99 protected void doTestAttributeTransparency(
100 UIComponent component,
101 String attrName,
102 Object attrValue,
103 Object propValue)
104 {
105 assertFalse("Test values for attribute \"" + attrName + "\" must differ",
106 (attrValue == propValue ||
107 (attrValue != null &&
108 attrValue.equals(propValue))));
109
110 Map<String, Object> attrMap = component.getAttributes();
111 try
112 {
113 boolean foundProperty = false;
114
115 BeanInfo info = Introspector.getBeanInfo(component.getClass());
116 PropertyDescriptor[] pds = info.getPropertyDescriptors();
117 for (int i=0; i < pds.length; i++)
118 {
119 String propName = pds[i].getName();
120 if (attrName.equals(propName))
121 {
122 if (pds[i].getPropertyType().isPrimitive())
123 {
124 assertNotNull("Primitive \"" + attrName +
125 "\" attribute value must be non-null",
126 attrValue);
127 assertNotNull("Primitive \"" + propName +
128 "\" property value must be non-null",
129 propValue);
130 }
131
132 foundProperty = true;
133
134 Method reader = pds[i].getReadMethod();
135 Method writer = pds[i].getWriteMethod();
136 writer.invoke(component, new Object[] { propValue });
137 assertEquals("Property set not visible in attribute map",
138 attrMap.get(attrName), propValue);
139 attrMap.put(attrName, attrValue);
140 assertEquals("Attribute put not visible in property value",
141 reader.invoke(component, new Object[0]), attrValue);
142 break;
143 }
144 }
145
146 if (!foundProperty)
147 fail("Unable to find attribute property \"" + attrName + "\"");
148 }
149 catch (IntrospectionException e)
150 {
151 e.printStackTrace();
152 fail("Unable to access attribute property \"" + attrName + "\"");
153 }
154 catch (InvocationTargetException e)
155 {
156 e.printStackTrace();
157 fail("Unable to access attribute property \"" + attrName + "\"");
158 }
159 catch (IllegalAccessException e)
160 {
161 e.printStackTrace();
162 fail("Unable to access attribute property \"" + attrName + "\"");
163 }
164 }
165
166
167
168
169
170
171
172
173
174
175
176 @SuppressWarnings("unchecked")
177 protected void doTestFacetTransparency(
178 UIComponent component,
179 String facetName)
180 {
181 Mock mockFacetValue = mock(UIComponent.class);
182 UIComponent facetValue = (UIComponent) mockFacetValue.proxy();
183 mockFacetValue.stubs().method("getParent").will(returnValue(null));
184 mockFacetValue.stubs().method("setParent");
185
186 Mock mockPropValue = mock(UIComponent.class);
187 UIComponent propValue = (UIComponent) mockPropValue.proxy();
188 mockPropValue.stubs().method("getParent").will(returnValue(null));
189 mockPropValue.stubs().method("setParent");
190
191 Map<String, UIComponent> facetMap = component.getFacets();
192 try
193 {
194
195 BeanInfo info = Introspector.getBeanInfo(component.getClass());
196 PropertyDescriptor[] pds = info.getPropertyDescriptors();
197 boolean foundProperty = false;
198 for (int i=0; i < pds.length; i++)
199 {
200 String propName = pds[i].getName();
201 if (facetName.equals(propName))
202 {
203 assertTrue("Facet bean accessor must return UIComponent or subclass",
204 UIComponent.class.isAssignableFrom(pds[i].getPropertyType()));
205
206 foundProperty = true;
207
208 Method reader = pds[i].getReadMethod();
209 Method writer = pds[i].getWriteMethod();
210 writer.invoke(component, new Object[] { propValue });
211 assertEquals("Property set not visible in facet map",
212 facetMap.get(facetName), propValue);
213 facetMap.put(facetName, facetValue);
214 assertEquals("Facet put not visible in property value",
215 reader.invoke(component, new Object[0]), facetValue);
216 break;
217 }
218 }
219
220 if (!foundProperty)
221 fail("Unable to find facet property \"" + facetName + "\"");
222 }
223 catch (IntrospectionException e)
224 {
225 e.printStackTrace();
226 fail("Unable to access facet property \"" + facetName + "\"");
227 }
228 catch (InvocationTargetException e)
229 {
230 e.printStackTrace();
231 fail("Unable to access facet property \"" + facetName + "\"");
232 }
233 catch (IllegalAccessException e)
234 {
235 e.printStackTrace();
236 fail("Unable to access facet property \"" + facetName + "\"");
237 }
238 finally
239 {
240 mockFacetValue.verify();
241 mockPropValue.verify();
242 }
243 }
244
245
246
247
248 protected void doTestApplyRequestValues(
249 UIComponent component)
250 {
251 UIViewRoot root = new UIViewRoot();
252 doTestApplyRequestValues(root, component);
253 }
254
255
256
257
258 protected void doTestApplyRequestValues(
259 UIViewRoot root,
260 UIComponent component)
261 {
262
263 Mock mockRenderKitFactory = mock(RenderKitFactory.class);
264
265 Mock mockRenderkit = getMockRenderKitWrapper().getMock();
266 RenderKit renderkit = getMockRenderKitWrapper().getRenderKit();
267
268 Mock mockRenderer = mock(Renderer.class);
269 Renderer renderer = (Renderer) mockRenderer.proxy();
270
271 mockRenderKitFactory.stubs().method("getRenderKit").will(returnValue(renderkit));
272 mockRenderkit.stubs().method("getRenderer").will(returnValue(renderer));
273
274 if (isRendererUsed() && component.isRendered())
275 {
276 mockRenderer.expects(once()).method("decode");
277 }
278 else
279 {
280 mockRenderer.expects(never()).method("decode");
281 }
282
283 doTestApplyRequestValues(facesContext, root, component);
284
285 mockRenderKitFactory.verify();
286 mockRenderkit.verify();
287 mockRenderer.verify();
288
289 setCurrentContext(null);
290 }
291
292
293 @SuppressWarnings("unchecked")
294 protected void doTestApplyRequestValues(
295 FacesContext context,
296 UIViewRoot root,
297 UIComponent component)
298 {
299
300 Mock mock = createMockUIComponent();
301 UIComponent child = (UIComponent) mock.proxy();
302
303
304
305
306 if (willChildrenBeProcessed(component))
307 mock.expects(once()).method("processDecodes");
308
309
310
311 if (component.getParent() == null)
312 root.getChildren().add(component);
313
314 component.getChildren().add(child);
315
316 AttributeChangeTester attributeChangeTester = null;
317 if (component instanceof UIXComponent)
318 {
319 attributeChangeTester = new AttributeChangeTester();
320 ((UIXComponent) component).setAttributeChangeListener(attributeChangeTester);
321 ((UIXComponent) component).addAttributeChangeListener(attributeChangeTester);
322 AttributeChangeEvent ace =
323 new AttributeChangeEvent(component, "testProperty",
324 Boolean.FALSE, Boolean.TRUE);
325 ace.queue();
326 }
327
328 root.processDecodes(context);
329
330 if (attributeChangeTester != null)
331 attributeChangeTester.verify();
332
333 mock.verify();
334 }
335
336
337
338
339 protected void doTestProcessValidations(
340 UIComponent component)
341 {
342 doTestProcessValidations(component, "submittedValue", "convertedValue");
343 }
344
345
346
347
348 protected void doTestProcessValidations(
349 UIComponent component,
350 Object submittedValue,
351 Object convertedValue)
352 {
353 UIViewRoot root = new UIViewRoot();
354 doTestProcessValidations(root, component, submittedValue, convertedValue);
355 }
356
357
358
359
360 protected void doTestProcessValidations(
361 UIViewRoot root,
362 UIComponent component,
363 Object submittedValue,
364 Object convertedValue)
365 {
366
367 Mock mockRenderKit = getMockRenderKitWrapper().getMock();
368
369 Mock mockRenderer = mock(Renderer.class);
370 Renderer renderer = (Renderer) mockRenderer.proxy();
371 mockRenderKit.stubs().method("getRenderer").will(returnValue(renderer));
372
373 Mock mockConverter = mock(Converter.class);
374 Converter converter = (Converter) mockConverter.proxy();
375
376 Mock mockValidator = mock(Validator.class);
377 Validator validator = (Validator) mockValidator.proxy();
378
379 Mock mockListener = mock(ValueChangeListener.class);
380 ValueChangeListener listener = (ValueChangeListener) mockListener.proxy();
381
382 setCurrentContext(facesContext);
383
384
385
386 if (component instanceof EditableValueHolder)
387 {
388
389 EditableValueHolder editable = (EditableValueHolder)component;
390 mockConverter.expects(never()).method("getAsObject");
391 mockConverter.expects(never()).method("getAsString");
392 mockRenderer.expects(once()).method("getConvertedValue").will(returnValue(convertedValue));
393 editable.setConverter(converter);
394 editable.setSubmittedValue(submittedValue);
395 editable.addValidator(validator);
396 editable.addValueChangeListener(listener);
397
398 mockListener.expects(once()).method("processValueChange");
399 mockValidator.expects(once()).method("validate").with(new Constraint[] { eq(facesContext), eq(component), eq(convertedValue) });
400
401 }
402
403
404 else if (component instanceof ValueHolder)
405 {
406 ValueHolder holder = (ValueHolder)component;
407 holder.setConverter(converter);
408 mockConverter.expects(never()).method("getAsObject");
409 mockConverter.expects(never()).method("getAsString");
410 }
411
412 doTestProcessValidations(facesContext, root, component);
413
414 mockRenderKit.verify();
415 mockRenderer.verify();
416 mockConverter.verify();
417 mockValidator.verify();
418 mockListener.verify();
419
420 setCurrentContext(null);
421 }
422
423
424 @SuppressWarnings("unchecked")
425 protected void doTestProcessValidations(
426 FacesContext context,
427 UIViewRoot root,
428 UIComponent component)
429 {
430
431 Mock mock = createMockUIComponent();
432 UIComponent child = (UIComponent) mock.proxy();
433
434
435
436
437 if (willChildrenBeProcessed(component))
438 mock.expects(once()).method("processValidators");
439
440
441
442 if (component.getParent() == null)
443 root.getChildren().add(component);
444 component.getChildren().add(child);
445
446 root.processValidators(context);
447
448 mock.verify();
449 }
450
451
452
453
454 protected void doTestUpdateModelValues(
455 UIComponent component)
456 {
457 UIViewRoot root = new UIViewRoot();
458 doTestUpdateModelValues(root, component);
459 }
460
461
462
463
464 protected void doTestUpdateModelValues(
465 UIViewRoot root,
466 UIComponent component)
467 {
468
469 Mock mockRenderkit = getMockRenderKitWrapper().getMock();
470
471 Mock mockRenderer = mock(Renderer.class);
472 Renderer renderer = (Renderer) mockRenderer.proxy();
473 mockRenderkit.stubs().method("getRenderer").will(returnValue(renderer));
474
475 Mock mockBinding = mock(ValueBinding.class);
476 ValueBinding binding = (ValueBinding) mockBinding.proxy();
477
478 setCurrentContext(facesContext);
479
480
481
482 if (component instanceof EditableValueHolder)
483 {
484 EditableValueHolder editable = (EditableValueHolder)component;
485 component.setValueBinding("value", binding);
486 editable.setValue("newValue");
487 mockBinding.expects(atLeastOnce()).method("setValue").with(eq(facesContext), eq("newValue"));
488
489 assertEquals(true, editable.isLocalValueSet());
490 }
491
492 doTestUpdateModelValues(facesContext, root, component);
493
494 setCurrentContext(null);
495
496 mockRenderer.verify();
497 mockBinding.verify();
498 }
499
500
501 @SuppressWarnings("unchecked")
502 protected void doTestUpdateModelValues(
503 FacesContext context,
504 UIViewRoot root,
505 UIComponent component)
506 {
507 Mock mock = createMockUIComponent();
508 UIComponent child = (UIComponent) mock.proxy();
509
510
511
512
513 if (willChildrenBeProcessed(component))
514 mock.expects(once()).method("processUpdates");
515
516
517
518 if (component.getParent() == null)
519 root.getChildren().add(component);
520 component.getChildren().add(child);
521 root.processUpdates(context);
522
523 mock.verify();
524 }
525
526
527
528
529 protected void doTestInvokeApplication(
530 UIComponent component,
531 FacesEvent event)
532 {
533 try
534 {
535 setCurrentContext(facesContext);
536
537 doTestInvokeApplication(facesContext, facesContext.getViewRoot(), component, event);
538
539 }
540 finally
541 {
542 setCurrentContext(null);
543 }
544 }
545
546
547
548 @SuppressWarnings("unchecked")
549 protected void doTestInvokeApplication(
550 FacesContext context,
551 UIViewRoot root,
552 UIComponent component,
553 FacesEvent event)
554 {
555
556 Mock mock = createMockUIComponent();
557 UIComponent child = (UIComponent) mock.proxy();
558
559
560
561
562
563
564 root.getChildren().add(component);
565 if (event != null)
566 event.queue();
567
568 component.getChildren().add(child);
569 root.processApplication(context);
570
571 mock.verify();
572 }
573
574
575
576
577
578
579 @SuppressWarnings("unchecked")
580 protected void doTestRenderResponse(
581 UIComponent component) throws IOException
582 {
583
584
585
586 Mock mockRenderkit = getMockRenderKitWrapper().getMock();
587
588 Mock mockRenderer = mock(Renderer.class);
589 Renderer renderer = (Renderer) mockRenderer.proxy();
590 mockRenderkit.stubs().method("getRenderer").will(returnValue(renderer));
591
592 Mock mockChild = createMockUIComponent();
593 UIComponent child = (UIComponent) mockChild.proxy();
594
595 mockChild.expects(atLeastOnce()).method("getParent").will(returnValue(null));
596 mockChild.expects(atLeastOnce()).method("isTransient").will(returnValue(false));
597 mockChild.expects(atLeastOnce()).method("getRendersChildren").will(returnValue(true));
598
599 UIViewRoot root = new UIViewRoot();
600
601 mockRenderer.expects(atLeastOnce()).method("getRendersChildren").will(returnValue(false));
602 mockRenderer.expects(never()).method("decode");
603 mockRenderer.expects(never()).method("getConvertedValue");
604 mockRenderer.expects(never()).method("encodeChildren");
605
606 if (isRendererUsed())
607 {
608 mockRenderer.expects(once()).method("encodeBegin");
609 mockRenderer.expects(once()).method("encodeEnd");
610 }
611 else
612 {
613 mockRenderer.expects(never()).method("encodeBegin");
614 mockRenderer.expects(never()).method("encodeEnd");
615 }
616
617
618
619
620
621 mockChild.expects(never()).method("processRestoreState");
622 mockChild.expects(never()).method("processDecodes");
623 mockChild.expects(never()).method("processValidators");
624 mockChild.expects(never()).method("processUpdates");
625 mockChild.expects(once()).method("processSaveState");
626
627
628 mockChild.expects(once()).method("encodeBegin");
629 mockChild.expects(once()).method("encodeChildren");
630 mockChild.expects(once()).method("encodeEnd");
631
632 root.getChildren().add(component);
633 component.getChildren().add(child);
634
635 FacesContext current = FacesContext.getCurrentInstance();
636 try
637 {
638 TestFacesContext.setCurrentInstance(facesContext);
639 root.processSaveState(facesContext);
640 doRenderResponse(facesContext, root);
641 }
642 finally
643 {
644 TestFacesContext.setCurrentInstance(current);
645 }
646
647 mockRenderer.verify();
648 mockChild.verify();
649 }
650
651 protected void doTestValidateFailure(
652 UIViewRoot root)
653 {
654
655
656
657
658
659
660 Mock mockRenderer = mock(Renderer.class);
661
662
663
664
665
666
667
668 setCurrentContext(facesContext);
669
670 root.processValidators(facesContext);
671
672 mockRenderer.verify();
673
674 setCurrentContext(null);
675 }
676
677
678
679
680
681
682
683 protected Mock createMockUIComponent()
684 {
685 Mock mock = mock(UIComponent.class);
686
687 mock.stubs().method("getParent").will(returnValue(null));
688 mock.stubs().method("setParent");
689 mock.expects(never()).method("processRestoreState");
690 mock.expects(never()).method("processDecodes");
691 mock.expects(never()).method("processValidators");
692 mock.expects(never()).method("processUpdates");
693 mock.expects(never()).method("processSaveState");
694 mock.expects(never()).method("encodeBegin");
695 mock.expects(never()).method("encodeChildren");
696 mock.expects(never()).method("encodeEnd");
697
698 return mock;
699 }
700
701 protected boolean willChildrenBeProcessed(UIComponent component)
702 {
703 return (component.isRendered());
704 }
705
706 protected boolean willChildrenBeRendered(UIComponent component)
707 {
708 return true;
709 }
710
711 protected boolean isRendererUsed()
712 {
713 return _isRendererUsed;
714 }
715
716 protected void setRendererUsed(boolean isRendererUsed)
717 {
718 _isRendererUsed = isRendererUsed;
719 }
720
721 private boolean _isRendererUsed = true;
722 }