1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base; 6 7 import org.junit.After; 8 import org.junit.Assert; 9 import org.junit.Before; 10 import org.junit.Test; 11 import org.junit.runner.RunWith; 12 import org.robolectric.annotation.Config; 13 14 import org.chromium.base.test.BaseRobolectricTestRunner; 15 import org.chromium.build.BuildConfig; 16 17 /** junit tests for {@link LifetimeAssert}. */ 18 @RunWith(BaseRobolectricTestRunner.class) 19 @Config(manifest = Config.NONE) 20 public class LifetimeAssertTest { 21 private static class TestClass { 22 // Put assert inside of a test class to mirror typical api usage. 23 final LifetimeAssert mLifetimeAssert = LifetimeAssert.create(this); 24 } 25 26 private final Object mLock = new Object(); 27 private TestClass mTestClass; 28 private LifetimeAssert.WrappedReference mTargetRef; 29 private boolean mFound; 30 private String mHookMessage; 31 32 @Before setUp()33 public void setUp() { 34 if (!BuildConfig.ENABLE_ASSERTS) { 35 return; 36 } 37 mTestClass = new TestClass(); 38 mTargetRef = mTestClass.mLifetimeAssert.mWrapper; 39 mFound = false; 40 mHookMessage = null; 41 LifetimeAssert.sTestHook = 42 (ref, msg) -> { 43 if (ref == mTargetRef) { 44 synchronized (mLock) { 45 mFound = true; 46 mHookMessage = msg; 47 mLock.notify(); 48 } 49 } 50 }; 51 } 52 53 @After tearDown()54 public void tearDown() { 55 if (!BuildConfig.ENABLE_ASSERTS) { 56 return; 57 } 58 LifetimeAssert.sTestHook = null; 59 } 60 runTest(boolean setSafe)61 private void runTest(boolean setSafe) { 62 if (!BuildConfig.ENABLE_ASSERTS) { 63 return; 64 } 65 66 synchronized (mLock) { 67 if (setSafe) { 68 LifetimeAssert.setSafeToGc(mTestClass.mLifetimeAssert, true); 69 } 70 // Null out field to make reference GC'able. 71 mTestClass = null; 72 // Call System.gc() until the background thread notices the reference. 73 for (int i = 0; i < 10 && !mFound; ++i) { 74 System.gc(); 75 try { 76 mLock.wait(200); 77 } catch (InterruptedException e) { 78 } 79 } 80 Assert.assertTrue(mFound); 81 if (setSafe) { 82 Assert.assertNull(mHookMessage); 83 } else { 84 Assert.assertNotNull(mHookMessage); 85 } 86 } 87 } 88 89 @Test testSafeGc()90 public void testSafeGc() { 91 runTest(true); 92 } 93 94 @Test testUnsafeGc()95 public void testUnsafeGc() { 96 runTest(false); 97 } 98 99 @Test testAssertAllInstancesDestroyedForTesting_notSafeToGc()100 public void testAssertAllInstancesDestroyedForTesting_notSafeToGc() { 101 if (!BuildConfig.ENABLE_ASSERTS) { 102 return; 103 } 104 try { 105 LifetimeAssert.assertAllInstancesDestroyedForTesting(); 106 Assert.fail(); 107 } catch (LifetimeAssert.LifetimeAssertException e) { 108 // Expected. 109 } 110 } 111 112 @Test testAssertAllInstancesDestroyedForTesting_safeToGc()113 public void testAssertAllInstancesDestroyedForTesting_safeToGc() { 114 if (!BuildConfig.ENABLE_ASSERTS) { 115 return; 116 } 117 LifetimeAssert.setSafeToGc(mTestClass.mLifetimeAssert, true); 118 // Should not throw. 119 LifetimeAssert.assertAllInstancesDestroyedForTesting(); 120 } 121 122 @Test testAssertAllInstancesDestroyedForTesting_resetAfterAssert()123 public void testAssertAllInstancesDestroyedForTesting_resetAfterAssert() { 124 if (!BuildConfig.ENABLE_ASSERTS) { 125 return; 126 } 127 try { 128 LifetimeAssert.assertAllInstancesDestroyedForTesting(); 129 Assert.fail(); 130 } catch (LifetimeAssert.LifetimeAssertException e) { 131 // Expected. 132 } 133 // Should no longer throw. 134 LifetimeAssert.assertAllInstancesDestroyedForTesting(); 135 } 136 137 @Test testResetForTesting()138 public void testResetForTesting() { 139 if (!BuildConfig.ENABLE_ASSERTS) { 140 return; 141 } 142 LifetimeAssert.resetForTesting(); 143 // Should not throw. 144 LifetimeAssert.assertAllInstancesDestroyedForTesting(); 145 } 146 } 147