| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.sling.api.wrappers.impl; |
| |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNull; |
| |
| import java.lang.reflect.Array; |
| import java.util.Calendar; |
| import java.util.Date; |
| |
| import org.apache.commons.lang3.ClassUtils; |
| |
| /** |
| * Tests all permutations of object conversions between single values and array types, and null handling. |
| */ |
| final class Convert { |
| |
| private Convert() { |
| // static methods only |
| } |
| |
| @SuppressWarnings("unchecked") |
| public static class ConversionAssert<T,U> { |
| private final T input1; |
| private final T input2; |
| private Class<T> inputType; |
| private U expected1; |
| private U expected2; |
| private U nullValue; |
| private Class<U> expectedType; |
| |
| private ConversionAssert(T input1, T input2, boolean inputTypePrimitive) { |
| this.input1 = input1; |
| this.input2 = input2; |
| this.inputType = (Class<T>)input1.getClass(); |
| if (inputTypePrimitive) { |
| this.inputType = (Class<T>)ClassUtils.wrapperToPrimitive(this.inputType); |
| } |
| } |
| |
| private void expected(U expected1, U expected2, boolean expectedTypePrimitive) { |
| this.expected1 = expected1; |
| this.expected2 = expected2; |
| this.expectedType = (Class<U>)expected1.getClass(); |
| if (expectedTypePrimitive) { |
| expectedType = (Class<U>)ClassUtils.wrapperToPrimitive(this.expectedType); |
| } |
| } |
| |
| /** |
| * @param expected1 Singleton or first array expected result value |
| * @param expected2 Second array expected result value |
| * @return this |
| */ |
| public ConversionAssert<T,U> to(U expected1, U expected2) { |
| expected(expected1, expected2, false); |
| return this; |
| } |
| |
| /** |
| * @param expected1 Singleton or first array expected result value |
| * @param expected2 Second array expected result value |
| * @return this |
| */ |
| public ConversionAssert<T,U> toPrimitive(U expected1, U expected2) { |
| expected(expected1, expected2, true); |
| return this; |
| } |
| |
| /** |
| * @param expected1 Singleton or first array expected result value |
| * @param expected2 Second array expected result value |
| * @return this |
| */ |
| public ConversionAssert<T,U> toNull(Class<U> expectedType) { |
| expected1 = null; |
| expected2 = null; |
| this.expectedType = expectedType; |
| return this; |
| } |
| |
| /** |
| * @param nullValue Result value in case of null |
| */ |
| public ConversionAssert<T,U> nullValue(U nullValue) { |
| this.nullValue = nullValue; |
| return this; |
| } |
| |
| /** |
| * Do assertion |
| */ |
| public void test() { |
| Class<U[]> expectedArrayType = (Class<U[]>)Array.newInstance(this.expectedType, 0).getClass(); |
| assertPermuations(input1, input2, inputType, expected1, expected2, nullValue, expectedType, expectedArrayType); |
| } |
| } |
| |
| /** |
| * @param input1 Singleton or first array input value |
| * @param input2 Second array input value |
| */ |
| public static <T,U> ConversionAssert<T,U> from(T input1, T input2) { |
| return new ConversionAssert<T,U>(input1, input2, false); |
| } |
| |
| /** |
| * @param input1 Singleton or first array input value |
| * @param input2 Second array input value |
| */ |
| public static <T,U> ConversionAssert<T,U> fromPrimitive(T input1, T input2) { |
| return new ConversionAssert<T,U>(input1, input2, true); |
| } |
| |
| private static <T,U> void assertPermuations(T input1, T input2, Class<T> inputType, |
| U expected1, U expected2, U nullValue, Class<U> expectedType, Class<U[]> expectedArrayType) { |
| |
| // single value to single value |
| assertConversion(expected1, input1, expectedType); |
| |
| // single value to array |
| Object expectedSingletonArray; |
| if (expected1 == null && expected2 == null) { |
| expectedSingletonArray = null; |
| } |
| else { |
| expectedSingletonArray = Array.newInstance(expectedType, 1); |
| Array.set(expectedSingletonArray, 0, expected1); |
| } |
| assertConversion(expectedSingletonArray, input1, expectedArrayType); |
| |
| // array to array |
| Object inputDoubleArray = Array.newInstance(inputType, 2); |
| Array.set(inputDoubleArray, 0, input1); |
| Array.set(inputDoubleArray, 1, input2); |
| Object expectedDoubleArray; |
| if (expected1 == null && expected2 == null) { |
| expectedDoubleArray = null; |
| } |
| else { |
| expectedDoubleArray = Array.newInstance(expectedType, 2); |
| Array.set(expectedDoubleArray, 0, expected1); |
| Array.set(expectedDoubleArray, 1, expected2); |
| } |
| assertConversion(expectedDoubleArray, inputDoubleArray, expectedArrayType); |
| |
| // array to single (first) value |
| assertConversion(expected1, inputDoubleArray, expectedType); |
| |
| // null to single value |
| assertConversion(nullValue, null, expectedType); |
| |
| // null to array |
| // assertConversion(null, null, expectedArrayType); |
| |
| // empty array to single value |
| Object inputEmptyArray = Array.newInstance(inputType, 0); |
| assertConversion(nullValue, inputEmptyArray, expectedType); |
| |
| // empty array to array |
| Object expectedEmptyArray = Array.newInstance(expectedType, 0); |
| assertConversion(expectedEmptyArray, inputEmptyArray, expectedArrayType); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static <T,U> void assertConversion(Object expected, Object input, Class<U> type) { |
| U result = ObjectConverter.convert(input, type); |
| String msg = "Convert '" + toString(input) + "' to " + type.getSimpleName(); |
| if (expected == null) { |
| assertNull(msg, result); |
| } |
| else if (expected.getClass().isArray()) { |
| assertArrayEquals(msg, (U[])toStringIfDate(expected), (U[])toStringIfDate(result)); |
| } |
| else { |
| assertEquals(msg, toStringIfDate(expected), toStringIfDate(result)); |
| } |
| } |
| |
| private static String toString(Object input) { |
| if (input == null) { |
| return "null"; |
| } |
| else if (input.getClass().isArray()) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("["); |
| for (int i=0; i<Array.getLength(input); i++) { |
| if (i > 0) { |
| sb.append(","); |
| } |
| sb.append(toString(Array.get(input, i))); |
| } |
| sb.append("]"); |
| return sb.toString(); |
| } |
| else { |
| return toStringIfDate(input).toString(); |
| } |
| } |
| |
| private static Object toStringIfDate(Object input) { |
| if (input == null) { |
| return null; |
| } |
| if (input instanceof Calendar) { |
| return "(Calendar)" + ((Calendar)input).getTime().toInstant().toString(); |
| } |
| if (input instanceof Date) { |
| return "(Date)" + ((Date)input).toInstant().toString(); |
| } |
| if (input.getClass().isArray()) { |
| if (Calendar.class.isAssignableFrom(input.getClass().getComponentType()) |
| || input.getClass().getComponentType() == Date.class) { |
| Object[] resultArray = new String[Array.getLength(input)]; |
| for (int i=0; i<Array.getLength(input); i++) { |
| resultArray[i] = toStringIfDate(Array.get(input, i)); |
| } |
| return resultArray; |
| } |
| } |
| return input; |
| } |
| |
| } |