forked from pinterest/ktlint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AnnotationRuleTest.kt
551 lines (503 loc) · 19.5 KB
/
AnnotationRuleTest.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
package com.pinterest.ktlint.ruleset.standard
import com.pinterest.ktlint.test.KtLintAssertThat.Companion.assertThatRule
import com.pinterest.ktlint.test.LintViolation
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
class AnnotationRuleTest {
private val annotationRuleAssertThat = assertThatRule { AnnotationRule() }
@Test
fun `Given a single annotation on same line before the annotated construct`() {
val code =
"""
@FunctionalInterface class FooBar {
@JvmField var foo: String
@Test fun bar() {}
}
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Given a single annotation on line above the annotated construct`() {
val code =
"""
@FunctionalInterface
class FooBar {
@JvmField
var foo: String
@Test
fun bar() {}
}
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Given an annotation with a parameter followed by a EOL comment`() {
val code =
"""
@Suppress("AnnotationRule") // some comment
class FooBar {
@Suppress("AnnotationRule") // some comment
var foo: String
@Suppress("AnnotationRule") // some comment
fun bar() {}
}
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Given an annotation with a parameter on same line as annotation construct (possibly separated by a block comment or KDoc)`() {
val code =
"""
@Suppress("AnnotationRule") class FooBar1 {
@Suppress("AnnotationRule") var foo: String
@Suppress("AnnotationRule") fun bar() {}
}
@Suppress("AnnotationRule") /* some comment */ class FooBar2 {
@Suppress("AnnotationRule") /* some comment */ var foo: String
@Suppress("AnnotationRule") /* some comment */ fun bar() {}
}
@Suppress("AnnotationRule") /** some comment */ class FooBar3 {
@Suppress("AnnotationRule") /** some comment */ var foo: String
@Suppress("AnnotationRule") /** some comment */ fun bar() {}
}
""".trimIndent()
val formattedCode =
"""
@Suppress("AnnotationRule")
class FooBar1 {
@Suppress("AnnotationRule")
var foo: String
@Suppress("AnnotationRule")
fun bar() {}
}
@Suppress("AnnotationRule")
/* some comment */ class FooBar2 {
@Suppress("AnnotationRule")
/* some comment */ var foo: String
@Suppress("AnnotationRule")
/* some comment */ fun bar() {}
}
@Suppress("AnnotationRule")
/** some comment */ class FooBar3 {
@Suppress("AnnotationRule")
/** some comment */ var foo: String
@Suppress("AnnotationRule")
/** some comment */ fun bar() {}
}
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolations(
LintViolation(1, 1, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(2, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(3, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(5, 1, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(6, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(7, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(9, 1, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(10, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(11, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
).isFormattedAs(formattedCode)
}
@Test
fun `Given multiple annotations on same line as annotated construct`() {
val code =
"""
@Foo @Bar class FooBar {
@Foo @Bar var foo: String
@Foo @Bar fun bar() {}
}
""".trimIndent()
val formattedCode =
"""
@Foo @Bar
class FooBar {
@Foo @Bar
var foo: String
@Foo @Bar
fun bar() {}
}
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolations(
LintViolation(1, 1, "Multiple annotations should not be placed on the same line as the annotated construct"),
LintViolation(2, 5, "Multiple annotations should not be placed on the same line as the annotated construct"),
LintViolation(3, 5, "Multiple annotations should not be placed on the same line as the annotated construct"),
).isFormattedAs(formattedCode)
}
@Test
fun `Given multiple annotations on same line as annotated construct (without indentation)`() {
val code =
"""
@JvmField @Volatile var foo: String
""".trimIndent()
val formattedCode =
"""
@JvmField @Volatile
var foo: String
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolation(1, 1, "Multiple annotations should not be placed on the same line as the annotated construct")
.isFormattedAs(formattedCode)
}
@Test
fun `Given multiple annotations on same line as annotated construct (without indentation but preceded by one or more blank line)`() {
val code =
"""
@JvmField @Volatile var foo: String
""".trimIndent()
val formattedCode =
"""
@JvmField @Volatile
var foo: String
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolation(1, 1, "Multiple annotations should not be placed on the same line as the annotated construct")
.isFormattedAs(formattedCode)
}
@Test
fun `Given an annotation with a parameter not followed by a space but on same line as annotated construct`() {
val code =
"""
@Suppress("AnnotationRule")class FooBar {
@Suppress("AnnotationRule")var foo: String
@Suppress("AnnotationRule")fun bar() {}
}
""".trimIndent()
val formattedCode =
"""
@Suppress("AnnotationRule")
class FooBar {
@Suppress("AnnotationRule")
var foo: String
@Suppress("AnnotationRule")
fun bar() {}
}
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolations(
LintViolation(1, 1, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(2, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(3, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
).isFormattedAs(formattedCode)
}
@Test
fun `Given a multiline annotation and annotated construct on same line as closing parenthesis of the annotation`() {
val code =
"""
class FooBar {
@Foo(
groups = [
"a",
"b"
]
) val bar: Any
}
""".trimIndent()
val formattedCode =
"""
class FooBar {
@Foo(
groups = [
"a",
"b"
]
)
val bar: Any
}
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolation(2, 5, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct")
.isFormattedAs(formattedCode)
}
@Test
fun `Given a annotation with parameter followed by an annotation without parameters on the same line as the annotated construct`() {
val code =
"""
class FooBar {
@Foo("foo")
@Bar val bar: Any
}
""".trimIndent()
val formattedCode =
"""
class FooBar {
@Foo("foo")
@Bar
val bar: Any
}
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolation(3, 5, "Annotation must be placed on separate line")
.isFormattedAs(formattedCode)
}
@Test
fun `Issue 497 - Given a data class`() {
val code =
"""
data class Foo(val bar: String)
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 509 - Given a overridden function class`() {
val code =
"""
override fun foo()
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 552 - Given multiple blank lines before annotation`() {
val code =
"""
@JvmField
var foo: String
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 628 - Given an annotation before the primary constructor `() {
val code =
"""
class Foo @Inject internal constructor()
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 642 - Given annotations on method parameters on same line as parameter`() {
val code =
"""
fun foo1(
@Path("fooId") fooId: String,
@Path("bar") bar: String,
@Body body: Foo
): Completable
fun foo2(@Query("include") include: String? = null, @QueryMap fields: Map<String, String> = emptyMap()): Single
fun foo3(@Path("fooId") fooId: String): Completable
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 642 - Given annotations on constructor parameters on same line as parameter`() {
val code =
"""
class Foo(@Path("fooId") val fooId: String)
class Bar(
@NotNull("fooId") val fooId: String,
@NotNull("bar") bar: String
)
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 642 - Given annotations on arguments on same line as argument`() {
val code =
"""
val foo =
foo(
@ExpressionStringAnn("foo") "test",
@ExpressionIntAnn("bar") 42
)
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 642 - Given annotations on type arguments on same line as argument`() {
val code =
"""
val aProperty: Map<@Ann("test") Int, @JvmSuppressWildcards(true) (String) -> Int?>
val bProperty: Map<
@Ann String,
@Ann("test") Int,
@JvmSuppressWildcards(true) (String) -> Int?
>
fun doSomething() {
funWithGenericsCall<@JvmSuppressWildcards(true) Int>()
}
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 740 - Given multiple annotations and ending with a EOL comment before annotated construct`() {
val code =
"""
annotation class A
annotation class B
@A // comment
@B
fun foo1() {}
@A
@B // comment
fun foo2() {}
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Nested
inner class FileAnnotation {
@Test
fun `Issue 714 - Given a file annotation without parameter on same line as package`() {
val code =
"""
@file:JvmName package foo.bar
""".trimIndent()
val formattedCode =
"""
@file:JvmName
package foo.bar
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolation(1, 13, "File annotations should be separated from file contents with a blank line")
.isFormattedAs(formattedCode)
}
@Test
fun `Issue 624 - Given a file annotation with parameter on same line as package`() {
val code =
"""
@file:JvmName("FooClass") package foo.bar
""".trimIndent()
val formattedCode =
"""
@file:JvmName("FooClass")
package foo.bar
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolations(
LintViolation(1, 1, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct"),
LintViolation(1, 25, "File annotations should be separated from file contents with a blank line"),
).isFormattedAs(formattedCode)
}
@Test
fun `Issue 714 - Given a file annotation on the line above the package statement but without blank line in between`() {
val code =
"""
@file:JvmName
package foo.bar
""".trimIndent()
val formattedCode =
"""
@file:JvmName
package foo.bar
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolation(1, 13, "File annotations should be separated from file contents with a blank line")
.isFormattedAs(formattedCode)
}
@Test
fun `Issue 714 - Given a file annotation followed by an EOL comment, on the line above the package statement but without blank line in between`() {
val code =
"""
@file:JvmName // comment
package foo.bar
""".trimIndent()
val formattedCode =
"""
@file:JvmName // comment
package foo.bar
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolation(1, 13, "File annotations should be separated from file contents with a blank line")
.isFormattedAs(formattedCode)
}
@Test
fun `Issue 714 - Given a file annotation followed by an block comment, on the same line as the package statement`() {
val code =
"""
@file:JvmName /* comment */ package foo.bar
""".trimIndent()
val formattedCode =
"""
@file:JvmName /* comment */
package foo.bar
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolation(1, 13, "File annotations should be separated from file contents with a blank line")
.isFormattedAs(formattedCode)
}
@Test
fun `lint file annotations should be separated with a blank line in script 1`() {
val code =
"""
@file:Suppress("UnstableApiUsage")
pluginManagement {
}
""".trimIndent()
val formattedCode =
"""
@file:Suppress("UnstableApiUsage")
pluginManagement {
}
""".trimIndent()
annotationRuleAssertThat(code)
.asKotlinScript()
.hasLintViolation(1, 34, "File annotations should be separated from file contents with a blank line")
.isFormattedAs(formattedCode)
}
}
@Test
fun `Given a receiver with annotation having a parameter should not be separate line`() {
val code =
"""
annotation class Ann(val arg: Int = 0)
fun @receiver:Ann(1) String.test() {}
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 1539 - Given an annotation with parameter followed by an EOL comment and followed by another annotation`() {
val code =
"""
@Suppress("AnnotationRule") // some comment
@Bar
class Foo
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Issue 1539 - Given an annotation with parameter followed by an EOL comment on separate line before annotated construct`() {
val code =
"""
@Suppress("AnnotationRule")
// some comment between last annotation and annotated construct
class Foo
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
@Test
fun `Given a line containing multiple annotations without parameters and another line with another annotation`() {
val code =
"""
@Foo1
@Foo2 @Foo3
fun foo() {}
""".trimIndent()
val formattedCode =
"""
@Foo1
@Foo2
@Foo3
fun foo() {}
""".trimIndent()
annotationRuleAssertThat(code)
.asKotlinScript()
.hasLintViolation(2, 1, "Annotation must be placed on separate line")
.isFormattedAs(formattedCode)
}
@Test
fun `Given an annotated expression on same line as annotated construct and the annotation contains a parameter then report a violation which can not be autocorrected`() {
val code =
"""
fun foo() = @Suppress("DEPRECATION") bar()
""".trimIndent()
annotationRuleAssertThat(code)
.hasLintViolationWithoutAutoCorrect(1, 13, "Annotation with parameter(s) should be placed on a separate line prior to the annotated construct")
}
@Test
fun `Given an annotation with multiple annotation entries then do not force wrapping of the entries`() {
val code =
"""
@[JvmStatic Provides]
fun foo() = 42
""".trimIndent()
annotationRuleAssertThat(code).hasNoLintViolations()
}
}