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 * https://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 @file:Suppress("UnstableApiUsage") 18 19 package com.google.accompanist.permissions.lint 20 21 import com.android.tools.lint.checks.infrastructure.TestFiles 22 import com.android.tools.lint.checks.infrastructure.TestLintResult 23 import com.android.tools.lint.checks.infrastructure.TestLintTask 24 import org.junit.Test 25 import org.junit.runner.RunWith 26 import org.junit.runners.JUnit4 27 28 /* ktlint-disable max-line-length */ 29 30 /** 31 * Test for [PermissionsLaunchDetector]. 32 */ 33 @RunWith(JUnit4::class) 34 internal class PermissionsLaunchDetectorTest { 35 checknull36 private fun check(fileToAdd: String): TestLintResult { 37 return TestLintTask.lint() 38 .files( 39 LaunchPermissionsStub, 40 ComposableStub, 41 TestFiles.kt(fileToAdd) 42 ) 43 .allowMissingSdk() 44 .issues(PermissionsLaunchDetector.PermissionLaunchedDuringComposition) 45 .run() 46 } 47 48 @Test errorsnull49 fun errors() { 50 check( 51 """ 52 import androidx.compose.runtime.Composable 53 import com.google.accompanist.permissions.* 54 55 @Composable 56 fun Test() { 57 PermissionState().launchPermissionRequest() 58 MultiplePermissionsState().launchMultiplePermissionRequest() 59 } 60 61 val lambda = @Composable { 62 PermissionState().launchPermissionRequest() 63 MultiplePermissionsState().launchMultiplePermissionRequest() 64 } 65 66 val lambda2: @Composable () -> Unit = { 67 PermissionState().launchPermissionRequest() 68 MultiplePermissionsState().launchMultiplePermissionRequest() 69 } 70 71 @Composable 72 fun LambdaParameter(content: @Composable () -> Unit) {} 73 74 @Composable 75 fun Test2() { 76 LambdaParameter(content = { 77 PermissionState().launchPermissionRequest() 78 MultiplePermissionsState().launchMultiplePermissionRequest() 79 }) 80 LambdaParameter { 81 PermissionState().launchPermissionRequest() 82 MultiplePermissionsState().launchMultiplePermissionRequest() 83 } 84 } 85 86 fun test3() { 87 val localLambda1 = @Composable { 88 PermissionState().launchPermissionRequest() 89 MultiplePermissionsState().launchMultiplePermissionRequest() 90 } 91 92 val localLambda2: @Composable () -> Unit = { 93 PermissionState().launchPermissionRequest() 94 MultiplePermissionsState().launchMultiplePermissionRequest() 95 } 96 } 97 """ 98 ) 99 .expect( 100 """ 101 src/test.kt:7: Error: Calls to launchPermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 102 PermissionState().launchPermissionRequest() 103 ~~~~~~~~~~~~~~~~~~~~~~~ 104 src/test.kt:8: Error: Calls to launchMultiplePermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 105 MultiplePermissionsState().launchMultiplePermissionRequest() 106 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 107 src/test.kt:12: Error: Calls to launchPermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 108 PermissionState().launchPermissionRequest() 109 ~~~~~~~~~~~~~~~~~~~~~~~ 110 src/test.kt:13: Error: Calls to launchMultiplePermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 111 MultiplePermissionsState().launchMultiplePermissionRequest() 112 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 113 src/test.kt:17: Error: Calls to launchPermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 114 PermissionState().launchPermissionRequest() 115 ~~~~~~~~~~~~~~~~~~~~~~~ 116 src/test.kt:18: Error: Calls to launchMultiplePermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 117 MultiplePermissionsState().launchMultiplePermissionRequest() 118 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 119 src/test.kt:27: Error: Calls to launchPermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 120 PermissionState().launchPermissionRequest() 121 ~~~~~~~~~~~~~~~~~~~~~~~ 122 src/test.kt:28: Error: Calls to launchMultiplePermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 123 MultiplePermissionsState().launchMultiplePermissionRequest() 124 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 125 src/test.kt:31: Error: Calls to launchPermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 126 PermissionState().launchPermissionRequest() 127 ~~~~~~~~~~~~~~~~~~~~~~~ 128 src/test.kt:32: Error: Calls to launchMultiplePermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 129 MultiplePermissionsState().launchMultiplePermissionRequest() 130 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 131 src/test.kt:38: Error: Calls to launchPermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 132 PermissionState().launchPermissionRequest() 133 ~~~~~~~~~~~~~~~~~~~~~~~ 134 src/test.kt:39: Error: Calls to launchMultiplePermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 135 MultiplePermissionsState().launchMultiplePermissionRequest() 136 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 137 src/test.kt:43: Error: Calls to launchPermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 138 PermissionState().launchPermissionRequest() 139 ~~~~~~~~~~~~~~~~~~~~~~~ 140 src/test.kt:44: Error: Calls to launchMultiplePermissionRequest should happen inside a regular lambda or a side-effect, but never in the Composition. [PermissionLaunchedDuringComposition] 141 MultiplePermissionsState().launchMultiplePermissionRequest() 142 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 143 14 errors, 0 warnings 144 """.trimIndent() 145 ) 146 } 147 148 @Test noErrorsnull149 fun noErrors() { 150 check( 151 """ 152 import com.google.accompanist.permissions.* 153 154 fun test() { 155 PermissionState().launchPermissionRequest() 156 MultiplePermissionsState().launchMultiplePermissionRequest() 157 } 158 159 val lambda = { 160 PermissionState().launchPermissionRequest() 161 MultiplePermissionsState().launchMultiplePermissionRequest() 162 } 163 164 val lambda2: () -> Unit = { 165 PermissionState().launchPermissionRequest() 166 MultiplePermissionsState().launchMultiplePermissionRequest() 167 } 168 169 fun lambdaParameter(action: () -> Unit) {} 170 171 fun test2() { 172 lambdaParameter(action = { 173 PermissionState().launchPermissionRequest() 174 MultiplePermissionsState().launchMultiplePermissionRequest() 175 }) 176 lambdaParameter { 177 PermissionState().launchPermissionRequest() 178 MultiplePermissionsState().launchMultiplePermissionRequest() 179 } 180 } 181 182 fun test3() { 183 val localLambda1 = { 184 PermissionState().launchPermissionRequest() 185 MultiplePermissionsState().launchMultiplePermissionRequest() 186 } 187 188 val localLambda2: () -> Unit = { 189 PermissionState().launchPermissionRequest() 190 MultiplePermissionsState().launchMultiplePermissionRequest() 191 } 192 } 193 """ 194 ) 195 .expectClean() 196 } 197 } 198 199 private val LaunchPermissionsStub = TestFiles.kt( 200 "com/google/accompanist/permissions/LaunchPermissions.kt", 201 """ 202 package com.google.accompanist.permissions 203 204 class PermissionState { launchPermissionRequestnull205 fun launchPermissionRequest() 206 } 207 208 class MultiplePermissionsState { 209 fun launchMultiplePermissionRequest() 210 } 211 """ 212 ).indented().within("src") 213 214 private val ComposableStub = TestFiles.kt( 215 "androidx/compose/runtime/Composable.kt", 216 """ 217 package androidx.compose.runtime 218 219 annotation class Composable 220 """ 221 ).indented().within("src") 222 /* ktlint-enable max-line-length */ 223