package org.mockitoutil; import java.util.concurrent.atomic.AtomicBoolean; import org.assertj.core.api.Assertions; import org.junit.Test; import org.mockito.Mockito; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import static org.mockitoutil.ClassLoaders.currentClassLoader; import static org.mockitoutil.ClassLoaders.excludingClassLoader; import static org.mockitoutil.ClassLoaders.isolatedClassLoader; import static org.mockitoutil.ClassLoaders.jdkClassLoader; public class ClassLoadersTest { public static final String CLASS_NAME_DEPENDING_ON_INTERFACE = "org.mockitoutil.ClassLoadersTest$ClassUsingInterface1"; public static final String INTERFACE_NAME = "org.mockitoutil.ClassLoadersTest$Interface1"; @Test(expected = ClassNotFoundException.class) public void isolated_class_loader_cannot_load_classes_when_no_given_prefix() throws Exception { // given ClassLoader cl = isolatedClassLoader().build(); // when cl.loadClass("org.mockito.Mockito"); // then raises CNFE } @Test public void isolated_class_loader_cannot_load_classes_if_no_code_source_path() throws Exception { // given ClassLoader cl = isolatedClassLoader() .withPrivateCopyOf(CLASS_NAME_DEPENDING_ON_INTERFACE) .build(); // when try { cl.loadClass(CLASS_NAME_DEPENDING_ON_INTERFACE); fail(); } catch (ClassNotFoundException e) { // then assertThat(e).hasMessageContaining(CLASS_NAME_DEPENDING_ON_INTERFACE); } } @Test public void isolated_class_loader_cannot_load_classes_if_dependent_classes_do_not_match_the_prefixes() throws Exception { // given ClassLoader cl = isolatedClassLoader() .withCurrentCodeSourceUrls() .withPrivateCopyOf(CLASS_NAME_DEPENDING_ON_INTERFACE) .build(); // when try { cl.loadClass(CLASS_NAME_DEPENDING_ON_INTERFACE); fail(); } catch (NoClassDefFoundError e) { // then assertThat(e).hasMessageContaining("org/mockitoutil/ClassLoadersTest$Interface1"); } } @Test public void isolated_class_loader_can_load_classes_when_dependent_classes_are_matching_the_prefixes() throws Exception { // given ClassLoader cl = isolatedClassLoader() .withCurrentCodeSourceUrls() .withPrivateCopyOf(CLASS_NAME_DEPENDING_ON_INTERFACE) .withPrivateCopyOf(INTERFACE_NAME) .build(); // when Class aClass = cl.loadClass(CLASS_NAME_DEPENDING_ON_INTERFACE); // then assertThat(aClass).isNotNull(); assertThat(aClass.getClassLoader()).isEqualTo(cl); assertThat(aClass.getInterfaces()[0].getClassLoader()).isEqualTo(cl); } @Test public void isolated_class_loader_can_load_classes_isolated_classes_in_isolation() throws Exception { // given ClassLoader cl = isolatedClassLoader() .withCurrentCodeSourceUrls() .withPrivateCopyOf(ClassLoadersTest.class.getPackage().getName()) .build(); // when Class aClass = cl.loadClass(AClass.class.getName()); // then assertThat(aClass).isNotNull(); assertThat(aClass).isNotSameAs(AClass.class); assertThat(aClass.getClassLoader()).isEqualTo(cl); } @Test public void isolated_class_loader_cannot_load_classes_if_prefix_excluded() throws Exception { // given ClassLoader cl = isolatedClassLoader() .withCurrentCodeSourceUrls() .withPrivateCopyOf(ClassLoadersTest.class.getPackage().getName()) .without(AClass.class.getName()) .build(); // when try { cl.loadClass(AClass.class.getName()); fail(); } catch (ClassNotFoundException e) { // then assertThat(e).hasMessageContaining("org.mockitoutil") .hasMessageContaining(AClass.class.getName()); } } @Test public void isolated_class_loader_has_no_parent() throws Exception { ClassLoader cl = isolatedClassLoader() .withCurrentCodeSourceUrls() .withPrivateCopyOf(CLASS_NAME_DEPENDING_ON_INTERFACE) .withPrivateCopyOf(INTERFACE_NAME) .build(); assertThat(cl.getParent()).isNull(); } @Test(expected = ClassNotFoundException.class) public void excluding_class_loader_cannot_load_classes_when_no_correct_source_url_set() throws Exception { // given ClassLoader cl = excludingClassLoader() .withCodeSourceUrlOf(this.getClass()) .build(); // when cl.loadClass("org.mockito.Mockito"); // then class CNFE } @Test public void excluding_class_loader_can_load_classes_when_correct_source_url_set() throws Exception { // given ClassLoader cl = excludingClassLoader() .withCodeSourceUrlOf(Mockito.class) .build(); // when cl.loadClass("org.mockito.Mockito"); // then class successfully loaded } @Test public void excluding_class_loader_cannot_load_class_when_excluded_prefix_match_class_to_load() throws Exception { // given ClassLoader cl = excludingClassLoader() .withCodeSourceUrlOf(Mockito.class) .without("org.mockito.BDDMockito") .build(); cl.loadClass("org.mockito.Mockito"); // when try { cl.loadClass("org.mockito.BDDMockito"); fail("should have raise a ClassNotFoundException"); } catch (ClassNotFoundException e) { assertThat(e.getMessage()).contains("org.mockito.BDDMockito"); } // then class successfully loaded } @Test public void can_not_load_a_class_not_previously_registered_in_builder() throws Exception { // given ClassLoader cl = ClassLoaders .inMemoryClassLoader() .withClassDefinition("yop.Dude", SimpleClassGenerator.makeMarkerInterface("yop.Dude")) .build(); // when try { cl.loadClass("not.Defined"); fail(); } catch (ClassNotFoundException e) { // then assertThat(e.getMessage()).contains("not.Defined"); } } @Test public void can_load_a_class_in_memory_from_bytes() throws Exception { // given ClassLoader cl = ClassLoaders .inMemoryClassLoader() .withClassDefinition("yop.Dude", SimpleClassGenerator.makeMarkerInterface("yop.Dude")) .build(); // when Class aClass = cl.loadClass("yop.Dude"); // then assertThat(aClass).isNotNull(); assertThat(aClass.getClassLoader()).isEqualTo(cl); assertThat(aClass.getName()).isEqualTo("yop.Dude"); } @Test public void cannot_load_a_class_file_not_in_parent() throws Exception { // given ClassLoader cl = ClassLoaders .inMemoryClassLoader() .withParent(jdkClassLoader()) .build(); cl.loadClass("java.lang.String"); try { // when cl.loadClass("org.mockito.Mockito"); fail("should have not found Mockito class"); } catch (ClassNotFoundException e) { // then assertThat(e.getMessage()).contains("org.mockito.Mockito"); } } @Test public void can_list_all_classes_reachable_in_a_classloader() throws Exception { ClassLoader classLoader = ClassLoaders.inMemoryClassLoader() .withParent(jdkClassLoader()) .withClassDefinition("a.A", SimpleClassGenerator.makeMarkerInterface("a.A")) .withClassDefinition("a.b.B", SimpleClassGenerator.makeMarkerInterface("a.b.B")) .withClassDefinition("c.C", SimpleClassGenerator.makeMarkerInterface("c.C")) // .withCodeSourceUrlOf(ClassLoaders.class) .build(); assertThat(ClassLoaders.in(classLoader).listOwnedClasses()).containsOnly("a.A", "a.b.B", "c.C"); assertThat(ClassLoaders.in(classLoader).omit("b", "c").listOwnedClasses()).containsOnly("a.A"); } @Test public void return_bootstrap_classloader() throws Exception { assertThat(jdkClassLoader()).isNotEqualTo(Mockito.class.getClassLoader()); assertThat(jdkClassLoader()).isNotEqualTo(ClassLoaders.class.getClassLoader()); assertThat(jdkClassLoader()).isEqualTo(Number.class.getClassLoader()); assertThat(jdkClassLoader()).isEqualTo(null); } @Test public void return_current_classloader() throws Exception { assertThat(currentClassLoader()).isEqualTo(this.getClass().getClassLoader()); } @Test public void can_run_in_given_classloader() throws Exception { // given final ClassLoader cl = isolatedClassLoader() .withCurrentCodeSourceUrls() .withCodeSourceUrlOf(Assertions.class) .withPrivateCopyOf("org.assertj.core") .withPrivateCopyOf(ClassLoadersTest.class.getPackage().getName()) .without(AClass.class.getName()) .build(); final AtomicBoolean executed = new AtomicBoolean(false); // when ClassLoaders.using(cl).execute(new Runnable() { @Override public void run() { assertThat(this.getClass().getClassLoader()).describedAs("runnable is reloaded in given classloader").isEqualTo(cl); assertThat(Thread.currentThread().getContextClassLoader()).describedAs("Thread context classloader is using given classloader").isEqualTo(cl); try { assertThat(Thread.currentThread() .getContextClassLoader() .loadClass("java.lang.String")) .describedAs("can load JDK type") .isNotNull(); assertThat(Thread.currentThread() .getContextClassLoader() .loadClass("org.mockitoutil.ClassLoadersTest$ClassUsingInterface1")) .describedAs("can load classloader types") .isNotNull(); } catch (ClassNotFoundException cnfe) { Assertions.fail("should not have raised a CNFE", cnfe); } executed.set(true); } }); // then assertThat(executed.get()).isEqualTo(true); } @Test public void cannot_load_runnable_in_given_classloader_if_some_type_cant_be_loaded() throws Exception { // given final ClassLoader cl = isolatedClassLoader() .withCurrentCodeSourceUrls() .withPrivateCopyOf(ClassLoadersTest.class.getPackage().getName()) .without(AClass.class.getName()) .build(); // when try { ClassLoaders.using(cl).execute(new Runnable() { @Override public void run() { AClass cant_be_found = new AClass(); } }); Assertions.fail("should have raised a ClassNotFoundException"); } catch (IllegalStateException ise) { // then assertThat(ise).hasCauseInstanceOf(NoClassDefFoundError.class) .hasMessageContaining("AClass"); } } @SuppressWarnings("unused") static class AClass { } @SuppressWarnings("unused") static class ClassUsingInterface1 implements Interface1 { } @SuppressWarnings("unused") interface Interface1 { } }