1 package leakcanary 2 3 import org.junit.rules.RuleChain 4 import org.junit.rules.TestRule 5 import org.junit.runner.Description 6 import org.junit.runners.model.Statement 7 8 /** 9 * [TestRule] that invokes [LeakAssertions.assertNoLeaks] after the test 10 * successfully evaluates. Pay attention to where you set up this rule in the 11 * rule chain as you might detect different leaks (e.g. around vs wrapped by the 12 * activity rule). It's also possible to use this rule several times in a rule 13 * chain. 14 * 15 * This rule automatically applies the [TestDescriptionHolder] rule. 16 */ 17 class DetectLeaksAfterTestSuccess( 18 private val tag: String = DetectLeaksAfterTestSuccess::class.java.simpleName 19 ) : TestRule { applynull20 override fun apply(base: Statement, description: Description): Statement { 21 return TestDescriptionHolder.wrap(object : Statement() { 22 override fun evaluate() { 23 try { 24 base.evaluate() 25 // If the test fails, evaluate() will throw and we won't run the analysis (which is good). 26 LeakAssertions.assertNoLeaks(tag) 27 } finally { 28 // Otherwise upstream test failures will be reported as leaks. 29 // https://github.com/square/leakcanary/issues/2297 30 AppWatcher.objectWatcher.clearWatchedObjects() 31 } 32 } 33 }, description) 34 } 35 36 companion object { 37 /** 38 * A helper function to trigger leak detection twice during test tear down, before and after 39 * the tear down of a set of wrapped rule chains. For example, this can be useful to detect 40 * leaks both right before and right after the activity under test is destroyed. Before means 41 * we can detect detached fragment leaks that go away when the activity is destroyed. After 42 * means we can detect activity leaks. 43 * 44 * ```kotlin 45 * RuleChain.outerRule(LoginRule()) 46 * .detectLeaksAfterTestSuccessWrapping("ActivitiesDestroyed") { 47 * around(ActivityScenarioRule(MyActivity::class.java)) 48 * } 49 * .around(LoadingScreenRule()) 50 * ``` 51 */ detectLeaksAfterTestSuccessWrappingnull52 fun RuleChain.detectLeaksAfterTestSuccessWrapping( 53 tag: String, 54 wrapped: RuleChain.() -> RuleChain 55 ): RuleChain { 56 return around(DetectLeaksAfterTestSuccess("After$tag")).wrapped() 57 .around(DetectLeaksAfterTestSuccess("Before$tag")) 58 } 59 } 60 } 61 62 63