package org.codehaus.groovy.grails.commons.metaclass;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import junit.framework.TestCase;

public class DynamicMethodsInterceptorTests extends TestCase {

    /*
     * Test method for 'org.codehaus.groovy.grails.commons.metaclass.AbstractDynamicMethodsInterceptor.afterConstructor(Object[], Object)'
     */
    public void testAfterConstructor() throws Exception {
        GroovyClassLoader gcl = new GroovyClassLoader();
        final Class<?> testClass = gcl.parseClass("class Test {}");
        GroovyObject go = (GroovyObject)testClass.newInstance();

        ProxyMetaClass pmc = ProxyMetaClass.getInstance(testClass);
        go.setMetaClass(pmc);

        pmc.setInterceptor( new ConstructorInterceptor() {
            public Object beforeConstructor(Object[] args, InvocationCallback callback) {
                return null;
            }
            public Object afterConstructor(Object[] args, Object instantiatedInstance) {
                assertNotNull(instantiatedInstance);
                assertEquals(testClass,instantiatedInstance.getClass());
                return instantiatedInstance;
            }
            public Object beforeInvoke(Object object, String methodName, Object[] arguments, InvocationCallback callback) {
                return null;
            }
            public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
                return null;
            }
        });

        Object instance = go.getMetaClass().invokeConstructor(new Object[0]);
        assertNotNull(instance);
        assertEquals(testClass,instance.getClass());
    }

    /*
     * Test method for 'org.codehaus.groovy.grails.commons.metaclass.AbstractDynamicMethodsInterceptor.beforeConstructor(Object[], InvocationCallback)'
     */
    public void testBeforeConstructor() throws Exception {
        GroovyClassLoader gcl = new GroovyClassLoader();
        final Class<?> testClass = gcl.parseClass("class Test {}");
        GroovyObject go = (GroovyObject)testClass.newInstance();

        ProxyMetaClass pmc = ProxyMetaClass.getInstance(testClass);
        go.setMetaClass(pmc);

        pmc.setInterceptor( new ConstructorInterceptor() {
            public Object beforeConstructor(Object[] args, InvocationCallback callback) {
                callback.markInvoked();
                return "success";
            }
            public Object afterConstructor(Object[] args, Object instantiatedInstance) {
                return instantiatedInstance;
            }
            public Object beforeInvoke(Object object, String methodName, Object[] arguments, InvocationCallback callback) {
                return null;
            }
            public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
                return null;
            }
        });

        Object instance = go.getMetaClass().invokeConstructor(new Object[0]);
        assertNotNull(instance);
        assertEquals("success",instance);
    }

    /*
     * Test method for 'org.codehaus.groovy.grails.commons.metaclass.AbstractDynamicMethodsInterceptor.beforeInvoke(Object, String, Object[], InvocationCallback)'
     */
    public void testBeforeInvoke() throws Exception {
        GroovyClassLoader gcl = new GroovyClassLoader();
        final Class<?> testClass = gcl.parseClass("class Test { def invokeMe() {'hello'} }");
        GroovyObject go = (GroovyObject)testClass.newInstance();

        ProxyMetaClass pmc = ProxyMetaClass.getInstance(testClass);
        go.setMetaClass(pmc);

        pmc.setInterceptor( new Interceptor() {
            public Object beforeInvoke(Object object, String methodName, Object[] arguments, InvocationCallback callback) {
                callback.markInvoked();
                return "success";
            }
            public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
                return result;
            }
        });

        Object result = go.invokeMethod("invokeMe", null);
        assertNotNull(result);
        assertEquals("success",result);
    }

    /*
     * Test method for 'org.codehaus.groovy.grails.commons.metaclass.AbstractDynamicMethodsInterceptor.afterInvoke(Object, String, Object[], Object)'
     */
    public void testAfterInvoke() throws Exception {
        GroovyClassLoader gcl = new GroovyClassLoader();
        final Class<?> testClass = gcl.parseClass("class Test { def invokeMe() {'hello'} }");
        GroovyObject go = (GroovyObject)testClass.newInstance();

        ProxyMetaClass pmc = ProxyMetaClass.getInstance(testClass);
        go.setMetaClass(pmc);

        pmc.setInterceptor( new Interceptor() {
            public Object beforeInvoke(Object object, String methodName, Object[] arguments, InvocationCallback callback) {
                return null;
            }
            public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
                assertEquals("hello", result);
                assertEquals("invokeMe", methodName);
                return result.toString() + 1;
            }
        });

        Object result = go.invokeMethod("invokeMe", null);
        assertNotNull(result);
        assertEquals("hello1",result);
    }

    /*
     * Test method for 'org.codehaus.groovy.grails.commons.metaclass.AbstractDynamicMethodsInterceptor.beforeGet(Object, String, InvocationCallback)'
     */
    public void testBeforeGet() throws Exception {
        GroovyClassLoader gcl = new GroovyClassLoader();
        final Class<?> testClass = gcl.parseClass("class Test { def prop = 'hello' }");
        GroovyObject go = (GroovyObject)testClass.newInstance();

        ProxyMetaClass pmc = ProxyMetaClass.getInstance(testClass);
        go.setMetaClass(pmc);

        pmc.setInterceptor( new PropertyAccessInterceptor(){

            public Object beforeGet(Object object, String property, InvocationCallback callback) {
                callback.markInvoked();
                return "success";
            }

            public void beforeSet(Object object, String property, Object newValue, InvocationCallback callback) {
                // TODO Auto-generated method stub
            }

            public Object beforeInvoke(Object object, String methodName, Object[] arguments, InvocationCallback callback) {
                return null;
            }

            public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
                return null;
            }
        });

        Object result = go.getProperty("prop");
        assertNotNull(result);
        assertEquals("success",result);
    }

    /*
     * Test method for 'org.codehaus.groovy.grails.commons.metaclass.AbstractDynamicMethodsInterceptor.beforeSet(Object, String, Object, InvocationCallback)'
     */
    public void testBeforeSet() throws Exception {
        GroovyClassLoader gcl = new GroovyClassLoader();
        final Class<?> testClass = gcl.parseClass("class Test { def prop = 'hello' }");
        GroovyObject go = (GroovyObject)testClass.newInstance();

        ProxyMetaClass pmc = ProxyMetaClass.getInstance(testClass);
        go.setMetaClass(pmc);

        pmc.setInterceptor( new PropertyAccessInterceptor(){

            public Object beforeGet(Object object, String property, InvocationCallback callback) {
                return null;
            }

            public void beforeSet(Object object, String property, Object newValue, InvocationCallback callback) {
                assertEquals("prop", property);
                BeanWrapper bean = new BeanWrapperImpl(object);
                bean.setPropertyValue("prop","success");
                callback.markInvoked();
            }

            public Object beforeInvoke(Object object, String methodName, Object[] arguments, InvocationCallback callback) {
                return null;
            }

            public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
                return null;
            }
        });

        go.setProperty("prop", "newValue");
        Object result = go.getProperty("prop");
        assertNotNull(result);
        assertEquals("success",result);
    }
}
