/*
 * @author Ranides Atterwim <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.Set;
import net.ranides.assira.reflection.mockup.ForClassTraits;
import org.junit.Test;
import static net.ranides.assira.junit.NewAssert.*;
import static net.ranides.assira.reflection.IAttribute.*;
import net.ranides.assira.reflection.mockup.ForMemberTraits;
//import static net.ranides.assira.reflection.mockup.ForMemberTraits.$method;
import net.ranides.assira.reflection.mockup.ForMethodUtils;

/**
 *
 * @author Ranides Atterwim <ranides@gmail.com>
 */
public class IAttributeTest {
    
        
    @Test
    public void testContract() throws Exception {
        assertEnumInvariants(IAttribute.class);
    }
    
    @Test
    public void testType() {
        Set<IAttribute> ex1 = collect(DECLARED, PUBLIC);
        Set<IAttribute> ex2 = collect(DECLARED, PRIVATE);
        Set<IAttribute> ex3 = collect(DECLARED, PACKAGE, STATIC, ABSTRACT, INTERFACE);
        Set<IAttribute> ex4 = collect(DECLARED, PACKAGE, FINAL);
        
        assertEquals(ex1, resolve(ForClassTraits.PUBLIC));
        assertEquals(ex2, resolve(ForClassTraits.PRIVATE));
        assertEquals(ex3, resolve(ForClassTraits.INTERFACE));
        assertEquals(ex4, resolve(ForClassTraits.FINAL));
    }
    
    @Test
    public void testTypeParameterized() {
        Set<IAttribute> ex1 = collect(DECLARED, PACKAGE, PARAMETERIZED);
        Set<IAttribute> ex2 = collect(DECLARED, PACKAGE);
        
        assertEquals(ex1, resolve(ForClassTraits.PARAMS));
        assertEquals(ex2, resolve(ForClassTraits.NO_PARAMS));
    }
    
    @Test
    public void testMethod() {
        Set<IAttribute> ex1 = collect(PUBLIC);
        Set<IAttribute> ex2 = collect(PACKAGE);
        Set<IAttribute> ex3 = collect(PRIVATE, STRICT);
        Set<IAttribute> ex4 = collect(PUBLIC, VARARGS);
        Set<IAttribute> ex5 = collect(PUBLIC, BRIDGE, SYNTHETIC);
        
        Set<IAttribute> ex6 = collect(PUBLIC);
        Set<IAttribute> ex7 = collect(PUBLIC, PARAMETERIZED);
        
        assertEquals(ex1, resolve($method(ForMethodUtils.A.class, "fun1")));
        assertEquals(ex2, resolve($method(ForMethodUtils.A.class, "fun4")));
        assertEquals(ex3, resolve($method(ForMethodUtils.A.class, "fun5")));
        assertEquals(ex4, resolve($method(ForMethodUtils.class, "funV1")));
        assertEquals(ex4, resolve($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, resolve(m1));
        assertEquals(ex6, resolve(m2));
        assertEquals(ex7, resolve(m3));
        assertEquals(ex6, resolve($method(ForMethodUtils.MCP.class, "fun7")));
    }
    
    @Test
    public void testField() {
        Set<IAttribute> ex1 = collect(DECLARED, PUBLIC, FINAL);
        Set<IAttribute> ex2 = collect(DECLARED, PACKAGE);
        Set<IAttribute> ex3 = collect(DECLARED, PACKAGE, PARAMETERIZED);
        Set<IAttribute> ex4 = collect(DECLARED, PACKAGE, PARAMETERIZED);
        
        assertEquals(ex1, resolve(ForMemberTraits.FINAL));
        assertEquals(ex2, resolve(ForMemberTraits.NOTHING));
        assertEquals(ex3, resolve(ForMemberTraits.LIST1));
        assertEquals(ex4, resolve(ForMemberTraits.LIST2));
    }
    
    @Test
    public void testParams() {
        Set<IAttribute> ex1 = collect(DECLARED, PACKAGE, PARAMETERIZED);
        Set<IAttribute> ex2 = collect(DECLARED, PACKAGE);
        
        assertEquals(ex1, resolve($param(ForMethodUtils.MCP.class, "fun6", 0)));
        assertEquals(ex1, resolve($param(ForMethodUtils.MCP.class, "fun6", 1)));
        assertEquals(ex2, resolve($param(ForMethodUtils.MCP.class, "fun6", 2)));
        assertEquals(ex1, resolve($param(ForMethodUtils.MCP.class, "fun7", 0)));
    }
    
    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();
    }

}
