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