Author: johnh
Date: Wed Mar 10 01:43:58 2010
New Revision: 921204

URL: http://svn.apache.org/viewvc?rev=921204&view=rev
Log:
Using the Visitor paradigm, implements a rewriter that pulls all
<style>, <link rel="stylesheet"..>, and <link type="*css*"...> nodes
into <head> in document-relative order, adjacent to one another.

As noted in the comments, this maintains CSS semantics in all but the
most pathological cases while assisting in reducing browser repaints and
making concatenation operations more likely.

This CL also includes a StyleConcatContentRewriter impl using the
ConcatVisitor's CSS class.



Added:
    
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriter.java
    
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitor.java
    
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriter.java
    
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriterTest.java
    
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitorTest.java
    
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriterTest.java
Modified:
    
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java
    
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DomWalkerTestBase.java

Modified: 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java?rev=921204&r1=921203&r2=921204&view=diff
==============================================================================
--- 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java
 (original)
+++ 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/RewriteModule.java
 Wed Mar 10 01:43:58 2010
@@ -23,7 +23,6 @@ import org.apache.shindig.gadgets.render
 import org.apache.shindig.gadgets.render.old.SanitizingGadgetRewriter;
 import org.apache.shindig.gadgets.render.old.SanitizingRequestRewriter;
 import org.apache.shindig.gadgets.rewrite.old.CssRequestRewriter;
-import org.apache.shindig.gadgets.rewrite.old.HTMLContentRewriter;
 import org.apache.shindig.gadgets.servlet.CajaContentRewriter;
 
 import java.util.List;
