| /* |
| * 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> {} |
| } |
| |