/*
 * 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.webbeans.test.util;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

import org.apache.webbeans.util.GenericsUtil;
import org.junit.Assert;
import org.junit.Test;

public class GenericsUtilTest {

    @Test
    public void resolveType() throws NoSuchFieldException {
        Field field = AbstractObject.class.getDeclaredField("field");
        Assert.assertEquals(Object.class, GenericsUtil.resolveType(SimpleObject.class, field));
        assertEquals(String.class, GenericsUtil.resolveType(StringObject.class, field));

        Type t = GenericsUtil.resolveType(GenericObject.class, field);
        assertTrue(t instanceof TypeVariable);
        assertEquals("T", ((TypeVariable<?>)t).getName());

        Type number = GenericsUtil.resolveType(GenericNumberObject.class, field);
        assertTrue(number instanceof TypeVariable);
		assertEquals(Number.class, GenericsUtil.getRawType(number));

        assertEquals(Integer.class, GenericsUtil.resolveType(IntegerObject.class, field));
        GenericArrayType genericArrayType = (GenericArrayType)GenericsUtil.resolveType(GenericArrayObject.class, field);
        assertTrue(genericArrayType.getGenericComponentType() instanceof TypeVariable);
        assertEquals("V", ((TypeVariable)genericArrayType.getGenericComponentType()).getName());
        assertEquals(Object[].class, GenericsUtil.getRawType(genericArrayType));
        assertEquals(Long[].class, GenericsUtil.resolveType(LongArrayObject.class, field));
        
        Type subInterfaceType = GenericsUtil.resolveType(InterfaceObject.class, field);
        assertTrue(subInterfaceType instanceof TypeVariable);
        assertEquals(SubInterface.class, GenericsUtil.getRawType(subInterfaceType));
    }

    @Test
    public void testContainsWildcardTypes() throws Exception
    {
        Assert.assertFalse(GenericsUtil.containsWildcardType(StringObject.class));
        Assert.assertTrue(GenericsUtil.containsWildcardType(GenericNumberObject.class.getMethod("getObject").getGenericReturnType()));
        Assert.assertFalse(GenericsUtil.containsWildcardType(GenericObject.class.getMethod("getObject").getGenericReturnType()));
    }


    public static abstract class AbstractObject<V> {
    
        private V field;
    }

    private static class SimpleObject extends AbstractObject {

    }

    private static class StringObject extends AbstractObject<String> {

    }

    private static class GenericObject<T, V> extends AbstractObject<T> {

        public GenericObject<T, V> getObject()
        {
            return new GenericObject<T, V>();
        }

    }

    private static class GenericNumberObject<X, Y extends Number & Comparable<Integer>> extends AbstractObject<Y> {

        public GenericNumberObject<?, ? extends Comparable<Integer>> getObject()
        {
            return new GenericNumberObject<X, Integer>();
        }
    }

    private static class IntegerObject extends GenericNumberObject<String, Integer> {

    }

    private static class GenericArrayObject<V> extends GenericObject<V[], V> {

    }

    private static class LongArrayObject extends GenericArrayObject<Long> {

    }

    private static class InterfaceObject<V extends SubInterface & SuperInterface> extends AbstractObject<V> {

    }

    private interface SuperInterface {

    }

    private interface SubInterface extends SuperInterface {

    }
}

@@ -1068,16 +1068,38 @@
 ariable;
+%0Aimport java.util.Set;
 %0A%0Aimport
@@ -1862,10 +1862,16 @@
 e);%0A
-%09%09
+        
 asse
@@ -2737,24 +2737,248 @@
 rfaceType));
+%0A%0A        assertEquals(JustAPlainClass.class, GenericsUtil.getRawType(JustAPlainClass.class));%0A%0A        Set%3CType%3E typeClosure = GenericsUtil.getTypeClosure(JustAPlainClass.class);%0A        assertEquals(2, typeClosure.size());
 %0A    %7D%0A%0A    
@@ -3456,16 +3456,20 @@
 bject%3CV%3E
+%0A   
  %7B%0A    %0A
@@ -3560,16 +3560,20 @@
 ctObject
+%0A   
  %7B%0A%0A    
@@ -3643,16 +3643,20 @@
 %3CString%3E
+%0A   
  %7B%0A%0A    
@@ -3728,16 +3728,20 @@
 bject%3CT%3E
+%0A   
  %7B%0A%0A    
@@ -3970,16 +3970,20 @@
 bject%3CY%3E
+%0A   
  %7B%0A%0A    
@@ -4227,16 +4227,20 @@
 Integer%3E
+%0A   
  %7B%0A%0A    
@@ -4318,16 +4318,20 @@
 %3CV%5B%5D, V%3E
+%0A   
  %7B%0A%0A    
@@ -4406,16 +4406,20 @@
 ct%3CLong%3E
+%0A   
  %7B%0A%0A    
@@ -4528,16 +4528,20 @@
 bject%3CV%3E
+%0A   
  %7B%0A%0A    
@@ -4571,32 +4571,36 @@
 e SuperInterface
+%0A   
  %7B%0A%0A    %7D%0A%0A    p
@@ -4651,16 +4651,75 @@
 nterface
+%0A    %7B%0A%0A    %7D%0A%0A    private static class JustAPlainClass%0A   
  %7B%0A%0A    

improve GenericsUtilTest