@@ -57,7 +56,11 @@ public class RewriteModule extends Abstr
     @Inject
     public GadgetRewritersProvider(PipelineDataGadgetRewriter pipelineRewriter,
         TemplateRewriter templateRewriter,
-        HTMLContentRewriter optimizingRewriter,
+        StyleTagExtractorContentRewriter styleExtractorRewriter,
+        StyleAdjacencyContentRewriter styleAdjacentRewriter,
+        StyleConcatContentRewriter styleConcatRewriter,
+        ScriptConcatContentRewriter scriptConcatRewriter,
+        ProxyingContentRewriter proxyingRewriter,
         CssRequestRewriter cssRewriter,
         CajaContentRewriter cajaRewriter,
         SanitizingGadgetRewriter sanitizedRewriter,
@@ -66,7 +69,14 @@ public class RewriteModule extends Abstr
       rewriters = Lists.newArrayList();
       rewriters.add(pipelineRewriter);
       rewriters.add(templateRewriter);
-      rewriters.add(optimizingRewriter);
+
+      // Optimizing rewriters.
+      rewriters.add(styleExtractorRewriter);
+      rewriters.add(styleAdjacentRewriter);
+      rewriters.add(styleConcatRewriter);
+      rewriters.add(scriptConcatRewriter);
+      rewriters.add(proxyingRewriter);
+      
       rewriters.add(cajaRewriter);
       rewriters.add(sanitizedRewriter);
       rewriters.add(renderingRewriter);
@@ -83,10 +93,21 @@ public class RewriteModule extends Abstr
 
     @Inject
     public AccelRewritersProvider(
-        HTMLContentRewriter optimizingRewriter,
+        StyleTagExtractorContentRewriter styleExtractorRewriter,
+        StyleAdjacencyContentRewriter styleAdjacentRewriter,
+        StyleConcatContentRewriter styleConcatRewriter,
+        ScriptConcatContentRewriter scriptConcatRewriter,
+        ProxyingContentRewriter proxyingRewriter,
         CajaContentRewriter cajaRewriter) {
       rewriters = Lists.newArrayList();
-      rewriters.add(optimizingRewriter);
+
+      // Optimizing rewriters.
+      rewriters.add(styleExtractorRewriter);
+      rewriters.add(styleAdjacentRewriter);
+      rewriters.add(styleConcatRewriter);
+      rewriters.add(scriptConcatRewriter);
+      rewriters.add(proxyingRewriter);
+      
       rewriters.add(cajaRewriter);
     }
 
@@ -99,11 +120,23 @@ public class RewriteModule extends Abstr
     private final List<RequestRewriter> rewriters;
 
     @Inject
-    public RequestRewritersProvider(HTMLContentRewriter optimizingRewriter,
+    public RequestRewritersProvider(
+        StyleTagExtractorContentRewriter styleExtractorRewriter,
+        StyleAdjacencyContentRewriter styleAdjacentRewriter,
+        StyleConcatContentRewriter styleConcatRewriter,
+        ScriptConcatContentRewriter scriptConcatRewriter,
+        ProxyingContentRewriter proxyingRewriter,
         CssRequestRewriter cssRewriter,
         SanitizingRequestRewriter sanitizedRewriter) {
       rewriters = Lists.newArrayList();
-      rewriters.add(optimizingRewriter);
+
+      // Optimizing rewriters.
+      rewriters.add(styleExtractorRewriter);
+      rewriters.add(styleAdjacentRewriter);
+      rewriters.add(styleConcatRewriter);
+      rewriters.add(scriptConcatRewriter);
+      rewriters.add(proxyingRewriter);
+      
       rewriters.add(cssRewriter);
       rewriters.add(sanitizedRewriter);
     }

Added: 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriter.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriter.java?rev=921204&view=auto
==============================================================================
--- 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriter.java
 (added)
+++ 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriter.java
 Wed Mar 10 01:43:58 2010
@@ -0,0 +1,27 @@
+/*
+ * 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.shindig.gadgets.rewrite;
+
+import org.apache.shindig.gadgets.rewrite.DomWalker;
+
+public class StyleAdjacencyContentRewriter extends DomWalker.Rewriter {
+  public StyleAdjacencyContentRewriter() {
+    super(new StyleAdjacencyVisitor());
+  }
+}

Added: 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitor.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitor.java?rev=921204&view=auto
==============================================================================
--- 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitor.java
 (added)
+++ 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitor.java
 Wed Mar 10 01:43:58 2010
@@ -0,0 +1,83 @@
+/*
+ * 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.shindig.gadgets.rewrite;
+
+import org.apache.shindig.common.xml.DomUtil;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import java.util.List;
+
+/**
+ * Visitor that pulls all stylesheet nodes in a document to head, in
+ * the order they were found in the document. This maintains CSS semantics
+ * in all but the most pathological (JS manipulating CSS through stylesheets
+ * in an order-dependent way) cases while reducing browser reflows and making
+ * CSS concatenated-proxying more likely.
+ */
+public class StyleAdjacencyVisitor implements Visitor {
+  
+  public VisitStatus visit(Gadget gadget, Node node) throws RewritingException 
{
+    if (node.getNodeType() == Node.ELEMENT_NODE &&
+        ("style".equalsIgnoreCase(node.getNodeName()) ||
+         ("link".equalsIgnoreCase(node.getNodeName()) &&
+          ("stylesheet".equalsIgnoreCase(getAttrib(node, "rel")) ||
+           (getAttrib(node, "type").toLowerCase().contains("css")))))) {
+      // Reserve <style...>, <link rel="stylesheet"...>, or <link 
type="*css*"...>
+      return VisitStatus.RESERVE_TREE;
+    }
+    
+    return VisitStatus.BYPASS;
+  }
+  
+  public boolean revisit(Gadget gadget, List<Node> nodes)
+      throws RewritingException {
+    Node head = DomUtil.getFirstNamedChildNode(
+        nodes.get(0).getOwnerDocument().getDocumentElement(), "head");
+    
+    if (head == null) {
+      // Should never occur; do for paranoia's sake.
+      return false;
+    }
+    
+    for (Node node : nodes) {
+      // Append all at the end of head. Relative order is maintained.
+      head.appendChild(node.getParentNode().removeChild(node));
+    }
+    
+    return true;
+  }
+
+  private String getAttrib(Node node, String key) {
+    String value = null;
+    NamedNodeMap attribs = node.getAttributes();
+    for (int i = 0; i < attribs.getLength(); ++i) {
+      Attr attr = (Attr)attribs.item(i);
+      if (key.equalsIgnoreCase(attr.getName())) {
+        value = attr.getValue();
+        break;
+      }
+    }
+    return value == null ? "" : value;
+  }
+}

Added: 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriter.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriter.java?rev=921204&view=auto
==============================================================================
--- 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriter.java
 (added)
+++ 
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriter.java
 Wed Mar 10 01:43:58 2010
@@ -0,0 +1,48 @@
+/*
+ * 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.shindig.gadgets.rewrite;
+
+import com.google.inject.Inject;
+
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.rewrite.DomWalker;
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor;
+import org.apache.shindig.gadgets.uri.ConcatUriManager;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class StyleConcatContentRewriter extends DomWalker.Rewriter {
+  private final ContentRewriterFeature.Factory featureConfigFactory;
+  private final ConcatUriManager concatUriManager;
+  
+  @Inject
+  public StyleConcatContentRewriter(ContentRewriterFeature.Factory 
featureConfigFactory,
+      ConcatUriManager concatUriManager) {
+    this.featureConfigFactory = featureConfigFactory;
+    this.concatUriManager = concatUriManager;
+  }
+  
+  @Override
+  protected List<Visitor> makeVisitors(Gadget context, Uri gadgetUri) {
+    ContentRewriterFeature.Config config = featureConfigFactory.get(gadgetUri);
+    return Arrays.<Visitor>asList(new ConcatVisitor.Css(config, 
concatUriManager));
+  }
+}

Modified: 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DomWalkerTestBase.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DomWalkerTestBase.java?rev=921204&r1=921203&r2=921204&view=diff
==============================================================================
--- 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DomWalkerTestBase.java
 (original)
+++ 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/DomWalkerTestBase.java
 Wed Mar 10 01:43:58 2010
@@ -34,6 +34,7 @@ import org.w3c.dom.Attr;
 import org.w3c.dom.DOMImplementation;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
+import org.w3c.dom.Node;
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
@@ -72,6 +73,33 @@ public class DomWalkerTestBase {
     return elem;
   }
   
+  protected Element htmlDoc(Node[] headNodes, Node... bodyNodes) {
+    // Clear document of all nodes.
+    while (doc.hasChildNodes()) {
+      doc.removeChild(doc.getFirstChild());
+    }
+    
+    // Recreate document with valid HTML structure.
+    Element html = elem("html");
+    Element head = elem("head");
+    appendAll(head, headNodes);
+    Element body = elem("body");
+    appendAll(body, bodyNodes);
+    html.appendChild(head);
+    html.appendChild(body);
+    doc.appendChild(html);
+    
+    return html;
+  }
+  
+  private void appendAll(Node parent, Node[] children) {
+    if (children == null || children.length == 0) return;
+    
+    for (Node child : children) {
+      parent.appendChild(child);
+    }
+  }
+  
   protected Gadget gadget() {
     return gadget(false, false);
   }

Added: 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriterTest.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriterTest.java?rev=921204&view=auto
==============================================================================
--- 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriterTest.java
 (added)
+++ 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyContentRewriterTest.java
 Wed Mar 10 01:43:58 2010
@@ -0,0 +1,28 @@
+/*
+ * 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.shindig.gadgets.rewrite;
+
+import org.junit.Test;
+
+public class StyleAdjacencyContentRewriterTest {
+  @Test
+  public void implementIntegrationTests() throws Exception {
+    // TODO: what the method says
+  }
+}

Added: 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitorTest.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitorTest.java?rev=921204&view=auto
==============================================================================
--- 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitorTest.java
 (added)
+++ 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleAdjacencyVisitorTest.java
 Wed Mar 10 01:43:58 2010
@@ -0,0 +1,245 @@
+/*
+ * 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.shindig.gadgets.rewrite;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.apache.shindig.gadgets.rewrite.DomWalker.Visitor.VisitStatus;
+
+import org.w3c.dom.Node;
+
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableList;
+
+public class StyleAdjacencyVisitorTest extends DomWalkerTestBase {
+  @Test
+  public void visitStyle() throws Exception {
+    Node node = elem("style");
+    assertEquals(VisitStatus.RESERVE_TREE, visit(node));
+  }
+  
+  @Test
+  public void visitLinkWithRel() throws Exception {
+    Node node = elem("link", "rel", "stylesheet");
+    assertEquals(VisitStatus.RESERVE_TREE, visit(node));
+  }
+  
+  @Test
+  public void visitLinkWithType() throws Exception {
+    Node node = elem("link", "type", "text/css");
+    assertEquals(VisitStatus.RESERVE_TREE, visit(node));
+  }
+  
+  @Test
+  public void visitStyleCaseInsensitive() throws Exception {
+    Node node = elem("sTYlE");
+    assertEquals(VisitStatus.RESERVE_TREE, visit(node));
+  }
+  
+  @Test
+  public void visitLinkCaseInsensitive() throws Exception {
+    Node node = elem("lINK", "REL", "stYlEsheet");
+    assertEquals(VisitStatus.RESERVE_TREE, visit(node));
+    node = elem("LINk", "tyPe", "csS");
+    assertEquals(VisitStatus.RESERVE_TREE, visit(node));
+  }
+  
+  @Test
+  public void visitStyleWithAttribs() throws Exception {
+    Node node = elem("style", "foo", "bar");
+    assertEquals(VisitStatus.RESERVE_TREE, visit(node));
+  }
+  
+  @Test
+  public void bypassUnknownElement() throws Exception {
+    Node node = elem("div");
+    assertEquals(VisitStatus.BYPASS, visit(node));
+  }
+  
+  @Test
+  public void bypassLinkWithoutAttribs() throws Exception {
+    Node node = elem("link");
+    assertEquals(VisitStatus.BYPASS, visit(node));
+  }
+  
+  @Test
+  public void bypassText() throws Exception {
+    Node node = doc.createTextNode("text");
+    assertEquals(VisitStatus.BYPASS, visit(node));
+  }
+  
+  @Test
+  public void bypassComment() throws Exception {
+    Node node = doc.createComment("comment");
+    assertEquals(VisitStatus.BYPASS, visit(node));
+  }
+  
+  @Test
+  public void reshuffleSingleNodeInHead() throws Exception {
+    Node style = elem("style");
+    Node html = htmlDoc(new Node[] { elem("script"), doc.createTextNode("foo"),
+        style, doc.createComment("comment") });
+    assertTrue(revisit(style));
+    
+    // Document structure sanity tests.
+    assertEquals(2, html.getChildNodes().getLength());
+    Node head = html.getFirstChild();
+    assertEquals("head", head.getNodeName());
+    Node body = html.getLastChild();
+    assertEquals("body", body.getNodeName());
+    
+    // Reshuffling validation.
+    assertEquals(4, head.getChildNodes().getLength());
+    assertSame(style, head.getChildNodes().item(3)); // Last.
+  }
+  
+  @Test
+  public void reshuffleSingleNodeFromBody() throws Exception {
+    Node style = elem("style");
+    Node html = htmlDoc(new Node[] { elem("foo") }, elem("script"), 
doc.createTextNode("foo"),
+        style, doc.createComment("comment"));
+    assertTrue(revisit(style));
+    
+    // Document structure sanity tests.
+    assertEquals(2, html.getChildNodes().getLength());
+    Node head = html.getFirstChild();
+    assertEquals("head", head.getNodeName());
+    Node body = html.getLastChild();
+    assertEquals("body", body.getNodeName());
+    
+    // Reshuffling validation.
+    assertEquals(2, head.getChildNodes().getLength());
+    assertSame(style, head.getChildNodes().item(1)); // Last.
+    assertEquals(3, body.getChildNodes().getLength());
+  }
+  
+  @Test
+  public void reshuffleMultipleStyleNodes() throws Exception {
+    Node style1 = elem("style");
+    Node style2 = elem("style");
+    Node style3 = elem("style");
+    
+    // Some in head, some in body.
+    Node html = htmlDoc(new Node[] { elem("script"), style1, elem("foo") },
+        doc.createTextNode("text1"), style2, doc.createComment("comment"), 
elem("div"),
+        style3);
+    assertTrue(revisit(style1, style2, style3));
+
+    // Document structure sanity tests.
+    assertEquals(2, html.getChildNodes().getLength());
+    Node head = html.getFirstChild();
+    assertEquals("head", head.getNodeName());
+    Node body = html.getLastChild();
+    assertEquals("body", body.getNodeName());
+    
+    // Reshuffling validation.
+    assertEquals(5, head.getChildNodes().getLength());
+    assertSame(style1, head.getChildNodes().item(2));
+    assertSame(style2, head.getChildNodes().item(3));
+    assertSame(style3, head.getChildNodes().item(4));
+    assertEquals(3, body.getChildNodes().getLength());
+  }
+  
+  @Test
+  public void reshuffleMultipleLinkNodes() throws Exception {
+    Node link1 = elem("link", "rel", "stylesheet");
+    Node link2 = elem("link", "rel", "stylesheet");
+    Node link3 = elem("link", "rel", "stylesheet");
+    
+    // Some in head, some in body.
+    Node html = htmlDoc(new Node[] { elem("script"), link1, elem("foo") },
+        doc.createTextNode("text1"), link2, doc.createComment("comment"), 
elem("div"),
+        link3);
+    assertTrue(revisit(link1, link2, link3));
+
+    // Document structure sanity tests.
+    assertEquals(2, html.getChildNodes().getLength());
+    Node head = html.getFirstChild();
+    assertEquals("head", head.getNodeName());
+    Node body = html.getLastChild();
+    assertEquals("body", body.getNodeName());
+    
+    // Reshuffling validation.
+    assertEquals(5, head.getChildNodes().getLength());
+    assertSame(link1, head.getChildNodes().item(2));
+    assertSame(link2, head.getChildNodes().item(3));
+    assertSame(link3, head.getChildNodes().item(4));
+    assertEquals(3, body.getChildNodes().getLength());
+  }
+  
+  @Test
+  public void reshuffleMultiMatchedNodes() throws Exception {
+    Node style1 = elem("style");
+    Node style2 = elem("style");
+    Node link1 = elem("link", "rel", "stylesheet");
+    Node link2 = elem("link", "type", "text/css");
+    
+    // Some in head, some in body, one embedded.
+    Node div = elem("div");
+    div.appendChild(style2);
+    Node html = htmlDoc(new Node[] { elem("base"), elem("script"), 
elem("script"), style1,
+        doc.createComment("comment"), link1 },
+        elem("div"), div, link2, doc.createTextNode("text"));
+    assertTrue(revisit(style1, link1, style2, link2));
+
+    // Document structure sanity tests.
+    assertEquals(2, html.getChildNodes().getLength());
+    Node head = html.getFirstChild();
+    assertEquals("head", head.getNodeName());
+    Node body = html.getLastChild();
+    assertEquals("body", body.getNodeName());
+    
+    // Reshuffling validation.
+    assertEquals(8, head.getChildNodes().getLength());
+    assertSame(style1, head.getChildNodes().item(4));
+    assertSame(link1, head.getChildNodes().item(5));
+    assertSame(style2, head.getChildNodes().item(6));
+    assertSame(link2, head.getChildNodes().item(7));
+    assertEquals(0, div.getChildNodes().getLength());
+    assertEquals(3, body.getChildNodes().getLength());
+  }
+  
+  @Test
+  public void avoidReshufflingInHeadlessDocument() throws Exception {
+    Node style = elem("style");
+    Node html = elem("html");
+    Node body = elem("body");
+    body.appendChild(style);
+    html.appendChild(body);
+    doc.appendChild(html);
+    
+    assertFalse(revisit(style));
+    
+    // Document structure sanity tests.
+    assertEquals(1, html.getChildNodes().getLength());
+    assertSame(body, html.getFirstChild());
+  }
+  
+  private VisitStatus visit(Node node) throws Exception {
+    return new StyleAdjacencyVisitor().visit(gadget(), node);
+  }
+  
+  private boolean revisit(Node... nodes) throws Exception {
+    return new StyleAdjacencyVisitor().revisit(gadget(), 
ImmutableList.<Node>of(nodes));
+  }
+}

Added: 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriterTest.java
URL: 
http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriterTest.java?rev=921204&view=auto
==============================================================================
--- 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriterTest.java
 (added)
+++ 
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/StyleConcatContentRewriterTest.java
 Wed Mar 10 01:43:58 2010
@@ -0,0 +1,28 @@
+/*
+ * 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.shindig.gadgets.rewrite;
+
+import org.junit.Test;
+
+public class StyleConcatContentRewriterTest {
+  @Test
+  public void implementIntegrationTests() throws Exception {
+    // TODO: what the method says
+  }
+}


Reply via email to