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: lu4242 $)
47   * @version $Revision: 1164681 $ $Date: 2011-09-02 15:00:11 -0500 (Fri, 02 Sep 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                     return null;
157                 else
158                     return value;
159             }
160 
161             public String getAsString(FacesContext context,
162                     UIComponent component, Object value)
163                     throws ConverterException
164             {
165                 if (value == null)
166                     return "";
167                 else
168                     return value.toString();
169             }
170         };
171         
172         inputText.setConverter(converter);
173         
174         ValueExpression expression = new MockValueExpression("#{requestScope.someDefaultValueOnBean}",String.class);
175         expression.setValue(facesContext.getELContext(), "defaultValue");
176         inputText.setValueExpression("value", expression);
177         
178         // 1) user enters an empty string in an input-component: ""
179         //Call to setSubmittedValue on HtmlRendererUtils.decodeUIInput(facesContext, component), 
180         //that is called from renderer decode()
181         externalContext.addRequestParameterMap(inputText.getClientId(facesContext), "");
182         
183         inputText.decode(facesContext);
184         
185         // 2) conversion and validation phase: "" --> setValue(null);
186         // isLocalValueSet = true; setSubmittedValue(null);
187         inputText.validate(facesContext);
188         
189         // 3) validation fails in some component on the page --> update model
190         // phase is skipped
191         // No OP
192         
193         // 4) renderer calls getValue(); --> getValue() evaluates the
194         // value-binding, as the local-value is 'null', and I get the
195         // default-value of the bean shown again
196         assertNotSame(expression.getValue(facesContext.getELContext()), inputText.getValue());
197         assertNull(inputText.getValue());
198     }
199     
200     /**
201      * Components that render client behaviors should always render "id" and "name" attribute
202      */
203     public void testClientBehaviorHolderRendersIdAndName() 
204     {
205         inputText.addClientBehavior("keypress", new AjaxBehavior());
206         try 
207         {
208             inputText.encodeAll(facesContext);
209             String output = ((StringWriter) writer.getWriter()).getBuffer().toString();
210             assertTrue(output.matches("(?s).+id=\".+\".+"));
211             assertTrue(output.matches("(?s).+name=\".+\".+"));
212         }
213         catch (Exception e)
214         {
215             fail(e.getMessage());
216         }
217         
218     }
219     
220     /**
221      * Tests if a JavaScript user code is correctly escaped.
222      * e.g. alert('test') has to become alert(\'test\')
223      */
224     public void testClientBehaviorUserCodeJavaScriptEscaping()
225     {
226         inputText.getAttributes().put("onchange", "alert('test')");
227         inputText.addClientBehavior("change", new AjaxBehavior());
228         try 
229         {
230             inputText.encodeAll(facesContext);
231             String output = ((StringWriter) writer.getWriter()).getBuffer().toString();
232             // onchange="jsf.util.chain(document.getElementById(&apos;j_id0&apos;), event,
233             //                          &apos;alert(\&apos;test\&apos;)&apos;);"
234             assertTrue(output.contains("&apos;alert(\\&apos;test\\&apos;)&apos;"));
235         }
236         catch (Exception e)
237         {
238             fail(e.getMessage());
239         }
240     }
241     
242     /**
243      * Tests if a JavaScript user code that already contains ' is correctly escaped.
244      * e.g. test = 'a\'b'; has to become test = \'a\\\'b\';
245      */
246     public void testClientBehaviorUserCodeJavaScriptDoubleEscaping()
247     {
248         inputText.getAttributes().put("onchange", "var test = \'a\\\'b\'; alert(test);");
249         inputText.addClientBehavior("change", new AjaxBehavior());
250         try 
251         {
252             inputText.encodeAll(facesContext);
253             String output = ((StringWriter) writer.getWriter()).getBuffer().toString();
254             // onchange="jsf.util.chain(document.getElementById(&apos;j_id0&apos;), event,
255             //               &apos;var test = \&apos;a\\\&apos;b\&apos;; alert(test);&apos;);"
256             assertTrue(output.contains("&apos;var test = \\&apos;a\\\\\\&apos;b\\&apos;; alert(test);&apos;"));
257         }
258         catch (Exception e)
259         {
260             fail(e.getMessage());
261         }
262     }
263     
264 }