1 package leakcanary 2 3 import leakcanary.TestDescriptionHolder.testDescription 4 import org.junit.rules.TestRule 5 import org.junit.runner.Description 6 import org.junit.runners.model.Statement 7 import shark.SharkLog 8 9 /** 10 * A [TestRule] that holds onto the test [Description] in a thread local while evaluating, making 11 * it possible to retrieve that test [Description] from the test thread via [testDescription]. 12 * 13 * This rule is automatically applied by [DetectLeaksAfterTestSuccess]. 14 */ 15 object TestDescriptionHolder : TestRule { 16 17 private val descriptionThreadLocal = ThreadLocal<Description>() 18 isEvaluatingnull19 fun isEvaluating() = descriptionThreadLocal.get() != null 20 21 val testDescription: Description 22 get() { 23 return descriptionThreadLocal.get() ?: error( 24 "Test description is null, either you forgot to add the TestDescriptionHolder rule around" + 25 "the current code or you did not call testDescription from the test thread." 26 ) 27 } 28 applynull29 override fun apply(base: Statement, description: Description): Statement { 30 return wrap(base, description) 31 } 32 wrapnull33 fun wrap(base: Statement, description: Description) = object : Statement() { 34 override fun evaluate() { 35 val previousDescription = descriptionThreadLocal.get() 36 val descriptionNotAlreadySet = previousDescription == null 37 if (descriptionNotAlreadySet) { 38 descriptionThreadLocal.set(description) 39 } else { 40 SharkLog.d { "Test description already set, you should remove the TestDescriptionHolder rule." } 41 } 42 try { 43 base.evaluate() 44 } finally { 45 if (descriptionNotAlreadySet) { 46 val currentDescription = descriptionThreadLocal.get() 47 check(currentDescription != null) { 48 "Test description should not be null after the rule evaluates." 49 } 50 descriptionThreadLocal.remove() 51 } 52 } 53 } 54 } 55 } 56