/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This 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 software 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 software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
package org.jboss.test.aop.joinpointcomparator;


import java.lang.reflect.Constructor;
import java.util.Arrays;

import org.jboss.aop.ConstructorInfo;
import org.jboss.aop.advice.Interceptor;
import org.jboss.aop.util.JoinPointComparator;
import org.jboss.test.aop.AOPTestWithSetup;


import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestSuite;
import junit.textui.TestRunner;

/**
 * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
 * @version $Revision: 70829 $
 */
public class JoinPointComparatorTestCase extends AOPTestWithSetup
{

   private static final Constructor<?> CTOR1;
   private static final Constructor<?> CTOR2;
   private static final Constructor<?> CTOR3;
   static
   {
      try
      {
         CTOR1 = POJO.class.getConstructor();
         CTOR2 = POJO.class.getConstructor(Integer.TYPE);
         CTOR3 = POJO.class.getConstructor(Long.TYPE);
      }
      catch (SecurityException e)
      {
         // AutoGenerated
         throw new RuntimeException(e);
      }
      catch (NoSuchMethodException e)
      {
         // AutoGenerated
         throw new RuntimeException(e);
      }
   }
   
   public static void main(String[] args)
   {
      TestRunner.run(suite());
   }

   public static Test suite()
   {
      TestSuite suite = new TestSuite("JoinPointComparatorTestCase");
      suite.addTestSuite(JoinPointComparatorTestCase.class);
      return suite;
   }

   public JoinPointComparatorTestCase(String name)
   {
      super(name);
   }
   
