You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by sv...@apache.org on 2016/08/01 08:49:46 UTC

wicket git commit: WICKET-6220 improved support for void elements; unified code for createTagsXXX and createTagXX

Repository: wicket
Updated Branches:
  refs/heads/WICKET-6220-tag-tester-void-elements b27e6aca9 -> 069735395


WICKET-6220 improved support for void elements; unified code for createTagsXXX and createTagXX


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/06973539
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/06973539
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/06973539

Branch: refs/heads/WICKET-6220-tag-tester-void-elements
Commit: 069735395955b6a68347fae61217df05811d8a43
Parents: b27e6ac
Author: Sven Meier <sv...@apache.org>
Authored: Mon Aug 1 10:49:21 2016 +0200
Committer: Sven Meier <sv...@apache.org>
Committed: Mon Aug 1 10:49:21 2016 +0200

----------------------------------------------------------------------
 .../apache/wicket/util/tester/TagTester.java    | 302 +++++++------------
 .../wicket/util/tester/TagTesterTest.java       | 114 ++++++-
 2 files changed, 214 insertions(+), 202 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/06973539/wicket-core/src/main/java/org/apache/wicket/util/tester/TagTester.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/util/tester/TagTester.java b/wicket-core/src/main/java/org/apache/wicket/util/tester/TagTester.java
index 04f8280..610b181 100644
--- a/wicket-core/src/main/java/org/apache/wicket/util/tester/TagTester.java
+++ b/wicket-core/src/main/java/org/apache/wicket/util/tester/TagTester.java
@@ -16,20 +16,22 @@
  */
 package org.apache.wicket.util.tester;
 
+import static org.apache.wicket.markup.parser.filter.HtmlHandler.requiresCloseTag;
+
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
-import java.util.Map;
+import java.util.Stack;
+import java.util.function.Function;
 import java.util.regex.Pattern;
 
 import org.apache.wicket.WicketRuntimeException;
 import org.apache.wicket.markup.parser.XmlPullParser;
 import org.apache.wicket.markup.parser.XmlTag;
-import org.apache.wicket.markup.parser.filter.HtmlHandler;
 import org.apache.wicket.util.lang.Args;
 import org.apache.wicket.util.string.Strings;
 import org.apache.wicket.util.value.IValueMap;
 
