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.test.utils;
20  
21  import java.util.Map;
22  
23  import javax.faces.component.UIComponent;
24  import javax.faces.context.FacesContext;
25  
26  import org.apache.shale.test.mock.MockResponseWriter;
27  
28  /**
29   * This is a utility class used in unit test cases to check if
30   * a component's attributes are rendered properly.
31   */
32  public class HtmlCheckAttributesUtil 
33  {
34      /**
35       * This method adds all elements of attrs to the attributes map of component.
36       * @param component The component to add the attributes to.
37       * @param attrs     The attributes to be added to the component.
38       */
39      private static void addBaseAttributes(UIComponent component, HtmlRenderedAttr[] attrs) 
40      {
41          Map map = component.getAttributes();
42          for(int i = 0; i < attrs.length; i++) 
43          {
44              HtmlRenderedAttr attr = attrs[i];
45              map.put(attr.getName(), attr.getValue());
46          }
47      }
48      
49      /**
50       * Iterates through all elements of attrs to check if they are only rendered once in output.
51       * @param attrs      The attributes to be checked.
52       * @param output     The html output of the component's renderer.
53       * @throws Exception
54       */
55      private static void checkRenderedAttributes(HtmlRenderedAttr[] attrs, String output) throws Exception 
56      {
57          for(int i = 0; i < attrs.length; i++) 
58          {
59              //assertContainsOnlyOnce(attrs[i], output);
60              checkAttributeOccurrences(attrs[i], output);
61          }
62      }
63      
64      /**
65       * This method adds all attributes from attrs into the component.  After adding the attributes,
66       * it calls the encodeAll() method of the component.  The html generated from the component's
67       * renderer will be checked to see if the attributes have been rendered correctly.
68       * @param component  The component whose attributes will be tested.
69       * @param context    
70       * @param writer     The ResponseWriter used by the renderer to output the html generated.
71       * @param attrs      An array of attributes which will be tested.
72       * @throws Exception
73       */
74      public static void checkRenderedAttributes(
75              UIComponent component, 
76              FacesContext context, 
77              MockResponseWriter writer,
78              HtmlRenderedAttr[] attrs) throws Exception 
79      {
80          
81          addBaseAttributes(component, attrs);
82          component.encodeBegin(context);
83          component.encodeChildren(context);
84          component.encodeEnd(context);
85          context.renderResponse();
86          checkRenderedAttributes(attrs, writer.getWriter().toString());
87      }
88      
89      /**
90       * Checks the attrs array if it has elements which were rendered incorrectly.
91       * @param attrs The attributes to be checked.
92       * @return True if there are attributes not rendered correctly.
93       */
94      public static boolean hasFailedAttrRender(HtmlRenderedAttr[] attrs) 
95      {
96          for(int i = 0; i < attrs.length; i++) 
97          {
98              if(!attrs[i].isRenderSuccessful()) return true;
99          }
100         return false;
101     }
102     
103     /**
104      * Constructs an error message string detailing which attributes were not rendered
105      * and which attributes were rendered more than once.
106      * @param attrs   The attributes to be tested.
107      * @param actual  The html generated by the renderer.
108      * @return The error message.
109      */
110     public static String constructErrorMessage(HtmlRenderedAttr[] attrs, String actual) 
111     {
112         StringBuffer messgBuffer = new StringBuffer();
113         for(int i = 0; i < attrs.length; i++) 
114         {
115             if(attrs[i].getErrorCode() == HtmlRenderedAttr.RENDERED_MORE_TIMES_THAN_EXPECTED) 
116             {
117                 messgBuffer.append(attrs[i].getName()).append(" (");
118                 messgBuffer.append(attrs[i].getExpectedHtml()).append(") was rendered more times (");
119                 messgBuffer.append(attrs[i].getActualOccurrences()).append(") than expected (");
120                 messgBuffer.append(attrs[i].getExpectedOccurrences()).append(").");
121                 messgBuffer.append(System.getProperty("line.separator"));
122             } 
123             else if(attrs[i].getErrorCode() == HtmlRenderedAttr.RENDERED_LESS_TIMES_THAN_EXPECTED)
124             {
125                 messgBuffer.append(attrs[i].getName()).append(" (");
126                 messgBuffer.append(attrs[i].getExpectedHtml()).append(") was rendered less times (");
127                 messgBuffer.append(attrs[i].getActualOccurrences()).append(") than expected (");
128                 messgBuffer.append(attrs[i].getExpectedOccurrences()).append(").");
129                 messgBuffer.append(System.getProperty("line.separator"));
130             }
131         }
132         messgBuffer.append("Actual HTML: ").append(actual);
133         return messgBuffer.toString();
134     }
135     
136     /**
137      * Checks if the occurrence of the rendered attribute in the html
138      * generated by the renderer is equal to the number of times expected.
139      * @param attr   The attribute to be tested.
140      * @param actual The html generated by the renderer.
141      */
142     private static void checkAttributeOccurrences(HtmlRenderedAttr attr, String actual)
143     {
144         String expectedHtml = attr.getExpectedHtml();
145         
146         int index;
147         int offset = 0;
148         while((index=actual.indexOf(expectedHtml,offset)) != -1) 
149         {
150             attr.increaseActualOccurrences();
151             if(attr.getActualOccurrences() > attr.getExpectedOccurrences()) 
152             {
153                 attr.setErrorCode(HtmlRenderedAttr.RENDERED_MORE_TIMES_THAN_EXPECTED);
154                 return;
155             } 
156 
157             offset += index + expectedHtml.length();
158         }
159         
160         if(attr.getActualOccurrences() < attr.getExpectedOccurrences()) 
161         {
162             attr.setErrorCode(HtmlRenderedAttr.RENDERED_LESS_TIMES_THAN_EXPECTED);
163         } 
164         else 
165         {
166             attr.setRenderSuccessful(true);
167         }
168     }
169     
170     public static HtmlRenderedAttr[] generateBasicAttrs() {
171         HtmlRenderedAttr[] attrs = {
172             //_AccesskeyProperty
173             new HtmlRenderedAttr("accesskey"),
174             //_UniversalProperties
175             new HtmlRenderedAttr("dir"), 
176             new HtmlRenderedAttr("lang"), 
177             new HtmlRenderedAttr("title"),
178             //_FocusBlurProperties
179             new HtmlRenderedAttr("onfocus"), 
180             new HtmlRenderedAttr("onblur"),
181             //_EventProperties
182             new HtmlRenderedAttr("onclick"), 
183             new HtmlRenderedAttr("ondblclick"), 
184             new HtmlRenderedAttr("onkeydown"), 
185             new HtmlRenderedAttr("onkeypress"),
186             new HtmlRenderedAttr("onkeyup"), 
187             new HtmlRenderedAttr("onmousedown"), 
188             new HtmlRenderedAttr("onmousemove"), 
189             new HtmlRenderedAttr("onmouseout"),
190             new HtmlRenderedAttr("onmouseover"), 
191             new HtmlRenderedAttr("onmouseup"),
192             //_StyleProperties
193             new HtmlRenderedAttr("style"), 
194             new HtmlRenderedAttr("styleClass", "styleClass", "class=\"styleClass\""),
195             //_TabindexProperty
196             new HtmlRenderedAttr("tabindex")
197         };
198         
199         return attrs;
200     }
201     
202     public static HtmlRenderedAttr[] generateAttrsNotRenderedForReadOnly() 
203     {
204         HtmlRenderedAttr[] attrs = {
205             //_AccesskeyProperty
206             new HtmlRenderedAttr("accesskey", 0),
207             //_FocusBlurProperties
208             new HtmlRenderedAttr("onfocus", 0), 
209             new HtmlRenderedAttr("onblur", 0),
210             //_ChangeSelectProperties
211             new HtmlRenderedAttr("onchange", 0), 
212             new HtmlRenderedAttr("onselect", 0),
213             //_TabindexProperty
214             new HtmlRenderedAttr("tabindex", 0)
215         };
216         return attrs;
217     }
218     
219     public static HtmlRenderedAttr[] generateBasicReadOnlyAttrs() {
220         HtmlRenderedAttr[] attrs = {
221             //_UniversalProperties
222             new HtmlRenderedAttr("dir"), 
223             new HtmlRenderedAttr("lang"), 
224             new HtmlRenderedAttr("title"),
225             //_EventProperties
226             new HtmlRenderedAttr("onclick"), 
227             new HtmlRenderedAttr("ondblclick"), 
228             new HtmlRenderedAttr("onkeydown"), 
229             new HtmlRenderedAttr("onkeypress"),
230             new HtmlRenderedAttr("onkeyup"), 
231             new HtmlRenderedAttr("onmousedown"), 
232             new HtmlRenderedAttr("onmousemove"), 
233             new HtmlRenderedAttr("onmouseout"),
234             new HtmlRenderedAttr("onmouseover"), 
235             new HtmlRenderedAttr("onmouseup"),
236             //_StyleProperties
237             new HtmlRenderedAttr("style"), 
238             new HtmlRenderedAttr("styleClass", "styleClass", "class=\"styleClass\""),
239         };
240         
241         return attrs;
242     }
243 }