1 /* 2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.lifecycle.runtime.testing.lint 18 19 import androidx.lifecycle.testing.lint.TestLifecycleOwnerInCoroutineDetector 20 import com.android.tools.lint.checks.infrastructure.LintDetectorTest 21 import com.android.tools.lint.checks.infrastructure.TestFile 22 import com.android.tools.lint.detector.api.Detector 23 import com.android.tools.lint.detector.api.Issue 24 import org.junit.Test 25 import org.junit.runner.RunWith 26 import org.junit.runners.JUnit4 27 28 @RunWith(JUnit4::class) 29 class TestLifecycleOwnerInCoroutineDetectorTest : LintDetectorTest() { 30 getDetectornull31 override fun getDetector(): Detector = TestLifecycleOwnerInCoroutineDetector() 32 33 override fun getIssues(): MutableList<Issue> = 34 mutableListOf(TestLifecycleOwnerInCoroutineDetector.ISSUE) 35 36 private val lifecycleStub: TestFile = 37 bytecode( 38 "libs/lifecycle.jar", 39 kotlin( 40 """ 41 package androidx.lifecycle 42 43 abstract class Lifecycle { 44 enum class State { CREATED, STARTED, RESUMED } 45 } 46 """ 47 ) 48 .indented(), 49 0xf3659215, 50 """ 51 META-INF/main.kotlin_module: 52 H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3AJcrFnVqRmFuQk6qXlp8vxBaSWlzi 53 XcKlySWenV+Sk5lXoZecX5RfWpKZl1qsVwKUFOIDKXEqzcxJSS0q9i5RYtBi 54 AAAIhggPWgAAAA== 55 """, 56 """ 57 androidx/lifecycle/Lifecycle$State.class: 58 H4sIAAAAAAAA/41T30/TUBT+btetXa0yJiIg/sJNuk0ZoII6RCYMnQxJKC4x 59 eypbxULXJmtH9I0n/xD/AsFEjUaz+OgfZTz3DgkEozz03Hu++51zvnvu6c9f 60 X74DuI0lhhHLa7R8p/E67zov7fqbumvnK392KTO0QlsBY5iqbFrbVt61vI18 61 yWs3Zyr/DyzMFhjOHI1TIDPEZhzPCWcZ+o1Dac2w5XgbhXKmyhAxMlUdMSga 62 oogzyOErJ2BInaQqg5ayqVTKs5o2Q/J4CYbTXYbfajie5TKwMqnatty2TVVG 63 jUztZIWUVLVYeV4yGdInitBxFn1xSDjHcLZ2SNjK+qZdDwsKzjNE667vkfA+ 64 I3OcoWMQQxoGcEFBHwkQmldeMtz9SyszJ7vFncOh864VBIW/5Tr6kKTkEq7w 65 57lKkoUM3o8/PVTmV0vFtdKCjjR0fuPrhJlrxVWBGV0sQ9hqyXy+zLFcF7vB 66 oM7UXTEgKtIaQXEVhoqcjhSS3L/F0FvZ8kMi5Zft0GpYoUXXkJrbERprxk2U 67 nnSLoNcO98Zp15hgmO7s6Jo0IGlSIqFJqqz+eMsGOjuTalJOSuOdnXH2SFGl 68 H+9iUkLalNQIfTJ9UR4+ySg1hv/VUAVz1ArRVQb9AB7bCmmA5/0GoT0Vx7Of 69 tZvrdmvNWnfFePp1y61aLYf7+2DcdDY8K2y3eKKy59kt8Sy8sZrpt1t1e9Hh 70 vMHVthc6TbvqBA4FFj3Pp+qO7wVzE9SoKN1dnhvkTwDQauyvOb4mhvgw8l4R 71 k/40sgvklRAB75mSzQ1/grZLW4lAEIUJ8iLZK10KTvFEYncaZ8S5gh4kKOKx 72 iFMRRy+SdMJT9wsGoO2h/yOGO7j4XvhxmqTL+xyDojhLS0rZzxjpQOIcJqrq 73 3RNco1pcfuogc5r08LPB2DdIS9nIHkbNrLyHrJmN7uGmme0WUjFGXzdkEbLA 74 xr5CepHMRz5h/ANGhTMhCycrnMmocG5+xu0P6N8VYg63Q8YTIYpmBEU8ou52 75 rx5BWazzeErrAzq/Q+ypGiJlTJdxlyzucXO/jAJmamABsWZriAXQAzwMoARI 76 BzAC5H4DVwG07rEFAAA= 77 """, 78 """ 79 androidx/lifecycle/Lifecycle.class: 80 H4sIAAAAAAAA/31QTU8UQRB91TM7uw6jLCiwq8hXiAEPDhATEiVEJTHZZNRE 81 yF721DvTYLOzPcl0L8Hb/hb+AScTD2bD0R9lqFnUI314Ve/1q+rq+v3n5y8A 82 r7FGWJYmKwudXca5PlXp9zRXcfIvq4MIzXN5IeNcmrP4S/9cpa4OjxAcaKPd 83 IcHb2u5GqCEI4aNO8N03bQkryX2N3xLmkkHhcm3iT8rJTDrJmhheeDwYVVAj 84 0IClS12xHc6yXcLmZByFoiVC0ZyMQ9EQjRetyXhP7NAb8j7Ubq4C0RSVd4+4 85 D2rHTjpF2LhvmM2pqY4lQvRffDVw/JejIuPq2UQb9Xk07KvyRPZzVuaTIpV5 86 V5a64n/FqGOMKo9yaa3iDYTHxahM1Udd3bW/jozTQ9XVVrP5vTEFP6oLY/11 87 CN5cdaiaGAHjU2bxlPMiXv5A45oTgWeMwVT0scwY3RnwACFHD88ZQ9Za7F18 88 18bKtKqNVY77rM+wN+rB6+BhB48YMVtBs4M5zPdAFo/xpAffIrRYsAgsFm8B 89 Whw3Ci0CAAA= 90 """ 91 ) 92 93 private val testLifecycleOwnerStub: TestFile = 94 bytecode( 95 "libs/testlifecycleowner.jar", 96 kotlin( 97 """ 98 package androidx.lifecycle.testing 99 100 import androidx.lifecycle.Lifecycle 101 102 class TestLifecycleOwner { 103 var currentState: Lifecycle.State = Lifecycle.State.STARTED 104 } 105 """ 106 ) 107 .indented(), 108 0x5140a562, 109 """ 110 META-INF/main.kotlin_module: 111 H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3AJcrFnVqRmFuQk6qXlp8vxBaSWlzi 112 XcKlySWenV+Sk5lXoZecX5RfWpKZl1qsVwKUFOIDKXEqzcxJSS0q9i5RYtBi 113 AAAIhggPWgAAAA== 114 """, 115 """ 116 androidx/lifecycle/testing/TestLifecycleOwner.class: 117 H4sIAAAAAAAA/41TXU8TQRQ9s213S62l5ZviJyDQImxB3kpQREmaVDC0aUx4 118 WrYjTNnuJrvTim88+UP8BWo0Gh9Mw6M/yninrFg+jLzcO/fec8+ZuTPz89f3 119 HwBWsMKwYLl13xP1I9MRr7n91na4KXkghbtvVsmX/2S337jcN8AY0g2rbZmO 120 RYjtvQa3pYEIg74qXCHXGCJzuVoSMegJRGEwTF6hcMY6XZGW5Ab6GIxKdX2n 121 +vwZw3T5/y3FJG4g2YcEbjIk7Zbvc1d2K0n0q4KGNENUHoiAwbyK8N+nLDL0 122 73O50UPKMDOXu862GKbKnr9vNrjc8y3hBqbluh6VhEfrLU9utRxHCQQXBWbn 123 rsOfq9GkVql54fFaHOMMdw496QjXbLSbpnAl913LMUuu9Elb2IGBCYZh+4Db 124 h6H4S8u3mpyAXcmLd1nsyVQUyX5RXedt3EngFu4yZMqh4AsurbolLTqM1mxH 125 6EExZWIM7JBSR0JFBVrVlxg2O8dDCW1MS2jpznFCi2unQTw61jle1grsaezk 126 va6ltZ1sOpLVCtFXJ+9SlEklOsfZaDyW1iejcSMdV2zLjJQwfPnaFg8lw8RO 127 y5WiyUtuWwRiz+Hrf8dP72HDq9Oo+8vC5Vut5h73qxZhGAbKnm05NcsXKg6T 128 0xe5zkZ3jjRR8Vq+zTeF6hkPe2qX1LFEbzKqxkSenij5BYp08iPkI+Rj3WiR 129 ojXC0DmRzH9FPP8JqS/IfKRYg0k2hUi3k/4X/QIdBYU8xWMAg+QzGMIwoRWX 130 SRVVi+U/I/PhjETvJo2e5ljY3LutDEYxFhI9Ia8p9PxA9hvu5efPbUp16CHf 131 yCku5FOr8a7GklJkIbWG5a59iEfkNyl7n7YwuYtICVMlTJPFA2VmSpjF3C5Y 132 gBzyu+gLMBhgPoAe0D9CMsBQgOEAowHGfgPeFoO+3AQAAA== 133 """ 134 ) 135 136 private val coroutineStub: TestFile = 137 bytecode( 138 "libs/coroutinecontext.jar", 139 kotlin( 140 """ 141 package kotlinx.coroutines 142 143 object EmptyCoroutineContext : CoroutineContext 144 145 interface CoroutineContext 146 """ 147 ) 148 .indented(), 149 0x37041da2, 150 """ 151 META-INF/main.kotlin_module: 152 H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3AJcrFnVqRmFuQk6qXlp8vxBaSWlzi 153 XcKlySWenV+Sk5lXoZecX5RfWpKZl1qsVwKUFOIDKXEqzcxJSS0q9i5RYtBi 154 AAAIhggPWgAAAA== 155 """, 156 """ 157 kotlinx/coroutines/CoroutineContext.class: 158 H4sIAAAAAAAA/41OPUsDQRB9s2c+PL8uRiHWYusmwc5KAsJBRFCwuWpzWWVz 159 l13I7oUr87ssJLU/Spwz2Fg5A2/evGHezOfX+weAG5wRLgsXSmNrmbuVq4Kx 160 2svJL504G3QdOiBCslBrJUtl3+TjbKFzViNCb7rblw86qLkK6pYgluuI7amB 161 FoEKlmrTdENm8xHhfLvpxmIgYpEwex1sN2MxpGY4JlxN//ESnwGh/1e+LgIh 162 fnbVKtf3ptSEi6fKBrPUL8abWanvrHVBBeOsb/M97GEXAqc/2EOf64i9W5zt 163 DFGKToouI/YbiFMc4DADeRzhOIPwOPFIvgHKkw26UwEAAA== 164 """, 165 """ 166 kotlinx/coroutines/EmptyCoroutineContext.class: 167 H4sIAAAAAAAA/41STW/TQBB9uwmN6xqalo+mlO9SqfSA24obFVKJimQpGIlW 168 kaqeNs6qbOLsInsdhVtO/BD+QcWhEkgoghs/CjFrAkg0B2ztzL63M88zs/7+ 169 49MXAE+wwbDZNzZVehQmJjOFVVrm4cHgrX3X/I2bRls5sjUwhnpPDEWYCn0a 170 vur0ZEJshWF9hsbF9EsMc3tKK/uMobL5qB2gBs9HFfMMVftG5Qxbrf+t5imD 171 t5ekpZwP7jS8KD482o+bBwEWEcwTWafSWiY7DXvSdjKhdB4KrY0VVhnax8bG 172 RZqS1NL0u+FLaUVXWEEcHwwrNCTmDJXO+kSNlEPbtOvukPZk7Pu8wcs1GXvf 173 3vPGZLzLt9nzmse/fpjjde5Cdxk2ZjU2o6er/3KP+5Zh7XWhrRrISA9Vrjqp 174 3P/bBc2uabqSYbFFWXEx6MjsSFAMw3LLJCJti0w5PCX9Q1NkiXyhHFidCrcv 175 yGKH5lcFXRmtVTdQ8nepeYeXyXN66f4I3SMUkmduUFvn8M/K4/vTYJDMA7LB 176 rwAs0A6UePlP8gpFu2fhM/jxOa58xNJZSXCsl/YOHpa/K82HBK6doBLheoQb 177 ZLHiTCOiGm+egOVYwy06zxHkuJ3D+wnnrXWf6wIAAA== 178 """ 179 ) 180 181 private val runTestCoroutineStub: TestFile = 182 bytecode( 183 "libs/testbuilders.jar", 184 kotlin( 185 """ 186 package kotlinx.coroutines.test 187 188 import kotlinx.coroutines.* 189 190 public fun runTest( 191 context: CoroutineContext = EmptyCoroutineContext, 192 timeout: Int = 0, 193 testBody: () -> Unit 194 ) { } 195 """ 196 ) 197 .indented(), 198 0xd166e09a, 199 """ 200 META-INF/main.kotlin_module: 201 H4sIAAAAAAAA/2NgYGBmYGBgBGJWKM3AJcrFnVqRmFuQk6qXlp8vxBaSWlzi 202 XcKlySWenV+Sk5lXoZecX5RfWpKZl1qsVwKUFOIDKXEqzcxJSS0q9i5RYtBi 203 AAAIhggPWgAAAA== 204 """, 205 """ 206 kotlinx/coroutines/test/TestBuildersKt.class: 207 H4sIAAAAAAAA/61TW08TURD+Tm+7ra2UcpG7KLeCyBbEW0pMoIFkBaqxSEzw 208 5bBd6rbbXbJ7lsCL4W/4M/SJ+GB49kcZ52xbRW0iD7TJzHfm8s2cmT3ff3z9 209 BmAVzxlmG66wLedUM1zPDYTlmL4mTF9oeyQ2Asuump6/LRQwhmydn3DN5k5N 210 e3VYNw2yRhkUL3BkMIOe3+nCVurAkusI81QU9XaUVj9pakeBYwjLdXxtq40K 211 xfl9hnc3w7XW8b91LFF8EVJP7bheTaub4tDjFgVzx3EFbyWWXVEObLtI1zJa 212 JVQkGSauVLHI7Dnc1nRHeJRvGb6CWwwDxgfTaLQJXnOPN00KZJjL7/w9t+IV 213 S0WS1KixNDK4nUIaPQyqXMGGWz1T0cswc61RUMvCappkZGA6w+T/xszQ017d 214 dNU84oFNie9vaIX6v3eWo893Id9sHouzvysoGKYp6OXK3nq5tMmw0K2trpnF 215 NEYxlsQIxmnV17iMgrtpxJFIIYJ7DL2dq+2agle54DSnSPMkSg+GSRGn6TYk 216 iJD91JKoQKi6zPDy8nwodXmeimQjoRpqqazaPo3ks5fnI5ECW1FViiEUDVGM 217 UHwlnU2MqLlYjvwFRTKuMCqJXKefPxZ39XUuNWhxsZJbNcmxQxcrB81D09vj 218 h7Yp812D2/vcs+S5bUxWrJrDReARnn4TOPLD0Z0Ty7fI/evbXf/9MBgyFcGN 219 xi4/blOkKm7gGeaWJQ/DbY79FsOVRCzTWGOQvwiG5ZwRJRuwTWc5vMxCLnWB 220 7GIuR/JzGLZCMkFXTyOFR4QnW4FIoi8kyqAfA+SXqBeDlLEa5il4TLonSi41 221 DAx1Nok7GCIsq5aJKk56bDz28RNSXzBxicnt8Tgd4tG1hdHFC9xvNfGEZAyR 222 jBK2MxhmJeivUNEENaJSCwmKexpGF/CMdImqTFHk9AGiOmZ0zJLEnI485nUs 223 4MEBmI9FPDyA6iPuY8lH0kefj/4Q9/rQfgIMLZFBnQUAAA== 224 """ 225 ) 226 227 @Test 228 fun errors() { 229 lint() 230 .files( 231 kotlin( 232 """ 233 package example.foo 234 235 import androidx.lifecycle.Lifecycle 236 import androidx.lifecycle.testing.TestLifecycleOwner 237 import kotlinx.coroutines.test.runTest 238 239 fun testSetCurrentStateInRunTest() = runTest { 240 val owner = TestLifecycleOwner() 241 owner.currentState = Lifecycle.State.RESUMED 242 } 243 244 fun testSetCurrentStateInRunTestWithTimeOut() = runTest(timeout = 5000) { 245 val owner = TestLifecycleOwner() 246 owner.currentState = Lifecycle.State.RESUMED 247 } 248 """ 249 ), 250 coroutineStub, 251 lifecycleStub, 252 runTestCoroutineStub, 253 testLifecycleOwnerStub 254 ) 255 .run() 256 .expect( 257 """ 258 src/example/foo/test.kt:8: Error: Incorrect use of currentState property inside of Coroutine, please use the suspending setCurrentState() function. [TestLifecycleOwnerInCoroutine] 259 fun testSetCurrentStateInRunTest() = runTest { 260 ~~~~~~~ 261 src/example/foo/test.kt:13: Error: Incorrect use of currentState property inside of Coroutine, please use the suspending setCurrentState() function. [TestLifecycleOwnerInCoroutine] 262 fun testSetCurrentStateInRunTestWithTimeOut() = runTest(timeout = 5000) { 263 ~~~~~~~ 264 2 errors, 0 warnings 265 """ 266 .trimIndent() 267 ) 268 } 269 270 @Test noErrorsnull271 fun noErrors() { 272 lint() 273 .files( 274 kotlin( 275 """ 276 package example.foo 277 278 import androidx.lifecycle.Lifecycle 279 import androidx.lifecycle.testing.TestLifecycleOwner 280 import kotlinx.coroutines.test.runTest 281 282 fun testSetCurrentStateInRunTest() = runTest { 283 val owner = TestLifecycleOwner() 284 owner.setCurrentState(Lifecycle.State.RESUMED) 285 } 286 """ 287 ), 288 coroutineStub, 289 lifecycleStub, 290 runTestCoroutineStub, 291 testLifecycleOwnerStub 292 ) 293 .run() 294 .expectClean() 295 } 296 } 297