1 /* 2 * Copyright 2023 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.compose.lint 18 19 import com.android.tools.lint.checks.infrastructure.LintDetectorTest 20 import com.android.tools.lint.detector.api.Detector 21 import com.android.tools.lint.detector.api.Issue 22 import org.junit.Test 23 import org.junit.runner.RunWith 24 import org.junit.runners.Parameterized 25 26 @RunWith(Parameterized::class) 27 class AsCollectionDetectorTest(val types: CollectionType) : LintDetectorTest() { 28 getDetectornull29 override fun getDetector(): Detector = AsCollectionDetector() 30 31 override fun getIssues(): MutableList<Issue> = mutableListOf(AsCollectionDetector.ISSUE) 32 33 private val collectionTilde = "~".repeat(types.collection.length) 34 35 @Test 36 fun immutableAsImmutable() { 37 lint() 38 .files( 39 ScatterMapClass, 40 ScatterSetClass, 41 ObjectListClass, 42 kotlin( 43 """ 44 package androidx.compose.lint 45 46 import androidx.collection.${types.immutable} 47 48 fun foo(collection: ${types.immutable}${types.params}): ${types.collection}${types.params} = 49 collection.as${types.collection}() 50 """ 51 ) 52 ) 53 .run() 54 .expect( 55 """ 56 src/androidx/compose/lint/test.kt:7: Error: Use method as${types.collection}() only for public API usage [AsCollectionCall] 57 collection.as${types.collection}() 58 ~~~~~~~~~~~~~$collectionTilde~~ 59 1 errors, 0 warnings 60 """ 61 ) 62 } 63 64 @Test mutableAsImmutablenull65 fun mutableAsImmutable() { 66 lint() 67 .files( 68 ScatterMapClass, 69 ScatterSetClass, 70 ObjectListClass, 71 kotlin( 72 """ 73 package androidx.compose.lint 74 75 import androidx.collection.Mutable${types.immutable} 76 77 fun foo(collection: Mutable${types.immutable}${types.params}): ${types.collection}${types.params} = 78 collection.as${types.collection}() 79 """ 80 ) 81 ) 82 .run() 83 .expect( 84 """ 85 src/androidx/compose/lint/test.kt:7: Error: Use method as${types.collection}() only for public API usage [AsCollectionCall] 86 collection.as${types.collection}() 87 ~~~~~~~~~~~~~$collectionTilde~~ 88 1 errors, 0 warnings 89 """ 90 ) 91 } 92 93 @Test mutableAsMutablenull94 fun mutableAsMutable() { 95 lint() 96 .files( 97 ScatterMapClass, 98 ScatterSetClass, 99 ObjectListClass, 100 kotlin( 101 """ 102 package androidx.compose.lint 103 104 import androidx.collection.Mutable${types.immutable} 105 106 fun foo(collection: Mutable${types.immutable}${types.params}): Mutable${types.collection}${types.params} = 107 collection.asMutable${types.collection}() 108 """ 109 ) 110 ) 111 .run() 112 .expect( 113 """ 114 src/androidx/compose/lint/test.kt:7: Error: Use method asMutable${types.collection}() only for public API usage [AsCollectionCall] 115 collection.asMutable${types.collection}() 116 ~~~~~~~~~~~~~~~~~~~~$collectionTilde~~ 117 1 errors, 0 warnings 118 """ 119 ) 120 } 121 122 @Test nonCollectionAsnull123 fun nonCollectionAs() { 124 lint() 125 .files( 126 kotlin( 127 """ 128 package androidx.compose.lint 129 130 fun foo(): ${types.collection}${types.params} = 131 WeirdCollection().as${types.collection}() 132 133 class WeirdCollection { 134 fun asList(): List<String>? = null 135 fun asSet(): Set<String>? = null 136 fun asMap(): Map<String, String>? = null 137 } 138 """ 139 ) 140 ) 141 .run() 142 .expectClean() 143 } 144 145 class CollectionType(val immutable: String, val collection: String, val params: String) 146 147 companion object { 148 @JvmStatic 149 @Parameterized.Parameters(name = "{0}") initParametersnull150 fun initParameters() = 151 listOf( 152 CollectionType("ScatterMap", "Map", "<String, String>"), 153 CollectionType("ScatterSet", "Set", "<String>"), 154 CollectionType("ObjectList", "List", "<String>") 155 ) 156 157 val ScatterMapClass = 158 kotlin( 159 """ 160 package androidx.collection 161 sealed class ScatterMap<K, V> { 162 fun asMap(): Map<K, V> = mapOf() 163 } 164 165 class MutableScatterMap<K, V> : ScatterMap<K, V>() { 166 fun asMutableMap(): MutableMap<K, V> = mutableMapOf() 167 } 168 """ 169 .trimIndent() 170 ) 171 172 val ScatterSetClass = 173 kotlin( 174 """ 175 package androidx.collection 176 sealed class ScatterSet<E> { 177 fun asSet(): Set<E> = setOf() 178 } 179 180 class MutableScatterSet<E> : ScatterSet<E>() { 181 fun asMutableSet(): MutableSet<E> = mutableSetOf() 182 } 183 """ 184 .trimIndent() 185 ) 186 187 val ObjectListClass = 188 kotlin( 189 """ 190 package androidx.collection 191 sealed class ObjectList<E> { 192 fun asList(): List<E> = listOf() 193 } 194 195 class MutableObjectList<E> : ObjectList<E>() { 196 fun asMutableList(): MutableList<E> = mutableListOf() 197 } 198 """ 199 .trimIndent() 200 ) 201 } 202 } 203