ReferenceTest.java revision e978e33deb1f7fbf5f6e81ed9948b303b8493ed3
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17package tests.api.java.lang.ref; 18 19import dalvik.annotation.TestTargets; 20import dalvik.annotation.TestLevel; 21import dalvik.annotation.TestTargetNew; 22import dalvik.annotation.TestTargetClass; 23 24import junit.framework.AssertionFailedError; 25 26import java.lang.ref.PhantomReference; 27import java.lang.ref.Reference; 28import java.lang.ref.ReferenceQueue; 29import java.lang.ref.SoftReference; 30import java.lang.ref.WeakReference; 31import java.util.Vector; 32 33@TestTargetClass(Reference.class) 34public class ReferenceTest extends junit.framework.TestCase { 35 Object tmpA, tmpB, tmpC, obj; 36 37 volatile Reference r; 38 39 /* 40 * For test_subclass(). 41 */ 42 static TestWeakReference twr; 43 static AssertionFailedError error; 44 static boolean testObjectFinalized; 45 static class TestWeakReference<T> extends WeakReference<T> { 46 public volatile boolean clearSeen = false; 47 public volatile boolean enqueueSeen = false; 48 49 public TestWeakReference(T referent) { 50 super(referent); 51 } 52 53 public TestWeakReference(T referent, ReferenceQueue<? super T> q) { 54 super(referent, q); 55 } 56 57 public void clear() { 58 clearSeen = true; 59 if (testObjectFinalized) { 60 error = new AssertionFailedError("Clear should happen " + 61 "before finalization."); 62 throw error; 63 } 64 if (enqueueSeen) { 65 error = new AssertionFailedError("Clear should happen " + 66 "before enqueue."); 67 throw error; 68 } 69 super.clear(); 70 } 71 72 public boolean enqueue() { 73 enqueueSeen = true; 74 if (!clearSeen) { 75 error = new AssertionFailedError("Clear should happen " + 76 "before enqueue."); 77 throw error; 78 } 79 80 /* Do this last; it may notify the main test thread, 81 * and anything we'd do after it (e.g., setting clearSeen) 82 * wouldn't be seen. 83 */ 84 return super.enqueue(); 85 } 86 } 87 88 protected void doneSuite() { 89 tmpA = tmpB = obj = null; 90 } 91 92 /** 93 * @tests java.lang.ref.Reference#clear() 94 */ 95 @TestTargetNew( 96 level = TestLevel.COMPLETE, 97 notes = "", 98 method = "clear", 99 args = {} 100 ) 101 public void test_clear() { 102 tmpA = new Object(); 103 tmpB = new Object(); 104 tmpC = new Object(); 105 SoftReference sr = new SoftReference(tmpA, new ReferenceQueue()); 106 WeakReference wr = new WeakReference(tmpB, new ReferenceQueue()); 107 PhantomReference pr = new PhantomReference(tmpC, new ReferenceQueue()); 108 assertTrue("Start: Object not cleared.", (sr.get() != null) 109 && (wr.get() != null)); 110 assertNull("Referent is not null.", pr.get()); 111 sr.clear(); 112 wr.clear(); 113 pr.clear(); 114 assertTrue("End: Object cleared.", (sr.get() == null) 115 && (wr.get() == null)); 116 assertNull("Referent is not null.", pr.get()); 117 // Must reference tmpA and tmpB so the jit does not optimize them away 118 assertTrue("should always pass", tmpA != sr.get() && tmpB != wr.get()); 119 } 120 121 /** 122 * @tests java.lang.ref.Reference#enqueue() 123 */ 124 @TestTargets({ 125 @TestTargetNew( 126 level = TestLevel.COMPLETE, 127 notes = "", 128 method = "enqueue", 129 args = {} 130 ), 131 @TestTargetNew( 132 level = TestLevel.COMPLETE, 133 notes = "", 134 method = "isEnqueued", 135 args = {} 136 ) 137 }) 138 public void test_enqueue() { 139 ReferenceQueue rq = new ReferenceQueue(); 140 obj = new Object(); 141 Reference ref = new SoftReference(obj, rq); 142 assertTrue("Enqueue failed.", (!ref.isEnqueued()) 143 && ((ref.enqueue()) && (ref.isEnqueued()))); 144 assertTrue("Not properly enqueued.", rq.poll().get() == obj); 145 // This fails... 146 assertTrue("Should remain enqueued.", !ref.isEnqueued()); 147 assertTrue("Can not enqueue twice.", (!ref.enqueue()) 148 && (rq.poll() == null)); 149 150 rq = new ReferenceQueue(); 151 obj = new Object(); 152 153 ref = new WeakReference(obj, rq); 154 assertTrue("Enqueue failed2.", (!ref.isEnqueued()) 155 && ((ref.enqueue()) && (ref.isEnqueued()))); 156 assertTrue("Not properly enqueued2.", rq.poll().get() == obj); 157 assertTrue("Should remain enqueued2.", !ref.isEnqueued()); // This 158 // fails. 159 assertTrue("Can not enqueue twice2.", (!ref.enqueue()) 160 && (rq.poll() == null)); 161 162 ref = new PhantomReference(obj, rq); 163 assertTrue("Enqueue failed3.", (!ref.isEnqueued()) 164 && ((ref.enqueue()) && (ref.isEnqueued()))); 165 assertNull("Not properly enqueued3.", rq.poll().get()); 166 assertTrue("Should remain enqueued3.", !ref.isEnqueued()); // This 167 // fails. 168 assertTrue("Can not enqueue twice3.", (!ref.enqueue()) 169 && (rq.poll() == null)); 170 } 171 172 /** 173 * @tests java.lang.ref.Reference#enqueue() 174 */ 175 @TestTargetNew( 176 level = TestLevel.PARTIAL_COMPLETE, 177 notes = "Verifies positive functionality for WeakReference.", 178 method = "get", 179 args = {} 180 ) 181 public void test_get_WeakReference() { 182 // Test the general/overall functionality of Reference. 183 184 class TestObject { 185 public boolean finalized; 186 187 public TestObject() { 188 finalized = false; 189 } 190 191 protected void finalize() { 192 finalized = true; 193 } 194 } 195 196 final ReferenceQueue rq = new ReferenceQueue(); 197 198 class TestThread extends Thread { 199 200 public void run() { 201 // Create the object in a separate thread to ensure it will be 202 // gc'ed 203 Object testObj = new TestObject(); 204 r = new WeakReference(testObj, rq); 205 testObj = null; 206 } 207 } 208 209 Reference ref; 210 211 try { 212 TestThread t = new TestThread(); 213 t.start(); 214 t.join(); 215 System.gc(); 216 System.runFinalization(); 217 ref = rq.remove(); 218 assertNotNull("Object not garbage collected1.", ref); 219 assertTrue("Unexpected ref1", ref == r); 220 assertNull("Object could not be reclaimed1.", r.get()); 221 } catch (InterruptedException e) { 222 fail("InterruptedException : " + e.getMessage()); 223 } 224 225 try { 226 TestThread t = new TestThread(); 227 t.start(); 228 t.join(); 229 System.gc(); 230 System.runFinalization(); 231 ref = rq.poll(); 232 assertNotNull("Object not garbage collected.", ref); 233 assertTrue("Unexpected ref2", ref == r); 234 assertNull("Object could not be reclaimed.", ref.get()); 235 // Reference wr so it does not get collected 236 assertNull("Object could not be reclaimed.", r.get()); 237 } catch (Exception e) { 238 fail("Exception : " + e.getMessage()); 239 } 240 } 241 242 243 /** 244 * Makes sure that overridden versions of clear() and enqueue() 245 * get called, and that clear/enqueue/finalize happen in the 246 * right order for WeakReferences. 247 * 248 * @tests java.lang.ref.Reference#clear() 249 * @tests java.lang.ref.Reference#enqueue() 250 * @tests java.lang.Object#finalize() 251 */ 252 @TestTargets({ 253 @TestTargetNew( 254 level = TestLevel.PARTIAL_COMPLETE, 255 notes = "Makes sure that overridden versions of clear() and enqueue() " + 256 "get called, and that clear/enqueue/finalize happen in the " + 257 "right order for WeakReferences.", 258 method = "clear", 259 args = {} 260 ), 261 @TestTargetNew( 262 level = TestLevel.PARTIAL_COMPLETE, 263 notes = "Makes sure that overridden versions of clear() and enqueue() " + 264 "get called, and that clear/enqueue/finalize happen in the " + 265 "right order for WeakReferences.", 266 method = "enqueue", 267 args = {} 268 ) 269 }) 270 public void test_subclass() { 271 error = null; 272 testObjectFinalized = false; 273 twr = null; 274 275 class TestObject { 276 public TestWeakReference testWeakReference = null; 277 278 public void setTestWeakReference(TestWeakReference twr) { 279 testWeakReference = twr; 280 } 281 282 protected void finalize() { 283 testObjectFinalized = true; 284 if (!testWeakReference.clearSeen) { 285 error = new AssertionFailedError("Clear should happen " + 286 "before finalize."); 287 throw error; 288 } 289 } 290 } 291 292 final ReferenceQueue rq = new ReferenceQueue(); 293 294 class TestThread extends Thread { 295 public void run() { 296 // Create the object in a separate thread to ensure it will be 297 // gc'ed 298 TestObject testObj = new TestObject(); 299 twr = new TestWeakReference(testObj, rq); 300 testObj.setTestWeakReference(twr); 301 testObj = null; 302 } 303 } 304 305 Reference ref; 306 307 try { 308 Thread t = new TestThread(); 309 t.start(); 310 t.join(); 311 System.gc(); 312 System.runFinalization(); 313 ref = rq.remove(5000L); // Give up after five seconds. 314 315 assertNotNull("Object not garbage collected.", ref); 316 assertTrue("Unexpected reference.", ref == twr); 317 assertNull("Object could not be reclaimed.", twr.get()); 318 //assertTrue("Overridden clear() should have been called.", 319 // twr.clearSeen); 320 //assertTrue("Overridden enqueue() should have been called.", 321 // twr.enqueueSeen); 322 assertTrue("finalize() should have been called.", 323 testObjectFinalized); 324 } catch (InterruptedException e) { 325 fail("InterruptedException : " + e.getMessage()); 326 } 327 328 } 329 330 /** 331 * @tests java.lang.ref.Reference#get() 332 */ 333 @TestTargetNew( 334 level = TestLevel.PARTIAL_COMPLETE, 335 notes = "Doesn't check that get() can return null.", 336 method = "get", 337 args = {} 338 ) 339 public void test_get() { 340 341 Vector<StringBuffer> vec = new Vector<StringBuffer>(); 342 WeakReference ref = new WeakReference(vec, new ReferenceQueue()); 343 assertTrue("Get succeeded.", ref.get() == vec); 344 345 Runtime rt = Runtime.getRuntime(); 346 347 long beforeTest = rt.freeMemory(); 348 while(rt.freeMemory() < beforeTest * 2/3) { 349 vec.add(new StringBuffer(1000)); 350 } 351 vec = null; 352 353 System.gc(); 354 System.runFinalization(); 355 assertNull("get() doesn't return null after gc for WeakReference", 356 ref.get()); 357 358 obj = new Object(); 359 ref = new WeakReference(obj, new ReferenceQueue()); 360 ref.clear(); 361 assertNull("get() doesn't return null after clear for WeakReference", 362 ref.get()); 363 } 364 365 /** 366 * @tests java.lang.ref.Reference#isEnqueued() 367 */ 368 @TestTargetNew( 369 level = TestLevel.COMPLETE, 370 notes = "", 371 method = "isEnqueued", 372 args = {} 373 ) 374 public void test_isEnqueued() { 375 ReferenceQueue rq = new ReferenceQueue(); 376 obj = new Object(); 377 Reference ref = new SoftReference(obj, rq); 378 assertTrue("Should start off not enqueued.", !ref.isEnqueued()); 379 ref.enqueue(); 380 assertTrue("Should now be enqueued.", ref.isEnqueued()); 381 ref.enqueue(); 382 assertTrue("Should still be enqueued.", ref.isEnqueued()); 383 rq.poll(); 384 // This fails ... 385 assertTrue("Should now be not enqueued.", !ref.isEnqueued()); 386 } 387 388 /* Contrives a situation where the only reference to a string 389 * is a WeakReference from an object that is being finalized. 390 * Checks to make sure that the referent of the WeakReference 391 * is still pointing to a valid object. 392 */ 393 @TestTargetNew( 394 level = TestLevel.PARTIAL_COMPLETE, 395 notes = "Contrives a situation where the only reference to a string " + 396 "is a WeakReference from an object that is being finalized. " + 397 "Checks to make sure that the referent of the WeakReference " + 398 "is still pointing to a valid object.", 399 method = "get", 400 args = {} 401 ) 402 public void test_finalizeReferenceInteraction() { 403 error = null; 404 testObjectFinalized = false; 405 406 class TestObject { 407 WeakReference<String> stringRef; 408 409 public TestObject(String referent) { 410 stringRef = new WeakReference<String>(referent); 411 } 412 413 protected void finalize() { 414 try { 415 /* If a VM bug has caused the referent to get 416 * freed without the reference getting cleared, 417 * looking it up, assigning it to a local and 418 * doing a GC should cause some sort of exception. 419 */ 420 String s = stringRef.get(); 421 System.gc(); 422 testObjectFinalized = true; 423 } catch (Throwable t) { 424 error = new AssertionFailedError("something threw '" + t + 425 "' in finalize()"); 426 } 427 } 428 } 429 430 class TestThread extends Thread { 431 public void run() { 432 // Create the object in a separate thread to ensure it will be 433 // gc'ed 434 TestObject testObj = new TestObject(new String("sup /b/")); 435 } 436 } 437 438 try { 439 Thread t = new TestThread(); 440 t.start(); 441 t.join(); 442 System.gc(); 443 System.runFinalization(); 444 Thread.sleep(1000); 445 if (error != null) { 446 throw error; 447 } 448 assertTrue("finalize() should have been called.", 449 testObjectFinalized); 450 } catch (InterruptedException e) { 451 fail("InterruptedException : " + e.getMessage()); 452 } 453 } 454 455 456 protected void setUp() { 457 } 458 459 protected void tearDown() { 460 } 461} 462