/*
 * Copyright (C) 2004 TiongHiang Lee
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not,  write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Email: thlee@onemindsoft.org
 */

package org.onemind.commons.java.lang.reflect;

import java.lang.reflect.Method;
import junit.framework.TestCase;
/**
 * Unit test for reflection utilities
 * @author TiongHiang Lee (thlee@onemindsoft.org)
 * @version $Id: ReflectUtilsTest.java,v 1.7 2006/08/02 00:07:24 thlee Exp $ $Name:  $
 */
public class ReflectUtilsTest extends TestCase
{

    private Class[] _classNames = {java.lang.Object.class, java.lang.Integer.class, java.lang.Float.class, java.lang.Double.class,
            java.lang.Long.class, java.lang.Boolean.class, java.lang.String.class, java.lang.Double.class, java.lang.Byte.class,
            java.lang.Character.class, java.lang.Exception.class, java.lang.Class.class};

    /** a test class * */
    public static class TestClass
    {

        /**
         * Static method
         */
        public static void staticMethod()
        {
        }

        public String normalMethod(Object obj)
        {
            return "A";
            //do nothing
        }

        public String normalMethod(Integer obj)
        {
            return "B";
            //do nothing
        }

        public String normalMethod(String obj)
        {
            return "C";
            //do nothing
        }

        public String similarMethod(short a)
        {
            return "short";
        }

        public String similarMethod(int a)
        {
            return "int";
        }

        public String similarMethod(long a)
        {
            return "long";
        }
    }

    public static class TestSubClass extends TestClass
    {
    }

    /** test the util * */
    public void testStaticMethodInvocation() throws Exception
    {
        ReflectUtils.invoke(TestClass.class, "staticMethod", null);
        ReflectUtils.invoke(TestSubClass.class, "staticMethod", null);
    }

    public void testClassMethodInvocation() throws Exception
    {
        ReflectUtils.invoke(new TestSubClass().getClass(), "getName", null);
        ReflectUtils.invoke(new TestSubClass().getClass(), "getName", null);
    }

    public void testObjectMethodInvcation() throws Exception
    {
        ReflectUtils.invoke(new TestClass(), "normalMethod", new Object[]{null});
    }

    public void testMethodSearch() throws Exception
    {
        Object result = ReflectUtils.invoke(new TestSubClass(), "similarMethod", new Object[]{new Long(1)});
        assertTrue(result.equals("long"));
        result = ReflectUtils.invoke(new TestSubClass(), "similarMethod", new Object[]{new Integer(1)});
        assertTrue(result.equals("int"));
        result = ReflectUtils.invoke(new TestSubClass(), "similarMethod", new Object[]{new Short((short) 1)});
        assertTrue(result.equals("short"));
        Object args[] = new Object[] { new Integer(1), new Integer(1) } ;
        ReflectUtils.invoke(Math.class, "pow", args);
    }

    public void testClassCache() throws Exception
    {
        long start = System.currentTimeMillis();
        ReflectUtils.setClassCaching(false);
        for (int i = 0; i < 10000; i++)
        {
            lookForClasses();
        }
        long end = System.currentTimeMillis();
        System.out.println("Time used for class lookup without caching = " + (end - start));
        start = System.currentTimeMillis();
        ReflectUtils.setClassCaching(true);
        start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++)
        {
            lookForClasses();
        }
        end = System.currentTimeMillis();
        System.out.println("Time used for class lookup with caching = " + (end - start));
    }

    public void testMethodCache() throws Exception
    {
        long start = System.currentTimeMillis();
        ReflectUtils.setMethodCaching(false);
        for (int i = 0; i < 10000; i++)
        {
            lookForMethods();
        }
        long end = System.currentTimeMillis();
        System.out.println("Time used for method lookup without caching = " + (end - start));
        start = System.currentTimeMillis();
        ReflectUtils.setMethodCaching(true);
        start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++)
        {
            lookForMethods();
        }
        end = System.currentTimeMillis();
        System.out.println("Time used for method lookup with caching = " + (end - start));
    }

    private void lookForClasses() throws Exception
    {
        for (int i = 0; i < _classNames.length; i++)
        {
            ReflectUtils.getClass(_classNames[i].getName());
        }
    }

    private void lookForMethods() throws Exception
    {
        for (int i = 0; i < _classNames.length; i++)
        {
            ReflectUtils.getMethod(_classNames[i], "equals", new Class[]{Object.class});
        }
    }

    public void testPrimitiveArgumentCheck() throws Exception
    {
        assertTrue(ReflectUtils.isCompatible(new Class[]{Long.TYPE}, new Object[]{new Long(1)}));
        assertTrue(ReflectUtils.isCompatible(new Class[]{Long.TYPE}, new Object[]{new Integer(1)}));
        assertFalse(ReflectUtils.isCompatible(new Class[]{Long.TYPE}, new Object[]{new Float(1.5)}));
        assertFalse(ReflectUtils.isCompatible(new Class[]{Long.TYPE}, new Object[]{new Double(1.5)}));
        assertTrue(ReflectUtils.isCompatible(new Class[]{Long.TYPE}, new Class[]{Long.class}));
        assertTrue(ReflectUtils.isCompatible(new Class[]{Long.TYPE}, new Class[]{Integer.class}));
        assertFalse(ReflectUtils.isCompatible(new Class[]{Long.TYPE}, new Class[]{Float.class}));
        assertFalse(ReflectUtils.isCompatible(new Class[]{Long.TYPE}, new Class[]{Double.class}));
    }

    public static void main(String[] args) throws Exception
    {
        ReflectUtilsTest test = new ReflectUtilsTest();
        test.testClassCache();
    }
}