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 @file:Suppress("UnstableApiUsage")
18 
19 package androidx.build.lint
20 
21 import com.android.tools.lint.checks.infrastructure.TestMode
22 import org.junit.Test
23 import org.junit.runner.RunWith
24 import org.junit.runners.JUnit4
25 
26 @RunWith(JUnit4::class)
27 class BanConcurrentHashMapTest :
28     AbstractLintDetectorTest(
29         useDetector = BanConcurrentHashMap(),
30         useIssues = listOf(BanConcurrentHashMap.ISSUE),
31     ) {
32 
33     @Test
Detection of ConcurrentHashMap import in Java sourcesnull34     fun `Detection of ConcurrentHashMap import in Java sources`() {
35         val input =
36             java(
37                 "src/androidx/ConcurrentHashMapImportJava.java",
38                 """
39                 import androidx.annotation.NonNull;
40                 import java.util.Map;
41                 import java.util.concurrent.ConcurrentHashMap;
42 
43                 public class ConcurrentHashMapUsageJava {
44                     private final Map<?, ?> mMap = new ConcurrentHashMap<>();
45 
46                     public <V, K> Map<V, K> createMap() {
47                         return new ConcurrentHashMap<>();
48                     }
49                 }
50             """
51                     .trimIndent()
52             )
53 
54         val expected =
55             """
56 src/androidx/ConcurrentHashMapImportJava.java:3: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
57 import java.util.concurrent.ConcurrentHashMap;
58 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
59 1 errors, 0 warnings
60         """
61                 .trimIndent()
62 
63         // Skip FULLY_QUALIFIED mode -- this test specifically deals with importing the class, and
64         // FULLY_QUALIFIED removes the import. Usages of the fully qualified type are tested below.
65         lint().files(input).skipTestModes(TestMode.FULLY_QUALIFIED).run().expect(expected)
66     }
67 
68     @Test
Detection of ConcurrentHashMap fully-qualified usage in Java sourcesnull69     fun `Detection of ConcurrentHashMap fully-qualified usage in Java sources`() {
70         val input =
71             java(
72                 "src/androidx/ConcurrentHashMapUsageJava.java",
73                 """
74                 import androidx.annotation.NonNull;
75                 import java.util.Map;
76 
77                 public class ConcurrentHashMapUsageJava {
78                     private final Map<?, ?> mMap = new java.util.concurrent.ConcurrentHashMap<>();
79 
80                     public <V, K> Map<V, K> createMap() {
81                         return new java.util.concurrent.ConcurrentHashMap<>();
82                     }
83                 }
84             """
85                     .trimIndent()
86             )
87 
88         val expected =
89             """
90 src/androidx/ConcurrentHashMapUsageJava.java:5: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
91     private final Map<?, ?> mMap = new java.util.concurrent.ConcurrentHashMap<>();
92                                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
93 src/androidx/ConcurrentHashMapUsageJava.java:8: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
94         return new java.util.concurrent.ConcurrentHashMap<>();
95                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
96 2 errors, 0 warnings
97         """
98                 .trimIndent()
99 
100         check(input).expect(expected)
101     }
102 
103     @Test
Detection of ConcurrentHashMap import in Kotlin sourcesnull104     fun `Detection of ConcurrentHashMap import in Kotlin sources`() {
105         val input =
106             kotlin(
107                 "src/androidx/ConcurrentHashMapImportKotlin.kt",
108                 """
109                 package androidx
110 
111                 import java.util.concurrent.ConcurrentHashMap
112 
113                 class ConcurrentHashMapUsageKotlin {
114                     private val mMap: ConcurrentHashMap<*, *> = ConcurrentHashMap<Any, Any>()
115 
116                     fun <V, K> createMap(): Map<V, K> {
117                         return ConcurrentHashMap()
118                     }
119                 }
120             """
121                     .trimIndent()
122             )
123 
124         val expected =
125             """
126 src/androidx/ConcurrentHashMapImportKotlin.kt:3: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
127 import java.util.concurrent.ConcurrentHashMap
128 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
129 1 errors, 0 warnings
130         """
131                 .trimIndent()
132 
133         lint()
134             .files(*stubs, input)
135             // This fails in IMPORT_ALIAS mode because changing the import line changes the error.
136             // It fails in FULLY_QUALIFIED mode because more errors occur when the fully-qualified
137             // class is used. These cases are tested separately.
138             .skipTestModes(TestMode.IMPORT_ALIAS, TestMode.FULLY_QUALIFIED)
139             .run()
140             .expect(expected)
141     }
142 
143     @Test
Detection of ConcurrentHashMap fully-qualified usage in Kotlin sourcesnull144     fun `Detection of ConcurrentHashMap fully-qualified usage in Kotlin sources`() {
145         val input =
146             kotlin(
147                 "src/androidx/ConcurrentHashMapUsageKotlin.kt",
148                 """
149                 package androidx
150 
151                 class ConcurrentHashMapUsageKotlin {
152                     private val mMap: Map<*, *> = java.util.concurrent.ConcurrentHashMap<Any, Any>()
153 
154                     fun <V, K> createMap(): Map<V, K> {
155                         return java.util.concurrent.ConcurrentHashMap()
156                     }
157                 }
158             """
159                     .trimIndent()
160             )
161 
162         val expected =
163             """
164 src/androidx/ConcurrentHashMapUsageKotlin.kt:4: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
165     private val mMap: Map<*, *> = java.util.concurrent.ConcurrentHashMap<Any, Any>()
166                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
167 src/androidx/ConcurrentHashMapUsageKotlin.kt:7: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
168         return java.util.concurrent.ConcurrentHashMap()
169                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
170 2 errors, 0 warnings
171         """
172                 .trimIndent()
173 
174         lint().files(*stubs, input).run().expect(expected)
175     }
176 
177     @Test
Detection of ConcurrentHashMap import alias in Kotlin sourcesnull178     fun `Detection of ConcurrentHashMap import alias in Kotlin sources`() {
179         val input =
180             kotlin(
181                 "src/androidx/ConcurrentHashMapUsageAliasKotlin.kt",
182                 """
183                 package androidx
184 
185                 import java.util.concurrent.ConcurrentHashMap as NewClassName
186 
187                 class ConcurrentHashMapUsageAliasKotlin {
188                     private val mMap: Map<*, *> = NewClassName<Any, Any>()
189 
190                     fun <V, K> createMap(): Map<V, K> {
191                         return NewClassName()
192                     }
193                 }
194             """
195                     .trimIndent()
196             )
197 
198         val expected =
199             """
200 src/androidx/ConcurrentHashMapUsageAliasKotlin.kt:3: Error: Detected ConcurrentHashMap usage. [BanConcurrentHashMap]
201 import java.util.concurrent.ConcurrentHashMap as NewClassName
202 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
203 1 errors, 0 warnings
204         """
205                 .trimIndent()
206 
207         lint()
208             .files(*stubs, input)
209             // In FULLY_QUALIFIED test mode, more errors occur when the fully-qualified class is
210             // used. This case is tested separately.
211             .skipTestModes(TestMode.FULLY_QUALIFIED)
212             .run()
213             .expect(expected)
214     }
215 }
216