/************************************************
 * Copyright (c) Shen Li. All rights reserved.  *
 * http://joyaop.sourceforge.net                *
 * -------------------------------------------- *
 * Distributable under LGPL license.            *
 * See terms of license at gnu.org.             *
 ************************************************/
package test.runtime;

import junit.framework.TestCase;
import net.sf.joyaop.framework.AspectRuntime;
import net.sf.joyaop.framework.InterceptorAspect;
import net.sf.joyaop.framework.MixinAspect;
import net.sf.joyaop.impl.AspectRuntimeImpl;
import net.sf.joyaop.impl.InterceptorAspectImpl;
import net.sf.joyaop.impl.MixinAspectImpl;
import net.sf.joyaop.impl.Pointcuts;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Shen Li
 */
public class RuntimeTest extends TestCase {
    public static final String ARROW = "->";
    private Target target;

    public void testAspects() {
        assertEquals("Target.target()" + ARROW + "FooImpl.foo()" + ARROW + "BarImpl.bar()", target.target());
        assertEquals("FooImpl.foo()" + ARROW + "BarImpl.bar()", target.foo());
        assertEquals("BarImpl.bar()", target.bar());
        assertEquals("FooInterceptor.intercept()" + ARROW
                + "AbstractFooInterceptor.execute()" + ARROW
                + "FooDecorator.anotherFoo()" + ARROW
                + "FooImpl.foo()" + ARROW
                + "BarImpl.bar()&FooImpl.anotherFoo()",
                target.anotherFoo());
    }

    public void testSerialization() throws Throwable {
        target.setTargetState("targetState");
        target.setBarState("barState");
        target.target();
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        new ObjectOutputStream(output).writeObject(target);
        ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(output.toByteArray()));
        target = (Target) input.readObject();
        assertEquals("targetState", target.getTargetState());
        assertEquals("barState", target.getBarState());
        testAspects();
    }

    protected void setUp() throws Exception {
        super.setUp();
        AspectRuntime runtime = new AspectRuntimeImpl();
        Map params = new HashMap();
        params.put("arrow", ARROW);

        MixinAspect mixinAspect = new MixinAspectImpl();
        mixinAspect.setAspectClass(BarImpl.class);
        mixinAspect.setInterfaceClass(Bar.class);
        mixinAspect.setParameters(params);
        mixinAspect.setPointcut(Pointcuts.byInterface(Bar.class));
        runtime.addMixin(mixinAspect);

        mixinAspect = new MixinAspectImpl();
        mixinAspect.setAspectClass(FooImpl.class);
        mixinAspect.setInterfaceClass(Foo.class);
        mixinAspect.setParameters(params);
        mixinAspect.setPointcut(Pointcuts.byInterface(Foo.class));
        runtime.addMixin(mixinAspect);

        InterceptorAspect interceptorAspect = new InterceptorAspectImpl();
        interceptorAspect.setAspectClass(FooDecorator.class);
        interceptorAspect.setParameters(params);
        interceptorAspect.setPrecedence(1);
        interceptorAspect.setPointcut(Pointcuts.byInterface(Foo.class));
        runtime.addInterceptor(interceptorAspect);

        interceptorAspect = new InterceptorAspectImpl();
        interceptorAspect.setAspectClass(AbstractFooInterceptor.class);
        interceptorAspect.setParameters(params);
        interceptorAspect.setPrecedence(2);
        interceptorAspect.setPointcut(Pointcuts.byRegexp(Target.class.getName(), "anotherFoo()"));
        runtime.addInterceptor(interceptorAspect);

        interceptorAspect = new InterceptorAspectImpl();
        interceptorAspect.setAspectClass(FooInterceptor.class);
        interceptorAspect.setParameters(params);
        interceptorAspect.setPrecedence(3);
        interceptorAspect.setPointcut(Pointcuts.byRegexp(Target.class.getName(), "anotherFoo()"));
        runtime.addInterceptor(interceptorAspect);

        target = (Target) runtime.newInstance(Target.class);
    }
}
