package net.bytebuddy.dynamic;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.scaffold.TypeInitializer;
import net.bytebuddy.implementation.LoadedTypeInitializer;
import net.bytebuddy.test.utility.MockitoRule;
import net.bytebuddy.test.utility.ObjectPropertyAssertion;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.mockito.Mock;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Map;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.*;
public class TypeResolutionStrategyTest {
private static final byte[] FOO = new byte[]{1, 2, 3};
@Rule
public TestRule mockitoRule = new MockitoRule(this);
@Mock
private TypeInitializer typeInitializer, otherTypeInitializer;
@Mock
private DynamicType dynamicType;
@Mock
private ClassLoader classLoader;
@Mock
private ClassLoadingStrategy<ClassLoader> classLoadingStrategy;
@Mock
private TypeDescription typeDescription;
@Mock
private LoadedTypeInitializer loadedTypeInitializer;
@Before
public void setUp() throws Exception {
when(dynamicType.getTypeDescription()).thenReturn(typeDescription);
when(dynamicType.getAllTypes()).thenReturn(Collections.singletonMap(typeDescription, FOO));
when(dynamicType.getLoadedTypeInitializers()).thenReturn(Collections.singletonMap(typeDescription, loadedTypeInitializer));
when(classLoadingStrategy.load(classLoader, Collections.singletonMap(typeDescription, FOO)))
.thenReturn(Collections.<TypeDescription, Class<?>>singletonMap(typeDescription, Foo.class));
when(loadedTypeInitializer.isAlive()).thenReturn(true);
when(typeDescription.getName()).thenReturn(Foo.class.getName());
}
@Test
public void testPassive() throws Exception {
TypeResolutionStrategy.Resolved resolved = TypeResolutionStrategy.Passive.INSTANCE.resolve();
assertThat(resolved.injectedInto(typeInitializer), is(typeInitializer));
assertThat(resolved.initialize(dynamicType, classLoader, classLoadingStrategy),
is(Collections.<TypeDescription, Class<?>>singletonMap(typeDescription, Foo.class)));
verify(classLoadingStrategy).load(classLoader, Collections.singletonMap(typeDescription, FOO));
verifyNoMoreInteractions(classLoadingStrategy);
verify(loadedTypeInitializer).onLoad(Foo.class);
verifyNoMoreInteractions(loadedTypeInitializer);
}
@Test
public void testActive() throws Exception {
TypeResolutionStrategy.Resolved resolved = new TypeResolutionStrategy.Active().resolve();
Field field = TypeResolutionStrategy.Active.Resolved.class.getDeclaredField("identification");
field.setAccessible(true);
int identification = (Integer) field.get(resolved);
when(typeInitializer.expandWith(new NexusAccessor.InitializationAppender(identification))).thenReturn(otherTypeInitializer);
assertThat(resolved.injectedInto(typeInitializer), is(otherTypeInitializer));
assertThat(resolved.initialize(dynamicType, classLoader, classLoadingStrategy),
is(Collections.<TypeDescription, Class<?>>singletonMap(typeDescription, Foo.class)));
try {
verify(classLoadingStrategy).load(classLoader, Collections.singletonMap(typeDescription, FOO));
verifyNoMoreInteractions(classLoadingStrategy);
verify(loadedTypeInitializer).isAlive();
verifyNoMoreInteractions(loadedTypeInitializer);
} finally {
Field initializers = Nexus.class.getDeclaredField("TYPE_INITIALIZERS");
initializers.setAccessible(true);
Constructor<Nexus> constructor = Nexus.class.getDeclaredConstructor(String.class, ClassLoader.class, ReferenceQueue.class, int.class);
constructor.setAccessible(true);
Object value = ((Map<?, ?>) initializers.get(null)).remove(constructor.newInstance(Foo.class.getName(), Foo.class.getClassLoader(), null, identification));
assertThat(value, CoreMatchers.is((Object) loadedTypeInitializer));
}
}
@Test
public void testLazy() throws Exception {
TypeResolutionStrategy.Resolved resolved = TypeResolutionStrategy.Lazy.INSTANCE.resolve();
assertThat(resolved.injectedInto(typeInitializer), is(typeInitializer));
assertThat(resolved.initialize(dynamicType, classLoader, classLoadingStrategy),
is(Collections.<TypeDescription, Class<?>>singletonMap(typeDescription, Foo.class)));
verify(classLoadingStrategy).load(classLoader, Collections.singletonMap(typeDescription, FOO));
verifyNoMoreInteractions(classLoadingStrategy);
verifyNoMoreInteractions(loadedTypeInitializer);
}
@Test
public void testDisabled() throws Exception {
TypeResolutionStrategy.Resolved resolved = TypeResolutionStrategy.Disabled.INSTANCE.resolve();
assertThat(resolved.injectedInto(typeInitializer), is(typeInitializer));
}
@Test(expected = IllegalStateException.class)
public void testDisabledCannotBeApplied() throws Exception {
TypeResolutionStrategy.Disabled.INSTANCE.resolve().initialize(dynamicType, classLoader, classLoadingStrategy);
}
@Test
public void testObjectProperties() throws Exception {
ObjectPropertyAssertion.of(TypeResolutionStrategy.Active.class).apply();
ObjectPropertyAssertion.of(TypeResolutionStrategy.Active.Resolved.class).apply();
ObjectPropertyAssertion.of(TypeResolutionStrategy.Passive.class).apply();
ObjectPropertyAssertion.of(TypeResolutionStrategy.Lazy.class).apply();
ObjectPropertyAssertion.of(TypeResolutionStrategy.Disabled.class).apply();
}
private static class Foo {
/* empty */
}
}