diff options
author | Emmanuel Bourg <ebourg@apache.org> | 2014-12-03 14:31:16 +0100 |
---|---|---|
committer | Emmanuel Bourg <ebourg@apache.org> | 2014-12-03 14:31:16 +0100 |
commit | c56370beb0a2bfa263e125fce107dceccee89fd3 (patch) | |
tree | 7ee611ceb0acbbdf7f83abcd72adb854b7d77225 /spring-core/src/test/java/org/springframework | |
parent | aa5221b73661fa728dc4e62e1230e9104528c4eb (diff) |
Imported Upstream version 3.2.12
Diffstat (limited to 'spring-core/src/test/java/org/springframework')
134 files changed, 21257 insertions, 0 deletions
diff --git a/spring-core/src/test/java/org/springframework/core/AbstractControlFlowTests.java b/spring-core/src/test/java/org/springframework/core/AbstractControlFlowTests.java new file mode 100644 index 00000000..56e59e2d --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/AbstractControlFlowTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + */ +public abstract class AbstractControlFlowTests extends TestCase { + + protected abstract ControlFlow createControlFlow(); + + /* + * Class to test for boolean under(Class) + */ + public void testUnderClassAndMethod() { + new One().test(); + new Two().testing(); + new Three().test(); + } + + /* + public void testUnderPackage() { + ControlFlow cflow = new ControlFlow(); + assertFalse(cflow.underPackage("org.springframework.aop")); + assertTrue(cflow.underPackage("org.springframework.aop.support")); + assertFalse(cflow.underPackage("com.interface21")); + } + */ + + + public class One { + + public void test() { + ControlFlow cflow = createControlFlow(); + assertTrue(cflow.under(One.class)); + assertTrue(cflow.under(AbstractControlFlowTests.class)); + assertFalse(cflow.under(Two.class)); + assertTrue(cflow.under(One.class, "test")); + assertFalse(cflow.under(One.class, "hashCode")); + } + + } + + + public class Two { + + public void testing() { + ControlFlow cflow = createControlFlow(); + assertTrue(cflow.under(Two.class)); + assertTrue(cflow.under(AbstractControlFlowTests.class)); + assertFalse(cflow.under(One.class)); + assertFalse(cflow.under(Two.class, "test")); + assertTrue(cflow.under(Two.class, "testing")); + } + } + + + public class Three { + + public void test() { + testing(); + } + + private void testing() { + ControlFlow cflow = createControlFlow(); + assertTrue(cflow.under(Three.class)); + assertTrue(cflow.under(AbstractControlFlowTests.class)); + assertFalse(cflow.under(One.class)); + assertTrue(cflow.under(Three.class, "test")); + assertTrue(cflow.under(Three.class, "testing")); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/AbstractGenericsTests.java b/spring-core/src/test/java/org/springframework/core/AbstractGenericsTests.java new file mode 100644 index 00000000..3d85742f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/AbstractGenericsTests.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * 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 org.springframework.core; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +import junit.framework.TestCase; + +/** + * @author Serge Bogatyrjov + */ +public abstract class AbstractGenericsTests extends TestCase { + + protected Class<?> targetClass; + + protected String methods[]; + + protected Type expectedResults[]; + + protected void executeTest() throws NoSuchMethodException { + String methodName = getName().substring(4); + methodName = methodName.substring(0, 1).toLowerCase() + methodName.substring(1); + for (int i = 0; i < this.methods.length; i++) { + if (methodName.equals(this.methods[i])) { + Method method = this.targetClass.getMethod(methodName); + Type type = getType(method); + assertEquals(this.expectedResults[i], type); + return; + } + } + throw new IllegalStateException("Bad test data"); + } + + protected abstract Type getType(Method method); + +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/core/AttributeAccessorSupportTests.java b/spring-core/src/test/java/org/springframework/core/AttributeAccessorSupportTests.java new file mode 100644 index 00000000..3a92c77c --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/AttributeAccessorSupportTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +import junit.framework.TestCase; + +import java.util.Arrays; + +/** + * @author Rob Harrop + * @since 2.0 + */ +public class AttributeAccessorSupportTests extends TestCase { + + private static final String NAME = "foo"; + + private static final String VALUE = "bar"; + + private AttributeAccessor attributeAccessor; + + @Override + @SuppressWarnings("serial") + protected void setUp() throws Exception { + this.attributeAccessor = new AttributeAccessorSupport() { + }; + } + + public void testSetAndGet() throws Exception { + this.attributeAccessor.setAttribute(NAME, VALUE); + assertEquals(VALUE, this.attributeAccessor.getAttribute(NAME)); + } + + public void testSetAndHas() throws Exception { + assertFalse(this.attributeAccessor.hasAttribute(NAME)); + this.attributeAccessor.setAttribute(NAME, VALUE); + assertTrue(this.attributeAccessor.hasAttribute(NAME)); + } + + public void testRemove() throws Exception { + assertFalse(this.attributeAccessor.hasAttribute(NAME)); + this.attributeAccessor.setAttribute(NAME, VALUE); + assertEquals(VALUE, this.attributeAccessor.removeAttribute(NAME)); + assertFalse(this.attributeAccessor.hasAttribute(NAME)); + } + + public void testAttributeNames() throws Exception { + this.attributeAccessor.setAttribute(NAME, VALUE); + this.attributeAccessor.setAttribute("abc", "123"); + String[] attributeNames = this.attributeAccessor.attributeNames(); + Arrays.sort(attributeNames); + assertTrue(Arrays.binarySearch(attributeNames, NAME) > -1); + assertTrue(Arrays.binarySearch(attributeNames, "abc") > -1); + } + @Override + protected void tearDown() throws Exception { + this.attributeAccessor.removeAttribute(NAME); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java b/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java new file mode 100644 index 00000000..dbca8b7b --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/BridgeMethodResolverTests.java @@ -0,0 +1,1315 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Delayed; + +import static org.junit.Assert.*; +import org.junit.Test; + +import org.springframework.util.ReflectionUtils; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + * @author Chris Beams + */ +public class BridgeMethodResolverTests { + + private static TypeVariable<?> findTypeVariable(Class<?> clazz, String name) { + TypeVariable<?>[] variables = clazz.getTypeParameters(); + for (TypeVariable<?> variable : variables) { + if (variable.getName().equals(name)) { + return variable; + } + } + return null; + } + + private static Method findMethodWithReturnType(String name, Class<?> returnType, Class<SettingsDaoImpl> targetType) { + Method[] methods = targetType.getMethods(); + for (Method m : methods) { + if (m.getName().equals(name) && m.getReturnType().equals(returnType)) { + return m; + } + } + return null; + } + + + @Test + public void testFindBridgedMethod() throws Exception { + Method unbridged = MyFoo.class.getDeclaredMethod("someMethod", String.class, Object.class); + Method bridged = MyFoo.class.getDeclaredMethod("someMethod", Serializable.class, Object.class); + assertFalse(unbridged.isBridge()); + assertTrue(bridged.isBridge()); + + assertEquals("Unbridged method not returned directly", unbridged, BridgeMethodResolver.findBridgedMethod(unbridged)); + assertEquals("Incorrect bridged method returned", unbridged, BridgeMethodResolver.findBridgedMethod(bridged)); + } + + @Test + public void testFindBridgedVarargMethod() throws Exception { + Method unbridged = MyFoo.class.getDeclaredMethod("someVarargMethod", String.class, Object[].class); + Method bridged = MyFoo.class.getDeclaredMethod("someVarargMethod", Serializable.class, Object[].class); + assertFalse(unbridged.isBridge()); + assertTrue(bridged.isBridge()); + + assertEquals("Unbridged method not returned directly", unbridged, BridgeMethodResolver.findBridgedMethod(unbridged)); + assertEquals("Incorrect bridged method returned", unbridged, BridgeMethodResolver.findBridgedMethod(bridged)); + } + + @Test + public void testFindBridgedMethodInHierarchy() throws Exception { + Method bridgeMethod = DateAdder.class.getMethod("add", Object.class); + assertTrue(bridgeMethod.isBridge()); + Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(bridgeMethod); + assertFalse(bridgedMethod.isBridge()); + assertEquals("add", bridgedMethod.getName()); + assertEquals(1, bridgedMethod.getParameterTypes().length); + assertEquals(Date.class, bridgedMethod.getParameterTypes()[0]); + } + + @Test + public void testIsBridgeMethodFor() throws Exception { + Map<TypeVariable, Type> typeParameterMap = GenericTypeResolver.getTypeVariableMap(MyBar.class); + Method bridged = MyBar.class.getDeclaredMethod("someMethod", String.class, Object.class); + Method other = MyBar.class.getDeclaredMethod("someMethod", Integer.class, Object.class); + Method bridge = MyBar.class.getDeclaredMethod("someMethod", Object.class, Object.class); + + assertTrue("Should be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, bridged, typeParameterMap)); + assertFalse("Should not be bridge method", BridgeMethodResolver.isBridgeMethodFor(bridge, other, typeParameterMap)); + } + + @Test + public void testCreateTypeVariableMap() throws Exception { + Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(MyBar.class); + TypeVariable<?> barT = findTypeVariable(InterBar.class, "T"); + assertEquals(String.class, typeVariableMap.get(barT)); + + typeVariableMap = GenericTypeResolver.getTypeVariableMap(MyFoo.class); + TypeVariable<?> fooT = findTypeVariable(Foo.class, "T"); + assertEquals(String.class, typeVariableMap.get(fooT)); + + typeVariableMap = GenericTypeResolver.getTypeVariableMap(ExtendsEnclosing.ExtendsEnclosed.ExtendsReallyDeepNow.class); + TypeVariable<?> r = findTypeVariable(Enclosing.Enclosed.ReallyDeepNow.class, "R"); + TypeVariable<?> s = findTypeVariable(Enclosing.Enclosed.class, "S"); + TypeVariable<?> t = findTypeVariable(Enclosing.class, "T"); + assertEquals(Long.class, typeVariableMap.get(r)); + assertEquals(Integer.class, typeVariableMap.get(s)); + assertEquals(String.class, typeVariableMap.get(t)); + } + + @Test + public void testDoubleParameterization() throws Exception { + Method objectBridge = MyBoo.class.getDeclaredMethod("foo", Object.class); + Method serializableBridge = MyBoo.class.getDeclaredMethod("foo", Serializable.class); + + Method stringFoo = MyBoo.class.getDeclaredMethod("foo", String.class); + Method integerFoo = MyBoo.class.getDeclaredMethod("foo", Integer.class); + + assertEquals("foo(String) not resolved.", stringFoo, BridgeMethodResolver.findBridgedMethod(objectBridge)); + assertEquals("foo(Integer) not resolved.", integerFoo, BridgeMethodResolver.findBridgedMethod(serializableBridge)); + } + + @Test + public void testFindBridgedMethodFromMultipleBridges() throws Exception { + Method loadWithObjectReturn = findMethodWithReturnType("load", Object.class, SettingsDaoImpl.class); + assertNotNull(loadWithObjectReturn); + + Method loadWithSettingsReturn = findMethodWithReturnType("load", Settings.class, SettingsDaoImpl.class); + assertNotNull(loadWithSettingsReturn); + assertNotSame(loadWithObjectReturn, loadWithSettingsReturn); + + Method method = SettingsDaoImpl.class.getMethod("load"); + assertEquals(method, BridgeMethodResolver.findBridgedMethod(loadWithObjectReturn)); + assertEquals(method, BridgeMethodResolver.findBridgedMethod(loadWithSettingsReturn)); + } + + @Test + public void testFindBridgedMethodFromParent() throws Exception { + Method loadFromParentBridge = SettingsDaoImpl.class.getMethod("loadFromParent"); + assertTrue(loadFromParentBridge.isBridge()); + + Method loadFromParent = AbstractDaoImpl.class.getMethod("loadFromParent"); + assertFalse(loadFromParent.isBridge()); + + assertEquals(loadFromParent, BridgeMethodResolver.findBridgedMethod(loadFromParentBridge)); + } + + @Test + public void testWithSingleBoundParameterizedOnInstantiate() throws Exception { + Method bridgeMethod = DelayQueue.class.getMethod("add", Object.class); + assertTrue(bridgeMethod.isBridge()); + Method actualMethod = DelayQueue.class.getMethod("add", Delayed.class); + assertFalse(actualMethod.isBridge()); + assertEquals(actualMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testWithDoubleBoundParameterizedOnInstantiate() throws Exception { + Method bridgeMethod = SerializableBounded.class.getMethod("boundedOperation", Object.class); + assertTrue(bridgeMethod.isBridge()); + Method actualMethod = SerializableBounded.class.getMethod("boundedOperation", HashMap.class); + assertFalse(actualMethod.isBridge()); + assertEquals(actualMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testWithGenericParameter() throws Exception { + Method[] methods = StringGenericParameter.class.getMethods(); + Method bridgeMethod = null; + Method bridgedMethod = null; + for (Method method : methods) { + if ("getFor".equals(method.getName()) && !method.getParameterTypes()[0].equals(Integer.class)) { + if (method.getReturnType().equals(Object.class)) { + bridgeMethod = method; + } + else { + bridgedMethod = method; + } + } + } + assertTrue(bridgeMethod != null && bridgeMethod.isBridge()); + assertTrue(bridgedMethod != null && !bridgedMethod.isBridge()); + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testOnAllMethods() throws Exception { + Method[] methods = StringList.class.getMethods(); + for (Method method : methods) { + assertNotNull(BridgeMethodResolver.findBridgedMethod(method)); + } + } + + @Test + public void testSPR2583() throws Exception { + Method bridgedMethod = MessageBroadcasterImpl.class.getMethod("receive", MessageEvent.class); + assertFalse(bridgedMethod.isBridge()); + Method bridgeMethod = MessageBroadcasterImpl.class.getMethod("receive", Event.class); + assertTrue(bridgeMethod.isBridge()); + + Method otherMethod = MessageBroadcasterImpl.class.getMethod("receive", NewMessageEvent.class); + assertFalse(otherMethod.isBridge()); + + Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(MessageBroadcasterImpl.class); + assertFalse("Match identified incorrectly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, otherMethod, typeVariableMap)); + assertTrue("Match not found correctly", BridgeMethodResolver.isBridgeMethodFor(bridgeMethod, bridgedMethod, typeVariableMap)); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testSPR2454() throws Exception { + Map<TypeVariable, Type> typeVariableMap = GenericTypeResolver.getTypeVariableMap(YourHomer.class); + TypeVariable<?> variable = findTypeVariable(MyHomer.class, "L"); + assertEquals(AbstractBounded.class, ((ParameterizedType) typeVariableMap.get(variable)).getRawType()); + } + + @Test + public void testSPR2603() throws Exception { + Method objectBridge = YourHomer.class.getDeclaredMethod("foo", Bounded.class); + Method abstractBoundedFoo = YourHomer.class.getDeclaredMethod("foo", AbstractBounded.class); + + Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(objectBridge); + assertEquals("foo(AbstractBounded) not resolved.", abstractBoundedFoo, bridgedMethod); + } + + @Test + public void testSPR2648() throws Exception { + Method bridgeMethod = ReflectionUtils.findMethod(GenericSqlMapIntegerDao.class, "saveOrUpdate", Object.class); + assertTrue(bridgeMethod != null && bridgeMethod.isBridge()); + Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(bridgeMethod); + assertFalse(bridgedMethod.isBridge()); + assertEquals("saveOrUpdate", bridgedMethod.getName()); + } + + @Test + public void testSPR2763() throws Exception { + Method bridgedMethod = AbstractDao.class.getDeclaredMethod("save", Object.class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = UserDaoImpl.class.getDeclaredMethod("save", User.class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testSPR3041() throws Exception { + Method bridgedMethod = BusinessDao.class.getDeclaredMethod("save", Business.class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = BusinessDao.class.getDeclaredMethod("save", Object.class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testSPR3173() throws Exception { + Method bridgedMethod = UserDaoImpl.class.getDeclaredMethod("saveVararg", User.class, Object[].class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = UserDaoImpl.class.getDeclaredMethod("saveVararg", Object.class, Object[].class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testSPR3304() throws Exception { + Method bridgedMethod = MegaMessageProducerImpl.class.getDeclaredMethod("receive", MegaMessageEvent.class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = MegaMessageProducerImpl.class.getDeclaredMethod("receive", MegaEvent.class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testSPR3324() throws Exception { + Method bridgedMethod = BusinessDao.class.getDeclaredMethod("get", Long.class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = BusinessDao.class.getDeclaredMethod("get", Object.class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testSPR3357() throws Exception { + Method bridgedMethod = ExtendsAbstractImplementsInterface.class.getDeclaredMethod( + "doSomething", DomainObjectExtendsSuper.class, Object.class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = ExtendsAbstractImplementsInterface.class.getDeclaredMethod( + "doSomething", DomainObjectSuper.class, Object.class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testSPR3485() throws Exception { + Method bridgedMethod = DomainObject.class.getDeclaredMethod( + "method2", ParameterType.class, byte[].class); + assertFalse(bridgedMethod.isBridge()); + + Method bridgeMethod = DomainObject.class.getDeclaredMethod( + "method2", Serializable.class, Object.class); + assertTrue(bridgeMethod.isBridge()); + + assertEquals(bridgedMethod, BridgeMethodResolver.findBridgedMethod(bridgeMethod)); + } + + @Test + public void testSPR3534() throws Exception { + Method bridgeMethod = ReflectionUtils.findMethod(TestEmailProvider.class, "findBy", Object.class); + assertTrue(bridgeMethod != null && bridgeMethod.isBridge()); + Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(bridgeMethod); + assertFalse(bridgedMethod.isBridge()); + assertEquals("findBy", bridgedMethod.getName()); + } + + + public static interface Foo<T extends Serializable> { + + void someMethod(T theArg, Object otherArg); + + void someVarargMethod(T theArg, Object... otherArg); + } + + + public static class MyFoo implements Foo<String> { + + public void someMethod(Integer theArg, Object otherArg) { + } + + @Override + public void someMethod(String theArg, Object otherArg) { + } + + @Override + public void someVarargMethod(String theArg, Object... otherArgs) { + } + } + + + public static abstract class Bar<T> { + + void someMethod(Map<?, ?> m, Object otherArg) { + } + + void someMethod(T theArg, Map<?, ?> m) { + } + + abstract void someMethod(T theArg, Object otherArg); + } + + + public static abstract class InterBar<T> extends Bar<T> { + + } + + + public static class MyBar extends InterBar<String> { + + @Override + public void someMethod(String theArg, Object otherArg) { + } + + public void someMethod(Integer theArg, Object otherArg) { + } + } + + + public interface Adder<T> { + + void add(T item); + } + + + public abstract class AbstractDateAdder implements Adder<Date> { + + @Override + public abstract void add(Date date); + } + + + public class DateAdder extends AbstractDateAdder { + + @Override + public void add(Date date) { + } + } + + + public class Enclosing<T> { + + public class Enclosed<S> { + + public class ReallyDeepNow<R> { + + void someMethod(S s, T t, R r) { + } + } + } + } + + + public class ExtendsEnclosing extends Enclosing<String> { + + public class ExtendsEnclosed extends Enclosed<Integer> { + + public class ExtendsReallyDeepNow extends ReallyDeepNow<Long> { + + @Override + void someMethod(Integer s, String t, Long r) { + throw new UnsupportedOperationException(); + } + } + } + } + + + public interface Boo<E, T extends Serializable> { + + void foo(E e); + + void foo(T t); + } + + + public class MyBoo implements Boo<String, Integer> { + + @Override + public void foo(String e) { + throw new UnsupportedOperationException(); + } + + @Override + public void foo(Integer t) { + throw new UnsupportedOperationException(); + } + } + + + public interface Settings { + + } + + + public interface ConcreteSettings extends Settings { + + } + + + public interface Dao<T, S> { + + T load(); + + S loadFromParent(); + } + + + public interface SettingsDao<T extends Settings, S> extends Dao<T, S> { + + @Override + T load(); + } + + + public interface ConcreteSettingsDao extends SettingsDao<ConcreteSettings, String> { + + @Override + String loadFromParent(); + } + + + abstract class AbstractDaoImpl<T, S> implements Dao<T, S> { + + protected T object; + + protected S otherObject; + + protected AbstractDaoImpl(T object, S otherObject) { + this.object = object; + this.otherObject = otherObject; + } + + //@Transactional(readOnly = true) + @Override + public S loadFromParent() { + return otherObject; + } + } + + + class SettingsDaoImpl extends AbstractDaoImpl<ConcreteSettings, String> implements ConcreteSettingsDao { + + protected SettingsDaoImpl(ConcreteSettings object) { + super(object, "From Parent"); + } + + //@Transactional(readOnly = true) + @Override + public ConcreteSettings load() { + return super.object; + } + } + + + public static interface Bounded<E> { + + boolean boundedOperation(E e); + } + + + private static class AbstractBounded<E> implements Bounded<E> { + + @Override + public boolean boundedOperation(E myE) { + return true; + } + } + + + private static class SerializableBounded<E extends HashMap & Delayed> extends AbstractBounded<E> { + + @Override + public boolean boundedOperation(E myE) { + return false; + } + } + + + public static interface GenericParameter<T> { + + T getFor(Class<T> cls); + } + + + @SuppressWarnings("unused") + private static class StringGenericParameter implements GenericParameter<String> { + + @Override + public String getFor(Class<String> cls) { + return "foo"; + } + + public String getFor(Integer integer) { + return "foo"; + } + } + + + private static class StringList implements List<String> { + + @Override + public int size() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isEmpty() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean contains(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator<String> iterator() { + throw new UnsupportedOperationException(); + } + + @Override + public Object[] toArray() { + throw new UnsupportedOperationException(); + } + + @Override + public <T> T[] toArray(T[] a) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean add(String o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsAll(Collection<?> c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(Collection<? extends String> c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(int index, Collection<? extends String> c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(Collection<?> c) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean retainAll(Collection<?> c) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public String get(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public String set(int index, String element) { + throw new UnsupportedOperationException(); + } + + @Override + public void add(int index, String element) { + throw new UnsupportedOperationException(); + } + + @Override + public String remove(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public int indexOf(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public int lastIndexOf(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public ListIterator<String> listIterator() { + throw new UnsupportedOperationException(); + } + + @Override + public ListIterator<String> listIterator(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public List<String> subList(int fromIndex, int toIndex) { + throw new UnsupportedOperationException(); + } + } + + + public interface Event { + + int getPriority(); + } + + + public class GenericEvent implements Event { + + private int priority; + + @Override + public int getPriority() { + return priority; + } + + /** + * Constructor that takes an event priority + */ + public GenericEvent(int priority) { + this.priority = priority; + } + + /** + * Default Constructor + */ + public GenericEvent() { + } + } + + + public interface UserInitiatedEvent { + + //public Session getInitiatorSession(); + } + + + public abstract class BaseUserInitiatedEvent extends GenericEvent implements UserInitiatedEvent { + + } + + + public class MessageEvent extends BaseUserInitiatedEvent { + + } + + + public interface Channel<E extends Event> { + + void send(E event); + + void subscribe(final Receiver<E> receiver, Class<E> event); + + void unsubscribe(final Receiver<E> receiver, Class<E> event); + } + + + public interface Broadcaster { + } + + + public interface EventBroadcaster extends Broadcaster { + + public void subscribe(); + + public void unsubscribe(); + + public void setChannel(Channel<?> channel); + } + + + public class GenericBroadcasterImpl implements Broadcaster { + + } + + + public abstract class GenericEventBroadcasterImpl<T extends Event> extends GenericBroadcasterImpl + implements EventBroadcaster { + + private Class<T>[] subscribingEvents; + + private Channel<T> channel; + + /** + * Abstract method to retrieve instance of subclass + * + * @return receiver instance + */ + public abstract Receiver<T> getInstance(); + + @Override + public void setChannel(Channel channel) { + this.channel = channel; + } + + private String beanName; + + public void setBeanName(String name) { + this.beanName = name; + } + + @Override + public void subscribe() { + + } + + @Override + public void unsubscribe() { + + } + + public GenericEventBroadcasterImpl(Class<? extends T>... events) { + + } + } + + + public interface Receiver<E extends Event> { + + void receive(E event); + } + + + public interface MessageBroadcaster extends Receiver<MessageEvent> { + + } + + + public class RemovedMessageEvent extends MessageEvent { + + } + + + public class NewMessageEvent extends MessageEvent { + + } + + + public class ModifiedMessageEvent extends MessageEvent { + + } + + + public class MessageBroadcasterImpl extends GenericEventBroadcasterImpl<MessageEvent> + implements MessageBroadcaster { + + public MessageBroadcasterImpl() { + super(NewMessageEvent.class); + } + + @Override + public void receive(MessageEvent event) { + throw new UnsupportedOperationException("should not be called, use subclassed events"); + } + + public void receive(NewMessageEvent event) { + } + + @Override + public Receiver<MessageEvent> getInstance() { + return null; + } + + public void receive(RemovedMessageEvent event) { + } + + public void receive(ModifiedMessageEvent event) { + } + } + + + //----------------------------- + // SPR-2454 Test Classes + //----------------------------- + + public interface SimpleGenericRepository<T> { + + public Class<T> getPersistentClass(); + + List<T> findByQuery(); + + List<T> findAll(); + + T refresh(T entity); + + T saveOrUpdate(T entity); + + void delete(Collection<T> entities); + } + + + public interface RepositoryRegistry { + + <T> SimpleGenericRepository<T> getFor(Class<T> entityType); + } + + + public class SettableRepositoryRegistry<R extends SimpleGenericRepository<?>> + implements RepositoryRegistry { + + protected void injectInto(R rep) { + } + + public void register(R rep) { + } + + public void register(R... reps) { + } + + public void setRepos(R... reps) { + } + + @Override + public <T> SimpleGenericRepository<T> getFor(Class<T> entityType) { + return null; + } + + public void afterPropertiesSet() throws Exception { + } + } + + + public interface ConvenientGenericRepository<T, ID extends Serializable> extends SimpleGenericRepository<T> { + + T findById(ID id, boolean lock); + + List<T> findByExample(T exampleInstance); + + void delete(ID id); + + void delete(T entity); + } + + + public class GenericHibernateRepository<T, ID extends Serializable> + implements ConvenientGenericRepository<T, ID> { + + /** + * @param c Mandatory. The domain class this repository is responsible for. + */ + // Since it is impossible to determine the actual type of a type + // parameter (!), we resort to requiring the caller to provide the + // actual type as parameter, too. + // Not set in a constructor to enable easy CGLIB-proxying (passing + // constructor arguments to Spring AOP proxies is quite cumbersome). + public void setPersistentClass(Class<T> c) { + } + + @Override + public Class<T> getPersistentClass() { + return null; + } + + @Override + public T findById(ID id, boolean lock) { + return null; + } + + @Override + public List<T> findAll() { + return null; + } + + @Override + public List<T> findByExample(T exampleInstance) { + return null; + } + + @Override + public List<T> findByQuery() { + return null; + } + + @Override + public T saveOrUpdate(T entity) { + return null; + } + + @Override + public void delete(T entity) { + } + + @Override + public T refresh(T entity) { + return null; + } + + @Override + public void delete(ID id) { + } + + @Override + public void delete(Collection<T> entities) { + } + } + + + public class HibernateRepositoryRegistry extends SettableRepositoryRegistry<GenericHibernateRepository<?, ?>> { + + @Override + public void injectInto(GenericHibernateRepository<?, ?> rep) { + } + + @Override + public <T> GenericHibernateRepository<T, ?> getFor(Class<T> entityType) { + return null; + } + } + + + //------------------- + // SPR-2603 classes + //------------------- + + public interface Homer<E> { + + void foo(E e); + } + + + public class MyHomer<T extends Bounded<T>, L extends T> implements Homer<L> { + + @Override + public void foo(L t) { + throw new UnsupportedOperationException(); + } + } + + + public class YourHomer<T extends AbstractBounded<T>, L extends T> extends MyHomer<T, L> { + + @Override + public void foo(L t) { + throw new UnsupportedOperationException(); + } + } + + + public interface GenericDao<T> { + + public void saveOrUpdate(T t); + } + + + public interface ConvenienceGenericDao<T> extends GenericDao<T> { + } + + + public class GenericSqlMapDao<T extends Serializable> implements ConvenienceGenericDao<T> { + + @Override + public void saveOrUpdate(T t) { + throw new UnsupportedOperationException(); + } + } + + + public class GenericSqlMapIntegerDao<T extends Number> extends GenericSqlMapDao<T> { + + @Override + public void saveOrUpdate(T t) { + } + } + + + public class Permission { + } + + + public class User { + } + + + public interface UserDao { + + //@Transactional + void save(User user); + + //@Transactional + void save(Permission perm); + } + + + public abstract class AbstractDao<T> { + + public void save(T t) { + } + + public void saveVararg(T t, Object... args) { + } + } + + + public class UserDaoImpl extends AbstractDao<User> implements UserDao { + + @Override + public void save(Permission perm) { + } + + @Override + public void saveVararg(User user, Object... args) { + } + } + + + public interface DaoInterface<T,P> { + T get(P id); + } + + + public abstract class BusinessGenericDao<T, PK extends Serializable> implements DaoInterface<T, PK> { + + public void save(T object) { + } + } + + + public class Business<T> { + } + + + public class BusinessDao extends BusinessGenericDao<Business<?>, Long> { + + @Override + public void save(Business<?> business) { + } + + @Override + public Business<?> get(Long id) { + return null; + } + + public Business<?> get(String code) { + return null; + } + } + + + //------------------- + // SPR-3304 classes + //------------------- + + private static class MegaEvent { + } + + + private static class MegaMessageEvent extends MegaEvent { + } + + + private static class NewMegaMessageEvent extends MegaEvent { + } + + + private static class ModifiedMegaMessageEvent extends MegaEvent { + } + + + public static interface MegaReceiver<E extends MegaEvent> { + + void receive(E event); + } + + + public static interface MegaMessageProducer extends MegaReceiver<MegaMessageEvent> { + } + + + private static class Other<S,E> { + } + + + @SuppressWarnings("unused") + private static class MegaMessageProducerImpl extends Other<Long, String> implements MegaMessageProducer { + + public void receive(NewMegaMessageEvent event) { + throw new UnsupportedOperationException(); + } + + public void receive(ModifiedMegaMessageEvent event) { + throw new UnsupportedOperationException(); + } + + @Override + public void receive(MegaMessageEvent event) { + throw new UnsupportedOperationException(); + } + } + + + //------------------- + // SPR-3357 classes + //------------------- + + private static class DomainObjectSuper { + } + + + private static class DomainObjectExtendsSuper extends DomainObjectSuper { + } + + + public interface IGenericInterface<D extends DomainObjectSuper> { + + <T> void doSomething(final D domainObject, final T value); + } + + + @SuppressWarnings("unused") + private static abstract class AbstractImplementsInterface<D extends DomainObjectSuper> implements IGenericInterface<D> { + + @Override + public <T> void doSomething(D domainObject, T value) { + } + + public void anotherBaseMethod() { + } + } + + + private static class ExtendsAbstractImplementsInterface extends AbstractImplementsInterface<DomainObjectExtendsSuper> { + + @Override + public <T> void doSomething(DomainObjectExtendsSuper domainObject, T value) { + super.doSomething(domainObject, value); + } + } + + + //------------------- + // SPR-3485 classes + //------------------- + + @SuppressWarnings("serial") + private static class ParameterType implements Serializable { + } + + + private static class AbstractDomainObject<P extends Serializable, R> { + + public R method1(P p) { + return null; + } + + public void method2(P p, R r) { + } + } + + + private static class DomainObject extends AbstractDomainObject<ParameterType, byte[]> { + + @Override + public byte[] method1(ParameterType p) { + return super.method1(p); + } + + @Override + public void method2(ParameterType p, byte[] r) { + super.method2(p, r); + } + } + + + //------------------- + // SPR-3534 classes + //------------------- + + public interface SearchProvider<RETURN_TYPE, CONDITIONS_TYPE> { + + Collection<RETURN_TYPE> findBy(CONDITIONS_TYPE conditions); + } + + + public static class SearchConditions { + } + + + public interface IExternalMessageProvider<S extends ExternalMessage, T extends ExternalMessageSearchConditions<?>> + extends SearchProvider<S, T> { + } + + + public static class ExternalMessage { + } + + + public static class ExternalMessageSearchConditions<T extends ExternalMessage> extends SearchConditions { + } + + + public static class ExternalMessageProvider<S extends ExternalMessage, T extends ExternalMessageSearchConditions<S>> + implements IExternalMessageProvider<S, T> { + + @Override + public Collection<S> findBy(T conditions) { + return null; + } + } + + + public static class EmailMessage extends ExternalMessage { + } + + + public static class EmailSearchConditions extends ExternalMessageSearchConditions<EmailMessage> { + } + + + public static class EmailMessageProvider extends ExternalMessageProvider<EmailMessage, EmailSearchConditions> { + } + + + public static class TestEmailProvider extends EmailMessageProvider { + + @Override + public Collection<EmailMessage> findBy(EmailSearchConditions conditions) { + return null; + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/CollectionFactoryTests.java b/spring-core/src/test/java/org/springframework/core/CollectionFactoryTests.java new file mode 100644 index 00000000..45b27e2d --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/CollectionFactoryTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +import java.util.IdentityHashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.util.MultiValueMap; + +/** + * @author Darren Davison + * @author Juergen Hoeller + * @author Dave Syer + */ +public class CollectionFactoryTests extends TestCase { + + @SuppressWarnings("deprecation") + public void testLinkedSet() { + Set set = CollectionFactory.createLinkedSetIfPossible(16); + assertTrue(set instanceof LinkedHashSet); + } + + @SuppressWarnings("deprecation") + public void testLinkedMap() { + Map map = CollectionFactory.createLinkedMapIfPossible(16); + assertTrue(map instanceof LinkedHashMap); + } + + @SuppressWarnings("deprecation") + public void testIdentityMap() { + Map map = CollectionFactory.createIdentityMapIfPossible(16); + assertTrue(map instanceof IdentityHashMap); + } + + @SuppressWarnings("deprecation") + public void testConcurrentMap() { + Map map = CollectionFactory.createConcurrentMapIfPossible(16); + assertTrue(map.getClass().getName().endsWith("ConcurrentHashMap")); + } + + public void testMultiValueMap() { + Map map = CollectionFactory.createMap(MultiValueMap.class, 16); + assertTrue(map.getClass().getName().endsWith("MultiValueMap")); + } + + @SuppressWarnings("deprecation") + public void testConcurrentMapWithExplicitInterface() { + ConcurrentMap map = CollectionFactory.createConcurrentMap(16); + assertTrue(map.getClass().getSuperclass().getName().endsWith("ConcurrentHashMap")); + map.putIfAbsent("key", "value1"); + map.putIfAbsent("key", "value2"); + assertEquals("value1", map.get("key")); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/ConstantsTests.java b/spring-core/src/test/java/org/springframework/core/ConstantsTests.java new file mode 100644 index 00000000..2dc85aae --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/ConstantsTests.java @@ -0,0 +1,272 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +import java.util.Locale; +import java.util.Set; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + * @since 28.04.2003 + */ +public class ConstantsTests extends TestCase { + + public void testConstants() { + Constants c = new Constants(A.class); + assertEquals(A.class.getName(), c.getClassName()); + assertEquals(9, c.getSize()); + + assertEquals(c.asNumber("DOG").intValue(), A.DOG); + assertEquals(c.asNumber("dog").intValue(), A.DOG); + assertEquals(c.asNumber("cat").intValue(), A.CAT); + + try { + c.asNumber("bogus"); + fail("Can't get bogus field"); + } + catch (ConstantException expected) { + } + + assertTrue(c.asString("S1").equals(A.S1)); + try { + c.asNumber("S1"); + fail("Wrong type"); + } + catch (ConstantException expected) { + } + } + + public void testGetNames() { + Constants c = new Constants(A.class); + + Set<?> names = c.getNames(""); + assertEquals(c.getSize(), names.size()); + assertTrue(names.contains("DOG")); + assertTrue(names.contains("CAT")); + assertTrue(names.contains("S1")); + + names = c.getNames("D"); + assertEquals(1, names.size()); + assertTrue(names.contains("DOG")); + + names = c.getNames("d"); + assertEquals(1, names.size()); + assertTrue(names.contains("DOG")); + } + + public void testGetValues() { + Constants c = new Constants(A.class); + + Set<?> values = c.getValues(""); + assertEquals(7, values.size()); + assertTrue(values.contains(new Integer(0))); + assertTrue(values.contains(new Integer(66))); + assertTrue(values.contains("")); + + values = c.getValues("D"); + assertEquals(1, values.size()); + assertTrue(values.contains(new Integer(0))); + + values = c.getValues("prefix"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(1))); + assertTrue(values.contains(new Integer(2))); + + values = c.getValuesForProperty("myProperty"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(1))); + assertTrue(values.contains(new Integer(2))); + } + + public void testGetValuesInTurkey() { + Locale oldLocale = Locale.getDefault(); + Locale.setDefault(new Locale("tr", "")); + try { + Constants c = new Constants(A.class); + + Set<?> values = c.getValues(""); + assertEquals(7, values.size()); + assertTrue(values.contains(new Integer(0))); + assertTrue(values.contains(new Integer(66))); + assertTrue(values.contains("")); + + values = c.getValues("D"); + assertEquals(1, values.size()); + assertTrue(values.contains(new Integer(0))); + + values = c.getValues("prefix"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(1))); + assertTrue(values.contains(new Integer(2))); + + values = c.getValuesForProperty("myProperty"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(1))); + assertTrue(values.contains(new Integer(2))); + } + finally { + Locale.setDefault(oldLocale); + } + } + + public void testSuffixAccess() { + Constants c = new Constants(A.class); + + Set<?> names = c.getNamesForSuffix("_PROPERTY"); + assertEquals(2, names.size()); + assertTrue(names.contains("NO_PROPERTY")); + assertTrue(names.contains("YES_PROPERTY")); + + Set<?> values = c.getValuesForSuffix("_PROPERTY"); + assertEquals(2, values.size()); + assertTrue(values.contains(new Integer(3))); + assertTrue(values.contains(new Integer(4))); + } + + public void testToCode() { + Constants c = new Constants(A.class); + + assertEquals(c.toCode(new Integer(0), ""), "DOG"); + assertEquals(c.toCode(new Integer(0), "D"), "DOG"); + assertEquals(c.toCode(new Integer(0), "DO"), "DOG"); + assertEquals(c.toCode(new Integer(0), "DoG"), "DOG"); + assertEquals(c.toCode(new Integer(0), null), "DOG"); + assertEquals(c.toCode(new Integer(66), ""), "CAT"); + assertEquals(c.toCode(new Integer(66), "C"), "CAT"); + assertEquals(c.toCode(new Integer(66), "ca"), "CAT"); + assertEquals(c.toCode(new Integer(66), "cAt"), "CAT"); + assertEquals(c.toCode(new Integer(66), null), "CAT"); + assertEquals(c.toCode("", ""), "S1"); + assertEquals(c.toCode("", "s"), "S1"); + assertEquals(c.toCode("", "s1"), "S1"); + assertEquals(c.toCode("", null), "S1"); + try { + c.toCode("bogus", "bogus"); + fail("Should have thrown ConstantException"); + } + catch (ConstantException expected) { + } + try { + c.toCode("bogus", null); + fail("Should have thrown ConstantException"); + } + catch (ConstantException expected) { + } + + assertEquals(c.toCodeForProperty(new Integer(1), "myProperty"), "MY_PROPERTY_NO"); + assertEquals(c.toCodeForProperty(new Integer(2), "myProperty"), "MY_PROPERTY_YES"); + try { + c.toCodeForProperty("bogus", "bogus"); + fail("Should have thrown ConstantException"); + } + catch (ConstantException expected) { + } + + assertEquals(c.toCodeForSuffix(new Integer(0), ""), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(0), "G"), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(0), "OG"), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(0), "DoG"), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(0), null), "DOG"); + assertEquals(c.toCodeForSuffix(new Integer(66), ""), "CAT"); + assertEquals(c.toCodeForSuffix(new Integer(66), "T"), "CAT"); + assertEquals(c.toCodeForSuffix(new Integer(66), "at"), "CAT"); + assertEquals(c.toCodeForSuffix(new Integer(66), "cAt"), "CAT"); + assertEquals(c.toCodeForSuffix(new Integer(66), null), "CAT"); + assertEquals(c.toCodeForSuffix("", ""), "S1"); + assertEquals(c.toCodeForSuffix("", "1"), "S1"); + assertEquals(c.toCodeForSuffix("", "s1"), "S1"); + assertEquals(c.toCodeForSuffix("", null), "S1"); + try { + c.toCodeForSuffix("bogus", "bogus"); + fail("Should have thrown ConstantException"); + } + catch (ConstantException expected) { + } + try { + c.toCodeForSuffix("bogus", null); + fail("Should have thrown ConstantException"); + } + catch (ConstantException expected) { + } + } + + public void testGetValuesWithNullPrefix() throws Exception { + Constants c = new Constants(A.class); + Set<?> values = c.getValues(null); + assertEquals("Must have returned *all* public static final values", 7, values.size()); + } + + public void testGetValuesWithEmptyStringPrefix() throws Exception { + Constants c = new Constants(A.class); + Set<Object> values = c.getValues(""); + assertEquals("Must have returned *all* public static final values", 7, values.size()); + } + + public void testGetValuesWithWhitespacedStringPrefix() throws Exception { + Constants c = new Constants(A.class); + Set<?> values = c.getValues(" "); + assertEquals("Must have returned *all* public static final values", 7, values.size()); + } + + public void testWithClassThatExposesNoConstants() throws Exception { + Constants c = new Constants(NoConstants.class); + assertEquals(0, c.getSize()); + final Set<?> values = c.getValues(""); + assertNotNull(values); + assertEquals(0, values.size()); + } + + public void testCtorWithNullClass() throws Exception { + try { + new Constants(null); + fail("Must have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) {} + } + + + private static final class NoConstants { + } + + + @SuppressWarnings("unused") + private static final class A { + + public static final int DOG = 0; + public static final int CAT = 66; + public static final String S1 = ""; + + public static final int PREFIX_NO = 1; + public static final int PREFIX_YES = 2; + + public static final int MY_PROPERTY_NO = 1; + public static final int MY_PROPERTY_YES = 2; + + public static final int NO_PROPERTY = 3; + public static final int YES_PROPERTY = 4; + + /** ignore these */ + protected static final int P = -1; + protected boolean f; + static final Object o = new Object(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/ConventionsTests.java b/spring-core/src/test/java/org/springframework/core/ConventionsTests.java new file mode 100644 index 00000000..cdc94380 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/ConventionsTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.tests.sample.objects.TestObject; + +/** + * @author Rob Harrop + */ +public class ConventionsTests extends TestCase { + + public void testSimpleObject() { + TestObject testObject = new TestObject(); + assertEquals("Incorrect singular variable name", "testObject", Conventions.getVariableName(testObject)); + } + + public void testArray() { + TestObject[] testObjects = new TestObject[0]; + assertEquals("Incorrect plural array form", "testObjectList", Conventions.getVariableName(testObjects)); + } + + public void testCollections() { + List<TestObject> list = new ArrayList<TestObject>(); + list.add(new TestObject()); + assertEquals("Incorrect plural List form", "testObjectList", Conventions.getVariableName(list)); + + Set<TestObject> set = new HashSet<TestObject>(); + set.add(new TestObject()); + assertEquals("Incorrect plural Set form", "testObjectList", Conventions.getVariableName(set)); + + List<?> emptyList = new ArrayList<Object>(); + try { + Conventions.getVariableName(emptyList); + fail("Should not be able to generate name for empty collection"); + } + catch(IllegalArgumentException ex) { + // success + } + } + + public void testAttributeNameToPropertyName() throws Exception { + assertEquals("transactionManager", Conventions.attributeNameToPropertyName("transaction-manager")); + assertEquals("pointcutRef", Conventions.attributeNameToPropertyName("pointcut-ref")); + assertEquals("lookupOnStartup", Conventions.attributeNameToPropertyName("lookup-on-startup")); + } + + public void testGetQualifiedAttributeName() throws Exception { + String baseName = "foo"; + Class<String> cls = String.class; + String desiredResult = "java.lang.String.foo"; + assertEquals(desiredResult, Conventions.getQualifiedAttributeName(cls, baseName)); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/DefaultControlFlowTests.java b/spring-core/src/test/java/org/springframework/core/DefaultControlFlowTests.java new file mode 100644 index 00000000..a3929896 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/DefaultControlFlowTests.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +/** + * Tests with ControlFlowFactory return. + * + * @author Rod Johnson + */ +public class DefaultControlFlowTests extends AbstractControlFlowTests { + + /** + * Necessary only because Eclipse won't run test suite unless + * it declares some methods as well as inherited methods. + */ + public void testThisClassPlease() { + } + + @Override + protected ControlFlow createControlFlow() { + return ControlFlowFactory.createControlFlow(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/ExceptionDepthComparatorTests.java b/spring-core/src/test/java/org/springframework/core/ExceptionDepthComparatorTests.java new file mode 100644 index 00000000..5de3f4b6 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/ExceptionDepthComparatorTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +import java.util.Arrays; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + * @author Chris Shepperd + */ +public class ExceptionDepthComparatorTests { + + @Test + public void targetBeforeSameDepth() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(TargetException.class, SameDepthException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void sameDepthBeforeTarget() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(SameDepthException.class, TargetException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void lowestDepthBeforeTarget() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(LowestDepthException.class, TargetException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void targetBeforeLowestDepth() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(TargetException.class, LowestDepthException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void noDepthBeforeTarget() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(NoDepthException.class, TargetException.class); + assertEquals(TargetException.class, foundClass); + } + + @Test + public void noDepthBeforeHighestDepth() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(NoDepthException.class, HighestDepthException.class); + assertEquals(HighestDepthException.class, foundClass); + } + + @Test + public void highestDepthBeforeNoDepth() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(HighestDepthException.class, NoDepthException.class); + assertEquals(HighestDepthException.class, foundClass); + } + + @Test + public void highestDepthBeforeLowestDepth() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(HighestDepthException.class, LowestDepthException.class); + assertEquals(LowestDepthException.class, foundClass); + } + + @Test + public void lowestDepthBeforeHighestDepth() throws Exception { + Class<? extends Throwable> foundClass = findClosestMatch(LowestDepthException.class, HighestDepthException.class); + assertEquals(LowestDepthException.class, foundClass); + } + + private Class<? extends Throwable> findClosestMatch( + Class<? extends Throwable>... classes) { + return ExceptionDepthComparator.findClosestMatch(Arrays.asList(classes), new TargetException()); + } + + @SuppressWarnings("serial") + public class HighestDepthException extends Throwable { + } + + @SuppressWarnings("serial") + public class LowestDepthException extends HighestDepthException { + } + + @SuppressWarnings("serial") + public class TargetException extends LowestDepthException { + } + + @SuppressWarnings("serial") + public class SameDepthException extends LowestDepthException { + } + + @SuppressWarnings("serial") + public class NoDepthException extends TargetException { + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java b/spring-core/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java new file mode 100644 index 00000000..08fbaa96 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/GenericCollectionTypeResolverTests.java @@ -0,0 +1,149 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.springframework.core.io.Resource; +import org.springframework.tests.sample.objects.GenericObject; + +/** + * @author Serge Bogatyrjov + * @author Juergen Hoeller + */ +public class GenericCollectionTypeResolverTests extends AbstractGenericsTests { + + @Override + protected void setUp() throws Exception { + this.targetClass = Foo.class; + this.methods = new String[] {"a", "b", "b2", "b3", "c", "d", "d2", "d3", "e", "e2", "e3"}; + this.expectedResults = new Class[] { + Integer.class, null, Set.class, Set.class, null, Integer.class, + Integer.class, Integer.class, Integer.class, Integer.class, Integer.class}; + } + + @Override + protected Type getType(Method method) { + return GenericCollectionTypeResolver.getMapValueReturnType(method); + } + + public void testA() throws Exception { + executeTest(); + } + + public void testB() throws Exception { + executeTest(); + } + + public void testB2() throws Exception { + executeTest(); + } + + public void testB3() throws Exception { + executeTest(); + } + + public void testC() throws Exception { + executeTest(); + } + + public void testD() throws Exception { + executeTest(); + } + + public void testD2() throws Exception { + executeTest(); + } + + public void testD3() throws Exception { + executeTest(); + } + + public void testE() throws Exception { + executeTest(); + } + + public void testE2() throws Exception { + executeTest(); + } + + public void testE3() throws Exception { + executeTest(); + } + + public void testProgrammaticListIntrospection() throws Exception { + Method setter = GenericObject.class.getMethod("setResourceList", List.class); + assertEquals(Resource.class, + GenericCollectionTypeResolver.getCollectionParameterType(new MethodParameter(setter, 0))); + + Method getter = GenericObject.class.getMethod("getResourceList"); + assertEquals(Resource.class, + GenericCollectionTypeResolver.getCollectionReturnType(getter)); + } + + public void testClassResolution() { + assertEquals(String.class, GenericCollectionTypeResolver.getCollectionType(CustomSet.class)); + assertEquals(String.class, GenericCollectionTypeResolver.getMapKeyType(CustomMap.class)); + assertEquals(Integer.class, GenericCollectionTypeResolver.getMapValueType(CustomMap.class)); + } + + + private abstract class CustomSet<T> extends AbstractSet<String> { + } + + + private abstract class CustomMap<T> extends AbstractMap<String, Integer> { + } + + + private abstract class OtherCustomMap<T> implements Map<String, Integer> { + } + + + private interface Foo { + + Map<String, Integer> a(); + + Map<?, ?> b(); + + Map<?, ? extends Set> b2(); + + Map<?, ? super Set> b3(); + + Map c(); + + CustomMap<Date> d(); + + CustomMap<?> d2(); + + CustomMap d3(); + + OtherCustomMap<Date> e(); + + OtherCustomMap<?> e2(); + + OtherCustomMap e3(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java new file mode 100644 index 00000000..ca335500 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/GenericTypeResolverTests.java @@ -0,0 +1,316 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.springframework.core.GenericTypeResolver.*; +import static org.springframework.util.ReflectionUtils.*; + +/** + * @author Juergen Hoeller + * @author Sam Brannen + */ +public class GenericTypeResolverTests { + + @Test + public void simpleInterfaceType() { + assertEquals(String.class, resolveTypeArgument(MySimpleInterfaceType.class, MyInterfaceType.class)); + } + + @Test + public void simpleCollectionInterfaceType() { + assertEquals(Collection.class, resolveTypeArgument(MyCollectionInterfaceType.class, MyInterfaceType.class)); + } + + @Test + public void simpleSuperclassType() { + assertEquals(String.class, resolveTypeArgument(MySimpleSuperclassType.class, MySuperclassType.class)); + } + + @Test + public void simpleCollectionSuperclassType() { + assertEquals(Collection.class, resolveTypeArgument(MyCollectionSuperclassType.class, MySuperclassType.class)); + } + + @Test + public void nullIfNotResolvable() { + GenericClass<String> obj = new GenericClass<String>(); + assertNull(resolveTypeArgument(obj.getClass(), GenericClass.class)); + } + + @Test + public void methodReturnTypes() { + assertEquals(Integer.class, + resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "integer"), MyInterfaceType.class)); + assertEquals(String.class, + resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "string"), MyInterfaceType.class)); + assertEquals(null, resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "raw"), MyInterfaceType.class)); + assertEquals(null, + resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "object"), MyInterfaceType.class)); + } + + @Test + public void testResolveType() { + Method intMessageMethod = findMethod(MyTypeWithMethods.class, "readIntegerInputMessage", MyInterfaceType.class); + MethodParameter intMessageMethodParam = new MethodParameter(intMessageMethod, 0); + assertEquals(MyInterfaceType.class, + resolveType(intMessageMethodParam.getGenericParameterType(), new HashMap<TypeVariable, Type>())); + + Method intArrMessageMethod = findMethod(MyTypeWithMethods.class, "readIntegerArrayInputMessage", + MyInterfaceType[].class); + MethodParameter intArrMessageMethodParam = new MethodParameter(intArrMessageMethod, 0); + assertEquals(MyInterfaceType[].class, + resolveType(intArrMessageMethodParam.getGenericParameterType(), new HashMap<TypeVariable, Type>())); + + Method genericArrMessageMethod = findMethod(MySimpleTypeWithMethods.class, "readGenericArrayInputMessage", + Object[].class); + MethodParameter genericArrMessageMethodParam = new MethodParameter(genericArrMessageMethod, 0); + Map<TypeVariable, Type> varMap = getTypeVariableMap(MySimpleTypeWithMethods.class); + assertEquals(Integer[].class, resolveType(genericArrMessageMethodParam.getGenericParameterType(), varMap)); + } + + @Test + public void testBoundParameterizedType() { + assertEquals(B.class, resolveTypeArgument(TestImpl.class, ITest.class)); + } + + @Test + public void testGetTypeVariableMap() throws Exception { + Map<TypeVariable, Type> map; + + map = GenericTypeResolver.getTypeVariableMap(MySimpleInterfaceType.class); + assertThat(map.toString(), equalTo("{T=class java.lang.String}")); + + map = GenericTypeResolver.getTypeVariableMap(MyCollectionInterfaceType.class); + assertThat(map.toString(), equalTo("{T=java.util.Collection<java.lang.String>}")); + + map = GenericTypeResolver.getTypeVariableMap(MyCollectionSuperclassType.class); + assertThat(map.toString(), equalTo("{T=java.util.Collection<java.lang.String>}")); + + map = GenericTypeResolver.getTypeVariableMap(MySimpleTypeWithMethods.class); + assertThat(map.toString(), equalTo("{T=class java.lang.Integer}")); + + map = GenericTypeResolver.getTypeVariableMap(TopLevelClass.class); + assertThat(map.toString(), equalTo("{}")); + + map = GenericTypeResolver.getTypeVariableMap(TypedTopLevelClass.class); + assertThat(map.toString(), equalTo("{T=class java.lang.Integer}")); + + map = GenericTypeResolver.getTypeVariableMap(TypedTopLevelClass.TypedNested.class); + assertThat(map.size(), equalTo(2)); + Type t = null; + Type x = null; + for (Map.Entry<TypeVariable, Type> entry : map.entrySet()) { + if(entry.getKey().toString().equals("T")) { + t = entry.getValue(); + } + else { + x = entry.getValue(); + } + } + assertThat(t, equalTo((Type) Integer.class)); + assertThat(x, equalTo((Type) Long.class)); + } + + @Test + public void getGenericsCannotBeResolved() throws Exception { + // SPR-11030 + Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(List.class, Iterable.class); + // Note: to be changed to return null in Spring 4.0 + assertThat(resolved, equalTo(new Class[] {Object.class})); + } + + @Test + public void getRawMapTypeCannotBeResolved() throws Exception { + // SPR-11052 + Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(Map.class, Map.class); + assertNull(resolved); + } + + @Test + public void getGenericsOnArrayFromParamCannotBeResolved() throws Exception { + // SPR-11044 + MethodParameter methodParameter = MethodParameter.forMethodOrConstructor( + WithArrayBase.class.getDeclaredMethod("array", Object[].class), 0); + Class<?> resolved = GenericTypeResolver.resolveParameterType(methodParameter, WithArray.class); + assertThat(resolved, equalTo((Class) Object[].class)); + } + + @Test + public void getGenericsOnArrayFromReturnCannotBeResolved() throws Exception { + // SPR-11044 + Class<?> resolved = GenericTypeResolver.resolveReturnType( + WithArrayBase.class.getDeclaredMethod("array", Object[].class), + WithArray.class); + assertThat(resolved, equalTo((Class) Object[].class)); + } + + public interface MyInterfaceType<T> { + } + + public class MySimpleInterfaceType implements MyInterfaceType<String> { + } + + public class MyCollectionInterfaceType implements MyInterfaceType<Collection<String>> { + } + + public abstract class MySuperclassType<T> { + } + + public class MySimpleSuperclassType extends MySuperclassType<String> { + } + + public class MyCollectionSuperclassType extends MySuperclassType<Collection<String>> { + } + + public static class MyTypeWithMethods<T> { + + public MyInterfaceType<Integer> integer() { + return null; + } + + public MySimpleInterfaceType string() { + return null; + } + + public Object object() { + return null; + } + + @SuppressWarnings("rawtypes") + public MyInterfaceType raw() { + return null; + } + + public String notParameterized() { + return null; + } + + public String notParameterizedWithArguments(Integer x, Boolean b) { + return null; + } + + /** + * Simulates a factory method that wraps the supplied object in a proxy of the + * same type. + */ + public static <T> T createProxy(T object) { + return null; + } + + /** + * Similar to {@link #createProxy(Object)} but adds an additional argument before + * the argument of type {@code T}. Note that they may potentially be of the same + * time when invoked! + */ + public static <T> T createNamedProxy(String name, T object) { + return null; + } + + /** + * Simulates factory methods found in libraries such as Mockito and EasyMock. + */ + public static <MOCK> MOCK createMock(Class<MOCK> toMock) { + return null; + } + + /** + * Similar to {@link #createMock(Class)} but adds an additional method argument + * before the parameterized argument. + */ + public static <T> T createNamedMock(String name, Class<T> toMock) { + return null; + } + + /** + * Similar to {@link #createNamedMock(String, Class)} but adds an additional + * parameterized type. + */ + public static <V extends Object, T> T createVMock(V name, Class<T> toMock) { + return null; + } + + /** + * Extract some value of the type supported by the interface (i.e., by a concrete, + * non-generic implementation of the interface). + */ + public static <T> T extractValueFrom(MyInterfaceType<T> myInterfaceType) { + return null; + } + + /** + * Extract some magic value from the supplied map. + */ + public static <K, V> V extractMagicValue(Map<K, V> map) { + return null; + } + + public void readIntegerInputMessage(MyInterfaceType<Integer> message) { + } + + public void readIntegerArrayInputMessage(MyInterfaceType<Integer>[] message) { + } + + public void readGenericArrayInputMessage(T[] message) { + } + } + + public static class MySimpleTypeWithMethods extends MyTypeWithMethods<Integer> { + } + + static class GenericClass<T> { + } + + class A{} + + class B<T>{} + + class ITest<T>{} + + class TestImpl<I extends A, T extends B<I>> extends ITest<T>{ + } + + static class TopLevelClass<T> { + class Nested<X> { + } + } + + static class TypedTopLevelClass extends TopLevelClass<Integer> { + class TypedNested extends Nested<Long> { + } + } + + static abstract class WithArrayBase<T> { + + public abstract T[] array(T... args); + } + + static abstract class WithArray<T> extends WithArrayBase<T> { + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/Jdk14ControlFlowTests.java b/spring-core/src/test/java/org/springframework/core/Jdk14ControlFlowTests.java new file mode 100644 index 00000000..66f1e4f7 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/Jdk14ControlFlowTests.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +/** + * Tests with ControlFlowFactory return. + * + * @author Rod Johnson + */ +public class Jdk14ControlFlowTests extends AbstractControlFlowTests { + + /** + * Necessary only because Eclipse won't run test suite unless it declares + * some methods as well as inherited methods + */ + public void testThisClassPlease() { + } + + @Override + protected ControlFlow createControlFlow() { + return ControlFlowFactory.createControlFlow(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java b/spring-core/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java new file mode 100644 index 00000000..bc659f61 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/LocalVariableTableParameterNameDiscovererTests.java @@ -0,0 +1,314 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core; + +import java.awt.Component; +import java.io.PrintStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Date; + +import junit.framework.TestCase; + +import org.junit.Ignore; +import org.springframework.tests.sample.objects.TestObject; + +/** + * @author Adrian Colyer + */ +public class LocalVariableTableParameterNameDiscovererTests extends TestCase { + + private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer(); + + public void testMethodParameterNameDiscoveryNoArgs() throws NoSuchMethodException { + Method getName = TestObject.class.getMethod("getName", new Class[0]); + String[] names = discoverer.getParameterNames(getName); + assertNotNull("should find method info", names); + assertEquals("no argument names", 0, names.length); + } + + public void testMethodParameterNameDiscoveryWithArgs() throws NoSuchMethodException { + Method setName = TestObject.class.getMethod("setName", new Class[] { String.class }); + String[] names = discoverer.getParameterNames(setName); + assertNotNull("should find method info", names); + assertEquals("one argument", 1, names.length); + assertEquals("name", names[0]); + } + + public void testConsParameterNameDiscoveryNoArgs() throws NoSuchMethodException { + Constructor<TestObject> noArgsCons = TestObject.class.getConstructor(new Class[0]); + String[] names = discoverer.getParameterNames(noArgsCons); + assertNotNull("should find cons info", names); + assertEquals("no argument names", 0, names.length); + } + + public void testConsParameterNameDiscoveryArgs() throws NoSuchMethodException { + Constructor<TestObject> twoArgCons = TestObject.class.getConstructor(new Class[] { String.class, int.class }); + String[] names = discoverer.getParameterNames(twoArgCons); + assertNotNull("should find cons info", names); + assertEquals("one argument", 2, names.length); + assertEquals("name", names[0]); + assertEquals("age", names[1]); + } + + public void testStaticMethodParameterNameDiscoveryNoArgs() throws NoSuchMethodException { + Method m = getClass().getMethod("staticMethodNoLocalVars", new Class[0]); + String[] names = discoverer.getParameterNames(m); + assertNotNull("should find method info", names); + assertEquals("no argument names", 0, names.length); + } + + public void testOverloadedStaticMethod() throws Exception { + Class<? extends LocalVariableTableParameterNameDiscovererTests> clazz = this.getClass(); + + Method m1 = clazz.getMethod("staticMethod", new Class[] { Long.TYPE, Long.TYPE }); + String[] names = discoverer.getParameterNames(m1); + assertNotNull("should find method info", names); + assertEquals("two arguments", 2, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + + Method m2 = clazz.getMethod("staticMethod", new Class[] { Long.TYPE, Long.TYPE, Long.TYPE }); + names = discoverer.getParameterNames(m2); + assertNotNull("should find method info", names); + assertEquals("three arguments", 3, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + assertEquals("z", names[2]); + } + + public void testOverloadedStaticMethodInInnerClass() throws Exception { + Class<InnerClass> clazz = InnerClass.class; + + Method m1 = clazz.getMethod("staticMethod", new Class[] { Long.TYPE }); + String[] names = discoverer.getParameterNames(m1); + assertNotNull("should find method info", names); + assertEquals("one argument", 1, names.length); + assertEquals("x", names[0]); + + Method m2 = clazz.getMethod("staticMethod", new Class[] { Long.TYPE, Long.TYPE }); + names = discoverer.getParameterNames(m2); + assertNotNull("should find method info", names); + assertEquals("two arguments", 2, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + } + + public void testOverloadedMethod() throws Exception { + Class<? extends LocalVariableTableParameterNameDiscovererTests> clazz = this.getClass(); + + Method m1 = clazz.getMethod("instanceMethod", new Class[] { Double.TYPE, Double.TYPE }); + String[] names = discoverer.getParameterNames(m1); + assertNotNull("should find method info", names); + assertEquals("two arguments", 2, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + + Method m2 = clazz.getMethod("instanceMethod", new Class[] { Double.TYPE, Double.TYPE, Double.TYPE }); + names = discoverer.getParameterNames(m2); + assertNotNull("should find method info", names); + assertEquals("three arguments", 3, names.length); + assertEquals("x", names[0]); + assertEquals("y", names[1]); + assertEquals("z", names[2]); + } + + public void testOverloadedMethodInInnerClass() throws Exception { + Class<InnerClass> clazz = InnerClass.class; + + Method m1 = clazz.getMethod("instanceMethod", new Class[] { String.class }); + String[] names = discoverer.getParameterNames(m1); + assertNotNull("should find method info", names); + assertEquals("one argument", 1, names.length); + assertEquals("aa", names[0]); + + Method m2 = clazz.getMethod("instanceMethod", new Class[] { String.class, String.class }); + names = discoverer.getParameterNames(m2); + assertNotNull("should find method info", names); + assertEquals("two arguments", 2, names.length); + assertEquals("aa", names[0]); + assertEquals("bb", names[1]); + } + + public void testGenerifiedClass() throws Exception { + Class<?> clazz = (Class<?>)GenerifiedClass.class; + + Constructor<?> ctor = clazz.getDeclaredConstructor(Object.class); + String[] names = discoverer.getParameterNames(ctor); + assertEquals(1, names.length); + assertEquals("key", names[0]); + + ctor = clazz.getDeclaredConstructor(Object.class, Object.class); + names = discoverer.getParameterNames(ctor); + assertEquals(2, names.length); + assertEquals("key", names[0]); + assertEquals("value", names[1]); + + Method m = clazz.getMethod("generifiedStaticMethod", Object.class); + names = discoverer.getParameterNames(m); + assertEquals(1, names.length); + assertEquals("param", names[0]); + + m = clazz.getMethod("generifiedMethod", Object.class, long.class, Object.class, Object.class); + names = discoverer.getParameterNames(m); + assertEquals(4, names.length); + assertEquals("param", names[0]); + assertEquals("x", names[1]); + assertEquals("key", names[2]); + assertEquals("value", names[3]); + + m = clazz.getMethod("voidStaticMethod", Object.class, long.class, int.class); + names = discoverer.getParameterNames(m); + assertEquals(3, names.length); + assertEquals("obj", names[0]); + assertEquals("x", names[1]); + assertEquals("i", names[2]); + + m = clazz.getMethod("nonVoidStaticMethod", Object.class, long.class, int.class); + names = discoverer.getParameterNames(m); + assertEquals(3, names.length); + assertEquals("obj", names[0]); + assertEquals("x", names[1]); + assertEquals("i", names[2]); + + m = clazz.getMethod("getDate"); + names = discoverer.getParameterNames(m); + assertEquals(0, names.length); + + //System.in.read(); + } + + /** + * Ignored because Ubuntu packages OpenJDK with debug symbols enabled. + * See SPR-8078. + */ + @Ignore + public void ignore_testClassesWithoutDebugSymbols() throws Exception { + // JDK classes don't have debug information (usually) + Class<Component> clazz = Component.class; + String methodName = "list"; + + Method m = clazz.getMethod(methodName); + String[] names = discoverer.getParameterNames(m); + assertNull(names); + + m = clazz.getMethod(methodName, PrintStream.class); + names = discoverer.getParameterNames(m); + assertNull(names); + + m = clazz.getMethod(methodName, PrintStream.class, int.class); + names = discoverer.getParameterNames(m); + assertNull(names); + + //System.in.read(); + } + + public static void staticMethodNoLocalVars() { + } + + public static long staticMethod(long x, long y) { + long u = x * y; + return u; + } + + public static long staticMethod(long x, long y, long z) { + long u = x * y * z; + return u; + } + + public double instanceMethod(double x, double y) { + double u = x * y; + return u; + } + + public double instanceMethod(double x, double y, double z) { + double u = x * y * z; + return u; + } + + public static class InnerClass { + + public int waz = 0; + + public InnerClass() { + } + + public InnerClass(String firstArg, long secondArg, Object thirdArg) { + long foo = 0; + short bar = 10; + this.waz = (int) (foo + bar); + } + + public String instanceMethod(String aa) { + return aa; + } + + public String instanceMethod(String aa, String bb) { + return aa + bb; + } + + public static long staticMethod(long x) { + long u = x; + return u; + } + + public static long staticMethod(long x, long y) { + long u = x * y; + return u; + } + } + + public static class GenerifiedClass<K, V> { + private static long date; + + static { + // some custom static bloc or <clinit> + date = new Date().getTime(); + } + + public GenerifiedClass() { + this(null, null); + } + + public GenerifiedClass(K key) { + this(key, null); + } + + public GenerifiedClass(K key, V value) { + } + + public static <P> long generifiedStaticMethod(P param) { + return date; + } + + public <P> void generifiedMethod(P param, long x, K key, V value) { + // nothing + } + + public static void voidStaticMethod(Object obj, long x, int i) { + // nothing + } + + public static long nonVoidStaticMethod(Object obj, long x, int i) { + return date; + } + + public static long getDate() { + return date; + } + } +} diff --git a/spring-core/src/test/java/org/springframework/core/MethodParameterTests.java b/spring-core/src/test/java/org/springframework/core/MethodParameterTests.java new file mode 100644 index 00000000..c3c3e7d1 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/MethodParameterTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +import java.lang.reflect.Method; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Arjen Poutsma + */ +public class MethodParameterTests { + + private MethodParameter stringParameter; + + private MethodParameter longParameter; + + private MethodParameter intReturnType; + + + @Before + public void setUp() throws NoSuchMethodException { + Method method = getClass().getMethod("method", String.class, Long.TYPE); + stringParameter = new MethodParameter(method, 0); + longParameter = new MethodParameter(method, 1); + intReturnType = new MethodParameter(method, -1); + } + + @Test + public void testEquals() throws NoSuchMethodException { + assertEquals(stringParameter, stringParameter); + assertEquals(longParameter, longParameter); + assertEquals(intReturnType, intReturnType); + + assertFalse(stringParameter.equals(longParameter)); + assertFalse(stringParameter.equals(intReturnType)); + assertFalse(longParameter.equals(stringParameter)); + assertFalse(longParameter.equals(intReturnType)); + assertFalse(intReturnType.equals(stringParameter)); + assertFalse(intReturnType.equals(longParameter)); + + Method method = getClass().getMethod("method", String.class, Long.TYPE); + MethodParameter methodParameter = new MethodParameter(method, 0); + assertEquals(stringParameter, methodParameter); + assertEquals(methodParameter, stringParameter); + assertFalse(longParameter.equals(methodParameter)); + assertFalse(methodParameter.equals(longParameter)); + } + + @Test + public void testHashCode() throws NoSuchMethodException { + assertEquals(stringParameter.hashCode(), stringParameter.hashCode()); + assertEquals(longParameter.hashCode(), longParameter.hashCode()); + assertEquals(intReturnType.hashCode(), intReturnType.hashCode()); + + Method method = getClass().getMethod("method", String.class, Long.TYPE); + MethodParameter methodParameter = new MethodParameter(method, 0); + assertEquals(stringParameter.hashCode(), methodParameter.hashCode()); + assertTrue(longParameter.hashCode() != methodParameter.hashCode()); + } + + + public int method(String p1, long p2) { + return 42; + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/NestedExceptionTests.java b/spring-core/src/test/java/org/springframework/core/NestedExceptionTests.java new file mode 100644 index 00000000..dff42909 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/NestedExceptionTests.java @@ -0,0 +1,106 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +import java.io.ByteArrayOutputStream; +import java.io.PrintWriter; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + */ +public class NestedExceptionTests extends TestCase { + + @SuppressWarnings("serial") + public void testNestedRuntimeExceptionWithNoRootCause() { + String mesg = "mesg of mine"; + // Making a class abstract doesn't _really_ prevent instantiation :-) + NestedRuntimeException nex = new NestedRuntimeException(mesg) {}; + assertNull(nex.getCause()); + assertEquals(nex.getMessage(), mesg); + + // Check printStackTrace + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(baos); + nex.printStackTrace(pw); + pw.flush(); + String stackTrace = new String(baos.toByteArray()); + assertFalse(stackTrace.indexOf(mesg) == -1); + } + + @SuppressWarnings("serial") + public void testNestedRuntimeExceptionWithRootCause() { + String myMessage = "mesg for this exception"; + String rootCauseMesg = "this is the obscure message of the root cause"; + Exception rootCause = new Exception(rootCauseMesg); + // Making a class abstract doesn't _really_ prevent instantiation :-) + NestedRuntimeException nex = new NestedRuntimeException(myMessage, rootCause) {}; + assertEquals(nex.getCause(), rootCause); + assertTrue(nex.getMessage().indexOf(myMessage) != -1); + assertTrue(nex.getMessage().indexOf(rootCauseMesg) != -1); + + // check PrintStackTrace + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(baos); + nex.printStackTrace(pw); + pw.flush(); + String stackTrace = new String(baos.toByteArray()); + assertFalse(stackTrace.indexOf(rootCause.getClass().getName()) == -1); + assertFalse(stackTrace.indexOf(rootCauseMesg) == -1); + } + + @SuppressWarnings("serial") + public void testNestedCheckedExceptionWithNoRootCause() { + String mesg = "mesg of mine"; + // Making a class abstract doesn't _really_ prevent instantiation :-) + NestedCheckedException nex = new NestedCheckedException(mesg) {}; + assertNull(nex.getCause()); + assertEquals(nex.getMessage(), mesg); + + // Check printStackTrace + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(baos); + nex.printStackTrace(pw); + pw.flush(); + String stackTrace = new String(baos.toByteArray()); + assertFalse(stackTrace.indexOf(mesg) == -1); + } + + @SuppressWarnings("serial") + public void testNestedCheckedExceptionWithRootCause() { + String myMessage = "mesg for this exception"; + String rootCauseMesg = "this is the obscure message of the root cause"; + Exception rootCause = new Exception(rootCauseMesg); + // Making a class abstract doesn't _really_ prevent instantiation :-) + NestedCheckedException nex = new NestedCheckedException(myMessage, rootCause) {}; + assertEquals(nex.getCause(), rootCause); + assertTrue(nex.getMessage().indexOf(myMessage) != -1); + assertTrue(nex.getMessage().indexOf(rootCauseMesg) != -1); + + // check PrintStackTrace + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintWriter pw = new PrintWriter(baos); + nex.printStackTrace(pw); + pw.flush(); + String stackTrace = new String(baos.toByteArray()); + assertFalse(stackTrace.indexOf(rootCause.getClass().getName()) == -1); + assertFalse(stackTrace.indexOf(rootCauseMesg) == -1); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/OrderComparatorTests.java b/spring-core/src/test/java/org/springframework/core/OrderComparatorTests.java new file mode 100644 index 00000000..d93649a0 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/OrderComparatorTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core; + +import junit.framework.TestCase; + +import java.util.Comparator; + +/** + * Unit tests for the {@link OrderComparator} class. + * + * @author Rick Evans + */ +public final class OrderComparatorTests extends TestCase { + + private Comparator comparator; + + + @Override + protected void setUp() throws Exception { + this.comparator = new OrderComparator(); + } + + + public void testCompareOrderedInstancesBefore() throws Exception { + assertEquals(-1, this.comparator.compare( + new StubOrdered(100), new StubOrdered(2000))); + } + + public void testCompareOrderedInstancesSame() throws Exception { + assertEquals(0, this.comparator.compare( + new StubOrdered(100), new StubOrdered(100))); + } + + public void testCompareOrderedInstancesAfter() throws Exception { + assertEquals(1, this.comparator.compare( + new StubOrdered(982300), new StubOrdered(100))); + } + + public void testCompareTwoNonOrderedInstancesEndsUpAsSame() throws Exception { + assertEquals(0, this.comparator.compare(new Object(), new Object())); + } + + + private static final class StubOrdered implements Ordered { + + private final int order; + + + public StubOrdered(int order) { + this.order = order; + } + + @Override + public int getOrder() { + return this.order; + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTests.java b/spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTests.java new file mode 100644 index 00000000..56060b24 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Test fixture for {@link ParameterizedTypeReference}. + * + * @author Arjen Poutsma + * @author Rossen Stoyanchev + */ +public class ParameterizedTypeReferenceTests { + + @Test + public void map() throws NoSuchMethodException { + Type mapType = getClass().getMethod("mapMethod").getGenericReturnType(); + ParameterizedTypeReference<Map<Object,String>> mapTypeReference = new ParameterizedTypeReference<Map<Object,String>>() {}; + assertEquals(mapType, mapTypeReference.getType()); + } + + @Test + public void list() throws NoSuchMethodException { + Type mapType = getClass().getMethod("listMethod").getGenericReturnType(); + ParameterizedTypeReference<List<String>> mapTypeReference = new ParameterizedTypeReference<List<String>>() {}; + assertEquals(mapType, mapTypeReference.getType()); + } + + @Test + public void string() { + ParameterizedTypeReference<String> typeReference = new ParameterizedTypeReference<String>() {}; + assertEquals(String.class, typeReference.getType()); + } + + public static Map<Object, String> mapMethod() { + return null; + } + + public static List<String> listMethod() { + return null; + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java b/spring-core/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java new file mode 100644 index 00000000..19c16d15 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/PrioritizedParameterNameDiscovererTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Arrays; + +import junit.framework.TestCase; + +import org.springframework.tests.sample.objects.TestObject; + +public class PrioritizedParameterNameDiscovererTests extends TestCase { + + private static final String[] FOO_BAR = new String[] { "foo", "bar" }; + + private static final String[] SOMETHING_ELSE = new String[] { "something", "else" }; + + ParameterNameDiscoverer returnsFooBar = new ParameterNameDiscoverer() { + @Override + public String[] getParameterNames(Method m) { + return FOO_BAR; + } + @Override + public String[] getParameterNames(Constructor ctor) { + return FOO_BAR; + } + }; + + ParameterNameDiscoverer returnsSomethingElse = new ParameterNameDiscoverer() { + @Override + public String[] getParameterNames(Method m) { + return SOMETHING_ELSE; + } + @Override + public String[] getParameterNames(Constructor ctor) { + return SOMETHING_ELSE; + } + }; + + private final Method anyMethod; + private final Class anyClass = Object.class; + + public PrioritizedParameterNameDiscovererTests() throws SecurityException, NoSuchMethodException { + anyMethod = TestObject.class.getMethod("getAge", (Class[]) null); + } + + public void testNoParametersDiscoverers() { + ParameterNameDiscoverer pnd = new PrioritizedParameterNameDiscoverer(); + assertNull(pnd.getParameterNames(anyMethod)); + assertNull(pnd.getParameterNames((Constructor) null)); + } + + public void testOrderedParameterDiscoverers1() { + PrioritizedParameterNameDiscoverer pnd = new PrioritizedParameterNameDiscoverer(); + pnd.addDiscoverer(returnsFooBar); + assertTrue(Arrays.equals(FOO_BAR, pnd.getParameterNames(anyMethod))); + assertTrue(Arrays.equals(FOO_BAR, pnd.getParameterNames((Constructor) null))); + pnd.addDiscoverer(returnsSomethingElse); + assertTrue(Arrays.equals(FOO_BAR, pnd.getParameterNames(anyMethod))); + assertTrue(Arrays.equals(FOO_BAR, pnd.getParameterNames((Constructor) null))); + } + + public void testOrderedParameterDiscoverers2() { + PrioritizedParameterNameDiscoverer pnd = new PrioritizedParameterNameDiscoverer(); + pnd.addDiscoverer(returnsSomethingElse); + assertTrue(Arrays.equals(SOMETHING_ELSE, pnd.getParameterNames(anyMethod))); + assertTrue(Arrays.equals(SOMETHING_ELSE, pnd.getParameterNames((Constructor) null))); + pnd.addDiscoverer(returnsFooBar); + assertTrue(Arrays.equals(SOMETHING_ELSE, pnd.getParameterNames(anyMethod))); + assertTrue(Arrays.equals(SOMETHING_ELSE, pnd.getParameterNames((Constructor) null))); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java new file mode 100644 index 00000000..487b3399 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.annotation; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; + +/** + * Unit tests for {@link AnnotationAttributes}. + * + * @author Chris Beams + * @since 3.1.1 + */ +public class AnnotationAttributesTests { + + enum Color { RED, WHITE, BLUE } + + @Test + public void testTypeSafeAttributeAccess() { + AnnotationAttributes a = new AnnotationAttributes(); + a.put("name", "dave"); + a.put("names", new String[] { "dave", "frank", "hal" }); + a.put("bool1", true); + a.put("bool2", false); + a.put("color", Color.RED); + a.put("clazz", Integer.class); + a.put("classes", new Class<?>[] { Number.class, Short.class, Integer.class }); + a.put("number", 42); + a.put("numbers", new int[] { 42, 43 }); + AnnotationAttributes anno = new AnnotationAttributes(); + anno.put("value", 10); + anno.put("name", "algernon"); + a.put("anno", anno); + a.put("annoArray", new AnnotationAttributes[] { anno }); + + assertThat(a.getString("name"), equalTo("dave")); + assertThat(a.getStringArray("names"), equalTo(new String[] { "dave", "frank", "hal" })); + assertThat(a.getBoolean("bool1"), equalTo(true)); + assertThat(a.getBoolean("bool2"), equalTo(false)); + assertThat(a.<Color>getEnum("color"), equalTo(Color.RED)); + assertTrue(a.getClass("clazz").equals(Integer.class)); + assertThat(a.getClassArray("classes"), equalTo(new Class[] { Number.class, Short.class, Integer.class })); + assertThat(a.<Integer>getNumber("number"), equalTo(42)); + assertThat(a.getAnnotation("anno").<Integer>getNumber("value"), equalTo(10)); + assertThat(a.getAnnotationArray("annoArray")[0].getString("name"), equalTo("algernon")); + } + + @Test + public void getEnum_emptyAttributeName() { + AnnotationAttributes a = new AnnotationAttributes(); + a.put("color", "RED"); + try { + a.getEnum(""); + fail(); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), equalTo("attributeName must not be null or empty")); + } + try { + a.getEnum(null); + fail(); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), equalTo("attributeName must not be null or empty")); + } + } + + @Test + public void getEnum_notFound() { + AnnotationAttributes a = new AnnotationAttributes(); + a.put("color", "RED"); + try { + a.getEnum("colour"); + fail(); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), equalTo("Attribute 'colour' not found")); + } + } + + @Test + public void getEnum_typeMismatch() { + AnnotationAttributes a = new AnnotationAttributes(); + a.put("color", "RED"); + try { + a.getEnum("color"); + fail(); + } catch (IllegalArgumentException ex) { + String expected = + "Attribute 'color' is of type [String], but [Enum] was expected"; + assertThat(ex.getMessage().substring(0, expected.length()), equalTo(expected)); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAwareOrderComparatorTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAwareOrderComparatorTests.java new file mode 100644 index 00000000..df656655 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAwareOrderComparatorTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.annotation; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + * @author Oliver Gierke + */ +public class AnnotationAwareOrderComparatorTests { + + @Test + public void instanceVariableIsAnAnnotationAwareOrderComparator() { + assertThat(AnnotationAwareOrderComparator.INSTANCE, is(instanceOf(AnnotationAwareOrderComparator.class))); + } + + @Test + public void sortInstances() { + List<Object> list = new ArrayList<>(); + list.add(new B()); + list.add(new A()); + AnnotationAwareOrderComparator.sort(list); + assertTrue(list.get(0) instanceof A); + assertTrue(list.get(1) instanceof B); + } + + @Test + public void sortInstancesWithSubclass() { + List<Object> list = new ArrayList<>(); + list.add(new B()); + list.add(new C()); + AnnotationAwareOrderComparator.sort(list); + assertTrue(list.get(0) instanceof C); + assertTrue(list.get(1) instanceof B); + } + + @Test + public void sortClasses() { + List<Object> list = new ArrayList<>(); + list.add(B.class); + list.add(A.class); + AnnotationAwareOrderComparator.sort(list); + assertEquals(A.class, list.get(0)); + assertEquals(B.class, list.get(1)); + } + + @Test + public void sortClassesWithSubclass() { + List<Object> list = new ArrayList<>(); + list.add(B.class); + list.add(C.class); + AnnotationAwareOrderComparator.sort(list); + assertEquals(C.class, list.get(0)); + assertEquals(B.class, list.get(1)); + } + + + @Order(1) + private static class A { + } + + @Order(2) + private static class B { + } + + private static class C extends A { + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java new file mode 100644 index 00000000..d4b6d5ee --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java @@ -0,0 +1,441 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.annotation; + +import java.lang.annotation.Annotation; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; + +import static org.junit.Assert.*; +import static org.springframework.core.annotation.AnnotationUtils.*; + +/** + * Unit tests for {@link AnnotationUtils}. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Sam Brannen + * @author Chris Beams + */ +public class AnnotationUtilsTests { + + @Test + public void findMethodAnnotationOnLeaf() throws Exception { + Method m = Leaf.class.getMethod("annotatedOnLeaf", (Class[]) null); + assertNotNull(m.getAnnotation(Order.class)); + assertNotNull(getAnnotation(m, Order.class)); + assertNotNull(findAnnotation(m, Order.class)); + } + + @Test + public void findMethodAnnotationOnRoot() throws Exception { + Method m = Leaf.class.getMethod("annotatedOnRoot", (Class[]) null); + assertNotNull(m.getAnnotation(Order.class)); + assertNotNull(getAnnotation(m, Order.class)); + assertNotNull(findAnnotation(m, Order.class)); + } + + @Test + public void findMethodAnnotationOnRootButOverridden() throws Exception { + Method m = Leaf.class.getMethod("overrideWithoutNewAnnotation", (Class[]) null); + assertNull(m.getAnnotation(Order.class)); + assertNull(getAnnotation(m, Order.class)); + assertNotNull(findAnnotation(m, Order.class)); + } + + @Test + public void findMethodAnnotationNotAnnotated() throws Exception { + Method m = Leaf.class.getMethod("notAnnotated", (Class[]) null); + assertNull(findAnnotation(m, Order.class)); + } + + @Test + public void findMethodAnnotationOnBridgeMethod() throws Exception { + Method m = SimpleFoo.class.getMethod("something", Object.class); + assertTrue(m.isBridge()); + assertNull(m.getAnnotation(Order.class)); + assertNull(getAnnotation(m, Order.class)); + assertNotNull(findAnnotation(m, Order.class)); + // TODO: actually found on OpenJDK 8 b99! assertNull(m.getAnnotation(Transactional.class)); + assertNotNull(getAnnotation(m, Transactional.class)); + assertNotNull(findAnnotation(m, Transactional.class)); + } + + // TODO consider whether we want this to handle annotations on interfaces + // public void findMethodAnnotationFromInterfaceImplementedByRoot() + // throws Exception { + // Method m = Leaf.class.getMethod("fromInterfaceImplementedByRoot", + // (Class[]) null); + // Order o = findAnnotation(Order.class, m, Leaf.class); + // assertNotNull(o); + // } + + @Test + public void testFindAnnotationDeclaringClass() throws Exception { + // no class-level annotation + assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedInterface.class)); + assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedClass.class)); + + // inherited class-level annotation; note: @Transactional is inherited + assertEquals(InheritedAnnotationInterface.class, + findAnnotationDeclaringClass(Transactional.class, InheritedAnnotationInterface.class)); + assertNull(findAnnotationDeclaringClass(Transactional.class, SubInheritedAnnotationInterface.class)); + assertEquals(InheritedAnnotationClass.class, + findAnnotationDeclaringClass(Transactional.class, InheritedAnnotationClass.class)); + assertEquals(InheritedAnnotationClass.class, + findAnnotationDeclaringClass(Transactional.class, SubInheritedAnnotationClass.class)); + + // non-inherited class-level annotation; note: @Order is not inherited, + // but findAnnotationDeclaringClass() should still find it on classes. + assertEquals(NonInheritedAnnotationInterface.class, + findAnnotationDeclaringClass(Order.class, NonInheritedAnnotationInterface.class)); + assertNull(findAnnotationDeclaringClass(Order.class, SubNonInheritedAnnotationInterface.class)); + assertEquals(NonInheritedAnnotationClass.class, + findAnnotationDeclaringClass(Order.class, NonInheritedAnnotationClass.class)); + assertEquals(NonInheritedAnnotationClass.class, + findAnnotationDeclaringClass(Order.class, SubNonInheritedAnnotationClass.class)); + } + + @Test + public void findAnnotationDeclaringClassForTypesWithSingleCandidateType() { + // no class-level annotation + List<Class<? extends Annotation>> transactionalCandidateList = Arrays.<Class<? extends Annotation>> asList(Transactional.class); + assertNull(findAnnotationDeclaringClassForTypes(transactionalCandidateList, NonAnnotatedInterface.class)); + assertNull(findAnnotationDeclaringClassForTypes(transactionalCandidateList, NonAnnotatedClass.class)); + + // inherited class-level annotation; note: @Transactional is inherited + assertEquals(InheritedAnnotationInterface.class, + findAnnotationDeclaringClassForTypes(transactionalCandidateList, InheritedAnnotationInterface.class)); + assertNull(findAnnotationDeclaringClassForTypes(transactionalCandidateList, SubInheritedAnnotationInterface.class)); + assertEquals(InheritedAnnotationClass.class, + findAnnotationDeclaringClassForTypes(transactionalCandidateList, InheritedAnnotationClass.class)); + assertEquals(InheritedAnnotationClass.class, + findAnnotationDeclaringClassForTypes(transactionalCandidateList, SubInheritedAnnotationClass.class)); + + // non-inherited class-level annotation; note: @Order is not inherited, + // but findAnnotationDeclaringClassForTypes() should still find it on classes. + List<Class<? extends Annotation>> orderCandidateList = Arrays.<Class<? extends Annotation>> asList(Order.class); + assertEquals(NonInheritedAnnotationInterface.class, + findAnnotationDeclaringClassForTypes(orderCandidateList, NonInheritedAnnotationInterface.class)); + assertNull(findAnnotationDeclaringClassForTypes(orderCandidateList, SubNonInheritedAnnotationInterface.class)); + assertEquals(NonInheritedAnnotationClass.class, + findAnnotationDeclaringClassForTypes(orderCandidateList, NonInheritedAnnotationClass.class)); + assertEquals(NonInheritedAnnotationClass.class, + findAnnotationDeclaringClassForTypes(orderCandidateList, SubNonInheritedAnnotationClass.class)); + } + + @Test + public void findAnnotationDeclaringClassForTypesWithMultipleCandidateTypes() { + List<Class<? extends Annotation>> candidates = Arrays.<Class<? extends Annotation>> asList(Transactional.class, Order.class); + + // no class-level annotation + assertNull(findAnnotationDeclaringClassForTypes(candidates, NonAnnotatedInterface.class)); + assertNull(findAnnotationDeclaringClassForTypes(candidates, NonAnnotatedClass.class)); + + // inherited class-level annotation; note: @Transactional is inherited + assertEquals(InheritedAnnotationInterface.class, + findAnnotationDeclaringClassForTypes(candidates, InheritedAnnotationInterface.class)); + assertNull(findAnnotationDeclaringClassForTypes(candidates, SubInheritedAnnotationInterface.class)); + assertEquals(InheritedAnnotationClass.class, + findAnnotationDeclaringClassForTypes(candidates, InheritedAnnotationClass.class)); + assertEquals(InheritedAnnotationClass.class, + findAnnotationDeclaringClassForTypes(candidates, SubInheritedAnnotationClass.class)); + + // non-inherited class-level annotation; note: @Order is not inherited, + // but findAnnotationDeclaringClassForTypes() should still find it on classes. + assertEquals(NonInheritedAnnotationInterface.class, + findAnnotationDeclaringClassForTypes(candidates, NonInheritedAnnotationInterface.class)); + assertNull(findAnnotationDeclaringClassForTypes(candidates, SubNonInheritedAnnotationInterface.class)); + assertEquals(NonInheritedAnnotationClass.class, + findAnnotationDeclaringClassForTypes(candidates, NonInheritedAnnotationClass.class)); + assertEquals(NonInheritedAnnotationClass.class, + findAnnotationDeclaringClassForTypes(candidates, SubNonInheritedAnnotationClass.class)); + + // class hierarchy mixed with @Transactional and @Order declarations + assertEquals(TransactionalClass.class, + findAnnotationDeclaringClassForTypes(candidates, TransactionalClass.class)); + assertEquals(TransactionalAndOrderedClass.class, + findAnnotationDeclaringClassForTypes(candidates, TransactionalAndOrderedClass.class)); + assertEquals(TransactionalAndOrderedClass.class, + findAnnotationDeclaringClassForTypes(candidates, SubTransactionalAndOrderedClass.class)); + } + + @Test + public void testIsAnnotationDeclaredLocally() throws Exception { + // no class-level annotation + assertFalse(isAnnotationDeclaredLocally(Transactional.class, NonAnnotatedInterface.class)); + assertFalse(isAnnotationDeclaredLocally(Transactional.class, NonAnnotatedClass.class)); + + // inherited class-level annotation; note: @Transactional is inherited + assertTrue(isAnnotationDeclaredLocally(Transactional.class, InheritedAnnotationInterface.class)); + assertFalse(isAnnotationDeclaredLocally(Transactional.class, SubInheritedAnnotationInterface.class)); + assertTrue(isAnnotationDeclaredLocally(Transactional.class, InheritedAnnotationClass.class)); + assertFalse(isAnnotationDeclaredLocally(Transactional.class, SubInheritedAnnotationClass.class)); + + // non-inherited class-level annotation; note: @Order is not inherited + assertTrue(isAnnotationDeclaredLocally(Order.class, NonInheritedAnnotationInterface.class)); + assertFalse(isAnnotationDeclaredLocally(Order.class, SubNonInheritedAnnotationInterface.class)); + assertTrue(isAnnotationDeclaredLocally(Order.class, NonInheritedAnnotationClass.class)); + assertFalse(isAnnotationDeclaredLocally(Order.class, SubNonInheritedAnnotationClass.class)); + } + + @Test + public void testIsAnnotationInherited() throws Exception { + // no class-level annotation + assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedInterface.class)); + assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedClass.class)); + + // inherited class-level annotation; note: @Transactional is inherited + assertFalse(isAnnotationInherited(Transactional.class, InheritedAnnotationInterface.class)); + // isAnnotationInherited() does not currently traverse interface + // hierarchies. Thus the following, though perhaps counter intuitive, + // must be false: + assertFalse(isAnnotationInherited(Transactional.class, SubInheritedAnnotationInterface.class)); + assertFalse(isAnnotationInherited(Transactional.class, InheritedAnnotationClass.class)); + assertTrue(isAnnotationInherited(Transactional.class, SubInheritedAnnotationClass.class)); + + // non-inherited class-level annotation; note: @Order is not inherited + assertFalse(isAnnotationInherited(Order.class, NonInheritedAnnotationInterface.class)); + assertFalse(isAnnotationInherited(Order.class, SubNonInheritedAnnotationInterface.class)); + assertFalse(isAnnotationInherited(Order.class, NonInheritedAnnotationClass.class)); + assertFalse(isAnnotationInherited(Order.class, SubNonInheritedAnnotationClass.class)); + } + + @Test + public void getValueFromAnnotation() throws Exception { + Method method = SimpleFoo.class.getMethod("something", Object.class); + Order order = findAnnotation(method, Order.class); + + assertEquals(1, AnnotationUtils.getValue(order, AnnotationUtils.VALUE)); + assertEquals(1, AnnotationUtils.getValue(order)); + } + + @Test + public void getValueFromNonPublicAnnotation() throws Exception { + Method method = SimpleFoo.class.getMethod("something", Object.class); + Order order = findAnnotation(method, Order.class); + + assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(order, AnnotationUtils.VALUE)); + assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(order)); + } + + @Test + public void getDefaultValueFromAnnotation() throws Exception { + Method method = SimpleFoo.class.getMethod("something", Object.class); + Order order = findAnnotation(method, Order.class); + + assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(order, AnnotationUtils.VALUE)); + assertEquals(Ordered.LOWEST_PRECEDENCE, AnnotationUtils.getDefaultValue(order)); + } + + @Test + public void getDefaultValueFromNonPublicAnnotation() throws Exception { + Method method = ImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo"); + Order order = findAnnotation(method, Order.class); + assertNotNull(order); + } + + @Test + public void findAnnotationFromInterfaceOnSuper() throws Exception { + Method method = SubOfImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo"); + Order order = findAnnotation(method, Order.class); + assertNotNull(order); + } + + @Test + public void findAnnotationFromInterfaceWhenSuperDoesNotImplementMethod() throws Exception { + Method method = SubOfAbstractImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo"); + Order order = findAnnotation(method, Order.class); + assertNotNull(order); + } + + + @Component(value = "meta1") + @Retention(RetentionPolicy.RUNTIME) + @interface Meta1 { + } + + @Component(value = "meta2") + @Retention(RetentionPolicy.RUNTIME) + @interface Meta2 { + } + + @Meta1 + @Component(value = "local") + @Meta2 + static class HasLocalAndMetaComponentAnnotation { + } + + public static interface AnnotatedInterface { + + @Order(0) + void fromInterfaceImplementedByRoot(); + } + + public static class Root implements AnnotatedInterface { + + @Order(27) + public void annotatedOnRoot() { + + } + + public void overrideToAnnotate() { + + } + + @Order(27) + public void overrideWithoutNewAnnotation() { + + } + + public void notAnnotated() { + + } + + @Override + public void fromInterfaceImplementedByRoot() { + + } + } + + public static class Leaf extends Root { + + @Order(25) + public void annotatedOnLeaf() { + + } + + @Override + @Order(1) + public void overrideToAnnotate() { + + } + + @Override + public void overrideWithoutNewAnnotation() { + + } + } + + @Retention(RetentionPolicy.RUNTIME) + @Inherited + @interface Transactional { + + } + + public static abstract class Foo<T> { + + @Order(1) + public abstract void something(T arg); + } + + public static class SimpleFoo extends Foo<String> { + + @Override + @Transactional + public void something(final String arg) { + + } + } + + @Transactional + public static interface InheritedAnnotationInterface { + } + + public static interface SubInheritedAnnotationInterface extends InheritedAnnotationInterface { + } + + @Order + public static interface NonInheritedAnnotationInterface { + } + + public static interface SubNonInheritedAnnotationInterface extends NonInheritedAnnotationInterface { + } + + public static class NonAnnotatedClass { + } + + public static interface NonAnnotatedInterface { + } + + @Transactional + public static class InheritedAnnotationClass { + } + + public static class SubInheritedAnnotationClass extends InheritedAnnotationClass { + } + + @Order + public static class NonInheritedAnnotationClass { + } + + public static class SubNonInheritedAnnotationClass extends NonInheritedAnnotationClass { + } + + @Transactional + public static class TransactionalClass { + } + + @Order + public static class TransactionalAndOrderedClass { + } + + public static class SubTransactionalAndOrderedClass extends TransactionalAndOrderedClass { + } + + public static interface InterfaceWithAnnotatedMethod { + + @Order + void foo(); + } + + public static class ImplementsInterfaceWithAnnotatedMethod implements InterfaceWithAnnotatedMethod { + + @Override + public void foo() { + } + } + + public static class SubOfImplementsInterfaceWithAnnotatedMethod extends ImplementsInterfaceWithAnnotatedMethod { + + @Override + public void foo() { + } + } + + public abstract static class AbstractDoesNotImplementInterfaceWithAnnotatedMethod implements + InterfaceWithAnnotatedMethod { + } + + public static class SubOfAbstractImplementsInterfaceWithAnnotatedMethod extends + AbstractDoesNotImplementInterfaceWithAnnotatedMethod { + + @Override + public void foo() { + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java b/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java new file mode 100644 index 00000000..7af9d19f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/convert/TypeDescriptorTests.java @@ -0,0 +1,890 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.convert; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Test; +import org.springframework.core.MethodParameter; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * @author Keith Donald + * @author Andy Clement + * @author Phillip Webb + */ +@SuppressWarnings("rawtypes") +public class TypeDescriptorTests { + + public List<String> listOfString; + + public List<List<String>> listOfListOfString = new ArrayList<List<String>>(); + + public List<List> listOfListOfUnknown = new ArrayList<List>(); + + public int[] intArray; + + public List<String>[] arrayOfListOfString; + + public List<Integer> listField = new ArrayList<Integer>(); + + public Map<String, Integer> mapField = new HashMap<String, Integer>(); + + public Map<String, List<Integer>> nestedMapField = new HashMap<String, List<Integer>>(); + + @Test + public void parameterPrimitive() throws Exception { + TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterPrimitive", int.class), 0)); + assertEquals(int.class, desc.getType()); + assertEquals(Integer.class, desc.getObjectType()); + assertEquals("int", desc.getName()); + assertEquals("int", desc.toString()); + assertTrue(desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isMap()); + } + + public void testParameterPrimitive(int primitive) { + + } + + @Test + public void parameterScalar() throws Exception { + TypeDescriptor desc = new TypeDescriptor(new MethodParameter(getClass().getMethod("testParameterScalar", String.class), 0)); + assertEquals(String.class, desc.getType()); + assertEquals(String.class, desc.getObjectType()); + assertEquals("java.lang.String", desc.getName()); + assertEquals("java.lang.String", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isArray()); + assertFalse(desc.isMap()); + } + + public void testParameterScalar(String value) { + + } + + @Test + public void parameterList() throws Exception { + MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterList", List.class), 0); + TypeDescriptor desc = new TypeDescriptor(methodParameter); + assertEquals(List.class, desc.getType()); + assertEquals(List.class, desc.getObjectType()); + assertEquals("java.util.List", desc.getName()); + assertEquals("java.util.List<java.util.List<java.util.Map<java.lang.Integer, java.lang.Enum>>>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertTrue(desc.isCollection()); + assertFalse(desc.isArray()); + assertEquals(List.class, desc.getElementTypeDescriptor().getType()); + assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getElementTypeDescriptor()); + assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getElementTypeDescriptor().getElementTypeDescriptor()); + assertEquals(TypeDescriptor.nested(methodParameter, 3), desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapKeyTypeDescriptor().getType()); + assertEquals(Enum.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getMapValueTypeDescriptor().getType()); + assertFalse(desc.isMap()); + } + + public void testParameterList(List<List<Map<Integer, Enum<?>>>> list) { + + } + + @Test + public void parameterListNoParamTypes() throws Exception { + MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterListNoParamTypes", List.class), 0); + TypeDescriptor desc = new TypeDescriptor(methodParameter); + assertEquals(List.class, desc.getType()); + assertEquals(List.class, desc.getObjectType()); + assertEquals("java.util.List", desc.getName()); + assertEquals("java.util.List<?>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertTrue(desc.isCollection()); + assertFalse(desc.isArray()); + assertNull(desc.getElementTypeDescriptor()); + assertFalse(desc.isMap()); + } + + public void testParameterListNoParamTypes(List list) { + + } + + @Test + public void parameterArray() throws Exception { + MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterArray", Integer[].class), 0); + TypeDescriptor desc = new TypeDescriptor(methodParameter); + assertEquals(Integer[].class, desc.getType()); + assertEquals(Integer[].class, desc.getObjectType()); + assertEquals("java.lang.Integer[]", desc.getName()); + assertEquals("java.lang.Integer[]", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertTrue(desc.isArray()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor()); + assertFalse(desc.isMap()); + } + + public void testParameterArray(Integer[] array) { + + } + + @Test + public void parameterMap() throws Exception { + MethodParameter methodParameter = new MethodParameter(getClass().getMethod("testParameterMap", Map.class), 0); + TypeDescriptor desc = new TypeDescriptor(methodParameter); + assertEquals(Map.class, desc.getType()); + assertEquals(Map.class, desc.getObjectType()); + assertEquals("java.util.Map", desc.getName()); + assertEquals("java.util.Map<java.lang.Integer, java.util.List<java.lang.String>>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isArray()); + assertTrue(desc.isMap()); + assertEquals(TypeDescriptor.nested(methodParameter, 1), desc.getMapValueTypeDescriptor()); + assertEquals(TypeDescriptor.nested(methodParameter, 2), desc.getMapValueTypeDescriptor().getElementTypeDescriptor()); + assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getType()); + assertEquals(List.class, desc.getMapValueTypeDescriptor().getType()); + assertEquals(String.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + } + + public void testParameterMap(Map<Integer, List<String>> map) { + + } + + @Test + public void parameterAnnotated() throws Exception { + TypeDescriptor t1 = new TypeDescriptor(new MethodParameter(getClass().getMethod("testAnnotatedMethod", String.class), 0)); + assertEquals(String.class, t1.getType()); + assertEquals(1, t1.getAnnotations().length); + assertNotNull(t1.getAnnotation(ParameterAnnotation.class)); + assertTrue(t1.hasAnnotation(ParameterAnnotation.class)); + assertEquals(123, t1.getAnnotation(ParameterAnnotation.class).value()); + } + + @Target({ElementType.PARAMETER}) + @Retention(RetentionPolicy.RUNTIME) + public @interface ParameterAnnotation { + int value(); + } + + public void testAnnotatedMethod(@ParameterAnnotation(123) String parameter) { + + } + + @Test + public void propertyComplex() throws Exception { + Property property = new Property(getClass(), getClass().getMethod("getComplexProperty"), getClass().getMethod("setComplexProperty", Map.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); + assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getElementTypeDescriptor().getType()); + } + + public Map<String, List<List<Integer>>> getComplexProperty() { + return null; + } + + public void setComplexProperty(Map<String, List<List<Integer>>> complexProperty) { + + } + + @Test + public void propertyGenericType() throws Exception { + GenericType<Integer> genericBean = new IntegerType(); + Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Integer.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void propertyTypeCovariance() throws Exception { + GenericType<Number> genericBean = new NumberType(); + Property property = new Property(getClass(), genericBean.getClass().getMethod("getProperty"), genericBean.getClass().getMethod("setProperty", Number.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void propertyGenericTypeList() throws Exception { + GenericType<Integer> genericBean = new IntegerType(); + Property property = new Property(getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(List.class, desc.getType()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + } + + public interface GenericType<T> { + T getProperty(); + + void setProperty(T t); + + List<T> getListProperty(); + + void setListProperty(List<T> t); + + } + + public class IntegerType implements GenericType<Integer> { + + @Override + public Integer getProperty() { + return null; + } + + @Override + public void setProperty(Integer t) { + } + + @Override + public List<Integer> getListProperty() { + return null; + } + + @Override + public void setListProperty(List<Integer> t) { + } + } + + public class NumberType implements GenericType<Number> { + + @Override + public Integer getProperty() { + return null; + } + + @Override + public void setProperty(Number t) { + } + + @Override + public List<Number> getListProperty() { + return null; + } + + @Override + public void setListProperty(List<Number> t) { + } + } + + @Test + public void propertyGenericClassList() throws Exception { + IntegerClass genericBean = new IntegerClass(); + Property property = new Property(genericBean.getClass(), genericBean.getClass().getMethod("getListProperty"), genericBean.getClass().getMethod("setListProperty", List.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(List.class, desc.getType()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(MethodAnnotation1.class)); + assertTrue(desc.hasAnnotation(MethodAnnotation1.class)); + } + + public static class GenericClass<T> { + + public T getProperty() { + return null; + } + + public void setProperty(T t) { + } + + @MethodAnnotation1 + public List<T> getListProperty() { + return null; + } + + public void setListProperty(List<T> t) { + } + + } + + public static class IntegerClass extends GenericClass<Integer> { + + } + + @Test + public void property() throws Exception { + Property property = new Property(getClass(), getClass().getMethod("getProperty"), getClass().getMethod("setProperty", Map.class)); + TypeDescriptor desc = new TypeDescriptor(property); + assertEquals(Map.class, desc.getType()); + assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(MethodAnnotation1.class)); + assertNotNull(desc.getAnnotation(MethodAnnotation2.class)); + assertNotNull(desc.getAnnotation(MethodAnnotation3.class)); + } + + @MethodAnnotation1 + public Map<List<Integer>, List<Long>> getProperty() { + return property; + } + + @MethodAnnotation2 + public void setProperty(Map<List<Integer>, List<Long>> property) { + this.property = property; + } + + @MethodAnnotation3 + private Map<List<Integer>, List<Long>> property; + + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MethodAnnotation1 { + + } + + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MethodAnnotation2 { + + } + + @Target({ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface MethodAnnotation3 { + + } + + @Test + public void fieldScalar() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldScalar")); + assertFalse(typeDescriptor.isPrimitive()); + assertFalse(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isMap()); + assertEquals(Integer.class, typeDescriptor.getType()); + assertEquals(Integer.class, typeDescriptor.getObjectType()); + } + + public Integer fieldScalar; + + @Test + public void fieldList() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfString")); + assertFalse(typeDescriptor.isArray()); + assertEquals(List.class, typeDescriptor.getType()); + assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getType()); + assertEquals("java.util.List<java.lang.String>", typeDescriptor.toString()); + } + + @Test + public void fieldListOfListOfString() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfString")); + assertFalse(typeDescriptor.isArray()); + assertEquals(List.class, typeDescriptor.getType()); + assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType()); + assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals("java.util.List<java.util.List<java.lang.String>>", typeDescriptor.toString()); + } + + @Test + public void fieldListOfListUnknown() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("listOfListOfUnknown")); + assertFalse(typeDescriptor.isArray()); + assertEquals(List.class, typeDescriptor.getType()); + assertEquals(List.class, typeDescriptor.getElementTypeDescriptor().getType()); + assertNull(typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor()); + assertEquals("java.util.List<java.util.List<?>>", typeDescriptor.toString()); + } + + @Test + public void fieldArray() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("intArray")); + assertTrue(typeDescriptor.isArray()); + assertEquals(Integer.TYPE,typeDescriptor.getElementTypeDescriptor().getType()); + assertEquals("int[]",typeDescriptor.toString()); + } + + @Test + public void fieldComplexTypeDescriptor() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("arrayOfListOfString")); + assertTrue(typeDescriptor.isArray()); + assertEquals(List.class,typeDescriptor.getElementTypeDescriptor().getType()); + assertEquals(String.class, typeDescriptor.getElementTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals("java.util.List[]",typeDescriptor.toString()); + } + + @Test + public void fieldComplexTypeDescriptor2() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(TypeDescriptorTests.class.getDeclaredField("nestedMapField")); + assertTrue(typeDescriptor.isMap()); + assertEquals(String.class,typeDescriptor.getMapKeyTypeDescriptor().getType()); + assertEquals(List.class, typeDescriptor.getMapValueTypeDescriptor().getType()); + assertEquals(Integer.class, typeDescriptor.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals("java.util.Map<java.lang.String, java.util.List<java.lang.Integer>>", typeDescriptor.toString()); + } + + @Test + public void fieldMap() throws Exception { + TypeDescriptor desc = new TypeDescriptor(TypeDescriptorTests.class.getField("fieldMap")); + assertTrue(desc.isMap()); + assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); + assertEquals(Long.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + } + + public Map<List<Integer>, List<Long>> fieldMap; + + @Test + public void fieldAnnotated() throws Exception { + TypeDescriptor typeDescriptor = new TypeDescriptor(getClass().getField("fieldAnnotated")); + assertEquals(1, typeDescriptor.getAnnotations().length); + assertNotNull(typeDescriptor.getAnnotation(FieldAnnotation.class)); + } + + @FieldAnnotation + public List<String> fieldAnnotated; + + @Target({ElementType.FIELD}) + @Retention(RetentionPolicy.RUNTIME) + public @interface FieldAnnotation { + + } + + @Test + public void valueOfScalar() { + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Integer.class); + assertFalse(typeDescriptor.isPrimitive()); + assertFalse(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isMap()); + assertEquals(Integer.class, typeDescriptor.getType()); + assertEquals(Integer.class, typeDescriptor.getObjectType()); + } + + @Test + public void valueOfPrimitive() { + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int.class); + assertTrue(typeDescriptor.isPrimitive()); + assertFalse(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isMap()); + assertEquals(Integer.TYPE, typeDescriptor.getType()); + assertEquals(Integer.class, typeDescriptor.getObjectType()); + } + + @Test + public void valueOfArray() throws Exception { + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(int[].class); + assertTrue(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isMap()); + assertEquals(Integer.TYPE, typeDescriptor.getElementTypeDescriptor().getType()); + } + + @Test + public void valueOfCollection() throws Exception { + TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(Collection.class); + assertTrue(typeDescriptor.isCollection()); + assertFalse(typeDescriptor.isArray()); + assertFalse(typeDescriptor.isMap()); + assertNull(typeDescriptor.getElementTypeDescriptor()); + } + + @Test + public void forObject() { + TypeDescriptor desc = TypeDescriptor.forObject("3"); + assertEquals(String.class, desc.getType()); + } + + @Test + public void forObjectNullTypeDescriptor() { + TypeDescriptor desc = TypeDescriptor.forObject(null); + assertNull(desc); + } + + @Test + public void nestedMethodParameterType2Levels() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test2", List.class), 0), 2); + assertEquals(String.class, t1.getType()); + } + + @Test + public void nestedMethodParameterTypeMap() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test3", Map.class), 0), 1); + assertEquals(String.class, t1.getType()); + } + + @Test + public void nestedMethodParameterTypeMapTwoLevels() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 2); + assertEquals(String.class, t1.getType()); + } + + @Test(expected=IllegalArgumentException.class) + public void nestedMethodParameterNot1NestedLevel() throws Exception { + TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0, 2), 2); + } + + @Test(expected=IllegalStateException.class) + public void nestedTooManyLevels() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test4", List.class), 0), 3); + assertEquals(String.class, t1.getType()); + } + + @Test(expected=IllegalStateException.class) + public void nestedMethodParameterTypeNotNestable() throws Exception { + TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0), 2); + } + + @Test(expected=IllegalArgumentException.class) + public void nestedMethodParameterTypeInvalidNestingLevel() throws Exception { + TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test5", String.class), 0, 2), 2); + } + + public void test1(List<String> param1) { + + } + + public void test2(List<List<String>> param1) { + + } + + public void test3(Map<Integer, String> param1) { + + } + + public void test4(List<Map<Integer, String>> param1) { + + } + + public void test5(String param1) { + + } + + @Test + public void nestedNotParameterized() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 1); + assertEquals(List.class,t1.getType()); + assertEquals("java.util.List<?>", t1.toString()); + TypeDescriptor t2 = TypeDescriptor.nested(new MethodParameter(getClass().getMethod("test6", List.class), 0), 2); + assertNull(t2); + } + + public void test6(List<List> param1) { + + } + + @Test + public void nestedFieldTypeMapTwoLevels() throws Exception { + TypeDescriptor t1 = TypeDescriptor.nested(getClass().getField("test4"), 2); + assertEquals(String.class, t1.getType()); + } + + public List<Map<Integer, String>> test4; + + @Test + public void nestedPropertyTypeMapTwoLevels() throws Exception { + Property property = new Property(getClass(), getClass().getMethod("getTest4"), getClass().getMethod("setTest4", List.class)); + TypeDescriptor t1 = TypeDescriptor.nested(property, 2); + assertEquals(String.class, t1.getType()); + } + + public List<Map<Integer, String>> getTest4() { + return null; + } + + public void setTest4(List<Map<Integer, String>> test4) { + + } + + @Test + public void collection() { + TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class)); + assertEquals(List.class, desc.getType()); + assertEquals(List.class, desc.getObjectType()); + assertEquals("java.util.List", desc.getName()); + assertEquals("java.util.List<java.lang.Integer>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertTrue(desc.isCollection()); + assertFalse(desc.isArray()); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor()); + assertFalse(desc.isMap()); + } + + @Test + public void collectionNested() { + TypeDescriptor desc = TypeDescriptor.collection(List.class, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class))); + assertEquals(List.class, desc.getType()); + assertEquals(List.class, desc.getObjectType()); + assertEquals("java.util.List", desc.getName()); + assertEquals("java.util.List<java.util.List<java.lang.Integer>>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertTrue(desc.isCollection()); + assertFalse(desc.isArray()); + assertEquals(List.class, desc.getElementTypeDescriptor().getType()); + assertEquals(TypeDescriptor.valueOf(Integer.class), desc.getElementTypeDescriptor().getElementTypeDescriptor()); + assertFalse(desc.isMap()); + } + + @Test + public void map() { + TypeDescriptor desc = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class)); + assertEquals(Map.class, desc.getType()); + assertEquals(Map.class, desc.getObjectType()); + assertEquals("java.util.Map", desc.getName()); + assertEquals("java.util.Map<java.lang.String, java.lang.Integer>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isArray()); + assertTrue(desc.isMap()); + assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); + assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getType()); + } + + @Test + public void mapNested() { + TypeDescriptor desc = TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), + TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class))); + assertEquals(Map.class, desc.getType()); + assertEquals(Map.class, desc.getObjectType()); + assertEquals("java.util.Map", desc.getName()); + assertEquals("java.util.Map<java.lang.String, java.util.Map<java.lang.String, java.lang.Integer>>", desc.toString()); + assertTrue(!desc.isPrimitive()); + assertEquals(0, desc.getAnnotations().length); + assertFalse(desc.isCollection()); + assertFalse(desc.isArray()); + assertTrue(desc.isMap()); + assertEquals(String.class, desc.getMapKeyTypeDescriptor().getType()); + assertEquals(String.class, desc.getMapValueTypeDescriptor().getMapKeyTypeDescriptor().getType()); + assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getMapValueTypeDescriptor().getType()); + } + + @Test + public void narrow() { + TypeDescriptor desc = TypeDescriptor.valueOf(Number.class); + Integer value = new Integer(3); + desc = desc.narrow(value); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void elementType() { + TypeDescriptor desc = TypeDescriptor.valueOf(List.class); + Integer value = new Integer(3); + desc = desc.elementTypeDescriptor(value); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void elementTypePreserveContext() throws Exception { + TypeDescriptor desc = new TypeDescriptor(getClass().getField("listPreserveContext")); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getElementTypeDescriptor().getType()); + List<Integer> value = new ArrayList<Integer>(3); + desc = desc.elementTypeDescriptor(value); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(FieldAnnotation.class)); + } + + @FieldAnnotation + public List<List<Integer>> listPreserveContext; + + @Test + public void mapKeyType() { + TypeDescriptor desc = TypeDescriptor.valueOf(Map.class); + Integer value = new Integer(3); + desc = desc.getMapKeyTypeDescriptor(value); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void mapKeyTypePreserveContext() throws Exception { + TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext")); + assertEquals(Integer.class, desc.getMapKeyTypeDescriptor().getElementTypeDescriptor().getType()); + List<Integer> value = new ArrayList<Integer>(3); + desc = desc.getMapKeyTypeDescriptor(value); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(FieldAnnotation.class)); + } + + @FieldAnnotation + public Map<List<Integer>, List<Integer>> mapPreserveContext; + + @Test + public void mapValueType() { + TypeDescriptor desc = TypeDescriptor.valueOf(Map.class); + Integer value = new Integer(3); + desc = desc.getMapValueTypeDescriptor(value); + assertEquals(Integer.class, desc.getType()); + } + + @Test + public void mapValueTypePreserveContext() throws Exception { + TypeDescriptor desc = new TypeDescriptor(getClass().getField("mapPreserveContext")); + assertEquals(Integer.class, desc.getMapValueTypeDescriptor().getElementTypeDescriptor().getType()); + List<Integer> value = new ArrayList<Integer>(3); + desc = desc.getMapValueTypeDescriptor(value); + assertEquals(Integer.class, desc.getElementTypeDescriptor().getType()); + assertNotNull(desc.getAnnotation(FieldAnnotation.class)); + } + + @Test + public void equals() throws Exception { + TypeDescriptor t1 = TypeDescriptor.valueOf(String.class); + TypeDescriptor t2 = TypeDescriptor.valueOf(String.class); + TypeDescriptor t3 = TypeDescriptor.valueOf(Date.class); + TypeDescriptor t4 = TypeDescriptor.valueOf(Date.class); + TypeDescriptor t5 = TypeDescriptor.valueOf(List.class); + TypeDescriptor t6 = TypeDescriptor.valueOf(List.class); + TypeDescriptor t7 = TypeDescriptor.valueOf(Map.class); + TypeDescriptor t8 = TypeDescriptor.valueOf(Map.class); + assertEquals(t1, t2); + assertEquals(t3, t4); + assertEquals(t5, t6); + assertEquals(t7, t8); + + TypeDescriptor t9 = new TypeDescriptor(getClass().getField("listField")); + TypeDescriptor t10 = new TypeDescriptor(getClass().getField("listField")); + assertEquals(t9, t10); + + TypeDescriptor t11 = new TypeDescriptor(getClass().getField("mapField")); + TypeDescriptor t12 = new TypeDescriptor(getClass().getField("mapField")); + assertEquals(t11, t12); + } + + @Test + public void isAssignableTypes() { + assertTrue(TypeDescriptor.valueOf(Integer.class).isAssignableTo(TypeDescriptor.valueOf(Number.class))); + assertFalse(TypeDescriptor.valueOf(Number.class).isAssignableTo(TypeDescriptor.valueOf(Integer.class))); + assertFalse(TypeDescriptor.valueOf(String.class).isAssignableTo(TypeDescriptor.valueOf(String[].class))); + } + + @Test + public void isAssignableElementTypes() throws Exception { + assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); + assertTrue(new TypeDescriptor(getClass().getField("notGenericList")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); + assertTrue(new TypeDescriptor(getClass().getField("listField")).isAssignableTo(new TypeDescriptor(getClass().getField("notGenericList")))); + assertFalse(new TypeDescriptor(getClass().getField("isAssignableElementTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); + assertTrue(TypeDescriptor.valueOf(List.class).isAssignableTo(new TypeDescriptor(getClass().getField("listField")))); + } + + public List notGenericList; + + public List<Number> isAssignableElementTypes; + + @Test + public void isAssignableMapKeyValueTypes() throws Exception { + assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); + assertTrue(new TypeDescriptor(getClass().getField("notGenericMap")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); + assertTrue(new TypeDescriptor(getClass().getField("mapField")).isAssignableTo(new TypeDescriptor(getClass().getField("notGenericMap")))); + assertFalse(new TypeDescriptor(getClass().getField("isAssignableMapKeyValueTypes")).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); + assertTrue(TypeDescriptor.valueOf(Map.class).isAssignableTo(new TypeDescriptor(getClass().getField("mapField")))); + } + + public Map notGenericMap; + + public Map<CharSequence, Number> isAssignableMapKeyValueTypes; + + @Test + public void testUpCast() throws Exception { + Property property = new Property(getClass(), getClass().getMethod("getProperty"), + getClass().getMethod("setProperty", Map.class)); + TypeDescriptor typeDescriptor = new TypeDescriptor(property); + TypeDescriptor upCast = typeDescriptor.upcast(Object.class); + assertTrue(upCast.getAnnotation(MethodAnnotation1.class) != null); + } + + @Test + public void testUpCastNotSuper() throws Exception { + Property property = new Property(getClass(), getClass().getMethod("getProperty"), + getClass().getMethod("setProperty", Map.class)); + TypeDescriptor typeDescriptor = new TypeDescriptor(property); + try { + typeDescriptor.upcast(Collection.class); + fail("Did not throw"); + } catch(IllegalArgumentException e) { + assertEquals("interface java.util.Map is not assignable to interface java.util.Collection", e.getMessage()); + } + } + + @Test + public void elementTypeForCollectionSubclass() throws Exception { + @SuppressWarnings("serial") + class CustomSet extends HashSet<String> { + } + + assertEquals(TypeDescriptor.valueOf(CustomSet.class).getElementTypeDescriptor(), TypeDescriptor.valueOf(String.class)); + assertEquals(TypeDescriptor.forObject(new CustomSet()).getElementTypeDescriptor(), TypeDescriptor.valueOf(String.class)); + } + + @Test + public void elementTypeForMapSubclass() throws Exception { + @SuppressWarnings("serial") + class CustomMap extends HashMap<String, Integer> { + } + + assertEquals(TypeDescriptor.valueOf(CustomMap.class).getMapKeyTypeDescriptor(), TypeDescriptor.valueOf(String.class)); + assertEquals(TypeDescriptor.valueOf(CustomMap.class).getMapValueTypeDescriptor(), TypeDescriptor.valueOf(Integer.class)); + assertEquals(TypeDescriptor.forObject(new CustomMap()).getMapKeyTypeDescriptor(), TypeDescriptor.valueOf(String.class)); + assertEquals(TypeDescriptor.forObject(new CustomMap()).getMapValueTypeDescriptor(), TypeDescriptor.valueOf(Integer.class)); + } + + @Test + public void createMapArray() throws Exception { + TypeDescriptor mapType = TypeDescriptor.map(LinkedHashMap.class, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class)); + TypeDescriptor arrayType = TypeDescriptor.array(mapType); + assertEquals(arrayType.getType(), LinkedHashMap[].class); + assertEquals(arrayType.getElementTypeDescriptor(), mapType); + } + + + @Test + public void createStringArray() throws Exception { + TypeDescriptor arrayType = TypeDescriptor.array(TypeDescriptor.valueOf(String.class)); + assertEquals(arrayType, TypeDescriptor.valueOf(String[].class)); + } + + @Test + public void createNullArray() throws Exception { + assertNull(TypeDescriptor.array(null)); + } + + @Test + public void serializable() throws Exception { + TypeDescriptor typeDescriptor = TypeDescriptor.forObject(""); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ObjectOutputStream outputStream = new ObjectOutputStream(out); + outputStream.writeObject(typeDescriptor); + ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream( + out.toByteArray())); + TypeDescriptor readObject = (TypeDescriptor) inputStream.readObject(); + assertThat(readObject, equalTo(typeDescriptor)); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/convert/converter/ConvertingComparatorTests.java b/spring-core/src/test/java/org/springframework/core/convert/converter/ConvertingComparatorTests.java new file mode 100644 index 00000000..4cadfe74 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/convert/converter/ConvertingComparatorTests.java @@ -0,0 +1,148 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.convert.converter; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.junit.Test; + +import org.springframework.core.convert.ConversionService; +import org.springframework.core.convert.support.DefaultConversionService; +import org.springframework.util.comparator.ComparableComparator; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +/** + * Tests for {@link ConvertingComparator}. + * + * @author Phillip Webb + */ +public class ConvertingComparatorTests { + + private final StringToInteger converter = new StringToInteger(); + + private final ConversionService conversionService = new DefaultConversionService(); + + private final TestComparator comparator = new TestComparator(); + + @Test(expected=IllegalArgumentException.class) + public void shouldThrowOnNullComparator() throws Exception { + new ConvertingComparator<String, Integer>(null, this.converter); + } + + @Test(expected=IllegalArgumentException.class) + public void shouldThrowOnNullConverter() throws Exception { + new ConvertingComparator<String, Integer>(this.comparator, null); + } + + @Test(expected=IllegalArgumentException.class) + public void shouldThrowOnNullConversionService() throws Exception { + new ConvertingComparator<String, Integer>(this.comparator, null, Integer.class); + } + + @Test(expected=IllegalArgumentException.class) + public void shouldThrowOnNullType() throws Exception { + new ConvertingComparator<String, Integer>(this.comparator, + this.conversionService, null); + } + + @Test + public void shouldUseConverterOnCompare() throws Exception { + ConvertingComparator<String, Integer> convertingComparator = new ConvertingComparator<String, Integer>( + this.comparator, this.converter); + testConversion(convertingComparator); + } + + @Test + public void shouldUseConversionServiceOnCompare() throws Exception { + ConvertingComparator<String, Integer> convertingComparator = new ConvertingComparator<String, Integer>( + comparator, conversionService, Integer.class); + testConversion(convertingComparator); + } + + @Test + public void shouldGetForConverter() throws Exception { + testConversion(new ConvertingComparator<String, Integer>(comparator, converter)); + } + + private void testConversion(ConvertingComparator<String, Integer> convertingComparator) { + assertThat(convertingComparator.compare("0", "0"), is(0)); + assertThat(convertingComparator.compare("0", "1"), is(-1)); + assertThat(convertingComparator.compare("1", "0"), is(1)); + comparator.assertCalled(); + } + + @Test + public void shouldGetMapEntryKeys() throws Exception { + ArrayList<Entry<String, Integer>> list = createReverseOrderMapEntryList(); + Comparator<Map.Entry<String, Integer>> comparator = ConvertingComparator.mapEntryKeys(new ComparableComparator<String>()); + Collections.sort(list, comparator); + assertThat(list.get(0).getKey(), is("a")); + } + + @Test + public void shouldGetMapEntryValues() throws Exception { + ArrayList<Entry<String, Integer>> list = createReverseOrderMapEntryList(); + Comparator<Map.Entry<String, Integer>> comparator = ConvertingComparator.mapEntryValues(new ComparableComparator<Integer>()); + Collections.sort(list, comparator); + assertThat(list.get(0).getValue(), is(1)); + } + + private ArrayList<Entry<String, Integer>> createReverseOrderMapEntryList() { + Map<String, Integer> map = new LinkedHashMap<String, Integer>(); + map.put("b", 2); + map.put("a", 1); + ArrayList<Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>( + map.entrySet()); + assertThat(list.get(0).getKey(), is("b")); + return list; + } + + private static class StringToInteger implements Converter<String, Integer> { + + @Override + public Integer convert(String source) { + return new Integer(source); + } + + } + + + private static class TestComparator extends ComparableComparator<Integer> { + + private boolean called; + + @Override + public int compare(Integer o1, Integer o2) { + assertThat(o1, instanceOf(Integer.class)); + assertThat(o2, instanceOf(Integer.class)); + this.called = true; + return super.compare(o1, o2); + }; + + public void assertCalled() { + assertThat(this.called, is(true)); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java new file mode 100644 index 00000000..00bf054a --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/convert/support/CollectionToCollectionConverterTests.java @@ -0,0 +1,338 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * 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 org.springframework.core.convert.support; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +import static org.junit.Assert.*; + +/** + * @author Keith Donald + * @author Juergen Hoeller + * @author Stephane Nicoll + */ +public class CollectionToCollectionConverterTests { + + private GenericConversionService conversionService = new GenericConversionService(); + + + @Before + public void setUp() { + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + } + + + @Test + public void scalarList() throws Exception { + List<String> list = new ArrayList<String>(); + list.add("9"); + list.add("37"); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarListTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + try { + conversionService.convert(list, sourceType, targetType); + } + catch (ConversionFailedException ex) { + assertTrue(ex.getCause() instanceof ConverterNotFoundException); + } + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + List<String> result = (List<String>) conversionService.convert(list, sourceType, targetType); + assertFalse(list.equals(result)); + assertEquals(9, result.get(0)); + assertEquals(37, result.get(1)); + } + + @Test + public void emptyListToList() throws Exception { + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + List<String> list = new ArrayList<String>(); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyListTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + assertEquals(list, conversionService.convert(list, sourceType, targetType)); + } + + @Test + public void emptyListToListDifferentTargetType() throws Exception { + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + List<String> list = new ArrayList<String>(); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyListDifferentTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + LinkedList<Integer> result = (LinkedList<Integer>) conversionService.convert(list, sourceType, targetType); + assertEquals(LinkedList.class, result.getClass()); + assertTrue(result.isEmpty()); + } + + @Test + public void collectionToObjectInteraction() throws Exception { + List<List<String>> list = new ArrayList<List<String>>(); + list.add(Arrays.asList("9", "12")); + list.add(Arrays.asList("37", "23")); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + assertTrue(conversionService.canConvert(List.class, List.class)); + assertSame(list, conversionService.convert(list, List.class)); + } + + @Test + @SuppressWarnings("unchecked") + public void arrayCollectionToObjectInteraction() throws Exception { + List<String>[] array = new List[2]; + array[0] = Arrays.asList("9", "12"); + array[1] = Arrays.asList("37", "23"); + conversionService.addConverter(new ArrayToCollectionConverter(conversionService)); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + assertTrue(conversionService.canConvert(String[].class, List.class)); + assertEquals(Arrays.asList(array), conversionService.convert(array, List.class)); + } + + @Test + @SuppressWarnings("unchecked") + public void objectToCollection() throws Exception { + List<List<String>> list = new ArrayList<List<String>>(); + list.add(Arrays.asList("9", "12")); + list.add(Arrays.asList("37", "23")); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addConverter(new ObjectToCollectionConverter(conversionService)); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("objectToCollection")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + List<List<List<Integer>>> result = (List<List<List<Integer>>>) conversionService.convert(list, sourceType, targetType); + assertEquals((Integer) 9, result.get(0).get(0).get(0)); + assertEquals((Integer) 12, result.get(0).get(1).get(0)); + assertEquals((Integer) 37, result.get(1).get(0).get(0)); + assertEquals((Integer) 23, result.get(1).get(1).get(0)); + } + + @Test + @SuppressWarnings("unchecked") + public void stringToCollection() throws Exception { + List<List<String>> list = new ArrayList<List<String>>(); + list.add(Arrays.asList("9,12")); + list.add(Arrays.asList("37,23")); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + conversionService.addConverter(new StringToCollectionConverter(conversionService)); + conversionService.addConverter(new ObjectToCollectionConverter(conversionService)); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("objectToCollection")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + List<List<List<Integer>>> result = (List<List<List<Integer>>>) conversionService.convert(list, sourceType, targetType); + assertEquals((Integer) 9, result.get(0).get(0).get(0)); + assertEquals((Integer) 12, result.get(0).get(0).get(1)); + assertEquals((Integer) 37, result.get(1).get(0).get(0)); + assertEquals((Integer) 23, result.get(1).get(0).get(1)); + } + + @Test + public void convertEmptyVector_shouldReturnEmptyArrayList() { + Vector<String> vector = new Vector<String>(); + vector.add("Element"); + testCollectionConversionToArrayList(vector); + } + + @Test + public void convertNonEmptyVector_shouldReturnNonEmptyArrayList() { + Vector<String> vector = new Vector<String>(); + vector.add("Element"); + testCollectionConversionToArrayList(vector); + } + + @Test + public void testCollectionsEmptyList() throws Exception { + CollectionToCollectionConverter converter = new CollectionToCollectionConverter(new GenericConversionService()); + TypeDescriptor type = new TypeDescriptor(getClass().getField("list")); + converter.convert(list, type, TypeDescriptor.valueOf(Class.forName("java.util.Collections$EmptyList"))); + } + + @SuppressWarnings("rawtypes") + private void testCollectionConversionToArrayList(Collection<String> aSource) { + Object myConverted = (new CollectionToCollectionConverter(new GenericConversionService())).convert( + aSource, TypeDescriptor.forObject(aSource), TypeDescriptor.forObject(new ArrayList())); + assertTrue(myConverted instanceof ArrayList<?>); + assertEquals(aSource.size(), ((ArrayList<?>) myConverted).size()); + } + + @Test + public void listToCollectionNoCopyRequired() throws NoSuchFieldException { + List<?> input = new ArrayList<String>(Arrays.asList("foo", "bar")); + assertSame(input, conversionService.convert(input, TypeDescriptor.forObject(input), + new TypeDescriptor(getClass().getField("wildCardCollection")))); + } + + @Test + public void differentImpls() throws Exception { + List<Resource> resources = new ArrayList<Resource>(); + resources.add(new ClassPathResource("test")); + resources.add(new FileSystemResource("test")); + resources.add(new TestResource()); + TypeDescriptor sourceType = TypeDescriptor.forObject(resources); + assertSame(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + @Test + public void mixedInNulls() throws Exception { + List<Resource> resources = new ArrayList<Resource>(); + resources.add(new ClassPathResource("test")); + resources.add(null); + resources.add(new FileSystemResource("test")); + resources.add(new TestResource()); + TypeDescriptor sourceType = TypeDescriptor.forObject(resources); + assertSame(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + @Test + public void allNulls() throws Exception { + List<Resource> resources = new ArrayList<Resource>(); + resources.add(null); + resources.add(null); + TypeDescriptor sourceType = TypeDescriptor.forObject(resources); + assertSame(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + @Test(expected=ConverterNotFoundException.class) + public void elementTypesNotConvertible() throws Exception { + List<String> resources = new ArrayList<String>(); + resources.add(null); + resources.add(null); + TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("strings")); + assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + @Test(expected=ConversionFailedException.class) + public void nothingInCommon() throws Exception { + List<Object> resources = new ArrayList<Object>(); + resources.add(new ClassPathResource("test")); + resources.add(3); + TypeDescriptor sourceType = TypeDescriptor.forObject(resources); + assertEquals(resources, conversionService.convert(resources, sourceType, new TypeDescriptor(getClass().getField("resources")))); + } + + + public ArrayList<Integer> scalarListTarget; + + public List<Integer> emptyListTarget; + + public LinkedList<Integer> emptyListDifferentTarget; + + public List<List<List<Integer>>> objectToCollection; + + public List<String> strings; + + public List list = Collections.emptyList(); + + public Collection<?> wildCardCollection = Collections.emptyList(); + + public List<Resource> resources; + + + public static abstract class BaseResource implements Resource { + + @Override + public InputStream getInputStream() throws IOException { + return null; + } + + @Override + public boolean exists() { + return false; + } + + @Override + public boolean isReadable() { + return false; + } + + @Override + public boolean isOpen() { + return false; + } + + @Override + public URL getURL() throws IOException { + return null; + } + + @Override + public URI getURI() throws IOException { + return null; + } + + @Override + public File getFile() throws IOException { + return null; + } + + @Override + public long contentLength() throws IOException { + return 0; + } + + @Override + public long lastModified() throws IOException { + return 0; + } + + @Override + public Resource createRelative(String relativePath) throws IOException { + return null; + } + + @Override + public String getFilename() { + return null; + } + + @Override + public String getDescription() { + return null; + } + } + + + public static class TestResource extends BaseResource { + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java new file mode 100644 index 00000000..f3498894 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/convert/support/DefaultConversionTests.java @@ -0,0 +1,876 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * 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 org.springframework.core.convert.support; + +import java.awt.Color; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import org.junit.Test; + +import org.springframework.core.MethodParameter; +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterRegistry; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * @author Keith Donald + * @author Juergen Hoeller + */ +public class DefaultConversionTests { + + private final DefaultConversionService conversionService = new DefaultConversionService(); + + + @Test + public void testStringToCharacter() { + assertEquals(Character.valueOf('1'), conversionService.convert("1", Character.class)); + } + + @Test + public void testStringToCharacterEmptyString() { + assertEquals(null, conversionService.convert("", Character.class)); + } + + @Test(expected=ConversionFailedException.class) + public void testStringToCharacterInvalidString() { + conversionService.convert("invalid", Character.class); + } + + @Test + public void testCharacterToString() { + assertEquals("3", conversionService.convert('3', String.class)); + } + + @Test + public void testStringToBooleanTrue() { + assertEquals(Boolean.valueOf(true), conversionService.convert("true", Boolean.class)); + assertEquals(Boolean.valueOf(true), conversionService.convert("on", Boolean.class)); + assertEquals(Boolean.valueOf(true), conversionService.convert("yes", Boolean.class)); + assertEquals(Boolean.valueOf(true), conversionService.convert("1", Boolean.class)); + assertEquals(Boolean.valueOf(true), conversionService.convert("TRUE", Boolean.class)); + assertEquals(Boolean.valueOf(true), conversionService.convert("ON", Boolean.class)); + assertEquals(Boolean.valueOf(true), conversionService.convert("YES", Boolean.class)); + } + + @Test + public void testStringToBooleanFalse() { + assertEquals(Boolean.valueOf(false), conversionService.convert("false", Boolean.class)); + assertEquals(Boolean.valueOf(false), conversionService.convert("off", Boolean.class)); + assertEquals(Boolean.valueOf(false), conversionService.convert("no", Boolean.class)); + assertEquals(Boolean.valueOf(false), conversionService.convert("0", Boolean.class)); + assertEquals(Boolean.valueOf(false), conversionService.convert("FALSE", Boolean.class)); + assertEquals(Boolean.valueOf(false), conversionService.convert("OFF", Boolean.class)); + assertEquals(Boolean.valueOf(false), conversionService.convert("NO", Boolean.class)); + } + + @Test + public void testStringToBooleanEmptyString() { + assertEquals(null, conversionService.convert("", Boolean.class)); + } + + @Test(expected=ConversionFailedException.class) + public void testStringToBooleanInvalidString() { + conversionService.convert("invalid", Boolean.class); + } + + @Test + public void testBooleanToString() { + assertEquals("true", conversionService.convert(true, String.class)); + } + + @Test + public void testStringToByte() throws Exception { + assertEquals(Byte.valueOf("1"), conversionService.convert("1", Byte.class)); + } + + @Test + public void testByteToString() { + assertEquals("65", conversionService.convert(new String("A").getBytes()[0], String.class)); + } + + @Test + public void testStringToShort() { + assertEquals(Short.valueOf("1"), conversionService.convert("1", Short.class)); + } + + @Test + public void testShortToString() { + short three = 3; + assertEquals("3", conversionService.convert(three, String.class)); + } + + @Test + public void testStringToInteger() { + assertEquals(Integer.valueOf("1"), conversionService.convert("1", Integer.class)); + } + + @Test + public void testIntegerToString() { + assertEquals("3", conversionService.convert(3, String.class)); + } + + @Test + public void testStringToLong() { + assertEquals(Long.valueOf("1"), conversionService.convert("1", Long.class)); + } + + @Test + public void testLongToString() { + assertEquals("3", conversionService.convert(3L, String.class)); + } + + @Test + public void testStringToFloat() { + assertEquals(Float.valueOf("1.0"), conversionService.convert("1.0", Float.class)); + } + + @Test + public void testFloatToString() { + assertEquals("1.0", conversionService.convert(new Float("1.0"), String.class)); + } + + @Test + public void testStringToDouble() { + assertEquals(Double.valueOf("1.0"), conversionService.convert("1.0", Double.class)); + } + + @Test + public void testDoubleToString() { + assertEquals("1.0", conversionService.convert(new Double("1.0"), String.class)); + } + + @Test + public void testStringToBigInteger() { + assertEquals(new BigInteger("1"), conversionService.convert("1", BigInteger.class)); + } + + @Test + public void testBigIntegerToString() { + assertEquals("100", conversionService.convert(new BigInteger("100"), String.class)); + } + + @Test + public void testStringToBigDecimal() { + assertEquals(new BigDecimal("1.0"), conversionService.convert("1.0", BigDecimal.class)); + } + + @Test + public void testBigDecimalToString() { + assertEquals("100.00", conversionService.convert(new BigDecimal("100.00"), String.class)); + } + + @Test + public void testStringToNumber() { + assertEquals(new BigDecimal("1.0"), conversionService.convert("1.0", Number.class)); + } + + @Test + public void testStringToNumberEmptyString() { + assertEquals(null, conversionService.convert("", Number.class)); + } + + @Test + public void testStringToEnum() throws Exception { + assertEquals(Foo.BAR, conversionService.convert("BAR", Foo.class)); + } + + @Test + public void testStringToEnumWithSubclass() throws Exception { + assertEquals(SubFoo.BAZ, conversionService.convert("BAZ", SubFoo.BAR.getClass())); + } + + @Test + public void testStringToEnumEmptyString() { + assertEquals(null, conversionService.convert("", Foo.class)); + } + + @Test + public void testEnumToString() { + assertEquals("BAR", conversionService.convert(Foo.BAR, String.class)); + } + + public static enum Foo { + BAR, BAZ + } + + public static enum SubFoo { + + BAR { + @Override + String s() { + return "x"; + } + }, + BAZ { + @Override + String s() { + return "y"; + } + }; + + abstract String s(); + } + + @Test + public void testStringToLocale() { + assertEquals(Locale.ENGLISH, conversionService.convert("en", Locale.class)); + } + + @Test + public void testStringToString() { + String str = "test"; + assertSame(str, conversionService.convert(str, String.class)); + } + + @Test + public void testNumberToNumber() { + assertEquals(Long.valueOf(1), conversionService.convert(Integer.valueOf(1), Long.class)); + } + + @Test(expected=ConversionFailedException.class) + public void testNumberToNumberNotSupportedNumber() { + conversionService.convert(Integer.valueOf(1), CustomNumber.class); + } + + @SuppressWarnings("serial") + public static class CustomNumber extends Number { + + @Override + public double doubleValue() { + return 0; + } + + @Override + public float floatValue() { + return 0; + } + + @Override + public int intValue() { + return 0; + } + + @Override + public long longValue() { + return 0; + } + + } + + @Test + public void testNumberToCharacter() { + assertEquals(Character.valueOf('A'), conversionService.convert(Integer.valueOf(65), Character.class)); + } + + @Test + public void testCharacterToNumber() { + assertEquals(new Integer(65), conversionService.convert('A', Integer.class)); + } + + // collection conversion + + @Test + public void convertArrayToCollectionInterface() { + List<?> result = conversionService.convert(new String[] { "1", "2", "3" }, List.class); + assertEquals("1", result.get(0)); + assertEquals("2", result.get(1)); + assertEquals("3", result.get(2)); + } + + public List<Integer> genericList = new ArrayList<Integer>(); + + @Test + public void convertArrayToCollectionGenericTypeConversion() throws Exception { + List<Integer> result = (List<Integer>) conversionService.convert(new String[] { "1", "2", "3" }, TypeDescriptor + .valueOf(String[].class), new TypeDescriptor(getClass().getDeclaredField("genericList"))); + assertEquals(new Integer("1"), result.get(0)); + assertEquals(new Integer("2"), result.get(1)); + assertEquals(new Integer("3"), result.get(2)); + } + + @Test + public void testSpr7766() throws Exception { + ConverterRegistry registry = (conversionService); + registry.addConverter(new ColorConverter()); + List<Color> colors = (List<Color>) conversionService.convert(new String[] { "ffffff", "#000000" }, TypeDescriptor.valueOf(String[].class), new TypeDescriptor(new MethodParameter(getClass().getMethod("handlerMethod", List.class), 0))); + assertEquals(2, colors.size()); + assertEquals(Color.WHITE, colors.get(0)); + assertEquals(Color.BLACK, colors.get(1)); + } + + public class ColorConverter implements Converter<String, Color> { + @Override + public Color convert(String source) { if (!source.startsWith("#")) source = "#" + source; return Color.decode(source); } + } + + public void handlerMethod(List<Color> color) { + + } + + @Test + public void convertArrayToCollectionImpl() { + LinkedList<?> result = conversionService.convert(new String[] { "1", "2", "3" }, LinkedList.class); + assertEquals("1", result.get(0)); + assertEquals("2", result.get(1)); + assertEquals("3", result.get(2)); + } + + @Test(expected = ConversionFailedException.class) + public void convertArrayToAbstractCollection() { + conversionService.convert(new String[] { "1", "2", "3" }, AbstractList.class); + } + + public static enum FooEnum { + BAR, BAZ + } + + @Test + public void convertArrayToString() { + String result = conversionService.convert(new String[] { "1", "2", "3" }, String.class); + assertEquals("1,2,3", result); + } + + @Test + public void convertArrayToStringWithElementConversion() { + String result = conversionService.convert(new Integer[] { 1, 2, 3 }, String.class); + assertEquals("1,2,3", result); + } + + @Test + public void convertEmptyArrayToString() { + String result = conversionService.convert(new String[0], String.class); + assertEquals("", result); + } + + @Test + public void convertStringToArray() { + String[] result = conversionService.convert("1,2,3", String[].class); + assertEquals(3, result.length); + assertEquals("1", result[0]); + assertEquals("2", result[1]); + assertEquals("3", result[2]); + } + + @Test + public void convertStringToArrayWithElementConversion() { + Integer[] result = conversionService.convert("1,2,3", Integer[].class); + assertEquals(3, result.length); + assertEquals(new Integer(1), result[0]); + assertEquals(new Integer(2), result[1]); + assertEquals(new Integer(3), result[2]); + } + + @Test + public void convertStringToPrimitiveArrayWithElementConversion() { + int[] result = conversionService.convert("1,2,3", int[].class); + assertEquals(3, result.length); + assertEquals(1, result[0]); + assertEquals(2, result[1]); + assertEquals(3, result[2]); + } + + @Test + public void convertEmptyStringToArray() { + String[] result = conversionService.convert("", String[].class); + assertEquals(0, result.length); + } + + @Test + public void convertArrayToObject() { + Object[] array = new Object[] { 3L }; + Object result = conversionService.convert(array, Long.class); + assertEquals(3L, result); + } + + @Test + public void convertArrayToObjectWithElementConversion() { + String[] array = new String[] { "3" }; + Integer result = conversionService.convert(array, Integer.class); + assertEquals(new Integer(3), result); + } + + @Test + public void convertArrayToObjectAssignableTargetType() { + Long[] array = new Long[] { 3L }; + Long[] result = (Long[]) conversionService.convert(array, Object.class); + assertArrayEquals(array, result); + } + + @Test + public void convertObjectToArray() { + Object[] result = conversionService.convert(3L, Object[].class); + assertEquals(1, result.length); + assertEquals(3L, result[0]); + } + + @Test + public void convertObjectToArrayWithElementConversion() { + Integer[] result = conversionService.convert(3L, Integer[].class); + assertEquals(1, result.length); + assertEquals(new Integer(3), result[0]); + } + + @Test + public void convertCollectionToArray() { + List<String> list = new ArrayList<String>(); + list.add("1"); + list.add("2"); + list.add("3"); + String[] result = conversionService.convert(list, String[].class); + assertEquals("1", result[0]); + assertEquals("2", result[1]); + assertEquals("3", result[2]); + } + + @Test + public void convertCollectionToArrayWithElementConversion() { + List<String> list = new ArrayList<String>(); + list.add("1"); + list.add("2"); + list.add("3"); + Integer[] result = conversionService.convert(list, Integer[].class); + assertEquals(new Integer(1), result[0]); + assertEquals(new Integer(2), result[1]); + assertEquals(new Integer(3), result[2]); + } + + @Test + public void convertCollectionToString() { + List<String> list = Arrays.asList(new String[] { "foo", "bar" }); + String result = conversionService.convert(list, String.class); + assertEquals("foo,bar", result); + } + + @Test + public void convertCollectionToStringWithElementConversion() throws Exception { + List<Integer> list = Arrays.asList(new Integer[] { 3, 5 }); + String result = (String) conversionService.convert(list, + new TypeDescriptor(getClass().getField("genericList")), TypeDescriptor.valueOf(String.class)); + assertEquals("3,5", result); + } + + @Test + public void convertStringToCollection() { + List result = conversionService.convert("1,2,3", List.class); + assertEquals(3, result.size()); + assertEquals("1", result.get(0)); + assertEquals("2", result.get(1)); + assertEquals("3", result.get(2)); + } + + @Test + public void convertStringToCollectionWithElementConversion() throws Exception { + List result = (List) conversionService.convert("1,2,3", TypeDescriptor.valueOf(String.class), + new TypeDescriptor(getClass().getField("genericList"))); + assertEquals(3, result.size()); + assertEquals(new Integer(1), result.get(0)); + assertEquals(new Integer(2), result.get(1)); + assertEquals(new Integer(3), result.get(2)); + } + + @Test + public void convertEmptyStringToCollection() { + Collection result = conversionService.convert("", Collection.class); + assertEquals(0, result.size()); + } + + @Test + public void convertCollectionToObject() { + List<Long> list = Collections.singletonList(3L); + Long result = conversionService.convert(list, Long.class); + assertEquals(new Long(3), result); + } + + @Test + public void convertCollectionToObjectWithElementConversion() { + List<String> list = Collections.singletonList("3"); + Integer result = conversionService.convert(list, Integer.class); + assertEquals(new Integer(3), result); + } + + @Test + public void convertCollectionToObjectAssignableTarget() throws Exception { + Collection<String> source = new ArrayList<String>(); + source.add("foo"); + Object result = conversionService.convert(source, new TypeDescriptor(getClass().getField("assignableTarget"))); + assertEquals(source, result); + } + + @Test + public void convertCollectionToObjectWithCustomConverter() throws Exception { + List<String> source = new ArrayList<String>(); + source.add("A"); + source.add("B"); + conversionService.addConverter(new Converter<List, ListWrapper>() { + @Override + public ListWrapper convert(List source) { + return new ListWrapper(source); + } + }); + ListWrapper result = conversionService.convert(source, ListWrapper.class); + assertSame(source, result.getList()); + } + + @Test + public void convertObjectToCollection() { + List<String> result = (List<String>) conversionService.convert(3L, List.class); + assertEquals(1, result.size()); + assertEquals(3L, result.get(0)); + } + + @Test + public void convertObjectToCollectionWithElementConversion() throws Exception { + List<Integer> result = (List<Integer>) conversionService.convert(3L, TypeDescriptor.valueOf(Long.class), + new TypeDescriptor(getClass().getField("genericList"))); + assertEquals(1, result.size()); + assertEquals(new Integer(3), result.get(0)); + } + + @Test + public void convertArrayToArray() { + Integer[] result = conversionService.convert(new String[] { "1", "2", "3" }, Integer[].class); + assertEquals(new Integer(1), result[0]); + assertEquals(new Integer(2), result[1]); + assertEquals(new Integer(3), result[2]); + } + + @Test + public void convertArrayToPrimitiveArray() { + int[] result = conversionService.convert(new String[] { "1", "2", "3" }, int[].class); + assertEquals(1, result[0]); + assertEquals(2, result[1]); + assertEquals(3, result[2]); + } + + @Test + public void convertArrayToArrayAssignable() { + int[] result = conversionService.convert(new int[] { 1, 2, 3 }, int[].class); + assertEquals(1, result[0]); + assertEquals(2, result[1]); + assertEquals(3, result[2]); + } + + @Test + public void convertCollectionToCollection() throws Exception { + Set<String> foo = new LinkedHashSet<String>(); + foo.add("1"); + foo.add("2"); + foo.add("3"); + List<Integer> bar = (List<Integer>) conversionService.convert(foo, TypeDescriptor.forObject(foo), + new TypeDescriptor(getClass().getField("genericList"))); + assertEquals(new Integer(1), bar.get(0)); + assertEquals(new Integer(2), bar.get(1)); + assertEquals(new Integer(3), bar.get(2)); + } + + @Test + public void convertCollectionToCollectionNull() throws Exception { + List<Integer> bar = (List<Integer>) conversionService.convert(null, + TypeDescriptor.valueOf(LinkedHashSet.class), new TypeDescriptor(getClass().getField("genericList"))); + assertNull(bar); + } + + @Test + public void convertCollectionToCollectionNotGeneric() throws Exception { + Set<String> foo = new LinkedHashSet<String>(); + foo.add("1"); + foo.add("2"); + foo.add("3"); + List bar = (List) conversionService.convert(foo, TypeDescriptor.valueOf(LinkedHashSet.class), TypeDescriptor + .valueOf(List.class)); + assertEquals("1", bar.get(0)); + assertEquals("2", bar.get(1)); + assertEquals("3", bar.get(2)); + } + + @Test + public void convertCollectionToCollectionSpecialCaseSourceImpl() throws Exception { + Map map = new LinkedHashMap(); + map.put("1", "1"); + map.put("2", "2"); + map.put("3", "3"); + Collection values = map.values(); + List<Integer> bar = (List<Integer>) conversionService.convert(values, + TypeDescriptor.forObject(values), new TypeDescriptor(getClass().getField("genericList"))); + assertEquals(3, bar.size()); + assertEquals(new Integer(1), bar.get(0)); + assertEquals(new Integer(2), bar.get(1)); + assertEquals(new Integer(3), bar.get(2)); + } + + @Test + public void collection() { + List<String> strings = new ArrayList<String>(); + strings.add("3"); + strings.add("9"); + List<Integer> integers = (List<Integer>) conversionService.convert(strings, TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(Integer.class))); + assertEquals(new Integer(3), integers.get(0)); + assertEquals(new Integer(9), integers.get(1)); + } + + public Map<Integer, FooEnum> genericMap = new HashMap<Integer, FooEnum>(); + + @Test + public void convertMapToMap() throws Exception { + Map<String, String> foo = new HashMap<String, String>(); + foo.put("1", "BAR"); + foo.put("2", "BAZ"); + Map<String, FooEnum> map = (Map<String, FooEnum>) conversionService.convert(foo, + TypeDescriptor.forObject(foo), new TypeDescriptor(getClass().getField("genericMap"))); + assertEquals(FooEnum.BAR, map.get(1)); + assertEquals(FooEnum.BAZ, map.get(2)); + } + + @Test + public void map() { + Map<String, String> strings = new HashMap<String, String>(); + strings.put("3", "9"); + strings.put("6", "31"); + Map<Integer, Integer> integers = (Map<Integer, Integer>) conversionService.convert(strings, TypeDescriptor.map(Map.class, TypeDescriptor.valueOf(Integer.class), TypeDescriptor.valueOf(Integer.class))); + assertEquals(new Integer(9), integers.get(3)); + assertEquals(new Integer(31), integers.get(6)); + } + + @Test + public void convertPropertiesToString() { + Properties foo = new Properties(); + foo.setProperty("1", "BAR"); + foo.setProperty("2", "BAZ"); + String result = conversionService.convert(foo, String.class); + assertTrue(result.contains("1=BAR")); + assertTrue(result.contains("2=BAZ")); + } + + @Test + public void convertStringToProperties() { + Properties result = conversionService.convert("a=b\nc=2\nd=", Properties.class); + assertEquals(3, result.size()); + assertEquals("b", result.getProperty("a")); + assertEquals("2", result.getProperty("c")); + assertEquals("", result.getProperty("d")); + } + + @Test + public void convertStringToPropertiesWithSpaces() { + Properties result = conversionService.convert(" foo=bar\n bar=baz\n baz=boop", Properties.class); + assertEquals("bar", result.get("foo")); + assertEquals("baz", result.get("bar")); + assertEquals("boop", result.get("baz")); + } + + // generic object conversion + + @Test + public void convertObjectToStringValueOfMethodPresent() { + assertEquals("123456789", conversionService.convert(ISBN.valueOf("123456789"), String.class)); + } + + @Test + public void convertObjectToStringStringConstructorPresent() { + assertEquals("123456789", conversionService.convert(new SSN("123456789"), String.class)); + } + + @Test + public void convertObjectToStringNotSupported() { + assertFalse(conversionService.canConvert(TestEntity.class, String.class)); + } + + @Test + public void convertObjectToObjectValueOfMethod() { + assertEquals(ISBN.valueOf("123456789"), conversionService.convert("123456789", ISBN.class)); + } + + @Test + public void convertObjectToObjectConstructor() { + assertEquals(new SSN("123456789"), conversionService.convert("123456789", SSN.class)); + assertEquals("123456789", conversionService.convert(new SSN("123456789"), String.class)); + } + + @Test(expected=ConverterNotFoundException.class) + public void convertObjectToObjectNoValueOFMethodOrConstructor() { + conversionService.convert(new Long(3), SSN.class); + } + + @Test + public void convertObjectToObjectFinderMethod() { + TestEntity e = conversionService.convert(1L, TestEntity.class); + assertEquals(new Long(1), e.getId()); + } + + @Test + public void convertObjectToObjectFinderMethodWithNull() { + TestEntity e = (TestEntity) conversionService.convert(null, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(TestEntity.class)); + assertNull(e); + } + + @Test + public void convertObjectToObjectFinderMethodWithIdConversion() { + TestEntity e = conversionService.convert("1", TestEntity.class); + assertEquals(new Long(1), e.getId()); + } + + @Test + public void convertCharArrayToString() throws Exception { + String converted = conversionService.convert(new char[] { 'a', 'b', 'c' }, String.class); + assertThat(converted, equalTo("a,b,c")); + } + + @Test + public void convertStringToCharArray() throws Exception { + char[] converted = conversionService.convert("a,b,c", char[].class); + assertThat(converted, equalTo(new char[] { 'a', 'b', 'c' })); + } + + @Test + public void convertStringToCustomCharArray() throws Exception { + conversionService.addConverter(new Converter<String, char[]>() { + @Override + public char[] convert(String source) { + return source.toCharArray(); + } + }); + char[] converted = conversionService.convert("abc", char[].class); + assertThat(converted, equalTo(new char[] { 'a', 'b', 'c' })); + } + + @Test + public void multidimensionalArrayToListConversionShouldConvertEntriesCorrectly() { + String[][] grid = new String[][] { new String[] { "1", "2", "3", "4" }, new String[] { "5", "6", "7", "8" }, + new String[] { "9", "10", "11", "12" } }; + List<String[]> converted = conversionService.convert(grid, List.class); + String[][] convertedBack = conversionService.convert(converted, String[][].class); + assertArrayEquals(grid, convertedBack); + } + + + public static class TestEntity { + + private Long id; + + public TestEntity(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public static TestEntity findTestEntity(Long id) { + return new TestEntity(id); + } + } + + + private static class ListWrapper { + + private List<?> list; + + public ListWrapper(List<?> list) { + this.list = list; + } + + public List<?> getList() { + return list; + } + } + + + public Object assignableTarget; + + + private static class SSN { + + private String value; + + public SSN(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof SSN)) { + return false; + } + SSN ssn = (SSN) o; + return this.value.equals(ssn.value); + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public String toString() { + return value; + } + } + + + private static class ISBN { + + private String value; + + private ISBN(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ISBN)) { + return false; + } + ISBN isbn = (ISBN) o; + return this.value.equals(isbn.value); + } + + @Override + public int hashCode() { + return value.hashCode(); + } + + @Override + public String toString() { + return value; + } + + public static ISBN valueOf(String value) { + return new ISBN(value); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java new file mode 100644 index 00000000..8af4f860 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/convert/support/GenericConversionServiceTests.java @@ -0,0 +1,1020 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * 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 org.springframework.core.convert.support; + +import java.awt.Color; +import java.awt.SystemColor; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.junit.Test; + +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.TypeDescriptor; +import org.springframework.core.convert.converter.ConditionalConverter; +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterFactory; +import org.springframework.core.convert.converter.GenericConverter; +import org.springframework.core.io.DescriptiveResource; +import org.springframework.core.io.Resource; +import org.springframework.tests.Assume; +import org.springframework.tests.TestGroup; +import org.springframework.util.StopWatch; +import org.springframework.util.StringUtils; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * @author Keith Donald + * @author Juergen Hoeller + * @author Phillip Webb + * @author David Haraburda + */ +public class GenericConversionServiceTests { + + private GenericConversionService conversionService = new GenericConversionService(); + + + @Test + public void canConvert() { + assertFalse(conversionService.canConvert(String.class, Integer.class)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(String.class, Integer.class)); + } + + @Test + public void canConvertAssignable() { + assertTrue(conversionService.canConvert(String.class, String.class)); + assertTrue(conversionService.canConvert(Integer.class, Number.class)); + assertTrue(conversionService.canConvert(boolean.class, boolean.class)); + assertTrue(conversionService.canConvert(boolean.class, Boolean.class)); + } + + @Test + public void canConvertIllegalArgumentNullTargetType() { + try { + assertFalse(conversionService.canConvert(String.class, null)); + fail("Should have failed"); + } + catch (IllegalArgumentException ex) { + } + try { + assertFalse(conversionService.canConvert(TypeDescriptor.valueOf(String.class), null)); + fail("Should have failed"); + } + catch (IllegalArgumentException ex) { + } + } + + @Test + public void canConvertNullSourceType() { + assertTrue(conversionService.canConvert(null, Integer.class)); + assertTrue(conversionService.canConvert(null, TypeDescriptor.valueOf(Integer.class))); + } + + @Test + public void convert() { + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertEquals(new Integer(3), conversionService.convert("3", Integer.class)); + } + + @Test + public void convertNullSource() { + assertEquals(null, conversionService.convert(null, Integer.class)); + } + + @Test(expected=ConversionFailedException.class) + public void convertNullSourcePrimitiveTarget() { + assertEquals(null, conversionService.convert(null, int.class)); + } + + @Test(expected=ConversionFailedException.class) + public void convertNullSourcePrimitiveTargetTypeDescriptor() { + conversionService.convert(null, TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(int.class)); + } + + @Test(expected=IllegalArgumentException.class) + public void convertNotNullSourceNullSourceTypeDescriptor() { + conversionService.convert("3", null, TypeDescriptor.valueOf(int.class)); + } + + @Test + public void convertAssignableSource() { + assertEquals(Boolean.FALSE, conversionService.convert(false, boolean.class)); + assertEquals(Boolean.FALSE, conversionService.convert(false, Boolean.class)); + } + + @Test + public void converterNotFound() { + try { + conversionService.convert("3", Integer.class); + fail("Should have thrown an exception"); + } + catch (ConverterNotFoundException e) { + } + } + + @Test + @SuppressWarnings("rawtypes") + public void addConverterNoSourceTargetClassInfoAvailable() { + try { + conversionService.addConverter(new Converter() { + @Override + public Object convert(Object source) { + return source; + } + }); + fail("Should have failed"); + } + catch (IllegalArgumentException ex) { + } + } + + @Test + public void sourceTypeIsVoid() { + GenericConversionService conversionService = new GenericConversionService(); + assertFalse(conversionService.canConvert(void.class, String.class)); + } + + @Test + public void targetTypeIsVoid() { + GenericConversionService conversionService = new GenericConversionService(); + assertFalse(conversionService.canConvert(String.class, void.class)); + } + + @Test + public void convertNull() { + assertNull(conversionService.convert(null, Integer.class)); + } + + @Test(expected=IllegalArgumentException.class) + public void convertNullTargetClass() { + assertNull(conversionService.convert("3", (Class<?>) null)); + assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null)); + } + + @Test(expected=IllegalArgumentException.class) + public void convertNullTypeDescriptor() { + assertNull(conversionService.convert("3", TypeDescriptor.valueOf(String.class), null)); + } + + @Test(expected=IllegalArgumentException.class) + public void convertWrongSourceTypeDescriptor() { + conversionService.convert("3", TypeDescriptor.valueOf(Integer.class), TypeDescriptor.valueOf(Long.class)); + } + + @Test + public void convertWrongTypeArgument() { + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + try { + conversionService.convert("BOGUS", Integer.class); + fail("Should have failed"); + } + catch (ConversionFailedException e) { + + } + } + + @Test + public void convertSuperSourceType() { + conversionService.addConverter(new Converter<CharSequence, Integer>() { + @Override + public Integer convert(CharSequence source) { + return Integer.valueOf(source.toString()); + } + }); + Integer result = conversionService.convert("3", Integer.class); + assertEquals(new Integer(3), result); + } + + // SPR-8718 + + @Test(expected=ConverterNotFoundException.class) + public void convertSuperTarget() { + conversionService.addConverter(new ColorConverter()); + conversionService.convert("#000000", SystemColor.class); + } + + public class ColorConverter implements Converter<String, Color> { + @Override + public Color convert(String source) { if (!source.startsWith("#")) source = "#" + source; return Color.decode(source); } + } + + @Test + public void convertObjectToPrimitive() { + assertFalse(conversionService.canConvert(String.class, boolean.class)); + conversionService.addConverter(new StringToBooleanConverter()); + assertTrue(conversionService.canConvert(String.class, boolean.class)); + Boolean b = conversionService.convert("true", boolean.class); + assertEquals(Boolean.TRUE, b); + assertTrue(conversionService.canConvert(TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(boolean.class))); + b = (Boolean) conversionService.convert("true", TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(boolean.class)); + assertEquals(Boolean.TRUE, b); + } + + @Test + public void convertObjectToPrimitiveViaConverterFactory() { + assertFalse(conversionService.canConvert(String.class, int.class)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(String.class, int.class)); + Integer three = conversionService.convert("3", int.class); + assertEquals(3, three.intValue()); + } + + @Test + public void genericConverterDelegatingBackToConversionServiceConverterNotFound() { + conversionService.addConverter(new ObjectToArrayConverter(conversionService)); + assertFalse(conversionService.canConvert(String.class, Integer[].class)); + try { + conversionService.convert("3,4,5", Integer[].class); + fail("should have failed"); + } + catch (ConverterNotFoundException ex) { + } + } + + @Test + public void testListToIterableConversion() { + GenericConversionService conversionService = new GenericConversionService(); + List<Object> raw = new ArrayList<Object>(); + raw.add("one"); + raw.add("two"); + Object converted = conversionService.convert(raw, Iterable.class); + assertSame(raw, converted); + } + + @Test + public void testListToObjectConversion() { + GenericConversionService conversionService = new GenericConversionService(); + List<Object> raw = new ArrayList<Object>(); + raw.add("one"); + raw.add("two"); + Object converted = conversionService.convert(raw, Object.class); + assertSame(raw, converted); + } + + @Test + public void testMapToObjectConversion() { + GenericConversionService conversionService = new GenericConversionService(); + Map<Object, Object> raw = new HashMap<Object, Object>(); + raw.put("key", "value"); + Object converted = conversionService.convert(raw, Object.class); + assertSame(raw, converted); + } + + @Test + public void testInterfaceToString() { + GenericConversionService conversionService = new GenericConversionService(); + conversionService.addConverter(new MyBaseInterfaceConverter()); + conversionService.addConverter(new ObjectToStringConverter()); + Object converted = conversionService.convert(new MyInterfaceImplementer(), String.class); + assertEquals("RESULT", converted); + } + + @Test + public void testInterfaceArrayToStringArray() { + GenericConversionService conversionService = new GenericConversionService(); + conversionService.addConverter(new MyBaseInterfaceConverter()); + conversionService.addConverter(new ArrayToArrayConverter(conversionService)); + String[] converted = conversionService.convert(new MyInterface[] {new MyInterfaceImplementer()}, String[].class); + assertEquals("RESULT", converted[0]); + } + + @Test + public void testObjectArrayToStringArray() { + GenericConversionService conversionService = new GenericConversionService(); + conversionService.addConverter(new MyBaseInterfaceConverter()); + conversionService.addConverter(new ArrayToArrayConverter(conversionService)); + String[] converted = conversionService.convert(new MyInterfaceImplementer[] {new MyInterfaceImplementer()}, String[].class); + assertEquals("RESULT", converted[0]); + } + + @Test + public void testStringArrayToResourceArray() { + GenericConversionService conversionService = new DefaultConversionService(); + conversionService.addConverter(new MyStringArrayToResourceArrayConverter()); + Resource[] converted = conversionService.convert(new String[] {"x1", "z3"}, Resource[].class); + assertEquals(2, converted.length); + assertEquals("1", converted[0].getDescription()); + assertEquals("3", converted[1].getDescription()); + } + + @Test + public void testStringArrayToIntegerArray() { + GenericConversionService conversionService = new DefaultConversionService(); + conversionService.addConverter(new MyStringArrayToIntegerArrayConverter()); + Integer[] converted = conversionService.convert(new String[] {"x1", "z3"}, Integer[].class); + assertEquals(2, converted.length); + assertEquals(1, converted[0].intValue()); + assertEquals(3, converted[1].intValue()); + } + + @Test + public void testStringToIntegerArray() { + GenericConversionService conversionService = new DefaultConversionService(); + conversionService.addConverter(new MyStringToIntegerArrayConverter()); + Integer[] converted = conversionService.convert("x1,z3", Integer[].class); + assertEquals(2, converted.length); + assertEquals(1, converted[0].intValue()); + assertEquals(3, converted[1].intValue()); + } + + @Test + public void testWildcardMap() throws Exception { + GenericConversionService conversionService = new DefaultConversionService(); + Map<String, String> input = new LinkedHashMap<String, String>(); + input.put("key", "value"); + Object converted = conversionService.convert(input, TypeDescriptor.forObject(input), new TypeDescriptor(getClass().getField("wildcardMap"))); + assertEquals(input, converted); + } + + @Test + public void testListOfList() { + GenericConversionService service = new DefaultConversionService(); + List<String> list1 = Arrays.asList("Foo", "Bar"); + List<String> list2 = Arrays.asList("Baz", "Boop"); + List<List<String>> list = Arrays.asList(list1, list2); + String result = service.convert(list, String.class); + assertNotNull(result); + assertEquals("Foo,Bar,Baz,Boop", result); + } + + @Test + public void testStringToString() { + GenericConversionService service = new DefaultConversionService(); + String value = "myValue"; + String result = service.convert(value, String.class); + assertSame(value, result); + } + + @Test + public void testStringToObject() { + GenericConversionService service = new DefaultConversionService(); + String value = "myValue"; + Object result = service.convert(value, Object.class); + assertSame(value, result); + } + + @Test + public void testIgnoreCopyConstructor() { + GenericConversionService service = new DefaultConversionService(); + WithCopyConstructor value = new WithCopyConstructor(); + Object result = service.convert(value, WithCopyConstructor.class); + assertSame(value, result); + } + + @Test + public void testConvertUUID() { + GenericConversionService service = new DefaultConversionService(); + UUID uuid = UUID.randomUUID(); + String convertToString = service.convert(uuid, String.class); + UUID convertToUUID = service.convert(convertToString, UUID.class); + assertEquals(uuid, convertToUUID); + } + + @Test + public void testPerformance1() { + Assume.group(TestGroup.PERFORMANCE); + GenericConversionService conversionService = new DefaultConversionService(); + StopWatch watch = new StopWatch("integer->string conversionPerformance"); + watch.start("convert 4,000,000 with conversion service"); + for (int i = 0; i < 4000000; i++) { + conversionService.convert(3, String.class); + } + watch.stop(); + watch.start("convert 4,000,000 manually"); + for (int i = 0; i < 4000000; i++) { + new Integer(3).toString(); + } + watch.stop(); + System.out.println(watch.prettyPrint()); + } + + @Test + public void testPerformance2() throws Exception { + Assume.group(TestGroup.PERFORMANCE); + GenericConversionService conversionService = new DefaultConversionService(); + StopWatch watch = new StopWatch("list<string> -> list<integer> conversionPerformance"); + watch.start("convert 4,000,000 with conversion service"); + List<String> source = new LinkedList<String>(); + source.add("1"); + source.add("2"); + source.add("3"); + TypeDescriptor td = new TypeDescriptor(getClass().getField("list")); + for (int i = 0; i < 1000000; i++) { + conversionService.convert(source, TypeDescriptor.forObject(source), td); + } + watch.stop(); + watch.start("convert 4,000,000 manually"); + for (int i = 0; i < 4000000; i++) { + List<Integer> target = new ArrayList<Integer>(source.size()); + for (String element : source) { + target.add(Integer.valueOf(element)); + } + } + watch.stop(); + System.out.println(watch.prettyPrint()); + } + + public static List<Integer> list; + + @Test + public void testPerformance3() throws Exception { + Assume.group(TestGroup.PERFORMANCE); + GenericConversionService conversionService = new DefaultConversionService(); + StopWatch watch = new StopWatch("map<string, string> -> map<string, integer> conversionPerformance"); + watch.start("convert 4,000,000 with conversion service"); + Map<String, String> source = new HashMap<String, String>(); + source.put("1", "1"); + source.put("2", "2"); + source.put("3", "3"); + TypeDescriptor td = new TypeDescriptor(getClass().getField("map")); + for (int i = 0; i < 1000000; i++) { + conversionService.convert(source, TypeDescriptor.forObject(source), td); + } + watch.stop(); + watch.start("convert 4,000,000 manually"); + for (int i = 0; i < 4000000; i++) { + Map<String, Integer> target = new HashMap<String, Integer>(source.size()); + for (Map.Entry<String, String> entry : source.entrySet()) { + target.put(entry.getKey(), Integer.valueOf(entry.getValue())); + } + } + watch.stop(); + System.out.println(watch.prettyPrint()); + } + + public static Map<String, Integer> map; + + @Test + public void emptyListToArray() { + conversionService.addConverter(new CollectionToArrayConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + List<String> list = new ArrayList<String>(); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = TypeDescriptor.valueOf(String[].class); + assertTrue(conversionService.canConvert(sourceType, targetType)); + assertEquals(0, ((String[])conversionService.convert(list, sourceType, targetType)).length); + } + + @Test + public void emptyListToObject() { + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + List<String> list = new ArrayList<String>(); + TypeDescriptor sourceType = TypeDescriptor.forObject(list); + TypeDescriptor targetType = TypeDescriptor.valueOf(Integer.class); + assertTrue(conversionService.canConvert(sourceType, targetType)); + assertNull(conversionService.convert(list, sourceType, targetType)); + } + + private interface MyBaseInterface { + + } + + + private interface MyInterface extends MyBaseInterface { + + } + + + private static class MyInterfaceImplementer implements MyInterface { + + } + + + private static class MyBaseInterfaceConverter implements Converter<MyBaseInterface, String> { + + @Override + public String convert(MyBaseInterface source) { + return "RESULT"; + } + } + + + private static class MyStringArrayToResourceArrayConverter implements Converter<String[], Resource[]> { + + @Override + public Resource[] convert(String[] source) { + Resource[] result = new Resource[source.length]; + for (int i = 0; i < source.length; i++) { + result[i] = new DescriptiveResource(source[i].substring(1)); + } + return result; + } + } + + + private static class MyStringArrayToIntegerArrayConverter implements Converter<String[], Integer[]> { + + @Override + public Integer[] convert(String[] source) { + Integer[] result = new Integer[source.length]; + for (int i = 0; i < source.length; i++) { + result[i] = Integer.parseInt(source[i].substring(1)); + } + return result; + } + } + + + private static class MyStringToIntegerArrayConverter implements Converter<String, Integer[]> { + + @Override + public Integer[] convert(String source) { + String[] srcArray = StringUtils.commaDelimitedListToStringArray(source); + Integer[] result = new Integer[srcArray.length]; + for (int i = 0; i < srcArray.length; i++) { + result[i] = Integer.parseInt(srcArray[i].substring(1)); + } + return result; + } + } + + + public static class WithCopyConstructor { + + public WithCopyConstructor() { + } + + public WithCopyConstructor(WithCopyConstructor value) { + } + } + + + public static Map<String, ?> wildcardMap; + + @Test + public void stringToArrayCanConvert() { + conversionService.addConverter(new StringToArrayConverter(conversionService)); + assertFalse(conversionService.canConvert(String.class, Integer[].class)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(String.class, Integer[].class)); + } + + @Test + public void stringToCollectionCanConvert() throws Exception { + conversionService.addConverter(new StringToCollectionConverter(conversionService)); + assertTrue(conversionService.canConvert(String.class, Collection.class)); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("stringToCollection")); + assertFalse(conversionService.canConvert(TypeDescriptor.valueOf(String.class), targetType)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(TypeDescriptor.valueOf(String.class), targetType)); + } + + public Collection<Integer> stringToCollection; + + @Test + public void testConvertiblePairsInSet() { + Set<GenericConverter.ConvertiblePair> set = new HashSet<GenericConverter.ConvertiblePair>(); + set.add(new GenericConverter.ConvertiblePair(Number.class, String.class)); + assert set.contains(new GenericConverter.ConvertiblePair(Number.class, String.class)); + } + + @Test + public void testConvertiblePairEqualsAndHash() { + GenericConverter.ConvertiblePair pair = new GenericConverter.ConvertiblePair(Number.class, String.class); + GenericConverter.ConvertiblePair pairEqual = new GenericConverter.ConvertiblePair(Number.class, String.class); + assertEquals(pair, pairEqual); + assertEquals(pair.hashCode(), pairEqual.hashCode()); + } + + @Test + public void testConvertiblePairDifferentEqualsAndHash() { + GenericConverter.ConvertiblePair pair = new GenericConverter.ConvertiblePair(Number.class, String.class); + GenericConverter.ConvertiblePair pairOpposite = new GenericConverter.ConvertiblePair(String.class, Number.class); + assertFalse(pair.equals(pairOpposite)); + assertFalse(pair.hashCode() == pairOpposite.hashCode()); + } + + @Test + public void convertPrimitiveArray() { + GenericConversionService conversionService = new DefaultConversionService(); + byte[] byteArray = new byte[] { 1, 2, 3 }; + Byte[] converted = conversionService.convert(byteArray, Byte[].class); + assertTrue(Arrays.equals(converted, new Byte[] {1, 2, 3})); + } + + @Test + public void canConvertIllegalArgumentNullTargetTypeFromClass() { + try { + conversionService.canConvert(String.class, null); + fail("Did not thow IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + } + } + + @Test + public void canConvertIllegalArgumentNullTargetTypeFromTypeDescriptor() { + try { + conversionService.canConvert(TypeDescriptor.valueOf(String.class), null); + fail("Did not thow IllegalArgumentException"); + } + catch(IllegalArgumentException ex) { + } + } + + @Test + @SuppressWarnings({ "rawtypes" }) + public void convertHashMapValuesToList() { + GenericConversionService conversionService = new DefaultConversionService(); + Map<String, Integer> hashMap = new LinkedHashMap<String, Integer>(); + hashMap.put("1", 1); + hashMap.put("2", 2); + List converted = conversionService.convert(hashMap.values(), List.class); + assertEquals(Arrays.asList(1, 2), converted); + } + + @Test + public void removeConvertible() { + conversionService.addConverter(new ColorConverter()); + assertTrue(conversionService.canConvert(String.class, Color.class)); + conversionService.removeConvertible(String.class, Color.class); + assertFalse(conversionService.canConvert(String.class, Color.class)); + } + + @Test + public void conditionalConverter() { + GenericConversionService conversionService = new GenericConversionService(); + MyConditionalConverter converter = new MyConditionalConverter(); + conversionService.addConverter(new ColorConverter()); + conversionService.addConverter(converter); + assertEquals(Color.BLACK, conversionService.convert("#000000", Color.class)); + assertTrue(converter.getMatchAttempts() > 0); + } + + @Test + public void conditionalConverterFactory() { + GenericConversionService conversionService = new GenericConversionService(); + MyConditionalConverterFactory converter = new MyConditionalConverterFactory(); + conversionService.addConverter(new ColorConverter()); + conversionService.addConverterFactory(converter); + assertEquals(Color.BLACK, conversionService.convert("#000000", Color.class)); + assertTrue(converter.getMatchAttempts() > 0); + assertTrue(converter.getNestedMatchAttempts() > 0); + } + + @Test + public void shouldNotSupportNullConvertibleTypesFromNonConditionalGenericConverter() { + GenericConversionService conversionService = new GenericConversionService(); + GenericConverter converter = new GenericConverter() { + @Override + public Set<ConvertiblePair> getConvertibleTypes() { + return null; + } + @Override + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + return null; + } + }; + try { + conversionService.addConverter(converter); + fail("Did not throw"); + } + catch (IllegalStateException ex) { + assertEquals("Only conditional converters may return null convertible types", ex.getMessage()); + } + } + + @Test + public void conditionalConversionForAllTypes() { + GenericConversionService conversionService = new GenericConversionService(); + MyConditionalGenericConverter converter = new MyConditionalGenericConverter(); + conversionService.addConverter(converter); + assertEquals((Integer) 3, conversionService.convert(3, Integer.class)); + assertThat(converter.getSourceTypes().size(), greaterThan(2)); + Iterator<TypeDescriptor> iterator = converter.getSourceTypes().iterator(); + while(iterator.hasNext()) { + assertEquals(Integer.class, iterator.next().getType()); + } + } + + @Test + public void convertOptimizeArray() { + // SPR-9566 + GenericConversionService conversionService = new DefaultConversionService(); + byte[] byteArray = new byte[] { 1, 2, 3 }; + byte[] converted = conversionService.convert(byteArray, byte[].class); + assertSame(byteArray, converted); + } + + @Test + public void convertCannotOptimizeArray() { + GenericConversionService conversionService = new GenericConversionService(); + conversionService.addConverter(new Converter<Byte, Byte>() { + @Override + public Byte convert(Byte source) { + return (byte) (source + 1); + } + }); + DefaultConversionService.addDefaultConverters(conversionService); + byte[] byteArray = new byte[] { 1, 2, 3 }; + byte[] converted = conversionService.convert(byteArray, byte[].class); + assertNotSame(byteArray, converted); + assertTrue(Arrays.equals(new byte[] {2, 3, 4}, converted)); + } + + @Test + public void testEnumToStringConversion() { + conversionService.addConverter(new EnumToStringConverter(conversionService)); + String result = conversionService.convert(MyEnum.A, String.class); + assertEquals("A", result); + } + + @Test + public void testSubclassOfEnumToString() throws Exception { + conversionService.addConverter(new EnumToStringConverter(conversionService)); + String result = conversionService.convert(EnumWithSubclass.FIRST, String.class); + assertEquals("FIRST", result); + } + + @Test + public void testEnumWithInterfaceToStringConversion() { + // SPR-9692 + conversionService.addConverter(new EnumToStringConverter(conversionService)); + conversionService.addConverter(new MyEnumInterfaceToStringConverter<MyEnum>()); + String result = conversionService.convert(MyEnum.A, String.class); + assertEquals("1", result); + } + + @Test + public void convertNullAnnotatedStringToString() throws Exception { + DefaultConversionService.addDefaultConverters(conversionService); + String source = null; + TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("annotatedString")); + TypeDescriptor targetType = TypeDescriptor.valueOf(String.class); + conversionService.convert(source, sourceType, targetType); + } + + @Test + public void multipleCollectionTypesFromSameSourceType() throws Exception { + conversionService.addConverter(new MyStringToRawCollectionConverter()); + conversionService.addConverter(new MyStringToGenericCollectionConverter()); + conversionService.addConverter(new MyStringToStringCollectionConverter()); + conversionService.addConverter(new MyStringToIntegerCollectionConverter()); + + assertEquals(Collections.singleton(4), // should be "testX" from MyStringToStringCollectionConverter, ideally + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection")))); + assertEquals(Collections.singleton(4), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection")))); + assertEquals(Collections.singleton(4), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection")))); + assertEquals(Collections.singleton(4), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection")))); + assertEquals(Collections.singleton(4), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection")))); + assertEquals(Collections.singleton(4), // should be "testX" from MyStringToStringCollectionConverter, ideally + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection")))); + } + + @Test + public void adaptedCollectionTypesFromSameSourceType() throws Exception { + conversionService.addConverter(new MyStringToStringCollectionConverter()); + + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection")))); + + // The following is unpleasant but simply a consequence of the raw type matching algorithm in Spring 3.x + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection")))); + } + + @Test + public void genericCollectionAsSource() throws Exception { + conversionService.addConverter(new MyStringToGenericCollectionConverter()); + + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection")))); + + // The following is unpleasant but a consequence of the generic collection converter above... + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection")))); + } + + @Test + public void rawCollectionAsSource() throws Exception { + conversionService.addConverter(new MyStringToRawCollectionConverter()); + + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("stringCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("genericCollection")))); + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("rawCollection")))); + + // The following is unpleasant but a consequence of the raw collection converter above... + assertEquals(Collections.singleton("testX"), + conversionService.convert("test", TypeDescriptor.valueOf(String.class), new TypeDescriptor(getClass().getField("integerCollection")))); + } + + + @ExampleAnnotation + public String annotatedString; + + + @Retention(RetentionPolicy.RUNTIME) + public static @interface ExampleAnnotation { + } + + + private static class MyConditionalConverter implements Converter<String, Color>, ConditionalConverter { + + private int matchAttempts = 0; + + @Override + public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { + matchAttempts++; + return false; + } + + @Override + public Color convert(String source) { + throw new IllegalStateException(); + } + + public int getMatchAttempts() { + return matchAttempts; + } + } + + + private static class MyConditionalGenericConverter implements GenericConverter, ConditionalConverter { + + private List<TypeDescriptor> sourceTypes = new ArrayList<TypeDescriptor>(); + + @Override + public Set<ConvertiblePair> getConvertibleTypes() { + return null; + } + + @Override + public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { + sourceTypes.add(sourceType); + return false; + } + + @Override + public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { + return null; + } + + public List<TypeDescriptor> getSourceTypes() { + return sourceTypes; + } + } + + + private static class MyConditionalConverterFactory implements ConverterFactory<String, Color>, ConditionalConverter { + + private MyConditionalConverter converter = new MyConditionalConverter(); + + private int matchAttempts = 0; + + @Override + public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) { + matchAttempts++; + return true; + } + + @Override + @SuppressWarnings("unchecked") + public <T extends Color> Converter<String, T> getConverter(Class<T> targetType) { + return (Converter<String, T>) converter; + } + + public int getMatchAttempts() { + return matchAttempts; + } + + public int getNestedMatchAttempts() { + return converter.getMatchAttempts(); + } + } + + + interface MyEnumInterface { + + String getCode(); + } + + + public static enum MyEnum implements MyEnumInterface { + + A { + @Override + public String getCode() { + return "1"; + } + } + } + + + public enum EnumWithSubclass { + + FIRST { + @Override + public String toString() { + return "1st"; + } + } + } + + + public static class MyStringToRawCollectionConverter implements Converter<String, Collection> { + + @Override + public Collection convert(String source) { + return Collections.singleton(source + "X"); + } + } + + + public static class MyStringToGenericCollectionConverter implements Converter<String, Collection<?>> { + + @Override + public Collection<?> convert(String source) { + return Collections.singleton(source + "X"); + } + } + + + private static class MyEnumInterfaceToStringConverter<T extends MyEnumInterface> implements Converter<T, String> { + + @Override + public String convert(T source) { + return source.getCode(); + } + } + + + public static class MyStringToStringCollectionConverter implements Converter<String, Collection<String>> { + + @Override + public Collection<String> convert(String source) { + return Collections.singleton(source + "X"); + } + } + + + public static class MyStringToIntegerCollectionConverter implements Converter<String, Collection<Integer>> { + + @Override + public Collection<Integer> convert(String source) { + return Collections.singleton(source.length()); + } + } + + + public Collection rawCollection; + + public Collection<?> genericCollection; + + public Collection<String> stringCollection; + + public Collection<Integer> integerCollection; + +} diff --git a/spring-core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java b/spring-core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java new file mode 100644 index 00000000..9f3ca159 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/convert/support/MapToMapConverterTests.java @@ -0,0 +1,227 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.convert.support; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConverterNotFoundException; +import org.springframework.core.convert.TypeDescriptor; + +import static org.junit.Assert.*; + +public class MapToMapConverterTests { + + private GenericConversionService conversionService = new GenericConversionService(); + + @Before + public void setUp() { + conversionService.addConverter(new MapToMapConverter(conversionService)); + } + + @Test + public void scalarMap() throws Exception { + Map<String, String> map = new HashMap<String, String>(); + map.put("1", "9"); + map.put("2", "37"); + TypeDescriptor sourceType = TypeDescriptor.forObject(map); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + try { + conversionService.convert(map, sourceType, targetType); + } catch (ConversionFailedException e) { + assertTrue(e.getCause() instanceof ConverterNotFoundException); + } + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map<Integer, Integer> result = (Map<Integer, Integer>) conversionService.convert(map, sourceType, targetType); + assertFalse(map.equals(result)); + assertEquals((Integer) 9, result.get(1)); + assertEquals((Integer) 37, result.get(2)); + } + + public Map<Integer, Integer> scalarMapTarget; + + @Test + public void scalarMapNotGenericTarget() throws Exception { + Map<String, String> map = new HashMap<String, String>(); + map.put("1", "9"); + map.put("2", "37"); + assertTrue(conversionService.canConvert(Map.class, Map.class)); + assertSame(map, conversionService.convert(map, Map.class)); + } + + @Test + public void scalarMapNotGenericSourceField() throws Exception { + Map<String, String> map = new HashMap<String, String>(); + map.put("1", "9"); + map.put("2", "37"); + TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("notGenericMapSource")); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("scalarMapTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + try { + conversionService.convert(map, sourceType, targetType); + } catch (ConversionFailedException e) { + assertTrue(e.getCause() instanceof ConverterNotFoundException); + } + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map<Integer, Integer> result = (Map<Integer, Integer>) conversionService.convert(map, sourceType, targetType); + assertFalse(map.equals(result)); + assertEquals((Integer) 9, result.get(1)); + assertEquals((Integer) 37, result.get(2)); + } + + public Map notGenericMapSource; + + @Test + public void collectionMap() throws Exception { + Map<String, List<String>> map = new HashMap<String, List<String>>(); + map.put("1", Arrays.asList("9", "12")); + map.put("2", Arrays.asList("37", "23")); + TypeDescriptor sourceType = TypeDescriptor.forObject(map); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + try { + conversionService.convert(map, sourceType, targetType); + } catch (ConversionFailedException e) { + assertTrue(e.getCause() instanceof ConverterNotFoundException); + } + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map<Integer, List<Integer>> result = (Map<Integer, List<Integer>>) conversionService.convert(map, sourceType, targetType); + assertFalse(map.equals(result)); + assertEquals(Arrays.asList(9, 12), result.get(1)); + assertEquals(Arrays.asList(37, 23), result.get(2)); + } + + public Map<Integer, List<Integer>> collectionMapTarget; + + @Test + public void collectionMapSourceTarget() throws Exception { + Map<String, List<String>> map = new HashMap<String, List<String>>(); + map.put("1", Arrays.asList("9", "12")); + map.put("2", Arrays.asList("37", "23")); + TypeDescriptor sourceType = new TypeDescriptor(getClass().getField("sourceCollectionMapTarget")); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("collectionMapTarget")); + assertFalse(conversionService.canConvert(sourceType, targetType)); + try { + conversionService.convert(map, sourceType, targetType); + fail("Should have failed"); + } catch (ConverterNotFoundException e) { + + } + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverterFactory(new StringToNumberConverterFactory()); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map<Integer, List<Integer>> result = (Map<Integer, List<Integer>>) conversionService.convert(map, sourceType, targetType); + assertFalse(map.equals(result)); + assertEquals(Arrays.asList(9, 12), result.get(1)); + assertEquals(Arrays.asList(37, 23), result.get(2)); + } + + public Map<String, List<String>> sourceCollectionMapTarget; + + @Test + public void collectionMapNotGenericTarget() throws Exception { + Map<String, List<String>> map = new HashMap<String, List<String>>(); + map.put("1", Arrays.asList("9", "12")); + map.put("2", Arrays.asList("37", "23")); + assertTrue(conversionService.canConvert(Map.class, Map.class)); + assertSame(map, conversionService.convert(map, Map.class)); + } + + @Test + public void collectionMapNotGenericTargetCollectionToObjectInteraction() throws Exception { + Map<String, List<String>> map = new HashMap<String, List<String>>(); + map.put("1", Arrays.asList("9", "12")); + map.put("2", Arrays.asList("37", "23")); + conversionService.addConverter(new CollectionToCollectionConverter(conversionService)); + conversionService.addConverter(new CollectionToObjectConverter(conversionService)); + assertTrue(conversionService.canConvert(Map.class, Map.class)); + assertSame(map, conversionService.convert(map, Map.class)); + } + + @Test + public void emptyMap() throws Exception { + Map<String, String> map = new HashMap<String, String>(); + TypeDescriptor sourceType = TypeDescriptor.forObject(map); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyMapTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + assertSame(map, conversionService.convert(map, sourceType, targetType)); + } + + public Map<String, String> emptyMapTarget; + + @Test + public void emptyMapNoTargetGenericInfo() throws Exception { + Map<String, String> map = new HashMap<String, String>(); + assertTrue(conversionService.canConvert(Map.class, Map.class)); + assertSame(map, conversionService.convert(map, Map.class)); + } + + @Test + public void emptyMapDifferentTargetImplType() throws Exception { + Map<String, String> map = new HashMap<String, String>(); + TypeDescriptor sourceType = TypeDescriptor.forObject(map); + TypeDescriptor targetType = new TypeDescriptor(getClass().getField("emptyMapDifferentTarget")); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + LinkedHashMap<String, String> result = (LinkedHashMap<String, String>) conversionService.convert(map, sourceType, targetType); + assertEquals(map, result); + assertEquals(LinkedHashMap.class, result.getClass()); + } + + public LinkedHashMap<String, String> emptyMapDifferentTarget; + + @Test + public void noDefaultConstructorCopyNotRequired() throws Exception { + // SPR-9284 + NoDefaultConstructorMap<String, Integer> map = new NoDefaultConstructorMap<String,Integer>( + Collections.<String, Integer> singletonMap("1", 1)); + TypeDescriptor sourceType = TypeDescriptor.map(NoDefaultConstructorMap.class, + TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class)); + TypeDescriptor targetType = TypeDescriptor.map(NoDefaultConstructorMap.class, + TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(Integer.class)); + assertTrue(conversionService.canConvert(sourceType, targetType)); + @SuppressWarnings("unchecked") + Map<String, Integer> result = (Map<String, Integer>) conversionService.convert(map, sourceType, targetType); + assertEquals(map, result); + assertEquals(NoDefaultConstructorMap.class, result.getClass()); + } + + @SuppressWarnings("serial") + public static class NoDefaultConstructorMap<K, V> extends HashMap<K, V> { + public NoDefaultConstructorMap(Map<? extends K, ? extends V> m) { + super(m); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/enums/LabeledEnumTests.java b/spring-core/src/test/java/org/springframework/core/enums/LabeledEnumTests.java new file mode 100644 index 00000000..de0fccf4 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/enums/LabeledEnumTests.java @@ -0,0 +1,192 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.enums; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; + +import junit.framework.TestCase; + +/** + * @author Keith Donald + * @author Juergen Hoeller + * @author Sam Brannen + */ +@Deprecated +public class LabeledEnumTests extends TestCase { + + private byte[] serializeObject(final Object obj) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(obj); + oos.close(); + return baos.toByteArray(); + } + + private Object deserializeObject(final byte[] serializedBytes) throws IOException, ClassNotFoundException { + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serializedBytes)); + Object obj = ois.readObject(); + ois.close(); + return obj; + } + + private Object serializeAndDeserializeObject(Object obj) throws IOException, ClassNotFoundException { + return deserializeObject(serializeObject(obj)); + } + + public void testCodeFound() { + Dog golden = (Dog) StaticLabeledEnumResolver.instance().getLabeledEnumByCode(Dog.class, new Short((short) 11)); + Dog borderCollie = (Dog) StaticLabeledEnumResolver.instance().getLabeledEnumByCode(Dog.class, + new Short((short) 13)); + assertSame(golden, Dog.GOLDEN_RETRIEVER); + assertSame(borderCollie, Dog.BORDER_COLLIE); + } + + public void testCodeFoundForAbstractEnums() { + ValuedEnum one = (ValuedEnum) StaticLabeledEnumResolver.instance().getLabeledEnumByCode(ValuedEnum.class, + new Short((short) 1)); + ValuedEnum two = (ValuedEnum) StaticLabeledEnumResolver.instance().getLabeledEnumByCode(ValuedEnum.class, + new Short((short) 2)); + assertSame(one, ValuedEnum.ONE); + assertSame(two, ValuedEnum.TWO); + } + + public void testDeserializationOfInnerClassEnums() throws Exception { + assertSame(serializeAndDeserializeObject(Other.THING1), Other.THING1); + } + + public void testDeserializationOfStandAloneEnums() throws Exception { + assertSame(serializeAndDeserializeObject(StandAloneStaticLabeledEnum.ENUM1), + StandAloneStaticLabeledEnum.ENUM1); + } + + public void testLabelFound() { + Dog golden = (Dog) StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(Dog.class, "Golden Retriever"); + Dog borderCollie = (Dog) StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(Dog.class, "Border Collie"); + assertSame(golden, Dog.GOLDEN_RETRIEVER); + assertSame(borderCollie, Dog.BORDER_COLLIE); + } + + public void testLabelFoundForStandAloneEnum() { + StandAloneStaticLabeledEnum enum1 = (StandAloneStaticLabeledEnum) + StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(StandAloneStaticLabeledEnum.class, "Enum1"); + StandAloneStaticLabeledEnum enum2 = (StandAloneStaticLabeledEnum) + StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(StandAloneStaticLabeledEnum.class, "Enum2"); + assertSame(enum1, StandAloneStaticLabeledEnum.ENUM1); + assertSame(enum2, StandAloneStaticLabeledEnum.ENUM2); + } + + public void testLabelFoundForAbstractEnums() { + ValuedEnum one = (ValuedEnum) + StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(ValuedEnum.class, "one"); + ValuedEnum two = (ValuedEnum) + StaticLabeledEnumResolver.instance().getLabeledEnumByLabel(ValuedEnum.class, "two"); + assertSame(one, ValuedEnum.ONE); + assertSame(two, ValuedEnum.TWO); + } + + public void testDoesNotMatchWrongClass() { + try { + StaticLabeledEnumResolver.instance().getLabeledEnumByCode(Dog.class, + new Short((short) 1)); + fail("Should have failed"); + } + catch (IllegalArgumentException e) { + // expected + } + } + + public void testEquals() { + assertEquals("Code equality means equals", Dog.GOLDEN_RETRIEVER, new Dog(11, "Golden Retriever")); + assertFalse("Code inequality means notEquals", Dog.GOLDEN_RETRIEVER.equals(new Dog(12, "Golden Retriever"))); + } + + + @SuppressWarnings({ "serial", "unused" }) + private static class Other extends StaticLabeledEnum { + + public static final Other THING1 = new Other(1, "Thing1"); + + public static final Other THING2 = new Other(2, "Thing2"); + + + private Other(int code, String name) { + super(code, name); + } + } + + + @SuppressWarnings("serial") + private static class Dog extends StaticLabeledEnum { + + public static final Dog GOLDEN_RETRIEVER = new Dog(11, null) { + + @Override + public String getLabel() { + return "Golden Retriever"; + } + + // Overriding getType() is no longer necessary as of Spring 2.5; + // however, this is left here to provide valid testing for + // backwards compatibility. + @Override + public Class getType() { + return Dog.class; + } + }; + + public static final Dog BORDER_COLLIE = new Dog(13, "Border Collie"); + public static final Dog WHIPPET = new Dog(14, "Whippet"); + + // Ignore this + public static final Other THING1 = Other.THING1; + + + private Dog(int code, String name) { + super(code, name); + } + } + + + @SuppressWarnings("serial") + private static abstract class ValuedEnum extends StaticLabeledEnum { + + public static final ValuedEnum ONE = new ValuedEnum(1, "one") { + @Override + public int getValue() { + return 1; + } + }; + + public static final ValuedEnum TWO = new ValuedEnum(2, "two") { + @Override + public int getValue() { + return 2; + } + }; + + private ValuedEnum(int code, String name) { + super(code, name); + } + + public abstract int getValue(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/enums/StandAloneStaticLabeledEnum.java b/spring-core/src/test/java/org/springframework/core/enums/StandAloneStaticLabeledEnum.java new file mode 100644 index 00000000..078f3986 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/enums/StandAloneStaticLabeledEnum.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * 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 org.springframework.core.enums; + +/** + * Stand-alone static enum for use in {@link LabeledEnumTests}. + * + * @author Sam Brannen + * @since 2.5 + */ +public class StandAloneStaticLabeledEnum extends StaticLabeledEnum { + + private static final long serialVersionUID = 1L; + + public static final StandAloneStaticLabeledEnum ENUM1 = new StandAloneStaticLabeledEnum(1, "Enum1"); + public static final StandAloneStaticLabeledEnum ENUM2 = new StandAloneStaticLabeledEnum(2, "Enum2"); + + + private StandAloneStaticLabeledEnum(int code, String name) { + super(code, name); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java b/spring-core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java new file mode 100644 index 00000000..0f8a6c36 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/CustomEnvironmentTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +/** + * Unit tests covering the extensibility of {@link AbstractEnvironment}. + * + * @author Chris Beams + * @since 3.1 + */ +public class CustomEnvironmentTests { + + // -- tests relating to customizing reserved default profiles ---------------------- + + @Test + public void control() { + Environment env = new AbstractEnvironment() { }; + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(true)); + } + + @Test + public void withNoReservedDefaultProfile() { + class CustomEnvironment extends AbstractEnvironment { + @Override + protected Set<String> getReservedDefaultProfiles() { + return Collections.emptySet(); + } + } + + Environment env = new CustomEnvironment(); + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(false)); + } + + @Test + public void withSingleCustomReservedDefaultProfile() { + class CustomEnvironment extends AbstractEnvironment { + @Override + protected Set<String> getReservedDefaultProfiles() { + return Collections.singleton("rd1"); + } + } + + Environment env = new CustomEnvironment(); + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(false)); + assertThat(env.acceptsProfiles("rd1"), is(true)); + } + + @Test + public void withMultiCustomReservedDefaultProfile() { + class CustomEnvironment extends AbstractEnvironment { + @Override + @SuppressWarnings("serial") + protected Set<String> getReservedDefaultProfiles() { + return new HashSet<String>() {{ add("rd1"); add("rd2"); }}; + } + } + + ConfigurableEnvironment env = new CustomEnvironment(); + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(false)); + assertThat(env.acceptsProfiles("rd1", "rd2"), is(true)); + + // finally, issue additional assertions to cover all combinations of calling these + // methods, however unlikely. + env.setDefaultProfiles("d1"); + assertThat(env.acceptsProfiles("rd1", "rd2"), is(false)); + assertThat(env.acceptsProfiles("d1"), is(true)); + + env.setActiveProfiles("a1", "a2"); + assertThat(env.acceptsProfiles("d1"), is(false)); + assertThat(env.acceptsProfiles("a1", "a2"), is(true)); + + env.setActiveProfiles(); + assertThat(env.acceptsProfiles("d1"), is(true)); + assertThat(env.acceptsProfiles("a1", "a2"), is(false)); + + env.setDefaultProfiles(); + assertThat(env.acceptsProfiles(AbstractEnvironment.RESERVED_DEFAULT_PROFILE_NAME), is(false)); + assertThat(env.acceptsProfiles("rd1", "rd2"), is(false)); + assertThat(env.acceptsProfiles("d1"), is(false)); + assertThat(env.acceptsProfiles("a1", "a2"), is(false)); + } + + + // -- tests relating to customizing property sources ------------------------------- +} diff --git a/spring-core/src/test/java/org/springframework/core/env/DummyEnvironment.java b/spring-core/src/test/java/org/springframework/core/env/DummyEnvironment.java new file mode 100644 index 00000000..88d9347d --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/DummyEnvironment.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.env; + +public class DummyEnvironment implements Environment { + + public boolean containsProperty(String key) { + return false; + } + + public String getProperty(String key) { + return null; + } + + public String getProperty(String key, String defaultValue) { + return null; + } + + public <T> T getProperty(String key, Class<T> targetType) { + return null; + } + + public <T> T getProperty(String key, Class<T> targetType, T defaultValue) { + return null; + } + + public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) { + return null; + } + + public String getRequiredProperty(String key) throws IllegalStateException { + return null; + } + + public <T> T getRequiredProperty(String key, Class<T> targetType) + throws IllegalStateException { + return null; + } + + public String resolvePlaceholders(String text) { + return null; + } + + public String resolveRequiredPlaceholders(String text) + throws IllegalArgumentException { + return null; + } + + public String[] getActiveProfiles() { + return null; + } + + public String[] getDefaultProfiles() { + return null; + } + + public boolean acceptsProfiles(String... profiles) { + return false; + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/env/JOptCommandLinePropertySourceTests.java b/spring-core/src/test/java/org/springframework/core/env/JOptCommandLinePropertySourceTests.java new file mode 100644 index 00000000..6eced35d --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/JOptCommandLinePropertySourceTests.java @@ -0,0 +1,165 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.Arrays; + +import joptsimple.OptionParser; +import joptsimple.OptionSet; + +import org.junit.Test; + +/** + * Unit tests for {@link JOptCommandLinePropertySource}. + * + * @author Chris Beams + * @since 3.1 + */ +public class JOptCommandLinePropertySourceTests { + + @Test + public void withRequiredArg_andArgIsPresent() { + OptionParser parser = new OptionParser(); + parser.accepts("foo").withRequiredArg(); + OptionSet options = parser.parse("--foo=bar"); + + PropertySource<?> ps = new JOptCommandLinePropertySource(options); + assertThat((String)ps.getProperty("foo"), equalTo("bar")); + } + + @Test + public void withOptionalArg_andArgIsMissing() { + OptionParser parser = new OptionParser(); + parser.accepts("foo").withOptionalArg(); + OptionSet options = parser.parse("--foo"); + + PropertySource<?> ps = new JOptCommandLinePropertySource(options); + assertThat(ps.containsProperty("foo"), is(true)); + assertThat((String)ps.getProperty("foo"), equalTo("")); + } + + @Test + public void withNoArg() { + OptionParser parser = new OptionParser(); + parser.accepts("o1"); + parser.accepts("o2"); + OptionSet options = parser.parse("--o1"); + + PropertySource<?> ps = new JOptCommandLinePropertySource(options); + assertThat(ps.containsProperty("o1"), is(true)); + assertThat(ps.containsProperty("o2"), is(false)); + assertThat((String)ps.getProperty("o1"), equalTo("")); + assertThat(ps.getProperty("o2"), nullValue()); + } + + @Test + public void withRequiredArg_andMultipleArgsPresent_usingDelimiter() { + OptionParser parser = new OptionParser(); + parser.accepts("foo").withRequiredArg().withValuesSeparatedBy(','); + OptionSet options = parser.parse("--foo=bar,baz,biz"); + + CommandLinePropertySource<?> ps = new JOptCommandLinePropertySource(options); + assertEquals(Arrays.asList("bar","baz","biz"), ps.getOptionValues("foo")); + assertThat(ps.getProperty("foo"), equalTo("bar,baz,biz")); + } + + @Test + public void withRequiredArg_andMultipleArgsPresent_usingRepeatedOption() { + OptionParser parser = new OptionParser(); + parser.accepts("foo").withRequiredArg().withValuesSeparatedBy(','); + OptionSet options = parser.parse("--foo=bar", "--foo=baz", "--foo=biz"); + + CommandLinePropertySource<?> ps = new JOptCommandLinePropertySource(options); + assertEquals(Arrays.asList("bar","baz","biz"), ps.getOptionValues("foo")); + assertThat(ps.getProperty("foo"), equalTo("bar,baz,biz")); + } + + @Test + public void withMissingOption() { + OptionParser parser = new OptionParser(); + parser.accepts("foo").withRequiredArg().withValuesSeparatedBy(','); + OptionSet options = parser.parse(); // <-- no options whatsoever + + PropertySource<?> ps = new JOptCommandLinePropertySource(options); + assertThat(ps.getProperty("foo"), nullValue()); + } + + @Test + public void withDottedOptionName() { + OptionParser parser = new OptionParser(); + parser.accepts("spring.profiles.active").withRequiredArg(); + OptionSet options = parser.parse("--spring.profiles.active=p1"); + + CommandLinePropertySource<?> ps = new JOptCommandLinePropertySource(options); + assertThat(ps.getProperty("spring.profiles.active"), equalTo("p1")); + } + + @Test + public void withDefaultNonOptionArgsNameAndNoNonOptionArgsPresent() { + OptionParser parser = new OptionParser(); + parser.accepts("o1").withRequiredArg(); + parser.accepts("o2"); + OptionSet optionSet = parser.parse("--o1=v1", "--o2"); + PropertySource<?> ps = new JOptCommandLinePropertySource(optionSet); + + assertThat(ps.containsProperty("nonOptionArgs"), is(false)); + assertThat(ps.containsProperty("o1"), is(true)); + assertThat(ps.containsProperty("o2"), is(true)); + + assertThat(ps.containsProperty("nonOptionArgs"), is(false)); + assertThat(ps.getProperty("nonOptionArgs"), nullValue()); + } + + @Test + public void withDefaultNonOptionArgsNameAndNonOptionArgsPresent() { + OptionParser parser = new OptionParser(); + parser.accepts("o1").withRequiredArg(); + parser.accepts("o2"); + OptionSet optionSet = parser.parse("--o1=v1", "noa1", "--o2", "noa2"); + PropertySource<?> ps = new JOptCommandLinePropertySource(optionSet); + + assertThat(ps.containsProperty("nonOptionArgs"), is(true)); + assertThat(ps.containsProperty("o1"), is(true)); + assertThat(ps.containsProperty("o2"), is(true)); + + String nonOptionArgs = (String)ps.getProperty("nonOptionArgs"); + assertThat(nonOptionArgs, equalTo("noa1,noa2")); + } + + @Test + public void withCustomNonOptionArgsNameAndNoNonOptionArgsPresent() { + OptionParser parser = new OptionParser(); + parser.accepts("o1").withRequiredArg(); + parser.accepts("o2"); + OptionSet optionSet = parser.parse("--o1=v1", "noa1", "--o2", "noa2"); + CommandLinePropertySource<?> ps = new JOptCommandLinePropertySource(optionSet); + ps.setNonOptionArgsPropertyName("NOA"); + + assertThat(ps.containsProperty("nonOptionArgs"), is(false)); + assertThat(ps.containsProperty("NOA"), is(true)); + assertThat(ps.containsProperty("o1"), is(true)); + assertThat(ps.containsProperty("o2"), is(true)); + String nonOptionArgs = ps.getProperty("NOA"); + assertThat(nonOptionArgs, equalTo("noa1,noa2")); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/env/MutablePropertySourcesTests.java b/spring-core/src/test/java/org/springframework/core/env/MutablePropertySourcesTests.java new file mode 100644 index 00000000..747c30b1 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/MutablePropertySourcesTests.java @@ -0,0 +1,158 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.env; + +import org.junit.Test; +import org.springframework.mock.env.MockPropertySource; + +import static java.lang.String.*; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.springframework.core.env.MutablePropertySources.*; + +/** + * Unit tests for {@link MutablePropertySources} + * + * @author Chris Beams + */ +public class MutablePropertySourcesTests { + + @Test + public void test() { + MutablePropertySources sources = new MutablePropertySources(); + sources.addLast(new MockPropertySource("b").withProperty("p1", "bValue")); + sources.addLast(new MockPropertySource("d").withProperty("p1", "dValue")); + sources.addLast(new MockPropertySource("f").withProperty("p1", "fValue")); + + assertThat(sources.size(), equalTo(3)); + assertThat(sources.contains("a"), is(false)); + assertThat(sources.contains("b"), is(true)); + assertThat(sources.contains("c"), is(false)); + assertThat(sources.contains("d"), is(true)); + assertThat(sources.contains("e"), is(false)); + assertThat(sources.contains("f"), is(true)); + assertThat(sources.contains("g"), is(false)); + + assertThat(sources.get("b"), not(nullValue())); + assertThat(sources.get("b").getProperty("p1"), equalTo((Object)"bValue")); + assertThat(sources.get("d"), not(nullValue())); + assertThat(sources.get("d").getProperty("p1"), equalTo((Object)"dValue")); + + sources.addBefore("b", new MockPropertySource("a")); + sources.addAfter("b", new MockPropertySource("c")); + + assertThat(sources.size(), equalTo(5)); + assertThat(sources.precedenceOf(PropertySource.named("a")), is(0)); + assertThat(sources.precedenceOf(PropertySource.named("b")), is(1)); + assertThat(sources.precedenceOf(PropertySource.named("c")), is(2)); + assertThat(sources.precedenceOf(PropertySource.named("d")), is(3)); + assertThat(sources.precedenceOf(PropertySource.named("f")), is(4)); + + sources.addBefore("f", new MockPropertySource("e")); + sources.addAfter("f", new MockPropertySource("g")); + + assertThat(sources.size(), equalTo(7)); + assertThat(sources.precedenceOf(PropertySource.named("a")), is(0)); + assertThat(sources.precedenceOf(PropertySource.named("b")), is(1)); + assertThat(sources.precedenceOf(PropertySource.named("c")), is(2)); + assertThat(sources.precedenceOf(PropertySource.named("d")), is(3)); + assertThat(sources.precedenceOf(PropertySource.named("e")), is(4)); + assertThat(sources.precedenceOf(PropertySource.named("f")), is(5)); + assertThat(sources.precedenceOf(PropertySource.named("g")), is(6)); + + sources.addLast(new MockPropertySource("a")); + assertThat(sources.size(), equalTo(7)); + assertThat(sources.precedenceOf(PropertySource.named("b")), is(0)); + assertThat(sources.precedenceOf(PropertySource.named("c")), is(1)); + assertThat(sources.precedenceOf(PropertySource.named("d")), is(2)); + assertThat(sources.precedenceOf(PropertySource.named("e")), is(3)); + assertThat(sources.precedenceOf(PropertySource.named("f")), is(4)); + assertThat(sources.precedenceOf(PropertySource.named("g")), is(5)); + assertThat(sources.precedenceOf(PropertySource.named("a")), is(6)); + + sources.addFirst(new MockPropertySource("a")); + assertThat(sources.size(), equalTo(7)); + assertThat(sources.precedenceOf(PropertySource.named("a")), is(0)); + assertThat(sources.precedenceOf(PropertySource.named("b")), is(1)); + assertThat(sources.precedenceOf(PropertySource.named("c")), is(2)); + assertThat(sources.precedenceOf(PropertySource.named("d")), is(3)); + assertThat(sources.precedenceOf(PropertySource.named("e")), is(4)); + assertThat(sources.precedenceOf(PropertySource.named("f")), is(5)); + assertThat(sources.precedenceOf(PropertySource.named("g")), is(6)); + + assertEquals(sources.remove("a"), PropertySource.named("a")); + assertThat(sources.size(), equalTo(6)); + assertThat(sources.contains("a"), is(false)); + + assertEquals(sources.remove("a"), null); + assertThat(sources.size(), equalTo(6)); + + String bogusPS = "bogus"; + try { + sources.addAfter(bogusPS, new MockPropertySource("h")); + fail("expected non-existent PropertySource exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), + equalTo(format(NON_EXISTENT_PROPERTY_SOURCE_MESSAGE, bogusPS))); + } + + sources.addFirst(new MockPropertySource("a")); + assertThat(sources.size(), equalTo(7)); + assertThat(sources.precedenceOf(PropertySource.named("a")), is(0)); + assertThat(sources.precedenceOf(PropertySource.named("b")), is(1)); + assertThat(sources.precedenceOf(PropertySource.named("c")), is(2)); + + sources.replace("a", new MockPropertySource("a-replaced")); + assertThat(sources.size(), equalTo(7)); + assertThat(sources.precedenceOf(PropertySource.named("a-replaced")), is(0)); + assertThat(sources.precedenceOf(PropertySource.named("b")), is(1)); + assertThat(sources.precedenceOf(PropertySource.named("c")), is(2)); + + sources.replace("a-replaced", new MockPropertySource("a")); + + try { + sources.replace(bogusPS, new MockPropertySource("bogus-replaced")); + fail("expected non-existent PropertySource exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), + equalTo(format(NON_EXISTENT_PROPERTY_SOURCE_MESSAGE, bogusPS))); + } + + try { + sources.addBefore("b", new MockPropertySource("b")); + fail("expected exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), + equalTo(format(ILLEGAL_RELATIVE_ADDITION_MESSAGE, "b"))); + } + + try { + sources.addAfter("b", new MockPropertySource("b")); + fail("expected exception"); + } catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), + equalTo(format(ILLEGAL_RELATIVE_ADDITION_MESSAGE, "b"))); + } + } + + @Test + public void getNonExistentPropertySourceReturnsNull() { + MutablePropertySources sources = new MutablePropertySources(); + assertThat(sources.get("bogus"), nullValue()); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/env/PropertySourceTests.java b/spring-core/src/test/java/org/springframework/core/env/PropertySourceTests.java new file mode 100644 index 00000000..7bb57701 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/PropertySourceTests.java @@ -0,0 +1,120 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.junit.Test; + +/** + * Unit tests for {@link AbstractPropertySource} implementations. + * + * @author Chris Beams + * @since 3.1 + */ +public class PropertySourceTests { + @Test @SuppressWarnings("serial") + public void equals() { + Map<String, Object> map1 = new HashMap<String, Object>() {{ put("a", "b"); }}; + Map<String, Object> map2 = new HashMap<String, Object>() {{ put("c", "d"); }}; + Properties props1 = new Properties() {{ setProperty("a", "b"); }}; + Properties props2 = new Properties() {{ setProperty("c", "d"); }}; + + MapPropertySource mps = new MapPropertySource("mps", map1); + assertThat(mps, equalTo(mps)); + + assertThat(new MapPropertySource("x", map1).equals(new MapPropertySource("x", map1)), is(true)); + assertThat(new MapPropertySource("x", map1).equals(new MapPropertySource("x", map2)), is(true)); + assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("x", props1)), is(true)); + assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("x", props2)), is(true)); + + assertThat(new MapPropertySource("x", map1).equals(new Object()), is(false)); + assertThat(new MapPropertySource("x", map1).equals("x"), is(false)); + assertThat(new MapPropertySource("x", map1).equals(new MapPropertySource("y", map1)), is(false)); + assertThat(new MapPropertySource("x", map1).equals(new MapPropertySource("y", map2)), is(false)); + assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("y", props1)), is(false)); + assertThat(new MapPropertySource("x", map1).equals(new PropertiesPropertySource("y", props2)), is(false)); + } + + @Test @SuppressWarnings("serial") + public void collectionsOperations() { + Map<String, Object> map1 = new HashMap<String, Object>() {{ put("a", "b"); }}; + Map<String, Object> map2 = new HashMap<String, Object>() {{ put("c", "d"); }}; + + PropertySource<?> ps1 = new MapPropertySource("ps1", map1); + ps1.getSource(); + List<PropertySource<?>> propertySources = new ArrayList<PropertySource<?>>(); + assertThat(propertySources.add(ps1), equalTo(true)); + assertThat(propertySources.contains(ps1), is(true)); + assertThat(propertySources.contains(PropertySource.named("ps1")), is(true)); + + PropertySource<?> ps1replacement = new MapPropertySource("ps1", map2); // notice - different map + assertThat(propertySources.add(ps1replacement), is(true)); // true because linkedlist allows duplicates + assertThat(propertySources.size(), is(2)); + assertThat(propertySources.remove(PropertySource.named("ps1")), is(true)); + assertThat(propertySources.size(), is(1)); + assertThat(propertySources.remove(PropertySource.named("ps1")), is(true)); + assertThat(propertySources.size(), is(0)); + + PropertySource<?> ps2 = new MapPropertySource("ps2", map2); + propertySources.add(ps1); + propertySources.add(ps2); + assertThat(propertySources.indexOf(PropertySource.named("ps1")), is(0)); + assertThat(propertySources.indexOf(PropertySource.named("ps2")), is(1)); + propertySources.clear(); + } + + @Test @SuppressWarnings("serial") + public void toString_verbosityVariesOnLogLevel() { + String name = "props"; + Map<String, Object> map = new HashMap<String, Object>() {{ put("k1", "v1"); }}; + MapPropertySource ps = new MapPropertySource(name, map); + Logger logger = Logger.getLogger(ps.getClass()); + Level original = logger.getLevel(); + + try { + logger.setLevel(Level.DEBUG); + assertThat("PropertySource.toString() should render verbose output for log levels <= DEBUG", + ps.toString(), + equalTo(String.format("%s@%s [name='%s', properties=%s]", + ps.getClass().getSimpleName(), + System.identityHashCode(ps), + name, + map))); + + logger.setLevel(Level.INFO); + assertThat("PropertySource.toString() should render concise output for log levels >= INFO", + ps.toString(), + equalTo(String.format("%s [name='%s']", + ps.getClass().getSimpleName(), + name, + map.size()))); + } finally { + logger.setLevel(original); + } + } +} diff --git a/spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java b/spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java new file mode 100644 index 00000000..84f6fce0 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/PropertySourcesPropertyResolverTests.java @@ -0,0 +1,441 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.env; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.core.convert.ConversionException; +import org.springframework.mock.env.MockPropertySource; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * @author Chris Beams + * @since 3.1 + */ +public class PropertySourcesPropertyResolverTests { + + private Properties testProperties; + + private MutablePropertySources propertySources; + + private ConfigurablePropertyResolver propertyResolver; + + + @Before + public void setUp() { + propertySources = new MutablePropertySources(); + propertyResolver = new PropertySourcesPropertyResolver(propertySources); + testProperties = new Properties(); + propertySources.addFirst(new PropertiesPropertySource("testProperties", testProperties)); + } + + + @Test + public void containsProperty() { + assertThat(propertyResolver.containsProperty("foo"), is(false)); + testProperties.put("foo", "bar"); + assertThat(propertyResolver.containsProperty("foo"), is(true)); + } + + @Test + public void getProperty() { + assertThat(propertyResolver.getProperty("foo"), nullValue()); + testProperties.put("foo", "bar"); + assertThat(propertyResolver.getProperty("foo"), is("bar")); + } + + @Test + public void getProperty_withDefaultValue() { + assertThat(propertyResolver.getProperty("foo", "myDefault"), is("myDefault")); + testProperties.put("foo", "bar"); + assertThat(propertyResolver.getProperty("foo"), is("bar")); + } + + @Test + public void getProperty_propertySourceSearchOrderIsFIFO() { + MutablePropertySources sources = new MutablePropertySources(); + PropertyResolver resolver = new PropertySourcesPropertyResolver(sources); + sources.addFirst(new MockPropertySource("ps1").withProperty("pName", "ps1Value")); + assertThat(resolver.getProperty("pName"), equalTo("ps1Value")); + sources.addFirst(new MockPropertySource("ps2").withProperty("pName", "ps2Value")); + assertThat(resolver.getProperty("pName"), equalTo("ps2Value")); + sources.addFirst(new MockPropertySource("ps3").withProperty("pName", "ps3Value")); + assertThat(resolver.getProperty("pName"), equalTo("ps3Value")); + } + + @Test + public void getProperty_withExplicitNullValue() { + // java.util.Properties does not allow null values (because Hashtable does not) + Map<String, Object> nullableProperties = new HashMap<String, Object>(); + propertySources.addLast(new MapPropertySource("nullableProperties", nullableProperties)); + nullableProperties.put("foo", null); + assertThat(propertyResolver.getProperty("foo"), nullValue()); + } + + @Test + public void getProperty_withTargetType_andDefaultValue() { + assertThat(propertyResolver.getProperty("foo", Integer.class, 42), equalTo(42)); + testProperties.put("foo", 13); + assertThat(propertyResolver.getProperty("foo", Integer.class, 42), equalTo(13)); + } + + @Test + public void getProperty_withStringArrayConversion() { + testProperties.put("foo", "bar,baz"); + assertThat(propertyResolver.getProperty("foo", String[].class), equalTo(new String[] { "bar", "baz" })); + } + + @Test + public void getProperty_withNonConvertibleTargetType() { + testProperties.put("foo", "bar"); + + class TestType { } + + try { + propertyResolver.getProperty("foo", TestType.class); + fail("Expected IllegalArgumentException due to non-convertible types"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + @Test + public void getProperty_doesNotCache_replaceExistingKeyPostConstruction() { + String key = "foo"; + String value1 = "bar"; + String value2 = "biz"; + + HashMap<String, Object> map = new HashMap<String, Object>(); + map.put(key, value1); // before construction + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MapPropertySource("testProperties", map)); + PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources); + assertThat(propertyResolver.getProperty(key), equalTo(value1)); + map.put(key, value2); // after construction and first resolution + assertThat(propertyResolver.getProperty(key), equalTo(value2)); + } + + @Test + public void getProperty_doesNotCache_addNewKeyPostConstruction() { + HashMap<String, Object> map = new HashMap<String, Object>(); + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MapPropertySource("testProperties", map)); + PropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources); + assertThat(propertyResolver.getProperty("foo"), equalTo(null)); + map.put("foo", "42"); + assertThat(propertyResolver.getProperty("foo"), equalTo("42")); + } + + @Test + public void getPropertySources_replacePropertySource() { + propertySources = new MutablePropertySources(); + propertyResolver = new PropertySourcesPropertyResolver(propertySources); + propertySources.addLast(new MockPropertySource("local").withProperty("foo", "localValue")); + propertySources.addLast(new MockPropertySource("system").withProperty("foo", "systemValue")); + + // 'local' was added first so has precedence + assertThat(propertyResolver.getProperty("foo"), equalTo("localValue")); + + // replace 'local' with new property source + propertySources.replace("local", new MockPropertySource("new").withProperty("foo", "newValue")); + + // 'system' now has precedence + assertThat(propertyResolver.getProperty("foo"), equalTo("newValue")); + + assertThat(propertySources.size(), is(2)); + } + + @Test + public void getRequiredProperty() { + testProperties.put("exists", "xyz"); + assertThat(propertyResolver.getRequiredProperty("exists"), is("xyz")); + + try { + propertyResolver.getRequiredProperty("bogus"); + fail("expected IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + @Test + public void getRequiredProperty_withStringArrayConversion() { + testProperties.put("exists", "abc,123"); + assertThat(propertyResolver.getRequiredProperty("exists", String[].class), equalTo(new String[] { "abc", "123" })); + + try { + propertyResolver.getRequiredProperty("bogus", String[].class); + fail("expected IllegalStateException"); + } + catch (IllegalStateException ex) { + // expected + } + } + + @Test + public void resolvePlaceholders() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("key", "value")); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertThat(resolver.resolvePlaceholders("Replace this ${key}"), equalTo("Replace this value")); + } + + @Test + public void resolvePlaceholders_withUnresolvable() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("key", "value")); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertThat(resolver.resolvePlaceholders("Replace this ${key} plus ${unknown}"), + equalTo("Replace this value plus ${unknown}")); + } + + @Test + public void resolvePlaceholders_withDefaultValue() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("key", "value")); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertThat(resolver.resolvePlaceholders("Replace this ${key} plus ${unknown:defaultValue}"), + equalTo("Replace this value plus defaultValue")); + } + + @Test(expected=IllegalArgumentException.class) + public void resolvePlaceholders_withNullInput() { + new PropertySourcesPropertyResolver(new MutablePropertySources()).resolvePlaceholders(null); + } + + @Test + public void resolveRequiredPlaceholders() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("key", "value")); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertThat(resolver.resolveRequiredPlaceholders("Replace this ${key}"), equalTo("Replace this value")); + } + + @Test(expected=IllegalArgumentException.class) + public void resolveRequiredPlaceholders_withUnresolvable() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("key", "value")); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + resolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown}"); + } + + @Test + public void resolveRequiredPlaceholders_withDefaultValue() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("key", "value")); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertThat(resolver.resolveRequiredPlaceholders("Replace this ${key} plus ${unknown:defaultValue}"), + equalTo("Replace this value plus defaultValue")); + } + + @Test(expected=IllegalArgumentException.class) + public void resolveRequiredPlaceholders_withNullInput() { + new PropertySourcesPropertyResolver(new MutablePropertySources()).resolveRequiredPlaceholders(null); + } + + @Test + public void getPropertyAsClass() throws ClassNotFoundException, LinkageError { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("some.class", SpecificType.class.getName())); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class)); + } + + @Test + public void getPropertyAsClass_withInterfaceAsTarget() throws ClassNotFoundException, LinkageError { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("some.class", SomeType.class.getName())); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SomeType.class)); + } + + @Test(expected=ConversionException.class) + public void getPropertyAsClass_withMismatchedTypeForValue() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("some.class", "java.lang.String")); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + resolver.getPropertyAsClass("some.class", SomeType.class); + } + + @Test(expected=ConversionException.class) + public void getPropertyAsClass_withNonExistentClassForValue() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("some.class", "some.bogus.Class")); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + resolver.getPropertyAsClass("some.class", SomeType.class); + } + + @Test + public void getPropertyAsClass_withObjectForValue() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("some.class", new SpecificType())); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class)); + } + + @Test(expected=ConversionException.class) + public void getPropertyAsClass_withMismatchedObjectForValue() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("some.class", new Integer(42))); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + resolver.getPropertyAsClass("some.class", SomeType.class); + } + + @Test + public void getPropertyAsClass_withRealClassForValue() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("some.class", SpecificType.class)); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + assertTrue(resolver.getPropertyAsClass("some.class", SomeType.class).equals(SpecificType.class)); + } + + @Test(expected=ConversionException.class) + public void getPropertyAsClass_withMismatchedRealClassForValue() { + MutablePropertySources propertySources = new MutablePropertySources(); + propertySources.addFirst(new MockPropertySource().withProperty("some.class", Integer.class)); + PropertyResolver resolver = new PropertySourcesPropertyResolver(propertySources); + resolver.getPropertyAsClass("some.class", SomeType.class); + } + + @Test + public void setRequiredProperties_andValidateRequiredProperties() { + // no properties have been marked as required -> validation should pass + propertyResolver.validateRequiredProperties(); + + // mark which properties are required + propertyResolver.setRequiredProperties("foo", "bar"); + + // neither foo nor bar properties are present -> validating should throw + try { + propertyResolver.validateRequiredProperties(); + fail("expected validation exception"); + } + catch (MissingRequiredPropertiesException ex) { + assertThat(ex.getMessage(), equalTo( + "The following properties were declared as required " + + "but could not be resolved: [foo, bar]")); + } + + // add foo property -> validation should fail only on missing 'bar' property + testProperties.put("foo", "fooValue"); + try { + propertyResolver.validateRequiredProperties(); + fail("expected validation exception"); + } + catch (MissingRequiredPropertiesException ex) { + assertThat(ex.getMessage(), equalTo( + "The following properties were declared as required " + + "but could not be resolved: [bar]")); + } + + // add bar property -> validation should pass, even with an empty string value + testProperties.put("bar", ""); + propertyResolver.validateRequiredProperties(); + } + + @Test + public void resolveNestedPropertyPlaceholders() { + MutablePropertySources ps = new MutablePropertySources(); + ps.addFirst(new MockPropertySource() + .withProperty("p1", "v1") + .withProperty("p2", "v2") + .withProperty("p3", "${p1}:${p2}") // nested placeholders + .withProperty("p4", "${p3}") // deeply nested placeholders + .withProperty("p5", "${p1}:${p2}:${bogus}") // unresolvable placeholder + .withProperty("p6", "${p1}:${p2}:${bogus:def}") // unresolvable w/ default + .withProperty("pL", "${pR}") // cyclic reference left + .withProperty("pR", "${pL}") // cyclic reference right + ); + ConfigurablePropertyResolver pr = new PropertySourcesPropertyResolver(ps); + assertThat(pr.getProperty("p1"), equalTo("v1")); + assertThat(pr.getProperty("p2"), equalTo("v2")); + assertThat(pr.getProperty("p3"), equalTo("v1:v2")); + assertThat(pr.getProperty("p4"), equalTo("v1:v2")); + try { + pr.getProperty("p5"); + } + catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), containsString( + "Could not resolve placeholder 'bogus' in string value \"${p1}:${p2}:${bogus}\"")); + } + assertThat(pr.getProperty("p6"), equalTo("v1:v2:def")); + try { + pr.getProperty("pL"); + } + catch (IllegalArgumentException ex) { + assertTrue(ex.getMessage().toLowerCase().contains("circular")); + } + } + + @Test + public void ignoreUnresolvableNestedPlaceholdersIsConfigurable() { + MutablePropertySources ps = new MutablePropertySources(); + ps.addFirst(new MockPropertySource() + .withProperty("p1", "v1") + .withProperty("p2", "v2") + .withProperty("p3", "${p1}:${p2}:${bogus:def}") // unresolvable w/ default + .withProperty("p4", "${p1}:${p2}:${bogus}") // unresolvable placeholder + ); + ConfigurablePropertyResolver pr = new PropertySourcesPropertyResolver(ps); + assertThat(pr.getProperty("p1"), equalTo("v1")); + assertThat(pr.getProperty("p2"), equalTo("v2")); + assertThat(pr.getProperty("p3"), equalTo("v1:v2:def")); + + // placeholders nested within the value of "p4" are unresolvable and cause an + // exception by default + try { + pr.getProperty("p4"); + } + catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), containsString( + "Could not resolve placeholder 'bogus' in string value \"${p1}:${p2}:${bogus}\"")); + } + + // relax the treatment of unresolvable nested placeholders + pr.setIgnoreUnresolvableNestedPlaceholders(true); + // and observe they now pass through unresolved + assertThat(pr.getProperty("p4"), equalTo("v1:v2:${bogus}")); + + // resolve[Nested]Placeholders methods behave as usual regardless the value of + // ignoreUnresolvableNestedPlaceholders + assertThat(pr.resolvePlaceholders("${p1}:${p2}:${bogus}"), equalTo("v1:v2:${bogus}")); + try { + pr.resolveRequiredPlaceholders("${p1}:${p2}:${bogus}"); + } + catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), containsString( + "Could not resolve placeholder 'bogus' in string value \"${p1}:${p2}:${bogus}\"")); + } + } + + + interface SomeType { + } + + static class SpecificType implements SomeType { + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineParserTests.java b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineParserTests.java new file mode 100644 index 00000000..08111c70 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineParserTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.util.Collections; +import java.util.List; + +import org.junit.Test; + +public class SimpleCommandLineParserTests { + + @Test + public void withNoOptions() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + assertThat(parser.parse().getOptionValues("foo"), nullValue()); + } + + @Test + public void withSingleOptionAndNoValue() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + CommandLineArgs args = parser.parse("--o1"); + assertThat(args.containsOption("o1"), is(true)); + assertThat(args.getOptionValues("o1"), equalTo(Collections.EMPTY_LIST)); + } + + @Test + public void withSingleOptionAndValue() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + CommandLineArgs args = parser.parse("--o1=v1"); + assertThat(args.containsOption("o1"), is(true)); + assertThat(args.getOptionValues("o1").get(0), equalTo("v1")); + } + + @Test + public void withMixOfOptionsHavingValueAndOptionsHavingNoValue() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + CommandLineArgs args = parser.parse("--o1=v1", "--o2"); + assertThat(args.containsOption("o1"), is(true)); + assertThat(args.containsOption("o2"), is(true)); + assertThat(args.containsOption("o3"), is(false)); + assertThat(args.getOptionValues("o1").get(0), equalTo("v1")); + assertThat(args.getOptionValues("o2"), equalTo(Collections.EMPTY_LIST)); + assertThat(args.getOptionValues("o3"), nullValue()); + } + + @Test(expected=IllegalArgumentException.class) + public void withEmptyOptionText() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + parser.parse("--"); + } + + @Test(expected=IllegalArgumentException.class) + public void withEmptyOptionName() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + parser.parse("--=v1"); + } + + @Test(expected=IllegalArgumentException.class) + public void withEmptyOptionValue() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + parser.parse("--o1="); + } + + @Test(expected=IllegalArgumentException.class) + public void withEmptyOptionNameAndEmptyOptionValue() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + parser.parse("--="); + } + + @Test + public void withNonOptionArguments() { + SimpleCommandLineArgsParser parser = new SimpleCommandLineArgsParser(); + CommandLineArgs args = parser.parse("--o1=v1", "noa1", "--o2=v2", "noa2"); + assertThat(args.getOptionValues("o1").get(0), equalTo("v1")); + assertThat(args.getOptionValues("o2").get(0), equalTo("v2")); + + List<String> nonOptions = args.getNonOptionArgs(); + assertThat(nonOptions.get(0), equalTo("noa1")); + assertThat(nonOptions.get(1), equalTo("noa2")); + assertThat(nonOptions.size(), equalTo(2)); + } + + @Test(expected=UnsupportedOperationException.class) + public void assertOptionNamesIsUnmodifiable() { + CommandLineArgs args = new SimpleCommandLineArgsParser().parse(); + args.getOptionNames().add("bogus"); + } + + @Test(expected=UnsupportedOperationException.class) + public void assertNonOptionArgsIsUnmodifiable() { + CommandLineArgs args = new SimpleCommandLineArgsParser().parse(); + args.getNonOptionArgs().add("foo"); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java new file mode 100644 index 00000000..2f7c0fcc --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/SimpleCommandLinePropertySourceTests.java @@ -0,0 +1,126 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import org.junit.Test; + +/** + * Unit tests for {@link SimpleCommandLinePropertySource}. + * + * @author Chris Beams + * @since 3.1 + */ +public class SimpleCommandLinePropertySourceTests { + + @Test + public void withDefaultName() { + PropertySource<?> ps = new SimpleCommandLinePropertySource(); + assertThat(ps.getName(), + equalTo(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)); + } + + @Test + public void withCustomName() { + PropertySource<?> ps = new SimpleCommandLinePropertySource("ps1", new String[0]); + assertThat(ps.getName(), equalTo("ps1")); + } + + @Test + public void withNoArgs() { + PropertySource<?> ps = new SimpleCommandLinePropertySource(); + assertThat(ps.containsProperty("foo"), is(false)); + assertThat(ps.getProperty("foo"), nullValue()); + } + + @Test + public void withOptionArgsOnly() { + CommandLinePropertySource<?> ps = + new SimpleCommandLinePropertySource("--o1=v1", "--o2"); + assertThat(ps.containsProperty("o1"), is(true)); + assertThat(ps.containsProperty("o2"), is(true)); + assertThat(ps.containsProperty("o3"), is(false)); + assertThat(ps.getProperty("o1"), equalTo("v1")); + assertThat(ps.getProperty("o2"), equalTo("")); + assertThat(ps.getProperty("o3"), nullValue()); + } + + @Test + public void withDefaultNonOptionArgsNameAndNoNonOptionArgsPresent() { + PropertySource<?> ps = new SimpleCommandLinePropertySource("--o1=v1", "--o2"); + + assertThat(ps.containsProperty("nonOptionArgs"), is(false)); + assertThat(ps.containsProperty("o1"), is(true)); + assertThat(ps.containsProperty("o2"), is(true)); + + assertThat(ps.containsProperty("nonOptionArgs"), is(false)); + assertThat(ps.getProperty("nonOptionArgs"), nullValue()); + } + + @Test + public void withDefaultNonOptionArgsNameAndNonOptionArgsPresent() { + CommandLinePropertySource<?> ps = + new SimpleCommandLinePropertySource("--o1=v1", "noa1", "--o2", "noa2"); + + assertThat(ps.containsProperty("nonOptionArgs"), is(true)); + assertThat(ps.containsProperty("o1"), is(true)); + assertThat(ps.containsProperty("o2"), is(true)); + + String nonOptionArgs = ps.getProperty("nonOptionArgs"); + assertThat(nonOptionArgs, equalTo("noa1,noa2")); + } + + @Test + public void withCustomNonOptionArgsNameAndNoNonOptionArgsPresent() { + CommandLinePropertySource<?> ps = + new SimpleCommandLinePropertySource("--o1=v1", "noa1", "--o2", "noa2"); + ps.setNonOptionArgsPropertyName("NOA"); + + assertThat(ps.containsProperty("nonOptionArgs"), is(false)); + assertThat(ps.containsProperty("NOA"), is(true)); + assertThat(ps.containsProperty("o1"), is(true)); + assertThat(ps.containsProperty("o2"), is(true)); + String nonOptionArgs = ps.getProperty("NOA"); + assertThat(nonOptionArgs, equalTo("noa1,noa2")); + } + + @Test + public void covertNonOptionArgsToStringArrayAndList() { + CommandLinePropertySource<?> ps = + new SimpleCommandLinePropertySource("--o1=v1", "noa1", "--o2", "noa2"); + StandardEnvironment env = new StandardEnvironment(); + env.getPropertySources().addFirst(ps); + + String nonOptionArgs = env.getProperty("nonOptionArgs"); + assertThat(nonOptionArgs, equalTo("noa1,noa2")); + + String[] nonOptionArgsArray = env.getProperty("nonOptionArgs", String[].class); + assertThat(nonOptionArgsArray[0], equalTo("noa1")); + assertThat(nonOptionArgsArray[1], equalTo("noa2")); + + @SuppressWarnings("unchecked") + List<String> nonOptionArgsList = env.getProperty("nonOptionArgs", List.class); + assertThat(nonOptionArgsList.get(0), equalTo("noa1")); + assertThat(nonOptionArgsList.get(1), equalTo("noa2")); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/env/StandardEnvironmentTests.java b/spring-core/src/test/java/org/springframework/core/env/StandardEnvironmentTests.java new file mode 100644 index 00000000..e094e342 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/StandardEnvironmentTests.java @@ -0,0 +1,550 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * 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 org.springframework.core.env; + +import java.lang.reflect.Field; +import java.security.AccessControlException; +import java.security.Permission; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + +import org.junit.Test; + +import org.springframework.core.SpringProperties; +import org.springframework.mock.env.MockPropertySource; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.springframework.core.env.AbstractEnvironment.*; + +/** + * Unit tests for {@link StandardEnvironment}. + * + * @author Chris Beams + * @author Juergen Hoeller + */ +public class StandardEnvironmentTests { + + private static final String ALLOWED_PROPERTY_NAME = "theanswer"; + private static final String ALLOWED_PROPERTY_VALUE = "42"; + + private static final String DISALLOWED_PROPERTY_NAME = "verboten"; + private static final String DISALLOWED_PROPERTY_VALUE = "secret"; + + private static final String STRING_PROPERTY_NAME = "stringPropName"; + private static final String STRING_PROPERTY_VALUE = "stringPropValue"; + private static final Object NON_STRING_PROPERTY_NAME = new Object(); + private static final Object NON_STRING_PROPERTY_VALUE = new Object(); + + private ConfigurableEnvironment environment = new StandardEnvironment(); + + @Test + public void merge() { + ConfigurableEnvironment child = new StandardEnvironment(); + child.setActiveProfiles("c1", "c2"); + child.getPropertySources().addLast( + new MockPropertySource("childMock") + .withProperty("childKey", "childVal") + .withProperty("bothKey", "childBothVal")); + + ConfigurableEnvironment parent = new StandardEnvironment(); + parent.setActiveProfiles("p1", "p2"); + parent.getPropertySources().addLast( + new MockPropertySource("parentMock") + .withProperty("parentKey", "parentVal") + .withProperty("bothKey", "parentBothVal")); + + assertThat(child.getProperty("childKey"), is("childVal")); + assertThat(child.getProperty("parentKey"), nullValue()); + assertThat(child.getProperty("bothKey"), is("childBothVal")); + + assertThat(parent.getProperty("childKey"), nullValue()); + assertThat(parent.getProperty("parentKey"), is("parentVal")); + assertThat(parent.getProperty("bothKey"), is("parentBothVal")); + + assertThat(child.getActiveProfiles(), equalTo(new String[]{"c1","c2"})); + assertThat(parent.getActiveProfiles(), equalTo(new String[]{"p1","p2"})); + + child.merge(parent); + + assertThat(child.getProperty("childKey"), is("childVal")); + assertThat(child.getProperty("parentKey"), is("parentVal")); + assertThat(child.getProperty("bothKey"), is("childBothVal")); + + assertThat(parent.getProperty("childKey"), nullValue()); + assertThat(parent.getProperty("parentKey"), is("parentVal")); + assertThat(parent.getProperty("bothKey"), is("parentBothVal")); + + assertThat(child.getActiveProfiles(), equalTo(new String[]{"c1","c2","p1","p2"})); + assertThat(parent.getActiveProfiles(), equalTo(new String[]{"p1","p2"})); + } + + @Test + public void propertySourceOrder() { + ConfigurableEnvironment env = new StandardEnvironment(); + MutablePropertySources sources = env.getPropertySources(); + assertThat(sources.precedenceOf(PropertySource.named(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)), equalTo(0)); + assertThat(sources.precedenceOf(PropertySource.named(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME)), equalTo(1)); + assertThat(sources.size(), is(2)); + } + + @Test + public void propertySourceTypes() { + ConfigurableEnvironment env = new StandardEnvironment(); + MutablePropertySources sources = env.getPropertySources(); + assertThat(sources.get(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME), instanceOf(SystemEnvironmentPropertySource.class)); + } + + @Test + public void activeProfilesIsEmptyByDefault() { + assertThat(environment.getActiveProfiles().length, is(0)); + } + + @Test + public void defaultProfilesContainsDefaultProfileByDefault() { + assertThat(environment.getDefaultProfiles().length, is(1)); + assertThat(environment.getDefaultProfiles()[0], equalTo("default")); + } + + @Test + public void setActiveProfiles() { + environment.setActiveProfiles("local", "embedded"); + String[] activeProfiles = environment.getActiveProfiles(); + assertThat(Arrays.asList(activeProfiles), hasItems("local", "embedded")); + assertThat(activeProfiles.length, is(2)); + } + + @Test(expected=IllegalArgumentException.class) + public void setActiveProfiles_withNullProfileArray() { + environment.setActiveProfiles((String[])null); + } + + @Test(expected=IllegalArgumentException.class) + public void setActiveProfiles_withNullProfile() { + environment.setActiveProfiles((String)null); + } + + @Test(expected=IllegalArgumentException.class) + public void setActiveProfiles_withEmptyProfile() { + environment.setActiveProfiles(""); + } + + @Test(expected=IllegalArgumentException.class) + public void setActiveProfiles_withNotOperator() { + environment.setActiveProfiles("p1", "!p2"); + } + + @Test(expected=IllegalArgumentException.class) + public void setDefaultProfiles_withNullProfileArray() { + environment.setDefaultProfiles((String[])null); + } + + @Test(expected=IllegalArgumentException.class) + public void setDefaultProfiles_withNullProfile() { + environment.setDefaultProfiles((String)null); + } + + @Test(expected=IllegalArgumentException.class) + public void setDefaultProfiles_withEmptyProfile() { + environment.setDefaultProfiles(""); + } + + @Test(expected=IllegalArgumentException.class) + public void setDefaultProfiles_withNotOperator() { + environment.setDefaultProfiles("d1", "!d2"); + } + + @Test + public void addActiveProfile() { + assertThat(environment.getActiveProfiles().length, is(0)); + environment.setActiveProfiles("local", "embedded"); + assertThat(Arrays.asList(environment.getActiveProfiles()), hasItems("local", "embedded")); + assertThat(environment.getActiveProfiles().length, is(2)); + environment.addActiveProfile("p1"); + assertThat(Arrays.asList(environment.getActiveProfiles()), hasItems("p1")); + assertThat(environment.getActiveProfiles().length, is(3)); + environment.addActiveProfile("p2"); + environment.addActiveProfile("p3"); + assertThat(Arrays.asList(environment.getActiveProfiles()), hasItems("p2", "p3")); + assertThat(environment.getActiveProfiles().length, is(5)); + } + + @Test + public void addActiveProfile_whenActiveProfilesPropertyIsAlreadySet() { + ConfigurableEnvironment env = new StandardEnvironment(); + assertThat(env.getProperty(ACTIVE_PROFILES_PROPERTY_NAME), nullValue()); + env.getPropertySources().addFirst(new MockPropertySource().withProperty(ACTIVE_PROFILES_PROPERTY_NAME, "p1")); + assertThat(env.getProperty(ACTIVE_PROFILES_PROPERTY_NAME), equalTo("p1")); + env.addActiveProfile("p2"); + assertThat(env.getActiveProfiles(), arrayContaining("p1", "p2")); + } + + @Test + public void reservedDefaultProfile() { + assertThat(environment.getDefaultProfiles(), equalTo(new String[]{RESERVED_DEFAULT_PROFILE_NAME})); + System.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, "d0"); + assertThat(environment.getDefaultProfiles(), equalTo(new String[]{"d0"})); + environment.setDefaultProfiles("d1", "d2"); + assertThat(environment.getDefaultProfiles(), equalTo(new String[]{"d1","d2"})); + System.getProperties().remove(DEFAULT_PROFILES_PROPERTY_NAME); + } + + @Test(expected=IllegalArgumentException.class) + public void defaultProfileWithCircularPlaceholder() { + System.setProperty(DEFAULT_PROFILES_PROPERTY_NAME, "${spring.profiles.default}"); + try { + environment.getDefaultProfiles(); + } + finally { + System.getProperties().remove(DEFAULT_PROFILES_PROPERTY_NAME); + } + } + + @Test + public void getActiveProfiles_systemPropertiesEmpty() { + assertThat(environment.getActiveProfiles().length, is(0)); + System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, ""); + assertThat(environment.getActiveProfiles().length, is(0)); + System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME); + } + + @Test + public void getActiveProfiles_fromSystemProperties() { + System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo"); + assertThat(Arrays.asList(environment.getActiveProfiles()), hasItem("foo")); + System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME); + } + + @Test + public void getActiveProfiles_fromSystemProperties_withMultipleProfiles() { + System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, "foo,bar"); + assertThat(Arrays.asList(environment.getActiveProfiles()), hasItems("foo", "bar")); + System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME); + } + + @Test + public void getActiveProfiles_fromSystemProperties_withMulitpleProfiles_withWhitespace() { + System.setProperty(ACTIVE_PROFILES_PROPERTY_NAME, " bar , baz "); // notice whitespace + assertThat(Arrays.asList(environment.getActiveProfiles()), hasItems("bar", "baz")); + System.getProperties().remove(ACTIVE_PROFILES_PROPERTY_NAME); + } + + @Test + public void getDefaultProfiles() { + assertThat(environment.getDefaultProfiles(), equalTo(new String[] {RESERVED_DEFAULT_PROFILE_NAME})); + environment.getPropertySources().addFirst(new MockPropertySource().withProperty(DEFAULT_PROFILES_PROPERTY_NAME, "pd1")); + assertThat(environment.getDefaultProfiles().length, is(1)); + assertThat(Arrays.asList(environment.getDefaultProfiles()), hasItem("pd1")); + } + + @Test + public void setDefaultProfiles() { + environment.setDefaultProfiles(); + assertThat(environment.getDefaultProfiles().length, is(0)); + environment.setDefaultProfiles("pd1"); + assertThat(Arrays.asList(environment.getDefaultProfiles()), hasItem("pd1")); + environment.setDefaultProfiles("pd2", "pd3"); + assertThat(Arrays.asList(environment.getDefaultProfiles()), not(hasItem("pd1"))); + assertThat(Arrays.asList(environment.getDefaultProfiles()), hasItems("pd2", "pd3")); + } + + @Test(expected=IllegalArgumentException.class) + public void acceptsProfiles_withEmptyArgumentList() { + environment.acceptsProfiles(); + } + + @Test(expected=IllegalArgumentException.class) + public void acceptsProfiles_withNullArgumentList() { + environment.acceptsProfiles((String[])null); + } + + @Test(expected=IllegalArgumentException.class) + public void acceptsProfiles_withNullArgument() { + environment.acceptsProfiles((String)null); + } + + @Test(expected=IllegalArgumentException.class) + public void acceptsProfiles_withEmptyArgument() { + environment.acceptsProfiles(""); + } + + + @Test + public void acceptsProfiles_activeProfileSetProgrammatically() { + assertThat(environment.acceptsProfiles("p1", "p2"), is(false)); + environment.setActiveProfiles("p1"); + assertThat(environment.acceptsProfiles("p1", "p2"), is(true)); + environment.setActiveProfiles("p2"); + assertThat(environment.acceptsProfiles("p1", "p2"), is(true)); + environment.setActiveProfiles("p1", "p2"); + assertThat(environment.acceptsProfiles("p1", "p2"), is(true)); + } + + @Test + public void acceptsProfiles_activeProfileSetViaProperty() { + assertThat(environment.acceptsProfiles("p1"), is(false)); + environment.getPropertySources().addFirst(new MockPropertySource().withProperty(ACTIVE_PROFILES_PROPERTY_NAME, "p1")); + assertThat(environment.acceptsProfiles("p1"), is(true)); + } + + @Test + public void acceptsProfiles_defaultProfile() { + assertThat(environment.acceptsProfiles("pd"), is(false)); + environment.setDefaultProfiles("pd"); + assertThat(environment.acceptsProfiles("pd"), is(true)); + environment.setActiveProfiles("p1"); + assertThat(environment.acceptsProfiles("pd"), is(false)); + assertThat(environment.acceptsProfiles("p1"), is(true)); + } + + @Test + public void acceptsProfiles_withNotOperator() { + assertThat(environment.acceptsProfiles("p1"), is(false)); + assertThat(environment.acceptsProfiles("!p1"), is(true)); + environment.addActiveProfile("p1"); + assertThat(environment.acceptsProfiles("p1"), is(true)); + assertThat(environment.acceptsProfiles("!p1"), is(false)); + } + + @Test(expected=IllegalArgumentException.class) + public void acceptsProfiles_withInvalidNotOperator() { + environment.acceptsProfiles("p1", "!"); + } + + @Test + public void environmentSubclass_withCustomProfileValidation() { + ConfigurableEnvironment env = new AbstractEnvironment() { + @Override + protected void validateProfile(String profile) { + super.validateProfile(profile); + if (profile.contains("-")) { + throw new IllegalArgumentException( + "Invalid profile [" + profile + "]: must not contain dash character"); + } + } + }; + + env.addActiveProfile("validProfile"); // succeeds + + try { + env.addActiveProfile("invalid-profile"); + fail("expected validation exception"); + } + catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), + equalTo("Invalid profile [invalid-profile]: must not contain dash character")); + } + } + + @Test + public void suppressGetenvAccessThroughSystemProperty() { + System.setProperty("spring.getenv.ignore", "true"); + assertTrue(environment.getSystemEnvironment().isEmpty()); + System.clearProperty("spring.getenv.ignore"); + } + + @Test + public void suppressGetenvAccessThroughSpringProperty() { + SpringProperties.setProperty("spring.getenv.ignore", "true"); + assertTrue(environment.getSystemEnvironment().isEmpty()); + SpringProperties.setProperty("spring.getenv.ignore", null); + } + + @Test + public void suppressGetenvAccessThroughSpringFlag() { + SpringProperties.setFlag("spring.getenv.ignore"); + assertTrue(environment.getSystemEnvironment().isEmpty()); + SpringProperties.setProperty("spring.getenv.ignore", null); + } + + @Test + public void getSystemProperties_withAndWithoutSecurityManager() { + System.setProperty(ALLOWED_PROPERTY_NAME, ALLOWED_PROPERTY_VALUE); + System.setProperty(DISALLOWED_PROPERTY_NAME, DISALLOWED_PROPERTY_VALUE); + System.getProperties().put(STRING_PROPERTY_NAME, NON_STRING_PROPERTY_VALUE); + System.getProperties().put(NON_STRING_PROPERTY_NAME, STRING_PROPERTY_VALUE); + + { + Map<?, ?> systemProperties = environment.getSystemProperties(); + assertThat(systemProperties, notNullValue()); + assertSame(systemProperties, System.getProperties()); + assertThat(systemProperties.get(ALLOWED_PROPERTY_NAME), equalTo((Object)ALLOWED_PROPERTY_VALUE)); + assertThat(systemProperties.get(DISALLOWED_PROPERTY_NAME), equalTo((Object)DISALLOWED_PROPERTY_VALUE)); + + // non-string keys and values work fine... until the security manager is introduced below + assertThat(systemProperties.get(STRING_PROPERTY_NAME), equalTo(NON_STRING_PROPERTY_VALUE)); + assertThat(systemProperties.get(NON_STRING_PROPERTY_NAME), equalTo((Object)STRING_PROPERTY_VALUE)); + } + + SecurityManager oldSecurityManager = System.getSecurityManager(); + SecurityManager securityManager = new SecurityManager() { + @Override + public void checkPropertiesAccess() { + // see http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getProperties() + throw new AccessControlException("Accessing the system properties is disallowed"); + } + @Override + public void checkPropertyAccess(String key) { + // see http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getProperty(java.lang.String) + if (DISALLOWED_PROPERTY_NAME.equals(key)) { + throw new AccessControlException( + String.format("Accessing the system property [%s] is disallowed", DISALLOWED_PROPERTY_NAME)); + } + } + @Override + public void checkPermission(Permission perm) { + // allow everything else + } + }; + System.setSecurityManager(securityManager); + + { + Map<?, ?> systemProperties = environment.getSystemProperties(); + assertThat(systemProperties, notNullValue()); + assertThat(systemProperties, instanceOf(ReadOnlySystemAttributesMap.class)); + assertThat((String)systemProperties.get(ALLOWED_PROPERTY_NAME), equalTo(ALLOWED_PROPERTY_VALUE)); + assertThat(systemProperties.get(DISALLOWED_PROPERTY_NAME), equalTo(null)); + + // nothing we can do here in terms of warning the user that there was + // actually a (non-string) value available. By this point, we only + // have access to calling System.getProperty(), which itself returns null + // if the value is non-string. So we're stuck with returning a potentially + // misleading null. + assertThat(systemProperties.get(STRING_PROPERTY_NAME), nullValue()); + + // in the case of a non-string *key*, however, we can do better. Alert + // the user that under these very special conditions (non-object key + + // SecurityManager that disallows access to system properties), they + // cannot do what they're attempting. + try { + systemProperties.get(NON_STRING_PROPERTY_NAME); + fail("Expected IllegalArgumentException when searching with non-string key against ReadOnlySystemAttributesMap"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + System.setSecurityManager(oldSecurityManager); + System.clearProperty(ALLOWED_PROPERTY_NAME); + System.clearProperty(DISALLOWED_PROPERTY_NAME); + System.getProperties().remove(STRING_PROPERTY_NAME); + System.getProperties().remove(NON_STRING_PROPERTY_NAME); + } + + @Test + public void getSystemEnvironment_withAndWithoutSecurityManager() { + getModifiableSystemEnvironment().put(ALLOWED_PROPERTY_NAME, ALLOWED_PROPERTY_VALUE); + getModifiableSystemEnvironment().put(DISALLOWED_PROPERTY_NAME, DISALLOWED_PROPERTY_VALUE); + + { + Map<String, Object> systemEnvironment = environment.getSystemEnvironment(); + assertThat(systemEnvironment, notNullValue()); + assertSame(systemEnvironment, System.getenv()); + } + + SecurityManager oldSecurityManager = System.getSecurityManager(); + SecurityManager securityManager = new SecurityManager() { + @Override + public void checkPermission(Permission perm) { + //see http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getenv() + if ("getenv.*".equals(perm.getName())) { + throw new AccessControlException("Accessing the system environment is disallowed"); + } + //see http://download.oracle.com/javase/1.5.0/docs/api/java/lang/System.html#getenv(java.lang.String) + if (("getenv."+DISALLOWED_PROPERTY_NAME).equals(perm.getName())) { + throw new AccessControlException( + String.format("Accessing the system environment variable [%s] is disallowed", DISALLOWED_PROPERTY_NAME)); + } + } + }; + System.setSecurityManager(securityManager); + + { + Map<String, Object> systemEnvironment = environment.getSystemEnvironment(); + assertThat(systemEnvironment, notNullValue()); + assertThat(systemEnvironment, instanceOf(ReadOnlySystemAttributesMap.class)); + assertThat(systemEnvironment.get(ALLOWED_PROPERTY_NAME), equalTo((Object)ALLOWED_PROPERTY_VALUE)); + assertThat(systemEnvironment.get(DISALLOWED_PROPERTY_NAME), nullValue()); + } + + System.setSecurityManager(oldSecurityManager); + getModifiableSystemEnvironment().remove(ALLOWED_PROPERTY_NAME); + getModifiableSystemEnvironment().remove(DISALLOWED_PROPERTY_NAME); + } + + @SuppressWarnings("unchecked") + public static Map<String, String> getModifiableSystemEnvironment() { + // for os x / linux + Class<?>[] classes = Collections.class.getDeclaredClasses(); + Map<String, String> env = System.getenv(); + for (Class<?> cl : classes) { + if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { + try { + Field field = cl.getDeclaredField("m"); + field.setAccessible(true); + Object obj = field.get(env); + if (obj != null && obj.getClass().getName().equals("java.lang.ProcessEnvironment$StringEnvironment")) { + return (Map<String, String>) obj; + } + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + } + + // for windows + Class<?> processEnvironmentClass; + try { + processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment"); + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + + try { + Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment"); + theCaseInsensitiveEnvironmentField.setAccessible(true); + Object obj = theCaseInsensitiveEnvironmentField.get(null); + return (Map<String, String>) obj; + } + catch (NoSuchFieldException ex) { + // do nothing + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + + try { + Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment"); + theEnvironmentField.setAccessible(true); + Object obj = theEnvironmentField.get(null); + return (Map<String, String>) obj; + } + catch (NoSuchFieldException ex) { + // do nothing + } + catch (Exception ex) { + throw new IllegalStateException(ex); + } + + throw new IllegalStateException(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/env/SystemEnvironmentPropertySourceTests.java b/spring-core/src/test/java/org/springframework/core/env/SystemEnvironmentPropertySourceTests.java new file mode 100644 index 00000000..880868ee --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/env/SystemEnvironmentPropertySourceTests.java @@ -0,0 +1,104 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.core.env; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +/** + * Unit tests for {@link SystemEnvironmentPropertySource}. + * + * @author Chris Beams + * @since 3.1 + */ +public class SystemEnvironmentPropertySourceTests { + + private Map<String, Object> envMap; + private PropertySource<?> ps; + + @Before + public void setUp() { + envMap = new HashMap<String, Object>(); + ps = new SystemEnvironmentPropertySource("sysEnv", envMap); + } + + @Test + public void none() { + //envMap.put("a.key", "a_value"); + + assertThat(ps.containsProperty("a.key"), equalTo(false)); + assertThat(ps.getProperty("a.key"), equalTo(null)); + } + + @Test + public void normalWithoutPeriod() { + envMap.put("akey", "avalue"); + + assertThat(ps.containsProperty("akey"), equalTo(true)); + assertThat(ps.getProperty("akey"), equalTo((Object)"avalue")); + } + + @Test + public void normalWithPeriod() { + envMap.put("a.key", "a.value"); + + assertThat(ps.containsProperty("a.key"), equalTo(true)); + assertThat(ps.getProperty("a.key"), equalTo((Object)"a.value")); + } + + @Test + public void withUnderscore() { + envMap.put("a_key", "a_value"); + + assertThat(ps.containsProperty("a_key"), equalTo(true)); + assertThat(ps.containsProperty("a.key"), equalTo(true)); + + assertThat(ps.getProperty("a_key"), equalTo((Object)"a_value")); + assertThat( ps.getProperty("a.key"), equalTo((Object)"a_value")); + } + + @Test + public void withBothPeriodAndUnderscore() { + envMap.put("a_key", "a_value"); + envMap.put("a.key", "a.value"); + + assertThat(ps.getProperty("a_key"), equalTo((Object)"a_value")); + assertThat( ps.getProperty("a.key"), equalTo((Object)"a.value")); + } + + @Test + public void withUppercase() { + envMap.put("A_KEY", "a_value"); + + assertThat(ps.containsProperty("A_KEY"), equalTo(true)); + assertThat(ps.containsProperty("A.KEY"), equalTo(true)); + assertThat(ps.containsProperty("a_key"), equalTo(true)); + assertThat(ps.containsProperty("a.key"), equalTo(true)); + + assertThat(ps.getProperty("A_KEY"), equalTo((Object)"a_value")); + assertThat(ps.getProperty("A.KEY"), equalTo((Object)"a_value")); + assertThat(ps.getProperty("a_key"), equalTo((Object)"a_value")); + assertThat(ps.getProperty("a.key"), equalTo((Object)"a_value")); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java b/spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java new file mode 100644 index 00000000..bae6fb98 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/ClassPathResourceTests.java @@ -0,0 +1,126 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.io; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Test; + +import static org.hamcrest.Matchers.*; + +/** + * Unit tests that serve as regression tests for the bugs described in SPR-6888 + * and SPR-9413. + * + * @author Chris Beams + * @author Sam Brannen + */ +public class ClassPathResourceTests { + + private static final String PACKAGE_PATH = "org/springframework/core/io"; + private static final String NONEXISTENT_RESOURCE_NAME = "nonexistent.xml"; + private static final String FQ_RESOURCE_PATH = PACKAGE_PATH + '/' + NONEXISTENT_RESOURCE_NAME; + + /** + * Absolute path version of {@link #FQ_RESOURCE_PATH}. + */ + private static final String FQ_RESOURCE_PATH_WITH_LEADING_SLASH = '/' + FQ_RESOURCE_PATH; + + private static final Pattern DESCRIPTION_PATTERN = Pattern.compile("^class path resource \\[(.+?)\\]$"); + + + private void assertDescriptionContainsExpectedPath(ClassPathResource resource, String expectedPath) { + Matcher matcher = DESCRIPTION_PATTERN.matcher(resource.getDescription()); + assertTrue(matcher.matches()); + assertEquals(1, matcher.groupCount()); + String match = matcher.group(1); + + assertEquals(expectedPath, match); + } + + private void assertExceptionContainsFullyQualifiedPath(ClassPathResource resource) { + try { + resource.getInputStream(); + fail("FileNotFoundException expected for resource: " + resource); + } + catch (IOException ex) { + assertThat(ex, instanceOf(FileNotFoundException.class)); + assertThat(ex.getMessage(), containsString(FQ_RESOURCE_PATH)); + } + } + + @Test + public void stringConstructorRaisesExceptionWithFullyQualifiedPath() { + assertExceptionContainsFullyQualifiedPath(new ClassPathResource(FQ_RESOURCE_PATH)); + } + + @Test + public void classLiteralConstructorRaisesExceptionWithFullyQualifiedPath() { + assertExceptionContainsFullyQualifiedPath(new ClassPathResource(NONEXISTENT_RESOURCE_NAME, this.getClass())); + } + + @Test + public void classLoaderConstructorRaisesExceptionWithFullyQualifiedPath() { + assertExceptionContainsFullyQualifiedPath(new ClassPathResource(FQ_RESOURCE_PATH, + this.getClass().getClassLoader())); + } + + @Test + public void getDescriptionWithStringConstructor() { + assertDescriptionContainsExpectedPath(new ClassPathResource(FQ_RESOURCE_PATH), FQ_RESOURCE_PATH); + } + + @Test + public void getDescriptionWithStringConstructorAndLeadingSlash() { + assertDescriptionContainsExpectedPath(new ClassPathResource(FQ_RESOURCE_PATH_WITH_LEADING_SLASH), + FQ_RESOURCE_PATH); + } + + @Test + public void getDescriptionWithClassLiteralConstructor() { + assertDescriptionContainsExpectedPath(new ClassPathResource(NONEXISTENT_RESOURCE_NAME, this.getClass()), + FQ_RESOURCE_PATH); + } + + @Test + public void getDescriptionWithClassLiteralConstructorAndLeadingSlash() { + assertDescriptionContainsExpectedPath( + new ClassPathResource(FQ_RESOURCE_PATH_WITH_LEADING_SLASH, this.getClass()), FQ_RESOURCE_PATH); + } + + @Test + public void getDescriptionWithClassLoaderConstructor() { + assertDescriptionContainsExpectedPath( + new ClassPathResource(FQ_RESOURCE_PATH, this.getClass().getClassLoader()), FQ_RESOURCE_PATH); + } + + @Test + public void getDescriptionWithClassLoaderConstructorAndLeadingSlash() { + assertDescriptionContainsExpectedPath(new ClassPathResource(FQ_RESOURCE_PATH_WITH_LEADING_SLASH, + this.getClass().getClassLoader()), FQ_RESOURCE_PATH); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/io/ResourceEditorTests.java b/spring-core/src/test/java/org/springframework/core/io/ResourceEditorTests.java new file mode 100644 index 00000000..ff6a1fc6 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/ResourceEditorTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * 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 org.springframework.core.io; + +import java.beans.PropertyEditor; + +import static org.junit.Assert.*; +import org.junit.Test; +import org.springframework.core.env.StandardEnvironment; + +/** + * Unit tests for the {@link ResourceEditor} class. + * + * @author Rick Evans + * @author Arjen Poutsma + * @author Dave Syer + */ +public final class ResourceEditorTests { + + @Test + public void sunnyDay() throws Exception { + PropertyEditor editor = new ResourceEditor(); + editor.setAsText("classpath:org/springframework/core/io/ResourceEditorTests.class"); + Resource resource = (Resource) editor.getValue(); + assertNotNull(resource); + assertTrue(resource.exists()); + } + + @Test(expected = IllegalArgumentException.class) + public void ctorWithNullCtorArgs() throws Exception { + new ResourceEditor(null, null); + } + + @Test + public void setAndGetAsTextWithNull() throws Exception { + PropertyEditor editor = new ResourceEditor(); + editor.setAsText(null); + assertEquals("", editor.getAsText()); + } + + @Test + public void setAndGetAsTextWithWhitespaceResource() throws Exception { + PropertyEditor editor = new ResourceEditor(); + editor.setAsText(" "); + assertEquals("", editor.getAsText()); + } + + @Test + public void testSystemPropertyReplacement() { + PropertyEditor editor = new ResourceEditor(); + System.setProperty("test.prop", "foo"); + try { + editor.setAsText("${test.prop}-${bar}"); + Resource resolved = (Resource) editor.getValue(); + assertEquals("foo-${bar}", resolved.getFilename()); + } + finally { + System.getProperties().remove("test.prop"); + } + } + + @Test(expected=IllegalArgumentException.class) + public void testStrictSystemPropertyReplacement() { + PropertyEditor editor = new ResourceEditor(new DefaultResourceLoader(), new StandardEnvironment(), false); + System.setProperty("test.prop", "foo"); + try { + editor.setAsText("${test.prop}-${bar}"); + Resource resolved = (Resource) editor.getValue(); + assertEquals("foo-${bar}", resolved.getFilename()); + } + finally { + System.getProperties().remove("test.prop"); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java b/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java new file mode 100644 index 00000000..2da1da51 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/ResourceTests.java @@ -0,0 +1,254 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.io; + +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.HashSet; + +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.util.FileCopyUtils; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + * @author Chris Beams + * @since 09.09.2004 + */ +public class ResourceTests { + + @Test + public void testByteArrayResource() throws IOException { + Resource resource = new ByteArrayResource("testString".getBytes()); + assertTrue(resource.exists()); + assertFalse(resource.isOpen()); + String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream())); + assertEquals("testString", content); + assertEquals(resource, new ByteArrayResource("testString".getBytes())); + } + + @Test + public void testByteArrayResourceWithDescription() throws IOException { + Resource resource = new ByteArrayResource("testString".getBytes(), "my description"); + assertTrue(resource.exists()); + assertFalse(resource.isOpen()); + String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream())); + assertEquals("testString", content); + assertEquals("my description", resource.getDescription()); + assertEquals(resource, new ByteArrayResource("testString".getBytes())); + } + + @Test + public void testInputStreamResource() throws IOException { + InputStream is = new ByteArrayInputStream("testString".getBytes()); + Resource resource = new InputStreamResource(is); + assertTrue(resource.exists()); + assertTrue(resource.isOpen()); + String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream())); + assertEquals("testString", content); + assertEquals(resource, new InputStreamResource(is)); + } + + @Test + public void testInputStreamResourceWithDescription() throws IOException { + InputStream is = new ByteArrayInputStream("testString".getBytes()); + Resource resource = new InputStreamResource(is, "my description"); + assertTrue(resource.exists()); + assertTrue(resource.isOpen()); + String content = FileCopyUtils.copyToString(new InputStreamReader(resource.getInputStream())); + assertEquals("testString", content); + assertEquals("my description", resource.getDescription()); + assertEquals(resource, new InputStreamResource(is)); + } + + @Test + public void testClassPathResource() throws IOException { + Resource resource = new ClassPathResource("org/springframework/core/io/Resource.class"); + doTestResource(resource); + Resource resource2 = new ClassPathResource("org/springframework/core/../core/io/./Resource.class"); + assertEquals(resource, resource2); + Resource resource3 = new ClassPathResource("org/springframework/core/").createRelative("../core/io/./Resource.class"); + assertEquals(resource, resource3); + + // Check whether equal/hashCode works in a HashSet. + HashSet<Resource> resources = new HashSet<Resource>(); + resources.add(resource); + resources.add(resource2); + assertEquals(1, resources.size()); + } + + @Test + public void testClassPathResourceWithClassLoader() throws IOException { + Resource resource = + new ClassPathResource("org/springframework/core/io/Resource.class", getClass().getClassLoader()); + doTestResource(resource); + assertEquals(resource, + new ClassPathResource("org/springframework/core/../core/io/./Resource.class", getClass().getClassLoader())); + } + + @Test + public void testClassPathResourceWithClass() throws IOException { + Resource resource = new ClassPathResource("Resource.class", getClass()); + doTestResource(resource); + assertEquals(resource, new ClassPathResource("Resource.class", getClass())); + } + + @Ignore // passes under eclipse, fails under ant + @Test + public void testFileSystemResource() throws IOException { + Resource resource = new FileSystemResource(getClass().getResource("Resource.class").getFile()); + doTestResource(resource); + assertEquals(new FileSystemResource(getClass().getResource("Resource.class").getFile()), resource); + Resource resource2 = new FileSystemResource("core/io/Resource.class"); + assertEquals(resource2, new FileSystemResource("core/../core/io/./Resource.class")); + } + + @Test + public void testUrlResource() throws IOException { + Resource resource = new UrlResource(getClass().getResource("Resource.class")); + doTestResource(resource); + assertEquals(new UrlResource(getClass().getResource("Resource.class")), resource); + Resource resource2 = new UrlResource("file:core/io/Resource.class"); + assertEquals(resource2, new UrlResource("file:core/../core/io/./Resource.class")); + } + + private void doTestResource(Resource resource) throws IOException { + assertEquals("Resource.class", resource.getFilename()); + assertTrue(resource.getURL().getFile().endsWith("Resource.class")); + + Resource relative1 = resource.createRelative("ClassPathResource.class"); + assertEquals("ClassPathResource.class", relative1.getFilename()); + assertTrue(relative1.getURL().getFile().endsWith("ClassPathResource.class")); + assertTrue(relative1.exists()); + + Resource relative2 = resource.createRelative("support/ResourcePatternResolver.class"); + assertEquals("ResourcePatternResolver.class", relative2.getFilename()); + assertTrue(relative2.getURL().getFile().endsWith("ResourcePatternResolver.class")); + assertTrue(relative2.exists()); + + /* + Resource relative3 = resource.createRelative("../SpringVersion.class"); + assertEquals("SpringVersion.class", relative3.getFilename()); + assertTrue(relative3.getURL().getFile().endsWith("SpringVersion.class")); + assertTrue(relative3.exists()); + */ + } + + @Test + public void testClassPathResourceWithRelativePath() throws IOException { + Resource resource = new ClassPathResource("dir/"); + Resource relative = resource.createRelative("subdir"); + assertEquals(new ClassPathResource("dir/subdir"), relative); + } + + @Test + public void testFileSystemResourceWithRelativePath() throws IOException { + Resource resource = new FileSystemResource("dir/"); + Resource relative = resource.createRelative("subdir"); + assertEquals(new FileSystemResource("dir/subdir"), relative); + } + + @Test + public void testUrlResourceWithRelativePath() throws IOException { + Resource resource = new UrlResource("file:dir/"); + Resource relative = resource.createRelative("subdir"); + assertEquals(new UrlResource("file:dir/subdir"), relative); + } + + @Ignore @Test // this test is quite slow. TODO: re-enable with JUnit categories + public void testNonFileResourceExists() throws Exception { + Resource resource = new UrlResource("http://www.springframework.org"); + assertTrue(resource.exists()); + } + + @Test + public void testAbstractResourceExceptions() throws Exception { + final String name = "test-resource"; + + Resource resource = new AbstractResource() { + @Override + public String getDescription() { + return name; + } + @Override + public InputStream getInputStream() { + return null; + } + }; + + try { + resource.getURL(); + fail("FileNotFoundException should have been thrown"); + } + catch (FileNotFoundException ex) { + assertTrue(ex.getMessage().indexOf(name) != -1); + } + try { + resource.getFile(); + fail("FileNotFoundException should have been thrown"); + } + catch (FileNotFoundException ex) { + assertTrue(ex.getMessage().indexOf(name) != -1); + } + try { + resource.createRelative("/testing"); + fail("FileNotFoundException should have been thrown"); + } + catch (FileNotFoundException ex) { + assertTrue(ex.getMessage().indexOf(name) != -1); + } + + assertThat(resource.getFilename(), nullValue()); + } + + @Test + public void testContentLength() throws IOException { + AbstractResource resource = new AbstractResource() { + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(new byte[] { 'a', 'b', 'c' }); + } + @Override + public String getDescription() { + return null; + } + }; + assertThat(resource.contentLength(), is(3L)); + } + + @Test(expected=IllegalStateException.class) + public void testContentLength_withNullInputStream() throws IOException { + AbstractResource resource = new AbstractResource() { + @Override + public InputStream getInputStream() throws IOException { + return null; + } + @Override + public String getDescription() { + return null; + } + }; + resource.contentLength(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/io/example.properties b/spring-core/src/test/java/org/springframework/core/io/example.properties new file mode 100644 index 00000000..74d0a43f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/example.properties @@ -0,0 +1 @@ +foo=bar diff --git a/spring-core/src/test/java/org/springframework/core/io/example.xml b/spring-core/src/test/java/org/springframework/core/io/example.xml new file mode 100644 index 00000000..1d638537 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/example.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> +<properties version="1.0"> + <entry key="foo">bar</entry> +</properties> + diff --git a/spring-core/src/test/java/org/springframework/core/io/support/DummyFactory.java b/spring-core/src/test/java/org/springframework/core/io/support/DummyFactory.java new file mode 100644 index 00000000..12d98292 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/support/DummyFactory.java @@ -0,0 +1,28 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.io.support; + +/** + * Used by {@link SpringFactoriesLoaderTests} + * + * @author Arjen Poutsma + */ +public interface DummyFactory { + + String getString(); + +} diff --git a/spring-core/src/test/java/org/springframework/core/io/support/MyDummyFactory1.java b/spring-core/src/test/java/org/springframework/core/io/support/MyDummyFactory1.java new file mode 100644 index 00000000..11dd7ebf --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/support/MyDummyFactory1.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.io.support; + +import org.springframework.core.annotation.Order; + +/** + * Used by {@link SpringFactoriesLoaderTests} + * + * @author Arjen Poutsma + */ +@Order(1) +public class MyDummyFactory1 implements DummyFactory { + + @Override + public String getString() { + return "Foo"; + } +} diff --git a/spring-core/src/test/java/org/springframework/core/io/support/MyDummyFactory2.java b/spring-core/src/test/java/org/springframework/core/io/support/MyDummyFactory2.java new file mode 100644 index 00000000..5105c6b4 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/support/MyDummyFactory2.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.io.support; + +import org.springframework.core.annotation.Order; + +/** + * Used by {@link SpringFactoriesLoaderTests} + * + * @author Arjen Poutsma + */ +@Order(2) +public class MyDummyFactory2 implements DummyFactory { + + @Override + public String getString() { + return "Bar"; + } +} diff --git a/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java b/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java new file mode 100644 index 00000000..b494c708 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.java @@ -0,0 +1,165 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.io.support; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.core.io.Resource; + +/** + * If this test case fails, uncomment diagnostics in + * {@code assertProtocolAndFilenames} method. + * + * @author Oliver Hutchison + * @author Juergen Hoeller + * @author Chris Beams + * @since 17.11.2004 + */ +public class PathMatchingResourcePatternResolverTests { + + private static final String[] CLASSES_IN_CORE_IO_SUPPORT = + new String[] {"EncodedResource.class", "LocalizedResourceHelper.class", + "PathMatchingResourcePatternResolver.class", + "PropertiesLoaderSupport.class", "PropertiesLoaderUtils.class", + "ResourceArrayPropertyEditor.class", + "ResourcePatternResolver.class", "ResourcePatternUtils.class"}; + + private static final String[] TEST_CLASSES_IN_CORE_IO_SUPPORT = + new String[] {"PathMatchingResourcePatternResolverTests.class"}; + + private static final String[] CLASSES_IN_COMMONSLOGGING = + new String[] {"Log.class", "LogConfigurationException.class", "LogFactory.class", + "LogFactory$1.class", "LogFactory$2.class", "LogFactory$3.class", + "LogFactory$4.class", "LogFactory$5.class", "LogFactory$6.class", + "LogSource.class"}; + + private PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + + + @Test + public void testInvalidPrefixWithPatternElementInIt() throws IOException { + try { + resolver.getResources("xx**:**/*.xy"); + fail("Should have thrown FileNotFoundException"); + } + catch (FileNotFoundException ex) { + // expected + } + } + + @Test + public void testSingleResourceOnFileSystem() throws IOException { + Resource[] resources = + resolver.getResources("org/springframework/core/io/support/PathMatchingResourcePatternResolverTests.class"); + assertEquals(1, resources.length); + assertProtocolAndFilename(resources[0], "file", "PathMatchingResourcePatternResolverTests.class"); + } + + @Test + public void testSingleResourceInJar() throws IOException { + Resource[] resources = resolver.getResources("java/net/URL.class"); + assertEquals(1, resources.length); + assertProtocolAndFilename(resources[0], "jar", "URL.class"); + } + + @Ignore // passes under eclipse, fails under ant + @Test + public void testClasspathStarWithPatternOnFileSystem() throws IOException { + Resource[] resources = resolver.getResources("classpath*:org/springframework/core/io/sup*/*.class"); + // Have to exclude Clover-generated class files here, + // as we might be running as part of a Clover test run. + List noCloverResources = new ArrayList(); + for (int i = 0; i < resources.length; i++) { + if (resources[i].getFilename().indexOf("$__CLOVER_") == -1) { + noCloverResources.add(resources[i]); + } + } + resources = (Resource[]) noCloverResources.toArray(new Resource[noCloverResources.size()]); + assertProtocolAndFilenames(resources, "file", CLASSES_IN_CORE_IO_SUPPORT, TEST_CLASSES_IN_CORE_IO_SUPPORT); + } + + @Test + public void testClasspathWithPatternInJar() throws IOException { + Resource[] resources = resolver.getResources("classpath:org/apache/commons/logging/*.class"); + assertProtocolAndFilenames(resources, "jar", CLASSES_IN_COMMONSLOGGING); + } + + @Test + public void testClasspathStartWithPatternInJar() throws IOException { + Resource[] resources = resolver.getResources("classpath*:org/apache/commons/logging/*.class"); + assertProtocolAndFilenames(resources, "jar", CLASSES_IN_COMMONSLOGGING); + } + + private void assertProtocolAndFilename(Resource resource, String urlProtocol, String fileName) throws IOException { + assertProtocolAndFilenames(new Resource[] {resource}, urlProtocol, new String[] {fileName}); + } + + private void assertProtocolAndFilenames( + Resource[] resources, String urlProtocol, String[] fileNames1, String[] fileNames2) throws IOException { + List fileNames = new ArrayList(Arrays.asList(fileNames1)); + fileNames.addAll(Arrays.asList(fileNames2)); + assertProtocolAndFilenames(resources, urlProtocol, (String[]) fileNames.toArray(new String[fileNames.size()])); + } + + private void assertProtocolAndFilenames(Resource[] resources, String urlProtocol, String[] fileNames) + throws IOException { + + // Uncomment the following if you encounter problems with matching against the file system + // It shows file locations. +// String[] actualNames = new String[resources.length]; +// for (int i = 0; i < resources.length; i++) { +// actualNames[i] = resources[i].getFilename(); +// } +// List sortedActualNames = new LinkedList(Arrays.asList(actualNames)); +// List expectedNames = new LinkedList(Arrays.asList(fileNames)); +// Collections.sort(sortedActualNames); +// Collections.sort(expectedNames); +// +// System.out.println("-----------"); +// System.out.println("Expected: " + StringUtils.collectionToCommaDelimitedString(expectedNames)); +// System.out.println("Actual: " + StringUtils.collectionToCommaDelimitedString(sortedActualNames)); +// for (int i = 0; i < resources.length; i++) { +// System.out.println(resources[i]); +// } + + assertEquals("Correct number of files found", fileNames.length, resources.length); + for (int i = 0; i < resources.length; i++) { + Resource resource = resources[i]; + assertEquals(urlProtocol, resource.getURL().getProtocol()); + assertFilenameIn(resource, fileNames); + } + } + + private void assertFilenameIn(Resource resource, String[] fileNames) { + for (int i = 0; i < fileNames.length; i++) { + if (resource.getFilename().endsWith(fileNames[i])) { + return; + } + } + fail("resource [" + resource + "] does not have a filename that matches and of the names in 'fileNames'"); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/io/support/ResourceArrayPropertyEditorTests.java b/spring-core/src/test/java/org/springframework/core/io/support/ResourceArrayPropertyEditorTests.java new file mode 100644 index 00000000..a12d2c09 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/support/ResourceArrayPropertyEditorTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.io.support; + +import java.beans.PropertyEditor; + +import static org.junit.Assert.*; +import org.junit.Test; + +import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.Resource; + +/** + * @author Dave Syer + * @author Juergen Hoeller + */ +public class ResourceArrayPropertyEditorTests { + + @Test + public void testVanillaResource() throws Exception { + PropertyEditor editor = new ResourceArrayPropertyEditor(); + editor.setAsText("classpath:org/springframework/core/io/support/ResourceArrayPropertyEditor.class"); + Resource[] resources = (Resource[]) editor.getValue(); + assertNotNull(resources); + assertTrue(resources[0].exists()); + } + + @Test + public void testPatternResource() throws Exception { + // N.B. this will sometimes fail if you use classpath: instead of classpath*:. + // The result depends on the classpath - if test-classes are segregated from classes + // and they come first on the classpath (like in Maven) then it breaks, if classes + // comes first (like in Spring Build) then it is OK. + PropertyEditor editor = new ResourceArrayPropertyEditor(); + editor.setAsText("classpath*:org/springframework/core/io/support/Resource*Editor.class"); + Resource[] resources = (Resource[]) editor.getValue(); + assertNotNull(resources); + assertTrue(resources[0].exists()); + } + + @Test + public void testSystemPropertyReplacement() { + PropertyEditor editor = new ResourceArrayPropertyEditor(); + System.setProperty("test.prop", "foo"); + try { + editor.setAsText("${test.prop}-${bar}"); + Resource[] resources = (Resource[]) editor.getValue(); + assertEquals("foo-${bar}", resources[0].getFilename()); + } + finally { + System.getProperties().remove("test.prop"); + } + } + + @Test(expected=IllegalArgumentException.class) + public void testStrictSystemPropertyReplacement() { + PropertyEditor editor = new ResourceArrayPropertyEditor( + new PathMatchingResourcePatternResolver(), new StandardEnvironment(), + false); + System.setProperty("test.prop", "foo"); + try { + editor.setAsText("${test.prop}-${bar}"); + Resource[] resources = (Resource[]) editor.getValue(); + assertEquals("foo-${bar}", resources[0].getFilename()); + } + finally { + System.getProperties().remove("test.prop"); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/io/support/ResourcePropertySourceTests.java b/spring-core/src/test/java/org/springframework/core/io/support/ResourcePropertySourceTests.java new file mode 100644 index 00000000..1bbc3cb2 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/io/support/ResourcePropertySourceTests.java @@ -0,0 +1,102 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.io.support; + +import java.io.IOException; + +import org.junit.Test; + +import org.springframework.core.env.PropertySource; +import org.springframework.core.io.ByteArrayResource; +import org.springframework.core.io.ClassPathResource; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +/** + * Unit tests for {@link ResourcePropertySource}. + * + * @author Chris Beams + * @since 3.1 + */ +public class ResourcePropertySourceTests { + + private static final String PROPERTIES_PATH = "org/springframework/core/io/example.properties"; + private static final String PROPERTIES_LOCATION = "classpath:" + PROPERTIES_PATH; + private static final String PROPERTIES_RESOURCE_DESCRIPTION = "class path resource [" + PROPERTIES_PATH + "]"; + + private static final String XML_PROPERTIES_PATH = "org/springframework/core/io/example.xml"; + private static final String XML_PROPERTIES_LOCATION = "classpath:" + XML_PROPERTIES_PATH; + private static final String XML_PROPERTIES_RESOURCE_DESCRIPTION = "class path resource [" + XML_PROPERTIES_PATH + "]"; + + @Test + public void withLocationAndGeneratedName() throws IOException { + PropertySource<?> ps = new ResourcePropertySource(PROPERTIES_LOCATION); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is(PROPERTIES_RESOURCE_DESCRIPTION)); + } + + @Test + public void xmlWithLocationAndGeneratedName() throws IOException { + PropertySource<?> ps = new ResourcePropertySource(XML_PROPERTIES_LOCATION); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is(XML_PROPERTIES_RESOURCE_DESCRIPTION)); + } + + @Test + public void withLocationAndExplicitName() throws IOException { + PropertySource<?> ps = new ResourcePropertySource("ps1", PROPERTIES_LOCATION); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is("ps1")); + } + + @Test + public void withLocationAndExplicitNameAndExplicitClassLoader() throws IOException { + PropertySource<?> ps = new ResourcePropertySource("ps1", PROPERTIES_LOCATION, getClass().getClassLoader()); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is("ps1")); + } + + @Test + public void withLocationAndGeneratedNameAndExplicitClassLoader() throws IOException { + PropertySource<?> ps = new ResourcePropertySource(PROPERTIES_LOCATION, getClass().getClassLoader()); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is(PROPERTIES_RESOURCE_DESCRIPTION)); + } + + @Test + public void withResourceAndGeneratedName() throws IOException { + PropertySource<?> ps = new ResourcePropertySource(new ClassPathResource(PROPERTIES_PATH)); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is(PROPERTIES_RESOURCE_DESCRIPTION)); + } + + @Test + public void withResourceAndExplicitName() throws IOException { + PropertySource<?> ps = new ResourcePropertySource("ps1", new ClassPathResource(PROPERTIES_PATH)); + assertEquals(ps.getProperty("foo"), "bar"); + assertThat(ps.getName(), is("ps1")); + } + + @Test + public void withResourceHavingNoDescriptionAndGeneratedName() throws IOException { + PropertySource<?> ps = new ResourcePropertySource(new ByteArrayResource("foo=bar".getBytes(), "")); + assertEquals(ps.getProperty("foo"), "bar"); + assertTrue(ps.getName().startsWith("ByteArrayResource@")); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/serializer/SerializationConverterTests.java b/spring-core/src/test/java/org/springframework/core/serializer/SerializationConverterTests.java new file mode 100644 index 00000000..42c724ec --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/serializer/SerializationConverterTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * 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 org.springframework.core.serializer; + +import java.io.NotSerializableException; +import java.io.Serializable; + +import static org.junit.Assert.*; +import org.junit.Test; + +import org.springframework.core.serializer.support.DeserializingConverter; +import org.springframework.core.serializer.support.SerializationFailedException; +import org.springframework.core.serializer.support.SerializingConverter; + +/** + * @author Gary Russell + * @author Mark Fisher + * @since 3.0.5 + */ +public class SerializationConverterTests { + + @Test + public void serializeAndDeserializeString() { + SerializingConverter toBytes = new SerializingConverter(); + byte[] bytes = toBytes.convert("Testing"); + DeserializingConverter fromBytes = new DeserializingConverter(); + assertEquals("Testing", fromBytes.convert(bytes)); + } + + @Test + public void nonSerializableObject() { + SerializingConverter toBytes = new SerializingConverter(); + try { + toBytes.convert(new Object()); + fail("Expected IllegalArgumentException"); + } + catch (SerializationFailedException e) { + assertNotNull(e.getCause()); + assertTrue(e.getCause() instanceof IllegalArgumentException); + } + } + + @Test + public void nonSerializableField() { + SerializingConverter toBytes = new SerializingConverter(); + try { + toBytes.convert(new UnSerializable()); + fail("Expected SerializationFailureException"); + } + catch (SerializationFailedException e) { + assertNotNull(e.getCause()); + assertTrue(e.getCause() instanceof NotSerializableException); + } + } + + @Test(expected = SerializationFailedException.class) + public void deserializationFailure() { + DeserializingConverter fromBytes = new DeserializingConverter(); + fromBytes.convert("Junk".getBytes()); + } + + + class UnSerializable implements Serializable { + + private static final long serialVersionUID = 1L; + + @SuppressWarnings("unused") + private Object object; + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/style/ToStringCreatorTests.java b/spring-core/src/test/java/org/springframework/core/style/ToStringCreatorTests.java new file mode 100644 index 00000000..f353d34f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/style/ToStringCreatorTests.java @@ -0,0 +1,127 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.style; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +import org.springframework.util.ObjectUtils; + +/** + * @author Keith Donald + */ +public class ToStringCreatorTests extends TestCase { + + private SomeObject s1, s2, s3; + + @Override + protected void setUp() throws Exception { + s1 = new SomeObject() { + public String toString() { + return "A"; + } + }; + s2 = new SomeObject() { + public String toString() { + return "B"; + } + }; + s3 = new SomeObject() { + public String toString() { + return "C"; + } + }; + } + + public void testDefaultStyleMap() { + final Map map = getMap(); + Object stringy = new Object() { + public String toString() { + return new ToStringCreator(this).append("familyFavoriteSport", map).toString(); + } + }; + assertEquals("[ToStringCreatorTests.4@" + ObjectUtils.getIdentityHexString(stringy) + + " familyFavoriteSport = map['Keri' -> 'Softball', 'Scot' -> 'Fishing', 'Keith' -> 'Flag Football']]", + stringy.toString()); + } + + private Map getMap() { + Map map = new LinkedHashMap(3); + map.put("Keri", "Softball"); + map.put("Scot", "Fishing"); + map.put("Keith", "Flag Football"); + return map; + } + + public void testDefaultStyleArray() { + SomeObject[] array = new SomeObject[] { s1, s2, s3 }; + String str = new ToStringCreator(array).toString(); + assertEquals("[@" + ObjectUtils.getIdentityHexString(array) + + " array<ToStringCreatorTests.SomeObject>[A, B, C]]", str); + } + + public void testPrimitiveArrays() { + int[] integers = new int[] { 0, 1, 2, 3, 4 }; + String str = new ToStringCreator(integers).toString(); + assertEquals("[@" + ObjectUtils.getIdentityHexString(integers) + " array<Integer>[0, 1, 2, 3, 4]]", str); + } + + public void testList() { + List list = new ArrayList(); + list.add(s1); + list.add(s2); + list.add(s3); + String str = new ToStringCreator(this).append("myLetters", list).toString(); + assertEquals("[ToStringCreatorTests@" + ObjectUtils.getIdentityHexString(this) + " myLetters = list[A, B, C]]", + str); + } + + public void testSet() { + Set set = new LinkedHashSet<>(3); + set.add(s1); + set.add(s2); + set.add(s3); + String str = new ToStringCreator(this).append("myLetters", set).toString(); + assertEquals("[ToStringCreatorTests@" + ObjectUtils.getIdentityHexString(this) + " myLetters = set[A, B, C]]", + str); + } + + public void testClass() { + String str = new ToStringCreator(this).append("myClass", this.getClass()).toString(); + assertEquals("[ToStringCreatorTests@" + ObjectUtils.getIdentityHexString(this) + + " myClass = ToStringCreatorTests]", str); + } + + public void testMethod() throws Exception { + String str = new ToStringCreator(this).append("myMethod", this.getClass().getMethod("testMethod")) + .toString(); + assertEquals("[ToStringCreatorTests@" + ObjectUtils.getIdentityHexString(this) + + " myMethod = testMethod@ToStringCreatorTests]", str); + } + + + public static class SomeObject { + + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java b/spring-core/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java new file mode 100644 index 00000000..57560a25 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/task/SimpleAsyncTaskExecutorTests.java @@ -0,0 +1,141 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.core.task; + +import java.util.concurrent.ThreadFactory; + +import junit.framework.TestCase; + +import org.springframework.util.ConcurrencyThrottleSupport; + +/** + * @author Rick Evans + * @author Juergen Hoeller + */ +public final class SimpleAsyncTaskExecutorTests extends TestCase { + + public void testCannotExecuteWhenConcurrencyIsSwitchedOff() throws Exception { + SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(); + executor.setConcurrencyLimit(ConcurrencyThrottleSupport.NO_CONCURRENCY); + assertFalse(executor.isThrottleActive()); + try { + executor.execute(new NoOpRunnable()); + } + catch (IllegalStateException expected) { + } + } + + public void testThrottleIsNotActiveByDefault() throws Exception { + SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(); + assertFalse("Concurrency throttle must not default to being active (on)", executor.isThrottleActive()); + } + + public void testThreadNameGetsSetCorrectly() throws Exception { + final String customPrefix = "chankPop#"; + final Object monitor = new Object(); + SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(customPrefix); + ThreadNameHarvester task = new ThreadNameHarvester(monitor); + executeAndWait(executor, task, monitor); + assertTrue(task.getThreadName().startsWith(customPrefix)); + } + + public void testThreadFactoryOverridesDefaults() throws Exception { + final Object monitor = new Object(); + SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "test"); + } + }); + ThreadNameHarvester task = new ThreadNameHarvester(monitor); + executeAndWait(executor, task, monitor); + assertTrue(task.getThreadName().equals("test")); + } + + public void testThrowsExceptionWhenSuppliedWithNullRunnable() throws Exception { + try { + new SimpleAsyncTaskExecutor().execute(null); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + } + + private void executeAndWait(SimpleAsyncTaskExecutor executor, Runnable task, Object monitor) { + synchronized (monitor) { + executor.execute(task); + try { + monitor.wait(); + } + catch (InterruptedException ignored) { + } + } + } + + + private static final class NoOpRunnable implements Runnable { + + @Override + public void run() { + // no-op + } + } + + + private static abstract class AbstractNotifyingRunnable implements Runnable { + + private final Object monitor; + + protected AbstractNotifyingRunnable(Object monitor) { + this.monitor = monitor; + } + + @Override + public final void run() { + synchronized (this.monitor) { + try { + doRun(); + } + finally { + this.monitor.notifyAll(); + } + } + } + + protected abstract void doRun(); + } + + + private static final class ThreadNameHarvester extends AbstractNotifyingRunnable { + + private String threadName; + + protected ThreadNameHarvester(Object monitor) { + super(monitor); + } + + public String getThreadName() { + return this.threadName; + } + + @Override + protected void doRun() { + this.threadName = Thread.currentThread().getName(); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/AbstractClassMetadataMemberClassTests.java b/spring-core/src/test/java/org/springframework/core/type/AbstractClassMetadataMemberClassTests.java new file mode 100644 index 00000000..64802bbe --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/AbstractClassMetadataMemberClassTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.core.type; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +import org.junit.Test; + +/** + * Abstract base class for testing implementations of + * {@link ClassMetadata#getMemberClassNames()}. + * + * @author Chris Beams + * @since 3.1 + */ +public abstract class AbstractClassMetadataMemberClassTests { + + public abstract ClassMetadata getClassMetadataFor(Class<?> clazz); + + @Test + public void withNoMemberClasses() { + ClassMetadata metadata = getClassMetadataFor(L0_a.class); + String[] nestedClasses = metadata.getMemberClassNames(); + assertThat(nestedClasses, equalTo(new String[]{})); + } + + public static class L0_a { + } + + + @Test + public void withPublicMemberClasses() { + ClassMetadata metadata = getClassMetadataFor(L0_b.class); + String[] nestedClasses = metadata.getMemberClassNames(); + assertThat(nestedClasses, equalTo(new String[]{L0_b.L1.class.getName()})); + } + + public static class L0_b { + public static class L1 { } + } + + + @Test + public void withNonPublicMemberClasses() { + ClassMetadata metadata = getClassMetadataFor(L0_c.class); + String[] nestedClasses = metadata.getMemberClassNames(); + assertThat(nestedClasses, equalTo(new String[]{L0_c.L1.class.getName()})); + } + + public static class L0_c { + private static class L1 { } + } + + + @Test + public void againstMemberClass() { + ClassMetadata metadata = getClassMetadataFor(L0_b.L1.class); + String[] nestedClasses = metadata.getMemberClassNames(); + assertThat(nestedClasses, equalTo(new String[]{})); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java new file mode 100644 index 00000000..cb680811 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java @@ -0,0 +1,224 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.type; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Set; + +import org.junit.Test; + +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.stereotype.Component; + +/** + * Unit tests demonstrating that the reflection-based {@link StandardAnnotationMetadata} + * and ASM-based {@code AnnotationMetadataReadingVisitor} produce identical output. + * + * @author Juergen Hoeller + * @author Chris Beams + */ +public class AnnotationMetadataTests { + + @Test + public void testStandardAnnotationMetadata() throws IOException { + AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponent.class, true); + doTestAnnotationInfo(metadata); + doTestMethodAnnotationInfo(metadata); + } + + @Test + public void testAsmAnnotationMetadata() throws IOException { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponent.class.getName()); + AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); + doTestAnnotationInfo(metadata); + doTestMethodAnnotationInfo(metadata); + } + + /** + * In order to preserve backward-compatibility, {@link StandardAnnotationMetadata} + * defaults to return nested annotations and annotation arrays as actual + * Annotation instances. It is recommended for compatibility with ASM-based + * AnnotationMetadata implementations to set the 'nestedAnnotationsAsMap' flag to + * 'true' as is done in the main test above. + */ + @Test + public void testStandardAnnotationMetadata_nestedAnnotationsAsMap_false() throws IOException { + AnnotationMetadata metadata = new StandardAnnotationMetadata(AnnotatedComponent.class); + + AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName()); + Annotation[] nestedAnnoArray = (Annotation[])specialAttrs.get("nestedAnnoArray"); + assertThat(nestedAnnoArray[0], instanceOf(NestedAnno.class)); + } + + private void doTestAnnotationInfo(AnnotationMetadata metadata) { + assertThat(metadata.getClassName(), is(AnnotatedComponent.class.getName())); + assertThat(metadata.isInterface(), is(false)); + assertThat(metadata.isAbstract(), is(false)); + assertThat(metadata.isConcrete(), is(true)); + assertThat(metadata.hasSuperClass(), is(true)); + assertThat(metadata.getSuperClassName(), is(Object.class.getName())); + assertThat(metadata.getInterfaceNames().length, is(1)); + assertThat(metadata.getInterfaceNames()[0], is(Serializable.class.getName())); + + assertThat(metadata.hasAnnotation(Component.class.getName()), is(true)); + assertThat(metadata.hasAnnotation(Scope.class.getName()), is(true)); + assertThat(metadata.hasAnnotation(SpecialAttr.class.getName()), is(true)); + assertThat(metadata.getAnnotationTypes().size(), is(3)); + assertThat(metadata.getAnnotationTypes().contains(Component.class.getName()), is(true)); + assertThat(metadata.getAnnotationTypes().contains(Scope.class.getName()), is(true)); + assertThat(metadata.getAnnotationTypes().contains(SpecialAttr.class.getName()), is(true)); + + AnnotationAttributes compAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(Component.class.getName()); + assertThat(compAttrs.size(), is(1)); + assertThat(compAttrs.getString("value"), is("myName")); + AnnotationAttributes scopeAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(Scope.class.getName()); + assertThat(scopeAttrs.size(), is(1)); + assertThat(scopeAttrs.getString("value"), is("myScope")); + { // perform tests with classValuesAsString = false (the default) + AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName()); + assertThat(specialAttrs.size(), is(6)); + assertTrue(String.class.isAssignableFrom(specialAttrs.getClass("clazz"))); + assertTrue(specialAttrs.getEnum("state").equals(Thread.State.NEW)); + + AnnotationAttributes nestedAnno = specialAttrs.getAnnotation("nestedAnno"); + assertThat("na", is(nestedAnno.getString("value"))); + assertTrue(nestedAnno.getEnum("anEnum").equals(SomeEnum.LABEL1)); + assertArrayEquals(new Class[]{String.class}, (Class[])nestedAnno.get("classArray")); + + AnnotationAttributes[] nestedAnnoArray = specialAttrs.getAnnotationArray("nestedAnnoArray"); + assertThat(nestedAnnoArray.length, is(2)); + assertThat(nestedAnnoArray[0].getString("value"), is("default")); + assertTrue(nestedAnnoArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT)); + assertArrayEquals(new Class[]{Void.class}, (Class[])nestedAnnoArray[0].get("classArray")); + assertThat(nestedAnnoArray[1].getString("value"), is("na1")); + assertTrue(nestedAnnoArray[1].getEnum("anEnum").equals(SomeEnum.LABEL2)); + assertArrayEquals(new Class[]{Number.class}, (Class[])nestedAnnoArray[1].get("classArray")); + assertArrayEquals(new Class[]{Number.class}, nestedAnnoArray[1].getClassArray("classArray")); + + AnnotationAttributes optional = specialAttrs.getAnnotation("optional"); + assertThat(optional.getString("value"), is("optional")); + assertTrue(optional.getEnum("anEnum").equals(SomeEnum.DEFAULT)); + assertArrayEquals(new Class[]{Void.class}, (Class[])optional.get("classArray")); + assertArrayEquals(new Class[]{Void.class}, optional.getClassArray("classArray")); + + AnnotationAttributes[] optionalArray = specialAttrs.getAnnotationArray("optionalArray"); + assertThat(optionalArray.length, is(1)); + assertThat(optionalArray[0].getString("value"), is("optional")); + assertTrue(optionalArray[0].getEnum("anEnum").equals(SomeEnum.DEFAULT)); + assertArrayEquals(new Class[]{Void.class}, (Class[])optionalArray[0].get("classArray")); + assertArrayEquals(new Class[]{Void.class}, optionalArray[0].getClassArray("classArray")); + } + { // perform tests with classValuesAsString = true + AnnotationAttributes specialAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(SpecialAttr.class.getName(), true); + assertThat(specialAttrs.size(), is(6)); + assertThat(specialAttrs.get("clazz"), is((Object)String.class.getName())); + assertThat(specialAttrs.getString("clazz"), is(String.class.getName())); + + AnnotationAttributes nestedAnno = specialAttrs.getAnnotation("nestedAnno"); + assertArrayEquals(new String[]{String.class.getName()}, nestedAnno.getStringArray("classArray")); + assertArrayEquals(new String[]{String.class.getName()}, nestedAnno.getStringArray("classArray")); + + AnnotationAttributes[] nestedAnnoArray = specialAttrs.getAnnotationArray("nestedAnnoArray"); + assertArrayEquals(new String[]{Void.class.getName()}, (String[])nestedAnnoArray[0].get("classArray")); + assertArrayEquals(new String[]{Void.class.getName()}, nestedAnnoArray[0].getStringArray("classArray")); + assertArrayEquals(new String[]{Number.class.getName()}, (String[])nestedAnnoArray[1].get("classArray")); + assertArrayEquals(new String[]{Number.class.getName()}, nestedAnnoArray[1].getStringArray("classArray")); + + AnnotationAttributes optional = specialAttrs.getAnnotation("optional"); + assertArrayEquals(new String[]{Void.class.getName()}, (String[])optional.get("classArray")); + assertArrayEquals(new String[]{Void.class.getName()}, optional.getStringArray("classArray")); + + AnnotationAttributes[] optionalArray = specialAttrs.getAnnotationArray("optionalArray"); + assertArrayEquals(new String[]{Void.class.getName()}, (String[])optionalArray[0].get("classArray")); + assertArrayEquals(new String[]{Void.class.getName()}, optionalArray[0].getStringArray("classArray")); + } + } + + private void doTestMethodAnnotationInfo(AnnotationMetadata classMetadata) { + Set<MethodMetadata> methods = classMetadata.getAnnotatedMethods(TestAutowired.class.getName()); + assertThat(methods.size(), is(1)); + for (MethodMetadata methodMetadata : methods) { + assertThat(methodMetadata.isAnnotated(TestAutowired.class.getName()), is(true)); + } + } + + public static enum SomeEnum { + LABEL1, LABEL2, DEFAULT; + } + + @Target({}) + @Retention(RetentionPolicy.RUNTIME) + public @interface NestedAnno { + String value() default "default"; + SomeEnum anEnum() default SomeEnum.DEFAULT; + Class<?>[] classArray() default Void.class; + } + + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + public @interface SpecialAttr { + + Class<?> clazz(); + + Thread.State state(); + + NestedAnno nestedAnno(); + + NestedAnno[] nestedAnnoArray(); + + NestedAnno optional() default @NestedAnno(value="optional", anEnum=SomeEnum.DEFAULT, classArray=Void.class); + + NestedAnno[] optionalArray() default {@NestedAnno(value="optional", anEnum=SomeEnum.DEFAULT, classArray=Void.class)}; + } + + + @Component("myName") + @Scope("myScope") + @SpecialAttr(clazz = String.class, state = Thread.State.NEW, + nestedAnno = @NestedAnno(value = "na", anEnum = SomeEnum.LABEL1, classArray = {String.class}), + nestedAnnoArray = { + @NestedAnno, + @NestedAnno(value = "na1", anEnum = SomeEnum.LABEL2, classArray = {Number.class}) + }) + @SuppressWarnings({"serial", "unused"}) + private static class AnnotatedComponent implements Serializable { + + @TestAutowired + public void doWork(@TestQualifier("myColor") java.awt.Color color) { + } + + public void doSleep() { + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java b/spring-core/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java new file mode 100644 index 00000000..b316d174 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/AnnotationTypeFilterTests.java @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.type; + +import static org.junit.Assert.*; + +import java.lang.annotation.Inherited; + +import org.junit.Test; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.stereotype.Component; + +/** + * @author Ramnivas Laddad + * @author Juergen Hoeller + * @author Oliver Gierke + */ +public class AnnotationTypeFilterTests { + + @Test + public void testDirectAnnotationMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeComponent"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + @Test + public void testInheritedAnnotationFromInterfaceDoesNotMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubClassOfSomeComponentInterface"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class); + // Must fail as annotation on interfaces should not be considered a match + assertFalse(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + @Test + public void testInheritedAnnotationFromBaseClassDoesMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubClassOfSomeComponent"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + @Test + public void testNonInheritedAnnotationDoesNotMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeSubclassOfSomeClassMarkedWithNonInheritedAnnotation"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(NonInheritedAnnotation.class); + // Must fail as annotation isn't inherited + assertFalse(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + @Test + public void testNonAnnotatedClassDoesntMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeNonCandidateClass"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(Component.class); + assertFalse(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + @Test + public void testMatchesInterfacesIfConfigured() throws Exception { + + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AnnotationTypeFilterTests$SomeComponentInterface"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AnnotationTypeFilter filter = new AnnotationTypeFilter(InheritedAnnotation.class, false, true); + + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + // We must use a standalone set of types to ensure that no one else is loading them + // and interfering with ClassloadingAssertions.assertClassNotLoaded() + + @Inherited + private static @interface InheritedAnnotation { + } + + + @InheritedAnnotation + private static class SomeComponent { + } + + + @InheritedAnnotation + private static interface SomeComponentInterface { + } + + + @SuppressWarnings("unused") + private static class SomeSubClassOfSomeComponentInterface implements SomeComponentInterface { + } + + + @SuppressWarnings("unused") + private static class SomeSubClassOfSomeComponent extends SomeComponent { + } + + + private static @interface NonInheritedAnnotation { + } + + + @NonInheritedAnnotation + private static class SomeClassMarkedWithNonInheritedAnnotation { + } + + + @SuppressWarnings("unused") + private static class SomeSubclassOfSomeClassMarkedWithNonInheritedAnnotation extends SomeClassMarkedWithNonInheritedAnnotation { + } + + + @SuppressWarnings("unused") + private static class SomeNonCandidateClass { + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/AspectJTypeFilterTests.java b/spring-core/src/test/java/org/springframework/core/type/AspectJTypeFilterTests.java new file mode 100644 index 00000000..45abc29c --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/AspectJTypeFilterTests.java @@ -0,0 +1,164 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.core.type; + +import junit.framework.TestCase; + +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.core.type.filter.AspectJTypeFilter; +import org.springframework.stereotype.Component; + +/** + * @author Ramnivas Laddad + */ +public class AspectJTypeFilterTests extends TestCase { + + public void testNamePatternMatches() throws Exception { + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClass"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "*..SomeClass"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "org..SomeClass"); + } + + public void testNamePatternNoMatches() throws Exception { + assertNoMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClassX"); + } + + public void testSubclassPatternMatches() throws Exception { + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClass", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClass+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClass", + "*+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClass", + "java.lang.Object+"); + + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassImplementingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeInterface+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassImplementingSomeInterface", + "*+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassImplementingSomeInterface", + "java.lang.Object+"); + + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeInterface+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClassExtendingSomeClass+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeClass+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "*+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "java.lang.Object+"); + } + + public void testSubclassPatternNoMatches() throws Exception { + assertNoMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClass", + "java.lang.String+"); + } + + public void testAnnotationPatternMatches() throws Exception { + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@org.springframework.stereotype.Component *..*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@* *..*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@*..* *..*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@*..*Component *..*"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@org.springframework.stereotype.Component *..*Component"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@org.springframework.stereotype.Component *"); + } + + public void testAnnotationPatternNoMathces() throws Exception { + assertNoMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassAnnotatedWithComponent", + "@org.springframework.stereotype.Repository *..*"); + } + + public void testCompositionPatternMatches() throws Exception { + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "!*..SomeOtherClass"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeInterface+ " + + "&& org.springframework.core.type.AspectJTypeFilterTests.SomeClass+ " + + "&& org.springframework.core.type.AspectJTypeFilterTests.SomeClassExtendingSomeClass+"); + assertMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface", + "org.springframework.core.type.AspectJTypeFilterTests.SomeInterface+ " + + "|| org.springframework.core.type.AspectJTypeFilterTests.SomeClass+ " + + "|| org.springframework.core.type.AspectJTypeFilterTests.SomeClassExtendingSomeClass+"); + } + + public void testCompositionPatternNoMatches() throws Exception { + assertNoMatch("org.springframework.core.type.AspectJTypeFilterTests$SomeClass", + "*..Bogus && org.springframework.core.type.AspectJTypeFilterTests.SomeClass"); + } + + private void assertMatch(String type, String typePattern) throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(type); + + AspectJTypeFilter filter = new AspectJTypeFilter(typePattern, getClass().getClassLoader()); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(type); + } + + private void assertNoMatch(String type, String typePattern) throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(type); + + AspectJTypeFilter filter = new AspectJTypeFilter(typePattern, getClass().getClassLoader()); + assertFalse(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(type); + } + + + // We must use a standalone set of types to ensure that no one else is loading them + // and interfering with ClassloadingAssertions.assertClassNotLoaded() + static interface SomeInterface { + } + + + static class SomeClass { + } + + + static class SomeClassExtendingSomeClass extends SomeClass { + } + + + static class SomeClassImplementingSomeInterface implements SomeInterface { + } + + + static class SomeClassExtendingSomeClassExtendingSomeClassAndImplemnentingSomeInterface + extends SomeClassExtendingSomeClass implements SomeInterface { + } + + + @Component + static class SomeClassAnnotatedWithComponent { + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/AssignableTypeFilterTests.java b/spring-core/src/test/java/org/springframework/core/type/AssignableTypeFilterTests.java new file mode 100644 index 00000000..cc624af1 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/AssignableTypeFilterTests.java @@ -0,0 +1,105 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.type; + +import junit.framework.TestCase; + +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; +import org.springframework.core.type.filter.AssignableTypeFilter; + +/** + * @author Ramnivas Laddad + * @author Juergen Hoeller + */ +public class AssignableTypeFilterTests extends TestCase { + + public void testDirectMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AssignableTypeFilterTests$TestNonInheritingClass"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AssignableTypeFilter matchingFilter = new AssignableTypeFilter(TestNonInheritingClass.class); + AssignableTypeFilter notMatchingFilter = new AssignableTypeFilter(TestInterface.class); + assertFalse(notMatchingFilter.match(metadataReader, metadataReaderFactory)); + assertTrue(matchingFilter.match(metadataReader, metadataReaderFactory)); + } + + public void testInterfaceMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AssignableTypeFilterTests$TestInterfaceImpl"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AssignableTypeFilter filter = new AssignableTypeFilter(TestInterface.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + public void testSuperClassMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AssignableTypeFilterTests$SomeDaoLikeImpl"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AssignableTypeFilter filter = new AssignableTypeFilter(SimpleJdbcDaoSupport.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + public void testInterfaceThroughSuperClassMatch() throws Exception { + MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + String classUnderTest = "org.springframework.core.type.AssignableTypeFilterTests$SomeDaoLikeImpl"; + MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(classUnderTest); + + AssignableTypeFilter filter = new AssignableTypeFilter(JdbcDaoSupport.class); + assertTrue(filter.match(metadataReader, metadataReaderFactory)); + ClassloadingAssertions.assertClassNotLoaded(classUnderTest); + } + + + // We must use a standalone set of types to ensure that no one else is loading them + // and interfere with ClassloadingAssertions.assertClassNotLoaded() + private static class TestNonInheritingClass { + } + + + private static interface TestInterface { + } + + + @SuppressWarnings("unused") + private static class TestInterfaceImpl implements TestInterface { + } + + + private static interface SomeDaoLikeInterface { + } + + + @SuppressWarnings("unused") + private static class SomeDaoLikeImpl extends SimpleJdbcDaoSupport implements SomeDaoLikeInterface { + } + + private static interface JdbcDaoSupport { + + } + + private static class SimpleJdbcDaoSupport implements JdbcDaoSupport { + + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/CachingMetadataReaderLeakTest.java b/spring-core/src/test/java/org/springframework/core/type/CachingMetadataReaderLeakTest.java new file mode 100644 index 00000000..1d138b76 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/CachingMetadataReaderLeakTest.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.type; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; + +import java.net.URL; + +import org.junit.Before; +import org.junit.Test; +import org.springframework.core.io.Resource; +import org.springframework.core.io.UrlResource; +import org.springframework.core.type.classreading.CachingMetadataReaderFactory; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.tests.Assume; +import org.springframework.tests.TestGroup; + +/** + * Unit test checking the behaviour of {@link CachingMetadataReaderFactory} under load. + * If the cache is not controller, this test should fail with an out of memory exception around entry + * 5k. + * + * @author Costin Leau + */ +public class CachingMetadataReaderLeakTest { + + private static int ITEMS_LOAD = 9999; + private MetadataReaderFactory mrf; + + @Before + public void before() { + mrf = new CachingMetadataReaderFactory(); + } + + @Test + public void testSignificantLoad() throws Exception { + Assume.group(TestGroup.LONG_RUNNING); + + // the biggest public class in the JDK (>60k) + URL url = getClass().getResource("/java/awt/Component.class"); + assertThat(url, notNullValue()); + + // look at a LOT of items + for (int i = 0; i < ITEMS_LOAD; i++) { + Resource resource = new UrlResource(url) { + private int counter = 0; + + @Override + public boolean equals(Object obj) { + return (obj == this); + + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + }; + + MetadataReader reader = mrf.getMetadataReader(resource); + assertThat(reader, notNullValue()); + } + + // useful for profiling to take snapshots + //System.in.read(); + } +} diff --git a/spring-core/src/test/java/org/springframework/core/type/ClassloadingAssertions.java b/spring-core/src/test/java/org/springframework/core/type/ClassloadingAssertions.java new file mode 100644 index 00000000..a9996e33 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/ClassloadingAssertions.java @@ -0,0 +1,45 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * 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 org.springframework.core.type; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; + +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; + +/** + * + * @author Ramnivas Laddad + * + */ +public class ClassloadingAssertions { + public static boolean isClassLoaded(String className) { + ClassLoader cl = ClassUtils.getDefaultClassLoader(); + Method findLoadeClassMethod = ReflectionUtils.findMethod(cl.getClass(), "findLoadedClass", new Class[]{String.class}); + findLoadeClassMethod.setAccessible(true); + Class loadedClass = (Class)ReflectionUtils.invokeMethod(findLoadeClassMethod, cl, new Object[]{className}); + return loadedClass != null; + } + + public static void assertClassLoaded(String className) { + } + + public static void assertClassNotLoaded(String className) { + TestCase.assertFalse("Class shouldn't have been loaded", isClassLoaded(className)); + } +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/core/type/Scope.java b/spring-core/src/test/java/org/springframework/core/type/Scope.java new file mode 100644 index 00000000..a365f2a8 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/Scope.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.core.type; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Scope { + + /** + * Specifies the scope to use for instances of the annotated class. + * @return the desired scope + */ + String value() default "singleton"; + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/StandardClassMetadataMemberClassTests.java b/spring-core/src/test/java/org/springframework/core/type/StandardClassMetadataMemberClassTests.java new file mode 100644 index 00000000..716c03c4 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/StandardClassMetadataMemberClassTests.java @@ -0,0 +1,32 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.core.type; + +/** + * @author Chris Beams + * @since 3.1 + * @see AbstractClassMetadataMemberClassTests + */ +public class StandardClassMetadataMemberClassTests + extends AbstractClassMetadataMemberClassTests { + + @Override + public ClassMetadata getClassMetadataFor(Class<?> clazz) { + return new StandardClassMetadata(clazz); + } + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/TestAutowired.java b/spring-core/src/test/java/org/springframework/core/type/TestAutowired.java new file mode 100644 index 00000000..c1a1b1d2 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/TestAutowired.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.type; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD}) +public @interface TestAutowired { + + /** + * Declares whether the annotated dependency is required. + * <p>Defaults to {@code true}. + */ + boolean required() default true; + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/TestQualifier.java b/spring-core/src/test/java/org/springframework/core/type/TestQualifier.java new file mode 100644 index 00000000..9698ec71 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/TestQualifier.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.core.type; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +@Inherited +@Documented +public @interface TestQualifier { + + String value() default ""; + +} diff --git a/spring-core/src/test/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitorMemberClassTests.java b/spring-core/src/test/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitorMemberClassTests.java new file mode 100644 index 00000000..cc4ca072 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/core/type/classreading/ClassMetadataReadingVisitorMemberClassTests.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.core.type.classreading; + +import java.io.IOException; + +import org.springframework.core.type.AbstractClassMetadataMemberClassTests; +import org.springframework.core.type.ClassMetadata; + +/** + * @author Chris Beams + * @since 3.1 + * @see AbstractClassMetadataMemberClassTests + */ +public class ClassMetadataReadingVisitorMemberClassTests + extends AbstractClassMetadataMemberClassTests { + + @Override + public ClassMetadata getClassMetadataFor(Class<?> clazz) { + try { + MetadataReader reader = + new SimpleMetadataReaderFactory().getMetadataReader(clazz.getName()); + return reader.getAnnotationMetadata(); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/mock/env/MockPropertySource.java b/spring-core/src/test/java/org/springframework/mock/env/MockPropertySource.java new file mode 100644 index 00000000..2783f244 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/mock/env/MockPropertySource.java @@ -0,0 +1,104 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.mock.env; + +import java.util.Properties; + +import org.springframework.core.env.PropertiesPropertySource; +import org.springframework.core.env.PropertySource; + +/** + * Simple {@link PropertySource} implementation for use in testing. Accepts + * a user-provided {@link Properties} object, or if omitted during construction, + * the implementation will initialize its own. + * + * The {@link #setProperty} and {@link #withProperty} methods are exposed for + * convenience, for example: + * <pre> + * {@code + * PropertySource<?> source = new MockPropertySource().withProperty("foo", "bar"); + * } + * </pre> + * + * @author Chris Beams + * @since 3.1 + * @see org.springframework.mock.env.MockEnvironment + */ +public class MockPropertySource extends PropertiesPropertySource { + + /** + * {@value} is the default name for {@link MockPropertySource} instances not + * otherwise given an explicit name. + * @see #MockPropertySource() + * @see #MockPropertySource(String) + */ + public static final String MOCK_PROPERTIES_PROPERTY_SOURCE_NAME = "mockProperties"; + + /** + * Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME} + * that will maintain its own internal {@link Properties} instance. + */ + public MockPropertySource() { + this(new Properties()); + } + + /** + * Create a new {@code MockPropertySource} with the given name that will + * maintain its own internal {@link Properties} instance. + * @param name the {@linkplain #getName() name} of the property source + */ + public MockPropertySource(String name) { + this(name, new Properties()); + } + + /** + * Create a new {@code MockPropertySource} named {@value #MOCK_PROPERTIES_PROPERTY_SOURCE_NAME} + * and backed by the given {@link Properties} object. + * @param properties the properties to use + */ + public MockPropertySource(Properties properties) { + this(MOCK_PROPERTIES_PROPERTY_SOURCE_NAME, properties); + } + + /** + * Create a new {@code MockPropertySource} with the given name and backed by the given + * {@link Properties} object + * @param name the {@linkplain #getName() name} of the property source + * @param properties the properties to use + */ + public MockPropertySource(String name, Properties properties) { + super(name, properties); + } + + /** + * Set the given property on the underlying {@link Properties} object. + */ + public void setProperty(String name, Object value) { + this.source.put(name, value); + } + + /** + * Convenient synonym for {@link #setProperty} that returns the current instance. + * Useful for method chaining and fluent-style use. + * @return this {@link MockPropertySource} instance + */ + public MockPropertySource withProperty(String name, Object value) { + this.setProperty(name, value); + return this; + } + +} diff --git a/spring-core/src/test/java/org/springframework/stereotype/Component.java b/spring-core/src/test/java/org/springframework/stereotype/Component.java new file mode 100644 index 00000000..e0b637f8 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/stereotype/Component.java @@ -0,0 +1,54 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * 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 org.springframework.stereotype; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that an annotated class is a "component". + * Such classes are considered as candidates for auto-detection + * when using annotation-based configuration and classpath scanning. + * + * <p>Other class-level annotations may be considered as identifying + * a component as well, typically a special kind of component: + * e.g. the {@link Repository @Repository} annotation or AspectJ's + * {@link org.aspectj.lang.annotation.Aspect @Aspect} annotation. + * + * @author Mark Fisher + * @since 2.5 + * @see Repository + * @see Service + * @see Controller + * @see org.springframework.context.annotation.ClassPathBeanDefinitionScanner + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Component { + + /** + * The value may indicate a suggestion for a logical component name, + * to be turned into a Spring bean in case of an autodetected component. + * @return the suggested component name, if any + */ + public abstract String value() default ""; + +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/tests/Assume.java b/spring-core/src/test/java/org/springframework/tests/Assume.java new file mode 100644 index 00000000..801cd93a --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/Assume.java @@ -0,0 +1,112 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +import static org.junit.Assume.assumeFalse; + +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.junit.internal.AssumptionViolatedException; + +/** + * Provides utility methods that allow JUnit tests to {@link org.junit.Assume} certain + * conditions hold {@code true}. If the assumption fails, it means the test should be + * skipped. + * + * <p>For example, if a set of tests require at least JDK 1.7 it can use + * {@code Assume#atLeast(JdkVersion.JAVA_17)} as shown below: + * + * <pre class="code"> + * public void MyTests { + * + * @BeforeClass + * public static assumptions() { + * Assume.atLeast(JdkVersion.JAVA_17); + * } + * + * // ... all the test methods that require at least JDK 1.7 + * } + * </pre> + * + * If only a single test requires at least JDK 1.7 it can use the + * {@code Assume#atLeast(JdkVersion.JAVA_17)} as shown below: + * + * <pre class="code"> + * public void MyTests { + * + * @Test + * public void requiresJdk17 { + * Assume.atLeast(JdkVersion.JAVA_17); + * // ... perform the actual test + * } + * } + * </pre> + * + * In addition to assumptions based on the JDK version, tests can be categorized into + * {@link TestGroup}s. Active groups are enabled using the 'testGroups' system property, + * usually activated from the gradle command line: + * <pre> + * gradle test -PtestGroups="performance" + * </pre> + * + * Groups can be specified as a comma separated list of values, or using the pseudo group + * 'all'. See {@link TestGroup} for a list of valid groups. + * + * @author Rob Winch + * @author Phillip Webb + * @since 3.2 + * @see #atLeast(JavaVersion) + * @see #group(TestGroup) + */ +public abstract class Assume { + + + private static final Set<TestGroup> GROUPS = TestGroup.parse(System.getProperty("testGroups")); + + + /** + * Assume a minimum {@link JavaVersion} is running. + * @param version the minimum version for the test to run + */ + public static void atLeast(JavaVersion version) { + if (!JavaVersion.runningVersion().isAtLeast(version)) { + throw new AssumptionViolatedException("Requires JDK " + version + " but running " + + JavaVersion.runningVersion()); + } + } + + /** + * Assume that a particular {@link TestGroup} has been specified. + * @param group the group that must be specified. + */ + public static void group(TestGroup group) { + if (!GROUPS.contains(group)) { + throw new AssumptionViolatedException("Requires unspecified group " + group + + " from " + GROUPS); + } + } + + /** + * Assume that the specified log is not set to Trace or Debug. + * @param log the log to test + */ + public static void notLogging(Log log) { + assumeFalse(log.isTraceEnabled()); + assumeFalse(log.isDebugEnabled()); + } +} diff --git a/spring-core/src/test/java/org/springframework/tests/BuildTests.java b/spring-core/src/test/java/org/springframework/tests/BuildTests.java new file mode 100644 index 00000000..92008dfb --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/BuildTests.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +import org.junit.Test; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * General build related tests. Part of spring-core to ensure that they run early in the + * build process. + */ +public class BuildTests { + + @Test + public void javaVersion() throws Exception { + Assume.group(TestGroup.CI); + assertThat("Java Version", JavaVersion.runningVersion(), equalTo(JavaVersion.JAVA_17)); + } + +} diff --git a/spring-core/src/test/java/org/springframework/tests/JavaVersion.java b/spring-core/src/test/java/org/springframework/tests/JavaVersion.java new file mode 100644 index 00000000..b36319b2 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/JavaVersion.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +/** + * Enumeration of known JDK versions. + * + * @author Phillip Webb + * @see #runningVersion() + */ +public enum JavaVersion { + + + /** + * Java 1.5 + */ + JAVA_15("1.5", 15), + + /** + * Java 1.6 + */ + JAVA_16("1.6", 16), + + /** + * Java 1.7 + */ + JAVA_17("1.7", 17), + + /** + * Java 1.8 + */ + JAVA_18("1.8", 18); + + + private static final JavaVersion runningVersion = findRunningVersion(); + + private static JavaVersion findRunningVersion() { + String version = System.getProperty("java.version"); + for (JavaVersion candidate : values()) { + if (version.startsWith(candidate.version)) { + return candidate; + } + } + return JavaVersion.JAVA_15; + } + + + private String version; + + private int value; + + + private JavaVersion(String version, int value) { + this.version = version; + this.value = value; + } + + + @Override + public String toString() { + return version; + } + + /** + * Determines if the specified version is the same as or greater than this version. + * @param version the version to check + * @return {@code true} if the specified version is at least this version + */ + public boolean isAtLeast(JavaVersion version) { + return this.value >= version.value; + } + + + /** + * Returns the current running JDK version. If the current version cannot be + * determined {@link #JAVA_15} will be returned. + * @return the JDK version + */ + public static JavaVersion runningVersion() { + return runningVersion; + } +} diff --git a/spring-core/src/test/java/org/springframework/tests/JavaVersionTests.java b/spring-core/src/test/java/org/springframework/tests/JavaVersionTests.java new file mode 100644 index 00000000..82b51e00 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/JavaVersionTests.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +import static org.hamcrest.Matchers.startsWith; +import static org.junit.Assert.*; + +import org.junit.Test; + +/** + * Tests for {@link JavaVersion}. + * + * @author Phillip Webb + */ +public class JavaVersionTests { + + @Test + public void runningVersion() { + assertNotNull(JavaVersion.runningVersion()); + assertThat(System.getProperty("java.version"), startsWith(JavaVersion.runningVersion().toString())); + } + + @Test + public void isAtLeast() throws Exception { + assertTrue(JavaVersion.JAVA_16.isAtLeast(JavaVersion.JAVA_15)); + assertTrue(JavaVersion.JAVA_16.isAtLeast(JavaVersion.JAVA_16)); + assertFalse(JavaVersion.JAVA_16.isAtLeast(JavaVersion.JAVA_17)); + } +} diff --git a/spring-core/src/test/java/org/springframework/tests/Matchers.java b/spring-core/src/test/java/org/springframework/tests/Matchers.java new file mode 100644 index 00000000..826bd1c7 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/Matchers.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.tests; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.Rule; +import org.junit.rules.ExpectedException; + +/** + * Additional hamcrest matchers. + * + * @author Phillip Webb + */ +public class Matchers { + + /** + * Create a matcher that wrapps the specified matcher and tests against the + * {@link Throwable#getCause() cause} of an exception. If the item tested + * is {@code null} not a {@link Throwable} the wrapped matcher will be called + * with a {@code null} item. + * + * <p>Often useful when working with JUnit {@link ExpectedException} + * {@link Rule @Rule}s, for example: + * <pre> + * thrown.expect(DataAccessException.class); + * thrown.except(exceptionCause(isA(SQLException.class))); + * </pre> + * + * @param matcher the matcher to wrap (must not be null) + * @return a matcher that tests using the exception cause + */ + @SuppressWarnings("unchecked") + public static <T> Matcher<T> exceptionCause(final Matcher<T> matcher) { + return (Matcher<T>) new BaseMatcher<Object>() { + @Override + public boolean matches(Object item) { + Throwable cause = null; + if(item != null && item instanceof Throwable) { + cause = ((Throwable)item).getCause(); + } + return matcher.matches(cause); + } + + @Override + public void describeTo(Description description) { + description.appendText("exception cause ").appendDescriptionOf(matcher); + } + }; + } + +} diff --git a/spring-core/src/test/java/org/springframework/tests/MockitoUtils.java b/spring-core/src/test/java/org/springframework/tests/MockitoUtils.java new file mode 100644 index 00000000..0fb20f30 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/MockitoUtils.java @@ -0,0 +1,88 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.util.List; + +import org.mockito.Mockito; +import org.mockito.internal.util.MockUtil; +import org.mockito.invocation.Invocation; + +/** + * General test utilities for use with {@link Mockito}. + * + * @author Phillip Webb + */ +public class MockitoUtils { + + private static MockUtil mockUtil = new MockUtil(); + + /** + * Verify the same invocations have been applied to two mocks. This is generally not + * the preferred way test with mockito and should be avoided if possible. + * @param expected the mock containing expected invocations + * @param actual the mock containing actual invocations + * @param argumentAdapters adapters that can be used to change argument values before + * they are compared + */ + public static <T> void verifySameInvocations(T expected, T actual, InvocationArgumentsAdapter... argumentAdapters) { + List<Invocation> expectedInvocations = mockUtil.getMockHandler(expected).getInvocationContainer().getInvocations(); + List<Invocation> actualInvocations = mockUtil.getMockHandler(actual).getInvocationContainer().getInvocations(); + verifySameInvocations(expectedInvocations, actualInvocations, argumentAdapters); + } + + private static void verifySameInvocations(List<Invocation> expectedInvocations, List<Invocation> actualInvocations, InvocationArgumentsAdapter... argumentAdapters) { + assertThat(expectedInvocations.size(), is(equalTo(actualInvocations.size()))); + for (int i = 0; i < expectedInvocations.size(); i++) { + verifySameInvocation(expectedInvocations.get(i), actualInvocations.get(i), argumentAdapters); + } + } + + private static void verifySameInvocation(Invocation expectedInvocation, Invocation actualInvocation, InvocationArgumentsAdapter... argumentAdapters) { + System.out.println(expectedInvocation); + System.out.println(actualInvocation); + assertThat(expectedInvocation.getMethod(), is(equalTo(actualInvocation.getMethod()))); + Object[] expectedArguments = getInvocationArguments(expectedInvocation, argumentAdapters); + Object[] actualArguments = getInvocationArguments(actualInvocation, argumentAdapters); + assertThat(expectedArguments, is(equalTo(actualArguments))); + } + + private static Object[] getInvocationArguments(Invocation invocation, InvocationArgumentsAdapter... argumentAdapters) { + Object[] arguments = invocation.getArguments(); + for (InvocationArgumentsAdapter adapter : argumentAdapters) { + arguments = adapter.adaptArguments(arguments); + } + return arguments; + } + + /** + * Adapter strategy that can be used to change invocation arguments. + */ + public static interface InvocationArgumentsAdapter { + + /** + * Change the arguments if required + * @param arguments the source arguments + * @return updated or original arguments (never {@code null}) + */ + Object[] adaptArguments(Object[] arguments); + } +} diff --git a/spring-core/src/test/java/org/springframework/tests/TestGroup.java b/spring-core/src/test/java/org/springframework/tests/TestGroup.java new file mode 100644 index 00000000..c135e8e6 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/TestGroup.java @@ -0,0 +1,96 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; + +import org.springframework.util.StringUtils; + +import static java.lang.String.*; + +/** + * A test group used to limit when certain tests are run. + * + * @see Assume#group(TestGroup) + * @author Phillip Webb + * @author Chris Beams + */ +public enum TestGroup { + + + /** + * Tests that take a considerable amount of time to run. Any test lasting longer than + * 500ms should be considered a candidate in order to avoid making the overall test + * suite too slow to run during the normal development cycle. + */ + LONG_RUNNING, + + /** + * Performance-related tests that may fail unpredictably based on CPU profile and load. + * Any test using {@link Thread#sleep}, {@link Object#wait}, Spring's + * {@code StopWatch}, etc. should be considered a candidate as their successful + * execution is likely to be based on events occurring within a given time window. + */ + PERFORMANCE, + + /** + * Tests requiring the presence of jmxremote_optional.jar in jre/lib/ext in order to + * avoid "Unsupported protocol: jmxmp" errors. + */ + JMXMP, + + /** + * Tests that should only be run on the continuous integration server. + */ + CI, + + /** + * Tests that require custom compilation beyond that of the standard JDK. This helps to + * allow running tests that will otherwise fail when using JDK > 1.8 b88. See + * <a href="https://jira.springsource.org/browse/SPR-10558">SPR-10558</a> + */ + CUSTOM_COMPILATION; + + /** + * Parse the specified comma separates string of groups. + * @param value the comma separated string of groups + * @return a set of groups + */ + public static Set<TestGroup> parse(String value) { + if (value == null || "".equals(value)) { + return Collections.emptySet(); + } + if("ALL".equalsIgnoreCase(value)) { + return EnumSet.allOf(TestGroup.class); + } + Set<TestGroup> groups = new HashSet<TestGroup>(); + for (String group : value.split(",")) { + try { + groups.add(valueOf(group.trim().toUpperCase())); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(format( + "Unable to find test group '%s' when parsing testGroups value: '%s'. " + + "Available groups include: [%s]", group.trim(), value, + StringUtils.arrayToCommaDelimitedString(TestGroup.values()))); + } + } + return groups; + } +} diff --git a/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java b/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java new file mode 100644 index 00000000..2d519345 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/TestGroupTests.java @@ -0,0 +1,75 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Tests for {@link TestGroup}. + * + * @author Phillip Webb + */ +public class TestGroupTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void parseNull() throws Exception { + assertThat(TestGroup.parse(null), is(Collections.<TestGroup> emptySet())); + } + + @Test + public void parseEmptyString() throws Exception { + assertThat(TestGroup.parse(""), is(Collections.<TestGroup> emptySet())); + } + + @Test + public void parseWithSpaces() throws Exception { + assertThat(TestGroup.parse("PERFORMANCE, PERFORMANCE"), + is((Set<TestGroup>) EnumSet.of(TestGroup.PERFORMANCE))); + } + + @Test + public void parseInMixedCase() throws Exception { + assertThat(TestGroup.parse("performance, PERFormaNCE"), + is((Set<TestGroup>) EnumSet.of(TestGroup.PERFORMANCE))); + } + + @Test + public void parseMissing() throws Exception { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Unable to find test group 'missing' when parsing " + + "testGroups value: 'performance, missing'. Available groups include: " + + "[LONG_RUNNING,PERFORMANCE,JMXMP,CI,CUSTOM_COMPILATION]"); + TestGroup.parse("performance, missing"); + } + + @Test + public void parseAll() throws Exception { + assertThat(TestGroup.parse("all"), is((Set<TestGroup>)EnumSet.allOf(TestGroup.class))); + } +} diff --git a/spring-core/src/test/java/org/springframework/tests/TestResourceUtils.java b/spring-core/src/test/java/org/springframework/tests/TestResourceUtils.java new file mode 100644 index 00000000..93aab194 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/TestResourceUtils.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +import static java.lang.String.format; + +import org.springframework.core.io.ClassPathResource; + +/** + * Convenience utilities for common operations with test resources. + * + * @author Chris Beams + */ +public class TestResourceUtils { + + /** + * Loads a {@link ClassPathResource} qualified by the simple name of clazz, + * and relative to the package for clazz. + * + * <p>Example: given a clazz 'com.foo.BarTests' and a resourceSuffix of 'context.xml', + * this method will return a ClassPathResource representing com/foo/BarTests-context.xml + * + * <p>Intended for use loading context configuration XML files within JUnit tests. + * + * @param clazz + * @param resourceSuffix + */ + public static ClassPathResource qualifiedResource(Class<?> clazz, String resourceSuffix) { + return new ClassPathResource(format("%s-%s", clazz.getSimpleName(), resourceSuffix), clazz); + } + +} diff --git a/spring-core/src/test/java/org/springframework/tests/TimeStamped.java b/spring-core/src/test/java/org/springframework/tests/TimeStamped.java new file mode 100644 index 00000000..ad653a50 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/TimeStamped.java @@ -0,0 +1,34 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests; + +/** + * This interface can be implemented by cacheable objects or cache entries, + * to enable the freshness of objects to be checked. + * + * @author Rod Johnson + */ +public interface TimeStamped { + + /** + * Return the timestamp for this object. + * @return long the timestamp for this object, + * as returned by System.currentTimeMillis() + */ + long getTimeStamp(); + +} diff --git a/spring-core/src/test/java/org/springframework/tests/package-info.java b/spring-core/src/test/java/org/springframework/tests/package-info.java new file mode 100644 index 00000000..545c413c --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/package-info.java @@ -0,0 +1,22 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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. + */ + +/** + * Shared utilities that are used internally throughout the test suite but are not + * published. This package should not be confused with {@code org.springframework.test} + * which contains published code from the 'spring-test' module. + */ +package org.springframework.tests; diff --git a/spring-core/src/test/java/org/springframework/tests/sample/objects/DerivedTestObject.java b/spring-core/src/test/java/org/springframework/tests/sample/objects/DerivedTestObject.java new file mode 100644 index 00000000..45ab490a --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/sample/objects/DerivedTestObject.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests.sample.objects; + +import java.io.Serializable; + +@SuppressWarnings("serial") +public class DerivedTestObject extends TestObject implements Serializable { + +} diff --git a/spring-core/src/test/java/org/springframework/tests/sample/objects/GenericObject.java b/spring-core/src/test/java/org/springframework/tests/sample/objects/GenericObject.java new file mode 100644 index 00000000..efd0455f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/sample/objects/GenericObject.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests.sample.objects; + +import java.util.List; + +import org.springframework.core.io.Resource; + + +public class GenericObject<T> { + + private List<Resource> resourceList; + + public List<Resource> getResourceList() { + return this.resourceList; + } + + public void setResourceList(List<Resource> resourceList) { + this.resourceList = resourceList; + } + +} diff --git a/spring-core/src/test/java/org/springframework/tests/sample/objects/ITestInterface.java b/spring-core/src/test/java/org/springframework/tests/sample/objects/ITestInterface.java new file mode 100644 index 00000000..4aca1f25 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/sample/objects/ITestInterface.java @@ -0,0 +1,24 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests.sample.objects; + + +public interface ITestInterface { + + void absquatulate(); + +} diff --git a/spring-core/src/test/java/org/springframework/tests/sample/objects/ITestObject.java b/spring-core/src/test/java/org/springframework/tests/sample/objects/ITestObject.java new file mode 100644 index 00000000..ca795cb0 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/sample/objects/ITestObject.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests.sample.objects; + +public interface ITestObject { + + String getName(); + + void setName(String name); + + int getAge(); + + void setAge(int age); + + TestObject getSpouse(); + + void setSpouse(TestObject spouse); + +} diff --git a/spring-core/src/test/java/org/springframework/tests/sample/objects/TestObject.java b/spring-core/src/test/java/org/springframework/tests/sample/objects/TestObject.java new file mode 100644 index 00000000..68ce8c64 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/sample/objects/TestObject.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.tests.sample.objects; + +public class TestObject implements ITestObject, ITestInterface, Comparable<Object> { + + private String name; + + private int age; + + private TestObject spouse; + + public TestObject() { + } + + public TestObject(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return this.age; + } + + public void setAge(int age) { + this.age = age; + } + + public TestObject getSpouse() { + return this.spouse; + } + + public void setSpouse(TestObject spouse) { + this.spouse = spouse; + } + + @Override + public void absquatulate() { + } + + @Override + public int compareTo(Object o) { + if (this.name != null && o instanceof TestObject) { + return this.name.compareTo(((TestObject) o).getName()); + } + else { + return 1; + } + } +} diff --git a/spring-core/src/test/java/org/springframework/tests/sample/objects/package-info.java b/spring-core/src/test/java/org/springframework/tests/sample/objects/package-info.java new file mode 100644 index 00000000..98c15ca6 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/tests/sample/objects/package-info.java @@ -0,0 +1,4 @@ +/** + * General purpose sample objects that can be used with tests. + */ +package org.springframework.tests.sample.objects; diff --git a/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java new file mode 100644 index 00000000..05a98f40 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/AntPathMatcherTests.java @@ -0,0 +1,556 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Alef Arendsen + * @author Seth Ladd + * @author Juergen Hoeller + * @author Arjen Poutsma + * @author Rossen Stoyanchev + */ +public class AntPathMatcherTests { + + private AntPathMatcher pathMatcher; + + @Before + public void createMatcher() { + pathMatcher = new AntPathMatcher(); + } + + @Test + public void match() { + // test exact matching + assertTrue(pathMatcher.match("test", "test")); + assertTrue(pathMatcher.match("/test", "/test")); + assertFalse(pathMatcher.match("/test.jpg", "test.jpg")); + assertFalse(pathMatcher.match("test", "/test")); + assertFalse(pathMatcher.match("/test", "test")); + + // test matching with ?'s + assertTrue(pathMatcher.match("t?st", "test")); + assertTrue(pathMatcher.match("??st", "test")); + assertTrue(pathMatcher.match("tes?", "test")); + assertTrue(pathMatcher.match("te??", "test")); + assertTrue(pathMatcher.match("?es?", "test")); + assertFalse(pathMatcher.match("tes?", "tes")); + assertFalse(pathMatcher.match("tes?", "testt")); + assertFalse(pathMatcher.match("tes?", "tsst")); + + // test matchin with *'s + assertTrue(pathMatcher.match("*", "test")); + assertTrue(pathMatcher.match("test*", "test")); + assertTrue(pathMatcher.match("test*", "testTest")); + assertTrue(pathMatcher.match("test/*", "test/Test")); + assertTrue(pathMatcher.match("test/*", "test/t")); + assertTrue(pathMatcher.match("test/*", "test/")); + assertTrue(pathMatcher.match("*test*", "AnothertestTest")); + assertTrue(pathMatcher.match("*test", "Anothertest")); + assertTrue(pathMatcher.match("*.*", "test.")); + assertTrue(pathMatcher.match("*.*", "test.test")); + assertTrue(pathMatcher.match("*.*", "test.test.test")); + assertTrue(pathMatcher.match("test*aaa", "testblaaaa")); + assertFalse(pathMatcher.match("test*", "tst")); + assertFalse(pathMatcher.match("test*", "tsttest")); + assertFalse(pathMatcher.match("test*", "test/")); + assertFalse(pathMatcher.match("test*", "test/t")); + assertFalse(pathMatcher.match("test/*", "test")); + assertFalse(pathMatcher.match("*test*", "tsttst")); + assertFalse(pathMatcher.match("*test", "tsttst")); + assertFalse(pathMatcher.match("*.*", "tsttst")); + assertFalse(pathMatcher.match("test*aaa", "test")); + assertFalse(pathMatcher.match("test*aaa", "testblaaab")); + + // test matching with ?'s and /'s + assertTrue(pathMatcher.match("/?", "/a")); + assertTrue(pathMatcher.match("/?/a", "/a/a")); + assertTrue(pathMatcher.match("/a/?", "/a/b")); + assertTrue(pathMatcher.match("/??/a", "/aa/a")); + assertTrue(pathMatcher.match("/a/??", "/a/bb")); + assertTrue(pathMatcher.match("/?", "/a")); + + // test matching with **'s + assertTrue(pathMatcher.match("/**", "/testing/testing")); + assertTrue(pathMatcher.match("/*/**", "/testing/testing")); + assertTrue(pathMatcher.match("/**/*", "/testing/testing")); + assertTrue(pathMatcher.match("/bla/**/bla", "/bla/testing/testing/bla")); + assertTrue(pathMatcher.match("/bla/**/bla", "/bla/testing/testing/bla/bla")); + assertTrue(pathMatcher.match("/**/test", "/bla/bla/test")); + assertTrue(pathMatcher.match("/bla/**/**/bla", "/bla/bla/bla/bla/bla/bla")); + assertTrue(pathMatcher.match("/bla*bla/test", "/blaXXXbla/test")); + assertTrue(pathMatcher.match("/*bla/test", "/XXXbla/test")); + assertFalse(pathMatcher.match("/bla*bla/test", "/blaXXXbl/test")); + assertFalse(pathMatcher.match("/*bla/test", "XXXblab/test")); + assertFalse(pathMatcher.match("/*bla/test", "XXXbl/test")); + + assertFalse(pathMatcher.match("/????", "/bala/bla")); + assertFalse(pathMatcher.match("/**/*bla", "/bla/bla/bla/bbb")); + + assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing/")); + assertTrue(pathMatcher.match("/*bla*/**/bla/*", "/XXXblaXXXX/testing/testing/bla/testing")); + assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing")); + assertTrue(pathMatcher.match("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing.jpg")); + + assertTrue(pathMatcher.match("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing/")); + assertTrue(pathMatcher.match("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing")); + assertTrue(pathMatcher.match("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing")); + assertFalse(pathMatcher.match("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing/testing")); + + assertFalse(pathMatcher.match("/x/x/**/bla", "/x/x/x/")); + + assertTrue(pathMatcher.match("", "")); + + assertTrue(pathMatcher.match("/{bla}.*", "/testing.html")); + } + + @Test + public void withMatchStart() { + // test exact matching + assertTrue(pathMatcher.matchStart("test", "test")); + assertTrue(pathMatcher.matchStart("/test", "/test")); + assertFalse(pathMatcher.matchStart("/test.jpg", "test.jpg")); + assertFalse(pathMatcher.matchStart("test", "/test")); + assertFalse(pathMatcher.matchStart("/test", "test")); + + // test matching with ?'s + assertTrue(pathMatcher.matchStart("t?st", "test")); + assertTrue(pathMatcher.matchStart("??st", "test")); + assertTrue(pathMatcher.matchStart("tes?", "test")); + assertTrue(pathMatcher.matchStart("te??", "test")); + assertTrue(pathMatcher.matchStart("?es?", "test")); + assertFalse(pathMatcher.matchStart("tes?", "tes")); + assertFalse(pathMatcher.matchStart("tes?", "testt")); + assertFalse(pathMatcher.matchStart("tes?", "tsst")); + + // test matchin with *'s + assertTrue(pathMatcher.matchStart("*", "test")); + assertTrue(pathMatcher.matchStart("test*", "test")); + assertTrue(pathMatcher.matchStart("test*", "testTest")); + assertTrue(pathMatcher.matchStart("test/*", "test/Test")); + assertTrue(pathMatcher.matchStart("test/*", "test/t")); + assertTrue(pathMatcher.matchStart("test/*", "test/")); + assertTrue(pathMatcher.matchStart("*test*", "AnothertestTest")); + assertTrue(pathMatcher.matchStart("*test", "Anothertest")); + assertTrue(pathMatcher.matchStart("*.*", "test.")); + assertTrue(pathMatcher.matchStart("*.*", "test.test")); + assertTrue(pathMatcher.matchStart("*.*", "test.test.test")); + assertTrue(pathMatcher.matchStart("test*aaa", "testblaaaa")); + assertFalse(pathMatcher.matchStart("test*", "tst")); + assertFalse(pathMatcher.matchStart("test*", "test/")); + assertFalse(pathMatcher.matchStart("test*", "tsttest")); + assertFalse(pathMatcher.matchStart("test*", "test/")); + assertFalse(pathMatcher.matchStart("test*", "test/t")); + assertTrue(pathMatcher.matchStart("test/*", "test")); + assertTrue(pathMatcher.matchStart("test/t*.txt", "test")); + assertFalse(pathMatcher.matchStart("*test*", "tsttst")); + assertFalse(pathMatcher.matchStart("*test", "tsttst")); + assertFalse(pathMatcher.matchStart("*.*", "tsttst")); + assertFalse(pathMatcher.matchStart("test*aaa", "test")); + assertFalse(pathMatcher.matchStart("test*aaa", "testblaaab")); + + // test matching with ?'s and /'s + assertTrue(pathMatcher.matchStart("/?", "/a")); + assertTrue(pathMatcher.matchStart("/?/a", "/a/a")); + assertTrue(pathMatcher.matchStart("/a/?", "/a/b")); + assertTrue(pathMatcher.matchStart("/??/a", "/aa/a")); + assertTrue(pathMatcher.matchStart("/a/??", "/a/bb")); + assertTrue(pathMatcher.matchStart("/?", "/a")); + + // test matching with **'s + assertTrue(pathMatcher.matchStart("/**", "/testing/testing")); + assertTrue(pathMatcher.matchStart("/*/**", "/testing/testing")); + assertTrue(pathMatcher.matchStart("/**/*", "/testing/testing")); + assertTrue(pathMatcher.matchStart("test*/**", "test/")); + assertTrue(pathMatcher.matchStart("test*/**", "test/t")); + assertTrue(pathMatcher.matchStart("/bla/**/bla", "/bla/testing/testing/bla")); + assertTrue(pathMatcher.matchStart("/bla/**/bla", "/bla/testing/testing/bla/bla")); + assertTrue(pathMatcher.matchStart("/**/test", "/bla/bla/test")); + assertTrue(pathMatcher.matchStart("/bla/**/**/bla", "/bla/bla/bla/bla/bla/bla")); + assertTrue(pathMatcher.matchStart("/bla*bla/test", "/blaXXXbla/test")); + assertTrue(pathMatcher.matchStart("/*bla/test", "/XXXbla/test")); + assertFalse(pathMatcher.matchStart("/bla*bla/test", "/blaXXXbl/test")); + assertFalse(pathMatcher.matchStart("/*bla/test", "XXXblab/test")); + assertFalse(pathMatcher.matchStart("/*bla/test", "XXXbl/test")); + + assertFalse(pathMatcher.matchStart("/????", "/bala/bla")); + assertTrue(pathMatcher.matchStart("/**/*bla", "/bla/bla/bla/bbb")); + + assertTrue(pathMatcher.matchStart("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing/")); + assertTrue(pathMatcher.matchStart("/*bla*/**/bla/*", "/XXXblaXXXX/testing/testing/bla/testing")); + assertTrue(pathMatcher.matchStart("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing")); + assertTrue(pathMatcher.matchStart("/*bla*/**/bla/**", "/XXXblaXXXX/testing/testing/bla/testing/testing.jpg")); + + assertTrue(pathMatcher.matchStart("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing/")); + assertTrue(pathMatcher.matchStart("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing")); + assertTrue(pathMatcher.matchStart("*bla*/**/bla/**", "XXXblaXXXX/testing/testing/bla/testing/testing")); + assertTrue(pathMatcher.matchStart("*bla*/**/bla/*", "XXXblaXXXX/testing/testing/bla/testing/testing")); + + assertTrue(pathMatcher.matchStart("/x/x/**/bla", "/x/x/x/")); + + assertTrue(pathMatcher.matchStart("", "")); + } + + @Test + public void uniqueDeliminator() { + pathMatcher.setPathSeparator("."); + + // test exact matching + assertTrue(pathMatcher.match("test", "test")); + assertTrue(pathMatcher.match(".test", ".test")); + assertFalse(pathMatcher.match(".test/jpg", "test/jpg")); + assertFalse(pathMatcher.match("test", ".test")); + assertFalse(pathMatcher.match(".test", "test")); + + // test matching with ?'s + assertTrue(pathMatcher.match("t?st", "test")); + assertTrue(pathMatcher.match("??st", "test")); + assertTrue(pathMatcher.match("tes?", "test")); + assertTrue(pathMatcher.match("te??", "test")); + assertTrue(pathMatcher.match("?es?", "test")); + assertFalse(pathMatcher.match("tes?", "tes")); + assertFalse(pathMatcher.match("tes?", "testt")); + assertFalse(pathMatcher.match("tes?", "tsst")); + + // test matchin with *'s + assertTrue(pathMatcher.match("*", "test")); + assertTrue(pathMatcher.match("test*", "test")); + assertTrue(pathMatcher.match("test*", "testTest")); + assertTrue(pathMatcher.match("*test*", "AnothertestTest")); + assertTrue(pathMatcher.match("*test", "Anothertest")); + assertTrue(pathMatcher.match("*/*", "test/")); + assertTrue(pathMatcher.match("*/*", "test/test")); + assertTrue(pathMatcher.match("*/*", "test/test/test")); + assertTrue(pathMatcher.match("test*aaa", "testblaaaa")); + assertFalse(pathMatcher.match("test*", "tst")); + assertFalse(pathMatcher.match("test*", "tsttest")); + assertFalse(pathMatcher.match("*test*", "tsttst")); + assertFalse(pathMatcher.match("*test", "tsttst")); + assertFalse(pathMatcher.match("*/*", "tsttst")); + assertFalse(pathMatcher.match("test*aaa", "test")); + assertFalse(pathMatcher.match("test*aaa", "testblaaab")); + + // test matching with ?'s and .'s + assertTrue(pathMatcher.match(".?", ".a")); + assertTrue(pathMatcher.match(".?.a", ".a.a")); + assertTrue(pathMatcher.match(".a.?", ".a.b")); + assertTrue(pathMatcher.match(".??.a", ".aa.a")); + assertTrue(pathMatcher.match(".a.??", ".a.bb")); + assertTrue(pathMatcher.match(".?", ".a")); + + // test matching with **'s + assertTrue(pathMatcher.match(".**", ".testing.testing")); + assertTrue(pathMatcher.match(".*.**", ".testing.testing")); + assertTrue(pathMatcher.match(".**.*", ".testing.testing")); + assertTrue(pathMatcher.match(".bla.**.bla", ".bla.testing.testing.bla")); + assertTrue(pathMatcher.match(".bla.**.bla", ".bla.testing.testing.bla.bla")); + assertTrue(pathMatcher.match(".**.test", ".bla.bla.test")); + assertTrue(pathMatcher.match(".bla.**.**.bla", ".bla.bla.bla.bla.bla.bla")); + assertTrue(pathMatcher.match(".bla*bla.test", ".blaXXXbla.test")); + assertTrue(pathMatcher.match(".*bla.test", ".XXXbla.test")); + assertFalse(pathMatcher.match(".bla*bla.test", ".blaXXXbl.test")); + assertFalse(pathMatcher.match(".*bla.test", "XXXblab.test")); + assertFalse(pathMatcher.match(".*bla.test", "XXXbl.test")); + } + + @Test + public void extractPathWithinPattern() throws Exception { + assertEquals("", pathMatcher.extractPathWithinPattern("/docs/commit.html", "/docs/commit.html")); + + assertEquals("cvs/commit", pathMatcher.extractPathWithinPattern("/docs/*", "/docs/cvs/commit")); + assertEquals("commit.html", pathMatcher.extractPathWithinPattern("/docs/cvs/*.html", "/docs/cvs/commit.html")); + assertEquals("cvs/commit", pathMatcher.extractPathWithinPattern("/docs/**", "/docs/cvs/commit")); + assertEquals("cvs/commit.html", + pathMatcher.extractPathWithinPattern("/docs/**/*.html", "/docs/cvs/commit.html")); + assertEquals("commit.html", pathMatcher.extractPathWithinPattern("/docs/**/*.html", "/docs/commit.html")); + assertEquals("commit.html", pathMatcher.extractPathWithinPattern("/*.html", "/commit.html")); + assertEquals("docs/commit.html", pathMatcher.extractPathWithinPattern("/*.html", "/docs/commit.html")); + assertEquals("/commit.html", pathMatcher.extractPathWithinPattern("*.html", "/commit.html")); + assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("*.html", "/docs/commit.html")); + assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("**/*.*", "/docs/commit.html")); + assertEquals("/docs/commit.html", pathMatcher.extractPathWithinPattern("*", "/docs/commit.html")); + + assertEquals("docs/cvs/commit", pathMatcher.extractPathWithinPattern("/d?cs/*", "/docs/cvs/commit")); + assertEquals("cvs/commit.html", + pathMatcher.extractPathWithinPattern("/docs/c?s/*.html", "/docs/cvs/commit.html")); + assertEquals("docs/cvs/commit", pathMatcher.extractPathWithinPattern("/d?cs/**", "/docs/cvs/commit")); + assertEquals("docs/cvs/commit.html", + pathMatcher.extractPathWithinPattern("/d?cs/**/*.html", "/docs/cvs/commit.html")); + } + + @Test + public void extractUriTemplateVariables() throws Exception { + Map<String, String> result = pathMatcher.extractUriTemplateVariables("/hotels/{hotel}", "/hotels/1"); + assertEquals(Collections.singletonMap("hotel", "1"), result); + + result = pathMatcher.extractUriTemplateVariables("/h?tels/{hotel}", "/hotels/1"); + assertEquals(Collections.singletonMap("hotel", "1"), result); + + result = pathMatcher.extractUriTemplateVariables("/hotels/{hotel}/bookings/{booking}", "/hotels/1/bookings/2"); + Map<String, String> expected = new LinkedHashMap<String, String>(); + expected.put("hotel", "1"); + expected.put("booking", "2"); + assertEquals(expected, result); + + result = pathMatcher.extractUriTemplateVariables("/**/hotels/**/{hotel}", "/foo/hotels/bar/1"); + assertEquals(Collections.singletonMap("hotel", "1"), result); + + result = pathMatcher.extractUriTemplateVariables("/{page}.html", "/42.html"); + assertEquals(Collections.singletonMap("page", "42"), result); + + result = pathMatcher.extractUriTemplateVariables("/{page}.*", "/42.html"); + assertEquals(Collections.singletonMap("page", "42"), result); + + result = pathMatcher.extractUriTemplateVariables("/A-{B}-C", "/A-b-C"); + assertEquals(Collections.singletonMap("B", "b"), result); + + result = pathMatcher.extractUriTemplateVariables("/{name}.{extension}", "/test.html"); + expected = new LinkedHashMap<String, String>(); + expected.put("name", "test"); + expected.put("extension", "html"); + assertEquals(expected, result); + } + + @Test + public void extractUriTemplateVariablesRegex() { + Map<String, String> result = pathMatcher + .extractUriTemplateVariables("{symbolicName:[\\w\\.]+}-{version:[\\w\\.]+}.jar", + "com.example-1.0.0.jar"); + assertEquals("com.example", result.get("symbolicName")); + assertEquals("1.0.0", result.get("version")); + + result = pathMatcher.extractUriTemplateVariables("{symbolicName:[\\w\\.]+}-sources-{version:[\\w\\.]+}.jar", + "com.example-sources-1.0.0.jar"); + assertEquals("com.example", result.get("symbolicName")); + assertEquals("1.0.0", result.get("version")); + } + + // SPR-7787 + + @Test + public void extractUriTemplateVarsRegexQualifiers() { + Map<String, String> result = pathMatcher.extractUriTemplateVariables( + "{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.]+}.jar", + "com.example-sources-1.0.0.jar"); + assertEquals("com.example", result.get("symbolicName")); + assertEquals("1.0.0", result.get("version")); + + result = pathMatcher.extractUriTemplateVariables( + "{symbolicName:[\\w\\.]+}-sources-{version:[\\d\\.]+}-{year:\\d{4}}{month:\\d{2}}{day:\\d{2}}.jar", + "com.example-sources-1.0.0-20100220.jar"); + assertEquals("com.example", result.get("symbolicName")); + assertEquals("1.0.0", result.get("version")); + assertEquals("2010", result.get("year")); + assertEquals("02", result.get("month")); + assertEquals("20", result.get("day")); + + result = pathMatcher.extractUriTemplateVariables( + "{symbolicName:[\\p{L}\\.]+}-sources-{version:[\\p{N}\\.\\{\\}]+}.jar", + "com.example-sources-1.0.0.{12}.jar"); + assertEquals("com.example", result.get("symbolicName")); + assertEquals("1.0.0.{12}", result.get("version")); + } + + // SPR-8455 + + @Test + public void extractUriTemplateVarsRegexCapturingGroups() { + try { + pathMatcher.extractUriTemplateVariables("/web/{id:foo(bar)?}", "/web/foobar"); + fail("Expected exception"); + } catch (IllegalArgumentException e) { + assertTrue("Expected helpful message on the use of capturing groups", + e.getMessage().contains("The number of capturing groups in the pattern")); + } + } + + @Test + public void combine() { + assertEquals("", pathMatcher.combine(null, null)); + assertEquals("/hotels", pathMatcher.combine("/hotels", null)); + assertEquals("/hotels", pathMatcher.combine(null, "/hotels")); + assertEquals("/hotels/booking", pathMatcher.combine("/hotels/*", "booking")); + assertEquals("/hotels/booking", pathMatcher.combine("/hotels/*", "/booking")); + assertEquals("/hotels/**/booking", pathMatcher.combine("/hotels/**", "booking")); + assertEquals("/hotels/**/booking", pathMatcher.combine("/hotels/**", "/booking")); + assertEquals("/hotels/booking", pathMatcher.combine("/hotels", "/booking")); + assertEquals("/hotels/booking", pathMatcher.combine("/hotels", "booking")); + assertEquals("/hotels/{hotel}", pathMatcher.combine("/hotels/*", "{hotel}")); + assertEquals("/hotels/**/{hotel}", pathMatcher.combine("/hotels/**", "{hotel}")); + assertEquals("/hotels/{hotel}", pathMatcher.combine("/hotels", "{hotel}")); + assertEquals("/hotels/{hotel}.*", pathMatcher.combine("/hotels", "{hotel}.*")); + assertEquals("/hotels/*/booking/{booking}", pathMatcher.combine("/hotels/*/booking", "{booking}")); + assertEquals("/hotel.html", pathMatcher.combine("/*.html", "/hotel.html")); + assertEquals("/hotel.html", pathMatcher.combine("/*.html", "/hotel")); + assertEquals("/hotel.html", pathMatcher.combine("/*.html", "/hotel.*")); + assertEquals("/*.html", pathMatcher.combine("/**", "/*.html")); + assertEquals("/*.html", pathMatcher.combine("/*", "/*.html")); + assertEquals("/*.html", pathMatcher.combine("/*.*", "/*.html")); + assertEquals("/{foo}/bar", pathMatcher.combine("/{foo}", "/bar")); // SPR-8858 + assertEquals("/user/user", pathMatcher.combine("/user", "/user")); // SPR-7970 + assertEquals("/{foo:.*[^0-9].*}/edit/", pathMatcher.combine("/{foo:.*[^0-9].*}", "/edit/")); // SPR-10062 + } + + @Test + public void patternComparator() { + Comparator<String> comparator = pathMatcher.getPatternComparator("/hotels/new"); + + assertEquals(0, comparator.compare(null, null)); + assertEquals(1, comparator.compare(null, "/hotels/new")); + assertEquals(-1, comparator.compare("/hotels/new", null)); + + assertEquals(0, comparator.compare("/hotels/new", "/hotels/new")); + + assertEquals(-1, comparator.compare("/hotels/new", "/hotels/*")); + assertEquals(1, comparator.compare("/hotels/*", "/hotels/new")); + assertEquals(0, comparator.compare("/hotels/*", "/hotels/*")); + + assertEquals(-1, comparator.compare("/hotels/new", "/hotels/{hotel}")); + assertEquals(1, comparator.compare("/hotels/{hotel}", "/hotels/new")); + assertEquals(0, comparator.compare("/hotels/{hotel}", "/hotels/{hotel}")); + assertEquals(-1, comparator.compare("/hotels/{hotel}/booking", "/hotels/{hotel}/bookings/{booking}")); + assertEquals(1, comparator.compare("/hotels/{hotel}/bookings/{booking}", "/hotels/{hotel}/booking")); + + assertEquals(-1, comparator.compare("/hotels/{hotel}", "/hotels/*")); + assertEquals(1, comparator.compare("/hotels/*", "/hotels/{hotel}")); + + assertEquals(-2, comparator.compare("/hotels/*", "/hotels/*/**")); + assertEquals(2, comparator.compare("/hotels/*/**", "/hotels/*")); + + assertEquals(-1, comparator.compare("/hotels/new", "/hotels/new.*")); + + // longer is better + assertEquals(1, comparator.compare("/hotels", "/hotels2")); + } + + @Test + public void patternComparatorSort() { + Comparator<String> comparator = pathMatcher.getPatternComparator("/hotels/new"); + List<String> paths = new ArrayList<String>(3); + + paths.add(null); + paths.add("/hotels/new"); + Collections.sort(paths, comparator); + assertEquals("/hotels/new", paths.get(0)); + assertNull(paths.get(1)); + paths.clear(); + + paths.add("/hotels/new"); + paths.add(null); + Collections.sort(paths, comparator); + assertEquals("/hotels/new", paths.get(0)); + assertNull(paths.get(1)); + paths.clear(); + + paths.add("/hotels/*"); + paths.add("/hotels/new"); + Collections.sort(paths, comparator); + assertEquals("/hotels/new", paths.get(0)); + assertEquals("/hotels/*", paths.get(1)); + paths.clear(); + + paths.add("/hotels/new"); + paths.add("/hotels/*"); + Collections.sort(paths, comparator); + assertEquals("/hotels/new", paths.get(0)); + assertEquals("/hotels/*", paths.get(1)); + paths.clear(); + + paths.add("/hotels/**"); + paths.add("/hotels/*"); + Collections.sort(paths, comparator); + assertEquals("/hotels/*", paths.get(0)); + assertEquals("/hotels/**", paths.get(1)); + paths.clear(); + + paths.add("/hotels/*"); + paths.add("/hotels/**"); + Collections.sort(paths, comparator); + assertEquals("/hotels/*", paths.get(0)); + assertEquals("/hotels/**", paths.get(1)); + paths.clear(); + + paths.add("/hotels/{hotel}"); + paths.add("/hotels/new"); + Collections.sort(paths, comparator); + assertEquals("/hotels/new", paths.get(0)); + assertEquals("/hotels/{hotel}", paths.get(1)); + paths.clear(); + + paths.add("/hotels/new"); + paths.add("/hotels/{hotel}"); + Collections.sort(paths, comparator); + assertEquals("/hotels/new", paths.get(0)); + assertEquals("/hotels/{hotel}", paths.get(1)); + paths.clear(); + + paths.add("/hotels/*"); + paths.add("/hotels/{hotel}"); + paths.add("/hotels/new"); + Collections.sort(paths, comparator); + assertEquals("/hotels/new", paths.get(0)); + assertEquals("/hotels/{hotel}", paths.get(1)); + assertEquals("/hotels/*", paths.get(2)); + paths.clear(); + + paths.add("/hotels/ne*"); + paths.add("/hotels/n*"); + Collections.shuffle(paths); + Collections.sort(paths, comparator); + assertEquals("/hotels/ne*", paths.get(0)); + assertEquals("/hotels/n*", paths.get(1)); + paths.clear(); + + comparator = pathMatcher.getPatternComparator("/hotels/new.html"); + paths.add("/hotels/new.*"); + paths.add("/hotels/{hotel}"); + Collections.shuffle(paths); + Collections.sort(paths, comparator); + assertEquals("/hotels/new.*", paths.get(0)); + assertEquals("/hotels/{hotel}", paths.get(1)); + paths.clear(); + + comparator = pathMatcher.getPatternComparator("/web/endUser/action/login.html"); + paths.add("/**/login.*"); + paths.add("/**/endUser/action/login.*"); + Collections.sort(paths, comparator); + assertEquals("/**/endUser/action/login.*", paths.get(0)); + assertEquals("/**/login.*", paths.get(1)); + paths.clear(); + } + + // SPR-8687 + + @Test + public void trimTokensOff() { + pathMatcher.setTrimTokens(false); + + assertTrue(pathMatcher.match("/group/{groupName}/members", "/group/sales/members")); + assertTrue(pathMatcher.match("/group/{groupName}/members", "/group/ sales/members")); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/AssertTests.java b/spring-core/src/test/java/org/springframework/util/AssertTests.java new file mode 100644 index 00000000..0dfe86f1 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/AssertTests.java @@ -0,0 +1,176 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Unit tests for the {@link Assert} class. + * + * @author Keith Donald + * @author Erwin Vervaet + * @author Rick Evans + * @author Arjen Poutsma + */ +public class AssertTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test(expected = IllegalArgumentException.class) + public void instanceOf() { + final Set<?> set = new HashSet<Object>(); + Assert.isInstanceOf(HashSet.class, set); + Assert.isInstanceOf(HashMap.class, set); + } + + @Test + public void instanceOfNoMessage() throws Exception { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Object of class [java.lang.Object] must be an instance " + + "of interface java.util.Set"); + Assert.isInstanceOf(Set.class, new Object(), null); + } + + @Test + public void instanceOfMessage() throws Exception { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage("Custom message. Object of class [java.lang.Object] must " + + "be an instance of interface java.util.Set"); + Assert.isInstanceOf(Set.class, new Object(), "Custom message."); + } + + @Test + public void isNullDoesNotThrowExceptionIfArgumentIsNullWithMessage() { + Assert.isNull(null, "Bla"); + } + + @Test + public void isNullDoesNotThrowExceptionIfArgumentIsNull() { + Assert.isNull(null); + } + + @Test(expected = IllegalArgumentException.class) + public void isNullThrowsExceptionIfArgumentIsNotNull() { + Assert.isNull(new Object()); + } + + @Test(expected = IllegalArgumentException.class) + public void isTrueWithFalseExpressionThrowsException() throws Exception { + Assert.isTrue(false); + } + + @Test + public void isTrueWithTrueExpressionSunnyDay() throws Exception { + Assert.isTrue(true); + } + + @Test(expected = IllegalArgumentException.class) + public void testHasLengthWithNullStringThrowsException() throws Exception { + Assert.hasLength(null); + } + + @Test(expected = IllegalArgumentException.class) + public void hasLengthWithEmptyStringThrowsException() throws Exception { + Assert.hasLength(""); + } + + @Test + public void hasLengthWithWhitespaceOnlyStringDoesNotThrowException() throws Exception { + Assert.hasLength("\t "); + } + + @Test + public void hasLengthSunnyDay() throws Exception { + Assert.hasLength("I Heart ..."); + } + + @Test + public void doesNotContainWithNullSearchStringDoesNotThrowException() throws Exception { + Assert.doesNotContain(null, "rod"); + } + + @Test + public void doesNotContainWithNullSubstringDoesNotThrowException() throws Exception { + Assert.doesNotContain("A cool chick's name is Brod. ", null); + } + + @Test + public void doesNotContainWithEmptySubstringDoesNotThrowException() throws Exception { + Assert.doesNotContain("A cool chick's name is Brod. ", ""); + } + + @Test(expected = IllegalArgumentException.class) + public void assertNotEmptyWithNullCollectionThrowsException() throws Exception { + Assert.notEmpty((Collection<?>) null); + } + + @Test(expected = IllegalArgumentException.class) + public void assertNotEmptyWithEmptyCollectionThrowsException() throws Exception { + Assert.notEmpty(new ArrayList<Object>()); + } + + @Test + public void assertNotEmptyWithCollectionSunnyDay() throws Exception { + List<String> collection = new ArrayList<String>(); + collection.add(""); + Assert.notEmpty(collection); + } + + @Test(expected = IllegalArgumentException.class) + public void assertNotEmptyWithNullMapThrowsException() throws Exception { + Assert.notEmpty((Map<?, ?>) null); + } + + @Test(expected = IllegalArgumentException.class) + public void assertNotEmptyWithEmptyMapThrowsException() throws Exception { + Assert.notEmpty(new HashMap<Object, Object>()); + } + + @Test + public void assertNotEmptyWithMapSunnyDay() throws Exception { + Map<String, String> map = new HashMap<String, String>(); + map.put("", ""); + Assert.notEmpty(map); + } + + @Test(expected = IllegalArgumentException.class) + public void isInstanceofClassWithNullInstanceThrowsException() throws Exception { + Assert.isInstanceOf(String.class, null); + } + + @Test(expected = IllegalStateException.class) + public void stateWithFalseExpressionThrowsException() throws Exception { + Assert.state(false); + } + + @Test + public void stateWithTrueExpressionSunnyDay() throws Exception { + Assert.state(true); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/AutoPopulatingListTests.java b/spring-core/src/test/java/org/springframework/util/AutoPopulatingListTests.java new file mode 100644 index 00000000..550b826f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/AutoPopulatingListTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.LinkedList; + +import junit.framework.*; + +import org.springframework.tests.sample.objects.TestObject; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class AutoPopulatingListTests extends TestCase { + + public void testWithClass() throws Exception { + doTestWithClass(new AutoPopulatingList<Object>(TestObject.class)); + } + + public void testWithClassAndUserSuppliedBackingList() throws Exception { + doTestWithClass(new AutoPopulatingList<Object>(new LinkedList<Object>(), TestObject.class)); + } + + public void testWithElementFactory() throws Exception { + doTestWithElementFactory(new AutoPopulatingList<Object>(new MockElementFactory())); + } + + public void testWithElementFactoryAndUserSuppliedBackingList() throws Exception { + doTestWithElementFactory(new AutoPopulatingList<Object>(new LinkedList<Object>(), new MockElementFactory())); + } + + private void doTestWithClass(AutoPopulatingList<Object> list) { + Object lastElement = null; + for (int x = 0; x < 10; x++) { + Object element = list.get(x); + assertNotNull("Element is null", list.get(x)); + assertTrue("Element is incorrect type", element instanceof TestObject); + assertNotSame(lastElement, element); + lastElement = element; + } + + String helloWorld = "Hello World!"; + list.add(10, null); + list.add(11, helloWorld); + assertEquals(helloWorld, list.get(11)); + + assertTrue(list.get(10) instanceof TestObject); + assertTrue(list.get(12) instanceof TestObject); + assertTrue(list.get(13) instanceof TestObject); + assertTrue(list.get(20) instanceof TestObject); + } + + private void doTestWithElementFactory(AutoPopulatingList<Object> list) { + doTestWithClass(list); + + for(int x = 0; x < list.size(); x++) { + Object element = list.get(x); + if(element instanceof TestObject) { + assertEquals(x, ((TestObject) element).getAge()); + } + } + } + + public void testSerialization() throws Exception { + AutoPopulatingList<?> list = new AutoPopulatingList<Object>(TestObject.class); + assertEquals(list, SerializationTestUtils.serializeAndDeserialize(list)); + } + + + private static class MockElementFactory implements AutoPopulatingList.ElementFactory { + + @Override + public Object createElement(int index) { + TestObject bean = new TestObject(); + bean.setAge(index); + return bean; + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/CachingMapDecoratorTests.java b/spring-core/src/test/java/org/springframework/util/CachingMapDecoratorTests.java new file mode 100644 index 00000000..8e6dcc56 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/CachingMapDecoratorTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import junit.framework.TestCase; + +/** + * @author Keith Donald + * @author Juergen Hoeller + */ +@Deprecated +public class CachingMapDecoratorTests extends TestCase { + + public void testValidCache() { + MyCachingMap cache = new MyCachingMap(); + + assertFalse(cache.containsKey("value key")); + assertFalse(cache.containsValue("expensive value to cache")); + Object value = cache.get("value key"); + assertTrue(cache.createCalled()); + assertEquals(value, "expensive value to cache"); + assertTrue(cache.containsKey("value key")); + assertTrue(cache.containsValue("expensive value to cache")); + + assertFalse(cache.containsKey("value key 2")); + value = cache.get("value key 2"); + assertTrue(cache.createCalled()); + assertEquals(value, "expensive value to cache"); + assertTrue(cache.containsKey("value key 2")); + + value = cache.get("value key"); + assertFalse(cache.createCalled()); + assertEquals(value, "expensive value to cache"); + + cache.get("value key 2"); + assertFalse(cache.createCalled()); + assertEquals(value, "expensive value to cache"); + + assertFalse(cache.containsKey(null)); + assertFalse(cache.containsValue(null)); + value = cache.get(null); + assertTrue(cache.createCalled()); + assertNull(value); + assertTrue(cache.containsKey(null)); + assertTrue(cache.containsValue(null)); + + value = cache.get(null); + assertFalse(cache.createCalled()); + assertNull(value); + + Set<String> keySet = cache.keySet(); + assertEquals(3, keySet.size()); + assertTrue(keySet.contains("value key")); + assertTrue(keySet.contains("value key 2")); + assertTrue(keySet.contains(null)); + + Collection<String> values = cache.values(); + assertEquals(3, values.size()); + assertTrue(values.contains("expensive value to cache")); + assertTrue(values.contains(null)); + + Set<Map.Entry<String, String>> entrySet = cache.entrySet(); + assertEquals(3, entrySet.size()); + keySet = new HashSet<String>(); + values = new HashSet<String>(); + for (Map.Entry<String, String> entry : entrySet) { + keySet.add(entry.getKey()); + values.add(entry.getValue()); + } + assertTrue(keySet.contains("value key")); + assertTrue(keySet.contains("value key 2")); + assertTrue(keySet.contains(null)); + assertEquals(2, values.size()); + assertTrue(values.contains("expensive value to cache")); + assertTrue(values.contains(null)); + } + + + @SuppressWarnings("serial") + private static class MyCachingMap extends CachingMapDecorator<String, String> { + + private boolean createCalled; + + @Override + protected String create(String key) { + createCalled = true; + return (key != null ? "expensive value to cache" : null); + } + + public boolean createCalled() { + boolean c = createCalled; + this.createCalled = false; + return c; + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java new file mode 100644 index 00000000..f29b8b61 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/ClassUtilsTests.java @@ -0,0 +1,401 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.springframework.tests.sample.objects.DerivedTestObject; +import org.springframework.tests.sample.objects.ITestInterface; +import org.springframework.tests.sample.objects.ITestObject; +import org.springframework.tests.sample.objects.TestObject; + +import static org.junit.Assert.*; + +import org.junit.Before; +import org.junit.Test; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @author Rob Harrop + * @author Rick Evans + */ +public class ClassUtilsTests { + + private ClassLoader classLoader = getClass().getClassLoader(); + + @Before + public void setUp() { + InnerClass.noArgCalled = false; + InnerClass.argCalled = false; + InnerClass.overloadedCalled = false; + } + + @Test + public void testIsPresent() throws Exception { + assertTrue(ClassUtils.isPresent("java.lang.String", classLoader)); + assertFalse(ClassUtils.isPresent("java.lang.MySpecialString", classLoader)); + } + + @Test + public void testForName() throws ClassNotFoundException { + assertEquals(String.class, ClassUtils.forName("java.lang.String", classLoader)); + assertEquals(String[].class, ClassUtils.forName("java.lang.String[]", classLoader)); + assertEquals(String[].class, ClassUtils.forName(String[].class.getName(), classLoader)); + assertEquals(String[][].class, ClassUtils.forName(String[][].class.getName(), classLoader)); + assertEquals(String[][][].class, ClassUtils.forName(String[][][].class.getName(), classLoader)); + assertEquals(TestObject.class, ClassUtils.forName("org.springframework.tests.sample.objects.TestObject", classLoader)); + assertEquals(TestObject[].class, ClassUtils.forName("org.springframework.tests.sample.objects.TestObject[]", classLoader)); + assertEquals(TestObject[].class, ClassUtils.forName(TestObject[].class.getName(), classLoader)); + assertEquals(TestObject[][].class, ClassUtils.forName("org.springframework.tests.sample.objects.TestObject[][]", classLoader)); + assertEquals(TestObject[][].class, ClassUtils.forName(TestObject[][].class.getName(), classLoader)); + assertEquals(short[][][].class, ClassUtils.forName("[[[S", classLoader)); + } + + @Test + public void testForNameWithPrimitiveClasses() throws ClassNotFoundException { + assertEquals(boolean.class, ClassUtils.forName("boolean", classLoader)); + assertEquals(byte.class, ClassUtils.forName("byte", classLoader)); + assertEquals(char.class, ClassUtils.forName("char", classLoader)); + assertEquals(short.class, ClassUtils.forName("short", classLoader)); + assertEquals(int.class, ClassUtils.forName("int", classLoader)); + assertEquals(long.class, ClassUtils.forName("long", classLoader)); + assertEquals(float.class, ClassUtils.forName("float", classLoader)); + assertEquals(double.class, ClassUtils.forName("double", classLoader)); + assertEquals(void.class, ClassUtils.forName("void", classLoader)); + } + + @Test + public void testForNameWithPrimitiveArrays() throws ClassNotFoundException { + assertEquals(boolean[].class, ClassUtils.forName("boolean[]", classLoader)); + assertEquals(byte[].class, ClassUtils.forName("byte[]", classLoader)); + assertEquals(char[].class, ClassUtils.forName("char[]", classLoader)); + assertEquals(short[].class, ClassUtils.forName("short[]", classLoader)); + assertEquals(int[].class, ClassUtils.forName("int[]", classLoader)); + assertEquals(long[].class, ClassUtils.forName("long[]", classLoader)); + assertEquals(float[].class, ClassUtils.forName("float[]", classLoader)); + assertEquals(double[].class, ClassUtils.forName("double[]", classLoader)); + } + + @Test + public void testForNameWithPrimitiveArraysInternalName() throws ClassNotFoundException { + assertEquals(boolean[].class, ClassUtils.forName(boolean[].class.getName(), classLoader)); + assertEquals(byte[].class, ClassUtils.forName(byte[].class.getName(), classLoader)); + assertEquals(char[].class, ClassUtils.forName(char[].class.getName(), classLoader)); + assertEquals(short[].class, ClassUtils.forName(short[].class.getName(), classLoader)); + assertEquals(int[].class, ClassUtils.forName(int[].class.getName(), classLoader)); + assertEquals(long[].class, ClassUtils.forName(long[].class.getName(), classLoader)); + assertEquals(float[].class, ClassUtils.forName(float[].class.getName(), classLoader)); + assertEquals(double[].class, ClassUtils.forName(double[].class.getName(), classLoader)); + } + + @Test + public void testGetShortName() { + String className = ClassUtils.getShortName(getClass()); + assertEquals("Class name did not match", "ClassUtilsTests", className); + } + + @Test + public void testGetShortNameForObjectArrayClass() { + String className = ClassUtils.getShortName(Object[].class); + assertEquals("Class name did not match", "Object[]", className); + } + + @Test + public void testGetShortNameForMultiDimensionalObjectArrayClass() { + String className = ClassUtils.getShortName(Object[][].class); + assertEquals("Class name did not match", "Object[][]", className); + } + + @Test + public void testGetShortNameForPrimitiveArrayClass() { + String className = ClassUtils.getShortName(byte[].class); + assertEquals("Class name did not match", "byte[]", className); + } + + @Test + public void testGetShortNameForMultiDimensionalPrimitiveArrayClass() { + String className = ClassUtils.getShortName(byte[][][].class); + assertEquals("Class name did not match", "byte[][][]", className); + } + + @Test + public void testGetShortNameForInnerClass() { + String className = ClassUtils.getShortName(InnerClass.class); + assertEquals("Class name did not match", "ClassUtilsTests.InnerClass", className); + } + + @Test + public void testGetShortNameAsProperty() { + String shortName = ClassUtils.getShortNameAsProperty(this.getClass()); + assertEquals("Class name did not match", "classUtilsTests", shortName); + } + + @Test + public void testGetClassFileName() { + assertEquals("String.class", ClassUtils.getClassFileName(String.class)); + assertEquals("ClassUtilsTests.class", ClassUtils.getClassFileName(getClass())); + } + + @Test + public void testGetPackageName() { + assertEquals("java.lang", ClassUtils.getPackageName(String.class)); + assertEquals(getClass().getPackage().getName(), ClassUtils.getPackageName(getClass())); + } + + @Test + public void testGetQualifiedName() { + String className = ClassUtils.getQualifiedName(getClass()); + assertEquals("Class name did not match", "org.springframework.util.ClassUtilsTests", className); + } + + @Test + public void testGetQualifiedNameForObjectArrayClass() { + String className = ClassUtils.getQualifiedName(Object[].class); + assertEquals("Class name did not match", "java.lang.Object[]", className); + } + + @Test + public void testGetQualifiedNameForMultiDimensionalObjectArrayClass() { + String className = ClassUtils.getQualifiedName(Object[][].class); + assertEquals("Class name did not match", "java.lang.Object[][]", className); + } + + @Test + public void testGetQualifiedNameForPrimitiveArrayClass() { + String className = ClassUtils.getQualifiedName(byte[].class); + assertEquals("Class name did not match", "byte[]", className); + } + + @Test + public void testGetQualifiedNameForMultiDimensionalPrimitiveArrayClass() { + String className = ClassUtils.getQualifiedName(byte[][].class); + assertEquals("Class name did not match", "byte[][]", className); + } + + @Test + public void testHasMethod() throws Exception { + assertTrue(ClassUtils.hasMethod(Collection.class, "size")); + assertTrue(ClassUtils.hasMethod(Collection.class, "remove", Object.class)); + assertFalse(ClassUtils.hasMethod(Collection.class, "remove")); + assertFalse(ClassUtils.hasMethod(Collection.class, "someOtherMethod")); + } + + @Test + public void testGetMethodIfAvailable() throws Exception { + Method method = ClassUtils.getMethodIfAvailable(Collection.class, "size"); + assertNotNull(method); + assertEquals("size", method.getName()); + + method = ClassUtils.getMethodIfAvailable(Collection.class, "remove", new Class[] {Object.class}); + assertNotNull(method); + assertEquals("remove", method.getName()); + + assertNull(ClassUtils.getMethodIfAvailable(Collection.class, "remove")); + assertNull(ClassUtils.getMethodIfAvailable(Collection.class, "someOtherMethod")); + } + + @Test + public void testGetMethodCountForName() { + assertEquals("Verifying number of overloaded 'print' methods for OverloadedMethodsClass.", 2, + ClassUtils.getMethodCountForName(OverloadedMethodsClass.class, "print")); + assertEquals("Verifying number of overloaded 'print' methods for SubOverloadedMethodsClass.", 4, + ClassUtils.getMethodCountForName(SubOverloadedMethodsClass.class, "print")); + } + + @Test + public void testCountOverloadedMethods() { + assertFalse(ClassUtils.hasAtLeastOneMethodWithName(TestObject.class, "foobar")); + // no args + assertTrue(ClassUtils.hasAtLeastOneMethodWithName(TestObject.class, "hashCode")); + // matches although it takes an arg + assertTrue(ClassUtils.hasAtLeastOneMethodWithName(TestObject.class, "setAge")); + } + + @Test + public void testNoArgsStaticMethod() throws IllegalAccessException, InvocationTargetException { + Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod", (Class[]) null); + method.invoke(null, (Object[]) null); + assertTrue("no argument method was not invoked.", + InnerClass.noArgCalled); + } + + @Test + public void testArgsStaticMethod() throws IllegalAccessException, InvocationTargetException { + Method method = ClassUtils.getStaticMethod(InnerClass.class, "argStaticMethod", + new Class[] {String.class}); + method.invoke(null, new Object[] {"test"}); + assertTrue("argument method was not invoked.", InnerClass.argCalled); + } + + @Test + public void testOverloadedStaticMethod() throws IllegalAccessException, InvocationTargetException { + Method method = ClassUtils.getStaticMethod(InnerClass.class, "staticMethod", + new Class[] {String.class}); + method.invoke(null, new Object[] {"test"}); + assertTrue("argument method was not invoked.", + InnerClass.overloadedCalled); + } + + @Test + public void testIsAssignable() { + assertTrue(ClassUtils.isAssignable(Object.class, Object.class)); + assertTrue(ClassUtils.isAssignable(String.class, String.class)); + assertTrue(ClassUtils.isAssignable(Object.class, String.class)); + assertTrue(ClassUtils.isAssignable(Object.class, Integer.class)); + assertTrue(ClassUtils.isAssignable(Number.class, Integer.class)); + assertTrue(ClassUtils.isAssignable(Number.class, int.class)); + assertTrue(ClassUtils.isAssignable(Integer.class, int.class)); + assertTrue(ClassUtils.isAssignable(int.class, Integer.class)); + assertFalse(ClassUtils.isAssignable(String.class, Object.class)); + assertFalse(ClassUtils.isAssignable(Integer.class, Number.class)); + assertFalse(ClassUtils.isAssignable(Integer.class, double.class)); + assertFalse(ClassUtils.isAssignable(double.class, Integer.class)); + } + + @Test + public void testClassPackageAsResourcePath() { + String result = ClassUtils.classPackageAsResourcePath(Proxy.class); + assertTrue(result.equals("java/lang/reflect")); + } + + @Test + public void testAddResourcePathToPackagePath() { + String result = "java/lang/reflect/xyzabc.xml"; + assertEquals(result, ClassUtils.addResourcePathToPackagePath(Proxy.class, "xyzabc.xml")); + assertEquals(result, ClassUtils.addResourcePathToPackagePath(Proxy.class, "/xyzabc.xml")); + + assertEquals("java/lang/reflect/a/b/c/d.xml", + ClassUtils.addResourcePathToPackagePath(Proxy.class, "a/b/c/d.xml")); + } + + @Test + public void testGetAllInterfaces() { + DerivedTestObject testBean = new DerivedTestObject(); + List ifcs = Arrays.asList(ClassUtils.getAllInterfaces(testBean)); + assertEquals("Correct number of interfaces", 4, ifcs.size()); + assertTrue("Contains Serializable", ifcs.contains(Serializable.class)); + assertTrue("Contains ITestBean", ifcs.contains(ITestObject.class)); + assertTrue("Contains IOther", ifcs.contains(ITestInterface.class)); + } + + @Test + public void testClassNamesToString() { + List ifcs = new LinkedList(); + ifcs.add(Serializable.class); + ifcs.add(Runnable.class); + assertEquals("[interface java.io.Serializable, interface java.lang.Runnable]", ifcs.toString()); + assertEquals("[java.io.Serializable, java.lang.Runnable]", ClassUtils.classNamesToString(ifcs)); + + List classes = new LinkedList(); + classes.add(LinkedList.class); + classes.add(Integer.class); + assertEquals("[class java.util.LinkedList, class java.lang.Integer]", classes.toString()); + assertEquals("[java.util.LinkedList, java.lang.Integer]", ClassUtils.classNamesToString(classes)); + + assertEquals("[interface java.util.List]", Collections.singletonList(List.class).toString()); + assertEquals("[java.util.List]", ClassUtils.classNamesToString(List.class)); + + assertEquals("[]", Collections.EMPTY_LIST.toString()); + assertEquals("[]", ClassUtils.classNamesToString(Collections.EMPTY_LIST)); + } + + @Test + public void testDetermineCommonAncestor() { + assertEquals(Number.class, ClassUtils.determineCommonAncestor(Integer.class, Number.class)); + assertEquals(Number.class, ClassUtils.determineCommonAncestor(Number.class, Integer.class)); + assertEquals(Number.class, ClassUtils.determineCommonAncestor(Number.class, null)); + assertEquals(Integer.class, ClassUtils.determineCommonAncestor(null, Integer.class)); + assertEquals(Integer.class, ClassUtils.determineCommonAncestor(Integer.class, Integer.class)); + + assertEquals(Number.class, ClassUtils.determineCommonAncestor(Integer.class, Float.class)); + assertEquals(Number.class, ClassUtils.determineCommonAncestor(Float.class, Integer.class)); + assertNull(ClassUtils.determineCommonAncestor(Integer.class, String.class)); + assertNull(ClassUtils.determineCommonAncestor(String.class, Integer.class)); + + assertEquals(Collection.class, ClassUtils.determineCommonAncestor(List.class, Collection.class)); + assertEquals(Collection.class, ClassUtils.determineCommonAncestor(Collection.class, List.class)); + assertEquals(Collection.class, ClassUtils.determineCommonAncestor(Collection.class, null)); + assertEquals(List.class, ClassUtils.determineCommonAncestor(null, List.class)); + assertEquals(List.class, ClassUtils.determineCommonAncestor(List.class, List.class)); + + assertNull(ClassUtils.determineCommonAncestor(List.class, Set.class)); + assertNull(ClassUtils.determineCommonAncestor(Set.class, List.class)); + assertNull(ClassUtils.determineCommonAncestor(List.class, Runnable.class)); + assertNull(ClassUtils.determineCommonAncestor(Runnable.class, List.class)); + + assertEquals(List.class, ClassUtils.determineCommonAncestor(List.class, ArrayList.class)); + assertEquals(List.class, ClassUtils.determineCommonAncestor(ArrayList.class, List.class)); + assertNull(ClassUtils.determineCommonAncestor(List.class, String.class)); + assertNull(ClassUtils.determineCommonAncestor(String.class, List.class)); + } + + + public static class InnerClass { + + static boolean noArgCalled; + static boolean argCalled; + static boolean overloadedCalled; + + public static void staticMethod() { + noArgCalled = true; + } + + public static void staticMethod(String anArg) { + overloadedCalled = true; + } + + public static void argStaticMethod(String anArg) { + argCalled = true; + } + } + + @SuppressWarnings("unused") + private static class OverloadedMethodsClass { + + public void print(String messages) { + /* no-op */ + } + + public void print(String[] messages) { + /* no-op */ + } + } + + @SuppressWarnings("unused") + private static class SubOverloadedMethodsClass extends OverloadedMethodsClass { + + public void print(String header, String[] messages) { + /* no-op */ + } + + void print(String header, String[] messages, String footer) { + /* no-op */ + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/CollectionUtilsTests.java b/spring-core/src/test/java/org/springframework/util/CollectionUtilsTests.java new file mode 100644 index 00000000..42ac9309 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/CollectionUtilsTests.java @@ -0,0 +1,241 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + * @author Rick Evans + */ +public class CollectionUtilsTests { + + @Test + public void testIsEmpty() { + assertTrue(CollectionUtils.isEmpty((Set<Object>) null)); + assertTrue(CollectionUtils.isEmpty((Map<String, String>) null)); + assertTrue(CollectionUtils.isEmpty(new HashMap<String, String>())); + assertTrue(CollectionUtils.isEmpty(new HashSet<Object>())); + + List<Object> list = new LinkedList<Object>(); + list.add(new Object()); + assertFalse(CollectionUtils.isEmpty(list)); + + Map<String, String> map = new HashMap<String, String>(); + map.put("foo", "bar"); + assertFalse(CollectionUtils.isEmpty(map)); + } + + @Test + public void testMergeArrayIntoCollection() { + Object[] arr = new Object[] {"value1", "value2"}; + List<Comparable<?>> list = new LinkedList<Comparable<?>>(); + list.add("value3"); + + CollectionUtils.mergeArrayIntoCollection(arr, list); + assertEquals("value3", list.get(0)); + assertEquals("value1", list.get(1)); + assertEquals("value2", list.get(2)); + } + + @Test + public void testMergePrimitiveArrayIntoCollection() { + int[] arr = new int[] {1, 2}; + List<Comparable<?>> list = new LinkedList<Comparable<?>>(); + list.add(new Integer(3)); + + CollectionUtils.mergeArrayIntoCollection(arr, list); + assertEquals(new Integer(3), list.get(0)); + assertEquals(new Integer(1), list.get(1)); + assertEquals(new Integer(2), list.get(2)); + } + + @Test + public void testMergePropertiesIntoMap() { + Properties defaults = new Properties(); + defaults.setProperty("prop1", "value1"); + Properties props = new Properties(defaults); + props.setProperty("prop2", "value2"); + props.put("prop3", new Integer(3)); + + Map<String, String> map = new HashMap<String, String>(); + map.put("prop4", "value4"); + + CollectionUtils.mergePropertiesIntoMap(props, map); + assertEquals("value1", map.get("prop1")); + assertEquals("value2", map.get("prop2")); + assertEquals(new Integer(3), map.get("prop3")); + assertEquals("value4", map.get("prop4")); + } + + @Test + public void testContains() { + assertFalse(CollectionUtils.contains((Iterator<String>) null, "myElement")); + assertFalse(CollectionUtils.contains((Enumeration<String>) null, "myElement")); + assertFalse(CollectionUtils.contains(new LinkedList<String>().iterator(), "myElement")); + assertFalse(CollectionUtils.contains(new Hashtable<String, Object>().keys(), "myElement")); + + List<String> list = new LinkedList<String>(); + list.add("myElement"); + assertTrue(CollectionUtils.contains(list.iterator(), "myElement")); + + Hashtable<String, String> ht = new Hashtable<String, String>(); + ht.put("myElement", "myValue"); + assertTrue(CollectionUtils.contains(ht.keys(), "myElement")); + } + + @Test + public void testContainsAny() throws Exception { + List<String> source = new ArrayList<String>(); + source.add("abc"); + source.add("def"); + source.add("ghi"); + + List<String> candidates = new ArrayList<String>(); + candidates.add("xyz"); + candidates.add("def"); + candidates.add("abc"); + + assertTrue(CollectionUtils.containsAny(source, candidates)); + candidates.remove("def"); + assertTrue(CollectionUtils.containsAny(source, candidates)); + candidates.remove("abc"); + assertFalse(CollectionUtils.containsAny(source, candidates)); + } + + @Test + public void testContainsInstanceWithNullCollection() throws Exception { + assertFalse("Must return false if supplied Collection argument is null", + CollectionUtils.containsInstance(null, this)); + } + + @Test + public void testContainsInstanceWithInstancesThatAreEqualButDistinct() throws Exception { + List<Instance> list = new ArrayList<Instance>(); + list.add(new Instance("fiona")); + assertFalse("Must return false if instance is not in the supplied Collection argument", + CollectionUtils.containsInstance(list, new Instance("fiona"))); + } + + @Test + public void testContainsInstanceWithSameInstance() throws Exception { + List<Instance> list = new ArrayList<Instance>(); + list.add(new Instance("apple")); + Instance instance = new Instance("fiona"); + list.add(instance); + assertTrue("Must return true if instance is in the supplied Collection argument", + CollectionUtils.containsInstance(list, instance)); + } + + @Test + public void testContainsInstanceWithNullInstance() throws Exception { + List<Instance> list = new ArrayList<Instance>(); + list.add(new Instance("apple")); + list.add(new Instance("fiona")); + assertFalse("Must return false if null instance is supplied", + CollectionUtils.containsInstance(list, null)); + } + + @Test + public void testFindFirstMatch() throws Exception { + List<String> source = new ArrayList<String>(); + source.add("abc"); + source.add("def"); + source.add("ghi"); + + List<String> candidates = new ArrayList<String>(); + candidates.add("xyz"); + candidates.add("def"); + candidates.add("abc"); + + assertEquals("def", CollectionUtils.findFirstMatch(source, candidates)); + } + + @Test + public void testHasUniqueObject() { + List<String> list = new LinkedList<String>(); + list.add("myElement"); + list.add("myOtherElement"); + assertFalse(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList<String>(); + list.add("myElement"); + assertTrue(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList<String>(); + list.add("myElement"); + list.add(null); + assertFalse(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList<String>(); + list.add(null); + list.add("myElement"); + assertFalse(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList<String>(); + list.add(null); + list.add(null); + assertTrue(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList<String>(); + list.add(null); + assertTrue(CollectionUtils.hasUniqueObject(list)); + + list = new LinkedList<String>(); + assertFalse(CollectionUtils.hasUniqueObject(list)); + } + + + private static final class Instance { + + private final String name; + + public Instance(String name) { + this.name = name; + } + + public boolean equals(Object rhs) { + if (this == rhs) { + return true; + } + if (rhs == null || this.getClass() != rhs.getClass()) { + return false; + } + Instance instance = (Instance) rhs; + return this.name.equals(instance.name); + } + + public int hashCode() { + return this.name.hashCode(); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/CompositeIteratorTests.java b/spring-core/src/test/java/org/springframework/util/CompositeIteratorTests.java new file mode 100644 index 00000000..124bc04a --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/CompositeIteratorTests.java @@ -0,0 +1,129 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +import org.junit.Test; + +import static org.junit.Assert.*; + + +/** + * Test case for {@link CompositeIterator}. + * + * @author Erwin Vervaet + * @author Juergen Hoeller + */ +public class CompositeIteratorTests { + + @Test + public void testNoIterators() { + CompositeIterator<String> it = new CompositeIterator<String>(); + assertFalse(it.hasNext()); + try { + it.next(); + fail(); + } + catch (NoSuchElementException ex) { + // expected + } + } + + @Test + public void testSingleIterator() { + CompositeIterator<String> it = new CompositeIterator<String>(); + it.add(Arrays.asList("0", "1").iterator()); + for (int i = 0; i < 2; i++) { + assertTrue(it.hasNext()); + assertEquals(String.valueOf(i), it.next()); + } + assertFalse(it.hasNext()); + try { + it.next(); + fail(); + } + catch (NoSuchElementException ex) { + // expected + } + } + + @Test + public void testMultipleIterators() { + CompositeIterator<String> it = new CompositeIterator<String>(); + it.add(Arrays.asList("0", "1").iterator()); + it.add(Arrays.asList("2").iterator()); + it.add(Arrays.asList("3", "4").iterator()); + for (int i = 0; i < 5; i++) { + assertTrue(it.hasNext()); + assertEquals(String.valueOf(i), it.next()); + } + assertFalse(it.hasNext()); + try { + it.next(); + fail(); + } + catch (NoSuchElementException ex) { + // expected + } + } + + @Test + public void testInUse() { + List<String> list = Arrays.asList("0", "1"); + CompositeIterator<String> it = new CompositeIterator<String>(); + it.add(list.iterator()); + it.hasNext(); + try { + it.add(list.iterator()); + fail(); + } + catch (IllegalStateException ex) { + // expected + } + it = new CompositeIterator<String>(); + it.add(list.iterator()); + it.next(); + try { + it.add(list.iterator()); + fail(); + } + catch (IllegalStateException ex) { + // expected + } + } + + @Test + public void testDuplicateIterators() { + List<String> list = Arrays.asList("0", "1"); + Iterator<String> iterator = list.iterator(); + CompositeIterator<String> it = new CompositeIterator<String>(); + it.add(iterator); + it.add(list.iterator()); + try { + it.add(iterator); + fail(); + } + catch (IllegalArgumentException ex) { + // expected + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/ConcurrentReferenceHashMapTests.java b/spring-core/src/test/java/org/springframework/util/ConcurrentReferenceHashMapTests.java new file mode 100644 index 00000000..d585d0ae --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/ConcurrentReferenceHashMapTests.java @@ -0,0 +1,674 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; + +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import org.springframework.util.ConcurrentReferenceHashMap.Entry; +import org.springframework.util.ConcurrentReferenceHashMap.Reference; +import org.springframework.util.ConcurrentReferenceHashMap.Restructure; +import org.springframework.util.comparator.ComparableComparator; +import org.springframework.util.comparator.NullSafeComparator; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +/** + * Tests for {@link ConcurrentReferenceHashMap}. + * + * @author Phillip Webb + */ +public class ConcurrentReferenceHashMapTests { + + private static final Comparator<? super String> NULL_SAFE_STRING_SORT = new NullSafeComparator<String>( + new ComparableComparator<String>(), true); + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + private TestWeakConcurrentCache<Integer, String> map = new TestWeakConcurrentCache<Integer, String>(); + + + @Test + public void shouldCreateWithDefaults() throws Exception { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(); + assertThat(map.getSegmentsSize(), is(16)); + assertThat(map.getSegment(0).getSize(), is(1)); + assertThat(map.getLoadFactor(), is(0.75f)); + } + + @Test + public void shouldCreateWithInitialCapacity() throws Exception { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(32); + assertThat(map.getSegmentsSize(), is(16)); + assertThat(map.getSegment(0).getSize(), is(2)); + assertThat(map.getLoadFactor(), is(0.75f)); + } + + @Test + public void shouldCreateWithInitialCapacityAndLoadFactor() throws Exception { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(32, 0.5f); + assertThat(map.getSegmentsSize(), is(16)); + assertThat(map.getSegment(0).getSize(), is(2)); + assertThat(map.getLoadFactor(), is(0.5f)); + } + + @Test + public void shouldCreateWithInitialCapacityAndConcurrenyLevel() throws Exception { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(16, 2); + assertThat(map.getSegmentsSize(), is(2)); + assertThat(map.getSegment(0).getSize(), is(8)); + assertThat(map.getLoadFactor(), is(0.75f)); + } + + @Test + public void shouldCreateFullyCustom() throws Exception { + ConcurrentReferenceHashMap<Integer, String> map = new ConcurrentReferenceHashMap<Integer, String>(5, 0.5f, 3); + // concurrencyLevel of 3 ends up as 4 (nearest power of 2) + assertThat(map.getSegmentsSize(), is(4)); + // initialCapacity is 5/4 (rounded up, to nearest power of 2) + assertThat(map.getSegment(0).getSize(), is(2)); + assertThat(map.getLoadFactor(), is(0.5f)); + } + + @Test + public void shouldNeedNonNegativeInitialCapacity() throws Exception { + new ConcurrentReferenceHashMap<Integer, String>(0, 1); + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Initial capacity must not be negative"); + new TestWeakConcurrentCache<Integer, String>(-1, 1); + } + + @Test + public void shouldNeedPositiveLoadFactor() throws Exception { + new ConcurrentReferenceHashMap<Integer, String>(0, 0.1f, 1); + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Load factor must be positive"); + new TestWeakConcurrentCache<Integer, String>(0, 0.0f, 1); + } + + @Test + public void shouldNeedPositiveConcurrencyLevel() throws Exception { + new ConcurrentReferenceHashMap<Integer, String>(1, 1); + this.thrown.expect(IllegalArgumentException.class); + this.thrown.expectMessage("Concurrency level must be positive"); + new TestWeakConcurrentCache<Integer, String>(1, 0); + } + + @Test + public void shouldPutAndGet() throws Exception { + // NOTE we are using mock references so we don't need to worry about GC + assertThat(this.map.size(), is(0)); + this.map.put(123, "123"); + assertThat(this.map.get(123), is("123")); + assertThat(this.map.size(), is(1)); + this.map.put(123, "123b"); + assertThat(this.map.size(), is(1)); + this.map.put(123, null); + assertThat(this.map.size(), is(1)); + } + + @Test + public void shouldReplaceOnDoublePut() throws Exception { + this.map.put(123, "321"); + this.map.put(123, "123"); + assertThat(this.map.get(123), is("123")); + } + + @Test + public void shouldPutNullKey() throws Exception { + this.map.put(null, "123"); + assertThat(this.map.get(null), is("123")); + } + + @Test + public void shouldPutNullValue() throws Exception { + this.map.put(123, "321"); + this.map.put(123, null); + assertThat(this.map.get(123), is(nullValue())); + } + + @Test + public void shouldGetWithNoItems() throws Exception { + assertThat(this.map.get(123), is(nullValue())); + } + + @Test + public void shouldApplySupplimentalHash() throws Exception { + Integer key = 123; + this.map.put(key, "123"); + assertThat(this.map.getSupplimentalHash(), is(not(key.hashCode()))); + assertThat(this.map.getSupplimentalHash() >> 30 & 0xFF, is(not(0))); + } + + @Test + public void shouldGetFollowingNexts() throws Exception { + // Use loadFactor to disable resize + this.map = new TestWeakConcurrentCache<Integer, String>(1, 10.0f, 1); + this.map.put(1, "1"); + this.map.put(2, "2"); + this.map.put(3, "3"); + assertThat(this.map.getSegment(0).getSize(), is(1)); + assertThat(this.map.get(1), is("1")); + assertThat(this.map.get(2), is("2")); + assertThat(this.map.get(3), is("3")); + assertThat(this.map.get(4), is(nullValue())); + } + + @Test + public void shouldResize() throws Exception { + this.map = new TestWeakConcurrentCache<Integer, String>(1, 0.75f, 1); + this.map.put(1, "1"); + assertThat(this.map.getSegment(0).getSize(), is(1)); + assertThat(this.map.get(1), is("1")); + + this.map.put(2, "2"); + assertThat(this.map.getSegment(0).getSize(), is(2)); + assertThat(this.map.get(1), is("1")); + assertThat(this.map.get(2), is("2")); + + this.map.put(3, "3"); + assertThat(this.map.getSegment(0).getSize(), is(4)); + assertThat(this.map.get(1), is("1")); + assertThat(this.map.get(2), is("2")); + assertThat(this.map.get(3), is("3")); + + this.map.put(4, "4"); + assertThat(this.map.getSegment(0).getSize(), is(8)); + assertThat(this.map.get(4), is("4")); + + // Putting again should not increase the count + for (int i = 1; i <= 5; i++) { + this.map.put(i, String.valueOf(i)); + } + assertThat(this.map.getSegment(0).getSize(), is(8)); + assertThat(this.map.get(5), is("5")); + } + + @Test + public void shouldPurgeOnGet() throws Exception { + this.map = new TestWeakConcurrentCache<Integer, String>(1, 0.75f, 1); + for (int i = 1; i <= 5; i++) { + this.map.put(i, String.valueOf(i)); + } + this.map.getMockReference(1, Restructure.NEVER).queueForPurge(); + this.map.getMockReference(3, Restructure.NEVER).queueForPurge(); + assertThat(this.map.getReference(1, Restructure.WHEN_NECESSARY), is(nullValue())); + assertThat(this.map.get(2), is("2")); + assertThat(this.map.getReference(3, Restructure.WHEN_NECESSARY), is(nullValue())); + assertThat(this.map.get(4), is("4")); + assertThat(this.map.get(5), is("5")); + } + + @Test + public void shouldPergeOnPut() throws Exception { + this.map = new TestWeakConcurrentCache<Integer, String>(1, 0.75f, 1); + for (int i = 1; i <= 5; i++) { + this.map.put(i, String.valueOf(i)); + } + this.map.getMockReference(1, Restructure.NEVER).queueForPurge(); + this.map.getMockReference(3, Restructure.NEVER).queueForPurge(); + this.map.put(1, "1"); + assertThat(this.map.get(1), is("1")); + assertThat(this.map.get(2), is("2")); + assertThat(this.map.getReference(3, Restructure.WHEN_NECESSARY), is(nullValue())); + assertThat(this.map.get(4), is("4")); + assertThat(this.map.get(5), is("5")); + } + + @Test + public void shouldPutIfAbsent() throws Exception { + assertThat(this.map.putIfAbsent(123, "123"), is(nullValue())); + assertThat(this.map.putIfAbsent(123, "123b"), is("123")); + assertThat(this.map.get(123), is("123")); + } + + @Test + public void shouldPutIfAbsentWithNullValue() throws Exception { + assertThat(this.map.putIfAbsent(123, null), is(nullValue())); + assertThat(this.map.putIfAbsent(123, "123"), is(nullValue())); + assertThat(this.map.get(123), is(nullValue())); + } + + @Test + public void shouldPutIfAbsentWithNullKey() throws Exception { + assertThat(this.map.putIfAbsent(null, "123"), is(nullValue())); + assertThat(this.map.putIfAbsent(null, "123b"), is("123")); + assertThat(this.map.get(null), is("123")); + } + + @Test + public void shouldRemoveKeyAndValue() throws Exception { + this.map.put(123, "123"); + assertThat(this.map.remove(123, "456"), is(false)); + assertThat(this.map.get(123), is("123")); + assertThat(this.map.remove(123, "123"), is(true)); + assertFalse(this.map.containsKey(123)); + assertThat(this.map.isEmpty(), is(true)); + } + + @Test + public void shouldRemoveKeyAndValueWithExistingNull() throws Exception { + this.map.put(123, null); + assertThat(this.map.remove(123, "456"), is(false)); + assertThat(this.map.get(123), is(nullValue())); + assertThat(this.map.remove(123, null), is(true)); + assertFalse(this.map.containsKey(123)); + assertThat(this.map.isEmpty(), is(true)); + } + + @Test + public void shouldReplaceOldValueWithNewValue() throws Exception { + this.map.put(123, "123"); + assertThat(this.map.replace(123, "456", "789"), is(false)); + assertThat(this.map.get(123), is("123")); + assertThat(this.map.replace(123, "123", "789"), is(true)); + assertThat(this.map.get(123), is("789")); + } + + @Test + public void shouldReplaceOldNullValueWithNewValue() throws Exception { + this.map.put(123, null); + assertThat(this.map.replace(123, "456", "789"), is(false)); + assertThat(this.map.get(123), is(nullValue())); + assertThat(this.map.replace(123, null, "789"), is(true)); + assertThat(this.map.get(123), is("789")); + } + + @Test + public void shouldReplaceValue() throws Exception { + this.map.put(123, "123"); + assertThat(this.map.replace(123, "456"), is("123")); + assertThat(this.map.get(123), is("456")); + } + + @Test + public void shouldReplaceNullValue() throws Exception { + this.map.put(123, null); + assertThat(this.map.replace(123, "456"), is(nullValue())); + assertThat(this.map.get(123), is("456")); + } + + @Test + public void shouldGetSize() throws Exception { + assertThat(this.map.size(), is(0)); + this.map.put(123, "123"); + this.map.put(123, null); + this.map.put(456, "456"); + assertThat(this.map.size(), is(2)); + } + + @Test + public void shouldSupportIsEmpty() throws Exception { + assertThat(this.map.isEmpty(), is(true)); + this.map.put(123, "123"); + this.map.put(123, null); + this.map.put(456, "456"); + assertThat(this.map.isEmpty(), is(false)); + } + + @Test + public void shouldContainKey() throws Exception { + assertThat(this.map.containsKey(123), is(false)); + assertThat(this.map.containsKey(456), is(false)); + this.map.put(123, "123"); + this.map.put(456, null); + assertThat(this.map.containsKey(123), is(true)); + assertThat(this.map.containsKey(456), is(true)); + } + + @Test + public void shouldContainValue() throws Exception { + assertThat(this.map.containsValue("123"), is(false)); + assertThat(this.map.containsValue(null), is(false)); + this.map.put(123, "123"); + this.map.put(456, null); + assertThat(this.map.containsValue("123"), is(true)); + assertThat(this.map.containsValue(null), is(true)); + } + + @Test + public void shouldRemoveWhenKeyIsInMap() throws Exception { + this.map.put(123, null); + this.map.put(456, "456"); + this.map.put(null, "789"); + assertThat(this.map.remove(123), is(nullValue())); + assertThat(this.map.remove(456), is("456")); + assertThat(this.map.remove(null), is("789")); + assertThat(this.map.isEmpty(), is(true)); + } + + @Test + public void shouldRemoveWhenKeyIsNotInMap() throws Exception { + assertThat(this.map.remove(123), is(nullValue())); + assertThat(this.map.remove(null), is(nullValue())); + assertThat(this.map.isEmpty(), is(true)); + } + + @Test + public void shouldPutAll() throws Exception { + Map<Integer, String> m = new HashMap<Integer, String>(); + m.put(123, "123"); + m.put(456, null); + m.put(null, "789"); + this.map.putAll(m); + assertThat(this.map.size(), is(3)); + assertThat(this.map.get(123), is("123")); + assertThat(this.map.get(456), is(nullValue())); + assertThat(this.map.get(null), is("789")); + } + + @Test + public void shouldClear() throws Exception { + this.map.put(123, "123"); + this.map.put(456, null); + this.map.put(null, "789"); + this.map.clear(); + assertThat(this.map.size(), is(0)); + assertThat(this.map.containsKey(123), is(false)); + assertThat(this.map.containsKey(456), is(false)); + assertThat(this.map.containsKey(null), is(false)); + } + + @Test + public void shouldGetKeySet() throws Exception { + this.map.put(123, "123"); + this.map.put(456, null); + this.map.put(null, "789"); + Set<Integer> expected = new HashSet<Integer>(); + expected.add(123); + expected.add(456); + expected.add(null); + assertThat(this.map.keySet(), is(expected)); + } + + @Test + public void shouldGetValues() throws Exception { + this.map.put(123, "123"); + this.map.put(456, null); + this.map.put(null, "789"); + List<String> actual = new ArrayList<String>(this.map.values()); + List<String> expected = new ArrayList<String>(); + expected.add("123"); + expected.add(null); + expected.add("789"); + Collections.sort(actual, NULL_SAFE_STRING_SORT); + Collections.sort(expected, NULL_SAFE_STRING_SORT); + assertThat(actual, is(expected)); + } + + @Test + public void shouldGetEntrySet() throws Exception { + this.map.put(123, "123"); + this.map.put(456, null); + this.map.put(null, "789"); + HashMap<Integer, String> expected = new HashMap<Integer, String>(); + expected.put(123, "123"); + expected.put(456, null); + expected.put(null, "789"); + assertThat(this.map.entrySet(), is(expected.entrySet())); + } + + @Test + public void shouldGetEntrySetFollowingNext() throws Exception { + // Use loadFactor to disable resize + this.map = new TestWeakConcurrentCache<Integer, String>(1, 10.0f, 1); + this.map.put(1, "1"); + this.map.put(2, "2"); + this.map.put(3, "3"); + HashMap<Integer, String> expected = new HashMap<Integer, String>(); + expected.put(1, "1"); + expected.put(2, "2"); + expected.put(3, "3"); + assertThat(this.map.entrySet(), is(expected.entrySet())); + } + + @Test + public void shouldRemoveViaEntrySet() throws Exception { + this.map.put(1, "1"); + this.map.put(2, "2"); + this.map.put(3, "3"); + Iterator<Map.Entry<Integer, String>> iterator = this.map.entrySet().iterator(); + iterator.next(); + iterator.next(); + iterator.remove(); + iterator.next(); + assertThat(iterator.hasNext(), is(false)); + assertThat(this.map.size(), is(2)); + assertThat(this.map.containsKey(2), is(false)); + } + + @Test + public void shouldSetViaEntrySet() throws Exception { + this.map.put(1, "1"); + this.map.put(2, "2"); + this.map.put(3, "3"); + Iterator<Map.Entry<Integer, String>> iterator = this.map.entrySet().iterator(); + iterator.next(); + iterator.next().setValue("2b"); + iterator.next(); + assertThat(iterator.hasNext(), is(false)); + assertThat(this.map.size(), is(3)); + assertThat(this.map.get(2), is("2b")); + } + + @Test + @Ignore("Intended for use during development only") + public void shouldBeFasterThanSynchronizedMap() throws Exception { + Map<Integer, WeakReference<String>> synchronizedMap = Collections.synchronizedMap(new WeakHashMap<Integer, WeakReference<String>>()); + StopWatch mapTime = timeMultiThreaded("SynchronizedMap", synchronizedMap, + new ValueFactory<WeakReference<String>>() { + + @Override + public WeakReference<String> newValue(int v) { + return new WeakReference<String>(String.valueOf(v)); + } + }); + System.out.println(mapTime.prettyPrint()); + + this.map.setDisableTestHooks(true); + StopWatch cacheTime = timeMultiThreaded("WeakConcurrentCache", this.map, + new ValueFactory<String>() { + + @Override + public String newValue(int v) { + return String.valueOf(v); + } + }); + System.out.println(cacheTime.prettyPrint()); + + // We should be at least 4 time faster + assertThat(cacheTime.getTotalTimeSeconds(), + is(lessThan(mapTime.getTotalTimeSeconds() / 4.0))); + } + + @Test + public void shouldSupportNullReference() throws Exception { + // GC could happen during restructure so we must be able to create a reference for a null entry + map.createReferenceManager().createReference(null, 1234, null); + } + + /** + * Time a multi-threaded access to a cache. + * @return the timing stopwatch + */ + private <V> StopWatch timeMultiThreaded(String id, final Map<Integer, V> map, + ValueFactory<V> factory) throws InterruptedException { + + StopWatch stopWatch = new StopWatch(id); + for (int i = 0; i < 500; i++) { + map.put(i, factory.newValue(i)); + } + Thread[] threads = new Thread[30]; + stopWatch.start("Running threads"); + for (int threadIndex = 0; threadIndex < threads.length; threadIndex++) { + threads[threadIndex] = new Thread("Cache access thread " + threadIndex) { + @Override + public void run() { + for (int j = 0; j < 1000; j++) { + for (int i = 0; i < 1000; i++) { + map.get(i); + } + } + } + }; + } + for (Thread thread : threads) { + thread.start(); + } + + for (Thread thread : threads) { + if (thread.isAlive()) { + thread.join(2000); + } + } + stopWatch.stop(); + return stopWatch; + } + + + private static interface ValueFactory<V> { + + V newValue(int k); + } + + + private static class TestWeakConcurrentCache<K, V> extends ConcurrentReferenceHashMap<K, V> { + + private int supplimentalHash; + + private final LinkedList<MockReference<K, V>> queue = new LinkedList<MockReference<K, V>>(); + + private boolean disableTestHooks; + + public TestWeakConcurrentCache() { + super(); + } + + public void setDisableTestHooks(boolean disableTestHooks) { + this.disableTestHooks = disableTestHooks; + } + + public TestWeakConcurrentCache(int initialCapacity, float loadFactor, int concurrencyLevel) { + super(initialCapacity, loadFactor, concurrencyLevel); + } + + public TestWeakConcurrentCache(int initialCapacity, int concurrencyLevel) { + super(initialCapacity, concurrencyLevel); + } + + @Override + protected int getHash(Object o) { + if (this.disableTestHooks) { + return super.getHash(o); + } + // For testing we want more control of the hash + this.supplimentalHash = super.getHash(o); + return o == null ? 0 : o.hashCode(); + } + + public int getSupplimentalHash() { + return this.supplimentalHash; + } + + @Override + protected ReferenceManager createReferenceManager() { + return new ReferenceManager() { + @Override + public Reference<K, V> createReference(Entry<K, V> entry, int hash, + Reference<K, V> next) { + if (TestWeakConcurrentCache.this.disableTestHooks) { + return super.createReference(entry, hash, next); + } + return new MockReference<K, V>(entry, hash, next, TestWeakConcurrentCache.this.queue); + } + @Override + public Reference<K, V> pollForPurge() { + if (TestWeakConcurrentCache.this.disableTestHooks) { + return super.pollForPurge(); + } + return TestWeakConcurrentCache.this.queue.isEmpty() ? null : TestWeakConcurrentCache.this.queue.removeFirst(); + } + }; + } + + public MockReference<K, V> getMockReference(K key, Restructure restructure) { + return (MockReference<K, V>) super.getReference(key, restructure); + } + } + + + private static class MockReference<K, V> implements Reference<K, V> { + + private final int hash; + + private Entry<K, V> entry; + + private final Reference<K, V> next; + + private final LinkedList<MockReference<K, V>> queue; + + public MockReference(Entry<K, V> entry, int hash, Reference<K, V> next, LinkedList<MockReference<K, V>> queue) { + this.hash = hash; + this.entry = entry; + this.next = next; + this.queue = queue; + } + + @Override + public Entry<K, V> get() { + return this.entry; + } + + @Override + public int getHash() { + return this.hash; + } + + @Override + public Reference<K, V> getNext() { + return this.next; + } + + @Override + public void release() { + this.queue.add(this); + this.entry = null; + } + + public void queueForPurge() { + this.queue.add(this); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/DigestUtilsTests.java b/spring-core/src/test/java/org/springframework/util/DigestUtilsTests.java new file mode 100644 index 00000000..7233ad38 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/DigestUtilsTests.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.UnsupportedEncodingException; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +public class DigestUtilsTests { + + private byte[] bytes; + + @Before + public void createBytes() throws UnsupportedEncodingException { + bytes = "Hello World".getBytes("UTF-8"); + } + + @Test + public void md5() { + byte[] result = DigestUtils.md5Digest(bytes); + byte[] expected = new byte[]{-0x4f, 0xa, -0x73, -0x4f, 0x64, -0x20, 0x75, 0x41, 0x5, -0x49, -0x57, -0x65, -0x19, + 0x2e, 0x3f, -0x1b}; + assertArrayEquals("Invalid hash", expected, result); + } + + @Test + public void md5Hex() throws UnsupportedEncodingException { + String hash = DigestUtils.md5DigestAsHex(bytes); + assertEquals("Invalid hash", "b10a8db164e0754105b7a99be72e3fe5", hash); + } + + @Test + public void md5StringBuilder() throws UnsupportedEncodingException { + StringBuilder builder = new StringBuilder(); + DigestUtils.appendMd5DigestAsHex(bytes, builder); + assertEquals("Invalid hash", "b10a8db164e0754105b7a99be72e3fe5", builder.toString()); + } + + +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/util/FileCopyUtilsTests.java b/spring-core/src/test/java/org/springframework/util/FileCopyUtilsTests.java new file mode 100644 index 00000000..6848c4d1 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/FileCopyUtilsTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2006 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Arrays; + +import junit.framework.TestCase; + +/** + * Unit tests for the FileCopyUtils class. + * + * @author Juergen Hoeller + * @since 12.03.2005 + */ +public class FileCopyUtilsTests extends TestCase { + + public void testCopyFromInputStream() throws IOException { + byte[] content = "content".getBytes(); + ByteArrayInputStream in = new ByteArrayInputStream(content); + ByteArrayOutputStream out = new ByteArrayOutputStream(content.length); + int count = FileCopyUtils.copy(in, out); + assertEquals(content.length, count); + assertTrue(Arrays.equals(content, out.toByteArray())); + } + + public void testCopyFromByteArray() throws IOException { + byte[] content = "content".getBytes(); + ByteArrayOutputStream out = new ByteArrayOutputStream(content.length); + FileCopyUtils.copy(content, out); + assertTrue(Arrays.equals(content, out.toByteArray())); + } + + public void testCopyToByteArray() throws IOException { + byte[] content = "content".getBytes(); + ByteArrayInputStream in = new ByteArrayInputStream(content); + byte[] result = FileCopyUtils.copyToByteArray(in); + assertTrue(Arrays.equals(content, result)); + } + + public void testCopyFromReader() throws IOException { + String content = "content"; + StringReader in = new StringReader(content); + StringWriter out = new StringWriter(); + int count = FileCopyUtils.copy(in, out); + assertEquals(content.length(), count); + assertEquals(content, out.toString()); + } + + public void testCopyFromString() throws IOException { + String content = "content"; + StringWriter out = new StringWriter(); + FileCopyUtils.copy(content, out); + assertEquals(content, out.toString()); + } + + public void testCopyToString() throws IOException { + String content = "content"; + StringReader in = new StringReader(content); + String result = FileCopyUtils.copyToString(in); + assertEquals(content, result); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/FileSystemUtilsTests.java b/spring-core/src/test/java/org/springframework/util/FileSystemUtilsTests.java new file mode 100644 index 00000000..d87212c1 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/FileSystemUtilsTests.java @@ -0,0 +1,89 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.File; + +import junit.framework.TestCase; + +/** + * @author Rob Harrop + */ +public class FileSystemUtilsTests extends TestCase { + + public void testDeleteRecursively() throws Exception { + File root = new File("./tmp/root"); + File child = new File(root, "child"); + File grandchild = new File(child, "grandchild"); + + grandchild.mkdirs(); + + File bar = new File(child, "bar.txt"); + bar.createNewFile(); + + assertTrue(root.exists()); + assertTrue(child.exists()); + assertTrue(grandchild.exists()); + assertTrue(bar.exists()); + + FileSystemUtils.deleteRecursively(root); + + assertFalse(root.exists()); + assertFalse(child.exists()); + assertFalse(grandchild.exists()); + assertFalse(bar.exists()); + } + + public void testCopyRecursively() throws Exception { + File src = new File("./tmp/src"); + File child = new File(src, "child"); + File grandchild = new File(child, "grandchild"); + + grandchild.mkdirs(); + + File bar = new File(child, "bar.txt"); + bar.createNewFile(); + + assertTrue(src.exists()); + assertTrue(child.exists()); + assertTrue(grandchild.exists()); + assertTrue(bar.exists()); + + File dest = new File("./dest"); + FileSystemUtils.copyRecursively(src, dest); + + assertTrue(dest.exists()); + assertTrue(new File(dest, child.getName()).exists()); + + FileSystemUtils.deleteRecursively(src); + assertTrue(!src.exists()); + } + + @Override + protected void tearDown() throws Exception { + File tmp = new File("./tmp"); + if (tmp.exists()) { + FileSystemUtils.deleteRecursively(tmp); + } + File dest = new File("./dest"); + if (dest.exists()) { + FileSystemUtils.deleteRecursively(dest); + } + super.tearDown(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java b/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java new file mode 100644 index 00000000..7d3b171b --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/LinkedCaseInsensitiveMapTests.java @@ -0,0 +1,58 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Juergen Hoeller + */ +public class LinkedCaseInsensitiveMapTests { + + private LinkedCaseInsensitiveMap<String> map; + + @Before + public void setUp() { + map = new LinkedCaseInsensitiveMap<String>(); + } + + @Test + public void putAndGet() { + map.put("key", "value1"); + map.put("key", "value2"); + map.put("key", "value3"); + assertEquals(1, map.size()); + assertEquals("value3", map.get("key")); + assertEquals("value3", map.get("KEY")); + assertEquals("value3", map.get("Key")); + } + + @Test + public void putWithOverlappingKeys() { + map.put("key", "value1"); + map.put("KEY", "value2"); + map.put("Key", "value3"); + assertEquals(1, map.size()); + assertEquals("value3", map.get("key")); + assertEquals("value3", map.get("KEY")); + assertEquals("value3", map.get("Key")); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/LinkedMultiValueMapTests.java b/spring-core/src/test/java/org/springframework/util/LinkedMultiValueMapTests.java new file mode 100644 index 00000000..7e274557 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/LinkedMultiValueMapTests.java @@ -0,0 +1,84 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +/** + * @author Arjen Poutsma + */ +public class LinkedMultiValueMapTests { + + private LinkedMultiValueMap<String, String> map; + + @Before + public void setUp() { + map = new LinkedMultiValueMap<String, String>(); + } + + @Test + public void add() { + map.add("key", "value1"); + map.add("key", "value2"); + assertEquals(1, map.size()); + List<String> expected = new ArrayList<String>(2); + expected.add("value1"); + expected.add("value2"); + assertEquals(expected, map.get("key")); + } + + @Test + public void getFirst() { + List<String> values = new ArrayList<String>(2); + values.add("value1"); + values.add("value2"); + map.put("key", values); + assertEquals("value1", map.getFirst("key")); + assertNull(map.getFirst("other")); + } + + @Test + public void set() { + map.set("key", "value1"); + map.set("key", "value2"); + assertEquals(1, map.size()); + assertEquals(Collections.singletonList("value2"), map.get("key")); + } + + @Test + public void equals() { + map.set("key1", "value1"); + assertEquals(map, map); + MultiValueMap<String, String> o1 = new LinkedMultiValueMap<String, String>(); + o1.set("key1", "value1"); + assertEquals(map, o1); + assertEquals(o1, map); + Map<String, List<String>> o2 = new HashMap<String, List<String>>(); + o2.put("key1", Collections.singletonList("value1")); + assertEquals(map, o2); + assertEquals(o2, map); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/Log4jConfigurerTests.java b/spring-core/src/test/java/org/springframework/util/Log4jConfigurerTests.java new file mode 100644 index 00000000..90d40d7b --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/Log4jConfigurerTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.FileNotFoundException; +import java.net.URL; + +import junit.framework.TestCase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * @author Alef Arendsen + * @author Juergen Hoeller + */ +public class Log4jConfigurerTests extends TestCase { + + public void testInitLoggingWithClasspath() throws FileNotFoundException { + doTestInitLogging("classpath:org/springframework/util/testlog4j.properties", false); + } + + public void testInitLoggingWithRelativeFilePath() throws FileNotFoundException { + doTestInitLogging("src/test/resources/org/springframework/util/testlog4j.properties", false); + } + + public void testInitLoggingWithAbsoluteFilePath() throws FileNotFoundException { + URL url = getClass().getResource("testlog4j.properties"); + doTestInitLogging(url.toString(), false); + } + + public void testInitLoggingWithClasspathAndRefreshInterval() throws FileNotFoundException { + doTestInitLogging("classpath:org/springframework/util/testlog4j.properties", true); + } + + public void testInitLoggingWithRelativeFilePathAndRefreshInterval() throws FileNotFoundException { + doTestInitLogging("src/test/resources/org/springframework/util/testlog4j.properties", true); + } + + /* only works on Windows + public void testInitLoggingWithAbsoluteFilePathAndRefreshInterval() throws FileNotFoundException { + URL url = getClass().getResource("testlog4j.properties"); + doTestInitLogging(url.getFile(), true); + } + */ + + public void testInitLoggingWithFileUrlAndRefreshInterval() throws FileNotFoundException { + URL url = getClass().getResource("testlog4j.properties"); + doTestInitLogging(url.toString(), true); + } + + private void doTestInitLogging(String location, boolean refreshInterval) throws FileNotFoundException { + if (refreshInterval) { + Log4jConfigurer.initLogging(location, 10); + } + else { + Log4jConfigurer.initLogging(location); + } + + Log log = LogFactory.getLog(this.getClass()); + log.debug("debug"); + log.info("info"); + log.warn("warn"); + log.error("error"); + log.fatal("fatal"); + + assertTrue(MockLog4jAppender.loggingStrings.contains("debug")); + assertTrue(MockLog4jAppender.loggingStrings.contains("info")); + assertTrue(MockLog4jAppender.loggingStrings.contains("warn")); + assertTrue(MockLog4jAppender.loggingStrings.contains("error")); + assertTrue(MockLog4jAppender.loggingStrings.contains("fatal")); + + Log4jConfigurer.shutdownLogging(); + assertTrue(MockLog4jAppender.closeCalled); + } + + public void testInitLoggingWithRefreshIntervalAndFileNotFound() throws FileNotFoundException { + try { + Log4jConfigurer.initLogging("test/org/springframework/util/bla.properties", 10); + fail("Exception should have been thrown, file does not exist!"); + } + catch (FileNotFoundException ex) { + // OK + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/MethodInvokerTests.java b/spring-core/src/test/java/org/springframework/util/MethodInvokerTests.java new file mode 100644 index 00000000..679ab956 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/MethodInvokerTests.java @@ -0,0 +1,292 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import junit.framework.TestCase; + +/** + * @author Colin Sampaleanu + * @author Juergen Hoeller + * @since 21.11.2003 + */ +public class MethodInvokerTests extends TestCase { + + public void testPlainMethodInvoker() throws Exception { + // sanity check: singleton, non-static should work + TestClass1 tc1 = new TestClass1(); + MethodInvoker mi = new MethodInvoker(); + mi.setTargetObject(tc1); + mi.setTargetMethod("method1"); + mi.prepare(); + Integer i = (Integer) mi.invoke(); + assertEquals(1, i.intValue()); + + // sanity check: check that argument count matching works + mi = new MethodInvoker(); + mi.setTargetClass(TestClass1.class); + mi.setTargetMethod("supertypes"); + mi.setArguments(new Object[] {new ArrayList<>(), new ArrayList<>(), "hello"}); + mi.prepare(); + assertEquals("hello", mi.invoke()); + + mi = new MethodInvoker(); + mi.setTargetClass(TestClass1.class); + mi.setTargetMethod("supertypes2"); + mi.setArguments(new Object[] {new ArrayList<>(), new ArrayList<>(), "hello", "bogus"}); + mi.prepare(); + assertEquals("hello", mi.invoke()); + + // Sanity check: check that argument conversion doesn't work with plain MethodInvoker + mi = new MethodInvoker(); + mi.setTargetClass(TestClass1.class); + mi.setTargetMethod("supertypes2"); + mi.setArguments(new Object[] {new ArrayList<>(), new ArrayList<>(), "hello", Boolean.TRUE}); + try { + mi.prepare(); + fail("Shouldn't have matched without argument conversion"); + } + catch (NoSuchMethodException ex) { + // expected + } + } + + public void testStringWithMethodInvoker() throws Exception { + try { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new String("no match")}); + methodInvoker.prepare(); + fail("Should have thrown a NoSuchMethodException"); + } + catch (NoSuchMethodException e) { + // expected + } + } + + public void testPurchaserWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Purchaser()}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("purchaser: hello", greeting); + } + + public void testShopperWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Shopper()}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("purchaser: may I help you?", greeting); + } + + public void testSalesmanWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Salesman()}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("greetable: how are sales?", greeting); + } + + public void testCustomerWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Customer()}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("customer: good day", greeting); + } + + public void testRegularWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new Regular("Kotter")}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("regular: welcome back Kotter", greeting); + } + + public void testVIPWithMethodInvoker() throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(new Greeter()); + methodInvoker.setTargetMethod("greet"); + methodInvoker.setArguments(new Object[] {new VIP("Fonzie")}); + methodInvoker.prepare(); + String greeting = (String) methodInvoker.invoke(); + assertEquals("regular: whassup dude?", greeting); + } + + + public static class TestClass1 { + + public static int _staticField1; + + public int _field1 = 0; + + public int method1() { + return ++_field1; + } + + public static int staticMethod1() { + return ++TestClass1._staticField1; + } + + public static void voidRetvalMethod() { + } + + public static void nullArgument(Object arg) { + } + + public static void intArgument(int arg) { + } + + public static void intArguments(int[] arg) { + } + + public static String supertypes(Collection<?> c, Integer i) { + return i.toString(); + } + + public static String supertypes(Collection<?> c, List<?> l, String s) { + return s; + } + + public static String supertypes2(Collection<?> c, List<?> l, Integer i) { + return i.toString(); + } + + public static String supertypes2(Collection<?> c, List<?> l, String s, Integer i) { + return s; + } + + public static String supertypes2(Collection<?> c, List<?> l, String s, String s2) { + return s; + } + } + + + @SuppressWarnings("unused") + public static class Greeter { + + // should handle Salesman (only interface) + public String greet(Greetable greetable) { + return "greetable: " + greetable.getGreeting(); + } + + // should handle Shopper (beats Greetable since it is a class) + protected String greet(Purchaser purchaser) { + return "purchaser: " + purchaser.getGreeting(); + } + + // should handle Customer (exact match) + String greet(Customer customer) { + return "customer: " + customer.getGreeting(); + } + + // should handle Regular (exact) and VIP (closest match) + private String greet(Regular regular) { + return "regular: " + regular.getGreeting(); + } + } + + + private static interface Greetable { + + String getGreeting(); + } + + + private static interface Person extends Greetable { + } + + + private static class Purchaser implements Greetable { + + @Override + public String getGreeting() { + return "hello"; + } + } + + + private static class Shopper extends Purchaser implements Person { + + @Override + public String getGreeting() { + return "may I help you?"; + } + } + + + private static class Salesman implements Person { + + @Override + public String getGreeting() { + return "how are sales?"; + } + } + + + private static class Customer extends Shopper { + + @Override + public String getGreeting() { + return "good day"; + } + } + + + private static class Regular extends Customer { + + private String name; + + public Regular(String name) { + this.name = name; + } + + @Override + public String getGreeting() { + return "welcome back " + name ; + } + } + + + private static class VIP extends Regular { + + public VIP(String name) { + super(name); + } + + @Override + public String getGreeting() { + return "whassup dude?"; + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/MockLog4jAppender.java b/spring-core/src/test/java/org/springframework/util/MockLog4jAppender.java new file mode 100644 index 00000000..e145195b --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/MockLog4jAppender.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.spi.LoggingEvent; + +/** + * @author Alef Arendsen + */ +public class MockLog4jAppender extends AppenderSkeleton { + + public static final List loggingStrings = new ArrayList(); + + public static boolean closeCalled = false; + + /* (non-Javadoc) + * @see org.apache.log4j.AppenderSkeleton#append(org.apache.log4j.spi.LoggingEvent) + */ + @Override + protected void append(LoggingEvent evt) { + //System.out.println("Adding " + evt.getMessage()); + loggingStrings.add(evt.getMessage()); + } + + /* (non-Javadoc) + * @see org.apache.log4j.Appender#close() + */ + @Override + public void close() { + closeCalled = true; + } + + /* (non-Javadoc) + * @see org.apache.log4j.Appender#requiresLayout() + */ + @Override + public boolean requiresLayout() { + return false; + } + + + + +} diff --git a/spring-core/src/test/java/org/springframework/util/NumberUtilsTests.java b/spring-core/src/test/java/org/springframework/util/NumberUtilsTests.java new file mode 100644 index 00000000..aae2b8a7 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/NumberUtilsTests.java @@ -0,0 +1,348 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * 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 org.springframework.util; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.NumberFormat; +import java.util.Locale; + +import junit.framework.TestCase; + +import org.springframework.core.JdkVersion; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class NumberUtilsTests extends TestCase { + + public void testParseNumber() { + String aByte = "" + Byte.MAX_VALUE; + String aShort = "" + Short.MAX_VALUE; + String anInteger = "" + Integer.MAX_VALUE; + String aLong = "" + Long.MAX_VALUE; + String aFloat = "" + Float.MAX_VALUE; + String aDouble = "" + Double.MAX_VALUE; + + assertEquals("Byte did not parse", new Byte(Byte.MAX_VALUE), NumberUtils.parseNumber(aByte, Byte.class)); + assertEquals("Short did not parse", new Short(Short.MAX_VALUE), NumberUtils.parseNumber(aShort, Short.class)); + assertEquals("Integer did not parse", new Integer(Integer.MAX_VALUE), NumberUtils.parseNumber(anInteger, Integer.class)); + assertEquals("Long did not parse", new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class)); + assertEquals("Float did not parse", new Float(Float.MAX_VALUE), NumberUtils.parseNumber(aFloat, Float.class)); + assertEquals("Double did not parse", new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class)); + } + + public void testParseNumberUsingNumberFormat() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); + String aByte = "" + Byte.MAX_VALUE; + String aShort = "" + Short.MAX_VALUE; + String anInteger = "" + Integer.MAX_VALUE; + String aLong = "" + Long.MAX_VALUE; + String aFloat = "" + Float.MAX_VALUE; + String aDouble = "" + Double.MAX_VALUE; + + assertEquals("Byte did not parse", new Byte(Byte.MAX_VALUE), NumberUtils.parseNumber(aByte, Byte.class, nf)); + assertEquals("Short did not parse", new Short(Short.MAX_VALUE), NumberUtils.parseNumber(aShort, Short.class, nf)); + assertEquals("Integer did not parse", new Integer(Integer.MAX_VALUE), NumberUtils.parseNumber(anInteger, Integer.class, nf)); + assertEquals("Long did not parse", new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class, nf)); + assertEquals("Float did not parse", new Float(Float.MAX_VALUE), NumberUtils.parseNumber(aFloat, Float.class, nf)); + assertEquals("Double did not parse", new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class, nf)); + } + + public void testParseWithTrim() { + String aByte = " " + Byte.MAX_VALUE + " "; + String aShort = " " + Short.MAX_VALUE + " "; + String anInteger = " " + Integer.MAX_VALUE + " "; + String aLong = " " + Long.MAX_VALUE + " "; + String aFloat = " " + Float.MAX_VALUE + " "; + String aDouble = " " + Double.MAX_VALUE + " "; + + assertEquals("Byte did not parse", new Byte(Byte.MAX_VALUE), NumberUtils.parseNumber(aByte, Byte.class)); + assertEquals("Short did not parse", new Short(Short.MAX_VALUE), NumberUtils.parseNumber(aShort, Short.class)); + assertEquals("Integer did not parse", new Integer(Integer.MAX_VALUE), NumberUtils.parseNumber(anInteger, Integer.class)); + assertEquals("Long did not parse", new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class)); + assertEquals("Float did not parse", new Float(Float.MAX_VALUE), NumberUtils.parseNumber(aFloat, Float.class)); + assertEquals("Double did not parse", new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class)); + } + + public void testParseWithTrimUsingNumberFormat() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); + String aByte = " " + Byte.MAX_VALUE + " "; + String aShort = " " + Short.MAX_VALUE + " "; + String anInteger = " " + Integer.MAX_VALUE + " "; + String aLong = " " + Long.MAX_VALUE + " "; + String aFloat = " " + Float.MAX_VALUE + " "; + String aDouble = " " + Double.MAX_VALUE + " "; + + assertEquals("Byte did not parse", new Byte(Byte.MAX_VALUE), NumberUtils.parseNumber(aByte, Byte.class, nf)); + assertEquals("Short did not parse", new Short(Short.MAX_VALUE), NumberUtils.parseNumber(aShort, Short.class, nf)); + assertEquals("Integer did not parse", new Integer(Integer.MAX_VALUE), NumberUtils.parseNumber(anInteger, Integer.class, nf)); + assertEquals("Long did not parse", new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class, nf)); + assertEquals("Float did not parse", new Float(Float.MAX_VALUE), NumberUtils.parseNumber(aFloat, Float.class, nf)); + assertEquals("Double did not parse", new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class, nf)); + } + + public void testParseAsHex() { + String aByte = "0x" + Integer.toHexString(new Byte(Byte.MAX_VALUE).intValue()); + String aShort = "0x" + Integer.toHexString(new Short(Short.MAX_VALUE).intValue()); + String anInteger = "0x" + Integer.toHexString(Integer.MAX_VALUE); + String aLong = "0x" + Long.toHexString(Long.MAX_VALUE); + String aReallyBigInt = "FEBD4E677898DFEBFFEE44"; + + assertByteEquals(aByte); + assertShortEquals(aShort); + assertIntegerEquals(anInteger); + assertLongEquals(aLong); + assertEquals("BigInteger did not parse", + new BigInteger(aReallyBigInt, 16), NumberUtils.parseNumber("0x" + aReallyBigInt, BigInteger.class)); + } + + public void testParseNegativeHex() { + String aByte = "-0x80"; + String aShort = "-0x8000"; + String anInteger = "-0x80000000"; + String aLong = "-0x8000000000000000"; + String aReallyBigInt = "FEBD4E677898DFEBFFEE44"; + + assertNegativeByteEquals(aByte); + assertNegativeShortEquals(aShort); + assertNegativeIntegerEquals(anInteger); + assertNegativeLongEquals(aLong); + assertEquals("BigInteger did not parse", + new BigInteger(aReallyBigInt, 16).negate(), NumberUtils.parseNumber("-0x" + aReallyBigInt, BigInteger.class)); + } + + public void testDoubleToBigInteger() { + Double decimal = new Double(3.14d); + assertEquals(new BigInteger("3"), NumberUtils.convertNumberToTargetClass(decimal, BigInteger.class)); + } + + public void testBigDecimalToBigInteger() { + String number = "987459837583750387355346"; + BigDecimal decimal = new BigDecimal(number); + assertEquals(new BigInteger(number), NumberUtils.convertNumberToTargetClass(decimal, BigInteger.class)); + } + + public void testNonExactBigDecimalToBigInteger() { + BigDecimal decimal = new BigDecimal("987459837583750387355346.14"); + assertEquals(new BigInteger("987459837583750387355346"), NumberUtils.convertNumberToTargetClass(decimal, BigInteger.class)); + } + + public void testParseBigDecimalNumber1() { + String bigDecimalAsString = "0.10"; + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseBigDecimalNumber2() { + String bigDecimalAsString = "0.001"; + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseBigDecimalNumber3() { + String bigDecimalAsString = "3.14159265358979323846"; + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseLocalizedBigDecimalNumber1() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + String bigDecimalAsString = "0.10"; + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH); + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class, numberFormat); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseLocalizedBigDecimalNumber2() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + String bigDecimalAsString = "0.001"; + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH); + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class, numberFormat); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseLocalizedBigDecimalNumber3() { + if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_15) { + return; + } + String bigDecimalAsString = "3.14159265358979323846"; + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH); + Number bigDecimal = NumberUtils.parseNumber(bigDecimalAsString, BigDecimal.class, numberFormat); + assertEquals(new BigDecimal(bigDecimalAsString), bigDecimal); + } + + public void testParseOverflow() { + String aLong = "" + Long.MAX_VALUE; + String aDouble = "" + Double.MAX_VALUE; + + try { + NumberUtils.parseNumber(aLong, Byte.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Short.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Integer.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + assertEquals(new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class)); + + assertEquals(new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class)); + } + + public void testParseNegativeOverflow() { + String aLong = "" + Long.MIN_VALUE; + String aDouble = "" + Double.MIN_VALUE; + + try { + NumberUtils.parseNumber(aLong, Byte.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Short.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Integer.class); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + assertEquals(new Long(Long.MIN_VALUE), NumberUtils.parseNumber(aLong, Long.class)); + + assertEquals(new Double(Double.MIN_VALUE), NumberUtils.parseNumber(aDouble, Double.class)); + } + + public void testParseOverflowUsingNumberFormat() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); + String aLong = "" + Long.MAX_VALUE; + String aDouble = "" + Double.MAX_VALUE; + + try { + NumberUtils.parseNumber(aLong, Byte.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Short.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Integer.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + assertEquals(new Long(Long.MAX_VALUE), NumberUtils.parseNumber(aLong, Long.class, nf)); + + assertEquals(new Double(Double.MAX_VALUE), NumberUtils.parseNumber(aDouble, Double.class, nf)); + } + + public void testParseNegativeOverflowUsingNumberFormat() { + NumberFormat nf = NumberFormat.getNumberInstance(Locale.US); + String aLong = "" + Long.MIN_VALUE; + String aDouble = "" + Double.MIN_VALUE; + + try { + NumberUtils.parseNumber(aLong, Byte.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Short.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + try { + NumberUtils.parseNumber(aLong, Integer.class, nf); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException expected) { + } + + assertEquals(new Long(Long.MIN_VALUE), NumberUtils.parseNumber(aLong, Long.class, nf)); + + assertEquals(new Double(Double.MIN_VALUE), NumberUtils.parseNumber(aDouble, Double.class, nf)); + } + + private void assertLongEquals(String aLong) { + assertEquals("Long did not parse", Long.MAX_VALUE, NumberUtils.parseNumber(aLong, Long.class).longValue()); + } + + private void assertIntegerEquals(String anInteger) { + assertEquals("Integer did not parse", Integer.MAX_VALUE, NumberUtils.parseNumber(anInteger, Integer.class).intValue()); + } + + private void assertShortEquals(String aShort) { + assertEquals("Short did not parse", Short.MAX_VALUE, NumberUtils.parseNumber(aShort, Short.class).shortValue()); + } + + private void assertByteEquals(String aByte) { + assertEquals("Byte did not parse", Byte.MAX_VALUE, NumberUtils.parseNumber(aByte, Byte.class).byteValue()); + } + + private void assertNegativeLongEquals(String aLong) { + assertEquals("Long did not parse", Long.MIN_VALUE, NumberUtils.parseNumber(aLong, Long.class).longValue()); + } + + private void assertNegativeIntegerEquals(String anInteger) { + assertEquals("Integer did not parse", Integer.MIN_VALUE, NumberUtils.parseNumber(anInteger, Integer.class).intValue()); + } + + private void assertNegativeShortEquals(String aShort) { + assertEquals("Short did not parse", Short.MIN_VALUE, NumberUtils.parseNumber(aShort, Short.class).shortValue()); + } + + private void assertNegativeByteEquals(String aByte) { + assertEquals("Byte did not parse", Byte.MIN_VALUE, NumberUtils.parseNumber(aByte, Byte.class).byteValue()); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java new file mode 100644 index 00000000..8f4c1e28 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java @@ -0,0 +1,763 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.IOException; +import java.sql.SQLException; + +import org.junit.Test; + +import org.springframework.core.task.TaskRejectedException; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + */ +public class ObjectUtilsTests { + + @Test + public void testIsCheckedException() { + assertTrue(ObjectUtils.isCheckedException(new Exception())); + assertTrue(ObjectUtils.isCheckedException(new SQLException())); + + assertFalse(ObjectUtils.isCheckedException(new RuntimeException())); + assertFalse(ObjectUtils.isCheckedException(new TaskRejectedException(""))); + + // Any Throwable other than RuntimeException and Error + // has to be considered checked according to the JLS. + assertTrue(ObjectUtils.isCheckedException(new Throwable())); + } + + @Test + public void testIsCompatibleWithThrowsClause() { + Class<?>[] empty = new Class[0]; + Class<?>[] exception = new Class[] {Exception.class}; + Class<?>[] sqlAndIO = new Class[] {SQLException.class, IOException.class}; + Class<?>[] throwable = new Class[] {Throwable.class}; + + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException())); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), empty)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), exception)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), sqlAndIO)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new RuntimeException(), throwable)); + + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Exception())); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), empty)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), exception)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), sqlAndIO)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new Exception(), throwable)); + + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new SQLException())); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new SQLException(), empty)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new SQLException(), exception)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new SQLException(), sqlAndIO)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new SQLException(), throwable)); + + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Throwable())); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), empty)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), exception)); + assertFalse(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), sqlAndIO)); + assertTrue(ObjectUtils.isCompatibleWithThrowsClause(new Throwable(), throwable)); + } + + @Test + public void testToObjectArray() { + int[] a = new int[] {1, 2, 3, 4, 5}; + Integer[] wrapper = (Integer[]) ObjectUtils.toObjectArray(a); + assertTrue(wrapper.length == 5); + for (int i = 0; i < wrapper.length; i++) { + assertEquals(a[i], wrapper[i].intValue()); + } + } + + @Test + public void testToObjectArrayWithNull() { + Object[] objects = ObjectUtils.toObjectArray(null); + assertNotNull(objects); + assertEquals(0, objects.length); + } + + @Test + public void testToObjectArrayWithEmptyPrimitiveArray() { + Object[] objects = ObjectUtils.toObjectArray(new byte[] {}); + assertNotNull(objects); + assertEquals(0, objects.length); + } + + @Test + public void testToObjectArrayWithNonArrayType() { + try { + ObjectUtils.toObjectArray("Not an []"); + fail("Must have thrown an IllegalArgumentException by this point."); + } + catch (IllegalArgumentException expected) { + } + } + + @Test + public void testToObjectArrayWithNonPrimitiveArray() { + String[] source = new String[] {"Bingo"}; + assertArrayEquals(source, ObjectUtils.toObjectArray(source)); + } + + @Test + public void testAddObjectToArraySunnyDay() { + String[] array = new String[] {"foo", "bar"}; + String newElement = "baz"; + Object[] newArray = ObjectUtils.addObjectToArray(array, newElement); + assertEquals(3, newArray.length); + assertEquals(newElement, newArray[2]); + } + + @Test + public void testAddObjectToArrayWhenEmpty() { + String[] array = new String[0]; + String newElement = "foo"; + String[] newArray = ObjectUtils.addObjectToArray(array, newElement); + assertEquals(1, newArray.length); + assertEquals(newElement, newArray[0]); + } + + @Test + public void testAddObjectToSingleNonNullElementArray() { + String existingElement = "foo"; + String[] array = new String[] {existingElement}; + String newElement = "bar"; + String[] newArray = ObjectUtils.addObjectToArray(array, newElement); + assertEquals(2, newArray.length); + assertEquals(existingElement, newArray[0]); + assertEquals(newElement, newArray[1]); + } + + @Test + public void testAddObjectToSingleNullElementArray() { + String[] array = new String[] {null}; + String newElement = "bar"; + String[] newArray = ObjectUtils.addObjectToArray(array, newElement); + assertEquals(2, newArray.length); + assertEquals(null, newArray[0]); + assertEquals(newElement, newArray[1]); + } + + @Test + public void testAddObjectToNullArray() throws Exception { + String newElement = "foo"; + String[] newArray = ObjectUtils.addObjectToArray(null, newElement); + assertEquals(1, newArray.length); + assertEquals(newElement, newArray[0]); + } + + @Test + public void testAddNullObjectToNullArray() throws Exception { + Object[] newArray = ObjectUtils.addObjectToArray(null, null); + assertEquals(1, newArray.length); + assertEquals(null, newArray[0]); + } + + @Test + public void testNullSafeEqualsWithArrays() throws Exception { + assertTrue(ObjectUtils.nullSafeEquals(new String[] {"a", "b", "c"}, new String[] {"a", "b", "c"})); + assertTrue(ObjectUtils.nullSafeEquals(new int[] {1, 2, 3}, new int[] {1, 2, 3})); + } + + @Test + public void testHashCodeWithBooleanFalse() { + int expected = Boolean.FALSE.hashCode(); + assertEquals(expected, ObjectUtils.hashCode(false)); + } + + @Test + public void testHashCodeWithBooleanTrue() { + int expected = Boolean.TRUE.hashCode(); + assertEquals(expected, ObjectUtils.hashCode(true)); + } + + @Test + public void testHashCodeWithDouble() { + double dbl = 9830.43; + int expected = (new Double(dbl)).hashCode(); + assertEquals(expected, ObjectUtils.hashCode(dbl)); + } + + @Test + public void testHashCodeWithFloat() { + float flt = 34.8f; + int expected = (new Float(flt)).hashCode(); + assertEquals(expected, ObjectUtils.hashCode(flt)); + } + + @Test + public void testHashCodeWithLong() { + long lng = 883l; + int expected = (new Long(lng)).hashCode(); + assertEquals(expected, ObjectUtils.hashCode(lng)); + } + + @Test + public void testIdentityToString() { + Object obj = new Object(); + String expected = obj.getClass().getName() + "@" + ObjectUtils.getIdentityHexString(obj); + String actual = ObjectUtils.identityToString(obj); + assertEquals(expected, actual); + } + + @Test + public void testIdentityToStringWithNullObject() { + assertEquals("", ObjectUtils.identityToString(null)); + } + + @Test + public void testIsArrayOfPrimitivesWithBooleanArray() { + assertTrue(ClassUtils.isPrimitiveArray(boolean[].class)); + } + + @Test + public void testIsArrayOfPrimitivesWithObjectArray() { + assertFalse(ClassUtils.isPrimitiveArray(Object[].class)); + } + + @Test + public void testIsArrayOfPrimitivesWithNonArray() { + assertFalse(ClassUtils.isPrimitiveArray(String.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithBooleanPrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(boolean.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithBooleanWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Boolean.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithBytePrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(byte.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithByteWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Byte.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithCharacterClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Character.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithCharClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(char.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithDoublePrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(double.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithDoubleWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Double.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithFloatPrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(float.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithFloatWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Float.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithIntClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(int.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithIntegerClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Integer.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithLongPrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(long.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithLongWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Long.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithNonPrimitiveOrWrapperClass() { + assertFalse(ClassUtils.isPrimitiveOrWrapper(Object.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithShortPrimitiveClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(short.class)); + } + + @Test + public void testIsPrimitiveOrWrapperWithShortWrapperClass() { + assertTrue(ClassUtils.isPrimitiveOrWrapper(Short.class)); + } + + @Test + public void testNullSafeHashCodeWithBooleanArray() { + int expected = 31 * 7 + Boolean.TRUE.hashCode(); + expected = 31 * expected + Boolean.FALSE.hashCode(); + + boolean[] array = {true, false}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithBooleanArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((boolean[]) null)); + } + + @Test + public void testNullSafeHashCodeWithByteArray() { + int expected = 31 * 7 + 8; + expected = 31 * expected + 10; + + byte[] array = {8, 10}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithByteArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((byte[]) null)); + } + + @Test + public void testNullSafeHashCodeWithCharArray() { + int expected = 31 * 7 + 'a'; + expected = 31 * expected + 'E'; + + char[] array = {'a', 'E'}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithCharArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((char[]) null)); + } + + @Test + public void testNullSafeHashCodeWithDoubleArray() { + long bits = Double.doubleToLongBits(8449.65); + int expected = 31 * 7 + (int) (bits ^ (bits >>> 32)); + bits = Double.doubleToLongBits(9944.923); + expected = 31 * expected + (int) (bits ^ (bits >>> 32)); + + double[] array = {8449.65, 9944.923}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithDoubleArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((double[]) null)); + } + + @Test + public void testNullSafeHashCodeWithFloatArray() { + int expected = 31 * 7 + Float.floatToIntBits(9.6f); + expected = 31 * expected + Float.floatToIntBits(7.4f); + + float[] array = {9.6f, 7.4f}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithFloatArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((float[]) null)); + } + + @Test + public void testNullSafeHashCodeWithIntArray() { + int expected = 31 * 7 + 884; + expected = 31 * expected + 340; + + int[] array = {884, 340}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithIntArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((int[]) null)); + } + + @Test + public void testNullSafeHashCodeWithLongArray() { + long lng = 7993l; + int expected = 31 * 7 + (int) (lng ^ (lng >>> 32)); + lng = 84320l; + expected = 31 * expected + (int) (lng ^ (lng >>> 32)); + + long[] array = {7993l, 84320l}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithLongArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((long[]) null)); + } + + @Test + public void testNullSafeHashCodeWithObject() { + String str = "Luke"; + assertEquals(str.hashCode(), ObjectUtils.nullSafeHashCode(str)); + } + + @Test + public void testNullSafeHashCodeWithObjectArray() { + int expected = 31 * 7 + "Leia".hashCode(); + expected = 31 * expected + "Han".hashCode(); + + Object[] array = {"Leia", "Han"}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithObjectArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((Object[]) null)); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingBooleanArray() { + Object array = new boolean[] {true, false}; + int expected = ObjectUtils.nullSafeHashCode((boolean[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingByteArray() { + Object array = new byte[] {6, 39}; + int expected = ObjectUtils.nullSafeHashCode((byte[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingCharArray() { + Object array = new char[] {'l', 'M'}; + int expected = ObjectUtils.nullSafeHashCode((char[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingDoubleArray() { + Object array = new double[] {68930.993, 9022.009}; + int expected = ObjectUtils.nullSafeHashCode((double[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingFloatArray() { + Object array = new float[] {9.9f, 9.54f}; + int expected = ObjectUtils.nullSafeHashCode((float[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingIntArray() { + Object array = new int[] {89, 32}; + int expected = ObjectUtils.nullSafeHashCode((int[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingLongArray() { + Object array = new long[] {4389, 320}; + int expected = ObjectUtils.nullSafeHashCode((long[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingObjectArray() { + Object array = new Object[] {"Luke", "Anakin"}; + int expected = ObjectUtils.nullSafeHashCode((Object[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectBeingShortArray() { + Object array = new short[] {5, 3}; + int expected = ObjectUtils.nullSafeHashCode((short[]) array); + assertEqualHashCodes(expected, array); + } + + @Test + public void testNullSafeHashCodeWithObjectEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((Object) null)); + } + + @Test + public void testNullSafeHashCodeWithShortArray() { + int expected = 31 * 7 + 70; + expected = 31 * expected + 8; + + short[] array = {70, 8}; + int actual = ObjectUtils.nullSafeHashCode(array); + + assertEquals(expected, actual); + } + + @Test + public void testNullSafeHashCodeWithShortArrayEqualToNull() { + assertEquals(0, ObjectUtils.nullSafeHashCode((short[]) null)); + } + + @Test + public void testNullSafeToStringWithBooleanArray() { + boolean[] array = {true, false}; + assertEquals("{true, false}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithBooleanArrayBeingEmpty() { + boolean[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithBooleanArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((boolean[]) null)); + } + + @Test + public void testNullSafeToStringWithByteArray() { + byte[] array = {5, 8}; + assertEquals("{5, 8}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithByteArrayBeingEmpty() { + byte[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithByteArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((byte[]) null)); + } + + @Test + public void testNullSafeToStringWithCharArray() { + char[] array = {'A', 'B'}; + assertEquals("{'A', 'B'}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithCharArrayBeingEmpty() { + char[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithCharArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((char[]) null)); + } + + @Test + public void testNullSafeToStringWithDoubleArray() { + double[] array = {8594.93, 8594023.95}; + assertEquals("{8594.93, 8594023.95}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithDoubleArrayBeingEmpty() { + double[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithDoubleArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((double[]) null)); + } + + @Test + public void testNullSafeToStringWithFloatArray() { + float[] array = {8.6f, 43.8f}; + assertEquals("{8.6, 43.8}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithFloatArrayBeingEmpty() { + float[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithFloatArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((float[]) null)); + } + + @Test + public void testNullSafeToStringWithIntArray() { + int[] array = {9, 64}; + assertEquals("{9, 64}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithIntArrayBeingEmpty() { + int[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithIntArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((int[]) null)); + } + + @Test + public void testNullSafeToStringWithLongArray() { + long[] array = {434l, 23423l}; + assertEquals("{434, 23423}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithLongArrayBeingEmpty() { + long[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithLongArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((long[]) null)); + } + + @Test + public void testNullSafeToStringWithPlainOldString() { + assertEquals("I shoh love tha taste of mangoes", ObjectUtils.nullSafeToString("I shoh love tha taste of mangoes")); + } + + @Test + public void testNullSafeToStringWithObjectArray() { + Object[] array = {"Han", new Long(43)}; + assertEquals("{Han, 43}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithObjectArrayBeingEmpty() { + Object[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithObjectArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((Object[]) null)); + } + + @Test + public void testNullSafeToStringWithShortArray() { + short[] array = {7, 9}; + assertEquals("{7, 9}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithShortArrayBeingEmpty() { + short[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithShortArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((short[]) null)); + } + + @Test + public void testNullSafeToStringWithStringArray() { + String[] array = {"Luke", "Anakin"}; + assertEquals("{Luke, Anakin}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithStringArrayBeingEmpty() { + String[] array = {}; + assertEquals("{}", ObjectUtils.nullSafeToString(array)); + } + + @Test + public void testNullSafeToStringWithStringArrayEqualToNull() { + assertEquals("null", ObjectUtils.nullSafeToString((String[]) null)); + } + + @Test + public void testContainsConstant() { + assertThat(ObjectUtils.containsConstant(Tropes.values(), "FOO"), is(true)); + assertThat(ObjectUtils.containsConstant(Tropes.values(), "foo"), is(true)); + assertThat(ObjectUtils.containsConstant(Tropes.values(), "BaR"), is(true)); + assertThat(ObjectUtils.containsConstant(Tropes.values(), "bar"), is(true)); + assertThat(ObjectUtils.containsConstant(Tropes.values(), "BAZ"), is(true)); + assertThat(ObjectUtils.containsConstant(Tropes.values(), "baz"), is(true)); + + assertThat(ObjectUtils.containsConstant(Tropes.values(), "BOGUS"), is(false)); + + assertThat(ObjectUtils.containsConstant(Tropes.values(), "FOO", true), is(true)); + assertThat(ObjectUtils.containsConstant(Tropes.values(), "foo", true), is(false)); + } + + @Test + public void testCaseInsensitiveValueOf() { + assertThat(ObjectUtils.caseInsensitiveValueOf(Tropes.values(), "foo"), is(Tropes.FOO)); + assertThat(ObjectUtils.caseInsensitiveValueOf(Tropes.values(), "BAR"), is(Tropes.BAR)); + try { + ObjectUtils.caseInsensitiveValueOf(Tropes.values(), "bogus"); + fail("expected IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + assertThat(ex.getMessage(), + is("constant [bogus] does not exist in enum type " + + "org.springframework.util.ObjectUtilsTests$Tropes")); + } + } + + private void assertEqualHashCodes(int expected, Object array) { + int actual = ObjectUtils.nullSafeHashCode(array); + assertEquals(expected, actual); + assertTrue(array.hashCode() != actual); + } + + + enum Tropes { FOO, BAR, baz } + +} diff --git a/spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java b/spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java new file mode 100644 index 00000000..8128cee6 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/PatternMatchUtilsTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * 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 org.springframework.util; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + * @author Johan Gorter + */ +public class PatternMatchUtilsTests extends TestCase { + + public void testTrivial() { + assertEquals(false, PatternMatchUtils.simpleMatch((String) null, "")); + assertEquals(false, PatternMatchUtils.simpleMatch("1", null)); + doTest("*", "123", true); + doTest("123", "123", true); + } + + public void testStartsWith() { + doTest("get*", "getMe", true); + doTest("get*", "setMe", false); + } + + public void testEndsWith() { + doTest("*Test", "getMeTest", true); + doTest("*Test", "setMe", false); + } + + public void testBetween() { + doTest("*stuff*", "getMeTest", false); + doTest("*stuff*", "getstuffTest", true); + doTest("*stuff*", "stuffTest", true); + doTest("*stuff*", "getstuff", true); + doTest("*stuff*", "stuff", true); + } + + public void testStartsEnds() { + doTest("on*Event", "onMyEvent", true); + doTest("on*Event", "onEvent", true); + doTest("3*3", "3", false); + doTest("3*3", "33", true); + } + + public void testStartsEndsBetween() { + doTest("12*45*78", "12345678", true); + doTest("12*45*78", "123456789", false); + doTest("12*45*78", "012345678", false); + doTest("12*45*78", "124578", true); + doTest("12*45*78", "1245457878", true); + doTest("3*3*3", "33", false); + doTest("3*3*3", "333", true); + } + + public void testRidiculous() { + doTest("*1*2*3*", "0011002001010030020201030", true); + doTest("1*2*3*4", "10300204", false); + doTest("1*2*3*3", "10300203", false); + doTest("*1*2*3*", "123", true); + doTest("*1*2*3*", "132", false); + } + + private void doTest(String pattern, String str, boolean shouldMatch) { + assertEquals(shouldMatch, PatternMatchUtils.simpleMatch(pattern, str)); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/PropertiesPersisterTests.java b/spring-core/src/test/java/org/springframework/util/PropertiesPersisterTests.java new file mode 100644 index 00000000..0fcc4238 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/PropertiesPersisterTests.java @@ -0,0 +1,125 @@ +/* + * Copyright 2002-2005 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.Properties; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + * @since 11.01.2005 + */ +public class PropertiesPersisterTests extends TestCase { + + public void testPropertiesPersister() throws IOException { + String propString = "code1=message1\ncode2:message2"; + Properties props = loadProperties(propString, false); + String propCopy = storeProperties(props, null, false); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithWhitespace() throws IOException { + String propString = " code1\t= \tmessage1\n code2 \t :\t mess\\\n \t age2"; + Properties props = loadProperties(propString, false); + String propCopy = storeProperties(props, null, false); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithHeader() throws IOException { + String propString = "code1=message1\ncode2:message2"; + Properties props = loadProperties(propString, false); + String propCopy = storeProperties(props, "myHeader", false); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithEmptyValue() throws IOException { + String propString = "code1=message1\ncode2:message2\ncode3="; + Properties props = loadProperties(propString, false); + String propCopy = storeProperties(props, null, false); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithReader() throws IOException { + String propString = "code1=message1\ncode2:message2"; + Properties props = loadProperties(propString, true); + String propCopy = storeProperties(props, null, true); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithReaderAndWhitespace() throws IOException { + String propString = " code1\t= \tmessage1\n code2 \t :\t mess\\\n \t age2"; + Properties props = loadProperties(propString, true); + String propCopy = storeProperties(props, null, true); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithReaderAndHeader() throws IOException { + String propString = "code1\t=\tmessage1\n code2 \t : \t message2"; + Properties props = loadProperties(propString, true); + String propCopy = storeProperties(props, "myHeader", true); + loadProperties(propCopy, false); + } + + public void testPropertiesPersisterWithReaderAndEmptyValue() throws IOException { + String propString = "code1=message1\ncode2:message2\ncode3="; + Properties props = loadProperties(propString, true); + String propCopy = storeProperties(props, null, true); + loadProperties(propCopy, false); + } + + private Properties loadProperties(String propString, boolean useReader) throws IOException { + DefaultPropertiesPersister persister = new DefaultPropertiesPersister(); + Properties props = new Properties(); + if (useReader) { + persister.load(props, new StringReader(propString)); + } + else { + persister.load(props, new ByteArrayInputStream(propString.getBytes())); + } + assertEquals("message1", props.getProperty("code1")); + assertEquals("message2", props.getProperty("code2")); + return props; + } + + private String storeProperties(Properties props, String header, boolean useWriter) throws IOException { + DefaultPropertiesPersister persister = new DefaultPropertiesPersister(); + String propCopy = null; + if (useWriter) { + StringWriter propWriter = new StringWriter(); + persister.store(props, propWriter, header); + propCopy = propWriter.toString(); + } + else { + ByteArrayOutputStream propOut = new ByteArrayOutputStream(); + persister.store(props, propOut, header); + propCopy = new String(propOut.toByteArray()); + } + if (header != null) { + assertTrue(propCopy.indexOf(header) != -1); + } + assertTrue(propCopy.indexOf("\ncode1=message1") != -1); + assertTrue(propCopy.indexOf("\ncode2=message2") != -1); + return propCopy; + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/PropertyPlaceholderHelperTests.java b/spring-core/src/test/java/org/springframework/util/PropertyPlaceholderHelperTests.java new file mode 100644 index 00000000..20bb969c --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/PropertyPlaceholderHelperTests.java @@ -0,0 +1,116 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.Properties; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * @author Rob Harrop + */ +public class PropertyPlaceholderHelperTests { + + private final PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}"); + + @Test + public void testWithProperties() { + String text = "foo=${foo}"; + Properties props = new Properties(); + props.setProperty("foo", "bar"); + + assertEquals("foo=bar", this.helper.replacePlaceholders(text, props)); + } + + @Test + public void testWithMultipleProperties() { + String text = "foo=${foo},bar=${bar}"; + Properties props = new Properties(); + props.setProperty("foo", "bar"); + props.setProperty("bar", "baz"); + + assertEquals("foo=bar,bar=baz", this.helper.replacePlaceholders(text, props)); + } + + @Test + public void testRecurseInProperty() { + String text = "foo=${bar}"; + Properties props = new Properties(); + props.setProperty("bar", "${baz}"); + props.setProperty("baz", "bar"); + + assertEquals("foo=bar", this.helper.replacePlaceholders(text, props)); + } + + @Test + public void testRecurseInPlaceholder() { + String text = "foo=${b${inner}}"; + Properties props = new Properties(); + props.setProperty("bar", "bar"); + props.setProperty("inner", "ar"); + + assertEquals("foo=bar", this.helper.replacePlaceholders(text, props)); + + text = "${top}"; + props = new Properties(); + props.setProperty("top", "${child}+${child}"); + props.setProperty("child", "${${differentiator}.grandchild}"); + props.setProperty("differentiator", "first"); + props.setProperty("first.grandchild", "actualValue"); + + assertEquals("actualValue+actualValue", this.helper.replacePlaceholders(text, props)); + } + + @Test + public void testWithResolver() { + String text = "foo=${foo}"; + + assertEquals("foo=bar", + this.helper.replacePlaceholders(text, new PropertyPlaceholderHelper.PlaceholderResolver() { + @Override + public String resolvePlaceholder(String placeholderName) { + if ("foo".equals(placeholderName)) { + return "bar"; + } + else { + return null; + } + } + })); + } + + @Test + public void testUnresolvedPlaceholderIsIgnored() { + String text = "foo=${foo},bar=${bar}"; + Properties props = new Properties(); + props.setProperty("foo", "bar"); + + assertEquals("foo=bar,bar=${bar}", this.helper.replacePlaceholders(text, props)); + } + + @Test(expected=IllegalArgumentException.class) + public void testUnresolvedPlaceholderAsError() { + String text = "foo=${foo},bar=${bar}"; + Properties props = new Properties(); + props.setProperty("foo", "bar"); + + PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper("${", "}", null, false); + assertEquals("foo=bar,bar=${bar}", helper.replacePlaceholders(text, props)); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/ReflectionUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ReflectionUtilsTests.java new file mode 100644 index 00000000..7d555076 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/ReflectionUtilsTests.java @@ -0,0 +1,457 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.rmi.ConnectException; +import java.rmi.RemoteException; +import java.util.LinkedList; +import java.util.List; + +import org.hamcrest.Matchers; + +import org.junit.Ignore; +import org.junit.Test; + +import org.springframework.tests.Assume; +import org.springframework.tests.TestGroup; +import org.springframework.tests.sample.objects.TestObject; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + * @author Sam Brannen + * @author Arjen Poutsma + */ +public class ReflectionUtilsTests { + + @Test + public void findField() { + Field field = ReflectionUtils.findField(TestObjectSubclassWithPublicField.class, "publicField", String.class); + assertNotNull(field); + assertEquals("publicField", field.getName()); + assertEquals(String.class, field.getType()); + assertTrue("Field should be public.", Modifier.isPublic(field.getModifiers())); + + field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "prot", String.class); + assertNotNull(field); + assertEquals("prot", field.getName()); + assertEquals(String.class, field.getType()); + assertTrue("Field should be protected.", Modifier.isProtected(field.getModifiers())); + + field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class); + assertNotNull(field); + assertEquals("name", field.getName()); + assertEquals(String.class, field.getType()); + assertTrue("Field should be private.", Modifier.isPrivate(field.getModifiers())); + } + + @Test + public void setField() { + final TestObjectSubclassWithNewField testBean = new TestObjectSubclassWithNewField(); + final Field field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class); + + ReflectionUtils.makeAccessible(field); + + ReflectionUtils.setField(field, testBean, "FooBar"); + assertNotNull(testBean.getName()); + assertEquals("FooBar", testBean.getName()); + + ReflectionUtils.setField(field, testBean, null); + assertNull(testBean.getName()); + } + + @Test(expected = IllegalStateException.class) + public void setFieldIllegal() { + final TestObjectSubclassWithNewField testBean = new TestObjectSubclassWithNewField(); + final Field field = ReflectionUtils.findField(TestObjectSubclassWithNewField.class, "name", String.class); + ReflectionUtils.setField(field, testBean, "FooBar"); + } + + @Test + public void invokeMethod() throws Exception { + String rob = "Rob Harrop"; + + TestObject bean = new TestObject(); + bean.setName(rob); + + Method getName = TestObject.class.getMethod("getName", (Class[]) null); + Method setName = TestObject.class.getMethod("setName", new Class[] { String.class }); + + Object name = ReflectionUtils.invokeMethod(getName, bean); + assertEquals("Incorrect name returned", rob, name); + + String juergen = "Juergen Hoeller"; + ReflectionUtils.invokeMethod(setName, bean, new Object[] { juergen }); + assertEquals("Incorrect name set", juergen, bean.getName()); + } + + @Test + public void declaresException() throws Exception { + Method remoteExMethod = A.class.getDeclaredMethod("foo", new Class[] { Integer.class }); + assertTrue(ReflectionUtils.declaresException(remoteExMethod, RemoteException.class)); + assertTrue(ReflectionUtils.declaresException(remoteExMethod, ConnectException.class)); + assertFalse(ReflectionUtils.declaresException(remoteExMethod, NoSuchMethodException.class)); + assertFalse(ReflectionUtils.declaresException(remoteExMethod, Exception.class)); + + Method illegalExMethod = B.class.getDeclaredMethod("bar", new Class[] { String.class }); + assertTrue(ReflectionUtils.declaresException(illegalExMethod, IllegalArgumentException.class)); + assertTrue(ReflectionUtils.declaresException(illegalExMethod, NumberFormatException.class)); + assertFalse(ReflectionUtils.declaresException(illegalExMethod, IllegalStateException.class)); + assertFalse(ReflectionUtils.declaresException(illegalExMethod, Exception.class)); + } + + @Test + public void copySrcToDestinationOfIncorrectClass() { + TestObject src = new TestObject(); + String dest = new String(); + try { + ReflectionUtils.shallowCopyFieldState(src, dest); + fail(); + } catch (IllegalArgumentException ex) { + // Ok + } + } + + @Test + public void rejectsNullSrc() { + TestObject src = null; + String dest = new String(); + try { + ReflectionUtils.shallowCopyFieldState(src, dest); + fail(); + } catch (IllegalArgumentException ex) { + // Ok + } + } + + @Test + public void rejectsNullDest() { + TestObject src = new TestObject(); + String dest = null; + try { + ReflectionUtils.shallowCopyFieldState(src, dest); + fail(); + } catch (IllegalArgumentException ex) { + // Ok + } + } + + @Test + public void validCopy() { + TestObject src = new TestObject(); + TestObject dest = new TestObject(); + testValidCopy(src, dest); + } + + @Test + public void validCopyOnSubTypeWithNewField() { + TestObjectSubclassWithNewField src = new TestObjectSubclassWithNewField(); + TestObjectSubclassWithNewField dest = new TestObjectSubclassWithNewField(); + src.magic = 11; + + // Will check inherited fields are copied + testValidCopy(src, dest); + + // Check subclass fields were copied + assertEquals(src.magic, dest.magic); + assertEquals(src.prot, dest.prot); + } + + @Test + public void validCopyToSubType() { + TestObject src = new TestObject(); + TestObjectSubclassWithNewField dest = new TestObjectSubclassWithNewField(); + dest.magic = 11; + testValidCopy(src, dest); + // Should have left this one alone + assertEquals(11, dest.magic); + } + + @Test + public void validCopyToSubTypeWithFinalField() { + TestObjectSubclassWithFinalField src = new TestObjectSubclassWithFinalField(); + TestObjectSubclassWithFinalField dest = new TestObjectSubclassWithFinalField(); + // Check that this doesn't fail due to attempt to assign final + testValidCopy(src, dest); + } + + private void testValidCopy(TestObject src, TestObject dest) { + src.setName("freddie"); + src.setAge(15); + src.setSpouse(new TestObject()); + assertFalse(src.getAge() == dest.getAge()); + + ReflectionUtils.shallowCopyFieldState(src, dest); + assertEquals(src.getAge(), dest.getAge()); + assertEquals(src.getSpouse(), dest.getSpouse()); + } + + @Test + public void doWithProtectedMethods() { + ListSavingMethodCallback mc = new ListSavingMethodCallback(); + ReflectionUtils.doWithMethods(TestObject.class, mc, new ReflectionUtils.MethodFilter() { + @Override + public boolean matches(Method m) { + return Modifier.isProtected(m.getModifiers()); + } + }); + assertFalse(mc.getMethodNames().isEmpty()); + assertTrue("Must find protected method on Object", mc.getMethodNames().contains("clone")); + assertTrue("Must find protected method on Object", mc.getMethodNames().contains("finalize")); + assertFalse("Public, not protected", mc.getMethodNames().contains("hashCode")); + assertFalse("Public, not protected", mc.getMethodNames().contains("absquatulate")); + } + + @Test + public void duplicatesFound() { + ListSavingMethodCallback mc = new ListSavingMethodCallback(); + ReflectionUtils.doWithMethods(TestObjectSubclass.class, mc); + int absquatulateCount = 0; + for (String name : mc.getMethodNames()) { + if (name.equals("absquatulate")) { + ++absquatulateCount; + } + } + assertEquals("Found 2 absquatulates", 2, absquatulateCount); + } + + @Test + public void findMethod() throws Exception { + assertNotNull(ReflectionUtils.findMethod(B.class, "bar", String.class)); + assertNotNull(ReflectionUtils.findMethod(B.class, "foo", Integer.class)); + assertNotNull(ReflectionUtils.findMethod(B.class, "getClass")); + } + + @Ignore("[SPR-8644] findMethod() does not currently support var-args") + @Test + public void findMethodWithVarArgs() throws Exception { + assertNotNull(ReflectionUtils.findMethod(B.class, "add", int.class, int.class, int.class)); + } + + @Test + public void isCglibRenamedMethod() throws SecurityException, NoSuchMethodException { + @SuppressWarnings("unused") + class C { + public void CGLIB$m1$123() { + } + + public void CGLIB$m1$0() { + } + + public void CGLIB$$0() { + } + + public void CGLIB$m1$() { + } + + public void CGLIB$m1() { + } + + public void m1() { + } + + public void m1$() { + } + + public void m1$1() { + } + } + assertTrue(ReflectionUtils.isCglibRenamedMethod(C.class.getMethod("CGLIB$m1$123"))); + assertTrue(ReflectionUtils.isCglibRenamedMethod(C.class.getMethod("CGLIB$m1$0"))); + assertFalse(ReflectionUtils.isCglibRenamedMethod(C.class.getMethod("CGLIB$$0"))); + assertFalse(ReflectionUtils.isCglibRenamedMethod(C.class.getMethod("CGLIB$m1$"))); + assertFalse(ReflectionUtils.isCglibRenamedMethod(C.class.getMethod("CGLIB$m1"))); + assertFalse(ReflectionUtils.isCglibRenamedMethod(C.class.getMethod("m1"))); + assertFalse(ReflectionUtils.isCglibRenamedMethod(C.class.getMethod("m1$"))); + assertFalse(ReflectionUtils.isCglibRenamedMethod(C.class.getMethod("m1$1"))); + } + + @Test + public void getAllDeclaredMethods() throws Exception { + class Foo { + @Override + public String toString() { + return super.toString(); + } + } + int toStringMethodCount = 0; + for (Method method : ReflectionUtils.getAllDeclaredMethods(Foo.class)) { + if (method.getName().equals("toString")) { + toStringMethodCount++; + } + } + assertThat(toStringMethodCount, is(2)); + } + + @Test + public void getUniqueDeclaredMethods() throws Exception { + class Foo { + @Override + public String toString() { + return super.toString(); + } + } + int toStringMethodCount = 0; + for (Method method : ReflectionUtils.getUniqueDeclaredMethods(Foo.class)) { + if (method.getName().equals("toString")) { + toStringMethodCount++; + } + } + assertThat(toStringMethodCount, is(1)); + } + + @Test + public void getUniqueDeclaredMethods_withCovariantReturnType() throws Exception { + class Parent { + @SuppressWarnings("unused") + public Number m1() { + return new Integer(42); + } + } + class Leaf extends Parent { + @Override + public Integer m1() { + return new Integer(42); + } + } + int m1MethodCount = 0; + Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(Leaf.class); + for (Method method : methods) { + if (method.getName().equals("m1")) { + m1MethodCount++; + } + } + assertThat(m1MethodCount, is(1)); + assertTrue(ObjectUtils.containsElement(methods, Leaf.class.getMethod("m1"))); + assertFalse(ObjectUtils.containsElement(methods, Parent.class.getMethod("m1"))); + } + + @Test + public void getUniqueDeclaredMethods_isFastEnough() { + Assume.group(TestGroup.PERFORMANCE); + + @SuppressWarnings("unused") + class C { + void m00() { } void m01() { } void m02() { } void m03() { } void m04() { } + void m05() { } void m06() { } void m07() { } void m08() { } void m09() { } + void m10() { } void m11() { } void m12() { } void m13() { } void m14() { } + void m15() { } void m16() { } void m17() { } void m18() { } void m19() { } + void m20() { } void m21() { } void m22() { } void m23() { } void m24() { } + void m25() { } void m26() { } void m27() { } void m28() { } void m29() { } + void m30() { } void m31() { } void m32() { } void m33() { } void m34() { } + void m35() { } void m36() { } void m37() { } void m38() { } void m39() { } + void m40() { } void m41() { } void m42() { } void m43() { } void m44() { } + void m45() { } void m46() { } void m47() { } void m48() { } void m49() { } + void m50() { } void m51() { } void m52() { } void m53() { } void m54() { } + void m55() { } void m56() { } void m57() { } void m58() { } void m59() { } + void m60() { } void m61() { } void m62() { } void m63() { } void m64() { } + void m65() { } void m66() { } void m67() { } void m68() { } void m69() { } + void m70() { } void m71() { } void m72() { } void m73() { } void m74() { } + void m75() { } void m76() { } void m77() { } void m78() { } void m79() { } + void m80() { } void m81() { } void m82() { } void m83() { } void m84() { } + void m85() { } void m86() { } void m87() { } void m88() { } void m89() { } + void m90() { } void m91() { } void m92() { } void m93() { } void m94() { } + void m95() { } void m96() { } void m97() { } void m98() { } void m99() { } + } + + StopWatch sw = new StopWatch(); + sw.start(); + Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(C.class); + sw.stop(); + long totalMs = sw.getTotalTimeMillis(); + assertThat(methods.length, Matchers.greaterThan(100)); + assertThat(totalMs, Matchers.lessThan(10L)); + } + + private static class ListSavingMethodCallback implements ReflectionUtils.MethodCallback { + + private List<String> methodNames = new LinkedList<String>(); + + private List<Method> methods = new LinkedList<Method>(); + + @Override + public void doWith(Method m) throws IllegalArgumentException, IllegalAccessException { + this.methodNames.add(m.getName()); + this.methods.add(m); + } + + public List<String> getMethodNames() { + return this.methodNames; + } + + @SuppressWarnings("unused") + public List<Method> getMethods() { + return this.methods; + } + } + + private static class TestObjectSubclass extends TestObject { + + @Override + public void absquatulate() { + throw new UnsupportedOperationException(); + } + } + + private static class TestObjectSubclassWithPublicField extends TestObject { + + @SuppressWarnings("unused") + public String publicField = "foo"; + } + + private static class TestObjectSubclassWithNewField extends TestObject { + + private int magic; + + protected String prot = "foo"; + } + + private static class TestObjectSubclassWithFinalField extends TestObject { + + @SuppressWarnings("unused") + private final String foo = "will break naive copy that doesn't exclude statics"; + } + + private static class A { + + @SuppressWarnings("unused") + private void foo(Integer i) throws RemoteException { + } + } + + @SuppressWarnings("unused") + private static class B extends A { + + void bar(String s) throws IllegalArgumentException { + } + + int add(int... args) { + int sum = 0; + for (int i = 0; i < args.length; i++) { + sum += args[i]; + } + return sum; + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/ResourceUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ResourceUtilsTests.java new file mode 100644 index 00000000..7129e8d2 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/ResourceUtilsTests.java @@ -0,0 +1,72 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +import junit.framework.TestCase; + +/** + * @author Juergen Hoeller + */ +public class ResourceUtilsTests extends TestCase { + + public void testIsJarURL() throws Exception { + assertTrue(ResourceUtils.isJarURL(new URL("jar:file:myjar.jar!/mypath"))); + assertTrue(ResourceUtils.isJarURL(new URL(null, "zip:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertTrue(ResourceUtils.isJarURL(new URL(null, "wsjar:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertFalse(ResourceUtils.isJarURL(new URL("file:myjar.jar"))); + assertFalse(ResourceUtils.isJarURL(new URL("http:myserver/myjar.jar"))); + } + + public void testExtractJarFileURL() throws Exception { + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL("jar:file:myjar.jar!/mypath"))); + assertEquals(new URL("file:/myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "jar:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "zip:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "wsjar:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL("jar:file:myjar.jar!/"))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "zip:file:myjar.jar!/", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL(null, "wsjar:file:myjar.jar!/", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL("file:myjar.jar"))); + } + + + /** + * Dummy URLStreamHandler that's just specified to suppress the standard + * {@code java.net.URL} URLStreamHandler lookup, to be able to + * use the standard URL class for parsing "rmi:..." URLs. + */ + private static class DummyURLStreamHandler extends URLStreamHandler { + + @Override + protected URLConnection openConnection(URL url) throws IOException { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/SerializationTestUtils.java b/spring-core/src/test/java/org/springframework/util/SerializationTestUtils.java new file mode 100644 index 00000000..53e67f65 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/SerializationTestUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +/** + * Utilities for testing serializability of objects. + * Exposes static methods for use in other test cases. + * + * @author Rod Johnson + */ +public class SerializationTestUtils { + + public static void testSerialization(Object o) throws IOException { + OutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + } + + public static boolean isSerializable(Object o) throws IOException { + try { + testSerialization(o); + return true; + } + catch (NotSerializableException ex) { + return false; + } + } + + public static Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.flush(); + baos.flush(); + byte[] bytes = baos.toByteArray(); + + ByteArrayInputStream is = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(is); + Object o2 = ois.readObject(); + return o2; + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/SerializationUtilsTests.java b/spring-core/src/test/java/org/springframework/util/SerializationUtilsTests.java new file mode 100644 index 00000000..5b9c43c1 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/SerializationUtilsTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import java.math.BigInteger; + +import org.junit.Test; + +import org.springframework.util.SerializationUtils; + +/** + * Test for static utility to help with serialization. + * + * @author Dave Syer + * @since 3.0.5 + */ +public class SerializationUtilsTests { + + private static BigInteger FOO = new BigInteger( + "-9702942423549012526722364838327831379660941553432801565505143675386108883970811292563757558516603356009681061" + + "5697574744209306031461371833798723505120163874786203211176873686513374052845353833564048"); + + + @Test + public void serializeCycleSunnyDay() throws Exception { + assertEquals("foo", SerializationUtils.deserialize(SerializationUtils.serialize("foo"))); + } + + @Test(expected = IllegalStateException.class) + public void deserializeUndefined() throws Exception { + byte[] bytes = FOO.toByteArray(); + Object foo = SerializationUtils.deserialize(bytes); + assertNotNull(foo); + } + + @Test(expected = IllegalArgumentException.class) + public void serializeNonSerializable() throws Exception { + SerializationUtils.serialize(new Object()); + } + + @Test(expected = IllegalArgumentException.class) + public void deserializeNonSerializable() throws Exception { + SerializationUtils.deserialize("foo".getBytes()); + } + + @Test + public void serializeNull() throws Exception { + assertNull(SerializationUtils.serialize(null)); + } + + @Test + public void deserializeNull() throws Exception { + assertNull(SerializationUtils.deserialize(null)); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/StopWatchTests.java b/spring-core/src/test/java/org/springframework/util/StopWatchTests.java new file mode 100644 index 00000000..4170f556 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/StopWatchTests.java @@ -0,0 +1,144 @@ + +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import junit.framework.TestCase; + +/** + * @author Rod Johnson + */ +public class StopWatchTests extends TestCase { + + /** + * Are timings off in JUnit? + */ + public void testValidUsage() throws Exception { + StopWatch sw = new StopWatch(); + long int1 = 166L; + long int2 = 45L; + String name1 = "Task 1"; + String name2 = "Task 2"; + + assertFalse(sw.isRunning()); + sw.start(name1); + Thread.sleep(int1); + assertTrue(sw.isRunning()); + sw.stop(); + + // TODO are timings off in JUnit? Why do these assertions sometimes fail + // under both Ant and Eclipse? + + //long fudgeFactor = 5L; + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() >= int1); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() <= int1 + fudgeFactor); + sw.start(name2); + Thread.sleep(int2); + sw.stop(); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() >= int1 + int2); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() <= int1 + int2 + fudgeFactor); + + assertTrue(sw.getTaskCount() == 2); + String pp = sw.prettyPrint(); + assertTrue(pp.indexOf(name1) != -1); + assertTrue(pp.indexOf(name2) != -1); + + StopWatch.TaskInfo[] tasks = sw.getTaskInfo(); + assertTrue(tasks.length == 2); + assertTrue(tasks[0].getTaskName().equals(name1)); + assertTrue(tasks[1].getTaskName().equals(name2)); + sw.toString(); + } + + public void testValidUsageNotKeepingTaskList() throws Exception { + StopWatch sw = new StopWatch(); + sw.setKeepTaskList(false); + long int1 = 166L; + long int2 = 45L; + String name1 = "Task 1"; + String name2 = "Task 2"; + + assertFalse(sw.isRunning()); + sw.start(name1); + Thread.sleep(int1); + assertTrue(sw.isRunning()); + sw.stop(); + + // TODO are timings off in JUnit? Why do these assertions sometimes fail + // under both Ant and Eclipse? + + //long fudgeFactor = 5L; + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() >= int1); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() <= int1 + fudgeFactor); + sw.start(name2); + Thread.sleep(int2); + sw.stop(); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() >= int1 + int2); + //assertTrue("Unexpected timing " + sw.getTotalTime(), sw.getTotalTime() <= int1 + int2 + fudgeFactor); + + assertTrue(sw.getTaskCount() == 2); + String pp = sw.prettyPrint(); + assertTrue(pp.indexOf("kept") != -1); + sw.toString(); + + try { + sw.getTaskInfo(); + fail(); + } + catch (UnsupportedOperationException ex) { + // Ok + } + } + + public void testFailureToStartBeforeGettingTimings() { + StopWatch sw = new StopWatch(); + try { + sw.getLastTaskTimeMillis(); + fail("Can't get last interval if no tests run"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testFailureToStartBeforeStop() { + StopWatch sw = new StopWatch(); + try { + sw.stop(); + fail("Can't stop without starting"); + } + catch (IllegalStateException ex) { + // Ok + } + } + + public void testRejectsStartTwice() { + StopWatch sw = new StopWatch(); + try { + sw.start(""); + sw.stop(); + sw.start(""); + assertTrue(sw.isRunning()); + sw.start(""); + fail("Can't start twice"); + } + catch (IllegalStateException ex) { + // Ok + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java b/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java new file mode 100644 index 00000000..61810c98 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/StreamUtilsTests.java @@ -0,0 +1,125 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.util.Random; +import java.util.UUID; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.mockito.BDDMockito.*; + +/** + * Tests for {@link StreamUtils}. + * + * @author Phillip Webb + */ +public class StreamUtilsTests { + + private byte[] bytes = new byte[StreamUtils.BUFFER_SIZE + 10]; + + private String string = ""; + + @Before + public void setup() { + new Random().nextBytes(bytes); + while (string.length() < StreamUtils.BUFFER_SIZE + 10) { + string += UUID.randomUUID().toString(); + } + } + + @Test + public void copyToByteArray() throws Exception { + InputStream inputStream = spy(new ByteArrayInputStream(bytes)); + byte[] actual = StreamUtils.copyToByteArray(inputStream); + assertThat(actual, equalTo(bytes)); + verify(inputStream, never()).close(); + } + + @Test + public void copyToString() throws Exception { + Charset charset = Charset.defaultCharset(); + InputStream inputStream = spy(new ByteArrayInputStream(string.getBytes(charset))); + String actual = StreamUtils.copyToString(inputStream, charset); + assertThat(actual, equalTo(string)); + verify(inputStream, never()).close(); + } + + @Test + public void copyBytes() throws Exception { + ByteArrayOutputStream out = spy(new ByteArrayOutputStream()); + StreamUtils.copy(bytes, out); + assertThat(out.toByteArray(), equalTo(bytes)); + verify(out, never()).close(); + } + + @Test + public void copyString() throws Exception { + Charset charset = Charset.defaultCharset(); + ByteArrayOutputStream out = spy(new ByteArrayOutputStream()); + StreamUtils.copy(string, charset, out); + assertThat(out.toByteArray(), equalTo(string.getBytes(charset))); + verify(out, never()).close(); + } + + @Test + public void copyStream() throws Exception { + ByteArrayOutputStream out = spy(new ByteArrayOutputStream()); + StreamUtils.copy(new ByteArrayInputStream(bytes), out); + assertThat(out.toByteArray(), equalTo(bytes)); + verify(out, never()).close(); + } + + @Test + public void nonClosingInputStream() throws Exception { + InputStream source = mock(InputStream.class); + InputStream nonClosing = StreamUtils.nonClosing(source); + nonClosing.read(); + nonClosing.read(bytes); + nonClosing.read(bytes, 1, 2); + nonClosing.close(); + InOrder ordered = inOrder(source); + ordered.verify(source).read(); + ordered.verify(source).read(bytes, 0, bytes.length); + ordered.verify(source).read(bytes, 1, 2); + ordered.verify(source, never()).close(); + } + + @Test + public void nonClosingOutputStream() throws Exception { + OutputStream source = mock(OutputStream.class); + OutputStream nonClosing = StreamUtils.nonClosing(source); + nonClosing.write(1); + nonClosing.write(bytes); + nonClosing.write(bytes, 1, 2); + nonClosing.close(); + InOrder ordered = inOrder(source); + ordered.verify(source).write(1); + ordered.verify(source).write(bytes, 0, bytes.length); + ordered.verify(source).write(bytes, 1, 2); + ordered.verify(source, never()).close(); + } +} diff --git a/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java b/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java new file mode 100644 index 00000000..be40ac2d --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java @@ -0,0 +1,703 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.Arrays; +import java.util.Locale; +import java.util.Properties; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Rod Johnson + * @author Juergen Hoeller + * @author Rick Evans + */ +public class StringUtilsTests { + + @Test + public void testHasTextBlank() throws Exception { + String blank = " "; + assertEquals(false, StringUtils.hasText(blank)); + } + + @Test + public void testHasTextNullEmpty() throws Exception { + assertEquals(false, StringUtils.hasText(null)); + assertEquals(false, StringUtils.hasText("")); + } + + @Test + public void testHasTextValid() throws Exception { + assertEquals(true, StringUtils.hasText("t")); + } + + @Test + public void testContainsWhitespace() throws Exception { + assertFalse(StringUtils.containsWhitespace(null)); + assertFalse(StringUtils.containsWhitespace("")); + assertFalse(StringUtils.containsWhitespace("a")); + assertFalse(StringUtils.containsWhitespace("abc")); + assertTrue(StringUtils.containsWhitespace(" ")); + assertTrue(StringUtils.containsWhitespace(" a")); + assertTrue(StringUtils.containsWhitespace("abc ")); + assertTrue(StringUtils.containsWhitespace("a b")); + assertTrue(StringUtils.containsWhitespace("a b")); + } + + @Test + public void testTrimWhitespace() throws Exception { + assertEquals(null, StringUtils.trimWhitespace(null)); + assertEquals("", StringUtils.trimWhitespace("")); + assertEquals("", StringUtils.trimWhitespace(" ")); + assertEquals("", StringUtils.trimWhitespace("\t")); + assertEquals("a", StringUtils.trimWhitespace(" a")); + assertEquals("a", StringUtils.trimWhitespace("a ")); + assertEquals("a", StringUtils.trimWhitespace(" a ")); + assertEquals("a b", StringUtils.trimWhitespace(" a b ")); + assertEquals("a b c", StringUtils.trimWhitespace(" a b c ")); + } + + @Test + public void testTrimAllWhitespace() throws Exception { + assertEquals("", StringUtils.trimAllWhitespace("")); + assertEquals("", StringUtils.trimAllWhitespace(" ")); + assertEquals("", StringUtils.trimAllWhitespace("\t")); + assertEquals("a", StringUtils.trimAllWhitespace(" a")); + assertEquals("a", StringUtils.trimAllWhitespace("a ")); + assertEquals("a", StringUtils.trimAllWhitespace(" a ")); + assertEquals("ab", StringUtils.trimAllWhitespace(" a b ")); + assertEquals("abc", StringUtils.trimAllWhitespace(" a b c ")); + } + + @Test + public void testTrimLeadingWhitespace() throws Exception { + assertEquals(null, StringUtils.trimLeadingWhitespace(null)); + assertEquals("", StringUtils.trimLeadingWhitespace("")); + assertEquals("", StringUtils.trimLeadingWhitespace(" ")); + assertEquals("", StringUtils.trimLeadingWhitespace("\t")); + assertEquals("a", StringUtils.trimLeadingWhitespace(" a")); + assertEquals("a ", StringUtils.trimLeadingWhitespace("a ")); + assertEquals("a ", StringUtils.trimLeadingWhitespace(" a ")); + assertEquals("a b ", StringUtils.trimLeadingWhitespace(" a b ")); + assertEquals("a b c ", StringUtils.trimLeadingWhitespace(" a b c ")); + } + + @Test + public void testTrimTrailingWhitespace() throws Exception { + assertEquals(null, StringUtils.trimTrailingWhitespace(null)); + assertEquals("", StringUtils.trimTrailingWhitespace("")); + assertEquals("", StringUtils.trimTrailingWhitespace(" ")); + assertEquals("", StringUtils.trimTrailingWhitespace("\t")); + assertEquals("a", StringUtils.trimTrailingWhitespace("a ")); + assertEquals(" a", StringUtils.trimTrailingWhitespace(" a")); + assertEquals(" a", StringUtils.trimTrailingWhitespace(" a ")); + assertEquals(" a b", StringUtils.trimTrailingWhitespace(" a b ")); + assertEquals(" a b c", StringUtils.trimTrailingWhitespace(" a b c ")); + } + + @Test + public void testTrimLeadingCharacter() throws Exception { + assertEquals(null, StringUtils.trimLeadingCharacter(null, ' ')); + assertEquals("", StringUtils.trimLeadingCharacter("", ' ')); + assertEquals("", StringUtils.trimLeadingCharacter(" ", ' ')); + assertEquals("\t", StringUtils.trimLeadingCharacter("\t", ' ')); + assertEquals("a", StringUtils.trimLeadingCharacter(" a", ' ')); + assertEquals("a ", StringUtils.trimLeadingCharacter("a ", ' ')); + assertEquals("a ", StringUtils.trimLeadingCharacter(" a ", ' ')); + assertEquals("a b ", StringUtils.trimLeadingCharacter(" a b ", ' ')); + assertEquals("a b c ", StringUtils.trimLeadingCharacter(" a b c ", ' ')); + } + + @Test + public void testTrimTrailingCharacter() throws Exception { + assertEquals(null, StringUtils.trimTrailingCharacter(null, ' ')); + assertEquals("", StringUtils.trimTrailingCharacter("", ' ')); + assertEquals("", StringUtils.trimTrailingCharacter(" ", ' ')); + assertEquals("\t", StringUtils.trimTrailingCharacter("\t", ' ')); + assertEquals("a", StringUtils.trimTrailingCharacter("a ", ' ')); + assertEquals(" a", StringUtils.trimTrailingCharacter(" a", ' ')); + assertEquals(" a", StringUtils.trimTrailingCharacter(" a ", ' ')); + assertEquals(" a b", StringUtils.trimTrailingCharacter(" a b ", ' ')); + assertEquals(" a b c", StringUtils.trimTrailingCharacter(" a b c ", ' ')); + } + + @Test + public void testCountOccurrencesOf() { + assertTrue("nullx2 = 0", + StringUtils.countOccurrencesOf(null, null) == 0); + assertTrue("null string = 0", + StringUtils.countOccurrencesOf("s", null) == 0); + assertTrue("null substring = 0", + StringUtils.countOccurrencesOf(null, "s") == 0); + String s = "erowoiueoiur"; + assertTrue("not found = 0", + StringUtils.countOccurrencesOf(s, "WERWER") == 0); + assertTrue("not found char = 0", + StringUtils.countOccurrencesOf(s, "x") == 0); + assertTrue("not found ws = 0", + StringUtils.countOccurrencesOf(s, " ") == 0); + assertTrue("not found empty string = 0", + StringUtils.countOccurrencesOf(s, "") == 0); + assertTrue("found char=2", StringUtils.countOccurrencesOf(s, "e") == 2); + assertTrue("found substring=2", + StringUtils.countOccurrencesOf(s, "oi") == 2); + assertTrue("found substring=2", + StringUtils.countOccurrencesOf(s, "oiu") == 2); + assertTrue("found substring=3", + StringUtils.countOccurrencesOf(s, "oiur") == 1); + assertTrue("test last", StringUtils.countOccurrencesOf(s, "r") == 2); + } + + @Test + public void testReplace() throws Exception { + String inString = "a6AazAaa77abaa"; + String oldPattern = "aa"; + String newPattern = "foo"; + + // Simple replace + String s = StringUtils.replace(inString, oldPattern, newPattern); + assertTrue("Replace 1 worked", s.equals("a6AazAfoo77abfoo")); + + // Non match: no change + s = StringUtils.replace(inString, "qwoeiruqopwieurpoqwieur", newPattern); + assertTrue("Replace non matched is equal", s.equals(inString)); + + // Null new pattern: should ignore + s = StringUtils.replace(inString, oldPattern, null); + assertTrue("Replace non matched is equal", s.equals(inString)); + + // Null old pattern: should ignore + s = StringUtils.replace(inString, null, newPattern); + assertTrue("Replace non matched is equal", s.equals(inString)); + } + + @Test + public void testDelete() throws Exception { + String inString = "The quick brown fox jumped over the lazy dog"; + + String noThe = StringUtils.delete(inString, "the"); + assertTrue("Result has no the [" + noThe + "]", + noThe.equals("The quick brown fox jumped over lazy dog")); + + String nohe = StringUtils.delete(inString, "he"); + assertTrue("Result has no he [" + nohe + "]", + nohe.equals("T quick brown fox jumped over t lazy dog")); + + String nosp = StringUtils.delete(inString, " "); + assertTrue("Result has no spaces", + nosp.equals("Thequickbrownfoxjumpedoverthelazydog")); + + String killEnd = StringUtils.delete(inString, "dog"); + assertTrue("Result has no dog", + killEnd.equals("The quick brown fox jumped over the lazy ")); + + String mismatch = StringUtils.delete(inString, "dxxcxcxog"); + assertTrue("Result is unchanged", mismatch.equals(inString)); + + String nochange = StringUtils.delete(inString, ""); + assertTrue("Result is unchanged", nochange.equals(inString)); + } + + @Test + public void testDeleteAny() throws Exception { + String inString = "Able was I ere I saw Elba"; + + String res = StringUtils.deleteAny(inString, "I"); + assertTrue("Result has no Is [" + res + "]", res.equals("Able was ere saw Elba")); + + res = StringUtils.deleteAny(inString, "AeEba!"); + assertTrue("Result has no Is [" + res + "]", res.equals("l ws I r I sw l")); + + String mismatch = StringUtils.deleteAny(inString, "#@$#$^"); + assertTrue("Result is unchanged", mismatch.equals(inString)); + + String whitespace = "This is\n\n\n \t a messagy string with whitespace\n"; + assertTrue("Has CR", whitespace.contains("\n")); + assertTrue("Has tab", whitespace.contains("\t")); + assertTrue("Has sp", whitespace.contains(" ")); + String cleaned = StringUtils.deleteAny(whitespace, "\n\t "); + assertTrue("Has no CR", !cleaned.contains("\n")); + assertTrue("Has no tab", !cleaned.contains("\t")); + assertTrue("Has no sp", !cleaned.contains(" ")); + assertTrue("Still has chars", cleaned.length() > 10); + } + + + @Test + public void testQuote() { + assertEquals("'myString'", StringUtils.quote("myString")); + assertEquals("''", StringUtils.quote("")); + assertNull(StringUtils.quote(null)); + } + + @Test + public void testQuoteIfString() { + assertEquals("'myString'", StringUtils.quoteIfString("myString")); + assertEquals("''", StringUtils.quoteIfString("")); + assertEquals(new Integer(5), StringUtils.quoteIfString(5)); + assertNull(StringUtils.quoteIfString(null)); + } + + @Test + public void testUnqualify() { + String qualified = "i.am.not.unqualified"; + assertEquals("unqualified", StringUtils.unqualify(qualified)); + } + + @Test + public void testCapitalize() { + String capitalized = "i am not capitalized"; + assertEquals("I am not capitalized", StringUtils.capitalize(capitalized)); + } + + @Test + public void testUncapitalize() { + String capitalized = "I am capitalized"; + assertEquals("i am capitalized", StringUtils.uncapitalize(capitalized)); + } + + @Test + public void testGetFilename() { + assertEquals(null, StringUtils.getFilename(null)); + assertEquals("", StringUtils.getFilename("")); + assertEquals("myfile", StringUtils.getFilename("myfile")); + assertEquals("myfile", StringUtils.getFilename("mypath/myfile")); + assertEquals("myfile.", StringUtils.getFilename("myfile.")); + assertEquals("myfile.", StringUtils.getFilename("mypath/myfile.")); + assertEquals("myfile.txt", StringUtils.getFilename("myfile.txt")); + assertEquals("myfile.txt", StringUtils.getFilename("mypath/myfile.txt")); + } + + @Test + public void testGetFilenameExtension() { + assertEquals(null, StringUtils.getFilenameExtension(null)); + assertEquals(null, StringUtils.getFilenameExtension("")); + assertEquals(null, StringUtils.getFilenameExtension("myfile")); + assertEquals(null, StringUtils.getFilenameExtension("myPath/myfile")); + assertEquals(null, StringUtils.getFilenameExtension("/home/user/.m2/settings/myfile")); + assertEquals("", StringUtils.getFilenameExtension("myfile.")); + assertEquals("", StringUtils.getFilenameExtension("myPath/myfile.")); + assertEquals("txt", StringUtils.getFilenameExtension("myfile.txt")); + assertEquals("txt", StringUtils.getFilenameExtension("mypath/myfile.txt")); + assertEquals("txt", StringUtils.getFilenameExtension("/home/user/.m2/settings/myfile.txt")); + } + + @Test + public void testStripFilenameExtension() { + assertEquals(null, StringUtils.stripFilenameExtension(null)); + assertEquals("", StringUtils.stripFilenameExtension("")); + assertEquals("myfile", StringUtils.stripFilenameExtension("myfile")); + assertEquals("myfile", StringUtils.stripFilenameExtension("myfile.")); + assertEquals("myfile", StringUtils.stripFilenameExtension("myfile.txt")); + assertEquals("mypath/myfile", StringUtils.stripFilenameExtension("mypath/myfile")); + assertEquals("mypath/myfile", StringUtils.stripFilenameExtension("mypath/myfile.")); + assertEquals("mypath/myfile", StringUtils.stripFilenameExtension("mypath/myfile.txt")); + assertEquals("/home/user/.m2/settings/myfile", StringUtils.stripFilenameExtension("/home/user/.m2/settings/myfile")); + assertEquals("/home/user/.m2/settings/myfile", StringUtils.stripFilenameExtension("/home/user/.m2/settings/myfile.")); + assertEquals("/home/user/.m2/settings/myfile", StringUtils.stripFilenameExtension("/home/user/.m2/settings/myfile.txt")); + } + + @Test + public void testCleanPath() { + assertEquals("mypath/myfile", StringUtils.cleanPath("mypath/myfile")); + assertEquals("mypath/myfile", StringUtils.cleanPath("mypath\\myfile")); + assertEquals("mypath/myfile", StringUtils.cleanPath("mypath/../mypath/myfile")); + assertEquals("mypath/myfile", StringUtils.cleanPath("mypath/myfile/../../mypath/myfile")); + assertEquals("../mypath/myfile", StringUtils.cleanPath("../mypath/myfile")); + assertEquals("../mypath/myfile", StringUtils.cleanPath("../mypath/../mypath/myfile")); + assertEquals("../mypath/myfile", StringUtils.cleanPath("mypath/../../mypath/myfile")); + assertEquals("/../mypath/myfile", StringUtils.cleanPath("/../mypath/myfile")); + assertEquals("/mypath/myfile", StringUtils.cleanPath("/a/:b/../../mypath/myfile")); + assertEquals("file:///c:/path/to/the%20file.txt", StringUtils.cleanPath("file:///c:/some/../path/to/the%20file.txt")); + } + + @Test + public void testPathEquals() { + assertTrue("Must be true for the same strings", + StringUtils.pathEquals("/dummy1/dummy2/dummy3", + "/dummy1/dummy2/dummy3")); + assertTrue("Must be true for the same win strings", + StringUtils.pathEquals("C:\\dummy1\\dummy2\\dummy3", + "C:\\dummy1\\dummy2\\dummy3")); + assertTrue("Must be true for one top path on 1", + StringUtils.pathEquals("/dummy1/bin/../dummy2/dummy3", + "/dummy1/dummy2/dummy3")); + assertTrue("Must be true for one win top path on 2", + StringUtils.pathEquals("C:\\dummy1\\dummy2\\dummy3", + "C:\\dummy1\\bin\\..\\dummy2\\dummy3")); + assertTrue("Must be true for two top paths on 1", + StringUtils.pathEquals("/dummy1/bin/../dummy2/bin/../dummy3", + "/dummy1/dummy2/dummy3")); + assertTrue("Must be true for two win top paths on 2", + StringUtils.pathEquals("C:\\dummy1\\dummy2\\dummy3", + "C:\\dummy1\\bin\\..\\dummy2\\bin\\..\\dummy3")); + assertTrue("Must be true for double top paths on 1", + StringUtils.pathEquals("/dummy1/bin/tmp/../../dummy2/dummy3", + "/dummy1/dummy2/dummy3")); + assertTrue("Must be true for double top paths on 2 with similarity", + StringUtils.pathEquals("/dummy1/dummy2/dummy3", + "/dummy1/dum/dum/../../dummy2/dummy3")); + assertTrue("Must be true for current paths", + StringUtils.pathEquals("./dummy1/dummy2/dummy3", + "dummy1/dum/./dum/../../dummy2/dummy3")); + assertFalse("Must be false for relative/absolute paths", + StringUtils.pathEquals("./dummy1/dummy2/dummy3", + "/dummy1/dum/./dum/../../dummy2/dummy3")); + assertFalse("Must be false for different strings", + StringUtils.pathEquals("/dummy1/dummy2/dummy3", + "/dummy1/dummy4/dummy3")); + assertFalse("Must be false for one false path on 1", + StringUtils.pathEquals("/dummy1/bin/tmp/../dummy2/dummy3", + "/dummy1/dummy2/dummy3")); + assertFalse("Must be false for one false win top path on 2", + StringUtils.pathEquals("C:\\dummy1\\dummy2\\dummy3", + "C:\\dummy1\\bin\\tmp\\..\\dummy2\\dummy3")); + assertFalse("Must be false for top path on 1 + difference", + StringUtils.pathEquals("/dummy1/bin/../dummy2/dummy3", + "/dummy1/dummy2/dummy4")); + } + + @Test + public void testConcatenateStringArrays() { + String[] input1 = new String[] {"myString2"}; + String[] input2 = new String[] {"myString1", "myString2"}; + String[] result = StringUtils.concatenateStringArrays(input1, input2); + assertEquals(3, result.length); + assertEquals("myString2", result[0]); + assertEquals("myString1", result[1]); + assertEquals("myString2", result[2]); + + assertArrayEquals(input1, StringUtils.concatenateStringArrays(input1, null)); + assertArrayEquals(input2, StringUtils.concatenateStringArrays(null, input2)); + assertNull(StringUtils.concatenateStringArrays(null, null)); + } + + @Test + public void testMergeStringArrays() { + String[] input1 = new String[] {"myString2"}; + String[] input2 = new String[] {"myString1", "myString2"}; + String[] result = StringUtils.mergeStringArrays(input1, input2); + assertEquals(2, result.length); + assertEquals("myString2", result[0]); + assertEquals("myString1", result[1]); + + assertArrayEquals(input1, StringUtils.mergeStringArrays(input1, null)); + assertArrayEquals(input2, StringUtils.mergeStringArrays(null, input2)); + assertNull(StringUtils.mergeStringArrays(null, null)); + } + + @Test + public void testSortStringArray() { + String[] input = new String[] {"myString2"}; + input = StringUtils.addStringToArray(input, "myString1"); + assertEquals("myString2", input[0]); + assertEquals("myString1", input[1]); + + StringUtils.sortStringArray(input); + assertEquals("myString1", input[0]); + assertEquals("myString2", input[1]); + } + + @Test + public void testRemoveDuplicateStrings() { + String[] input = new String[] {"myString2", "myString1", "myString2"}; + input = StringUtils.removeDuplicateStrings(input); + assertEquals("myString1", input[0]); + assertEquals("myString2", input[1]); + } + + @Test + public void testSplitArrayElementsIntoProperties() { + String[] input = new String[] {"key1=value1 ", "key2 =\"value2\""}; + Properties result = StringUtils.splitArrayElementsIntoProperties(input, "="); + assertEquals("value1", result.getProperty("key1")); + assertEquals("\"value2\"", result.getProperty("key2")); + } + + @Test + public void testSplitArrayElementsIntoPropertiesAndDeletedChars() { + String[] input = new String[] {"key1=value1 ", "key2 =\"value2\""}; + Properties result = StringUtils.splitArrayElementsIntoProperties(input, "=", "\""); + assertEquals("value1", result.getProperty("key1")); + assertEquals("value2", result.getProperty("key2")); + } + + @Test + public void testTokenizeToStringArray() { + String[] sa = StringUtils.tokenizeToStringArray("a,b , ,c", ","); + assertEquals(3, sa.length); + assertTrue("components are correct", + sa[0].equals("a") && sa[1].equals("b") && sa[2].equals("c")); + } + + @Test + public void testTokenizeToStringArrayWithNotIgnoreEmptyTokens() { + String[] sa = StringUtils.tokenizeToStringArray("a,b , ,c", ",", true, false); + assertEquals(4, sa.length); + assertTrue("components are correct", + sa[0].equals("a") && sa[1].equals("b") && sa[2].equals("") && sa[3].equals("c")); + } + + @Test + public void testTokenizeToStringArrayWithNotTrimTokens() { + String[] sa = StringUtils.tokenizeToStringArray("a,b ,c", ",", false, true); + assertEquals(3, sa.length); + assertTrue("components are correct", + sa[0].equals("a") && sa[1].equals("b ") && sa[2].equals("c")); + } + + @Test + public void testCommaDelimitedListToStringArrayWithNullProducesEmptyArray() { + String[] sa = StringUtils.commaDelimitedListToStringArray(null); + assertTrue("String array isn't null with null input", sa != null); + assertTrue("String array length == 0 with null input", sa.length == 0); + } + + @Test + public void testCommaDelimitedListToStringArrayWithEmptyStringProducesEmptyArray() { + String[] sa = StringUtils.commaDelimitedListToStringArray(""); + assertTrue("String array isn't null with null input", sa != null); + assertTrue("String array length == 0 with null input", sa.length == 0); + } + + @Test + public void testDelimitedListToStringArrayWithComma() { + String[] sa = StringUtils.delimitedListToStringArray("a,b", ","); + assertEquals(2, sa.length); + assertEquals("a", sa[0]); + assertEquals("b", sa[1]); + } + + @Test + public void testDelimitedListToStringArrayWithSemicolon() { + String[] sa = StringUtils.delimitedListToStringArray("a;b", ";"); + assertEquals(2, sa.length); + assertEquals("a", sa[0]); + assertEquals("b", sa[1]); + } + + @Test + public void testDelimitedListToStringArrayWithEmptyString() { + String[] sa = StringUtils.delimitedListToStringArray("a,b", ""); + assertEquals(3, sa.length); + assertEquals("a", sa[0]); + assertEquals(",", sa[1]); + assertEquals("b", sa[2]); + } + + @Test + public void testDelimitedListToStringArrayWithNullDelimiter() { + String[] sa = StringUtils.delimitedListToStringArray("a,b", null); + assertEquals(1, sa.length); + assertEquals("a,b", sa[0]); + } + + @Test + public void testCommaDelimitedListToStringArrayMatchWords() { + // Could read these from files + String[] sa = new String[] {"foo", "bar", "big"}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + doTestStringArrayReverseTransformationMatches(sa); + + sa = new String[] {"a", "b", "c"}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + doTestStringArrayReverseTransformationMatches(sa); + + // Test same words + sa = new String[] {"AA", "AA", "AA", "AA", "AA"}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + doTestStringArrayReverseTransformationMatches(sa); + } + + private void doTestStringArrayReverseTransformationMatches(String[] sa) { + String[] reverse = + StringUtils.commaDelimitedListToStringArray(StringUtils.arrayToCommaDelimitedString(sa)); + assertEquals("Reverse transformation is equal", + Arrays.asList(sa), + Arrays.asList(reverse)); + } + + @Test + public void testCommaDelimitedListToStringArraySingleString() { + // Could read these from files + String s = "woeirqupoiewuropqiewuorpqiwueopriquwopeiurqopwieur"; + String[] sa = StringUtils.commaDelimitedListToStringArray(s); + assertTrue("Found one String with no delimiters", sa.length == 1); + assertTrue("Single array entry matches input String with no delimiters", + sa[0].equals(s)); + } + + @Test + public void testCommaDelimitedListToStringArrayWithOtherPunctuation() { + // Could read these from files + String[] sa = new String[] {"xcvwert4456346&*.", "///", ".!", ".", ";"}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + } + + /** + * We expect to see the empty Strings in the output. + */ + @Test + public void testCommaDelimitedListToStringArrayEmptyStrings() { + // Could read these from files + String[] sa = StringUtils.commaDelimitedListToStringArray("a,,b"); + assertEquals("a,,b produces array length 3", 3, sa.length); + assertTrue("components are correct", + sa[0].equals("a") && sa[1].equals("") && sa[2].equals("b")); + + sa = new String[] {"", "", "a", ""}; + doTestCommaDelimitedListToStringArrayLegalMatch(sa); + } + + private void doTestCommaDelimitedListToStringArrayLegalMatch(String[] components) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < components.length; i++) { + if (i != 0) { + sb.append(","); + } + sb.append(components[i]); + } + String[] sa = StringUtils.commaDelimitedListToStringArray(sb.toString()); + assertTrue("String array isn't null with legal match", sa != null); + assertEquals("String array length is correct with legal match", components.length, sa.length); + assertTrue("Output equals input", Arrays.equals(sa, components)); + } + + @Test + public void testEndsWithIgnoreCase() { + String suffix = "fOo"; + assertTrue(StringUtils.endsWithIgnoreCase("foo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("Foo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barfoo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barbarfoo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barFoo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barBarFoo", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barfoO", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barFOO", suffix)); + assertTrue(StringUtils.endsWithIgnoreCase("barfOo", suffix)); + assertFalse(StringUtils.endsWithIgnoreCase(null, suffix)); + assertFalse(StringUtils.endsWithIgnoreCase("barfOo", null)); + assertFalse(StringUtils.endsWithIgnoreCase("b", suffix)); + } + + + @Test + public void testParseLocaleStringSunnyDay() throws Exception { + Locale expectedLocale = Locale.UK; + Locale locale = StringUtils.parseLocaleString(expectedLocale.toString()); + assertNotNull("When given a bona-fide Locale string, must not return null.", locale); + assertEquals(expectedLocale, locale); + } + + @Test + public void testParseLocaleStringWithMalformedLocaleString() throws Exception { + Locale locale = StringUtils.parseLocaleString("_banjo_on_my_knee"); + assertNotNull("When given a malformed Locale string, must not return null.", locale); + } + + @Test + public void testParseLocaleStringWithEmptyLocaleStringYieldsNullLocale() throws Exception { + Locale locale = StringUtils.parseLocaleString(""); + assertNull("When given an empty Locale string, must return null.", locale); + } + + // SPR-8637 + @Test + public void testParseLocaleWithMultiSpecialCharactersInVariant() throws Exception { + final String variant = "proper-northern"; + final String localeString = "en_GB_" + variant; + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + // SPR-3671 + @Test + public void testParseLocaleWithMultiValuedVariant() throws Exception { + final String variant = "proper_northern"; + final String localeString = "en_GB_" + variant; + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + // SPR-3671 + @Test + public void testParseLocaleWithMultiValuedVariantUsingSpacesAsSeparators() throws Exception { + final String variant = "proper northern"; + final String localeString = "en GB " + variant; + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + // SPR-3671 + @Test + public void testParseLocaleWithMultiValuedVariantUsingMixtureOfUnderscoresAndSpacesAsSeparators() throws Exception { + final String variant = "proper northern"; + final String localeString = "en_GB_" + variant; + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + // SPR-3671 + @Test + public void testParseLocaleWithMultiValuedVariantUsingSpacesAsSeparatorsWithLotsOfLeadingWhitespace() throws Exception { + final String variant = "proper northern"; + final String localeString = "en GB " + variant; // lots of whitespace + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + // SPR-3671 + @Test + public void testParseLocaleWithMultiValuedVariantUsingUnderscoresAsSeparatorsWithLotsOfLeadingWhitespace() throws Exception { + final String variant = "proper_northern"; + final String localeString = "en_GB_____" + variant; // lots of underscores + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Multi-valued variant portion of the Locale not extracted correctly.", variant, locale.getVariant()); + } + + // SPR-7779 + @Test + public void testParseLocaleWithInvalidCharacters() { + try { + StringUtils.parseLocaleString("%0D%0AContent-length:30%0D%0A%0D%0A%3Cscript%3Ealert%28123%29%3C/script%3E"); + fail("Should have thrown IllegalArgumentException"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + // SPR-9420 + @Test + public void testParseLocaleWithSameLowercaseTokenForLanguageAndCountry() { + assertEquals("tr_TR", StringUtils.parseLocaleString("tr_tr").toString()); + assertEquals("bg_BG_vnt", StringUtils.parseLocaleString("bg_bg_vnt").toString()); + } + + // SPR-11806 + @Test + public void testParseLocaleWithVariantContainingCountryCode() { + String variant = "GBtest"; + String localeString = "en_GB_" + variant; + Locale locale = StringUtils.parseLocaleString(localeString); + assertEquals("Variant containing country code not extracted correctly", variant, locale.getVariant()); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/SystemPropertyUtilsTests.java b/spring-core/src/test/java/org/springframework/util/SystemPropertyUtilsTests.java new file mode 100644 index 00000000..d1fb6f8f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/SystemPropertyUtilsTests.java @@ -0,0 +1,137 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * 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 org.springframework.util; + +import java.util.Map; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * @author Rob Harrop + * @author Juergen Hoeller + */ +public class SystemPropertyUtilsTests { + + @Test + public void testReplaceFromSystemProperty() { + System.setProperty("test.prop", "bar"); + try { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}"); + assertEquals("bar", resolved); + } + finally { + System.getProperties().remove("test.prop"); + } + } + + @Test + public void testReplaceFromSystemPropertyWithDefault() { + System.setProperty("test.prop", "bar"); + try { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop:foo}"); + assertEquals("bar", resolved); + } + finally { + System.getProperties().remove("test.prop"); + } + } + + @Test + public void testReplaceFromSystemPropertyWithExpressionDefault() { + System.setProperty("test.prop", "bar"); + try { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop:#{foo.bar}}"); + assertEquals("bar", resolved); + } + finally { + System.getProperties().remove("test.prop"); + } + } + + @Test + public void testReplaceFromSystemPropertyWithExpressionContainingDefault() { + System.setProperty("test.prop", "bar"); + try { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop:Y#{foo.bar}X}"); + assertEquals("bar", resolved); + } + finally { + System.getProperties().remove("test.prop"); + } + } + + @Test + public void testReplaceWithDefault() { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop:foo}"); + assertEquals("foo", resolved); + } + + @Test + public void testReplaceWithExpressionDefault() { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop:#{foo.bar}}"); + assertEquals("#{foo.bar}", resolved); + } + + @Test + public void testReplaceWithExpressionContainingDefault() { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop:Y#{foo.bar}X}"); + assertEquals("Y#{foo.bar}X", resolved); + } + + @Test(expected=IllegalArgumentException.class) + public void testReplaceWithNoDefault() { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}"); + assertEquals("", resolved); + } + + @Test + public void testReplaceWithNoDefaultIgnored() { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}", true); + assertEquals("${test.prop}", resolved); + } + + @Test + public void testReplaceWithEmptyDefault() { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop:}"); + assertEquals("", resolved); + } + + @Test + public void testRecursiveFromSystemProperty() { + System.setProperty("test.prop", "foo=${bar}"); + System.setProperty("bar", "baz"); + try { + String resolved = SystemPropertyUtils.resolvePlaceholders("${test.prop}"); + assertEquals("foo=baz", resolved); + } + finally { + System.getProperties().remove("test.prop"); + System.getProperties().remove("bar"); + } + } + + @Test + public void testReplaceFromEnv() { + Map<String,String> env = System.getenv(); + if (env.containsKey("PATH")) { + String text = "${PATH}"; + assertEquals(env.get("PATH"), SystemPropertyUtils.resolvePlaceholders(text)); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/TypeUtilsTests.java b/spring-core/src/test/java/org/springframework/util/TypeUtilsTests.java new file mode 100644 index 00000000..b32dbbbb --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/TypeUtilsTests.java @@ -0,0 +1,128 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * 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 org.springframework.util; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; + +import org.junit.Test; + +/** + * Unit tests for {@link TypeUtils}. + * + * @author Juergen Hoeller + * @author Chris Beams + */ +public class TypeUtilsTests { + + public static Object object; + + public static String string; + + public static Integer number; + + public static List<Object> objects; + + public static List<String> strings; + + public static List<? extends Object> openObjects; + + public static List<? extends Number> openNumbers; + + public static List<? super Object> storableObjectList; + + public static List<Number>[] array; + + public static List<? extends Number>[] openArray; + + + @Test + public void withClasses() { + assertTrue(TypeUtils.isAssignable(Object.class, Object.class)); + assertTrue(TypeUtils.isAssignable(Object.class, String.class)); + assertFalse(TypeUtils.isAssignable(String.class, Object.class)); + assertTrue(TypeUtils.isAssignable(List.class, List.class)); + assertTrue(TypeUtils.isAssignable(List.class, LinkedList.class)); + assertFalse(TypeUtils.isAssignable(List.class, Collection.class)); + assertFalse(TypeUtils.isAssignable(List.class, HashSet.class)); + } + + @Test + public void withParameterizedTypes() throws Exception { + Type objectsType = getClass().getField("objects").getGenericType(); + Type openObjectsType = getClass().getField("openObjects").getGenericType(); + Type stringsType = getClass().getField("strings").getGenericType(); + assertTrue(TypeUtils.isAssignable(Object.class, objectsType)); + assertTrue(TypeUtils.isAssignable(Object.class, openObjectsType)); + assertTrue(TypeUtils.isAssignable(Object.class, stringsType)); + assertTrue(TypeUtils.isAssignable(List.class, objectsType)); + assertTrue(TypeUtils.isAssignable(List.class, openObjectsType)); + assertTrue(TypeUtils.isAssignable(List.class, stringsType)); + assertTrue(TypeUtils.isAssignable(objectsType, List.class)); + assertTrue(TypeUtils.isAssignable(openObjectsType, List.class)); + assertTrue(TypeUtils.isAssignable(stringsType, List.class)); + assertTrue(TypeUtils.isAssignable(objectsType, objectsType)); + assertTrue(TypeUtils.isAssignable(openObjectsType, openObjectsType)); + assertTrue(TypeUtils.isAssignable(stringsType, stringsType)); + assertTrue(TypeUtils.isAssignable(openObjectsType, objectsType)); + assertTrue(TypeUtils.isAssignable(openObjectsType, stringsType)); + assertFalse(TypeUtils.isAssignable(stringsType, objectsType)); + assertFalse(TypeUtils.isAssignable(objectsType, stringsType)); + } + + @Test + public void withWildcardTypes() throws Exception { + ParameterizedType openObjectsType = (ParameterizedType) getClass().getField("openObjects").getGenericType(); + ParameterizedType openNumbersType = (ParameterizedType) getClass().getField("openNumbers").getGenericType(); + Type storableObjectListType = getClass().getField("storableObjectList").getGenericType(); + + Type objectType = getClass().getField("object").getGenericType(); + Type numberType = getClass().getField("number").getGenericType(); + Type stringType = getClass().getField("string").getGenericType(); + + Type openWildcard = openObjectsType.getActualTypeArguments()[0]; // '?' + Type openNumbersWildcard = openNumbersType.getActualTypeArguments()[0]; // '? extends number' + + assertTrue(TypeUtils.isAssignable(openWildcard, objectType)); + assertTrue(TypeUtils.isAssignable(openNumbersWildcard, numberType)); + assertFalse(TypeUtils.isAssignable(openNumbersWildcard, stringType)); + assertFalse(TypeUtils.isAssignable(storableObjectListType, openObjectsType)); + } + + @Test + public void withGenericArrayTypes() throws Exception { + Type arrayType = getClass().getField("array").getGenericType(); + Type openArrayType = getClass().getField("openArray").getGenericType(); + assertTrue(TypeUtils.isAssignable(Object.class, arrayType)); + assertTrue(TypeUtils.isAssignable(Object.class, openArrayType)); + assertTrue(TypeUtils.isAssignable(List[].class, arrayType)); + assertTrue(TypeUtils.isAssignable(List[].class, openArrayType)); + assertTrue(TypeUtils.isAssignable(arrayType, List[].class)); + assertTrue(TypeUtils.isAssignable(openArrayType, List[].class)); + assertTrue(TypeUtils.isAssignable(arrayType, arrayType)); + assertTrue(TypeUtils.isAssignable(openArrayType, openArrayType)); + assertTrue(TypeUtils.isAssignable(openArrayType, arrayType)); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/comparator/BooleanComparatorTests.java b/spring-core/src/test/java/org/springframework/util/comparator/BooleanComparatorTests.java new file mode 100644 index 00000000..4074cc1b --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/comparator/BooleanComparatorTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util.comparator; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +import java.util.Comparator; + +import org.junit.Test; + +/** + * Tests for {@link BooleanComparator}. + * + * @author Keith Donald + * @author Chris Beams + * @author Phillip Webb + */ +public class BooleanComparatorTests { + + @Test + public void shouldCompareWithTrueLow() { + Comparator<Boolean> c = new BooleanComparator(true); + assertThat(c.compare(new Boolean(true), new Boolean(false)), is(-1)); + assertThat(c.compare(Boolean.TRUE, Boolean.TRUE), is(0)); + } + + @Test + public void shouldCompareWithTrueHigh() { + Comparator<Boolean> c = new BooleanComparator(false); + assertThat(c.compare(new Boolean(true), new Boolean(false)), is(1)); + assertThat(c.compare(Boolean.TRUE, Boolean.TRUE), is(0)); + } + + @Test + public void shouldCompareFromTrueLow() { + Comparator<Boolean> c = BooleanComparator.TRUE_LOW; + assertThat(c.compare(true, false), is(-1)); + assertThat(c.compare(Boolean.TRUE, Boolean.TRUE), is(0)); + } + + @Test + public void shouldCompareFromTrueHigh() { + Comparator<Boolean> c = BooleanComparator.TRUE_HIGH; + assertThat(c.compare(true, false), is(1)); + assertThat(c.compare(Boolean.TRUE, Boolean.TRUE), is(0)); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/comparator/ComparableComparatorTests.java b/spring-core/src/test/java/org/springframework/util/comparator/ComparableComparatorTests.java new file mode 100644 index 00000000..450442f2 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/comparator/ComparableComparatorTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util.comparator; + +import static org.junit.Assert.assertTrue; + +import java.util.Comparator; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Tests for {@link ComparableComparator}. + * + * @author Keith Donald + * @author Chris Beams + * @author Phillip Webb + */ +public class ComparableComparatorTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void testComparableComparator() { + Comparator<String> c = new ComparableComparator<String>(); + String s1 = "abc"; + String s2 = "cde"; + assertTrue(c.compare(s1, s2) < 0); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void shouldNeedComparable() { + Comparator c = new ComparableComparator(); + Object o1 = new Object(); + Object o2 = new Object(); + thrown.expect(ClassCastException.class); + c.compare(o1, o2); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/comparator/CompoundComparatorTests.java b/spring-core/src/test/java/org/springframework/util/comparator/CompoundComparatorTests.java new file mode 100644 index 00000000..10d5ca33 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/comparator/CompoundComparatorTests.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util.comparator; + +import java.util.Comparator; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +/** + * Test for {@link ComparableComparator}. + * + * @author Keith Donald + * @author Chris Beams + * @author Phillip Webb + */ +public class CompoundComparatorTests { + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Test + public void shouldNeedAtLeastOneComparator() { + Comparator<String> c = new CompoundComparator<String>(); + thrown.expect(IllegalStateException.class); + c.compare("foo", "bar"); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/comparator/InstanceComparatorTests.java b/spring-core/src/test/java/org/springframework/util/comparator/InstanceComparatorTests.java new file mode 100644 index 00000000..8a483dcb --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/comparator/InstanceComparatorTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util.comparator; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +import java.util.Comparator; + +import org.junit.Test; + +/** + * Tests for {@link InstanceComparator}. + * + * @author Phillip Webb + */ +public class InstanceComparatorTests { + + private C1 c1 = new C1(); + + private C2 c2 = new C2(); + + private C3 c3 = new C3(); + + private C4 c4 = new C4(); + + @Test + public void shouldCompareClasses() throws Exception { + Comparator<Object> comparator = new InstanceComparator<Object>(C1.class, C2.class); + assertThat(comparator.compare(c1, c1), is(0)); + assertThat(comparator.compare(c1, c2), is(-1)); + assertThat(comparator.compare(c2, c1), is(1)); + assertThat(comparator.compare(c2, c3), is(-1)); + assertThat(comparator.compare(c2, c4), is(-1)); + assertThat(comparator.compare(c3, c4), is(0)); + } + + @Test + public void shouldCompareInterfaces() throws Exception { + Comparator<Object> comparator = new InstanceComparator<Object>(I1.class, I2.class); + assertThat(comparator.compare(c1, c1), is(0)); + assertThat(comparator.compare(c1, c2), is(0)); + assertThat(comparator.compare(c2, c1), is(0)); + assertThat(comparator.compare(c1, c3), is(-1)); + assertThat(comparator.compare(c3, c1), is(1)); + assertThat(comparator.compare(c3, c4), is(0)); + } + + @Test + public void shouldCompareMix() throws Exception { + Comparator<Object> comparator = new InstanceComparator<Object>(I1.class, C3.class); + assertThat(comparator.compare(c1, c1), is(0)); + assertThat(comparator.compare(c3, c4), is(-1)); + assertThat(comparator.compare(c3, null), is(-1)); + assertThat(comparator.compare(c4, null), is(0)); + } + + private static interface I1 { + + } + + private static interface I2 { + + } + + private static class C1 implements I1 { + } + + private static class C2 implements I1 { + } + + private static class C3 implements I2 { + } + + private static class C4 implements I2 { + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/comparator/InvertibleComparatorTests.java b/spring-core/src/test/java/org/springframework/util/comparator/InvertibleComparatorTests.java new file mode 100644 index 00000000..c8afa7a6 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/comparator/InvertibleComparatorTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util.comparator; + +import java.util.Comparator; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; + +/** + * Tests for {@link InvertibleComparator}. + * + * @author Keith Donald + * @author Chris Beams + * @author Phillip Webb + */ + +public class InvertibleComparatorTests { + + private Comparator<Integer> comparator = new ComparableComparator<Integer>(); + + @Test(expected=IllegalArgumentException.class) + public void shouldNeedComparator() throws Exception { + new InvertibleComparator<Object>(null); + } + + @Test(expected=IllegalArgumentException.class) + public void shouldNeedComparatorWithAscending() throws Exception { + new InvertibleComparator<Object>(null, true); + } + + @Test + public void shouldDefaultToAscending() throws Exception { + InvertibleComparator<Integer> invertibleComparator = + new InvertibleComparator<Integer>(comparator); + assertThat(invertibleComparator.isAscending(), is(true)); + assertThat(invertibleComparator.compare(1, 2), is(-1)); + } + + @Test + public void shouldInvert() throws Exception { + InvertibleComparator<Integer> invertibleComparator = + new InvertibleComparator<Integer>(comparator); + assertThat(invertibleComparator.isAscending(), is(true)); + assertThat(invertibleComparator.compare(1, 2), is(-1)); + invertibleComparator.invertOrder(); + assertThat(invertibleComparator.isAscending(), is(false)); + assertThat(invertibleComparator.compare(1, 2), is(1)); + } + + @Test + public void shouldCompareAscending() throws Exception { + InvertibleComparator<Integer> invertibleComparator = + new InvertibleComparator<Integer>(comparator, true); + assertThat(invertibleComparator.compare(1, 2), is(-1)); + } + + @Test + public void shouldCompareDescending() throws Exception { + InvertibleComparator<Integer> invertibleComparator = + new InvertibleComparator<Integer>(comparator, false); + assertThat(invertibleComparator.compare(1, 2), is(1)); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/comparator/NullSafeComparatorTests.java b/spring-core/src/test/java/org/springframework/util/comparator/NullSafeComparatorTests.java new file mode 100644 index 00000000..9615f0c0 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/comparator/NullSafeComparatorTests.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util.comparator; + +import static org.junit.Assert.*; + +import java.util.Comparator; + +import org.junit.Test; + +/** + * Tests for {@link NullSafeComparator}. + * + * @author Keith Donald + * @author Chris Beams + * @author Phillip Webb + */ +public class NullSafeComparatorTests { + + @SuppressWarnings("unchecked") + @Test + public void shouldCompareWithNullsLow() { + Comparator<String> c = NullSafeComparator.NULLS_LOW; + assertTrue(c.compare(null, "boo") < 0); + } + + @SuppressWarnings("unchecked") + @Test + public void shouldCompareWithNullsHigh() { + Comparator<String> c = NullSafeComparator.NULLS_HIGH; + assertTrue(c.compare(null, "boo") > 0); + assertTrue(c.compare(null, null) == 0); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxContentHandlerTestCase.java b/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxContentHandlerTestCase.java new file mode 100644 index 00000000..9cab8c0d --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxContentHandlerTestCase.java @@ -0,0 +1,66 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import javax.xml.stream.XMLStreamException; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import org.junit.Before; +import org.junit.Test; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +public abstract class AbstractStaxContentHandlerTestCase { + + private static final String XML_CONTENT_HANDLER = + "<?xml version='1.0' encoding='UTF-8'?><?pi content?><root xmlns='namespace'><prefix:child xmlns:prefix='namespace2' prefix:attr='value'>content</prefix:child></root>" + ; + + private XMLReader xmlReader; + + @Before + public void createXMLReader() throws Exception { + xmlReader = XMLReaderFactory.createXMLReader(); + } + + @Test + public void contentHandler() throws Exception { + StringWriter stringWriter = new StringWriter(); + AbstractStaxContentHandler handler = createStaxContentHandler(stringWriter); + xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", false); + xmlReader.setContentHandler(handler); + xmlReader.parse(new InputSource(new StringReader(XML_CONTENT_HANDLER))); + assertXMLEqual("Invalid result", XML_CONTENT_HANDLER, stringWriter.toString()); + } + + @Test + public void contentHandlerNamespacePrefixes() throws Exception { + StringWriter stringWriter = new StringWriter(); + AbstractStaxContentHandler handler = createStaxContentHandler(stringWriter); + xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + xmlReader.setContentHandler(handler); + xmlReader.parse(new InputSource(new StringReader(XML_CONTENT_HANDLER))); + assertXMLEqual("Invalid result", XML_CONTENT_HANDLER, stringWriter.toString()); + } + + protected abstract AbstractStaxContentHandler createStaxContentHandler(Writer writer) throws XMLStreamException; + +} diff --git a/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxXMLReaderTestCase.java b/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxXMLReaderTestCase.java new file mode 100644 index 00000000..d28ad6e3 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/AbstractStaxXMLReaderTestCase.java @@ -0,0 +1,267 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXSource; + +import static org.junit.Assert.assertEquals; +import org.junit.Before; +import org.junit.Test; +import static org.mockito.BDDMockito.*; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.w3c.dom.Node; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.XMLReaderFactory; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.tests.MockitoUtils; +import org.springframework.tests.MockitoUtils.InvocationArgumentsAdapter; + +public abstract class AbstractStaxXMLReaderTestCase { + + protected static XMLInputFactory inputFactory; + + private XMLReader standardReader; + + private ContentHandler standardContentHandler; + + @Before + public void setUp() throws Exception { + inputFactory = XMLInputFactory.newInstance(); + standardReader = XMLReaderFactory.createXMLReader(); + standardContentHandler = mockContentHandler(); + standardReader.setContentHandler(standardContentHandler); + } + + @Test + public void contentHandlerNamespacesNoPrefixes() throws Exception { + standardReader.setFeature("http://xml.org/sax/features/namespaces", true); + standardReader.setFeature("http://xml.org/sax/features/namespace-prefixes", false); + standardReader.parse(new InputSource(createTestInputStream())); + + AbstractStaxXMLReader staxXmlReader = createStaxXmlReader(createTestInputStream()); + ContentHandler contentHandler = mockContentHandler(); + staxXmlReader.setFeature("http://xml.org/sax/features/namespaces", true); + staxXmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", false); + staxXmlReader.setContentHandler(contentHandler); + staxXmlReader.parse(new InputSource()); + + verifyIdenticalInvocations(standardContentHandler, contentHandler); + } + + @Test + public void contentHandlerNamespacesPrefixes() throws Exception { + standardReader.setFeature("http://xml.org/sax/features/namespaces", true); + standardReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + standardReader.parse(new InputSource(createTestInputStream())); + + AbstractStaxXMLReader staxXmlReader = createStaxXmlReader(createTestInputStream()); + ContentHandler contentHandler = mockContentHandler(); + staxXmlReader.setFeature("http://xml.org/sax/features/namespaces", true); + staxXmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + staxXmlReader.setContentHandler(contentHandler); + staxXmlReader.parse(new InputSource()); + + verifyIdenticalInvocations(standardContentHandler, contentHandler); + } + + @Test + public void contentHandlerNoNamespacesPrefixes() throws Exception { + standardReader.setFeature("http://xml.org/sax/features/namespaces", false); + standardReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + standardReader.parse(new InputSource(createTestInputStream())); + + AbstractStaxXMLReader staxXmlReader = createStaxXmlReader(createTestInputStream()); + ContentHandler contentHandler = mockContentHandler(); + staxXmlReader.setFeature("http://xml.org/sax/features/namespaces", false); + staxXmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + staxXmlReader.setContentHandler(contentHandler); + staxXmlReader.parse(new InputSource()); + + verifyIdenticalInvocations(standardContentHandler, contentHandler); + } + + @Test + public void whitespace() throws Exception { + String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><test><node1> </node1><node2> Some text </node2></test>"; + + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + + AbstractStaxXMLReader staxXmlReader = createStaxXmlReader( + new ByteArrayInputStream(xml.getBytes("UTF-8"))); + + SAXSource source = new SAXSource(staxXmlReader, new InputSource()); + DOMResult result = new DOMResult(); + + transformer.transform(source, result); + + Node node1 = result.getNode().getFirstChild().getFirstChild(); + assertEquals(" ", node1.getTextContent()); + assertEquals(" Some text ", node1.getNextSibling().getTextContent()); + } + + @Test + public void lexicalHandler() throws Exception { + Resource testLexicalHandlerXml = new ClassPathResource("testLexicalHandler.xml", getClass()); + + LexicalHandler expectedLexicalHandler = mockLexicalHandler(); + standardReader.setContentHandler(null); + standardReader.setProperty("http://xml.org/sax/properties/lexical-handler", expectedLexicalHandler); + standardReader.parse(new InputSource(testLexicalHandlerXml.getInputStream())); + inputFactory.setProperty("javax.xml.stream.isCoalescing", Boolean.FALSE); + inputFactory.setProperty("http://java.sun.com/xml/stream/properties/report-cdata-event", Boolean.TRUE); + inputFactory.setProperty("javax.xml.stream.isReplacingEntityReferences", Boolean.FALSE); + inputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", Boolean.FALSE); + + LexicalHandler actualLexicalHandler = mockLexicalHandler(); + willAnswer(new Answer<Object>() { + public Object answer(InvocationOnMock invocation) throws Throwable { + return invocation.getArguments()[0] = "element"; + } + }).given(actualLexicalHandler).startDTD(anyString(), anyString(), anyString()); + AbstractStaxXMLReader staxXmlReader = createStaxXmlReader(testLexicalHandlerXml.getInputStream()); + staxXmlReader.setProperty("http://xml.org/sax/properties/lexical-handler", actualLexicalHandler); + staxXmlReader.parse(new InputSource()); + + verifyIdenticalInvocations(expectedLexicalHandler, actualLexicalHandler); + } + + private LexicalHandler mockLexicalHandler() throws Exception { + LexicalHandler lexicalHandler = mock(LexicalHandler.class); + willAnswer(new CopyCharsAnswer()).given(lexicalHandler).comment(any(char[].class), anyInt(), anyInt()); + return lexicalHandler; + } + + private InputStream createTestInputStream() { + return getClass().getResourceAsStream("testContentHandler.xml"); + } + + protected abstract AbstractStaxXMLReader createStaxXmlReader(InputStream inputStream) throws XMLStreamException; + + protected final ContentHandler mockContentHandler() throws Exception { + ContentHandler contentHandler = mock(ContentHandler.class); + willAnswer(new CopyCharsAnswer()).given(contentHandler).characters(any(char[].class), anyInt(), anyInt()); + willAnswer(new CopyCharsAnswer()).given(contentHandler).ignorableWhitespace(any(char[].class), anyInt(), anyInt()); + willAnswer(new Answer<Object>() { + public Object answer(InvocationOnMock invocation) throws Throwable { + invocation.getArguments()[3] = new AttributesImpl((Attributes) invocation.getArguments()[3]); + return null; + } + }).given(contentHandler).startElement(anyString(), anyString(), anyString(), any(Attributes.class)); + return contentHandler; + } + + protected <T> void verifyIdenticalInvocations(T expected, T actual) { + MockitoUtils.verifySameInvocations(expected, actual, + new SkipLocatorArgumentsAdapter(), new CharArrayToStringAdapter(), new PartialAttributesAdapter()); + } + + private static class SkipLocatorArgumentsAdapter implements InvocationArgumentsAdapter { + public Object[] adaptArguments(Object[] arguments) { + for(int i=0; i<arguments.length; i++) { + if(arguments[i] instanceof Locator) { + arguments[i] = null; + } + } + return arguments; + } + } + + private static class CharArrayToStringAdapter implements InvocationArgumentsAdapter { + public Object[] adaptArguments(Object[] arguments) { + if(arguments.length == 3 && arguments[0] instanceof char[] + && arguments[1] instanceof Integer && arguments[2] instanceof Integer) { + return new Object[] {new String((char[]) arguments[0], (Integer) arguments[1], (Integer) arguments[2])}; + } + return arguments; + } + } + + private static class PartialAttributesAdapter implements InvocationArgumentsAdapter { + public Object[] adaptArguments(Object[] arguments) { + for (int i = 0; i < arguments.length; i++) { + if(arguments[i] instanceof Attributes) { + arguments[i] = new PartialAttributes((Attributes) arguments[i]); + } + }; + return arguments; + } + } + + private static class CopyCharsAnswer implements Answer<Object> { + public Object answer(InvocationOnMock invocation) throws Throwable { + char[] chars = (char[]) invocation.getArguments()[0]; + char[] copy = new char[chars.length]; + System.arraycopy(chars, 0, copy, 0, chars.length); + invocation.getArguments()[0] = copy; + return null; + } + } + + private static class PartialAttributes { + + private Attributes attributes; + + public PartialAttributes(Attributes attributes) { + this.attributes = attributes; + } + + @Override + public int hashCode() { + return 1; + } + + @Override + public boolean equals(Object obj) { + Attributes other = ((PartialAttributes) obj).attributes; + if (this.attributes.getLength() != other.getLength()) { + return false; + } + for (int i = 0; i < other.getLength(); i++) { + boolean found = false; + for (int j = 0; j < attributes.getLength(); j++) { + if (other.getURI(i).equals(attributes.getURI(j)) + && other.getQName(i).equals(attributes.getQName(j)) + && other.getType(i).equals(attributes.getType(j)) + && other.getValue(i).equals(attributes.getValue(j))) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; + } + } +} diff --git a/spring-core/src/test/java/org/springframework/util/xml/DomContentHandlerTest.java b/spring-core/src/test/java/org/springframework/util/xml/DomContentHandlerTest.java new file mode 100644 index 00000000..40ee7e6a --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/DomContentHandlerTest.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.StringReader; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import org.junit.Before; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +public class DomContentHandlerTest { + + private static final String XML_1 = + "<?xml version='1.0' encoding='UTF-8'?>" + "<?pi content?>" + "<root xmlns='namespace'>" + + "<prefix:child xmlns:prefix='namespace2' xmlns:prefix2='namespace3' prefix2:attr='value'>content</prefix:child>" + + "</root>"; + + private static final String XML_2_EXPECTED = + "<?xml version='1.0' encoding='UTF-8'?>" + "<root xmlns='namespace'>" + "<child xmlns='namespace2' />" + + "</root>"; + + private static final String XML_2_SNIPPET = + "<?xml version='1.0' encoding='UTF-8'?>" + "<child xmlns='namespace2' />"; + + private Document expected; + + private DomContentHandler handler; + + private Document result; + + private XMLReader xmlReader; + + private DocumentBuilder documentBuilder; + + @Before + public void setUp() throws Exception { + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + documentBuilder = documentBuilderFactory.newDocumentBuilder(); + result = documentBuilder.newDocument(); + xmlReader = XMLReaderFactory.createXMLReader(); + } + + @Test + public void contentHandlerDocumentNamespacePrefixes() throws Exception { + xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true); + handler = new DomContentHandler(result); + expected = documentBuilder.parse(new InputSource(new StringReader(XML_1))); + xmlReader.setContentHandler(handler); + xmlReader.parse(new InputSource(new StringReader(XML_1))); + assertXMLEqual("Invalid result", expected, result); + } + + @Test + public void contentHandlerDocumentNoNamespacePrefixes() throws Exception { + handler = new DomContentHandler(result); + expected = documentBuilder.parse(new InputSource(new StringReader(XML_1))); + xmlReader.setContentHandler(handler); + xmlReader.parse(new InputSource(new StringReader(XML_1))); + assertXMLEqual("Invalid result", expected, result); + } + + @Test + public void contentHandlerElement() throws Exception { + Element rootElement = result.createElementNS("namespace", "root"); + result.appendChild(rootElement); + handler = new DomContentHandler(rootElement); + expected = documentBuilder.parse(new InputSource(new StringReader(XML_2_EXPECTED))); + xmlReader.setContentHandler(handler); + xmlReader.parse(new InputSource(new StringReader(XML_2_SNIPPET))); + assertXMLEqual("Invalid result", expected, result); + + } +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/util/xml/SimpleNamespaceContextTests.java b/spring-core/src/test/java/org/springframework/util/xml/SimpleNamespaceContextTests.java new file mode 100644 index 00000000..64f7de88 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/SimpleNamespaceContextTests.java @@ -0,0 +1,121 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.util.Collections; +import java.util.Iterator; +import javax.xml.XMLConstants; + +import static org.junit.Assert.*; +import org.junit.Before; +import org.junit.Test; + +public class SimpleNamespaceContextTests { + + private SimpleNamespaceContext context; + + @Before + public void createContext() throws Exception { + context = new SimpleNamespaceContext(); + context.bindNamespaceUri("prefix", "namespaceURI"); + } + + @Test + public void getNamespaceURI() { + assertEquals("Invalid namespaceURI for default namespace", "", + context.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX)); + String defaultNamespaceUri = "defaultNamespace"; + context.bindNamespaceUri(XMLConstants.DEFAULT_NS_PREFIX, defaultNamespaceUri); + assertEquals("Invalid namespaceURI for default namespace", defaultNamespaceUri, + context.getNamespaceURI(XMLConstants.DEFAULT_NS_PREFIX)); + assertEquals("Invalid namespaceURI for bound prefix", "namespaceURI", context.getNamespaceURI("prefix")); + assertEquals("Invalid namespaceURI for unbound prefix", "", context.getNamespaceURI("unbound")); + assertEquals("Invalid namespaceURI for namespace prefix", XMLConstants.XML_NS_URI, + context.getNamespaceURI(XMLConstants.XML_NS_PREFIX)); + assertEquals("Invalid namespaceURI for attribute prefix", XMLConstants.XMLNS_ATTRIBUTE_NS_URI, + context.getNamespaceURI(XMLConstants.XMLNS_ATTRIBUTE)); + + } + + @Test + public void getPrefix() { + assertEquals("Invalid prefix for default namespace", XMLConstants.DEFAULT_NS_PREFIX, context.getPrefix("")); + assertEquals("Invalid prefix for bound namespace", "prefix", context.getPrefix("namespaceURI")); + assertNull("Invalid prefix for unbound namespace", context.getPrefix("unbound")); + assertEquals("Invalid prefix for namespace", XMLConstants.XML_NS_PREFIX, + context.getPrefix(XMLConstants.XML_NS_URI)); + assertEquals("Invalid prefix for attribute namespace", XMLConstants.XMLNS_ATTRIBUTE, + context.getPrefix(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)); + } + + @Test + public void getPrefixes() { + assertPrefixes("", XMLConstants.DEFAULT_NS_PREFIX); + assertPrefixes("namespaceURI", "prefix"); + assertFalse("Invalid prefix for unbound namespace", context.getPrefixes("unbound").hasNext()); + assertPrefixes(XMLConstants.XML_NS_URI, XMLConstants.XML_NS_PREFIX); + assertPrefixes(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE); + } + + @Test + public void multiplePrefixes() { + context.bindNamespaceUri("prefix1", "namespace"); + context.bindNamespaceUri("prefix2", "namespace"); + Iterator iterator = context.getPrefixes("namespace"); + assertNotNull("getPrefixes returns null", iterator); + assertTrue("iterator is empty", iterator.hasNext()); + String result = (String) iterator.next(); + assertTrue("Invalid prefix", result.equals("prefix1") || result.equals("prefix2")); + assertTrue("iterator is empty", iterator.hasNext()); + result = (String) iterator.next(); + assertTrue("Invalid prefix", result.equals("prefix1") || result.equals("prefix2")); + assertFalse("iterator contains more than two values", iterator.hasNext()); + } + + private void assertPrefixes(String namespaceUri, String prefix) { + Iterator iterator = context.getPrefixes(namespaceUri); + assertNotNull("getPrefixes returns null", iterator); + assertTrue("iterator is empty", iterator.hasNext()); + String result = (String) iterator.next(); + assertEquals("Invalid prefix", prefix, result); + assertFalse("iterator contains multiple values", iterator.hasNext()); + } + + @Test + public void getBoundPrefixes() throws Exception { + Iterator iterator = context.getBoundPrefixes(); + assertNotNull("getPrefixes returns null", iterator); + assertTrue("iterator is empty", iterator.hasNext()); + String result = (String) iterator.next(); + assertEquals("Invalid prefix", "prefix", result); + assertFalse("iterator contains multiple values", iterator.hasNext()); + } + + @Test + public void setBindings() throws Exception { + context.setBindings(Collections.singletonMap("prefix", "namespace")); + assertEquals("Invalid namespace uri", "namespace", context.getNamespaceURI("prefix")); + } + + @Test + public void removeBinding() throws Exception { + context.removeBinding("prefix"); + assertNull("Invalid prefix for unbound namespace", context.getPrefix("prefix")); + + + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/xml/StaxEventContentHandlerTests.java b/spring-core/src/test/java/org/springframework/util/xml/StaxEventContentHandlerTests.java new file mode 100644 index 00000000..da1657b8 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/StaxEventContentHandlerTests.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.Writer; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; + +public class StaxEventContentHandlerTests extends AbstractStaxContentHandlerTestCase { + + @Override + protected AbstractStaxContentHandler createStaxContentHandler(Writer writer) throws XMLStreamException { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + return new StaxEventContentHandler(outputFactory.createXMLEventWriter(writer)); + } +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/util/xml/StaxEventXMLReaderTests.java b/spring-core/src/test/java/org/springframework/util/xml/StaxEventXMLReaderTests.java new file mode 100644 index 00000000..355cb944 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/StaxEventXMLReaderTests.java @@ -0,0 +1,55 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.InputStream; +import java.io.StringReader; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; + +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.helpers.AttributesImpl; + +import static org.mockito.BDDMockito.*; + +public class StaxEventXMLReaderTests extends AbstractStaxXMLReaderTestCase { + + public static final String CONTENT = "<root xmlns='http://springframework.org/spring-ws'><child/></root>"; + + @Override + protected AbstractStaxXMLReader createStaxXmlReader(InputStream inputStream) throws XMLStreamException { + return new StaxEventXMLReader(inputFactory.createXMLEventReader(inputStream)); + } + + public void testPartial() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(CONTENT)); + eventReader.nextTag(); // skip to root + StaxEventXMLReader xmlReader = new StaxEventXMLReader(eventReader); + ContentHandler contentHandler = mock(ContentHandler.class); + xmlReader.setContentHandler(contentHandler); + xmlReader.parse(new InputSource()); + verify(contentHandler).startDocument(); + verify(contentHandler).startElement("http://springframework.org/spring-ws", "child", "child", new AttributesImpl()); + verify(contentHandler).endElement("http://springframework.org/spring-ws", "child", "child"); + verify(contentHandler).endDocument(); + } +} + diff --git a/spring-core/src/test/java/org/springframework/util/xml/StaxResultTests.java b/spring-core/src/test/java/org/springframework/util/xml/StaxResultTests.java new file mode 100644 index 00000000..ecd6a26e --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/StaxResultTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import org.junit.Before; +import org.junit.Test; + +public class StaxResultTests { + + private static final String XML = "<root xmlns='namespace'><child/></root>"; + + private Transformer transformer; + + private XMLOutputFactory inputFactory; + + @Before + public void setUp() throws Exception { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformer = transformerFactory.newTransformer(); + inputFactory = XMLOutputFactory.newInstance(); + } + + @Test + public void streamWriterSource() throws Exception { + StringWriter stringWriter = new StringWriter(); + XMLStreamWriter streamWriter = inputFactory.createXMLStreamWriter(stringWriter); + Reader reader = new StringReader(XML); + Source source = new StreamSource(reader); + StaxResult result = new StaxResult(streamWriter); + assertEquals("Invalid streamWriter returned", streamWriter, result.getXMLStreamWriter()); + assertNull("EventWriter returned", result.getXMLEventWriter()); + transformer.transform(source, result); + assertXMLEqual("Invalid result", XML, stringWriter.toString()); + } + + @Test + public void eventWriterSource() throws Exception { + StringWriter stringWriter = new StringWriter(); + XMLEventWriter eventWriter = inputFactory.createXMLEventWriter(stringWriter); + Reader reader = new StringReader(XML); + Source source = new StreamSource(reader); + StaxResult result = new StaxResult(eventWriter); + assertEquals("Invalid eventWriter returned", eventWriter, result.getXMLEventWriter()); + assertNull("StreamWriter returned", result.getXMLStreamWriter()); + transformer.transform(source, result); + assertXMLEqual("Invalid result", XML, stringWriter.toString()); + } + +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/util/xml/StaxSourceTests.java b/spring-core/src/test/java/org/springframework/util/xml/StaxSourceTests.java new file mode 100644 index 00000000..638b997b --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/StaxSourceTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util.xml; + +import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.io.StringReader; +import java.io.StringWriter; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.stream.StreamResult; + +import org.junit.Before; +import org.junit.Test; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; + +public class StaxSourceTests { + + private static final String XML = "<root xmlns='namespace'><child/></root>"; + + private Transformer transformer; + + private XMLInputFactory inputFactory; + + private DocumentBuilder documentBuilder; + + @Before + public void setUp() throws Exception { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformer = transformerFactory.newTransformer(); + inputFactory = XMLInputFactory.newInstance(); + DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + documentBuilder = documentBuilderFactory.newDocumentBuilder(); + } + + @Test + public void streamReaderSourceToStreamResult() throws Exception { + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(XML)); + StaxSource source = new StaxSource(streamReader); + assertEquals("Invalid streamReader returned", streamReader, source.getXMLStreamReader()); + assertNull("EventReader returned", source.getXMLEventReader()); + StringWriter writer = new StringWriter(); + transformer.transform(source, new StreamResult(writer)); + assertXMLEqual("Invalid result", XML, writer.toString()); + } + + @Test + public void streamReaderSourceToDOMResult() throws Exception { + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(XML)); + StaxSource source = new StaxSource(streamReader); + assertEquals("Invalid streamReader returned", streamReader, source.getXMLStreamReader()); + assertNull("EventReader returned", source.getXMLEventReader()); + + Document expected = documentBuilder.parse(new InputSource(new StringReader(XML))); + Document result = documentBuilder.newDocument(); + transformer.transform(source, new DOMResult(result)); + assertXMLEqual("Invalid result", expected, result); + } + + @Test + public void eventReaderSourceToStreamResult() throws Exception { + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(XML)); + StaxSource source = new StaxSource(eventReader); + assertEquals("Invalid eventReader returned", eventReader, source.getXMLEventReader()); + assertNull("StreamReader returned", source.getXMLStreamReader()); + StringWriter writer = new StringWriter(); + transformer.transform(source, new StreamResult(writer)); + assertXMLEqual("Invalid result", XML, writer.toString()); + } + + @Test + public void eventReaderSourceToDOMResult() throws Exception { + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(XML)); + StaxSource source = new StaxSource(eventReader); + assertEquals("Invalid eventReader returned", eventReader, source.getXMLEventReader()); + assertNull("StreamReader returned", source.getXMLStreamReader()); + + Document expected = documentBuilder.parse(new InputSource(new StringReader(XML))); + Document result = documentBuilder.newDocument(); + transformer.transform(source, new DOMResult(result)); + assertXMLEqual("Invalid result", expected, result); + } +} diff --git a/spring-core/src/test/java/org/springframework/util/xml/StaxStreamContentHandlerTests.java b/spring-core/src/test/java/org/springframework/util/xml/StaxStreamContentHandlerTests.java new file mode 100644 index 00000000..f39f0bff --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/StaxStreamContentHandlerTests.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.Writer; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; + +public class StaxStreamContentHandlerTests extends AbstractStaxContentHandlerTestCase { + + @Override + protected AbstractStaxContentHandler createStaxContentHandler(Writer writer) throws XMLStreamException { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + return new StaxStreamContentHandler(outputFactory.createXMLStreamWriter(writer)); + } +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/util/xml/StaxStreamXMLReaderTests.java b/spring-core/src/test/java/org/springframework/util/xml/StaxStreamXMLReaderTests.java new file mode 100644 index 00000000..e074085f --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/StaxStreamXMLReaderTests.java @@ -0,0 +1,69 @@ +/* + * Copyright 2002-2013 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.InputStream; +import java.io.StringReader; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.junit.Test; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.*; +import static org.mockito.BDDMockito.*; + +public class StaxStreamXMLReaderTests extends AbstractStaxXMLReaderTestCase { + + public static final String CONTENT = "<root xmlns='http://springframework.org/spring-ws'><child/></root>"; + + @Override + protected AbstractStaxXMLReader createStaxXmlReader(InputStream inputStream) throws XMLStreamException { + return new StaxStreamXMLReader(inputFactory.createXMLStreamReader(inputStream)); + } + + @Test + public void testPartial() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(CONTENT)); + streamReader.nextTag(); // skip to root + assertEquals("Invalid element", new QName("http://springframework.org/spring-ws", "root"), + streamReader.getName()); + streamReader.nextTag(); // skip to child + assertEquals("Invalid element", new QName("http://springframework.org/spring-ws", "child"), + streamReader.getName()); + StaxStreamXMLReader xmlReader = new StaxStreamXMLReader(streamReader); + + ContentHandler contentHandler = mock(ContentHandler.class); + xmlReader.setContentHandler(contentHandler); + xmlReader.parse(new InputSource()); + + verify(contentHandler).setDocumentLocator(any(Locator.class)); + verify(contentHandler).startDocument(); + verify(contentHandler).startElement(eq("http://springframework.org/spring-ws"), eq("child"), eq("child"), any(Attributes.class)); + verify(contentHandler).endElement("http://springframework.org/spring-ws", "child", "child"); + verify(contentHandler).endDocument(); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/xml/StaxUtilsTest.java b/spring-core/src/test/java/org/springframework/util/xml/StaxUtilsTest.java new file mode 100644 index 00000000..abe11528 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/StaxUtilsTest.java @@ -0,0 +1,93 @@ +/* + * Copyright 2002-2010 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.StringReader; +import java.io.StringWriter; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXResult; +import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import static org.junit.Assert.*; +import org.junit.Test; + +public class StaxUtilsTest { + + @Test + public void isStaxSourceInvalid() throws Exception { + assertFalse("A StAX Source", StaxUtils.isStaxSource(new DOMSource())); + assertFalse("A StAX Source", StaxUtils.isStaxSource(new SAXSource())); + assertFalse("A StAX Source", StaxUtils.isStaxSource(new StreamSource())); + } + + @Test + public void isStaxSource() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + String expected = "<element/>"; + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(expected)); + Source source = StaxUtils.createCustomStaxSource(streamReader); + + assertTrue("Not a StAX Source", StaxUtils.isStaxSource(source)); + } + + @Test + public void isStaxSourceJaxp14() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + String expected = "<element/>"; + XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new StringReader(expected)); + StAXSource source = new StAXSource(streamReader); + + assertTrue("Not a StAX Source", StaxUtils.isStaxSource(source)); + } + + @Test + public void isStaxResultInvalid() throws Exception { + assertFalse("A StAX Result", StaxUtils.isStaxResult(new DOMResult())); + assertFalse("A StAX Result", StaxUtils.isStaxResult(new SAXResult())); + assertFalse("A StAX Result", StaxUtils.isStaxResult(new StreamResult())); + } + + @Test + public void isStaxResult() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(new StringWriter()); + Result result = StaxUtils.createCustomStaxResult(streamWriter); + + assertTrue("Not a StAX Result", StaxUtils.isStaxResult(result)); + } + + @Test + public void isStaxResultJaxp14() throws Exception { + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + XMLStreamWriter streamWriter = outputFactory.createXMLStreamWriter(new StringWriter()); + StAXResult result = new StAXResult(streamWriter); + + assertTrue("Not a StAX Result", StaxUtils.isStaxResult(result)); + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/xml/TransformerUtilsTests.java b/spring-core/src/test/java/org/springframework/util/xml/TransformerUtilsTests.java new file mode 100644 index 00000000..21eb30b7 --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/TransformerUtilsTests.java @@ -0,0 +1,157 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.util.Properties; +import javax.xml.transform.ErrorListener; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import org.junit.Test; + +/** + * @author Rick Evans + * @author Arjen Poutsma + */ +public class TransformerUtilsTests { + + @Test + public void enableIndentingSunnyDay() throws Exception { + Transformer transformer = new StubTransformer(); + TransformerUtils.enableIndenting(transformer); + String indent = transformer.getOutputProperty(OutputKeys.INDENT); + assertNotNull(indent); + assertEquals("yes", indent); + String indentAmount = transformer.getOutputProperty("{http://xml.apache.org/xslt}indent-amount"); + assertNotNull(indentAmount); + assertEquals(String.valueOf(TransformerUtils.DEFAULT_INDENT_AMOUNT), indentAmount); + } + + @Test + public void enableIndentingSunnyDayWithCustomKosherIndentAmount() throws Exception { + final String indentAmountProperty = "10"; + Transformer transformer = new StubTransformer(); + TransformerUtils.enableIndenting(transformer, Integer.valueOf(indentAmountProperty)); + String indent = transformer.getOutputProperty(OutputKeys.INDENT); + assertNotNull(indent); + assertEquals("yes", indent); + String indentAmount = transformer.getOutputProperty("{http://xml.apache.org/xslt}indent-amount"); + assertNotNull(indentAmount); + assertEquals(indentAmountProperty, indentAmount); + } + + @Test + public void disableIndentingSunnyDay() throws Exception { + Transformer transformer = new StubTransformer(); + TransformerUtils.disableIndenting(transformer); + String indent = transformer.getOutputProperty(OutputKeys.INDENT); + assertNotNull(indent); + assertEquals("no", indent); + } + + @Test(expected = IllegalArgumentException.class) + public void enableIndentingWithNullTransformer() throws Exception { + TransformerUtils.enableIndenting(null); + } + + @Test(expected = IllegalArgumentException.class) + public void disableIndentingWithNullTransformer() throws Exception { + TransformerUtils.disableIndenting(null); + } + + @Test(expected = IllegalArgumentException.class) + public void enableIndentingWithNegativeIndentAmount() throws Exception { + TransformerUtils.enableIndenting(new StubTransformer(), -21938); + } + + @Test + public void enableIndentingWithZeroIndentAmount() throws Exception { + TransformerUtils.enableIndenting(new StubTransformer(), 0); + } + + private static class StubTransformer extends Transformer { + + private Properties outputProperties = new Properties(); + + @Override + public void transform(Source xmlSource, Result outputTarget) throws TransformerException { + throw new UnsupportedOperationException(); + } + + @Override + public void setParameter(String name, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public Object getParameter(String name) { + throw new UnsupportedOperationException(); + } + + @Override + public void clearParameters() { + throw new UnsupportedOperationException(); + } + + @Override + public void setURIResolver(URIResolver resolver) { + throw new UnsupportedOperationException(); + } + + @Override + public URIResolver getURIResolver() { + throw new UnsupportedOperationException(); + } + + @Override + public void setOutputProperties(Properties oformat) { + throw new UnsupportedOperationException(); + } + + @Override + public Properties getOutputProperties() { + return this.outputProperties; + } + + @Override + public void setOutputProperty(String name, String value) throws IllegalArgumentException { + this.outputProperties.setProperty(name, value); + } + + @Override + public String getOutputProperty(String name) throws IllegalArgumentException { + return this.outputProperties.getProperty(name); + } + + @Override + public void setErrorListener(ErrorListener listener) throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } + + @Override + public ErrorListener getErrorListener() { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamReaderTests.java b/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamReaderTests.java new file mode 100644 index 00000000..6e752b9d --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamReaderTests.java @@ -0,0 +1,63 @@ +/* + * Copyright 2002-2011 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.StringReader; +import java.io.StringWriter; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; + +import org.junit.Before; +import org.junit.Test; + +import static org.custommonkey.xmlunit.XMLAssert.*; + +public class XMLEventStreamReaderTests { + + private static final String XML = + "<?pi content?><root xmlns='namespace'><prefix:child xmlns:prefix='namespace2'>content</prefix:child></root>" + ; + + private XMLEventStreamReader streamReader; + + @Before + public void createStreamReader() throws Exception { + XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + XMLEventReader eventReader = inputFactory.createXMLEventReader(new StringReader(XML)); + streamReader = new XMLEventStreamReader(eventReader); + } + + @Test + public void readAll() throws Exception { + while (streamReader.hasNext()) { + streamReader.next(); + } + } + + @Test + public void readCorrect() throws Exception { + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + StaxSource source = new StaxSource(streamReader); + StringWriter writer = new StringWriter(); + transformer.transform(source, new StreamResult(writer)); + assertXMLEqual(XML, writer.toString()); + } + +}
\ No newline at end of file diff --git a/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamWriterTests.java b/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamWriterTests.java new file mode 100644 index 00000000..00fb47bd --- /dev/null +++ b/spring-core/src/test/java/org/springframework/util/xml/XMLEventStreamWriterTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * 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 org.springframework.util.xml; + +import java.io.StringWriter; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; + +import org.junit.Before; +import org.junit.Test; + +import static org.custommonkey.xmlunit.XMLAssert.*; + +public class XMLEventStreamWriterTests { + + private static final String XML = + "<?pi content?><root xmlns='namespace'><prefix:child xmlns:prefix='namespace2'><!--comment-->content</prefix:child></root>"; + + private XMLEventStreamWriter streamWriter; + + private StringWriter stringWriter; + + @Before + public void createStreamReader() throws Exception { + stringWriter = new StringWriter(); + XMLOutputFactory outputFactory = XMLOutputFactory.newInstance(); + XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(stringWriter); + streamWriter = new XMLEventStreamWriter(eventWriter, XMLEventFactory.newInstance()); + } + + @Test + public void write() throws Exception { + streamWriter.writeStartDocument(); + streamWriter.writeProcessingInstruction("pi", "content"); + streamWriter.writeStartElement("namespace", "root"); + streamWriter.writeDefaultNamespace("namespace"); + streamWriter.writeStartElement("prefix", "child", "namespace2"); + streamWriter.writeNamespace("prefix", "namespace2"); + streamWriter.writeComment("comment"); + streamWriter.writeCharacters("content"); + streamWriter.writeEndElement(); + streamWriter.writeEndElement(); + streamWriter.writeEndDocument(); + + assertXMLEqual(XML, stringWriter.toString()); + } + + +} |