/*
 * 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.tamaya;

import java.lang.reflect.Type;
import static org.apache.tamaya.TypeLiteral.getGenericInterfaceTypeParameters;
import static org.apache.tamaya.TypeLiteral.getTypeParameters;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.junit.Test;

/**
 * Tests for the {@link TypeLiteral} class.
 */
@SuppressWarnings("serial")
public class TypeLiteralTest {

    @Test(expected = NullPointerException.class)
    public void constructorRequiresNonNullParameter() {
        new TypeLiteral<List<String>>(null) { };
    }

    @Test
    public void test_constructor() {
        TypeLiteral<List<String>> listTypeLiteral = new TypeLiteral<List<String>>() { };
        assertThat(listTypeLiteral.getRawType()).isEqualTo(List.class);
        assertThat(TypeLiteral.getTypeParameters(listTypeLiteral.getType())[0]).isEqualTo(String.class);
    }

    @Test
    public void test_of() {
        class MyListClass extends ArrayList<String> { }
        TypeLiteral<MyListClass> listTypeLiteral = TypeLiteral.of(MyListClass.class);
        assertThat(listTypeLiteral.getRawType()).isEqualTo(MyListClass.class);
        assertThat(listTypeLiteral.getType()).isEqualTo(MyListClass.class);
    }

    @Test(expected = NullPointerException.class)
    public void ofDoesNotAcceptNullAsParamter() {
        TypeLiteral.of(null);
    }

    @Test
    public void test_getTypeParameters() {
        TypeLiteral<List<String>> listTypeLiteral = new TypeLiteral<List<String>>() { };
        assertThat(listTypeLiteral.getRawType()).isEqualTo(List.class);
        assertThat(TypeLiteral.getTypeParameters(listTypeLiteral.getType())[0]).isEqualTo(String.class);
    }

    @Test
    public void testGetTypeParametersNoGenerics() {
        assertThat(getTypeParameters(String.class).length).isEqualTo(0);
    }

    @Test
    public void test_getGenericInterfaceTypeParameter() {
        class MyListClass extends ArrayList<String> implements List<String> { }
        assertThat(getGenericInterfaceTypeParameters(MyListClass.class, List.class)[0]).isEqualTo(String.class);
    }

    @Test
    public void testGetGenericInterfaceTypeParameterNoGenerics() {
        assertThat(getGenericInterfaceTypeParameters(String.class, String.class).length).isEqualTo(0);
    }

    @Test(expected = NullPointerException.class)
    public void getGenericInterfaceTypeParametersRequiredNonNullValueForClassParameter() {
        getGenericInterfaceTypeParameters(null, Iterator.class);
    }

    @Test(expected = NullPointerException.class)
    public void getGenericInterfaceTypeParametersRequiredNonNullValueForInterfaceParameter() {
        getGenericInterfaceTypeParameters(String.class, null);
    }

    @Test(expected = NullPointerException.class)
    public void getTypeParametersRequiresNonNullParameter() {
        getTypeParameters(null);
    }

    @Test
    public void testTypeTakingParametersMustBeSubclassOfParameterizedType() {
        //Reflection on ArrayList<String> gives a ParameterizedType
        class A extends ArrayList<String> { };
        class B extends A { };
        TypeLiteral<List<String>> checker = new TypeLiteral<List<String>>() { };
        Type t = checker.getDefinedType(B.class);
        assertThat("java.lang.String").isEqualTo(t.getTypeName());
    }

    @SuppressWarnings("rawtypes")
    @Test(expected = RuntimeException.class)
    public void testTypeTakingParametersMustNotBeSubclassOfObject() {
        // Create a class hierarchy where B is a subclass of Object and not
        // ParameterizedType, but still takes parameters.
        class A<T> { };
		class B extends A { };
        TypeLiteral<List<String>> checker = new TypeLiteral<List<String>>() { };
        checker.getDefinedType(B.class);
    }
    
    @Test
    public void testHashAndEquals(){
        TypeLiteral<List<?>> a = TypeLiteral.of(List.class);
        TypeLiteral<List<?>> b = TypeLiteral.of(List.class);
        TypeLiteral<Map<?,?>> c = TypeLiteral.of(Map.class);
        assertThat(b.hashCode()).isEqualTo(a.hashCode());
        assertThat(a.hashCode()).isNotEqualTo(c.hashCode());
        assertThat(a.equals(a)).isTrue();
        assertThat(a.equals(b)).isTrue();
        assertThat(a.equals(null)).isFalse();
        assertThat("SomeString".equals(a)).isFalse();
        assertThat(a.equals(c)).isFalse();
    }

}

@@ -4507,10 +4507,16 @@
  %7D;%0A
-%09%09
+        
 clas

Remove tab