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