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