|
17 | 17 | package com.facebook.litho.diagnostics
|
18 | 18 |
|
19 | 19 | import com.facebook.litho.AbstractCompilerTest
|
20 |
| -import com.tschuchort.compiletesting.CompilationResult |
21 |
| -import com.tschuchort.compiletesting.KotlinCompilation.ExitCode |
22 |
| -import com.tschuchort.compiletesting.SourceFile |
23 |
| -import org.assertj.core.api.Assertions.assertThat |
24 |
| -import org.intellij.lang.annotations.Language |
25 |
| -import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi |
26 | 20 | import org.junit.Test
|
27 | 21 | import org.junit.runner.RunWith
|
28 | 22 | import org.junit.runners.Parameterized
|
29 | 23 | import org.junit.runners.Parameterized.Parameters
|
30 | 24 |
|
31 |
| -@OptIn(ExperimentalCompilerApi::class) |
32 | 25 | @RunWith(Parameterized::class)
|
33 | 26 | class LithoHookUsageCheckerTest(private val useK2: Boolean) : AbstractCompilerTest() {
|
34 | 27 |
|
35 | 28 | companion object {
|
36 |
| - @Parameters(name = "useK2={0}") @JvmStatic fun useK2() = listOf(false, true) |
| 29 | + @JvmStatic @Parameters(name = "useK2={0}") fun useK2() = listOf(false, true) |
37 | 30 | }
|
38 | 31 |
|
39 | 32 | @Test
|
40 |
| - fun `doesn't complain about hook used in render function`() { |
41 |
| - val content = |
42 |
| - """ |
43 |
| - |import com.facebook.litho.KComponent |
44 |
| - |import com.facebook.litho.Component |
45 |
| - |import com.facebook.litho.ComponentScope |
46 |
| - |import com.facebook.litho.Column |
47 |
| - |import com.facebook.litho.useState |
48 |
| - |import com.facebook.litho.core.width |
49 |
| - |import com.facebook.litho.Style |
50 |
| - |import com.facebook.rendercore.dp |
51 |
| - | |
52 |
| - |class TestClass : KComponent() { |
53 |
| - | override fun ComponentScope.render(): Component { |
54 |
| - | val state = useState { true } |
55 |
| - | return Column() |
56 |
| - | } |
57 |
| - |} |
58 |
| - """ |
59 |
| - .trimMargin() |
60 |
| - val result = compile(content) |
61 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.OK) |
| 33 | + fun hooks_misuse() { |
| 34 | + runTest("test-data/Hooks.misuse.kt", useK2 = useK2) |
62 | 35 | }
|
63 | 36 |
|
64 | 37 | @Test
|
65 |
| - fun `doesn't complain about hook used in function annotated @Hook`() { |
66 |
| - val content = |
67 |
| - """ |
68 |
| - |import com.facebook.litho.KComponent |
69 |
| - |import com.facebook.litho.Component |
70 |
| - |import com.facebook.litho.ComponentScope |
71 |
| - |import com.facebook.litho.useState |
72 |
| - |import com.facebook.litho.annotations.Hook |
73 |
| - | |
74 |
| - |class TestClass { |
75 |
| - | |
76 |
| - | @Hook |
77 |
| - | fun ComponentScope.useOurState() = useState { true } |
78 |
| - | |
79 |
| - | @Hook |
80 |
| - | fun ComponentScope.useOurBetterState() = useOurState() |
81 |
| - |} |
82 |
| - """ |
83 |
| - .trimMargin() |
84 |
| - val result = compile(content) |
85 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.OK) |
86 |
| - } |
87 |
| - |
88 |
| - @Test |
89 |
| - fun `complain about hook used in function without @Hook annotation`() { |
90 |
| - val content = |
91 |
| - """ |
92 |
| - |import com.facebook.litho.KComponent |
93 |
| - |import com.facebook.litho.Component |
94 |
| - |import com.facebook.litho.ComponentScope |
95 |
| - |import com.facebook.litho.animated.useBinding |
96 |
| - | |
97 |
| - |class TestClass { |
98 |
| - | fun ComponentScope.useOurBinding() = /*issue*/useBinding { true }/*issue*/ |
99 |
| - |} |
100 |
| - """ |
101 |
| - .trimMargin() |
102 |
| - val result = compile(content) |
103 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR) |
104 |
| - assertThat(result.messages).contains("Hooks") // use site |
105 |
| - } |
106 |
| - |
107 |
| - @Test |
108 |
| - fun `complain about hook used in if else`() { |
109 |
| - val content = |
110 |
| - """ |
111 |
| - |import com.facebook.litho.KComponent |
112 |
| - |import com.facebook.litho.Component |
113 |
| - |import com.facebook.litho.ComponentScope |
114 |
| - |import com.facebook.litho.useState |
115 |
| - |import com.facebook.litho.annotations.Hook |
116 |
| - | |
117 |
| - |class TestClass { |
118 |
| - | @Hook |
119 |
| - | fun ComponentScope.useConditionalState(): Boolean { |
120 |
| - | if(context.globalKey.isEmpty()) { |
121 |
| - | /*issue*/useState{true}/*issue*/ |
122 |
| - | return true |
123 |
| - | } else { |
124 |
| - | return false |
125 |
| - | } |
126 |
| - | } |
127 |
| - |} |
128 |
| - """ |
129 |
| - .trimMargin() |
130 |
| - val result = compile(content) |
131 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR) |
132 |
| - assertThat(result.messages).contains("Hooks") // conditional |
133 |
| - } |
134 |
| - |
135 |
| - @Test |
136 |
| - fun `complain about hook used in while`() { |
137 |
| - val content = |
138 |
| - """ |
139 |
| - |import com.facebook.litho.KComponent |
140 |
| - |import com.facebook.litho.Component |
141 |
| - |import com.facebook.litho.ComponentScope |
142 |
| - |import com.facebook.litho.annotations.Hook |
143 |
| - |import com.facebook.litho.useState |
144 |
| - | |
145 |
| - |class TestClass{ |
146 |
| - | |
147 |
| - | @Hook |
148 |
| - | fun ComponentScope.useConditionalState() { |
149 |
| - | while(true) { |
150 |
| - | val k = /*issue*/useState{ 0 }/*issue*/ |
151 |
| - | } |
152 |
| - | } |
153 |
| - |} |
154 |
| - """ |
155 |
| - .trimMargin() |
156 |
| - val result = compile(content) |
157 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR) |
158 |
| - assertThat(result.messages).contains("Hooks") // conditional |
159 |
| - } |
160 |
| - |
161 |
| - @Test |
162 |
| - fun `complain about hook used in when in render`() { |
163 |
| - val content = |
164 |
| - """ |
165 |
| - | |
166 |
| - |import com.facebook.litho.KComponent |
167 |
| - |import com.facebook.litho.Column |
168 |
| - |import com.facebook.litho.Component |
169 |
| - |import com.facebook.litho.ComponentScope |
170 |
| - |import com.facebook.litho.useState |
171 |
| - |import com.facebook.litho.annotations.Hook |
172 |
| - | |
173 |
| - |class TestClass(val color: Color) : com.facebook.litho.KComponent() { |
174 |
| - | |
175 |
| - | override fun ComponentScope.render(): Component { |
176 |
| - | when(color) { |
177 |
| - | Color.RED -> /*issue*/useState{}/*issue*/ |
178 |
| - | Color.GREEN -> println("green") |
179 |
| - | Color.BLUE -> println("blue") |
180 |
| - | } |
181 |
| - | return Column() |
182 |
| - | } |
183 |
| - |} |
184 |
| - | |
185 |
| - |enum class Color { |
186 |
| - | RED, GREEN, BLUE |
187 |
| - |} |
188 |
| - """ |
189 |
| - .trimMargin() |
190 |
| - val result = compile(content) |
191 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR) |
192 |
| - assertThat(result.messages).contains("Hooks") // conditional |
193 |
| - } |
194 |
| - |
195 |
| - @Test |
196 |
| - fun `complain about hook used used in while in render`() { |
197 |
| - val content = |
198 |
| - """ |
199 |
| - | |
200 |
| - |import com.facebook.litho.KComponent |
201 |
| - |import com.facebook.litho.Column |
202 |
| - |import com.facebook.litho.Component |
203 |
| - |import com.facebook.litho.ComponentScope |
204 |
| - |import com.facebook.litho.useState |
205 |
| - |import com.facebook.litho.annotations.Hook |
206 |
| - | |
207 |
| - |class TestClass : KComponent() { |
208 |
| - | |
209 |
| - | override fun ComponentScope.render(): Component { |
210 |
| - | while(true) { val k = /*issue*/useState{}/*issue*/ } |
211 |
| - | return Column() |
212 |
| - | } |
213 |
| - |} |
214 |
| - """ |
215 |
| - .trimMargin() |
216 |
| - val result = compile(content) |
217 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR) |
218 |
| - assertThat(result.messages).contains("Hooks") // conditional |
219 |
| - } |
220 |
| - |
221 |
| - @Test |
222 |
| - fun `complain about hook used in for loop`() { |
223 |
| - val content = |
224 |
| - """ |
225 |
| - | |
226 |
| - |import com.facebook.litho.KComponent |
227 |
| - |import com.facebook.litho.Component |
228 |
| - |import com.facebook.litho.ComponentScope |
229 |
| - |import com.facebook.litho.useState |
230 |
| - |import com.facebook.litho.annotations.Hook |
231 |
| - | |
232 |
| - |class TestClass { |
233 |
| - | |
234 |
| - | @Hook |
235 |
| - | fun ComponentScope.useConditionalState() { |
236 |
| - | for(i in 1..3) {/*issue*/useState{}/*issue*/} |
237 |
| - | } |
238 |
| - |} |
239 |
| - """ |
240 |
| - .trimMargin() |
241 |
| - val result = compile(content) |
242 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR) |
243 |
| - assertThat(result.messages).contains("Hooks") // conditional |
244 |
| - } |
245 |
| - |
246 |
| - @Test |
247 |
| - fun `complain about hook used in forEach loop`() { |
248 |
| - val content = |
249 |
| - """ |
250 |
| - | |
251 |
| - |import com.facebook.litho.KComponent |
252 |
| - |import com.facebook.litho.Component |
253 |
| - |import com.facebook.litho.ComponentScope |
254 |
| - |import com.facebook.litho.useState |
255 |
| - |import com.facebook.litho.annotations.Hook |
256 |
| - | |
257 |
| - |class TestClass { |
258 |
| - | |
259 |
| - | @Hook |
260 |
| - | fun ComponentScope.useConditionalState() { |
261 |
| - | (1..3).forEach {/*issue*/useState{}/*issue*/} |
262 |
| - | } |
263 |
| - |} |
264 |
| - """ |
265 |
| - .trimMargin() |
266 |
| - val result = compile(content) |
267 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR) |
268 |
| - assertThat(result.messages).contains("Hooks") // conditional |
269 |
| - } |
270 |
| - |
271 |
| - @Test |
272 |
| - fun `complain about hook used in forEach loop in render`() { |
273 |
| - val content = |
274 |
| - """ |
275 |
| - | |
276 |
| - |import com.facebook.litho.KComponent |
277 |
| - |import com.facebook.litho.Column |
278 |
| - |import com.facebook.litho.Component |
279 |
| - |import com.facebook.litho.ComponentScope |
280 |
| - |import com.facebook.litho.useState |
281 |
| - |import com.facebook.litho.annotations.Hook |
282 |
| - | |
283 |
| - |class TestClass : KComponent(){ |
284 |
| - | |
285 |
| - | override fun ComponentScope.render(): Component { |
286 |
| - | (1..3).forEach {/*issue*/useState{}/*issue*/} |
287 |
| - | return Column() |
288 |
| - | } |
289 |
| - |} |
290 |
| - """ |
291 |
| - .trimMargin() |
292 |
| - val result = compile(content) |
293 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.COMPILATION_ERROR) |
294 |
| - assertThat(result.messages).contains("Hooks") // conditional |
295 |
| - } |
296 |
| - |
297 |
| - @Test |
298 |
| - fun `doesn't complain about useState, useBinding or useEffect functions if they are not the litho ones`() { |
299 |
| - val content = |
300 |
| - """ |
301 |
| - | |
302 |
| - |class TestClass { |
303 |
| - | |
304 |
| - | fun useHooks() { |
305 |
| - | val i = useEffect() |
306 |
| - | val j = useBinding() |
307 |
| - | val k = useState() |
308 |
| - | } |
309 |
| - | |
310 |
| - | fun useState(): Boolean = false |
311 |
| - | |
312 |
| - | fun useEffect(): Boolean = true |
313 |
| - | |
314 |
| - | fun useBinding(): Boolean = true |
315 |
| - |} |
316 |
| - """ |
317 |
| - .trimMargin() |
318 |
| - val result = compile(content) |
319 |
| - assertThat(result.exitCode).isEqualTo(ExitCode.OK) |
320 |
| - } |
321 |
| - |
322 |
| - private fun compile(@Language("kotlin") source: String): CompilationResult { |
323 |
| - return compile(SourceFile.kotlin("TestClass.kt", source), useK2 = useK2) |
| 38 | + fun hooks_good_use() { |
| 39 | + runTest("test-data/Hooks.good.kt", useK2 = useK2) |
324 | 40 | }
|
325 | 41 | }
|
0 commit comments