ReferenceTest.java revision 8887e3837a2bf8ef914ed3aa825e089fb09aff19
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 } 285 } 286 287 final ReferenceQueue rq = new ReferenceQueue(); 288 289 class TestThread extends Thread { 290 public void run() { 291 // Create the object in a separate thread to ensure it will be 292 // gc'ed 293 TestObject testObj = new TestObject(); 294 twr = new TestWeakReference(testObj, rq); 295 testObj.setTestWeakReference(twr); 296 testObj = null; 297 } 298 } 299 300 Reference ref; 301 302 try { 303 Thread t = new TestThread(); 304 t.start(); 305 t.join(); 306 System.gc(); 307 System.runFinalization(); 308 ref = rq.remove(5000L); // Give up after five seconds. 309 310 assertNotNull("Object not garbage collected.", ref); 311 assertTrue("Unexpected reference.", ref == twr); 312 assertNull("Object could not be reclaimed.", twr.get()); 313 //assertTrue("Overridden clear() should have been called.", 314 // twr.clearSeen); 315 //assertTrue("Overridden enqueue() should have been called.", 316 // twr.enqueueSeen); 317 assertTrue("finalize() should have been called.", 318 testObjectFinalized); 319 } catch (InterruptedException e) { 320 fail("InterruptedException : " + e.getMessage()); 321 } 322 323 } 324 325 /** 326 * @tests java.lang.ref.Reference#get() 327 */ 328 @TestTargetNew( 329 level = TestLevel.PARTIAL_COMPLETE, 330 notes = "Doesn't check that get() can return null.", 331 method = "get", 332 args = {} 333 ) 334 public void test_get() { 335 336 Vector<StringBuffer> vec = new Vector<StringBuffer>(); 337 WeakReference ref = new WeakReference(vec, new ReferenceQueue()); 338 assertTrue("Get succeeded.", ref.get() == vec); 339 340 Runtime rt = Runtime.getRuntime(); 341 342 long beforeTest = rt.freeMemory(); 343 while(rt.freeMemory() < beforeTest * 2/3) { 344 vec.add(new StringBuffer(1000)); 345 } 346 vec = null; 347 348 System.gc(); 349 System.runFinalization(); 350 assertNull("get() doesn't return null after gc for WeakReference", 351 ref.get()); 352 353 obj = new Object(); 354 ref = new WeakReference(obj, new ReferenceQueue()); 355 ref.clear(); 356 assertNull("get() doesn't return null after clear for WeakReference", 357 ref.get()); 358 } 359 360 /** 361 * @tests java.lang.ref.Reference#isEnqueued() 362 */ 363 @TestTargetNew( 364 level = TestLevel.COMPLETE, 365 notes = "", 366 method = "isEnqueued", 367 args = {} 368 ) 369 public void test_isEnqueued() { 370 ReferenceQueue rq = new ReferenceQueue(); 371 obj = new Object(); 372 Reference ref = new SoftReference(obj, rq); 373 assertTrue("Should start off not enqueued.", !ref.isEnqueued()); 374 ref.enqueue(); 375 assertTrue("Should now be enqueued.", ref.isEnqueued()); 376 ref.enqueue(); 377 assertTrue("Should still be enqueued.", ref.isEnqueued()); 378 rq.poll(); 379 // This fails ... 380 assertTrue("Should now be not enqueued.", !ref.isEnqueued()); 381 } 382 383 /* Contrives a situation where the only reference to a string 384 * is a WeakReference from an object that is being finalized. 385 * Checks to make sure that the referent of the WeakReference 386 * is still pointing to a valid object. 387 */ 388 @TestTargetNew( 389 level = TestLevel.PARTIAL_COMPLETE, 390 notes = "Contrives a situation where the only reference to a string " + 391 "is a WeakReference from an object that is being finalized. " + 392 "Checks to make sure that the referent of the WeakReference " + 393 "is still pointing to a valid object.", 394 method = "get", 395 args = {} 396 ) 397 public void test_finalizeReferenceInteraction() { 398 error = null; 399 testObjectFinalized = false; 400 401 class TestObject { 402 WeakReference<String> stringRef; 403 404 public TestObject(String referent) { 405 stringRef = new WeakReference<String>(referent); 406 } 407 408 protected void finalize() { 409 try { 410 /* If a VM bug has caused the referent to get 411 * freed without the reference getting cleared, 412 * looking it up, assigning it to a local and 413 * doing a GC should cause some sort of exception. 414 */ 415 String s = stringRef.get(); 416 System.gc(); 417 testObjectFinalized = true; 418 } catch (Throwable t) { 419 error = new AssertionFailedError("something threw '" + t + 420 "' in finalize()"); 421 } 422 } 423 } 424 425 class TestThread extends Thread { 426 public void run() { 427 // Create the object in a separate thread to ensure it will be 428 // gc'ed 429 TestObject testObj = new TestObject(new String("sup /b/")); 430 } 431 } 432 433 try { 434 Thread t = new TestThread(); 435 t.start(); 436 t.join(); 437 System.gc(); 438 System.runFinalization(); 439 Thread.sleep(1000); 440 if (error != null) { 441 throw error; 442 } 443 assertTrue("finalize() should have been called.", 444 testObjectFinalized); 445 } catch (InterruptedException e) { 446 fail("InterruptedException : " + e.getMessage()); 447 } 448 } 449 450 451 protected void setUp() { 452 } 453 454 protected void tearDown() { 455 } 456} 457