package ru.vyarus.guice.ext.generator;
import com.google.inject.*;
import com.google.inject.matcher.Matchers;
import org.junit.Assert;
import org.junit.Test;
import ru.vyarus.guice.ext.core.generator.DynamicClassException;
import ru.vyarus.guice.ext.core.generator.DynamicClassGenerator;
import ru.vyarus.guice.ext.generator.support.*;
import ru.vyarus.guice.ext.generator.support.aop.CustomAop;
import ru.vyarus.guice.ext.generator.support.aop.CustomAopInterceptor;
import ru.vyarus.guice.ext.generator.support.bad.BadDeclarationBean;
import ru.vyarus.guice.ext.generator.support.bad.BadSingletonDeclaration;
import ru.vyarus.guice.ext.generator.support.bad.WrongUsageBean;
import ru.vyarus.guice.ext.generator.support.composite.CompositeCase1;
import ru.vyarus.guice.ext.generator.support.composite.CompositeCase2;
import ru.vyarus.guice.ext.generator.support.ctor.Ann;
import ru.vyarus.guice.ext.generator.support.ctor.CustomConstructorBean;
import ru.vyarus.guice.ext.generator.support.ctor.GenerifiedConstructorBean;
import javax.inject.Singleton;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author Vyacheslav Rusakov
* @since 10.12.2014
*/
public class GeneratorTest {
@Test
public void testClassGenerationCached() throws Exception {
Class cl1 = DynamicClassGenerator.generate(InterfaceBean.class);
// this time class should not be generated
Class cl2 = DynamicClassGenerator.generate(InterfaceBean.class);
assertTrue(cl1 == cl2);
}
@Test
public void testDirectRegistration() throws Exception {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(InterfaceBean.class).to(DynamicClassGenerator.generate(InterfaceBean.class));
bind(AbstractBean.class).to(DynamicClassGenerator.generate(AbstractBean.class));
}
});
injector.getInstance(InterfaceBean.class);
injector.getInstance(AbstractBean.class);
}
@Test
public void testIndirectRegistration() throws Exception {
Injector injector = Guice.createInjector(new AbstractModule() {
@SuppressWarnings("PointlessBinding")
@Override
protected void configure() {
bind(ProvidedInterfaceBean.class);
bind(ProvidedAbstractBean.class);
}
});
injector.getInstance(ProvidedInterfaceBean.class);
injector.getInstance(ProvidedAbstractBean.class);
}
@Test
public void testJITResolution() throws Exception {
Injector injector = Guice.createInjector();
injector.getInstance(ProvidedInterfaceBean.class);
injector.getInstance(ProvidedAbstractBean.class);
}
@Test
public void testAnnotationPropagation() throws Exception {
Injector injector = Guice.createInjector();
ProvidedInterfaceBean interfaceInstance = injector.getInstance(ProvidedInterfaceBean.class);
ProvidedAbstractBean beanInstance = injector.getInstance(ProvidedAbstractBean.class);
// singleton scope declared on interface and propagated
assertEquals(interfaceInstance, injector.getInstance(ProvidedInterfaceBean.class));
// no scope definition - prototype
Assert.assertNotEquals(beanInstance, injector.getInstance(ProvidedAbstractBean.class));
}
@Test
public void testAnnotationCopyCorrectness() throws Exception {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(InterfaceBean.class).to(DynamicClassGenerator.generate(InterfaceBean.class));
}
});
InterfaceBean bean = injector.getInstance(InterfaceBean.class);
AnnotationCheck ann = bean.getClass().getAnnotation(AnnotationCheck.class);
assertTrue(ann.ann().value() == Singleton.class);
assertTrue(Arrays.equals(ann.arr(), new int[]{1, 2, 3}));
assertTrue(Arrays.equals(ann.arrBool(), new boolean[]{true, false}));
assertTrue(Arrays.equals(ann.arrByte(), new byte[]{1, 2}));
assertTrue(Arrays.equals(ann.arrChar(), new char[]{',', 'l'}));
assertTrue(Arrays.equals(ann.arrDbl(), new double[]{0.1, 0.2}));
assertTrue(Arrays.equals(ann.arrFlt(), new float[]{0.1f, 0.2f}));
assertTrue(Arrays.equals(ann.arrLng(), new long[]{1l, 2l}));
assertTrue(Arrays.equals(ann.arrObj(), new String[]{"tst", "tst2"}));
assertTrue(ann.bool());
assertTrue(ann.bte() == 1);
assertTrue(ann.chr() == ',');
assertTrue(ann.dbl() == 1d);
assertTrue(ann.integer() == 1);
assertTrue(ann.lng() == 1l);
assertTrue(ann.flt() == 1f);
assertTrue(ann.srt() == 1);
assertTrue(ann.str().equals("string"));
assertTrue(ann.cls() == InterfaceBean.class);
assertTrue(ann.enm() == ElementType.TYPE);
}
@Test(expected = DynamicClassException.class)
public void testDirectScopeAnnotation() throws Exception {
// scope annotation can't be used directly
DynamicClassGenerator.generate(BadDeclarationBean.class);
}
@Test
public void testAop() throws Exception {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bind(InterfaceBean.class).to(DynamicClassGenerator.generate(InterfaceBean.class));
bind(AbstractBean.class).to(DynamicClassGenerator.generate(AbstractBean.class));
bindInterceptor(Matchers.any(), Matchers.annotatedWith(CustomAop.class), new CustomAopInterceptor());
}
});
injector.getInstance(InterfaceBean.class).hello();
injector.getInstance(AbstractBean.class).hello();
injector.getInstance(ProvidedInterfaceBean.class).hello();
injector.getInstance(ProvidedAbstractBean.class).hello();
}
@Test(expected = AbstractMethodError.class)
public void testNoAopCall() throws Exception {
Guice.createInjector().getInstance(ProvidedInterfaceBean.class).badMethod();
}
@Test
public void testCompositeCases() throws Exception {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(CustomAop.class), new CustomAopInterceptor());
}
});
CompositeCase1 case1 = injector.getInstance(CompositeCase1.class);
CompositeCase2 case2 = injector.getInstance(CompositeCase2.class);
case1.self();
case1.hello();
case2.self();
case2.hello();
}
@Test(expected = ProvisionException.class)
public void testWrongProviderUsage() throws Exception {
Guice.createInjector().getInstance(WrongUsageBean.class);
}
@Test
@SuppressWarnings("unchecked")
public void testCustomConstructor() throws Exception {
// original type constructor copied and constructor injection correctly handled
Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(CustomAop.class), new CustomAopInterceptor());
}
}).getInstance(CustomConstructorBean.class).hello();
Class<?> generated = DynamicClassGenerator.generate(CustomConstructorBean.class);
assertEquals(1, generated.getConstructors().length);
Constructor ctor = generated.getConstructors()[0];
assertTrue(ctor.isAnnotationPresent(Inject.class));
assertTrue(ctor.isAnnotationPresent(Ann.class));
assertEquals("ctor", ((Ann) ctor.getAnnotation(Ann.class)).value());
assertEquals(1, ctor.getExceptionTypes().length);
assertEquals(1, ctor.getParameterAnnotations()[0].length);
Annotation ann = ctor.getParameterAnnotations()[0][0];
assertTrue(ann instanceof Ann);
assertEquals("param", ((Ann) ann).value());
}
@Test
public void testGenerifiedConstructor() throws Exception {
// original type constructor copied and constructor injection correctly handled
Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(CustomAop.class), new CustomAopInterceptor());
}
}).getInstance(GenerifiedConstructorBean.class).hello();
}
@Test
public void testSingletonProvider() throws Exception {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(CustomAop.class), new CustomAopInterceptor());
}
});
GenerifiedConstructorBean bean1 = injector.getInstance(GenerifiedConstructorBean.class);
GenerifiedConstructorBean bean2 = injector.getInstance(GenerifiedConstructorBean.class);
Assert.assertTrue(bean1 == bean2);
}
@Test(expected = ProvisionException.class)
public void testDuplicateSingletonDeclaration() throws Exception {
Guice.createInjector().getInstance(BadSingletonDeclaration.class);
}
}