| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package tests.api.java.lang.ref; |
| |
| import dalvik.annotation.TestTargets; |
| import dalvik.annotation.TestLevel; |
| import dalvik.annotation.TestTargetNew; |
| import dalvik.annotation.TestTargetClass; |
| |
| import junit.framework.AssertionFailedError; |
| |
| import java.lang.ref.PhantomReference; |
| import java.lang.ref.Reference; |
| import java.lang.ref.ReferenceQueue; |
| import java.lang.ref.SoftReference; |
| import java.lang.ref.WeakReference; |
| import java.util.Vector; |
| |
| @TestTargetClass(Reference.class) |
| public class ReferenceTest extends junit.framework.TestCase { |
| Object tmpA, tmpB, tmpC, obj; |
| |
| volatile Reference r; |
| |
| /* |
| * For test_subclass(). |
| */ |
| static TestWeakReference twr; |
| static AssertionFailedError error; |
| static boolean testObjectFinalized; |
| static class TestWeakReference<T> extends WeakReference<T> { |
| public volatile boolean clearSeen = false; |
| public volatile boolean enqueueSeen = false; |
| |
| public TestWeakReference(T referent) { |
| super(referent); |
| } |
| |
| public TestWeakReference(T referent, ReferenceQueue<? super T> q) { |
| super(referent, q); |
| } |
| |
| public void clear() { |
| clearSeen = true; |
| if (testObjectFinalized) { |
| error = new AssertionFailedError("Clear should happen " + |
| "before finalization."); |
| throw error; |
| } |
| if (enqueueSeen) { |
| error = new AssertionFailedError("Clear should happen " + |
| "before enqueue."); |
| throw error; |
| } |
| super.clear(); |
| } |
| |
| public boolean enqueue() { |
| enqueueSeen = true; |
| if (!clearSeen) { |
| error = new AssertionFailedError("Clear should happen " + |
| "before enqueue."); |
| throw error; |
| } |
| |
| /* Do this last; it may notify the main test thread, |
| * and anything we'd do after it (e.g., setting clearSeen) |
| * wouldn't be seen. |
| */ |
| return super.enqueue(); |
| } |
| } |
| |
| protected void doneSuite() { |
| tmpA = tmpB = obj = null; |
| } |
| |
| /** |
| * @tests java.lang.ref.Reference#clear() |
| */ |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "clear", |
| args = {} |
| ) |
| public void test_clear() { |
| tmpA = new Object(); |
| tmpB = new Object(); |
| tmpC = new Object(); |
| SoftReference sr = new SoftReference(tmpA, new ReferenceQueue()); |
| WeakReference wr = new WeakReference(tmpB, new ReferenceQueue()); |
| PhantomReference pr = new PhantomReference(tmpC, new ReferenceQueue()); |
| assertTrue("Start: Object not cleared.", (sr.get() != null) |
| && (wr.get() != null)); |
| assertNull("Referent is not null.", pr.get()); |
| sr.clear(); |
| wr.clear(); |
| pr.clear(); |
| assertTrue("End: Object cleared.", (sr.get() == null) |
| && (wr.get() == null)); |
| assertNull("Referent is not null.", pr.get()); |
| // Must reference tmpA and tmpB so the jit does not optimize them away |
| assertTrue("should always pass", tmpA != sr.get() && tmpB != wr.get()); |
| } |
| |
| /** |
| * @tests java.lang.ref.Reference#enqueue() |
| */ |
| @TestTargets({ |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "enqueue", |
| args = {} |
| ), |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "isEnqueued", |
| args = {} |
| ) |
| }) |
| public void test_enqueue() { |
| ReferenceQueue rq = new ReferenceQueue(); |
| obj = new Object(); |
| Reference ref = new SoftReference(obj, rq); |
| assertTrue("Enqueue failed.", (!ref.isEnqueued()) |
| && ((ref.enqueue()) && (ref.isEnqueued()))); |
| assertTrue("Not properly enqueued.", rq.poll().get() == obj); |
| // This fails... |
| assertTrue("Should remain enqueued.", !ref.isEnqueued()); |
| assertTrue("Can not enqueue twice.", (!ref.enqueue()) |
| && (rq.poll() == null)); |
| |
| rq = new ReferenceQueue(); |
| obj = new Object(); |
| |
| ref = new WeakReference(obj, rq); |
| assertTrue("Enqueue failed2.", (!ref.isEnqueued()) |
| && ((ref.enqueue()) && (ref.isEnqueued()))); |
| assertTrue("Not properly enqueued2.", rq.poll().get() == obj); |
| assertTrue("Should remain enqueued2.", !ref.isEnqueued()); // This |
| // fails. |
| assertTrue("Can not enqueue twice2.", (!ref.enqueue()) |
| && (rq.poll() == null)); |
| |
| ref = new PhantomReference(obj, rq); |
| assertTrue("Enqueue failed3.", (!ref.isEnqueued()) |
| && ((ref.enqueue()) && (ref.isEnqueued()))); |
| assertNull("Not properly enqueued3.", rq.poll().get()); |
| assertTrue("Should remain enqueued3.", !ref.isEnqueued()); // This |
| // fails. |
| assertTrue("Can not enqueue twice3.", (!ref.enqueue()) |
| && (rq.poll() == null)); |
| } |
| |
| /** |
| * @tests java.lang.ref.Reference#enqueue() |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "Verifies positive functionality for WeakReference.", |
| method = "get", |
| args = {} |
| ) |
| public void test_get_WeakReference() { |
| // Test the general/overall functionality of Reference. |
| |
| class TestObject { |
| public boolean finalized; |
| |
| public TestObject() { |
| finalized = false; |
| } |
| |
| protected void finalize() { |
| finalized = true; |
| } |
| } |
| |
| final ReferenceQueue rq = new ReferenceQueue(); |
| |
| class TestThread extends Thread { |
| |
| public void run() { |
| // Create the object in a separate thread to ensure it will be |
| // gc'ed |
| Object testObj = new TestObject(); |
| r = new WeakReference(testObj, rq); |
| testObj = null; |
| } |
| } |
| |
| Reference ref; |
| |
| try { |
| TestThread t = new TestThread(); |
| t.start(); |
| t.join(); |
| System.gc(); |
| System.runFinalization(); |
| ref = rq.remove(); |
| assertNotNull("Object not garbage collected1.", ref); |
| assertTrue("Unexpected ref1", ref == r); |
| assertNull("Object could not be reclaimed1.", r.get()); |
| } catch (InterruptedException e) { |
| fail("InterruptedException : " + e.getMessage()); |
| } |
| |
| try { |
| TestThread t = new TestThread(); |
| t.start(); |
| t.join(); |
| System.gc(); |
| System.runFinalization(); |
| ref = rq.poll(); |
| assertNotNull("Object not garbage collected.", ref); |
| assertTrue("Unexpected ref2", ref == r); |
| assertNull("Object could not be reclaimed.", ref.get()); |
| // Reference wr so it does not get collected |
| assertNull("Object could not be reclaimed.", r.get()); |
| } catch (Exception e) { |
| fail("Exception : " + e.getMessage()); |
| } |
| } |
| |
| |
| /** |
| * Makes sure that overridden versions of clear() and enqueue() |
| * get called, and that clear/enqueue/finalize happen in the |
| * right order for WeakReferences. |
| * |
| * @tests java.lang.ref.Reference#clear() |
| * @tests java.lang.ref.Reference#enqueue() |
| * @tests java.lang.Object#finalize() |
| */ |
| @TestTargets({ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "Makes sure that overridden versions of clear() and enqueue() " + |
| "get called, and that clear/enqueue/finalize happen in the " + |
| "right order for WeakReferences.", |
| method = "clear", |
| args = {} |
| ), |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "Makes sure that overridden versions of clear() and enqueue() " + |
| "get called, and that clear/enqueue/finalize happen in the " + |
| "right order for WeakReferences.", |
| method = "enqueue", |
| args = {} |
| ) |
| }) |
| public void test_subclass() { |
| error = null; |
| testObjectFinalized = false; |
| twr = null; |
| |
| class TestObject { |
| public TestWeakReference testWeakReference = null; |
| |
| public void setTestWeakReference(TestWeakReference twr) { |
| testWeakReference = twr; |
| } |
| |
| protected void finalize() { |
| testObjectFinalized = true; |
| } |
| } |
| |
| final ReferenceQueue rq = new ReferenceQueue(); |
| |
| class TestThread extends Thread { |
| public void run() { |
| // Create the object in a separate thread to ensure it will be |
| // gc'ed |
| TestObject testObj = new TestObject(); |
| twr = new TestWeakReference(testObj, rq); |
| testObj.setTestWeakReference(twr); |
| testObj = null; |
| } |
| } |
| |
| Reference ref; |
| |
| try { |
| Thread t = new TestThread(); |
| t.start(); |
| t.join(); |
| System.gc(); |
| System.runFinalization(); |
| ref = rq.remove(5000L); // Give up after five seconds. |
| |
| assertNotNull("Object not garbage collected.", ref); |
| assertTrue("Unexpected reference.", ref == twr); |
| assertNull("Object could not be reclaimed.", twr.get()); |
| //assertTrue("Overridden clear() should have been called.", |
| // twr.clearSeen); |
| //assertTrue("Overridden enqueue() should have been called.", |
| // twr.enqueueSeen); |
| assertTrue("finalize() should have been called.", |
| testObjectFinalized); |
| } catch (InterruptedException e) { |
| fail("InterruptedException : " + e.getMessage()); |
| } |
| |
| } |
| |
| /** |
| * @tests java.lang.ref.Reference#get() |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "Doesn't check that get() can return null.", |
| method = "get", |
| args = {} |
| ) |
| public void test_get() { |
| |
| Vector<StringBuffer> vec = new Vector<StringBuffer>(); |
| WeakReference ref = new WeakReference(vec, new ReferenceQueue()); |
| assertTrue("Get succeeded.", ref.get() == vec); |
| |
| Runtime rt = Runtime.getRuntime(); |
| |
| long beforeTest = rt.freeMemory(); |
| while(rt.freeMemory() < beforeTest * 2/3) { |
| vec.add(new StringBuffer(1000)); |
| } |
| vec = null; |
| |
| System.gc(); |
| System.runFinalization(); |
| assertNull("get() doesn't return null after gc for WeakReference", |
| ref.get()); |
| |
| obj = new Object(); |
| ref = new WeakReference(obj, new ReferenceQueue()); |
| ref.clear(); |
| assertNull("get() doesn't return null after clear for WeakReference", |
| ref.get()); |
| } |
| |
| /** |
| * @tests java.lang.ref.Reference#isEnqueued() |
| */ |
| @TestTargetNew( |
| level = TestLevel.COMPLETE, |
| notes = "", |
| method = "isEnqueued", |
| args = {} |
| ) |
| public void test_isEnqueued() { |
| ReferenceQueue rq = new ReferenceQueue(); |
| obj = new Object(); |
| Reference ref = new SoftReference(obj, rq); |
| assertTrue("Should start off not enqueued.", !ref.isEnqueued()); |
| ref.enqueue(); |
| assertTrue("Should now be enqueued.", ref.isEnqueued()); |
| ref.enqueue(); |
| assertTrue("Should still be enqueued.", ref.isEnqueued()); |
| rq.poll(); |
| // This fails ... |
| assertTrue("Should now be not enqueued.", !ref.isEnqueued()); |
| } |
| |
| /* Contrives a situation where the only reference to a string |
| * is a WeakReference from an object that is being finalized. |
| * Checks to make sure that the referent of the WeakReference |
| * is still pointing to a valid object. |
| */ |
| @TestTargetNew( |
| level = TestLevel.PARTIAL_COMPLETE, |
| notes = "Contrives a situation where the only reference to a string " + |
| "is a WeakReference from an object that is being finalized. " + |
| "Checks to make sure that the referent of the WeakReference " + |
| "is still pointing to a valid object.", |
| method = "get", |
| args = {} |
| ) |
| public void test_finalizeReferenceInteraction() { |
| error = null; |
| testObjectFinalized = false; |
| |
| class TestObject { |
| WeakReference<String> stringRef; |
| |
| public TestObject(String referent) { |
| stringRef = new WeakReference<String>(referent); |
| } |
| |
| protected void finalize() { |
| try { |
| /* If a VM bug has caused the referent to get |
| * freed without the reference getting cleared, |
| * looking it up, assigning it to a local and |
| * doing a GC should cause some sort of exception. |
| */ |
| String s = stringRef.get(); |
| System.gc(); |
| testObjectFinalized = true; |
| } catch (Throwable t) { |
| error = new AssertionFailedError("something threw '" + t + |
| "' in finalize()"); |
| } |
| } |
| } |
| |
| class TestThread extends Thread { |
| public void run() { |
| // Create the object in a separate thread to ensure it will be |
| // gc'ed |
| TestObject testObj = new TestObject(new String("sup /b/")); |
| } |
| } |
| |
| try { |
| Thread t = new TestThread(); |
| t.start(); |
| t.join(); |
| System.gc(); |
| System.runFinalization(); |
| Thread.sleep(1000); |
| if (error != null) { |
| throw error; |
| } |
| assertTrue("finalize() should have been called.", |
| testObjectFinalized); |
| } catch (InterruptedException e) { |
| fail("InterruptedException : " + e.getMessage()); |
| } |
| } |
| |
| |
| protected void setUp() { |
| } |
| |
| protected void tearDown() { |
| } |
| } |