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 org.apache.harmony.tests.java.lang.ref; 18 19import java.lang.ref.PhantomReference; 20import java.lang.ref.Reference; 21import java.lang.ref.ReferenceQueue; 22import java.lang.ref.SoftReference; 23import java.lang.ref.WeakReference; 24import junit.framework.AssertionFailedError; 25import libcore.java.lang.ref.FinalizationTester; 26 27public class ReferenceTest extends junit.framework.TestCase { 28 Object tmpA, tmpB, tmpC, obj; 29 30 volatile Reference r; 31 32 /* 33 * For test_subclass(). 34 */ 35 static TestWeakReference twr; 36 static AssertionFailedError error; 37 static boolean testObjectFinalized; 38 39 static class TestWeakReference<T> extends WeakReference<T> { 40 public volatile boolean clearSeen = false; 41 public volatile boolean enqueueSeen = false; 42 43 public TestWeakReference(T referent, ReferenceQueue<? super T> q) { 44 super(referent, q); 45 } 46 47 public void clear() { 48 clearSeen = true; 49 super.clear(); 50 } 51 52 public boolean enqueue() { 53 enqueueSeen = true; 54 return super.enqueue(); 55 } 56 } 57 58 protected void doneSuite() { 59 tmpA = tmpB = obj = null; 60 } 61 62 /** 63 * java.lang.ref.Reference#clear() 64 */ 65 public void test_clear() { 66 tmpA = new Object(); 67 tmpB = new Object(); 68 tmpC = new Object(); 69 SoftReference sr = new SoftReference(tmpA, new ReferenceQueue()); 70 WeakReference wr = new WeakReference(tmpB, new ReferenceQueue()); 71 PhantomReference pr = new PhantomReference(tmpC, new ReferenceQueue()); 72 assertTrue("Start: Object not cleared.", (sr.get() != null) 73 && (wr.get() != null)); 74 assertNull("Referent is not null.", pr.get()); 75 sr.clear(); 76 wr.clear(); 77 pr.clear(); 78 assertTrue("End: Object cleared.", (sr.get() == null) 79 && (wr.get() == null)); 80 assertNull("Referent is not null.", pr.get()); 81 // Must reference tmpA and tmpB so the jit does not optimize them away 82 assertTrue("should always pass", tmpA != sr.get() && tmpB != wr.get()); 83 } 84 85 /** 86 * java.lang.ref.Reference#enqueue() 87 */ 88 public void test_enqueue() { 89 ReferenceQueue rq = new ReferenceQueue(); 90 obj = new Object(); 91 Reference ref = new SoftReference(obj, rq); 92 assertTrue("Enqueue failed.", (!ref.isEnqueued()) 93 && ((ref.enqueue()) && (ref.isEnqueued()))); 94 assertTrue("Not properly enqueued.", rq.poll().get() == obj); 95 // This fails... 96 assertTrue("Should remain enqueued.", !ref.isEnqueued()); 97 assertTrue("Can not enqueue twice.", (!ref.enqueue()) 98 && (rq.poll() == null)); 99 100 rq = new ReferenceQueue(); 101 obj = new Object(); 102 103 ref = new WeakReference(obj, rq); 104 assertTrue("Enqueue failed2.", (!ref.isEnqueued()) 105 && ((ref.enqueue()) && (ref.isEnqueued()))); 106 assertTrue("Not properly enqueued2.", rq.poll().get() == obj); 107 assertTrue("Should remain enqueued2.", !ref.isEnqueued()); // This 108 // fails. 109 assertTrue("Can not enqueue twice2.", (!ref.enqueue()) 110 && (rq.poll() == null)); 111 112 ref = new PhantomReference(obj, rq); 113 assertTrue("Enqueue failed3.", (!ref.isEnqueued()) 114 && ((ref.enqueue()) && (ref.isEnqueued()))); 115 assertNull("Not properly enqueued3.", rq.poll().get()); 116 assertTrue("Should remain enqueued3.", !ref.isEnqueued()); // This 117 // fails. 118 assertTrue("Can not enqueue twice3.", (!ref.enqueue()) 119 && (rq.poll() == null)); 120 } 121 122 public void test_get_WeakReference() throws Exception { 123 // Test the general/overall functionality of Reference. 124 ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); 125 126 r = newWeakReference(queue); 127 FinalizationTester.induceFinalization(); 128 Reference ref = queue.remove(); 129 assertNotNull("Object not enqueued.", ref); 130 assertSame("Unexpected ref1", ref, r); 131 assertNull("Object could not be reclaimed1.", r.get()); 132 133 r = newWeakReference(queue); 134 FinalizationTester.induceFinalization(); 135 136 // wait for the reference queue thread to enqueue the newly-finalized object 137 Thread.yield(); 138 Thread.sleep(200); 139 140 ref = queue.poll(); 141 assertNotNull("Object not enqueued.", ref); 142 assertSame("Unexpected ref2", ref, r); 143 assertNull("Object could not be reclaimed.", ref.get()); 144 assertNull("Object could not be reclaimed.", r.get()); 145 } 146 147 /** 148 * Makes sure that overridden versions of clear() and enqueue() 149 * get called, and that clear/enqueue/finalize happen in the 150 * right order for WeakReferences. 151 * 152 * java.lang.ref.Reference#clear() 153 * java.lang.ref.Reference#enqueue() 154 * java.lang.Object#finalize() 155 */ 156 public void test_subclass() { 157 error = null; 158 testObjectFinalized = false; 159 twr = null; 160 161 class TestObject { 162 public TestWeakReference testWeakReference = null; 163 164 public void setTestWeakReference(TestWeakReference twr) { 165 testWeakReference = twr; 166 } 167 168 protected void finalize() { 169 testObjectFinalized = true; 170 } 171 } 172 173 final ReferenceQueue rq = new ReferenceQueue(); 174 175 class TestThread extends Thread { 176 public void run() { 177 // Create the object in a separate thread to ensure it will be 178 // gc'ed 179 TestObject testObj = new TestObject(); 180 twr = new TestWeakReference(testObj, rq); 181 testObj.setTestWeakReference(twr); 182 testObj = null; 183 } 184 } 185 186 Reference ref; 187 188 try { 189 Thread t = new TestThread(); 190 t.start(); 191 t.join(); 192 FinalizationTester.induceFinalization(); 193 ref = rq.remove(5000L); // Give up after five seconds. 194 195 assertNotNull("Object not garbage collected.", ref); 196 assertTrue("Unexpected reference.", ref == twr); 197 assertNull("Object could not be reclaimed.", twr.get()); 198 199 // enqueue() and clear() will not be called by the garbage collector. The GC 200 // will perform the equivalent operations directly. 201 assertFalse(twr.clearSeen); 202 assertFalse(twr.enqueueSeen); 203 204 assertTrue(testObjectFinalized); 205 } catch (InterruptedException e) { 206 fail("InterruptedException : " + e.getMessage()); 207 } 208 209 } 210 211 /** 212 * java.lang.ref.Reference#get() 213 */ 214 public void test_get() { 215 WeakReference ref = newWeakReference(null); 216 217 FinalizationTester.induceFinalization(); 218 assertNull("get() doesn't return null after gc for WeakReference", ref.get()); 219 220 obj = new Object(); 221 ref = new WeakReference<Object>(obj, new ReferenceQueue<Object>()); 222 ref.clear(); 223 assertNull("get() doesn't return null after clear for WeakReference", ref.get()); 224 } 225 226 /** 227 * Helper method to prevent live-precise bugs from interfering with analysis 228 * of what is reachable. Do not inline this method; otherwise tests may fail 229 * on VMs that are not live-precise. http://b/4191345 230 */ 231 private WeakReference<Object> newWeakReference(ReferenceQueue<Object> queue) { 232 Object o = new Object(); 233 WeakReference<Object> ref = new WeakReference<Object>(o, queue); 234 assertSame(o, ref.get()); 235 return ref; 236 } 237 238 /** 239 * java.lang.ref.Reference#isEnqueued() 240 */ 241 public void test_isEnqueued() { 242 ReferenceQueue rq = new ReferenceQueue(); 243 obj = new Object(); 244 Reference ref = new SoftReference(obj, rq); 245 assertTrue("Should start off not enqueued.", !ref.isEnqueued()); 246 ref.enqueue(); 247 assertTrue("Should now be enqueued.", ref.isEnqueued()); 248 ref.enqueue(); 249 assertTrue("Should still be enqueued.", ref.isEnqueued()); 250 rq.poll(); 251 // This fails ... 252 assertTrue("Should now be not enqueued.", !ref.isEnqueued()); 253 } 254 255 /* Contrives a situation where the only reference to a string 256 * is a WeakReference from an object that is being finalized. 257 * Checks to make sure that the referent of the WeakReference 258 * is still pointing to a valid object. 259 */ 260 public void test_finalizeReferenceInteraction() { 261 error = null; 262 testObjectFinalized = false; 263 264 class TestObject { 265 WeakReference<String> stringRef; 266 267 public TestObject(String referent) { 268 stringRef = new WeakReference<String>(referent); 269 } 270 271 protected void finalize() { 272 try { 273 /* If a VM bug has caused the referent to get 274 * freed without the reference getting cleared, 275 * looking it up, assigning it to a local and 276 * doing a GC should cause some sort of exception. 277 */ 278 String s = stringRef.get(); 279 System.gc(); 280 testObjectFinalized = true; 281 } catch (Throwable t) { 282 error = new AssertionFailedError("something threw '" + t + 283 "' in finalize()"); 284 } 285 } 286 } 287 288 class TestThread extends Thread { 289 public void run() { 290 // Create the object in a separate thread to ensure it will be 291 // gc'ed 292 TestObject testObj = new TestObject(new String("sup /b/")); 293 } 294 } 295 296 try { 297 Thread t = new TestThread(); 298 t.start(); 299 t.join(); 300 FinalizationTester.induceFinalization(); 301 Thread.sleep(1000); 302 if (error != null) { 303 throw error; 304 } 305 assertTrue("finalize() should have been called.", 306 testObjectFinalized); 307 } catch (InterruptedException e) { 308 fail("InterruptedException : " + e.getMessage()); 309 } 310 } 311 312 313 protected void setUp() { 314 } 315 316 protected void tearDown() { 317 } 318} 319