blob: c75fe42d2bc73a8cb36bd6977c15be4f7400694e [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.
*/
package com.intellij.util.xml;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Key;
import com.intellij.testFramework.IdeaTestUtil;
import com.intellij.testFramework.PlatformTestUtil;
import com.intellij.util.Consumer;
import com.intellij.util.ParameterizedTypeImpl;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.xml.impl.DomTestCase;
import com.intellij.util.xml.reflect.*;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
/**
* @author peter
*/
public class DomExtensionsTest extends DomTestCase {
private static final Key<Boolean> BOOL_KEY = Key.create("aaa");
public void testExtendAttributes() throws Throwable {
registerDomExtender(AttrDomExtender.class);
assertEmpty(getCustomChildren(createElement("<a foo=\"xxx\"/>", MyElement.class)));
MyElement element = createElement("<a attr=\"foo\" foo=\"true\"/>", MyElement.class);
final GenericAttributeValue child = assertInstanceOf(assertOneElement(getCustomChildren(element)), GenericAttributeValue.class);
assertEquals("true", child.getStringValue());
assertEquals(Boolean.TRUE, child.getValue());
assertEquals(Boolean.class, DomUtil.getGenericValueParameter(child.getDomElementType()));
assertSame(element.getXmlTag().getAttribute("foo"), child.getXmlElement());
child.setStringValue("xxx");
assertEquals("xxx", child.getStringValue());
assertEquals("xxx", element.getXmlTag().getAttributeValue("foo"));
element = createElement("<a attr=\"foo\" foo=\"true\"/>", MyElement.class);
final GenericAttributeValue value = getDomManager().getDomElement(element.getXmlTag().getAttribute("foo"));
assertNotNull(value);
assertEquals(value, assertOneElement(getCustomChildren(element)));
assertNotNull(element.getGenericInfo().getAttributeChildDescription("foo"));
}
public void testCustomAttributeChildClass() throws Throwable {
registerDomExtender(AttrDomExtender3.class);
final MyElement element = createElement("<a attr=\"xxx\"/>", MyElement.class);
assertEquals("xxx", assertInstanceOf(assertOneElement(getCustomChildren(element)), MyAttribute.class).getXmlElementName());
}
public void testUserData() throws Throwable {
registerDomExtender(AttrDomExtender3.class);
final MyElement element = createElement("<a attr=\"xxx\"/>", MyElement.class);
final DomAttributeChildDescription description = element.getGenericInfo().getAttributeChildDescription("xxx");
assertNotNull(description);
assertSame(Boolean.TRUE, description.getUserData(BOOL_KEY));
}
public void testUseCustomConverter() throws Throwable {
registerDomExtender(AttrDomExtender2.class);
final MyElement myElement = createElement("<a attr=\"xxx\" xxx=\"zzz\" yyy=\"zzz\"/>", MyElement.class);
assertUnorderedCollection(getCustomChildren(myElement), new Consumer<DomElement>() {
@Override
public void consume(final DomElement element) {
final StringBuffer stringBuffer = ((GenericAttributeValue<StringBuffer>)element).getValue();
assertEquals("zzz", stringBuffer.toString());
assertInstanceOf(((GenericAttributeValue<StringBuffer>)element).getConverter(), StringBufferConverter.class);
assertNotNull(myElement.getGenericInfo().getAttributeChildDescription("xxx"));
Convert convert = element.getAnnotation(Convert.class);
assertNotNull(convert);
assertEquals(StringBufferConverter.class, convert.value());
assertTrue(convert.soft());
}
}, new Consumer<DomElement>() {
@Override
public void consume(final DomElement element) {
final StringBuffer stringBuffer = ((GenericAttributeValue<StringBuffer>)element).getValue();
assertEquals("zzz", stringBuffer.toString());
assertInstanceOf(((GenericAttributeValue<StringBuffer>)element).getConverter(), StringBufferConverter.class);
assertNotNull(myElement.getGenericInfo().getAttributeChildDescription("yyy"));
Convert convert = element.getAnnotation(Convert.class);
assertNotNull(convert);
assertEquals(StringBufferConverter.class, convert.value());
assertFalse(convert.soft());
}
});
}
public void testFixedChildren() throws Throwable {
registerDomExtender(FixedDomExtender.class);
final MyElement myElement = createElement("<a attr=\"xxx\"><xxx>zzz</xxx><yyy attr=\"foo\"/><yyy attr=\"bar\"/></a>", MyElement.class);
assertUnorderedCollection(getCustomChildren(myElement), new Consumer<DomElement>() {
@Override
public void consume(final DomElement element) {
assertEquals(GenericDomValue.class, ReflectionUtil.getRawType(element.getDomElementType()));
final StringBuffer stringBuffer = ((GenericDomValue<StringBuffer>)element).getValue();
assertEquals("zzz", stringBuffer.toString());
assertInstanceOf(((GenericDomValue<StringBuffer>)element).getConverter(), MyStringBufferConverter.class);
assertNotNull(myElement.getGenericInfo().getFixedChildDescription("xxx"));
Convert convert = element.getAnnotation(Convert.class);
assertNotNull(convert);
assertEquals(MyStringBufferConverter.class, convert.value());
assertTrue(convert.soft());
assertNotNull(element.getGenericInfo().getAttributeChildDescription("aaa"));
}
}, new Consumer<DomElement>() {
@Override
public void consume(final DomElement element) {
assertEquals("foo", ((MyElement) element).getAttr().getValue());
assertNull(element.getAnnotation(Convert.class));
}
}, new Consumer<DomElement>() {
@Override
public void consume(final DomElement element) {
assertEquals("bar", ((MyElement) element).getAttr().getValue());
assertNull(element.getAnnotation(Convert.class));
}
});
final DomFixedChildDescription description = myElement.getGenericInfo().getFixedChildDescription("yyy");
assertNotNull(description);
assertEquals(2, description.getCount());
}
public void testCollectionChildren() throws Throwable {
registerDomExtender(CollectionDomExtender.class);
final MyElement myElement = createElement("<a attr=\"xxx\"><xxx>zzz</xxx><xxx attr=\"foo\"/></a>", MyElement.class);
assertUnorderedCollection(getCustomChildren(myElement), new Consumer<DomElement>() {
@Override
public void consume(final DomElement element) {
assertEquals("foo", ((MyElement) element).getAttr().getValue());
assertNull(element.getAnnotation(Convert.class));
}
}, new Consumer<DomElement>() {
@Override
public void consume(final DomElement element) {
assertNull(((MyElement) element).getAttr().getValue());
assertNull(element.getAnnotation(Convert.class));
}
});
assertNotNull(myElement.getGenericInfo().getCollectionChildDescription("xxx"));
}
public void testCollectionAdders() throws Throwable {
registerDomExtender(CollectionDomExtender.class);
final MyElement myElement = createElement("<a attr=\"xxx\"></a>", MyElement.class);
final DomCollectionChildDescription description = myElement.getGenericInfo().getCollectionChildDescription("xxx");
final DomElement element2 = description.addValue(myElement);
final DomElement element0 = description.addValue(myElement, 0);
final DomElement element3 = description.addValue(myElement, MyConcreteElement.class);
final DomElement element1 = description.addValue(myElement, MyConcreteElement.class, 1);
assertSameElements(getCustomChildren(myElement), element0, element1, element2, element3);
}
public void testCustomChildrenAccessFromExtender() throws Throwable {
registerDomExtender(MyCustomChildrenElement.class, CustomDomExtender.class);
final MyCustomChildrenElement myElement = createElement("<a><xx/><yy/><concrete-child/><some-concrete-child/></a>", MyCustomChildrenElement.class);
final DomCollectionChildDescription description = myElement.getGenericInfo().getCollectionChildDescription("xx");
assertNotNull(description);
assertInstanceOf(assertOneElement(description.getValues(myElement)), MyDynamicElement.class);
assertInstanceOf(assertOneElement(myElement.getCustomChidren()), MyCustomElement.class);
assertInstanceOf(assertOneElement(myElement.getConcreteChildren()), MyConcreteElement.class);
assertNotNull(assertInstanceOf(myElement.getSomeConcreteChild(), MyConcreteElement.class).getXmlTag());
}
public void testFirstChildRedefinitionOnExtending() throws Exception {
registerDomExtender(MyCustomChildrenElement.class, ModestDomExtender.class);
final MyCustomChildrenElement myElement = createElement("<a><concrete-child/><concrete-child/></a>", MyCustomChildrenElement.class);
final List<MyConcreteElement> list = myElement.getConcreteChildren();
final List<MyConcreteElement> list2 = myElement.getConcreteChildren();
assertSame(list.get(0), list2.get(0));
assertSame(list.get(1), list2.get(1));
}
public static List<DomElement> getCustomChildren(final DomElement element) {
final List<DomElement> children = new ArrayList<DomElement>();
element.acceptChildren(new DomElementVisitor() {
@Override
public void visitDomElement(final DomElement element) {
if (!"attr".equals(element.getXmlElementName())) {
children.add(element);
}
}
});
return children;
}
public void registerDomExtender(Class<? extends DomExtender<MyElement>> extender) {
registerDomExtender(MyElement.class, extender);
}
public <T extends DomElement> void registerDomExtender(final Class<T> domClass, final Class<? extends DomExtender<T>> extenderClass) {
final DomExtenderEP extenderEP = new DomExtenderEP();
extenderEP.domClassName = domClass.getName();
extenderEP.extenderClassName = extenderClass.getName();
PlatformTestUtil.registerExtension(Extensions.getRootArea(), DomExtenderEP.EP_NAME, extenderEP, myTestRootDisposable);
}
public interface MyElement extends DomElement {
GenericAttributeValue<String> getAttr();
}
public interface MyCustomChildrenElement extends DomElement {
@CustomChildren List<MyCustomElement> getCustomChidren();
List<MyConcreteElement> getConcreteChildren();
MyConcreteElement getSomeConcreteChild();
}
public interface MyConcreteElement extends MyElement {
}
public interface MyCustomElement extends MyElement {
}
public interface MyDynamicElement extends MyElement {
}
public static class AttrDomExtender extends DomExtender<MyElement> {
@Override
public void registerExtensions(@NotNull final MyElement element, @NotNull final DomExtensionsRegistrar registrar) {
final String value = element.getAttr().getValue();
if (value != null) {
registrar.registerGenericAttributeValueChildExtension(new XmlName(value), Boolean.class);
}
}
}
public static class AttrDomExtender2 extends DomExtender<MyElement> {
@Override
public void registerExtensions(@NotNull final MyElement element, @NotNull final DomExtensionsRegistrar registrar) {
final String value = element.getAttr().getValue();
if (value != null) {
registrar.registerGenericAttributeValueChildExtension(new XmlName(value), StringBuffer.class).setConverter(new StringBufferConverter(), true);
registrar.registerGenericAttributeValueChildExtension(new XmlName("yyy"), StringBuffer.class).setConverter(new StringBufferConverter(), false);
}
}
}
public static class AttrDomExtender3 extends DomExtender<MyElement> {
@Override
public void registerExtensions(@NotNull final MyElement element, @NotNull final DomExtensionsRegistrar registrar) {
final String value = element.getAttr().getValue();
if (value != null) {
registrar.registerAttributeChildExtension(new XmlName(value), MyAttribute.class).putUserData(BOOL_KEY, Boolean.TRUE);
}
}
}
public static class FixedDomExtender extends DomExtender<MyElement> {
@Override
public void registerExtensions(@NotNull final MyElement element, @NotNull final DomExtensionsRegistrar registrar) {
final String value = element.getAttr().getValue();
if (value != null) {
final ParameterizedType type = new ParameterizedTypeImpl(GenericDomValue.class, StringBuffer.class);
final DomExtension extension =
registrar.registerFixedNumberChildExtension(new XmlName(value), type).setConverter(new MyStringBufferConverter(true), true);
extension.addExtender(new DomExtender<GenericDomValue<StringBuffer>>(){
@Override
public void registerExtensions(@NotNull final GenericDomValue<StringBuffer> stringBufferGenericDomValue, @NotNull final DomExtensionsRegistrar registrar) {
registrar.registerGenericAttributeValueChildExtension(new XmlName("aaa"), String.class);
}
});
((DomExtensionsRegistrarImpl)registrar).registerFixedNumberChildrenExtension(new XmlName("yyy"), MyElement.class, 2);
}
}
}
public static class CollectionDomExtender extends DomExtender<MyElement> {
@Override
public void registerExtensions(@NotNull final MyElement element, @NotNull final DomExtensionsRegistrar registrar) {
final String value = element.getAttr().getValue();
if (value != null) {
registrar.registerCollectionChildrenExtension(new XmlName(value), MyElement.class).setConverter(new MyStringBufferConverter(true), true);
}
}
}
public static class CustomDomExtender extends DomExtender<MyCustomChildrenElement> {
@Override
public void registerExtensions(@NotNull final MyCustomChildrenElement element, @NotNull final DomExtensionsRegistrar registrar) {
assertEmpty(element.getCustomChidren());
registrar.registerCollectionChildrenExtension(new XmlName("xx"), MyDynamicElement.class);
}
}
public static class ModestDomExtender extends DomExtender<MyCustomChildrenElement> {
@Override
public void registerExtensions(@NotNull final MyCustomChildrenElement element, @NotNull final DomExtensionsRegistrar registrar) {
registrar.registerCollectionChildrenExtension(new XmlName("xx"), MyDynamicElement.class);
}
}
public static class MyStringBufferConverter extends StringBufferConverter {
public MyStringBufferConverter(boolean b) {
}
}
public static interface MyAttribute extends GenericAttributeValue<Boolean> {}
}