-
 /**
  * Tag tester is used to test that a generated markup tag contains the correct attributes, values
  * etc. This can be done instead of comparing generated markup with some expected markup. The
@@ -359,7 +361,8 @@ public class TagTester
 	 */
 	public String getValue()
 	{
-		if (openTag == closeTag) {
+		if (openTag == closeTag)
+		{
 			return null;
 		}
 
@@ -374,85 +377,33 @@ public class TagTester
 	 * that it will return the first tag which matches the criteria.
 	 *
 	 * @param markup
-	 *            the markup to look for the tag to create the <code>TagTester</code> from
-	 *            the value which the attribute must have
+	 *            the markup to look for the tag to create the <code>TagTester</code> from the value
+	 *            which the attribute must have
 	 * @return the <code>TagTester</code> which matches the tag by name in the markup
 	 */
-	public static TagTester createTagByAttribute(String markup, String tagName)
+	public static TagTester createTagByName(String markup, String tagName)
 	{
-		TagTester tester = null;
-
-		if (Strings.isEmpty(markup) == false && Strings.isEmpty(tagName) == false)
+		List<TagTester> tester = createTags(markup, xmlTag -> xmlTag.getName().equalsIgnoreCase(tagName), true);
+		if ((tester == null) || (tester.size() == 0))
 		{
-			try
-			{
-				// remove the CDATA and
-				// the id attribute of the component because it is often the same as the element's id
-				markup = AJAX_COMPONENT_CDATA_OPEN.matcher(markup).replaceAll("<component>");
-				markup = AJAX_COMPONENT_CDATA_CLOSE.matcher(markup).replaceAll("</component>");
-
-				XmlPullParser parser = new XmlPullParser();
-				parser.parse(markup);
-
-				XmlTag elm;
-				XmlTag openTag = null;
-				XmlTag closeTag = null;
-				int level = 0;
-				while ((elm = parser.nextTag()) != null && closeTag == null)
-				{
-					XmlTag xmlTag = elm;
-
-					String xmlTagName = xmlTag.getName();
-					if (openTag == null && xmlTagName.equalsIgnoreCase(tagName))
-					{
-						if (xmlTag.isOpen())
-						{
-							openTag = xmlTag;
-						}
-						else if (xmlTag.isOpenClose())
-						{
-							openTag = xmlTag;
-							closeTag = xmlTag;
-						}
-					}
-					else if (openTag != null)
-					{
-						String openTagName = openTag.getName();
-						if (xmlTag.isOpen() && xmlTagName.equals(openTagName))
-						{
-							level++;
-						}
-
-						if (xmlTag.isClose())
-						{
-							if (xmlTagName.equals(openTagName))
-							{
-								if (level == 0)
-								{
-									closeTag = xmlTag;
-									closeTag.setOpenTag(openTag);
-								}
-								else
-								{
-									level--;
-								}
-							}
-						}
-					}
-				}
-
-				if (openTag != null && closeTag != null)
-				{
-					tester = new TagTester(parser, openTag, closeTag);
-				}
-			}
-			catch (Exception e)
-			{
-				throw new WicketRuntimeException(e);
-			}
+			return null;
 		}
+		return tester.get(0);
+	}
 
-		return tester;
+	/**
+	 * Static factory method for creating a <code>TagTester</code> based on a tag name. Please note
+	 * that it will return the first tag which matches the criteria.
+	 *
+	 * @param markup
+	 *            the markup to look for the tag to create the <code>TagTester</code> from the value
+	 *            which the attribute must have
+	 * @return the <code>TagTester</code> which matches the tag by name in the markup
+	 */
+	@Deprecated
+	public static TagTester createTagByAttribute(String markup, String tagName)
+	{
+		return createTagByName(markup, tagName);
 	}
 
 	/**
@@ -472,97 +423,18 @@ public class TagTester
 	 */
 	public static TagTester createTagByAttribute(String markup, String attribute, String value)
 	{
-		TagTester tester = null;
-
-		if (Strings.isEmpty(markup) == false && Strings.isEmpty(attribute) == false &&
-			Strings.isEmpty(value) == false)
+		List<TagTester> tester = createTagsByAttribute(markup, attribute, value, true);
+		if ((tester == null) || (tester.size() == 0))
 		{
-			try
-			{
-				// remove the CDATA and
-				// the id attribute of the component because it is often the same as the element's id
-				markup = AJAX_COMPONENT_CDATA_OPEN.matcher(markup).replaceAll("<component>");
-				markup = AJAX_COMPONENT_CDATA_CLOSE.matcher(markup).replaceAll("</component>");
-
-				XmlPullParser parser = new XmlPullParser();
-				parser.parse(markup);
-
-				XmlTag elm;
-				XmlTag openTag = null;
-				XmlTag closeTag = null;
-				int level = 0;
-				while ((elm = parser.nextTag()) != null && closeTag == null)
-				{
-					XmlTag xmlTag = elm;
-
-					if (openTag == null)
-					{
-						IValueMap attributeMap = xmlTag.getAttributes();
-
-						for (Map.Entry<String, Object> entry : attributeMap.entrySet())
-						{
-							String attr = entry.getKey();
-							if (attr.equals(attribute) && value.equals(entry.getValue()))
-							{
-								if (xmlTag.isOpen())
-								{
-									openTag = xmlTag;
-								}
-								else if (xmlTag.isOpenClose())
-								{
-									openTag = xmlTag;
-									closeTag = xmlTag;
-								}
-							}
-						}
-					}
-					else
-					{
-						if (xmlTag.isOpen() && xmlTag.getName().equals(openTag.getName()))
-						{
-							level++;
-						}
-
-						if (xmlTag.isClose())
-						{
-							if (xmlTag.getName().equals(openTag.getName()))
-							{
-								if (level == 0)
-								{
-									closeTag = xmlTag;
-									closeTag.setOpenTag(openTag);
-								}
-								else
-								{
-									level--;
-								}
-							}
-						}
-					}
-				}
-
-				if (openTag != null && closeTag != null)
-				{
-					tester = new TagTester(parser, openTag, closeTag);
-				}
-				else if (openTag != null)
-				{
-					tester = new TagTester(parser, openTag, openTag);
-				}
-			}
-			catch (Exception e)
-			{
-				throw new WicketRuntimeException(e);
-			}
+			return null;
 		}
-
-		return tester;
+		return tester.get(0);
 	}
 
 	/**
 	 * Static factory method for creating a <code>TagTester</code> based on a tag found by an
 	 * attribute with a specific value. Please note that it will return the first tag which matches
-	 * the criteria. It's therefore good for attributes such as "id" or "wicket:id", but only if
+	 * the criteria. It's therefore good for attributes suck as "id" or "wicket:id", but only if
 	 * "wicket:id" is unique in the specified markup.
 	 * 
 	 * @param markup
@@ -574,14 +446,33 @@ public class TagTester
 	 * @return the <code>TagTester</code> which matches the tag in the markup, that has the given
 	 *         value on the given attribute
 	 */
+	@Deprecated
 	public static TagTester createTagsByAttribute(String markup, String attribute, String value)
 	{
-		List<TagTester> tester = createTagsByAttribute(markup, attribute, value, true);
-		if ((tester == null) || (tester.size() == 0))
+		return createTagByAttribute(markup, attribute, value);
+	}
+
+	/**
+	 * find the correct openTag to the given closeTag and remove all unclosed openTags between both
+	 * in given array {@code stack}
+	 * 
+	 * @param closeTag
+	 *            tag to search for corresponding openTag
+	 * @param stack
+	 *            array of unclosed openTags
+	 * @return corresponding openTag or {@code null}
+	 */
+	private static XmlTag findOpenTag(XmlTag closeTag, Stack<XmlTag> stack)
+	{
+		while (stack.size() > 0)
 		{
-			return null;
+			XmlTag popped = stack.pop();
+			if (popped.getName().equals(closeTag.getName()))
+			{
+				return popped;
+			}
 		}
-		return tester.get(0);
+		return null;
 	}
 
 	/**
@@ -601,13 +492,20 @@ public class TagTester
 	 * @return the <code>TagTester</code> which matches the tag in the markup, that has the given
 	 *         value on the given attribute
 	 */
-	public static List<TagTester> createTagsByAttribute(String markup, String attribute,
-		String value, boolean stopAfterFirst)
+	public static List<TagTester> createTagsByAttribute(String markup, String attribute, String value, boolean stopAfterFirst)
+	{
+		if (Strings.isEmpty(attribute) || Strings.isEmpty(value)) {
+			return Collections.emptyList();
+		}
+		
+		return createTags(markup, xmlTag -> value.equals(xmlTag.getAttributes().get(attribute)), stopAfterFirst);
+	}
+	
+	public static List<TagTester> createTags(String markup, Function<XmlTag, Boolean> accept, boolean stopAfterFirst)
 	{
 		List<TagTester> testers = new ArrayList<>();
 
-		if ((Strings.isEmpty(markup) == false) && (Strings.isEmpty(attribute) == false) &&
-			(Strings.isEmpty(value) == false))
+		if ((Strings.isEmpty(markup) == false))
 		{
 			try
 			{
@@ -619,70 +517,74 @@ public class TagTester
 				XmlPullParser parser = new XmlPullParser();
 				parser.parse(markup);
 
-				XmlTag elm;
 				XmlTag openTag = null;
 				XmlTag closeTag = null;
-				int level = 0;
-				while ((elm = parser.nextTag()) != null)
+
+				// temporary Tag-Hierarchy after openTag
+				Stack<XmlTag> stack = new Stack<>();
+
+				while (true)
 				{
-					XmlTag xmlTag = elm;
+					XmlTag xmlTag = parser.nextTag();
+					if (xmlTag == null)
+					{
+						break;
+					}
+					
 					if (openTag == null)
 					{
-						IValueMap attributeMap = xmlTag.getAttributes();
-						for (Map.Entry<String, Object> entry : attributeMap.entrySet())
+						if (accept.apply(xmlTag))
 						{
-							if (entry.getKey().equals(attribute) && value.equals(entry.getValue()))
+							if (xmlTag.isOpen())
 							{
-								if (xmlTag.isOpen())
-								{
-									openTag = xmlTag;
-								}
-								else if (xmlTag.isOpenClose())
-								{
-									openTag = xmlTag;
-									closeTag = xmlTag;
-								}
+								openTag = xmlTag;
+							}
+							else if (xmlTag.isOpenClose())
+							{
+								openTag = xmlTag;
+								closeTag = xmlTag;
 							}
 						}
 					}
 					else
 					{
-						if (xmlTag.isOpen() && xmlTag.getName().equals(openTag.getName()))
+						if (xmlTag.isOpen() && !xmlTag.isOpenClose())
 						{
-							level++;
+							stack.push(xmlTag);
 						}
-
 						if (xmlTag.isClose())
 						{
-							if (xmlTag.getName().equals(openTag.getName()))
+							XmlTag foundTag = findOpenTag(xmlTag, stack);
+							if (foundTag == null)
 							{
-								if (level == 0)
+								if (xmlTag.getName().equals(openTag.getName()))
 								{
 									closeTag = xmlTag;
 									closeTag.setOpenTag(openTag);
 								}
+								else if (requiresCloseTag(openTag.getName()) == false)
+								{
+									// no closeTag for current openTag (allowed)
+									closeTag = openTag;
+								}
 								else
 								{
-									level--;
+									// no closeTag for current openTag (invalid structure)
+									// thus reset state
+									openTag = null;
+									closeTag = null;
 								}
 							}
 						}
 					}
 
-					if ((openTag != null) && (closeTag != null) && (level == 0))
+					if ((openTag != null) && (closeTag != null))
 					{
 						TagTester tester = new TagTester(parser, openTag, closeTag);
 						testers.add(tester);
 						openTag = null;
 						closeTag = null;
 					}
-					else if (openTag != null && !HtmlHandler.requiresCloseTag(openTag.getName()))
-					{
-						TagTester tester = new TagTester(parser, openTag, openTag);
-						testers.add(tester);
-						openTag = null;
-						closeTag = null;
-					}
 
 					if (stopAfterFirst && (closeTag != null))
 					{
@@ -698,4 +600,4 @@ public class TagTester
 
 		return testers;
 	}
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/wicket/blob/06973539/wicket-core/src/test/java/org/apache/wicket/util/tester/TagTesterTest.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/test/java/org/apache/wicket/util/tester/TagTesterTest.java b/wicket-core/src/test/java/org/apache/wicket/util/tester/TagTesterTest.java
index d184869..f992310 100644
--- a/wicket-core/src/test/java/org/apache/wicket/util/tester/TagTesterTest.java
+++ b/wicket-core/src/test/java/org/apache/wicket/util/tester/TagTesterTest.java
@@ -342,7 +342,117 @@ public class TagTesterTest extends Assert
 	@Test
 	public void valueFromTagsByAttribute()
 	{
-		TagTester tagTester = TagTester.createTagsByAttribute(MARKUP_1, "id", "test2");
+		TagTester tagTester = TagTester.createTagByAttribute(MARKUP_1, "id", "test2");
 		assertEquals("mock", tagTester.getValue());
 	}
-}
+	
+    private static final String MARKUP =
+        "<wicket:panel>" +
+            "<ul wicket:id=\"container\">" +
+                "<wicket:container wicket:id=\"items\">" +
+                    "<li wicket:id=\"item\" id=\"item1\">" +
+                        "<p wicket:id=\"p\" id=\"p1\">" +
+                            "<img wicket:id=\"img\" src=\"bild1.jpg\">" +
+                        "</p>" +
+                        "<hr wicket:id=\"hr\" id=\"hr1\"/>" +
+                    "</li>" +
+                    "<li wicket:id=\"item\" id=\"item2\">" +
+                        "<p wicket:id=\"p\" id=\"p2\">" +
+                        "<img wicket:id=\"img\" src=\"bild2.jpg\">" +
+                        "<hr wicket:id=\"hr\" id=\"hr2\"/>" +
+                    "</li>" +
+                "</wicket:container>" +
+            "</ul>" +
+        "</wicket:panel>";
+
+    private static final String WRONG_MARKUP =
+        "<wicket:panel>" +
+            "<ul wicket:id=\"container\">" +
+                "<wicket:container wicket:id=\"items\">" +
+                    "<li wicket:id=\"item\" id=\"item1\">" +
+                        "<span wicket:id=\"p\" id=\"p1\">" +
+                        "<img wicket:id=\"img\" src=\"bild1.jpg\">" +
+                        "<hr wicket:id=\"hr\" id=\"hr1\"/>" +
+                    "</li>" +
+                    "<li wicket:id=\"item\" id=\"item2\">" +
+                        "<span wicket:id=\"p\" id=\"p2\">" +
+                            "<img wicket:id=\"img\" src=\"bild2.jpg\">" +
+                            "<hr wicket:id=\"hr\" id=\"hr2\"/>" +
+                        "</span>" +
+                    "</li>" +
+                "</wicket:container>" +
+            "</ul>" +
+        "</wicket:panel>";
+
+    /**
+     * WICKET-6220
+     */
+    @Test
+    public void testOpenAndClose() {
+        List<TagTester> tags = TagTester.createTagsByAttribute(MARKUP, "wicket:id", "item", false);
+        assertEquals(2, tags.size());
+        assertEquals("li", tags.get(0).getName());
+        assertEquals("item1", tags.get(0).getAttribute("id"));
+        assertEquals("<p wicket:id=\"p\" id=\"p1\"><img wicket:id=\"img\" src=\"bild1.jpg\"></p><hr wicket:id=\"hr\" id=\"hr1\"/>", tags.get(0).getValue());
+        assertEquals("li", tags.get(1).getName());
+        assertEquals("item2", tags.get(1).getAttribute("id"));
+        assertEquals("<p wicket:id=\"p\" id=\"p2\"><img wicket:id=\"img\" src=\"bild2.jpg\"><hr wicket:id=\"hr\" id=\"hr2\"/>", tags.get(1).getValue());
+    }
+
+    /**
+     * WICKET-6220
+     */
+    @Test
+    public void testWrongHtmlStructure() {
+        List<TagTester> tags = TagTester.createTagsByAttribute(WRONG_MARKUP, "wicket:id", "p", false);
+        assertEquals(1, tags.size());
+        assertEquals("span", tags.get(0).getName());
+        assertEquals("p2", tags.get(0).getAttribute("id"));
+        assertEquals("<img wicket:id=\"img\" src=\"bild2.jpg\"><hr wicket:id=\"hr\" id=\"hr2\"/>", tags.get(0).getValue());
+    }
+
+    /**
+     * WICKET-6220
+     */
+    @Test
+    public void testOpenOrClose() {
+        List<TagTester> tags = TagTester.createTagsByAttribute(MARKUP, "wicket:id", "p", false);
+        assertEquals(2, tags.size());
+        assertEquals("p", tags.get(0).getName());
+        assertEquals("p1", tags.get(0).getAttribute("id"));
+        assertEquals("<img wicket:id=\"img\" src=\"bild1.jpg\">", tags.get(0).getValue());
+        assertEquals("p", tags.get(1).getName());
+        assertEquals("p2", tags.get(1).getAttribute("id"));
+        assertEquals("<p wicket:id=\"p\" id=\"p2\">", tags.get(1).getMarkup());
+    }
+
+    /**
+     * WICKET-6220
+     */
+    @Test
+    public void testOpen() {
+        List<TagTester> tags = TagTester.createTagsByAttribute(MARKUP, "wicket:id", "img", false);
+        assertEquals(2, tags.size());
+        assertEquals("img", tags.get(0).getName());
+        assertEquals("bild1.jpg", tags.get(0).getAttribute("src"));
+        assertEquals("<img wicket:id=\"img\" src=\"bild1.jpg\">", tags.get(0).getMarkup());
+        assertEquals("img", tags.get(1).getName());
+        assertEquals("bild2.jpg", tags.get(1).getAttribute("src"));
+        assertEquals("<img wicket:id=\"img\" src=\"bild2.jpg\">", tags.get(1).getMarkup());
+    }
+
+    /**
+     * WICKET-6220
+     */
+    @Test
+    public void testOpenClose() {
+        List<TagTester> tags = TagTester.createTagsByAttribute(MARKUP, "wicket:id", "hr", false);
+        assertEquals(2, tags.size());
+        assertEquals("hr", tags.get(0).getName());
+        assertEquals("hr1", tags.get(0).getAttribute("id"));
+        assertEquals("<hr wicket:id=\"hr\" id=\"hr1\"/>", tags.get(0).getMarkup());
+        assertEquals("hr", tags.get(1).getName());
+        assertEquals("hr2", tags.get(1).getAttribute("id"));
+        assertEquals("<hr wicket:id=\"hr\" id=\"hr2\"/>", tags.get(1).getMarkup());
+    }	
+}
\ No newline at end of file