/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.vf.ast;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.junit.Test;
/**
* Test parsing of a VF in document style, by checking the generated AST.
* Original @author pieter_van_raemdonck - Application Engineers NV/SA -
* www.ae.be
*
* @author sergey.gorbaty - VF adaptation
*
*/
public class VfDocStyleTest extends AbstractVfNodesTest {
/**
* Smoke test for VF parser.
*/
@Test
public void testSimplestVf() {
assertNumberOfNodes(ASTElement.class, TEST_SIMPLEST_HTML, 1);
}
/**
* Test the information on a Element and Attribute.
*/
@Test
public void testElementAttributeAndNamespace() {
Set<VfNode> nodes = getNodes(null, TEST_ELEMENT_AND_NAMESPACE);
Set<ASTElement> elementNodes = getNodesOfType(ASTElement.class, nodes);
assertEquals("One element node expected!", 1, elementNodes.size());
ASTElement element = elementNodes.iterator().next();
assertEquals("Correct name expected!", "h:html", element.getName());
assertEquals("Has namespace prefix!", true, element.isHasNamespacePrefix());
assertEquals("Element is empty!", true, element.isEmpty());
assertEquals("Correct namespace prefix of element expected!", "h", element.getNamespacePrefix());
assertEquals("Correct local name of element expected!", "html", element.getLocalName());
Set<ASTAttribute> attributeNodes = getNodesOfType(ASTAttribute.class, nodes);
assertEquals("One attribute node expected!", 1, attributeNodes.size());
ASTAttribute attribute = attributeNodes.iterator().next();
assertEquals("Correct name expected!", "MyNsPrefix:MyAttr", attribute.getName());
assertEquals("Has namespace prefix!", true, attribute.isHasNamespacePrefix());
assertEquals("Correct namespace prefix of element expected!", "MyNsPrefix", attribute.getNamespacePrefix());
assertEquals("Correct local name of element expected!", "MyAttr", attribute.getLocalName());
}
/**
* Test exposing a bug of parsing error when having a hash as last character
* in an attribute value.
*
*/
@Test
public void testAttributeValueContainingHash() {
Set<VfNode> nodes = getNodes(null, TEST_ATTRIBUTE_VALUE_CONTAINING_HASH);
Set<ASTAttribute> attributes = getNodesOfType(ASTAttribute.class, nodes);
assertEquals("Three attributes expected!", 3, attributes.size());
List<ASTAttribute> attrsList = new ArrayList<>(attributes);
Collections.sort(attrsList, new Comparator<ASTAttribute>() {
public int compare(ASTAttribute arg0, ASTAttribute arg1) {
return arg0.getName().compareTo(arg1.getName());
}
});
ASTAttribute attr = attrsList.get(0);
assertEquals("Correct attribute name expected!", "foo", attr.getName());
assertEquals("Correct attribute value expected!", "CREATE",
attr.getFirstDescendantOfType(ASTText.class).getImage());
attr = attrsList.get(1);
assertEquals("Correct attribute name expected!", "href", attr.getName());
assertEquals("Correct attribute value expected!", "#", attr.getFirstDescendantOfType(ASTText.class).getImage());
attr = attrsList.get(2);
assertEquals("Correct attribute name expected!", "something", attr.getName());
assertEquals("Correct attribute value expected!", "#yes#",
attr.getFirstDescendantOfType(ASTText.class).getImage());
}
/**
* Test correct parsing of CDATA.
*/
@Test
public void testCData() {
Set<ASTCData> cdataNodes = getNodes(ASTCData.class, TEST_CDATA);
assertEquals("One CDATA node expected!", 1, cdataNodes.size());
ASTCData cdata = cdataNodes.iterator().next();
assertEquals("Content incorrectly parsed!", " some <cdata> ]] ]> ", cdata.getImage());
}
/**
* Test parsing of Doctype declaration.
*/
@Test
public void testDoctype() {
Set<VfNode> nodes = getNodes(null, TEST_DOCTYPE);
Set<ASTDoctypeDeclaration> docTypeDeclarations = getNodesOfType(ASTDoctypeDeclaration.class, nodes);
assertEquals("One doctype declaration expected!", 1, docTypeDeclarations.size());
ASTDoctypeDeclaration docTypeDecl = docTypeDeclarations.iterator().next();
assertEquals("Correct doctype-name expected!", "html", docTypeDecl.getName());
Set<ASTDoctypeExternalId> externalIds = getNodesOfType(ASTDoctypeExternalId.class, nodes);
assertEquals("One doctype external id expected!", 1, externalIds.size());
ASTDoctypeExternalId externalId = externalIds.iterator().next();
assertEquals("Correct external public id expected!", "-//W3C//DTD XHTML 1.1//EN", externalId.getPublicId());
assertEquals("Correct external uri expected!", "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd",
externalId.getUri());
}
/**
* Test parsing of HTML <script> element.
*/
@Test
public void testHtmlScript() {
Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_HTML_SCRIPT);
assertEquals("One script expected!", 1, scripts.size());
ASTHtmlScript script = scripts.iterator().next();
ASTText text = script.getFirstChildOfType(ASTText.class);
assertEquals("Correct script content expected!", "Script!", text.getImage());
}
/**
* Test parsing of EL in attribute of an element.
*/
@Test
public void testELInTagValue() {
Set<ASTElement> elememts = getNodes(ASTElement.class, TEST_EL_IN_TAG_ATTRIBUTE);
assertEquals("One element expected!", 1, elememts.size());
ASTElement element = elememts.iterator().next();
ASTAttributeValue attribute = element.getFirstDescendantOfType(ASTAttributeValue.class);
ASTIdentifier id = attribute.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Correct identifier expected", "foo", id.getImage());
}
/**
* Test parsing of EL in attribute of an element that also has a comment.
*/
@Test
public void testELInTagValueWithCommentDQ() {
Set<ASTElement> elememts = getNodes(ASTElement.class, TEST_EL_IN_TAG_ATTRIBUTE_WITH_COMMENT);
assertEquals("One element expected!", 1, elememts.size());
ASTElement element = elememts.iterator().next();
ASTElExpression elExpr = element.getFirstDescendantOfType(ASTElExpression.class);
ASTIdentifier id = elExpr.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Correct identifier expected", "init", id.getImage());
}
/**
* Test parsing of EL in attribute of an element that also has a comment.
*/
@Test
public void testELInTagValueWithCommentSQ() {
Set<ASTElement> elememts = getNodes(ASTElement.class, TEST_EL_IN_TAG_ATTRIBUTE_WITH_COMMENT_SQ);
assertEquals("One element expected!", 1, elememts.size());
ASTElement element = elememts.iterator().next();
ASTElExpression elExpr = element.getFirstDescendantOfType(ASTElExpression.class);
ASTIdentifier id = elExpr.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Correct identifier expected", "init", id.getImage());
}
/**
* Test parsing of EL in HTML <script> element.
*/
@Test
public void testELInHtmlScript() {
Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_EL_IN_HTML_SCRIPT);
assertEquals("One script expected!", 1, scripts.size());
ASTHtmlScript script = scripts.iterator().next();
ASTText text = script.getFirstChildOfType(ASTText.class);
assertEquals("Correct script content expected!", "vartext=", text.getImage());
ASTElExpression el = script.getFirstChildOfType(ASTElExpression.class);
ASTIdentifier id = el.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Correct EL content expected!", "elInScript", id.getImage());
}
/**
* Test parsing of inline comment in EL.
*/
@Test
public void testInlineCommentInEL() {
Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_EL_IN_HTML_SCRIPT_WITH_COMMENT);
assertEquals("One script expected!", 1, scripts.size());
ASTHtmlScript script = scripts.iterator().next();
ASTText text = script.getFirstChildOfType(ASTText.class);
assertEquals("Correct script content expected!", "vartext=", text.getImage());
ASTElExpression el = script.getFirstChildOfType(ASTElExpression.class);
ASTIdentifier id = el.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Correct EL content expected!", "elInScript", id.getImage());
}
/**
* Test parsing of quoted EL in HTML <script> element.
*/
@Test
public void testQuotedELInHtmlScript() {
Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_QUOTED_EL_IN_HTML_SCRIPT);
assertEquals("One script expected!", 1, scripts.size());
ASTHtmlScript script = scripts.iterator().next();
ASTText text = script.getFirstChildOfType(ASTText.class);
assertEquals("Correct script content expected!", "vartext='textHere", text.getImage());
ASTElExpression el = script.getFirstChildOfType(ASTElExpression.class);
ASTIdentifier id = el.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Correct EL content expected!", "elInScript", id.getImage());
}
/**
* Test parsing of HTML <script src="x"/> element. It might not be
* valid html but it is likely to appear in .page files.
*/
@Test
public void testImportHtmlScript() {
Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_IMPORT_JAVASCRIPT);
assertEquals("One script expected!", 1, scripts.size());
ASTHtmlScript script = scripts.iterator().next();
List<ASTAttribute> attr = script.findDescendantsOfType(ASTAttribute.class);
assertEquals("One script expected!", 1, attr.size());
ASTAttribute att = attr.iterator().next();
ASTAttributeValue val = att.getFirstChildOfType(ASTAttributeValue.class);
ASTText text = val.getFirstChildOfType(ASTText.class);
assertEquals("filename.js", text.getImage());
}
/**
* Test parsing of HTML <script> element.
*/
@Test
public void testHtmlScriptWithAttribute() {
Set<ASTHtmlScript> scripts = getNodes(ASTHtmlScript.class, TEST_HTML_SCRIPT_WITH_ATTRIBUTE);
assertEquals("One script expected!", 1, scripts.size());
ASTHtmlScript script = scripts.iterator().next();
ASTText text = script.getFirstChildOfType(ASTText.class);
assertEquals("Correct script content expected!", "Script!", text.getImage());
List<ASTText> attrs = script.findDescendantsOfType(ASTText.class);
assertTrue("text/javascript".equals(attrs.get(0).getImage()));
}
/**
* A complex script containing HTML comments, escapes, quotes, etc.
*/
@Test
public void testComplexHtmlScript() {
Set<ASTHtmlScript> script = getNodes(ASTHtmlScript.class, TEST_COMPLEX_SCRIPT);
assertEquals("One script expected!", 1, script.size());
ASTHtmlScript next = script.iterator().next();
ASTText text = next.getFirstChildOfType(ASTText.class);
assertTrue(text.getImage().contains("<!--"));
}
/**
* Test parsing of HTML <style> element.
*/
@Test
public void testInlineCss() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_INLINE_STYLE);
assertEquals("Two elements expected!", 3, elements.size());
}
/**
* Test parsing of HTML text within element.
*/
@Test
public void testTextInTag() {
Set<ASTText> scripts = getNodes(ASTText.class, TEST_TEXT_IN_TAG);
assertEquals("One text chunk expected!", 1, scripts.size());
ASTText script = scripts.iterator().next();
assertEquals("Correct content expected!", " some text ", script.getImage());
}
/**
* Test parsing of HTML with no spaces between tags. Parser is likely in
* this scenario.
*/
@Test
public void noSpacesBetweenTags() {
Set<ASTElement> scripts = getNodes(ASTElement.class, TEST_TAGS_NO_SPACE);
assertEquals("Two tags expected!", 2, scripts.size());
List<ASTElement> elmts = sortNodesByName(scripts);
Iterator<ASTElement> iterator = elmts.iterator();
ASTElement script = iterator.next();
assertEquals("Correct content expected!", "a", script.getName());
script = iterator.next();
assertEquals("Correct content expected!", "b", script.getName());
}
/**
* the $ sign might trick the parser into thinking an EL is next. He should
* be able to treat it as plain text
*/
@Test
public void unclosedTagsWithDollar() {
Set<ASTText> scripts = getNodes(ASTText.class, TEST_TAGS_WITH_DOLLAR);
assertEquals("Two text chunks expected!", 2, scripts.size());
ASTText script = scripts.iterator().next();
assertEquals("Correct content expected!", " $ ", script.getImage());
}
/**
* Make sure EL expressions aren't treated as plain text when they are
* around unclosed tags.
*/
@Test
public void unclosedTagsWithELWithin() {
Set<ASTElement> element = getNodes(ASTElement.class, TEST_TAGS_WITH_EL_WITHIN);
assertEquals("One element expected!", 1, element.size());
for (ASTElement elem : element) {
ASTContent content = elem.getFirstChildOfType(ASTContent.class);
List<ASTElExpression> els = content.findChildrenOfType(ASTElExpression.class);
assertEquals("Two EL expressions expected!", 2, els.size());
ASTElExpression node = (ASTElExpression) content.jjtGetChild(0);
ASTIdentifier id = node.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Correct content expected!", "expr1", id.getImage());
node = (ASTElExpression) content.jjtGetChild(1);
id = node.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Correct content expected!", "expr2", id.getImage());
}
}
/**
* Test parsing of HTML <script> element.
*/
@Test
public void textAfterOpenAndClosedTag() {
Set<ASTElement> nodes = getNodes(ASTElement.class, TEST_TEXT_AFTER_OPEN_AND_CLOSED_TAG);
assertEquals("Two elements expected!", 2, nodes.size());
List<ASTElement> elmts = sortNodesByName(nodes);
assertEquals("First element should be a", "a", elmts.get(0).getName());
assertFalse("first element should be closed", elmts.get(0).isUnclosed());
assertEquals("Second element should be b", "b", elmts.get(1).getName());
assertTrue("Second element should not be closed", elmts.get(1).isUnclosed());
Set<ASTText> text = getNodes(ASTText.class, TEST_TEXT_AFTER_OPEN_AND_CLOSED_TAG);
assertEquals("Two text chunks expected!", 2, text.size());
}
@Test
public void quoteEL() {
Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_QUOTE_EL);
assertEquals("One attribute expected!", 1, attributes.size());
ASTAttributeValue attr = attributes.iterator().next();
List<ASTElExpression> els = attr.findChildrenOfType(ASTElExpression.class);
assertEquals("Must be 1!", 1, els.size());
ASTExpression expr = els.get(0).getFirstChildOfType(ASTExpression.class);
ASTIdentifier id = expr.getFirstChildOfType(ASTIdentifier.class);
assertEquals("Expected to detect proper value for attribute!", "something", id.getImage());
}
/**
* smoke test for a non-quoted attribute value
*/
@Test
public void quoteAttrValue() {
Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_ATTR);
assertEquals("One attribute expected!", 1, attributes.size());
ASTAttributeValue attr = attributes.iterator().next();
ASTText text = attr.getFirstChildOfType(ASTText.class);
assertEquals("Expected to detect proper value for attribute!", "yes|", text.getImage());
}
/**
* tests whether parse correctly interprets empty non quote attribute
*/
@Test
public void noQuoteAttrEmpty() {
Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_EMPTY_ATTR);
assertEquals("two attributes expected!", 2, attributes.size());
Iterator<ASTAttributeValue> iterator = attributes.iterator();
ASTAttributeValue attr = iterator.next();
if ("http://someHost:/some_URL".equals(attr.getImage())) {
// we have to employ this nasty work-around
// in order to ensure that we check the proper attribute
attr = iterator.next();
}
assertEquals("Expected to detect proper value for attribute!", null, attr.getImage());
}
/**
* tests whether parse correctly interprets an tab instead of an attribute
*/
@Test
public void singleQuoteAttrTab() {
Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_TAB_ATTR);
assertEquals("One attribute expected!", 1, attributes.size());
Iterator<ASTAttributeValue> iterator = attributes.iterator();
ASTAttributeValue attr = iterator.next();
ASTText text = attr.getFirstChildOfType(ASTText.class);
assertEquals("Expected to detect proper value for attribute!", "\t", text.getImage());
}
@Test
public void unclosedTag() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_SIMPLE);
List<ASTElement> sortedElmnts = sortNodesByName(elements);
assertEquals("2 tags expected", 2, elements.size());
assertEquals("First element should be sorted tag:if", "tag:if", sortedElmnts.get(0).getName());
assertEquals("Second element should be tag:someTag", "tag:someTag", sortedElmnts.get(1).getName());
assertTrue(sortedElmnts.get(0).isEmpty());
assertTrue(sortedElmnts.get(0).isUnclosed());
assertFalse(sortedElmnts.get(1).isEmpty());
assertFalse(sortedElmnts.get(1).isUnclosed());
}
@Test
public void unclosedTagAndNoQuotesForAttribute() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_ATTR);
List<ASTElement> sortedElmnts = sortNodesByName(elements);
assertEquals("2 tags expected", 2, elements.size());
assertEquals("First element should be sorted tag:if", "tag:if", sortedElmnts.get(0).getName());
assertEquals("Second element should be tag:someTag", "tag:someTag", sortedElmnts.get(1).getName());
assertTrue(sortedElmnts.get(0).isEmpty());
assertTrue(sortedElmnts.get(0).isUnclosed());
assertFalse(sortedElmnts.get(1).isEmpty());
assertFalse(sortedElmnts.get(1).isUnclosed());
}
@Test
public void unclosedTagMultipleLevels() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_MULTIPLE_LEVELS);
List<ASTElement> sortedElmnts = sortNodesByName(elements);
assertEquals("3 tags expected", 3, elements.size());
assertEquals("First element should be sorted tag:someTag", "tag:someTag", sortedElmnts.get(0).getName());
assertEquals("Second element should be tag:someTag", "tag:someTag", sortedElmnts.get(1).getName());
assertEquals("Third element should be tag:x", "tag:x", sortedElmnts.get(2).getName());
assertFalse(sortedElmnts.get(0).isEmpty());
assertFalse(sortedElmnts.get(0).isUnclosed());
assertTrue(sortedElmnts.get(1).isEmpty());
assertTrue(sortedElmnts.get(1).isUnclosed());
assertFalse(sortedElmnts.get(2).isEmpty());
assertFalse(sortedElmnts.get(2).isUnclosed());
}
/**
* <html> <a1> <a2/> <b/> </a1> </html>
*/
@Test
public void nestedEmptyTags() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_MULTIPLE_EMPTY_TAGS);
List<ASTElement> sortedElmnts = sortNodesByName(elements);
assertEquals("4 tags expected", 4, elements.size());
assertEquals("First element should a1", "a1", sortedElmnts.get(0).getName());
assertEquals("Second element should be a2", "a2", sortedElmnts.get(1).getName());
assertEquals("Third element should be b", "b", sortedElmnts.get(2).getName());
assertEquals("Third element should be html", "html", sortedElmnts.get(3).getName());
// a1
assertFalse(sortedElmnts.get(0).isEmpty());
assertFalse(sortedElmnts.get(0).isUnclosed());
// a2
assertTrue(sortedElmnts.get(1).isEmpty());
assertFalse(sortedElmnts.get(1).isUnclosed());
// b
assertTrue(sortedElmnts.get(2).isEmpty());
assertFalse(sortedElmnts.get(2).isUnclosed());
// html
assertFalse(sortedElmnts.get(3).isEmpty());
assertFalse(sortedElmnts.get(3).isUnclosed());
}
/**
* <html> <a1> <a2> <a3> </a2> </a1>
* <b/> <a4/> </html>
*/
@Test
public void nestedMultipleTags() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_MULTIPLE_NESTED_TAGS);
List<ASTElement> sortedElmnts = sortNodesByName(elements);
assertEquals("4 tags expected", 6, elements.size());
assertEquals("First element should a1", "a1", sortedElmnts.get(0).getName());
assertEquals("Second element should be a2", "a2", sortedElmnts.get(1).getName());
assertEquals("Third element should be a3", "a3", sortedElmnts.get(2).getName());
assertEquals("Forth element should be a4", "a4", sortedElmnts.get(3).getName());
assertEquals("Fifth element should be b", "b", sortedElmnts.get(4).getName());
assertEquals("Sixth element should be html", "html", sortedElmnts.get(5).getName());
// a1 not empty and closed
assertFalse(sortedElmnts.get(0).isEmpty());
assertFalse(sortedElmnts.get(0).isUnclosed());
// a2 not empty and closed
assertFalse(sortedElmnts.get(1).isEmpty());
assertFalse(sortedElmnts.get(1).isUnclosed());
// a3 empty and not closed
assertTrue(sortedElmnts.get(2).isEmpty());
assertTrue(sortedElmnts.get(2).isUnclosed());
// a4 empty but closed
assertTrue(sortedElmnts.get(3).isEmpty());
assertFalse(sortedElmnts.get(3).isUnclosed());
// b empty but closed
assertTrue(sortedElmnts.get(4).isEmpty());
assertFalse(sortedElmnts.get(4).isUnclosed());
// html not empty and closed
assertFalse(sortedElmnts.get(5).isEmpty());
assertFalse(sortedElmnts.get(5).isUnclosed());
}
/**
* will test <x> <a> <b> <b> </x> </a>
* </x> . Here x is the first tag to be closed thus rendering the next
* close of a (</a>) to be disregarded.
*/
@Test
public void unclosedParentTagClosedBeforeChild() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_END_AFTER_PARENT_CLOSE);
List<ASTElement> sortedElmnts = sortNodesByName(elements);
assertEquals("4 tags expected", 4, elements.size());
assertEquals("First element should be 'a'", "a", sortedElmnts.get(0).getName());
assertEquals("Second element should be b", "b", sortedElmnts.get(1).getName());
assertEquals("Third element should be b", "b", sortedElmnts.get(2).getName());
assertEquals("Forth element should be x", "x", sortedElmnts.get(3).getName());
// a
assertTrue(sortedElmnts.get(0).isEmpty());
assertTrue(sortedElmnts.get(0).isUnclosed());
// b
assertTrue(sortedElmnts.get(1).isEmpty());
assertTrue(sortedElmnts.get(1).isUnclosed());
// b
assertTrue(sortedElmnts.get(2).isEmpty());
assertTrue(sortedElmnts.get(2).isUnclosed());
// x
assertFalse(sortedElmnts.get(3).isEmpty());
assertFalse(sortedElmnts.get(3).isUnclosed());
}
/**
* <x> <a> <b> <b> </z> </a> </x>
* An unmatched closing of 'z' appears randomly in the document. This should
* be disregarded and structure of children and parents should not be
* influenced. in other words </a> should close the first <a>
* tag , </x> should close the first <x>, etc.
*/
@Test
public void unmatchedTagDoesNotInfluenceStructure() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_UNMATCHED_CLOSING_TAG);
List<ASTElement> sortedElmnts = sortNodesByName(elements);
assertEquals("4 tags expected", 4, elements.size());
assertEquals("First element should be 'a'", "a", sortedElmnts.get(0).getName());
assertEquals("Second element should be b", "b", sortedElmnts.get(1).getName());
assertEquals("Third element should be b", "b", sortedElmnts.get(2).getName());
assertEquals("Forth element should be x", "x", sortedElmnts.get(3).getName());
// a is not empty and closed
assertFalse(sortedElmnts.get(0).isEmpty());
assertFalse(sortedElmnts.get(0).isUnclosed());
// b empty and unclosed
assertTrue(sortedElmnts.get(1).isEmpty());
assertTrue(sortedElmnts.get(1).isUnclosed());
// b empty and unclosed
assertTrue(sortedElmnts.get(2).isEmpty());
assertTrue(sortedElmnts.get(2).isUnclosed());
// x not empty and closed
assertFalse(sortedElmnts.get(3).isEmpty());
assertFalse(sortedElmnts.get(3).isUnclosed());
}
/**
* <a> <x> <a> <b> <b> </z> </a>
* </x> An unmatched closing of 'z' appears randomly in the document.
* This should be disregarded and structure of children and parents should
* not be influenced. Also un unclosed <a> tag appears at the start of
* the document
*/
@Test
public void unclosedStartTagWithUnmatchedCloseOfDifferentTag() {
Set<ASTElement> elements = getNodes(ASTElement.class, TEST_UNCLOSED_START_TAG_WITH_UNMATCHED_CLOSE);
List<ASTElement> sortedElmnts = sortNodesByName(elements);
assertEquals("5 tags expected", 5, elements.size());
assertEquals("First element should be 'a'", "a", sortedElmnts.get(0).getName());
assertEquals("Second element should be a", "a", sortedElmnts.get(1).getName());
assertEquals("Third element should be b", "b", sortedElmnts.get(2).getName());
assertEquals("Forth element should be b", "b", sortedElmnts.get(3).getName());
assertEquals("Fifth element should be x", "x", sortedElmnts.get(4).getName());
// first a is empty and unclosed
assertTrue(sortedElmnts.get(0).isEmpty());
assertTrue(sortedElmnts.get(0).isUnclosed());
// second a not empty and closed
assertFalse(sortedElmnts.get(1).isEmpty());
assertFalse(sortedElmnts.get(1).isUnclosed());
// b empty and unclosed
assertTrue(sortedElmnts.get(2).isEmpty());
assertTrue(sortedElmnts.get(2).isUnclosed());
// b empty and unclosed
assertTrue(sortedElmnts.get(3).isEmpty());
assertTrue(sortedElmnts.get(3).isUnclosed());
// x not empty and closed
assertFalse(sortedElmnts.get(4).isEmpty());
assertFalse(sortedElmnts.get(4).isUnclosed());
}
/**
* will sort the AST element in list in alphabetical order and if tag name
* is the same it will sort against o1.getBeginColumn() +""+
* o1.getBeginLine(). so first criteria is the name, then the second is the
* column +""+line string.
*
* @param elements
* @return
*/
private List<ASTElement> sortNodesByName(Set<ASTElement> elements) {
List<ASTElement> list = new ArrayList<>();
list.addAll(elements);
Collections.sort(list, new Comparator<ASTElement>() {
public int compare(ASTElement o1, ASTElement o2) {
if (o1.getName() == null) {
return Integer.MIN_VALUE;
}
if (o2.getName() == null) {
return Integer.MAX_VALUE;
}
if (o1.getName().equals(o2.getName())) {
String o1Value = o1.getBeginColumn() + "" + o1.getBeginLine();
String o2Value = o2.getBeginColumn() + "" + o2.getBeginLine();
return o1Value.compareTo(o2Value);
}
return o1.getName().compareTo(o2.getName());
}
});
return list;
}
@Test
public void noQuoteAttrWithJspEL() {
Set<ASTAttributeValue> attributes = getNodes(ASTAttributeValue.class, TEST_NO_QUOTE_ATTR_WITH_EL);
assertEquals("One attribute expected!", 1, attributes.size());
Iterator<ASTAttributeValue> iterator = attributes.iterator();
ASTAttributeValue attr = iterator.next();
ASTIdentifier id = attr.getFirstDescendantOfType(ASTIdentifier.class);
assertEquals("Expected to detect proper value for EL in attribute!", "something", id.getImage());
}
private static final String TEST_SIMPLEST_HTML = "<html/>";
private static final String TEST_ELEMENT_AND_NAMESPACE = "<h:html MyNsPrefix:MyAttr='MyValue'/>";
private static final String TEST_CDATA = "<html><![CDATA[ some <cdata> ]] ]> ]]></html>";
private static final String TEST_DOCTYPE = "<?xml version=\"1.0\" standalone='yes'?>\n"
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
+ "\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" + "<greeting>Hello, world!</greeting>";
private static final String TEST_ATTRIBUTE_VALUE_CONTAINING_HASH = "<tag:if something=\"#yes#\" foo=\"CREATE\"> <a href=\"#\">foo</a> </tag:if>";
private static final String TEST_HTML_SCRIPT = "<html><head><script>Script!</script></head></html>";
private static final String TEST_EL_IN_TAG_ATTRIBUTE = "<apex:page action=\"{!foo}\">text</apex:page>";
private static final String TEST_EL_IN_TAG_ATTRIBUTE_WITH_COMMENT = "<apex:page action=\"{!/*comment here*/init}\">text</apex:page>";
private static final String TEST_EL_IN_TAG_ATTRIBUTE_WITH_COMMENT_SQ = "<apex:page action='{!/*comment here*/init}'>text</apex:page>";
private static final String TEST_EL_IN_HTML_SCRIPT = "<html><head><script>var text={!elInScript};</script></head></html>";
private static final String TEST_EL_IN_HTML_SCRIPT_WITH_COMMENT = "<html><head><script>var text={!/*junk1*/elInScript/*junk2*/};</script></head></html>";
private static final String TEST_QUOTED_EL_IN_HTML_SCRIPT = "<html><head><script>var text='textHere{!elInScript}';</script></head></html>";
private static final String TEST_IMPORT_JAVASCRIPT = "<html><head><script src=\"filename.js\" /></head></html>";
private static final String TEST_HTML_SCRIPT_WITH_ATTRIBUTE = "<html><head><script type=\"text/javascript\">Script!</script></head></html>";
private static final String TEST_COMPLEX_SCRIPT = "<HTML><BODY><!--Java Script-->"
+ "<SCRIPT language='JavaScript' type='text/javascript'>" + "<!--function calcDays(){"
+ " date1 = date1.split(\"-\"); date2 = date2.split(\"-\");"
+ " var sDate = new Date(date1[0]+\"/\"+date1[1]+\"/\"+date1[2]);"
+ " var eDate = new Date(date2[0]+\"/\"+date2[1]+\"/\"+date2[2]);" + " onload=calcDays;//-->"
+ "</SCRIPT></BODY></HTML>;";
private static final String TEST_INLINE_STYLE = "<html><head><style> div { color:red; } </style></head></html>";
private static final String TEST_TEXT_IN_TAG = "<a> some text </a>";
private static final String TEST_TAGS_NO_SPACE = "<a><b></a>";
private static final String TEST_TAGS_WITH_DOLLAR = "<a> $ <b> $ </a>";
private static final String TEST_TAGS_WITH_EL_WITHIN = "<a>{!expr1}{!expr2}</a>";
private static final String TEST_TEXT_AFTER_OPEN_AND_CLOSED_TAG = "<a> some text <b> some text </a>";
private static final String TEST_QUOTE_EL = "<tag:if something=\"{!something}\" > </tag:if>";
private static final String TEST_ATTR = "<tag:if something=\"yes|\" > </tag:if>";
private static final String TEST_EMPTY_ATTR = "<tag:if something= > <a href=\"http://someHost:/some_URL\" >foo</a> </tag:if>";
private static final String TEST_TAB_ATTR = "<tag:if something='\t' > </tag:if>";
private static final String TEST_UNCLOSED_SIMPLE = "<tag:someTag> <tag:if someting=\"x\" > </tag:someTag>";
/**
* someTag is closed just once
*/
private static final String TEST_UNCLOSED_MULTIPLE_LEVELS = "<tag:x> <tag:someTag> <tag:someTag someting=\"x\" > </tag:someTag> </tag:x>";
/**
* nested empty tags
*/
private static final String TEST_MULTIPLE_EMPTY_TAGS = "<html> <a1> <a2/> <b/> </a1> </html>";
/**
* multiple nested tags with some tags unclosed
*/
private static final String TEST_MULTIPLE_NESTED_TAGS = "<html> <a1> <a2> <a3> </a2> </a1> <b/> <a4/> </html>";
/**
* </x> will close before </a>, thus leaving <a> to remain unclosed
*/
private static final String TEST_UNCLOSED_END_AFTER_PARENT_CLOSE = "<x> <a> <b> <b> </x> </a> aa </x> bb </x>";
/**
* </z> is just a dangling closing tag not matching any parent. The parser
* should disregard it
*/
private static final String TEST_UNCLOSED_UNMATCHED_CLOSING_TAG = "<x> <a> <b> <b> </z> </a> </x>";
/**
* First <a> tag does not close. The first closing of </a> will match the
* second opening of a. Another rogue </z> is there for testing compliance
*/
private static final String TEST_UNCLOSED_START_TAG_WITH_UNMATCHED_CLOSE = "<a> <x> <a> <b> <b> </z> </a> </x>";
private static final String TEST_UNCLOSED_ATTR = "<tag:someTag> <tag:if someting='x' > </tag:someTag>";
private static final String TEST_NO_QUOTE_ATTR_WITH_EL = "<apex:someTag something={!something} > foo </apex:someTag>";
}