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

import java.util.List;
import static net.ranides.assira.junit.NewAssert.*;

import net.ranides.assira.reflection.*;
import net.ranides.assira.text.Wildcard;
import org.junit.Test;

/**
 *
 * @author Ranides Atterwim {@literal <ranides@gmail.com>}
 */
public class TraceUtilsTest {

    @Test
    public void testCallerType() {
        assertTrue( SI0.runCallerType0() );
    }
    
    @Test
    public void testCalleeType() {
        assertTrue( SI0.runCalleeType0() );
    }
    
    @Test
    public void testCallerName() {
        assertTrue( SI0.runCallerName0() );
    }
    
    @Test
    public void testCalleeName() {
        assertTrue( SI0.runCalleeName0() );
    }

    @Test
    public void testFrame() {
        assertTrue( SI0.runFrame0() );
    }

    @Test
    public void verySimpleName() {
        String actual = TraceUtils.getTestFrame()
            .map(f -> IClass.typeinfo(f).shortName() +"."+ f.getMethodName())
            .get();
        assertEquals("TraceUtilsTest.verySimpleName", actual);
    }
    
    private static final class SI0 {
        
        private SI0() { /* utility class */ }
        
        public static boolean runCallerType0() {
            SI1.runCallerType1();
            return true;
        }
        
        public static boolean runCalleeType0() {
            SI1.runCalleeType1();
            return true;
        }
        
        public static boolean runCallerName0() {
            SI1.runCallerName1();
            return true;
        }
        
        public static boolean runCalleeName0() {
            SI1.runCalleeName1();
            return true;
        }

        public static boolean runFrame0() {
            SI1.runFrame1();
            return true;
        }
        
    }
    
    private static final class SI1 {
        
        private SI1() { /* utility class */ }
        
        public static void runCallerType1() {
            Class<?> caller = SI0.class;

            Class callerAuto = TraceUtils.getCallerType();
            assertEquals(caller, callerAuto);
        }
        
        public static void runCalleeType1() {
            Class<?> callee = SI1.class;

            Class calleeAuto = TraceUtils.getCalleeType();
            assertEquals(callee, calleeAuto);
        }
        
        public static void runCallerName1() {
            String caller = SI0.class.getName();
            
            String callerAuto = TraceUtils.getCallerName();
            assertEquals(caller, callerAuto);
        }
        
        public static void runCalleeName1() {
            String callee = SI1.class.getName();
            
            String calleeAuto = TraceUtils.getCalleeName();
            assertEquals(callee, calleeAuto);
        }

        
        public static void runFrame1() {
            List<StackTraceElement> frames = TraceUtils.getFrames();

            if(false) { // NOPMD
                System.out.printf("frames = %d%n", frames.size());
                dump(frames);
            }
            
            Wildcard callee = Wildcard.compile("net.ranides.assira.trace.TraceUtilsTest$SI1.runFrame1(TraceUtilsTest.java:*)");
            Wildcard caller = Wildcard.compile("net.ranides.assira.trace.TraceUtilsTest$SI0.runFrame0(TraceUtilsTest.java:*)");
            Wildcard frame2 = Wildcard.compile("net.ranides.assira.trace.TraceUtilsTest.testFrame(TraceUtilsTest.java:*)");

            assertTrue(callee.test(TraceUtils.getCalleeFrame().toString()));
            assertTrue(caller.test(TraceUtils.getCallerFrame().toString()));

            assertTrue(callee.test(frames.get(0).toString()));
            assertTrue(caller.test(frames.get(1).toString()));
            assertTrue(frame2.test(frames.get(2).toString()));
        }

    }
    
    @SuppressWarnings("PMD")
    private static void dump(List<?> list) {
        int i = 0;
        for(Object c : list) {
            System.err.printf("%d. %s%n", i++, c);
        }
        System.out.printf("%n");
    }
    
}
