Home | History | Annotate | Download | only in ref
      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  */
     17 package org.apache.harmony.tests.java.lang.ref;
     18 
     19 import java.lang.ref.PhantomReference;
     20 import java.lang.ref.Reference;
     21 import java.lang.ref.ReferenceQueue;
     22 import java.lang.ref.SoftReference;
     23 import java.lang.ref.WeakReference;
     24 import junit.framework.AssertionFailedError;
     25 import libcore.java.lang.ref.FinalizationTester;
     26 
     27 public 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