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