| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.struts2.views.jsp; |
| |
| import com.opensymphony.xwork2.ActionContext; |
| import org.apache.commons.beanutils.BeanUtils; |
| import org.apache.logging.log4j.LogManager; |
| import org.apache.logging.log4j.Logger; |
| import org.apache.struts2.ServletActionContext; |
| import org.apache.struts2.dispatcher.mapper.ActionMapper; |
| import org.apache.struts2.dispatcher.mapper.DefaultActionMapper; |
| import org.apache.struts2.views.jsp.ui.AbstractUITag; |
| |
| import java.io.InputStream; |
| import java.net.URL; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| |
| public abstract class AbstractUITagTest extends AbstractTagTest { |
| |
| private static final Logger LOG = LogManager.getLogger(AbstractUITagTest.class); |
| |
| static final String FREEMARKER_ERROR_EXPECTATION = "Java backtrace for programmers:"; |
| |
| /** |
| * Simple helper class for generic tag property testing mechanism. Basically it holds a property name, a property |
| * value and an output to be expected in tag output when property was accordingly set. |
| * |
| * @author <a href="mailto:gielen@it-neering.net">Rene Gielen</a> |
| */ |
| public static class PropertyHolder { |
| String name, value, expectation; |
| |
| public String getName() { |
| return name; |
| } |
| |
| public String getValue() { |
| return value; |
| } |
| |
| public String getExpectation() { |
| return expectation; |
| } |
| |
| /** |
| * Construct simple holder with default expectation. |
| * |
| * @param name The property name to use. |
| * @param value The property value to set. |
| * @see #PropertyHolder(String, String, String) |
| */ |
| public PropertyHolder(String name, String value) { |
| this(name, value, null); |
| } |
| |
| /** |
| * Construct property holder. |
| * |
| * @param name The property name to use. |
| * @param value The property value to set. |
| * @param expectation The expected String to occur in tag output caused by setting given tag property. If |
| * <tt>null</tt>, will be set to <pre>name + "=\"" + value + "\"</pre>. |
| */ |
| public PropertyHolder(String name, String value, String expectation) { |
| this.name = name; |
| this.value = value; |
| if (expectation != null) { |
| this.expectation = expectation; |
| } else { |
| this.expectation = name + "=\"" + value + "\""; |
| } |
| } |
| |
| /** |
| * Convenience method for easily adding anonymous constructed instance to a given map, with {@link #getName()} |
| * as key. |
| * |
| * @param map The map to place this instance in. |
| */ |
| public void addToMap(Map<String, PropertyHolder> map) { |
| if (map != null) { |
| map.put(this.name, this); |
| } |
| } |
| } |
| |
| /** |
| * Initialize a map of {@link PropertyHolder} for generic tag property testing. Will be used when calling {@link |
| * #verifyGenericProperties(org.apache.struts2.views.jsp.ui.AbstractUITag, String, String[])} as properties to |
| * verify.<br> This implementation defines testdata for all common AbstractUITag properties and may be overridden in |
| * subclasses. |
| * |
| * @return A Map of PropertyHolders values bound to {@link org.apache.struts2.views.jsp.AbstractUITagTest.PropertyHolder#getName()} |
| * as key. |
| */ |
| protected Map<String, PropertyHolder> initializedGenericTagTestProperties() { |
| Map<String, PropertyHolder> result = new HashMap<>(); |
| new PropertyHolder("name", "someName").addToMap(result); |
| new PropertyHolder("id", "someId").addToMap(result); |
| new PropertyHolder("cssClass", "cssClass1", "class=\"cssClass1\"").addToMap(result); |
| new PropertyHolder("cssStyle", "cssStyle1", "style=\"cssStyle1\"").addToMap(result); |
| new PropertyHolder("title", "someTitle").addToMap(result); |
| new PropertyHolder("disabled", "true", "disabled=\"disabled\"").addToMap(result); |
| new PropertyHolder("tabindex", "99").addToMap(result); |
| new PropertyHolder("value", "someValue").addToMap(result); |
| new PropertyHolder("onclick", "onclick1").addToMap(result); |
| new PropertyHolder("ondblclick", "ondblclick1").addToMap(result); |
| new PropertyHolder("onmousedown", "onmousedown1").addToMap(result); |
| new PropertyHolder("onmouseup", "onmouseup1").addToMap(result); |
| new PropertyHolder("onmouseover", "onmouseover1").addToMap(result); |
| new PropertyHolder("onmousemove", "onmousemove1").addToMap(result); |
| new PropertyHolder("onmouseout", "onmouseout1").addToMap(result); |
| new PropertyHolder("onfocus", "onfocus1").addToMap(result); |
| new PropertyHolder("onblur", "onblur1").addToMap(result); |
| new PropertyHolder("onkeypress", "onkeypress1").addToMap(result); |
| new PropertyHolder("onkeydown", "onkeydown1").addToMap(result); |
| new PropertyHolder("onkeyup", "onkeyup1").addToMap(result); |
| new PropertyHolder("onclick", "onclick1").addToMap(result); |
| new PropertyHolder("onselect", "onchange").addToMap(result); |
| return result; |
| } |
| |
| /** |
| * Do a generic verification that setting certain properties on a tag causes expected output regarding this |
| * property. In most cases you would not call this directly, instead use {@link |
| * #verifyGenericProperties(org.apache.struts2.views.jsp.ui.AbstractUITag, String, String[])}. |
| * |
| * @param tag The fresh created tag instance to test. |
| * @param theme The theme to use. If <tt>null</tt>, use configured default theme. |
| * @param propertiesToTest Map of {@link PropertyHolder}s, defining properties to test. |
| * @param exclude Names of properties to exclude from particular test. |
| * @throws Exception |
| */ |
| public void verifyGenericProperties(AbstractUITag tag, String theme, Map<String, PropertyHolder> propertiesToTest, String[] exclude) throws Exception { |
| if (tag != null && propertiesToTest != null) { |
| List<String> excludeList; |
| if (exclude != null) { |
| excludeList = Arrays.asList(exclude); |
| } else { |
| excludeList = Collections.emptyList(); |
| } |
| |
| tag.setPageContext(pageContext); |
| if (theme != null) { |
| tag.setTheme(theme); |
| } |
| |
| for (PropertyHolder propertyHolder : propertiesToTest.values()) { |
| if (!excludeList.contains(propertyHolder.getName())) { |
| BeanUtils.setProperty(tag, propertyHolder.getName(), propertyHolder.getValue()); |
| } |
| } |
| |
| tag.setDynamicAttribute(null, "data-id", "id-random"); |
| |
| tag.doStartTag(); |
| tag.doEndTag(); |
| String writerString = normalize(writer.toString(), true); |
| LOG.debug("AbstractUITagTest - [verifyGenericProperties]: Tag output is {}", writerString); |
| |
| assertFalse("Freemarker error detected in tag output: " + writerString, writerString.contains(normalize(FREEMARKER_ERROR_EXPECTATION))); |
| |
| for (PropertyHolder propertyHolder : propertiesToTest.values()) { |
| if (!excludeList.contains(propertyHolder.getName())) { |
| assertTrue("Expected to find: " + propertyHolder.getExpectation() + " in resulting String: " + writerString, writerString.contains(propertyHolder.getExpectation())); |
| } |
| } |
| |
| assertTrue(writerString.contains("data-id=\"id-random\"")); |
| } |
| } |
| |
| /** |
| * Do a generic verification that setting certain properties on a tag causes expected output regarding this |
| * property. Which properties to test with which expectations will be determined by the Map retrieved by {@link #initializedGenericTagTestProperties()}. |
| * |
| * @param tag The fresh created tag instance to test. |
| * @param theme The theme to use. If <tt>null</tt>, use configured default theme. |
| * @param exclude Names of properties to exclude froObjectm particular test. |
| * @throws Exception |
| */ |
| public void verifyGenericProperties(AbstractUITag tag, String theme, String[] exclude) throws Exception { |
| verifyGenericProperties(tag, theme, initializedGenericTagTestProperties(), exclude); |
| } |
| |
| /** |
| * Attempt to verify the contents of this.writer against the contents of the resource specified. verify() performs a |
| * trim on both ends |
| * |
| * @param resource the HTML snippet that we want to validate against |
| * @throws Exception if the validation failed |
| */ |
| public void verifyResource(String resource) throws Exception { |
| verify(this.getClass().getResource(resource)); |
| } |
| |
| /** |
| * Attempt to verify the contents of this.writer against the contents of the URL specified. verify() performs a |
| * trim on both ends |
| * |
| * @param url the HTML snippet that we want to validate against |
| * @throws Exception if the validation failed |
| */ |
| public void verify(URL url) throws Exception { |
| if (url == null) { |
| fail("unable to verify a null URL"); |
| } else if (this.writer == null) { |
| fail("AbstractJspWriter.writer not initialized. Unable to verify"); |
| } |
| |
| StringBuilder buffer = new StringBuilder(128); |
| try (InputStream in = url.openStream()) { |
| byte[] buf = new byte[4096]; |
| int nbytes; |
| |
| while ((nbytes = in.read(buf)) > 0) { |
| buffer.append(new String(buf, 0, nbytes)); |
| } |
| } |
| |
| /* |
| * compare the trimmed values of each buffer and make sure they're equivalent. however, let's make sure to |
| * normalize the strings first to account for line termination differences between platforms. |
| */ |
| String writerString = normalize(writer.toString(), true); |
| String bufferString = normalize(buffer.toString(), true); |
| |
| assertEquals(bufferString, writerString); |
| } |
| |
| protected void setUp() throws Exception { |
| super.setUp(); |
| ((DefaultActionMapper) container.getInstance(ActionMapper.class)).setAllowDynamicMethodCalls("true"); |
| ServletActionContext.setServletContext(pageContext.getServletContext()); |
| } |
| |
| protected void tearDown() throws Exception { |
| super.tearDown(); |
| ActionContext.clear(); |
| } |
| |
| /** |
| * normalizes a string so that strings generated on different platforms can be compared. any group of one or more |
| * space, tab, \r, and \n characters are converted to a single space character |
| * |
| * @param obj the object to be normalized. normalize will perform its operation on obj.toString().trim() ; |
| * @return the normalized string |
| */ |
| public static String normalize(Object obj) { |
| return normalize(obj, false); |
| } |
| |
| /** |
| * normalizes a string so that strings generated on different platforms can be compared. any group of one or more |
| * space, tab, \r, and \n characters are converted to a single space character |
| * |
| * @param obj the object to be normalized. normalize will perform its operation on obj.toString().trim() ; |
| * @param appendSpace |
| * @return the normalized string |
| */ |
| public static String normalize(Object obj, boolean appendSpace) { |
| StringTokenizer st = new StringTokenizer(obj.toString().trim(), " \t\r\n"); |
| StringBuilder buffer = new StringBuilder(128); |
| |
| while (st.hasMoreTokens()) { |
| buffer.append(st.nextToken()); |
| |
| /* |
| if (appendSpace && st.hasMoreTokens()) { |
| buffer.append(""); |
| } |
| */ |
| } |
| |
| return buffer.toString(); |
| } |
| } |