View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.renderkit.html;
20  
21  import java.io.IOException;
22  import java.io.StringWriter;
23  
24  import javax.el.ValueExpression;
25  import javax.faces.component.UIComponent;
26  import javax.faces.component.UIForm;
27  import javax.faces.component.UIViewRoot;
28  import javax.faces.component.behavior.AjaxBehavior;
29  import javax.faces.component.html.HtmlInputText;
30  import javax.faces.component.html.HtmlOutputText;
31  import javax.faces.context.FacesContext;
32  import javax.faces.convert.Converter;
33  import javax.faces.convert.ConverterException;
34  
35  import junit.framework.Test;
36  import junit.framework.TestSuite;
37  
38  import org.apache.myfaces.test.utils.HtmlCheckAttributesUtil;
39  import org.apache.myfaces.test.utils.HtmlRenderedAttr;
40  import org.apache.myfaces.test.base.AbstractJsfTestCase;
41  import org.apache.myfaces.test.el.MockValueExpression;
42  import org.apache.myfaces.test.mock.MockRenderKitFactory;
43  import org.apache.myfaces.test.mock.MockResponseWriter;
44  
45  /**
46   * @author Bruno Aranda (latest modification by $Author: struberg $)
47   * @version $Revision: 1188235 $ $Date: 2011-10-24 12:09:33 -0500 (Mon, 24 Oct 2011) $
48   */
49  public class HtmlTextRendererTest extends AbstractJsfTestCase
50  {
51  
52      public static Test suite()
53      {
54          return new TestSuite(HtmlTextRendererTest.class); // needed in maven
55      }
56  
57      private MockResponseWriter writer ;
58      private HtmlOutputText outputText;
59      private HtmlInputText inputText;
60  
61      public HtmlTextRendererTest(String name)
62      {
63          super(name);
64      }
65  
66      public void setUp() throws Exception
67      {
68          super.setUp();
69  
70          outputText = new HtmlOutputText();
71          inputText = new HtmlInputText();
72  
73          writer = new MockResponseWriter(new StringWriter(), null, null);
74          facesContext.setResponseWriter(writer);
75          // TODO remove these two lines once myfaces-test goes alpha, see MYFACES-1155
76          facesContext.getViewRoot().setRenderKitId(MockRenderKitFactory.HTML_BASIC_RENDER_KIT);
77          facesContext.getRenderKit().addRenderer(
78                  outputText.getFamily(),
79                  outputText.getRendererType(),
80                  new HtmlTextRenderer());
81          facesContext.getRenderKit().addRenderer(
82                  inputText.getFamily(),
83                  inputText.getRendererType(),
84                  new HtmlTextRenderer());
85          
86          facesContext.getAttributes().put("org.apache.myfaces.RENDERED_JSF_JS", Boolean.TRUE);
87      }
88  
89      public void tearDown() throws Exception
90      {
91          super.tearDown();
92          outputText = null;
93          inputText = null;
94          writer = null;
95      }
96  
97      public void testStyleClassAttr() throws IOException
98      {
99          outputText.setValue("Output");
100         outputText.setStyleClass("myStyleClass");
101 
102         outputText.encodeEnd(facesContext);
103         facesContext.renderResponse();
104 
105         String output = writer.getWriter().toString();
106 
107         assertEquals("<span class=\"myStyleClass\">Output</span>", output);
108         assertNotSame("Output", output);
109     }
110     
111     /**
112      * Don't add span over escape
113      * @throws IOException
114      */
115     public void testEscapeNoSpan() throws IOException
116     {
117         outputText.setValue("Output");
118         outputText.setEscape(true);
119 
120         outputText.encodeEnd(facesContext);
121         facesContext.renderResponse();
122 
123         String output = writer.getWriter().toString();
124 
125         assertEquals("Output", output);
126     }
127 
128     public void testHtmlPropertyPassTru() throws Exception
129     {
130         HtmlRenderedAttr[] attrs = HtmlCheckAttributesUtil.generateBasicAttrs();
131         
132 
133         HtmlCheckAttributesUtil.checkRenderedAttributes(
134                 inputText, facesContext, writer, attrs);
135         if(HtmlCheckAttributesUtil.hasFailedAttrRender(attrs)) {
136             fail(HtmlCheckAttributesUtil.constructErrorMessage(attrs, writer.getWriter().toString()));
137         }
138     }
139     
140     public void testWhenSubmittedValueIsNullDefaultShouldDissapearFromRendering() {
141         //See MYFACES-2161 and MYFACES-1549 for details
142         UIViewRoot root = new UIViewRoot();
143         UIForm form = new UIForm();
144         form.setId("formId");
145         
146         form.getChildren().add(inputText);
147         root.getChildren().add(form);
148         
149         Converter converter = new Converter()
150         {
151             public Object getAsObject(FacesContext context,
152                     UIComponent component, String value)
153                     throws ConverterException
154             {
155                 if (value == null || "".equals(value))
156                 {
157                     return null;
158                 }
159                 else
160                 {
161                     return value;
162                 }
163             }
164 
165             public String getAsString(FacesContext context,
166                     UIComponent component, Object value)
167                     throws ConverterException
168             {
169                 if (value == null)
170                 {
171                     return "";
172                 }
173                 else
174                 {
175                     return value.toString();
176                 }
177             }
178         };
179         
180         inputText.setConverter(converter);
181         
182         ValueExpression expression = new MockValueExpression("#{requestScope.someDefaultValueOnBean}",String.class);
183         expression.setValue(facesContext.getELContext(), "defaultValue");
184         inputText.setValueExpression("value", expression);
185         
186         // 1) user enters an empty string in an input-component: ""
187         //Call to setSubmittedValue on HtmlRendererUtils.decodeUIInput(facesContext, component), 
188         //that is called from renderer decode()
189         externalContext.addRequestParameterMap(inputText.getClientId(facesContext), "");
190         
191         inputText.decode(facesContext);
192         
193         // 2) conversion and validation phase: "" --> setValue(null);
194         // isLocalValueSet = true; setSubmittedValue(null);
195         inputText.validate(facesContext);
196         
197         // 3) validation fails in some component on the page --> update model
198         // phase is skipped
199         // No OP
200         
201         // 4) renderer calls getValue(); --> getValue() evaluates the
202         // value-binding, as the local-value is 'null', and I get the
203         // default-value of the bean shown again
204         assertNotSame(expression.getValue(facesContext.getELContext()), inputText.getValue());
205         assertNull(inputText.getValue());
206     }
207     
208     /**
209      * Components that render client behaviors should always render "id" and "name" attribute
210      */
211     public void testClientBehaviorHolderRendersIdAndName() 
212     {
213         inputText.addClientBehavior("keypress", new AjaxBehavior());
214         try 
215         {
216             inputText.encodeAll(facesContext);
217             String output = ((StringWriter) writer.getWriter()).getBuffer().toString();
218             assertTrue(output.matches("(?s).+id=\".+\".+"));
219             assertTrue(output.matches("(?s).+name=\".+\".+"));
220         }
221         catch (Exception e)
222         {
223             fail(e.getMessage());
224         }
225         
226     }
227     
228     /**
229      * Tests if a JavaScript user code is correctly escaped.
230      * e.g. alert('test') has to become alert(\'test\')
231      */
232     public void testClientBehaviorUserCodeJavaScriptEscaping()
233     {
234         inputText.getAttributes().put("onchange", "alert('test')");
235         inputText.addClientBehavior("change", new AjaxBehavior());
236         try 
237         {
238             inputText.encodeAll(facesContext);
239             String output = ((StringWriter) writer.getWriter()).getBuffer().toString();
240             // onchange="jsf.util.chain(document.getElementById(&apos;j_id0&apos;), event,
241             //                          &apos;alert(\&apos;test\&apos;)&apos;);"
242             assertTrue(output.contains("&apos;alert(\\&apos;test\\&apos;)&apos;"));
243         }
244         catch (Exception e)
245         {
246             fail(e.getMessage());
247         }
248     }
249     
250     /**
251      * Tests if a JavaScript user code that already contains ' is correctly escaped.
252      * e.g. test = 'a\'b'; has to become test = \'a\\\'b\';
253      */
254     public void testClientBehaviorUserCodeJavaScriptDoubleEscaping()
255     {
256         inputText.getAttributes().put("onchange", "var test = \'a\\\'b\'; alert(test);");
257         inputText.addClientBehavior("change", new AjaxBehavior());
258         try 
259         {
260             inputText.encodeAll(facesContext);
261             String output = ((StringWriter) writer.getWriter()).getBuffer().toString();
262             // onchange="jsf.util.chain(document.getElementById(&apos;j_id0&apos;), event,
263             //               &apos;var test = \&apos;a\\\&apos;b\&apos;; alert(test);&apos;);"
264             assertTrue(output.contains("&apos;var test = \\&apos;a\\\\\\&apos;b\\&apos;; alert(test);&apos;"));
265         }
266         catch (Exception e)
267         {
268             fail(e.getMessage());
269         }
270     }
271     
272 }