/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.common.references; import java.io.Closeable; import java.io.IOException; import com.facebook.common.internal.Closeables; import com.facebook.testing.robolectric.v2.WithTestDefaultsRunner; import junit.framework.Assert; import org.robolectric.RobolectricTestRunner; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; /** * Basic tests for shared references */ @RunWith(WithTestDefaultsRunner.class) public class SharedReferenceTest { /** * Tests out the basic operations (isn't everything a basic operation?) */ @Test public void testBasic() { // ref count = 1 after creation SharedReference<Thing> tRef = new SharedReference<Thing>(new Thing("abc"), THING_RELEASER); Assert.assertTrue(SharedReference.isValid(tRef)); Assert.assertEquals(1, tRef.getRefCountTestOnly()); Thing t = tRef.get(); Assert.assertEquals("abc", t.get()); // adding a reference increases the ref count tRef.addReference(); Assert.assertTrue(SharedReference.isValid(tRef)); Assert.assertEquals(2, tRef.getRefCountTestOnly()); Assert.assertEquals(t, tRef.get()); Assert.assertEquals("abc", t.get()); // deleting a reference drops the reference count tRef.deleteReference(); Assert.assertTrue(SharedReference.isValid(tRef)); Assert.assertEquals(1, tRef.getRefCountTestOnly()); Assert.assertEquals(t, tRef.get()); Assert.assertEquals("abc", t.get()); // when the last reference is gone, the underlying object is disposed tRef.deleteReference(); Assert.assertFalse(SharedReference.isValid(tRef)); Assert.assertEquals(0, tRef.getRefCountTestOnly()); // adding a reference now should fail try { tRef.addReference(); Assert.fail(); } catch (SharedReference.NullReferenceException e) { // do nothing } // so should deleting a reference try { tRef.deleteReference(); Assert.fail(); } catch (SharedReference.NullReferenceException e) { // do nothing } // null shared references are not 'valid' Assert.assertFalse(SharedReference.isValid(null)); // test out exceptions during a close SharedReference<Thing> t2Ref = new SharedReference<Thing>(new Thing2("abc"), THING_RELEASER); // this should not throw t2Ref.deleteReference(); } @Test public void testNewSharedReference() { final Thing thing = new Thing("abc"); Assert.assertSame(thing, new SharedReference(thing, THING_RELEASER).get()); } @Test public void testCustomReleaser() { final Thing thing = new Thing("abc"); final ResourceReleaser releaser = Mockito.mock(ResourceReleaser.class); final SharedReference<Thing> tRef = new SharedReference<Thing>(thing, releaser); tRef.deleteReference(); Mockito.verify(releaser, Mockito.times(1)).release(thing); } public static class Thing implements Closeable { private String mValue; public Thing(String value) { mValue = value; } public String get() { return mValue; } public void close() throws IOException { mValue = null; } } /** * A subclass of Thing that throws an exception on close */ public static class Thing2 extends Thing { private String mValue; public Thing2(String value) { super(value); } public void close() throws IOException { throw new IOException(""); } } public final ResourceReleaser<Thing> THING_RELEASER = new ResourceReleaser<Thing>() { @Override public void release(Thing value) { try { Closeables.close(value, true); } catch (IOException ioe) { // this should not happen Assert.fail(); } } }; }