Home | History | Annotate | Download | only in mockitoutil
      1 /*
      2  * Copyright (c) 2017 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockitoutil;
      6 
      7 import java.util.concurrent.atomic.AtomicBoolean;
      8 import org.assertj.core.api.Assertions;
      9 import org.junit.Test;
     10 import org.mockito.Mockito;
     11 
     12 import static org.assertj.core.api.Assertions.assertThat;
     13 import static org.junit.Assert.fail;
     14 import static org.mockitoutil.ClassLoaders.currentClassLoader;
     15 import static org.mockitoutil.ClassLoaders.excludingClassLoader;
     16 import static org.mockitoutil.ClassLoaders.isolatedClassLoader;
     17 import static org.mockitoutil.ClassLoaders.jdkClassLoader;
     18 
     19 public class ClassLoadersTest {
     20 
     21     public static final String CLASS_NAME_DEPENDING_ON_INTERFACE = "org.mockitoutil.ClassLoadersTest$ClassUsingInterface1";
     22     public static final String INTERFACE_NAME = "org.mockitoutil.ClassLoadersTest$Interface1";
     23 
     24     @Test(expected = ClassNotFoundException.class)
     25     public void isolated_class_loader_cannot_load_classes_when_no_given_prefix() throws Exception {
     26         // given
     27         ClassLoader cl = isolatedClassLoader().build();
     28 
     29         // when
     30         cl.loadClass("org.mockito.Mockito");
     31 
     32         // then raises CNFE
     33     }
     34 
     35     @Test
     36     public void isolated_class_loader_cannot_load_classes_if_no_code_source_path() throws Exception {
     37         // given
     38         ClassLoader cl = isolatedClassLoader()
     39                 .withPrivateCopyOf(CLASS_NAME_DEPENDING_ON_INTERFACE)
     40                 .build();
     41 
     42         // when
     43         try {
     44             cl.loadClass(CLASS_NAME_DEPENDING_ON_INTERFACE);
     45             fail();
     46         } catch (ClassNotFoundException e) {
     47             // then
     48             assertThat(e).hasMessageContaining(CLASS_NAME_DEPENDING_ON_INTERFACE);
     49         }
     50     }
     51 
     52     @Test
     53     public void isolated_class_loader_cannot_load_classes_if_dependent_classes_do_not_match_the_prefixes() throws Exception {
     54         // given
     55         ClassLoader cl = isolatedClassLoader()
     56                 .withCurrentCodeSourceUrls()
     57                 .withPrivateCopyOf(CLASS_NAME_DEPENDING_ON_INTERFACE)
     58                 .build();
     59 
     60         // when
     61         try {
     62             cl.loadClass(CLASS_NAME_DEPENDING_ON_INTERFACE);
     63             fail();
     64         } catch (NoClassDefFoundError e) {
     65             // then
     66             assertThat(e).hasMessageContaining("org/mockitoutil/ClassLoadersTest$Interface1");
     67         }
     68     }
     69 
     70     @Test
     71     public void isolated_class_loader_can_load_classes_when_dependent_classes_are_matching_the_prefixes() throws Exception {
     72         // given
     73         ClassLoader cl = isolatedClassLoader()
     74                 .withCurrentCodeSourceUrls()
     75                 .withPrivateCopyOf(CLASS_NAME_DEPENDING_ON_INTERFACE)
     76                 .withPrivateCopyOf(INTERFACE_NAME)
     77                 .build();
     78 
     79         // when
     80         Class<?> aClass = cl.loadClass(CLASS_NAME_DEPENDING_ON_INTERFACE);
     81 
     82         // then
     83         assertThat(aClass).isNotNull();
     84         assertThat(aClass.getClassLoader()).isEqualTo(cl);
     85         assertThat(aClass.getInterfaces()[0].getClassLoader()).isEqualTo(cl);
     86     }
     87 
     88     @Test
     89     public void isolated_class_loader_can_load_classes_isolated_classes_in_isolation() throws Exception {
     90         // given
     91         ClassLoader cl = isolatedClassLoader()
     92                 .withCurrentCodeSourceUrls()
     93                 .withPrivateCopyOf(ClassLoadersTest.class.getPackage().getName())
     94                 .build();
     95 
     96         // when
     97         Class<?> aClass = cl.loadClass(AClass.class.getName());
     98 
     99         // then
    100         assertThat(aClass).isNotNull();
    101         assertThat(aClass).isNotSameAs(AClass.class);
    102         assertThat(aClass.getClassLoader()).isEqualTo(cl);
    103     }
    104 
    105     @Test
    106     public void isolated_class_loader_cannot_load_classes_if_prefix_excluded() throws Exception {
    107         // given
    108         ClassLoader cl = isolatedClassLoader()
    109                 .withCurrentCodeSourceUrls()
    110                 .withPrivateCopyOf(ClassLoadersTest.class.getPackage().getName())
    111                 .without(AClass.class.getName())
    112                 .build();
    113 
    114         // when
    115         try {
    116             cl.loadClass(AClass.class.getName());
    117             fail();
    118         } catch (ClassNotFoundException e) {
    119             // then
    120             assertThat(e).hasMessageContaining("org.mockitoutil")
    121                          .hasMessageContaining(AClass.class.getName());
    122         }
    123     }
    124 
    125     @Test
    126     public void isolated_class_loader_has_no_parent() throws Exception {
    127         ClassLoader cl = isolatedClassLoader()
    128                 .withCurrentCodeSourceUrls()
    129                 .withPrivateCopyOf(CLASS_NAME_DEPENDING_ON_INTERFACE)
    130                 .withPrivateCopyOf(INTERFACE_NAME)
    131                 .build();
    132 
    133         assertThat(cl.getParent()).isNull();
    134     }
    135 
    136     @Test(expected = ClassNotFoundException.class)
    137     public void excluding_class_loader_cannot_load_classes_when_no_correct_source_url_set() throws Exception {
    138         // given
    139         ClassLoader cl = excludingClassLoader()
    140                 .withCodeSourceUrlOf(this.getClass())
    141                 .build();
    142 
    143         // when
    144         cl.loadClass("org.mockito.Mockito");
    145 
    146         // then class CNFE
    147     }
    148 
    149     @Test
    150     public void excluding_class_loader_can_load_classes_when_correct_source_url_set() throws Exception {
    151         // given
    152         ClassLoader cl = excludingClassLoader()
    153                 .withCodeSourceUrlOf(Mockito.class)
    154                 .build();
    155 
    156         // when
    157         cl.loadClass("org.mockito.Mockito");
    158 
    159         // then class successfully loaded
    160     }
    161 
    162     @Test
    163     public void excluding_class_loader_cannot_load_class_when_excluded_prefix_match_class_to_load() throws Exception {
    164         // given
    165         ClassLoader cl = excludingClassLoader()
    166                 .withCodeSourceUrlOf(Mockito.class)
    167                 .without("org.mockito.BDDMockito")
    168                 .build();
    169 
    170         cl.loadClass("org.mockito.Mockito");
    171 
    172         // when
    173         try {
    174             cl.loadClass("org.mockito.BDDMockito");
    175             fail("should have raise a ClassNotFoundException");
    176         } catch (ClassNotFoundException e) {
    177             assertThat(e.getMessage()).contains("org.mockito.BDDMockito");
    178         }
    179 
    180         // then class successfully loaded
    181     }
    182 
    183     @Test
    184     public void can_not_load_a_class_not_previously_registered_in_builder() throws Exception {
    185         // given
    186         ClassLoader cl = ClassLoaders
    187                 .inMemoryClassLoader()
    188                 .withClassDefinition("yop.Dude", SimpleClassGenerator.makeMarkerInterface("yop.Dude"))
    189                 .build();
    190 
    191         // when
    192         try {
    193             cl.loadClass("not.Defined");
    194             fail();
    195         } catch (ClassNotFoundException e) {
    196             // then
    197             assertThat(e.getMessage()).contains("not.Defined");
    198         }
    199     }
    200 
    201     @Test
    202     public void can_load_a_class_in_memory_from_bytes() throws Exception {
    203         // given
    204         ClassLoader cl = ClassLoaders
    205                 .inMemoryClassLoader()
    206                 .withClassDefinition("yop.Dude", SimpleClassGenerator.makeMarkerInterface("yop.Dude"))
    207                 .build();
    208 
    209         // when
    210         Class<?> aClass = cl.loadClass("yop.Dude");
    211 
    212         // then
    213         assertThat(aClass).isNotNull();
    214         assertThat(aClass.getClassLoader()).isEqualTo(cl);
    215         assertThat(aClass.getName()).isEqualTo("yop.Dude");
    216     }
    217 
    218     @Test
    219     public void cannot_load_a_class_file_not_in_parent() throws Exception {
    220         // given
    221         ClassLoader cl = ClassLoaders
    222                 .inMemoryClassLoader()
    223                 .withParent(jdkClassLoader())
    224                 .build();
    225 
    226         cl.loadClass("java.lang.String");
    227 
    228         try {
    229             // when
    230             cl.loadClass("org.mockito.Mockito");
    231             fail("should have not found Mockito class");
    232         } catch (ClassNotFoundException e) {
    233             // then
    234             assertThat(e.getMessage()).contains("org.mockito.Mockito");
    235         }
    236     }
    237 
    238     @Test
    239     public void can_list_all_classes_reachable_in_a_classloader() throws Exception {
    240         ClassLoader classLoader = ClassLoaders.inMemoryClassLoader()
    241                                               .withParent(jdkClassLoader())
    242                                               .withClassDefinition("a.A", SimpleClassGenerator.makeMarkerInterface("a.A"))
    243                                               .withClassDefinition("a.b.B", SimpleClassGenerator.makeMarkerInterface("a.b.B"))
    244                                               .withClassDefinition("c.C", SimpleClassGenerator.makeMarkerInterface("c.C"))
    245 //                .withCodeSourceUrlOf(ClassLoaders.class)
    246                                               .build();
    247 
    248         assertThat(ClassLoaders.in(classLoader).listOwnedClasses()).containsOnly("a.A", "a.b.B", "c.C");
    249         assertThat(ClassLoaders.in(classLoader).omit("b", "c").listOwnedClasses()).containsOnly("a.A");
    250     }
    251 
    252     @Test
    253     public void return_bootstrap_classloader() throws Exception {
    254         assertThat(jdkClassLoader()).isNotEqualTo(Mockito.class.getClassLoader());
    255         assertThat(jdkClassLoader()).isNotEqualTo(ClassLoaders.class.getClassLoader());
    256         assertThat(jdkClassLoader()).isEqualTo(Number.class.getClassLoader());
    257         assertThat(jdkClassLoader()).isEqualTo(null);
    258     }
    259 
    260     @Test
    261     public void return_current_classloader() throws Exception {
    262         assertThat(currentClassLoader()).isEqualTo(this.getClass().getClassLoader());
    263     }
    264 
    265     @Test
    266     public void can_run_in_given_classloader() throws Exception {
    267         // given
    268         final ClassLoader cl = isolatedClassLoader()
    269                 .withCurrentCodeSourceUrls()
    270                 .withCodeSourceUrlOf(Assertions.class)
    271                 .withPrivateCopyOf("org.assertj.core")
    272                 .withPrivateCopyOf(ClassLoadersTest.class.getPackage().getName())
    273                 .without(AClass.class.getName())
    274                 .build();
    275 
    276         final AtomicBoolean executed = new AtomicBoolean(false);
    277 
    278         // when
    279         ClassLoaders.using(cl).execute(new Runnable() {
    280             @Override
    281             public void run() {
    282                 assertThat(this.getClass().getClassLoader()).describedAs("runnable is reloaded in given classloader").isEqualTo(cl);
    283                 assertThat(Thread.currentThread().getContextClassLoader()).describedAs("Thread context classloader is using given classloader").isEqualTo(cl);
    284 
    285                 try {
    286                     assertThat(Thread.currentThread()
    287                                      .getContextClassLoader()
    288                                      .loadClass("java.lang.String"))
    289                             .describedAs("can load JDK type")
    290                             .isNotNull();
    291                     assertThat(Thread.currentThread()
    292                                      .getContextClassLoader()
    293                                      .loadClass("org.mockitoutil.ClassLoadersTest$ClassUsingInterface1"))
    294                             .describedAs("can load classloader types")
    295                             .isNotNull();
    296                 } catch (ClassNotFoundException cnfe) {
    297                     Assertions.fail("should not have raised a CNFE", cnfe);
    298                 }
    299                 executed.set(true);
    300             }
    301         });
    302 
    303         // then
    304         assertThat(executed.get()).isEqualTo(true);
    305     }
    306 
    307 
    308     @Test
    309     public void cannot_load_runnable_in_given_classloader_if_some_type_cant_be_loaded() throws Exception {
    310         // given
    311         final ClassLoader cl = isolatedClassLoader()
    312                 .withCurrentCodeSourceUrls()
    313                 .withPrivateCopyOf(ClassLoadersTest.class.getPackage().getName())
    314                 .without(AClass.class.getName())
    315                 .build();
    316 
    317         // when
    318         try {
    319             ClassLoaders.using(cl).execute(new Runnable() {
    320                 @Override
    321                 public void run() {
    322                     AClass cant_be_found = new AClass();
    323                 }
    324             });
    325             Assertions.fail("should have raised a ClassNotFoundException");
    326         } catch (IllegalStateException ise) {
    327             // then
    328             assertThat(ise).hasCauseInstanceOf(NoClassDefFoundError.class)
    329                            .hasMessageContaining("AClass");
    330         }
    331     }
    332 
    333     @SuppressWarnings("unused")
    334     static class AClass {
    335     }
    336 
    337     @SuppressWarnings("unused")
    338     static class ClassUsingInterface1 implements Interface1 {
    339     }
    340 
    341     @SuppressWarnings("unused")
    342     interface Interface1 {
    343     }
    344 }
    345