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 tests.api.java.lang.ref;
     18 
     19 import dalvik.annotation.TestTargets;
     20 import dalvik.annotation.TestLevel;
     21 import dalvik.annotation.TestTargetNew;
     22 import dalvik.annotation.TestTargetClass;
     23 
     24 import junit.framework.AssertionFailedError;
     25 
     26 import java.lang.ref.PhantomReference;
     27 import java.lang.ref.Reference;
     28 import java.lang.ref.ReferenceQueue;
     29 import java.lang.ref.SoftReference;
     30 import java.lang.ref.WeakReference;
     31 import java.util.Vector;
     32 
     33 @TestTargetClass(Reference.class)
     34 public 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