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

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

import java.util.Map;
import java.util.TreeMap;
import net.ranides.test.mockup.reflection.ForClassTraits;
import org.junit.Ignore;
import org.junit.Test;
import static net.ranides.assira.junit.NewAssert.*;
import static net.ranides.assira.reflection.IAttributes.*;
import static net.ranides.assira.reflection.IAttribute.*;
import net.ranides.test.mockup.reflection.ForMemberTraits;
//import static net.ranides.test.mockup.reflection.ForMemberTraits.$method;
import net.ranides.test.mockup.reflection.ForMethodUtils;

/**
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public class IAttributeTest {
    
        
    @Test
    public void testContract() throws Exception {
        assertEnumInvariants(IAttribute.class);
    }
    
    @Test
    public void testType() {
        IAttributes ex1 = of(DECLARED, PUBLIC, RESOLVED);
        IAttributes ex2 = of(DECLARED, PRIVATE, RESOLVED);
        IAttributes ex3 = of(DECLARED, PACKAGE, STATIC, ABSTRACT, INTERFACE, RESOLVED);
        IAttributes ex4 = of(DECLARED, PACKAGE, FINAL, RESOLVED);
        
        assertEquals(ex1, of(ForClassTraits.PUBLIC));
        assertEquals(ex2, of(ForClassTraits.PRIVATE));
        assertEquals(ex3, of(ForClassTraits.INTERFACE));
        assertEquals(ex4, of(ForClassTraits.FINAL));
    }
    
    @Test
    public void testTypeParameterized() {
        IAttributes ex1 = of(DECLARED, PACKAGE, PARAMETERIZED);
        IAttributes ex2 = of(DECLARED, PACKAGE, RESOLVED);
        
        assertEquals(ex1, of(ForClassTraits.PARAMS));
        assertEquals(ex2, of(ForClassTraits.NO_PARAMS));
    }
    
    @Test
    public void testMethod() {
        IAttributes ex1 = of(PUBLIC);
        IAttributes ex2 = of(PACKAGE);
        IAttributes ex3 = of(PRIVATE, STRICT);
        IAttributes ex4 = of(PUBLIC, VARARGS);
        IAttributes ex5 = of(PUBLIC, BRIDGE, SYNTHETIC);
        
        IAttributes ex6 = of(PUBLIC);
        IAttributes ex7 = of(PUBLIC, PARAMETERIZED);
        
        assertEquals(ex1, of($method(ForMethodUtils.A.class, "fun1")));
        assertEquals(ex2, of($method(ForMethodUtils.A.class, "fun4")));
        assertEquals(ex3, of($method(ForMethodUtils.A.class, "fun5")));
        assertEquals(ex4, of($method(ForMethodUtils.class, "funV1")));
        assertEquals(ex4, of($method(ForMethodUtils.class, "funV2")));
        
        IClass<?> ic1 = IClass.typeinfo(ForMethodUtils.MC.class);
        IClass<?> ic2 = IClass.typeinfo(ForMethodUtils.MCP.class);
        
        Method m1 = ic1.methods().require("compare").require(BRIDGE).first().get().reflective();
        Method m2 = ic2.methods().require("compare").discard(BRIDGE).first().get().reflective();
        Method m3 = ic2.methods().require("fun6").first().get().reflective();
        
        assertEquals(ex5, of(m1));
        assertEquals(ex6, of(m2));
        assertEquals(ex7, of(m3));
        assertEquals(ex6, of($method(ForMethodUtils.MCP.class, "fun7")));
    }
    
    @Test
    public void testField() {
        IAttributes ex1 = of(DECLARED, PUBLIC, FINAL);
        IAttributes ex2 = of(DECLARED, PACKAGE);
        IAttributes ex3 = of(DECLARED, PACKAGE, PARAMETERIZED);
        IAttributes ex4 = of(DECLARED, PACKAGE, PARAMETERIZED);
        
        assertEquals(ex1, of(ForMemberTraits.FINAL));
        assertEquals(ex2, of(ForMemberTraits.NOTHING));
        assertEquals(ex3, of(ForMemberTraits.LIST1));
        assertEquals(ex4, of(ForMemberTraits.LIST2));
    }
    
    @Test
    public void testParams() {
        IAttributes ex1 = of(DECLARED, PACKAGE, PARAMETERIZED);
        IAttributes ex2 = of(DECLARED, PACKAGE);
        
        assertEquals(ex1, of($param(ForMethodUtils.MCP.class, "fun6", 0)));
        assertEquals(ex1, of($param(ForMethodUtils.MCP.class, "fun6", 1)));
        assertEquals(ex2, of($param(ForMethodUtils.MCP.class, "fun6", 2)));
        assertEquals(ex1, of($param(ForMethodUtils.MCP.class, "fun7", 0)));
    }

    @Test
    public void testResolved() {
        IAttributes ex1 = of(DECLARED, RESOLVED);

        assertTrue(ex1.contains(RESOLVED));
        assertTrue(ex1.contains(DECLARED));

        assertFalse(ex1.contains(PRIVATE));
        assertFalse(ex1.contains(PROTECTED));
        assertFalse(ex1.contains(PACKAGE));
        assertFalse(ex1.contains(PUBLIC));
    }

    @Ignore("manual")
    @Test
    public void dumpMask() {
        Map<Integer, IAttribute> map = new TreeMap<>();
        for(IAttribute attr : IAttribute.values()) {
            map.put(attr.mask, attr);
        }

        for (IAttribute attr : map.values()) {
            System.out.printf("%08x %s%n", attr.mask, attr.name());
        }
    }
    
    private static Method $method(Class<?> type, String name) {
        return IClass.typeinfo(type).methods().require(DECLARED).require(name).first().get().reflective();
    }
    
    private static Parameter $param(Class<?> type, String name, int index) {
        return IClass.typeinfo(type).methods().require(DECLARED).require(name).first().get().arguments().list().get(index).reflective();
    }

}
