blob: 70b0263d35adf409674a4551149b9aa4de9941c5 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed 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.
*/
/*
* @author max
*/
package com.intellij.codeInsight;
import com.intellij.psi.impl.source.parsing.xml.XmlBuilder;
import com.intellij.psi.impl.source.parsing.xml.XmlBuilderDriver;
import com.intellij.testFramework.LightCodeInsightTestCase;
import org.jetbrains.annotations.Nullable;
public class XmlBuilderTest extends LightCodeInsightTestCase {
private static class TestXmlBuilder implements XmlBuilder {
private final StringBuilder builder = new StringBuilder();
private final StringBuilder currentPhysicalText = new StringBuilder();
private final StringBuilder currentDisplayText = new StringBuilder();
private final ProcessingOrder myTagProcessingOrder;
public TestXmlBuilder(final ProcessingOrder tagsAndAttributes) {
myTagProcessingOrder = tagsAndAttributes;
}
@Override
public void attribute(final CharSequence name, final CharSequence value, final int startoffset, final int endoffset) {
flushText();
builder.append("ATT: name='").append(name).append("' value='").append(value).append("'\n");
}
@Override
public void endTag(final CharSequence localName, final String namespace, final int startoffset, final int endoffset) {
flushText();
builder.append("ENDTAG: name='").append(localName).append("' namespace='").append(namespace).append("'\n");
}
@Override
public void doctype(@Nullable final CharSequence publicId, @Nullable final CharSequence systemId, final int startOffset, final int endOffset) {
}
@Override
public ProcessingOrder startTag(final CharSequence localName, final String namespace, final int startoffset, final int endoffset,
final int headerEndOffset) {
flushText();
builder.append("TAG: name='").append(localName).append("' namespace='").append(namespace).append("'\n");
return myTagProcessingOrder;
}
@Override
public void textElement(final CharSequence display, final CharSequence physical, final int startoffset, final int endoffset) {
currentPhysicalText.append(physical);
currentDisplayText.append(display);
}
@Override
public void entityRef(final CharSequence ref, final int startOffset, final int endOffset) {
flushText();
builder.append("REF: '").append(ref).append("'\n");
}
@Override
public void error(String message, int startOffset, int endOffset) {
flushText();
builder.append("ERROR: '").append(message).append("'\n");
}
private void flushText() {
if (currentPhysicalText.length() > 0) {
builder.append("TEXT: '").append(currentPhysicalText).append("' DISPLAY: '").append(currentDisplayText).append("'\n");
currentPhysicalText.setLength(0);
currentDisplayText.setLength(0);
}
}
public String getResult() {
flushText();
return builder.toString();
}
}
public void testEmptyXml() throws Exception {
doTest("<root/>", "TAG: name='root' namespace=''\n" +
"ENDTAG: name='root' namespace=''\n", XmlBuilder.ProcessingOrder.TAGS_AND_ATTRIBUTES);
}
public void testRealJspx() throws Exception {
doTest(
/* Test: */
"<jsp:root xmlns:jsp=\"http://java.sun.com/JSP/Page\" xmlns=\"http://www.w3.org/1999/xhtml\" version=\"2.0\"\n" +
" xmlns:spring=\"http://www.springframework.org/tags\" xmlns:c=\"http://java.sun.com/jsp/jstl/core\">\n" +
"<html>\n" +
" <c:set var=\"foo\" value=\"${1}\"/>\n" +
" <c:set var=\"foobar\" value=\"${2}\"/>\n" +
" <spring:bind path=\"test.fieldName\">\n" +
" <jsp:scriptlet></jsp:scriptlet>\n" +
" </spring:bind>\n" +
"</html>\n" +
"</jsp:root>",
/* Expected result: */
"TAG: name='root' namespace='http://java.sun.com/JSP/Page'\n" +
"ATT: name='xmlns:jsp' value='http://java.sun.com/JSP/Page'\n" +
"ATT: name='xmlns' value='http://www.w3.org/1999/xhtml'\n" +
"ATT: name='version' value='2.0'\n" +
"ATT: name='xmlns:spring' value='http://www.springframework.org/tags'\n" +
"ATT: name='xmlns:c' value='http://java.sun.com/jsp/jstl/core'\n" +
"TAG: name='html' namespace='http://www.w3.org/1999/xhtml'\n" +
"TAG: name='set' namespace='http://java.sun.com/jsp/jstl/core'\n" +
"ATT: name='var' value='foo'\n" +
"ATT: name='value' value='${1}'\n" +
"ENDTAG: name='set' namespace='http://java.sun.com/jsp/jstl/core'\n" +
"TAG: name='set' namespace='http://java.sun.com/jsp/jstl/core'\n" +
"ATT: name='var' value='foobar'\n" +
"ATT: name='value' value='${2}'\n" +
"ENDTAG: name='set' namespace='http://java.sun.com/jsp/jstl/core'\n" +
"TAG: name='bind' namespace='http://www.springframework.org/tags'\n" +
"ATT: name='path' value='test.fieldName'\n" +
"TAG: name='scriptlet' namespace='http://java.sun.com/JSP/Page'\n" +
"ENDTAG: name='scriptlet' namespace='http://java.sun.com/JSP/Page'\n" +
"ENDTAG: name='bind' namespace='http://www.springframework.org/tags'\n" +
"ENDTAG: name='html' namespace='http://www.w3.org/1999/xhtml'\n" +
"ENDTAG: name='root' namespace='http://java.sun.com/JSP/Page'\n",
XmlBuilder.ProcessingOrder.TAGS_AND_ATTRIBUTES);
}
public void testRealJspxNoAttributes() throws Exception {
doTest(
/* Test: */
"<jsp:root xmlns:jsp=\"http://java.sun.com/JSP/Page\" xmlns=\"http://www.w3.org/1999/xhtml\" version=\"2.0\"\n" +
" xmlns:spring=\"http://www.springframework.org/tags\" xmlns:c=\"http://java.sun.com/jsp/jstl/core\">\n" +
"<html>\n" +
" <c:set var=\"foo\" value=\"${1}\"/>\n" +
" <c:set var=\"foobar\" value=\"${2}\"/>\n" +
" <spring:bind path=\"test.fieldName\">\n" +
" <jsp:scriptlet></jsp:scriptlet>\n" +
" </spring:bind>\n" +
"</html>\n" +
"</jsp:root>",
/* Expected result: */
"TAG: name='root' namespace='http://java.sun.com/JSP/Page'\n" +
"TAG: name='html' namespace='http://www.w3.org/1999/xhtml'\n" +
"TAG: name='set' namespace='http://java.sun.com/jsp/jstl/core'\n" +
"ENDTAG: name='set' namespace='http://java.sun.com/jsp/jstl/core'\n" +
"TAG: name='set' namespace='http://java.sun.com/jsp/jstl/core'\n" +
"ENDTAG: name='set' namespace='http://java.sun.com/jsp/jstl/core'\n" +
"TAG: name='bind' namespace='http://www.springframework.org/tags'\n" +
"TAG: name='scriptlet' namespace='http://java.sun.com/JSP/Page'\n" +
"ENDTAG: name='scriptlet' namespace='http://java.sun.com/JSP/Page'\n" +
"ENDTAG: name='bind' namespace='http://www.springframework.org/tags'\n" +
"ENDTAG: name='html' namespace='http://www.w3.org/1999/xhtml'\n" +
"ENDTAG: name='root' namespace='http://java.sun.com/JSP/Page'\n",
XmlBuilder.ProcessingOrder.TAGS);
}
public void testNamespaceOverride() throws Exception {
doTest(
"<c:x xmlns:c=\"ns1\">\n" +
" <c:y/>\n" +
" <c:x xmlns:c=\"ns2\">\n" +
" <c:y/>\n" +
" </c:x>\n" +
" <c:y/>\n" +
"</c:x>\n",
"TAG: name='x' namespace='ns1'\n" +
"ATT: name='xmlns:c' value='ns1'\n" +
"TAG: name='y' namespace='ns1'\n" +
"ENDTAG: name='y' namespace='ns1'\n" +
"TAG: name='x' namespace='ns2'\n" +
"ATT: name='xmlns:c' value='ns2'\n" +
"TAG: name='y' namespace='ns2'\n" +
"ENDTAG: name='y' namespace='ns2'\n" +
"ENDTAG: name='x' namespace='ns2'\n" +
"TAG: name='y' namespace='ns1'\n" +
"ENDTAG: name='y' namespace='ns1'\n" +
"ENDTAG: name='x' namespace='ns1'\n",
XmlBuilder.ProcessingOrder.TAGS_AND_ATTRIBUTES);
}
public void testSimpleEntityResolution() throws Exception {
doTest(
"<root>&lt;</root>",
"TAG: name='root' namespace=''\n" +
"TEXT: '&lt;' DISPLAY: '<'\n" +
"ENDTAG: name='root' namespace=''\n",
XmlBuilder.ProcessingOrder.TAGS_AND_TEXTS);
}
public void testCDATA() throws Exception {
doTest(
"<root><![CDATA[<asis/>]]></root>",
"TAG: name='root' namespace=''\n" +
"TEXT: '<![CDATA[<asis/>]]>' DISPLAY: '<asis/>'\n" +
"ENDTAG: name='root' namespace=''\n",
XmlBuilder.ProcessingOrder.TAGS_AND_TEXTS
);
}
public void testErrors() throws Exception {
doTest(
"<root>" +
"<foo>" +
"<bar" +
"<" +
"</root>",
"TAG: name='root' namespace=''\n" +
"TAG: name='foo' namespace=''\n" +
"ERROR: 'Element foo is not closed'\n" +
"ENDTAG: name='foo' namespace=''\n" +
"TAG: name='bar' namespace=''\n" +
"ERROR: 'Tag start is not closed'\n" +
"ENDTAG: name='bar' namespace=''\n" +
"TAG: name='' namespace=''\n" +
"ERROR: 'Tag name expected'\n" +
"ENDTAG: name='' namespace=''\n" +
"ENDTAG: name='root' namespace=''\n",
XmlBuilder.ProcessingOrder.TAGS_AND_TEXTS
);
}
public void testComments() throws Exception {
doTest(
"<root>" +
"<foo>" +
"<!--aa-->" +
"</foo>" +
"<foo>" +
"<!---->" +
"</foo>" +
"<foo>" +
"aaa<!--aa-->aaa" +
"</foo>" +
"<foo>" +
"\naaa\n<!--aa-->\naaa\n" +
"</foo>" +
"</root>",
"TAG: name='root' namespace=''\n" +
"TAG: name='foo' namespace=''\n" +
"ENDTAG: name='foo' namespace=''\n" +
"TAG: name='foo' namespace=''\n" +
"ENDTAG: name='foo' namespace=''\n" +
"TAG: name='foo' namespace=''\n" +
"TEXT: 'aaaaaa' DISPLAY: 'aaaaaa'\n" +
"ENDTAG: name='foo' namespace=''\n" +
"TAG: name='foo' namespace=''\n" +
"TEXT: '\naaa\n\naaa\n' DISPLAY: '\naaa\n\naaa\n'\n" +
"ENDTAG: name='foo' namespace=''\n" +
"ENDTAG: name='root' namespace=''\n",
XmlBuilder.ProcessingOrder.TAGS_AND_TEXTS
);
}
private static void doTest(String xml, String expectedEventSequence, final XmlBuilder.ProcessingOrder tagsAndAttributes) {
final TestXmlBuilder builder = new TestXmlBuilder(tagsAndAttributes);
new XmlBuilderDriver(xml).build(builder);
assertEquals(expectedEventSequence, builder.getResult());
}
}