package org.springframework.config.java.internal;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.junit.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.config.java.annotation.Bean;
import org.springframework.config.java.annotation.Configuration;
import org.springframework.config.java.context.JavaConfigApplicationContext;
import org.springframework.config.java.plugin.aop.AspectJAutoProxy;

import test.common.beans.ITestBean;
import test.common.beans.TestBean;

/**
 * Tests that dynamic attribution of the AspectJ's {@code @Aspect} annotation
 * on @Configuration CGLIB subclasses (and proxies) works as expected.
 * <p/>
 * This support is necessary because {@code @Aspect} is not {@code @Inherited}
 * and we want the container to treat Configuration beans that are marked with @Aspect
 * properly and pick up and apply any advice methods declared within.  Because
 * Configuration classes are subclassed by CGLIB, this doesn't work out of the gate,
 * and we must therefore add {@code @Aspect} on-the-fly to the subclass.
 *
 * @author Chris Beams
 */
public class DynamicAspectAnnotationTests {
    static class Config { }
    
    @Test
    public void doesDynamicAnnotationGetAddedToCglibSubclass() {
        
        JavaConfigApplicationContext ctx =
            new JavaConfigApplicationContext(AspectConfig.class);
        
        Class<? extends Config> aspectConfig = ctx.getBean(Config.class).getClass();
        
        assertTrue("not an instance of a CGLIB-generated class as expected",
                AopUtils.isCglibProxyClass(aspectConfig));
        
        assertTrue("CGLIB subclass does not have @Aspect annotation as expected",
                aspectConfig.isAnnotationPresent(Aspect.class));

        assertThat(((ITestBean)ctx.getBean("alice")).getName(), equalTo("advised"));
    }
    
    @AspectJAutoProxy
    @Aspect
    @Configuration
    static class AspectConfig extends Config {

        @Around("execution(* getName())")
        public String adviseName() {
            return "advised";
        }

        @Bean
        public TestBean alice() {
            return new TestBean("alice");
        }
    }
	    
}
