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 <[email protected]>
Authored: Mon Aug 1 10:49:21 2016 +0200
Committer: Sven Meier <[email protected]>
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

Reply via email to