/*
 * @author Ranides Atterwim <ranides@gmail.com>
 * @copyright Ranides Atterwim
 * @license WTFPL
 * @url http://ranides.net/projects/assira
 */
package net.ranides.assira.reflection.impl;

import net.ranides.assira.reflection.IClass;
import net.ranides.assira.reflection.mockup.ForRCompareUtils;
import net.ranides.assira.math.MathUtils;
import org.junit.Test;
import static net.ranides.assira.reflection.mockup.ForIClass.*;
import static net.ranides.assira.junit.NewAssert.*;


/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class RCompareUtilsTest {
    
    // Dobra. Zaimplementowaliśmy coś, co się zgadza na poziomie basic z JAVAC.
    // Czy się zgadza w 100% to nie wiadomo. Ale też nas to nic nie obchodzi tak naprawdę na ten moment.
    // Co jest bardzo dobrą wiadomością, to że tabelka wartości jest transpozycją po zmianie kolejności parametrów,
    // czyli jakieś elementarne własności funkcji porządkującej to mamy.
    
    @Test
    public void testWildcardsDirect() {
        /*
             | sup | cls | ext      JDK / type
        -----+-----+-----+-----
         sup |     |     |   
         cls |  +  |  +  |   
         ext |  +  |  +  |   
       
             | sup | cls | ext      issuper / type
        -----+-----+-----+-----
         sup |     |     |   
         cls |  +  |  +  |   
         ext |  +  |  +  |   
        
             | sup | cls | ext      issublcass / type
        -----+-----+-----+-----
         sup |     |  +  |  +
         cls |     |  +  |  +
         ext |     |     |   
        */
        IClass<?> ic = IClass.typeinfo(ForRCompareUtils.class);
        IClass<?> supA = ic.fields().require("superA").first().get().type().params().get(0);
        IClass<?> clsA = ic.fields().require("classA").first().get().type().params().get(0);
        IClass<?> extA = ic.fields().require("extenA").first().get().type().params().get(0);
        
        assertFalse( supA.isSuper(supA) );
        assertTrue( supA.isSuper(clsA) );
        assertTrue( supA.isSuper(extA) );

        assertFalse( clsA.isSuper(supA) );
        assertTrue( clsA.isSuper(clsA) );
        assertTrue( clsA.isSuper(extA) );
        
        assertFalse( extA.isSuper(supA) );
        assertFalse( extA.isSuper(clsA) );
        assertFalse( extA.isSuper(extA) );
        
        // ---
        
        assertFalse( supA.isSubclass(supA) );
        assertFalse( supA.isSubclass(clsA) );
        assertFalse( supA.isSubclass(extA) );

        assertTrue( clsA.isSubclass(supA) );
        assertTrue( clsA.isSubclass(clsA) );
        assertFalse( clsA.isSubclass(extA) );
        
        assertTrue( extA.isSubclass(supA) );
        assertTrue( extA.isSubclass(clsA) );
        assertFalse( extA.isSubclass(extA) );
    }

    @Test
    public void testWildcards() {
        /*
             | sup | cls | ext      JDK / parameterized type
        -----+-----+-----+-----
         sup |  +  |     |   
         cls |  +  |  +  |  +
         ext |     |     |  +
        
             | sup | cls | ext      issuper / parameterized type
        -----+-----+-----+-----
         sup |  +  |     |   
         cls |  +  |  +  |  +
         ext |     |     |  +
        
             | sup | cls | ext      issubclass / parameterized type
        -----+-----+-----+-----
         sup |  +  |  +  |   
         cls |     |  +  |   
         ext |     |  +  |  +
        */
        
        IClass<?> ic = IClass.typeinfo(ForRCompareUtils.class);
        IClass<?> supA = ic.fields().require("superA").first().get().type();
        IClass<?> clsA = ic.fields().require("classA").first().get().type();
        IClass<?> extA = ic.fields().require("extenA").first().get().type();
        
        assertTrue( supA.isSuper(supA) );
        assertTrue( supA.isSuper(clsA) );
        assertFalse( supA.isSuper(extA) );

        assertFalse( clsA.isSuper(supA) );
        assertTrue( clsA.isSuper(clsA) );
        assertFalse( clsA.isSuper(extA) );
        
        assertFalse( extA.isSuper(supA) );
        assertTrue( extA.isSuper(clsA) );
        assertTrue( extA.isSuper(extA) );
        
        // -- 
        
        assertTrue( supA.isSubclass(supA) );
        assertFalse( supA.isSubclass(clsA) );
        assertFalse( supA.isSubclass(extA) );

        assertTrue( clsA.isSubclass(supA) );
        assertTrue( clsA.isSubclass(clsA) );
        assertTrue( clsA.isSubclass(extA) );
        
        assertFalse( extA.isSubclass(supA) );
        assertFalse( extA.isSubclass(clsA) );
        assertTrue( extA.isSubclass(extA) );
    }
    
    @Test
    public void testCompare() {
        assertCompare(+0, NULL, NULL);
        assertCompare(-1, NULL, OBJECT);
        assertCompare(-1, OBJECT, I_NUMBER);
        assertCompare(-1, OBJECT, I_INTEGER);
        assertCompare(-1, I_NUMBER, I_INTEGER);
        assertCompare(-1, I_INTEGER, STRING);
    }
    
    void assertCompare(int cmp, IClass<?> a, IClass<?> b) {
        assertEquals(MathUtils.signum(cmp), MathUtils.signum(RCompareUtils.compare(a, b)));
        assertEquals(MathUtils.signum(cmp), -MathUtils.signum(RCompareUtils.compare(b, a)));
    }
    
    @Test
    public void testIsSuper() {
        assertTrue(RCompareUtils.isSuper(NULL, NULL));
        assertTrue(RCompareUtils.isSuper(NULL, OBJECT));
        assertTrue(RCompareUtils.isSuper(NULL, I_INTEGER));
        assertFalse(RCompareUtils.isSuper(NULL, INT));
        
        assertTrue(RCompareUtils.isSuper(I_NUMBER, I_INTEGER));
        assertFalse(RCompareUtils.isSuper(I_NUMBER, INT));
        assertFalse(RCompareUtils.isSuper(I_NUMBER, STRING));
        
        assertFalse(RCompareUtils.isSuper(I_INTEGER, I_NUMBER));
        assertTrue(RCompareUtils.isSuper(I_INTEGER, I_INTEGER));
    }
    
    @Test
    public void testIsInstance() {
        assertTrue(RCompareUtils.isInstance(NULL, null));
        assertTrue(RCompareUtils.isInstance(NULL, new Object()));
        assertTrue(RCompareUtils.isInstance(NULL, Integer.valueOf(44)));
        assertTrue(RCompareUtils.isInstance(NULL, 44));
        
        assertTrue(RCompareUtils.isInstance(I_NUMBER, Integer.valueOf(44)));
        assertTrue(RCompareUtils.isInstance(I_NUMBER, 44));
        assertFalse(RCompareUtils.isInstance(I_NUMBER, "hello"));
        
        assertFalse(RCompareUtils.isInstance(I_INTEGER, Float.valueOf(33)));
        assertTrue(RCompareUtils.isInstance(I_INTEGER, 44));
    }
    
}
