/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.xml.rule; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Test; import org.w3c.dom.Attr; import org.w3c.dom.CharacterData; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.DocumentType; import org.w3c.dom.Element; import org.w3c.dom.Entity; import org.w3c.dom.EntityReference; import org.w3c.dom.Notation; import org.w3c.dom.ProcessingInstruction; import org.w3c.dom.Text; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.Parser; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.xml.XmlLanguageModule; import net.sourceforge.pmd.lang.xml.XmlParserOptions; import net.sourceforge.pmd.lang.xml.ast.XmlNode; public class AbstractDomXmlRuleTest { @Test public void testVisit() throws Exception { String source = "<?xml version=\"1.0\"?><?mypi?><!DOCTYPE testDoc [<!ENTITY entity \"e\">]><!--Comment--><foo abc=\"abc\"><bar>TEXT</bar><![CDATA[cdata!]]>>&entity;<</foo>"; XmlParserOptions parserOptions = new XmlParserOptions(); parserOptions.setExpandEntityReferences(false); Parser parser = LanguageRegistry.getLanguage(XmlLanguageModule.NAME).getDefaultVersion() .getLanguageVersionHandler().getParser(parserOptions); XmlNode xmlNode = (XmlNode) parser.parse(null, new StringReader(source)); List<XmlNode> nodes = new ArrayList<>(); nodes.add(xmlNode); MyRule rule = new MyRule(); rule.apply(nodes, null); List<org.w3c.dom.Node> visited = rule.visitedNodes.get("Attr"); assertEquals(1, visited.size()); assertEquals("abc", visited.get(0).getLocalName()); visited = rule.visitedNodes.get("CharacterData"); assertEquals(1, visited.size()); assertEquals("cdata!", ((CharacterData) visited.get(0)).getData()); visited = rule.visitedNodes.get("Comment"); assertEquals("Comment", ((Comment) visited.get(0)).getData()); visited = rule.visitedNodes.get("Document"); assertEquals(1, visited.size()); visited = rule.visitedNodes.get("DocumentType"); assertEquals("testDoc", ((DocumentType) visited.get(0)).getName()); visited = rule.visitedNodes.get("Element"); assertEquals(2, visited.size()); assertEquals("foo", visited.get(0).getLocalName()); assertEquals("bar", visited.get(1).getLocalName()); // TODO Figure out how to trigger this. // visited = rule.visitedNodes.get("Entity"); // assertEquals(0, visited.size()); visited = rule.visitedNodes.get("EntityReference"); assertEquals(1, visited.size()); assertEquals("entity", ((EntityReference) visited.get(0)).getNodeName()); // TODO Figure out how to trigger this. // visited = rule.visitedNodes.get("Notation"); // assertEquals(0, visited.size()); visited = rule.visitedNodes.get("ProcessingInstruction"); assertEquals(1, visited.size()); assertEquals("mypi", ((ProcessingInstruction) visited.get(0)).getTarget()); visited = rule.visitedNodes.get("Text"); assertEquals(3, visited.size()); assertEquals("TEXT", ((Text) visited.get(0)).getData()); assertEquals(">", ((Text) visited.get(1)).getData()); assertEquals("e<", ((Text) visited.get(2)).getData()); } @Test public void dtdIsNotLookedUp() { String source = "<!DOCTYPE struts-config PUBLIC " + " \"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN \" " + " \"http://jakarta.inexistinghost.org/struts/dtds/struts-config_1_1.dtd\" >" + "<struts-config/>"; XmlParserOptions parserOptions = new XmlParserOptions(); parserOptions.setLookupDescriptorDoc(false); Parser parser = LanguageRegistry.getLanguage(XmlLanguageModule.NAME).getDefaultVersion() .getLanguageVersionHandler().getParser(parserOptions); XmlNode xmlNode = (XmlNode) parser.parse(null, new StringReader(source)); // no exception should be thrown MyRule rule = new MyRule(); List<XmlNode> nodes = new ArrayList<>(); nodes.add(xmlNode); rule.apply(nodes, null); // first element is still parsed assertNotNull(rule.visitedNodes.get("Element")); } @Test public void xsdIsNotLookedUp() { String source = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> " + "<web-app xmlns=\"http://java.sun.com/xml/ns/javaee\" " + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + "xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.inexisting.com/xml/ns/javaee/web-app_2_5.xsd\" " + "version=\"2.5\">" + "</web-app>"; XmlParserOptions parserOptions = new XmlParserOptions(); Parser parser = LanguageRegistry.getLanguage(XmlLanguageModule.NAME).getDefaultVersion() .getLanguageVersionHandler().getParser(parserOptions); XmlNode xmlNode = (XmlNode) parser.parse(null, new StringReader(source)); // no exception should be thrown // first element is still parsed MyRule rule = new MyRule(); List<XmlNode> nodes = new ArrayList<>(); nodes.add(xmlNode); rule.apply(nodes, null); assertNotNull(rule.visitedNodes.get("Element")); } private static class MyRule extends AbstractDomXmlRule { final Map<String, List<org.w3c.dom.Node>> visitedNodes = new HashMap<>(); MyRule() { } private void visit(String key, org.w3c.dom.Node node) { List<org.w3c.dom.Node> nodes = visitedNodes.get(key); if (nodes == null) { nodes = new ArrayList<>(); visitedNodes.put(key, nodes); } nodes.add(node); } @Override public void apply(List<? extends Node> nodes, RuleContext ctx) { super.apply(nodes, ctx); } @Override protected void visit(XmlNode node, Attr attr, RuleContext ctx) { visit("Attr", attr); super.visit(node, attr, ctx); } @Override protected void visit(XmlNode node, CharacterData characterData, RuleContext ctx) { visit("CharacterData", characterData); super.visit(node, characterData, ctx); } @Override protected void visit(XmlNode node, Comment comment, RuleContext ctx) { visit("Comment", comment); super.visit(node, comment, ctx); } @Override protected void visit(XmlNode node, Document document, RuleContext ctx) { visit("Document", document); super.visit(node, document, ctx); } @Override protected void visit(XmlNode node, DocumentType documentType, RuleContext ctx) { visit("DocumentType", documentType); super.visit(node, documentType, ctx); } @Override protected void visit(XmlNode node, Element element, RuleContext ctx) { visit("Element", element); super.visit(node, element, ctx); } @Override protected void visit(XmlNode node, Entity entity, RuleContext ctx) { visit("Entity", entity); super.visit(node, entity, ctx); } @Override protected void visit(XmlNode node, EntityReference entityReference, RuleContext ctx) { visit("EntityReference", entityReference); super.visit(node, entityReference, ctx); } @Override protected void visit(XmlNode node, Notation notation, RuleContext ctx) { visit("Notation", notation); super.visit(node, notation, ctx); } @Override protected void visit(XmlNode node, ProcessingInstruction processingInstruction, RuleContext ctx) { visit("ProcessingInstruction", processingInstruction); super.visit(node, processingInstruction, ctx); } @Override protected void visit(XmlNode node, Text text, RuleContext ctx) { visit("Text", text); super.visit(node, text, ctx); } } }