/*
* 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.common.collect.Lists;
import org.apache.shindig.gadgets.Gadget;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Node;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class DomWalkerTest extends DomWalkerTestBase {
private Node root;
private Node child1;
private Node child2;
private Node subchild1;
private Node text1;
private Node text2;
@Override
@Before
public void setUp() {
super.setUp();
// Create a base document with structure:
// <root>
// <child1>text1</child1>
// <child2>
// <subchild1>text2</subchild1>
// </child2>
// </root>
// ...which should allow all relevant test cases to be exercised.
root = doc.createElement("root");
child1 = doc.createElement("child1");
text1 = doc.createTextNode("text1");
child1.appendChild(text1);
root.appendChild(child1);
child2 = doc.createElement("child2");
subchild1 = doc.createElement("subchild1");
text2 = doc.createTextNode("text2");
subchild1.appendChild(text2);
child2.appendChild(subchild1);
root.appendChild(child2);
doc.appendChild(root);
}
@Test
public void allBypassDoesNothing() throws Exception {
Gadget gadget = gadget();
// Visitor always bypasses nodes, never gets called with revisit(),
// but visits every node in the document.
DomWalker.Visitor visitor = createMock(DomWalker.Visitor.class);
expect(visitor.visit(gadget, root))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor.visit(gadget, child1))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor.visit(gadget, child2))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor.visit(gadget, subchild1))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor.visit(gadget, text1))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor.visit(gadget, text2))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
replay(visitor);
MutableContent mc = getContent(0);
DomWalker.Rewriter rewriter = getRewriter(visitor);
rewriter.rewrite(gadget, mc);
// Verifying mutations on MutableContent completes the test.
verify(mc);
}
@Test
public void allMutateMutatesEveryTime() throws Exception {
Gadget gadget = gadget();
// Visitor mutates every node it sees immediately and inline.
DomWalker.Visitor visitor = createMock(DomWalker.Visitor.class);
expect(visitor.visit(gadget, root))
.andReturn(DomWalker.Visitor.VisitStatus.MODIFY).once();
expect(visitor.visit(gadget, child1))
.andReturn(DomWalker.Visitor.VisitStatus.MODIFY).once();
expect(visitor.visit(gadget, child2))
.andReturn(DomWalker.Visitor.VisitStatus.MODIFY).once();
expect(visitor.visit(gadget, subchild1))
.andReturn(DomWalker.Visitor.VisitStatus.MODIFY).once();
expect(visitor.visit(gadget, text1))
.andReturn(DomWalker.Visitor.VisitStatus.MODIFY).once();
expect(visitor.visit(gadget, text2))
.andReturn(DomWalker.Visitor.VisitStatus.MODIFY).once();
replay(visitor);
MutableContent mc = getContent(6);
DomWalker.Rewriter rewriter = getRewriter(visitor);
rewriter.rewrite(gadget, mc);
// Verifying mutations on MutableContent completes the test.
verify(mc);
}
@Test
public void allReserveNodeReservesAll() throws Exception {
Gadget gadget = gadget();
// Visitor mutates every node it sees immediately and inline.
DomWalker.Visitor visitor = createMock(DomWalker.Visitor.class);
expect(visitor.visit(gadget, root))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_NODE).once();
expect(visitor.visit(gadget, child1))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_NODE).once();
expect(visitor.visit(gadget, child2))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_NODE).once();
expect(visitor.visit(gadget, subchild1))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_NODE).once();
expect(visitor.visit(gadget, text1))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_NODE).once();
expect(visitor.visit(gadget, text2))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_NODE).once();
// All nodes are revisited in DFS order.
List<Node> allReserved =
Lists.newArrayList(root, child1, text1, child2, subchild1, text2);
expect(visitor.revisit(gadget, allReserved))
.andReturn(true).once();
replay(visitor);
MutableContent mc = getContent(1); // Mutated each revisit.
DomWalker.Rewriter rewriter = getRewriter(visitor);
rewriter.rewrite(gadget, mc);
// Verifying mutations on MutableContent completes the test.
verify(mc);
}
@Test
public void reserveRootPrecludesAllElse() throws Exception {
Gadget gadget = gadget();
// Visitor1 reserves root, visitor2 never gets anything.
DomWalker.Visitor visitor1 = createMock(DomWalker.Visitor.class);
expect(visitor1.visit(gadget, root))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_TREE).once();
List<Node> allReserved = Lists.newArrayList(root);
expect(visitor1.revisit(gadget, allReserved))
.andReturn(true).once();
DomWalker.Visitor visitor2 = createMock(DomWalker.Visitor.class);
replay(visitor1, visitor2);
MutableContent mc = getContent(1); // Mutated once by revisit.
DomWalker.Rewriter rewriter = getRewriter(visitor1, visitor2);
rewriter.rewrite(gadget, mc);
// Verifying mutations on MutableContent completes the test.
verify(mc);
}
@Test
public void allMixedModes() throws Exception {
Gadget gadget = gadget();
// Visitor1 reserves single text node 1
DomWalker.Visitor visitor1 = createMock(DomWalker.Visitor.class);
expect(visitor1.visit(gadget, root))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor1.visit(gadget, child1))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_NODE).once();
expect(visitor1.visit(gadget, text1))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor1.visit(gadget, child2))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
// No visitation of text2 for visitor1 since visitor2 reserves the tree.
expect(visitor1.visit(gadget, subchild1))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
// No modification the second time around.
List<Node> reserved1 = Lists.newArrayList(child1);
expect(visitor1.revisit(gadget, reserved1))
.andReturn(false).once();
// Visitor2 reserves tree of subchild 1
DomWalker.Visitor visitor2 = createMock(DomWalker.Visitor.class);
expect(visitor2.visit(gadget, root))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
// No visitation of v1-reserved child 1
expect(visitor2.visit(gadget, text1))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor2.visit(gadget, child2))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor2.visit(gadget, subchild1))
.andReturn(DomWalker.Visitor.VisitStatus.RESERVE_TREE).once();
List<Node> reserved2 = Lists.newArrayList(subchild1);
expect(visitor2.revisit(gadget, reserved2))
.andReturn(true).once();
// Visitor3 modifies child 2
DomWalker.Visitor visitor3 = createMock(DomWalker.Visitor.class);
expect(visitor3.visit(gadget, root))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
// No visitation of v1-reserved child 1
expect(visitor3.visit(gadget, text1))
.andReturn(DomWalker.Visitor.VisitStatus.BYPASS).once();
expect(visitor3.visit(gadget, child2))
.andReturn(DomWalker.Visitor.VisitStatus.MODIFY).once();
// No visitation of tree of subchild 1
replay(visitor1, visitor2, visitor3);
MutableContent mc = getContent(2); // Once v2.revisit(), once v3.visit()
DomWalker.Rewriter rewriter = getRewriter(visitor1, visitor2, visitor3);
rewriter.rewrite(gadget, mc);
// As before, MutableContent verification is the test.
verify(mc);
}
@Test
public void rewriteThrowsRewritingExceptionIfGetDocumentIsNull() throws Exception {
DomWalker.Visitor visitor1 = createMock(DomWalker.Visitor.class);
DomWalker.Rewriter rewriter = getRewriter(visitor1);
MutableContent mc = createMock(MutableContent.class);
expect(mc.getDocument()).andReturn(null);
expect(mc.getContent()).andReturn("hello!");
replay(mc);
Gadget gadget = gadget();
boolean exceptionCaught = false;
try {
rewriter.rewrite(gadget, mc);
} catch (RewritingException e) {
assertEquals(e.getHttpStatusCode(),
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
exceptionCaught = true;
}
assertTrue(exceptionCaught);
}
private DomWalker.Rewriter getRewriter(DomWalker.Visitor... visitors) {
return new DomWalker.Rewriter(Lists.newArrayList(visitors));
}
private MutableContent getContent(int docChangedTimes) {
MutableContent mc = createMock(MutableContent.class);
expect(mc.getDocument()).andReturn(doc).once();
if (docChangedTimes > 0) {
mc.documentChanged();
expectLastCall().times(docChangedTimes);
}
replay(mc);
return mc;
}
}