   public void testMergeMethodKeys()
   {
      {
         long[] l1 = new long[] {4, 3, 2, 1};
         long[] l2 = new long[] {4, 3, 2, 1};
         assertArray(new long[]{1, 2, 3, 4}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      {
         long[] l1 = new long[] {4, 3, 2, 1};
         long[] l2 = new long[] {};
         assertArray(new long[]{1, 2, 3, 4}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      {
         long[] l1 = new long[] {};
         long[] l2 = new long[] {4, 3, 2, 1};
         assertArray(new long[]{1, 2, 3, 4}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      {
         long[] l1 = new long[] {4, 3, 2, 1};
         long[] l2 = null;
         assertArray(new long[]{1, 2, 3, 4}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      {
         long[] l1 = null;
         long[] l2 = new long[] {4, 3, 2, 1};
         assertArray(new long[]{1, 2, 3, 4}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      {
         long[] l1 = new long[] {4, 3, 2, 1};
         long[] l2 = new long[] {1};
         assertArray(new long[]{1, 2, 3, 4}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      {
         long[] l1 = new long[] {4};
         long[] l2 = new long[] {4, 3, 2, 1};
         assertArray(new long[]{1, 2, 3, 4}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      {
         long[] l1 = new long[] {4, 3, 2, 1};
         long[] l2 = new long[] {1, 5};
         assertArray(new long[]{1, 2, 3, 4, 5}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      {
         long[] l1 = new long[] {5, 4};
         long[] l2 = new long[] {4, 3, 2,1};
         assertArray(new long[]{1, 2, 3, 4, 5}, JoinPointComparator.mergeMethodInfoKeys(l1, l2));
      }      
      
      
   }

   public void testEqualInterceptors()
   {
      MockJoinPointInfo a = new MockJoinPointInfo(new TestInterceptor());
      MockJoinPointInfo b = new MockJoinPointInfo(new TestInterceptor());
      assertEquals(0, JoinPointComparator.hasSameInterceptorLengths(a, b));
   }
   
   public void testBothNullInterceptors()
   {
      assertEquals(0, JoinPointComparator.hasSameInterceptorLengths(null, null));      
   }

   public void testBothZeroLengthChains()
   {
      MockJoinPointInfo a = new MockJoinPointInfo();
      assertNotNull(a.getInterceptors());
      MockJoinPointInfo b = new MockJoinPointInfo();
      assertEquals(0, JoinPointComparator.hasSameInterceptorLengths(a, b));
   }
   
   public void testBothNullChains()
   {
      MockJoinPointInfo a = new MockJoinPointInfo();
      a.setInterceptors(null);
      MockJoinPointInfo b = new MockJoinPointInfo();
      a.setInterceptors(null);
      assertEquals(0, JoinPointComparator.hasSameInterceptorLengths(a, b));
   }
   
   public void testNotEqualInterceptorsA()
   {
      MockJoinPointInfo a = new MockJoinPointInfo(new TestInterceptor(), new TestInterceptor());
      MockJoinPointInfo b = new MockJoinPointInfo(new TestInterceptor());
      assertEquals(-1, JoinPointComparator.hasSameInterceptorLengths(a, b));
   }
   
   public void testNotEqualInterceptorsB()
   {
      MockJoinPointInfo a = new MockJoinPointInfo(new TestInterceptor());
      MockJoinPointInfo b = new MockJoinPointInfo(new TestInterceptor(), new TestInterceptor());
      assertEquals(1, JoinPointComparator.hasSameInterceptorLengths(a, b));
   }
   
   public void testNullA()
   {
      MockJoinPointInfo a = null;
      MockJoinPointInfo b = new MockJoinPointInfo(new TestInterceptor());
      assertEquals(1, JoinPointComparator.hasSameInterceptorLengths(a, b));      
   }
   
   public void testNullB()
   {
      MockJoinPointInfo a = new MockJoinPointInfo(new TestInterceptor());
      MockJoinPointInfo b = null;
      assertEquals(-1, JoinPointComparator.hasSameInterceptorLengths(a, b));      
   }

   public void testNullAZeroLengthB()
   {
      MockJoinPointInfo a = new MockJoinPointInfo();
      a.setInterceptors(null);
      MockJoinPointInfo b = new MockJoinPointInfo();
      assertEquals(0, JoinPointComparator.hasSameInterceptorLengths(a, b));      
      
   }

   public void testNullBZeroLengthA()
   {
      MockJoinPointInfo a = new MockJoinPointInfo();
      MockJoinPointInfo b = new MockJoinPointInfo();
      b.setInterceptors(null);
      assertEquals(0, JoinPointComparator.hasSameInterceptorLengths(a, b));      
   }

   public void testEqualConstructorChains()
   {
      ConstructorInfo[] a = new ConstructorInfo[] {
            createConstructorInfo(CTOR1, 1, false),
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR3, 3, false)};
      
      ConstructorInfo[] b = new ConstructorInfo[] {
            createConstructorInfo(CTOR3, 3, false),
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR1, 1, false)};
      
      assertTrue(JoinPointComparator.hasSameConstructorAspectLength(a, b));
   }
   
   public void testDifferentConstructorLengthsAEqualChains()
   {
      ConstructorInfo[] a = new ConstructorInfo[] {
            createConstructorInfo(CTOR1, 1, false),
            createConstructorInfo(CTOR2, 2, false)};
      
      ConstructorInfo[] b = new ConstructorInfo[] {
            createConstructorInfo(CTOR3, 0, false),
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR1, 1, false)};
   
      assertTrue(JoinPointComparator.hasSameConstructorAspectLength(a, b));
   }
   
   public void testDifferentConstructorLengthsAEqualChainsNull()
   {
      ConstructorInfo[] a = new ConstructorInfo[] {
            createConstructorInfo(CTOR1, 1, false),
            createConstructorInfo(CTOR2, 2, false)};
      
      ConstructorInfo[] b = new ConstructorInfo[] {
            createConstructorInfo(CTOR3, 0, true),
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR1, 1, false)};
      
      assertTrue(JoinPointComparator.hasSameConstructorAspectLength(a, b));
   }
   
   public void testDifferentConstructorLengthsBEqualChains()
   {
      ConstructorInfo[] a = new ConstructorInfo[] {
            createConstructorInfo(CTOR3, 0, false),
            createConstructorInfo(CTOR1, 1, false),
            createConstructorInfo(CTOR2, 2, false)};
      
      ConstructorInfo[] b = new ConstructorInfo[] {
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR1, 1, false)};
      
      assertTrue(JoinPointComparator.hasSameConstructorAspectLength(a, b));
   }
   
   public void testDifferentConstructorLengthsBEqualChainsNull()
   {
      ConstructorInfo[] a = new ConstructorInfo[] {
            createConstructorInfo(CTOR3, 0, true),
            createConstructorInfo(CTOR1, 1, false),
            createConstructorInfo(CTOR2, 2, false)};
      
      ConstructorInfo[] b = new ConstructorInfo[] {
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR1, 1, false)};
      
      assertTrue(JoinPointComparator.hasSameConstructorAspectLength(a, b));
   }
   
   public void testDifferentConstructorChains()
   {
      ConstructorInfo[] a = new ConstructorInfo[] {
            createConstructorInfo(CTOR1, 1, false),
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR3, 4, false)};
      
      ConstructorInfo[] b = new ConstructorInfo[] {
            createConstructorInfo(CTOR3, 3, false),
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR1, 1, false)};
      
      assertFalse(JoinPointComparator.hasSameConstructorAspectLength(a, b));
   }
   
   
   public void testNullConstructorChainA()
   {
      ConstructorInfo[] a = null;
      
      ConstructorInfo[] b = new ConstructorInfo[] {
            createConstructorInfo(CTOR3, 3, false),
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR1, 1, false)};
      
      assertFalse(JoinPointComparator.hasSameConstructorAspectLength(a, b));
   }
   
   public void testNullConstructorChainB()
   {
      ConstructorInfo[] a = new ConstructorInfo[] {
            createConstructorInfo(CTOR3, 3, false),
            createConstructorInfo(CTOR2, 2, false),
            createConstructorInfo(CTOR1, 1, false)};
      
      ConstructorInfo[] b = null;
      
      assertFalse(JoinPointComparator.hasSameConstructorAspectLength(a, b));
   }
   
   private void assertArray(long[] expected, long[] actual)
   {
      if (expected.length != actual.length)
      {
         throw new AssertionFailedError("Expected " + Arrays.asList(expected) + " had " + Arrays.asList(actual));
      }
      
      for (int i = 0 ; i < expected.length ; i++)
      {
         if (expected[i] != actual[i])
         {
            throw new AssertionFailedError("Expected " + Arrays.asList(expected) + " had " + Arrays.asList(actual));
         }
      }
   }
      
   private ConstructorInfo createConstructorInfo(Constructor<?> ctor, int length, boolean nullIcptrs)
   {
      ConstructorInfo info = new ConstructorInfo();
      info.setConstructor(ctor);
      if (length > 0 && nullIcptrs)
      {
         throw new IllegalStateException("Cannot have both 0 length and null interceptors");
      }
      if (nullIcptrs)
      {
         info.setInterceptors(null);
      }
      else
      {
         Interceptor[] interceptors = new Interceptor[length];
         for (int i = 0 ; i < length ; i++)
         {
            interceptors[i] = new TestInterceptor();
         }
         info.setInterceptors(interceptors);   
      }
      return info;
   }
}
