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 package com.qulice.pmd;
32
33 import com.google.common.base.Joiner;
34 import com.jcabi.matchers.RegexMatchers;
35 import com.qulice.pmd.rules.ProhibitPlainJunitAssertionsRule;
36 import com.qulice.spi.Environment;
37 import com.qulice.spi.Violation;
38 import java.io.File;
39 import java.util.Collections;
40 import org.hamcrest.MatcherAssert;
41 import org.hamcrest.Matchers;
42 import org.hamcrest.core.IsEqual;
43 import org.hamcrest.core.IsNot;
44 import org.junit.jupiter.api.Test;
45 import org.junit.jupiter.api.condition.EnabledForJreRange;
46 import org.junit.jupiter.api.condition.JRE;
47
48
49
50
51
52 @SuppressWarnings("PMD.TooManyMethods")
53 final class PmdValidatorTest {
54
55
56
57
58
59
60 private static final String STATIC_ACCESS =
61 "%s\\[\\d+-\\d+\\]: Static fields should be accessed in a static way \\[CLASS_NAME.FIELD_NAME\\]\\.";
62
63
64
65
66
67 private static final String STATIC_VIA_THIS =
68 "%s\\[\\d+-\\d+\\]: Static members should be accessed in a static way \\[CLASS_NAME.FIELD_NAME\\], not via instance reference.";
69
70
71
72
73
74 private static final String CODE_IN_CON =
75 "%s\\[\\d+-\\d+\\]: Only field initialization or call to other constructors in a constructor";
76
77
78
79
80 private static final String NO_CON_INIT =
81 "%s\\[\\d+-\\d+\\]: Avoid doing field initialization outside constructor.";
82
83
84
85
86 private static final String MULT_CON_INIT =
87 "%s\\[\\d+-\\d+\\]: Avoid field initialization in several constructors.";
88
89
90
91
92 private static final String BRACKETS = "(%s)";
93
94
95
96
97 private static final String PLAIN_ASSERTIONS =
98 "Avoid using Plain JUnit assertions";
99
100
101
102
103 private static final String STATIC_METHODS =
104 "Public static methods are prohibited";
105
106
107
108
109 private static final String FILES_CREATE_ERR =
110 "Files.createFile should not be used in tests, replace them with @Rule TemporaryFolder";
111
112
113
114
115
116 @Test
117 void findsProblemsInJavaFiles() throws Exception {
118 final String file = "src/main/java/Main.java";
119 final Environment env = new Environment.Mock()
120 .withFile(file, "class Main { int x = 0; }");
121 MatcherAssert.assertThat(
122 "Violations should be found",
123 new PmdValidator(env).validate(
124 Collections.singletonList(new File(env.basedir(), file))
125 ),
126 Matchers.not(Matchers.<Violation>empty())
127 );
128 }
129
130
131
132
133
134 @Test
135 void understandsMethodReferences() throws Exception {
136 final String file = "UnderstandsMethodReferences.java";
137 new PmdAssert(
138 file,
139 Matchers.is(true),
140 Matchers.not(
141 Matchers.containsString("(UnusedPrivateMethod)")
142 )
143 ).validate();
144 }
145
146
147
148
149
150
151 @Test
152 @SuppressWarnings("PMD.AvoidDuplicateLiterals")
153 void doesNotComplainAboutConstantsInInnerClasses() throws Exception {
154 final String file = "src/main/java/foo/Foo.java";
155 final Environment env = new Environment.Mock().withFile(
156 file,
157 Joiner.on('\n').join(
158 "package foo;",
159 "interface Foo {",
160 " final class Bar implements Foo {",
161 " private static final Pattern TEST =",
162 " Pattern.compile(\"hey\");",
163 " public String doSomething() {",
164 " return Foo.Bar.TEST.toString();",
165 " }",
166 " }",
167 "}"
168 )
169 );
170 MatcherAssert.assertThat(
171 "Private constant in inner class is not a violation",
172 new PmdValidator(env).validate(
173 Collections.singletonList(new File(env.basedir(), file))
174 ),
175 Matchers.<Violation>empty()
176 );
177 }
178
179
180
181
182
183 @Test
184 void allowsFieldInitializationWhenConstructorIsMissing()
185 throws Exception {
186 final String file = "FieldInitNoConstructor.java";
187 new PmdAssert(
188 file, Matchers.is(false),
189 Matchers.not(
190 RegexMatchers.containsPattern(
191 String.format(PmdValidatorTest.NO_CON_INIT, file)
192 )
193 )
194 ).validate();
195 }
196
197
198
199
200
201 @Test
202 void forbidsFieldInitializationWhenConstructorExists()
203 throws Exception {
204 final String file = "FieldInitConstructor.java";
205 new PmdAssert(
206 file, Matchers.is(false),
207 RegexMatchers.containsPattern(
208 String.format(PmdValidatorTest.NO_CON_INIT, file)
209 )
210 ).validate();
211 }
212
213
214
215
216
217
218 @Test
219 void allowsStaticFieldInitializationWhenConstructorExists()
220 throws Exception {
221 final String file = "StaticFieldInitConstructor.java";
222 new PmdAssert(
223 file, Matchers.is(true),
224 Matchers.not(
225 RegexMatchers.containsPattern(
226 String.format(PmdValidatorTest.NO_CON_INIT, file)
227 )
228 )
229 ).validate();
230 }
231
232
233
234
235
236
237 @Test
238 void forbidsFieldInitializationInSeveralConstructors()
239 throws Exception {
240 final String file = "FieldInitSeveralConstructors.java";
241 new PmdAssert(
242 file, Matchers.is(false),
243 RegexMatchers.containsPattern(
244 String.format(PmdValidatorTest.MULT_CON_INIT, file)
245 )
246 ).validate();
247 }
248
249
250
251
252
253
254 @Test
255 void allowsFieldInitializationInOneConstructor()
256 throws Exception {
257 final String file = "FieldInitOneConstructor.java";
258 new PmdAssert(
259 file, Matchers.is(true),
260 Matchers.not(
261 RegexMatchers.containsPattern(
262 String.format(PmdValidatorTest.MULT_CON_INIT, file)
263 )
264 )
265 ).validate();
266 }
267
268
269
270
271
272 @Test
273 void forbidsUnnecessaryFinalModifier()
274 throws Exception {
275 final String file = "UnnecessaryFinalModifier.java";
276 new PmdAssert(
277 file, Matchers.is(false),
278 Matchers.containsString("Unnecessary modifier 'final'")
279 ).validate();
280 }
281
282
283
284
285
286 @Test
287 void forbidsUselessParentheses()
288 throws Exception {
289 final String file = "UselessParentheses.java";
290 new PmdAssert(
291 file, Matchers.is(false),
292 Matchers.containsString("Useless parentheses")
293 ).validate();
294 }
295
296
297
298
299
300
301 @Test
302 void forbidsCodeInConstructor()
303 throws Exception {
304 final String file = "CodeInConstructor.java";
305 new PmdAssert(
306 file, Matchers.is(false),
307 RegexMatchers.containsPattern(
308 String.format(PmdValidatorTest.CODE_IN_CON, file)
309 )
310 ).validate();
311 }
312
313
314
315
316
317 @Test
318 void allowsLambdaInConstructor()
319 throws Exception {
320 final String file = "LambdaInConstructor.java";
321 new PmdAssert(
322 file, new IsEqual<>(true),
323 new IsNot<>(
324 RegexMatchers.containsPattern(
325 String.format(PmdValidatorTest.CODE_IN_CON, file)
326 )
327 )
328 ).validate();
329 }
330
331
332
333
334
335 @Test
336 void forbidsFilesCreateFileInTests() throws Exception {
337 new PmdAssert(
338 "FilesCreateFileTest.java",
339 Matchers.is(false),
340 Matchers.containsString(
341 PmdValidatorTest.FILES_CREATE_ERR
342 )
343 ).validate();
344 }
345
346
347
348
349
350 @Test
351 void forbidsFilesCreateFileOutsideOfTests() throws Exception {
352 new PmdAssert(
353 "FilesCreateFileOther.java",
354 Matchers.is(true),
355 Matchers.not(
356 Matchers.containsString(
357 PmdValidatorTest.FILES_CREATE_ERR
358 )
359 )
360 ).validate();
361 }
362
363
364
365
366
367
368 @Test
369 void acceptsCallToConstructorInConstructor()
370 throws Exception {
371 final String file = "CallToConstructorInConstructor.java";
372 new PmdAssert(
373 file, Matchers.is(true),
374 Matchers.not(
375 RegexMatchers.containsPattern(
376 String.format(PmdValidatorTest.CODE_IN_CON, file)
377 )
378 )
379 ).validate();
380 }
381
382
383
384
385
386
387 @Test
388 void acceptsCallToStaticFieldsInStaticWay()
389 throws Exception {
390 final String file = "StaticAccessToStaticFields.java";
391 new PmdAssert(
392 file, Matchers.is(true),
393 Matchers.allOf(
394 Matchers.not(
395 RegexMatchers.containsPattern(
396 String.format(PmdValidatorTest.STATIC_ACCESS, file)
397 )
398 ),
399 Matchers.not(
400 RegexMatchers.containsPattern(
401 String.format(PmdValidatorTest.STATIC_VIA_THIS, file)
402 )
403 )
404 )
405 ).validate();
406 }
407
408
409
410
411
412
413 @Test
414 void forbidsCallToStaticFieldsDirectly()
415 throws Exception {
416 final String file = "DirectAccessToStaticFields.java";
417 new PmdAssert(
418 file, Matchers.is(false),
419 RegexMatchers.containsPattern(
420 String.format(PmdValidatorTest.STATIC_ACCESS, file)
421 )
422 ).validate();
423 }
424
425
426
427
428
429
430 @Test
431 void forbidsCallToStaticFieldsViaThis()
432 throws Exception {
433 final String file = "AccessToStaticFieldsViaThis.java";
434 new PmdAssert(
435 file, Matchers.is(false),
436 RegexMatchers.containsPattern(
437 String.format(PmdValidatorTest.STATIC_VIA_THIS, file)
438 )
439 ).validate();
440 }
441
442
443
444
445
446
447 @Test
448 void forbidsCallToStaticMethodsViaThis()
449 throws Exception {
450 final String file = "AccessToStaticMethodsViaThis.java";
451 new PmdAssert(
452 file, Matchers.is(false),
453 RegexMatchers.containsPattern(
454 String.format(PmdValidatorTest.STATIC_VIA_THIS, file)
455 )
456 ).validate();
457 }
458
459
460
461
462
463
464 @Test
465 void forbidsNonPublicCloneMethod() throws Exception {
466 new PmdAssert(
467 "CloneMethodMustBePublic.java",
468 Matchers.is(false),
469 Matchers.containsString(
470 String.format(
471 PmdValidatorTest.BRACKETS,
472 "CloneMethodMustBePublic"
473 )
474 )
475 ).validate();
476 }
477
478
479
480
481
482
483
484 @Test
485 void forbidsCloneMethodReturnTypeNotMatchingClassName()
486 throws Exception {
487 new PmdAssert(
488 "CloneMethodReturnTypeMustMatchClassName.java",
489 Matchers.is(false),
490 Matchers.containsString(
491 String.format(
492 PmdValidatorTest.BRACKETS,
493 "CloneMethodReturnTypeMustMatchClassName"
494 )
495 )
496 ).validate();
497 }
498
499
500
501
502
503
504 @Test
505 void forbidsNonSimplifiedTernaryOperators()
506 throws Exception {
507 new PmdAssert(
508 "SimplifiedTernary.java",
509 Matchers.is(false),
510 Matchers.containsString(
511 String.format(
512 PmdValidatorTest.BRACKETS,
513 "SimplifiedTernary"
514 )
515 )
516 ).validate();
517 }
518
519
520
521
522
523
524
525
526
527 @Test
528 void prohibitsStaticImportsPlainAssertionsInTests()
529 throws Exception {
530 final String file = "PlainJUnitAssertionStaticImportBlock.java";
531 new PmdAssert(
532 file, Matchers.is(false),
533 Matchers.containsString(
534 PmdValidatorTest.PLAIN_ASSERTIONS
535 )
536 ).validate();
537 }
538
539
540
541
542
543
544
545
546 @Test
547 void prohibitsPlainJunitAssertionsInTestMethods()
548 throws Exception {
549 final String file = "PlainJUnitAssertionTestMethod.java";
550 new PmdAssert(
551 file, Matchers.is(false),
552 Matchers.containsString(
553 PmdValidatorTest.PLAIN_ASSERTIONS
554 )
555 ).validate();
556 }
557
558
559
560
561
562
563
564 @Test
565 void allowsAssertFail()
566 throws Exception {
567 final String file = "AllowAssertFail.java";
568 new PmdAssert(
569 file, Matchers.is(true),
570 Matchers.not(
571 Matchers.containsString(
572 PmdValidatorTest.PLAIN_ASSERTIONS
573 )
574 )
575 ).validate();
576 }
577
578
579
580
581
582 @Test
583 void allowsNonTransientFields() throws Exception {
584 final String file = "AllowNonTransientFields.java";
585 new PmdAssert(
586 file, Matchers.is(true),
587 Matchers.not(
588 Matchers.containsString(
589 "Found non-transient, non-static member."
590 )
591 )
592 ).validate();
593 }
594
595
596
597
598
599 @Test
600 void prohibitsPublicStaticMethods() throws Exception {
601 new PmdAssert(
602 "StaticPublicMethod.java",
603 Matchers.is(false),
604 Matchers.containsString(PmdValidatorTest.STATIC_METHODS)
605 ).validate();
606 }
607
608
609
610
611
612 @Test
613 void allowsPublicStaticMainMethod() throws Exception {
614 new PmdAssert(
615 "StaticPublicVoidMainMethod.java",
616 Matchers.is(true),
617 Matchers.not(
618 Matchers.containsString(PmdValidatorTest.STATIC_METHODS)
619 )
620 ).validate();
621 }
622
623
624
625
626
627
628
629
630 @Test
631 void allowsJunitFrameworkPublicStaticMethods() throws Exception {
632 new PmdAssert(
633 "JunitStaticPublicMethods.java",
634 Matchers.is(true),
635 Matchers.not(
636 Matchers.containsString(PmdValidatorTest.STATIC_METHODS)
637 )
638 ).validate();
639 }
640
641
642
643
644
645 @Test
646 void allowsDuplicateLiteralsInAnnotations() throws Exception {
647 new PmdAssert(
648 "AllowsDuplicateLiteralsInAnnotations.java",
649 Matchers.is(true),
650 Matchers.not(
651 Matchers.containsString("AvoidDuplicateLiterals")
652 )
653 ).validate();
654 }
655
656
657
658
659
660
661 @Test
662 void testShouldBePackagePrivate() throws Exception {
663 new PmdAssert(
664 "TestShouldBePackagePrivate.java",
665 Matchers.is(false),
666 Matchers.containsString("JUnit5TestShouldBePackagePrivate")
667 ).validate();
668 }
669
670
671
672
673
674 @Test
675 void allowJunitThirdTestClassToBeFinal() throws Exception {
676 new PmdAssert(
677 "Junit3TestClassShouldBeFinal.java",
678 Matchers.is(false),
679 Matchers.containsString("JUnitTestClassShouldBeFinal")
680 ).validate();
681 }
682
683
684
685
686
687 @Test
688 void allowJunitFourthTestClassToBeFinal() throws Exception {
689 new PmdAssert(
690 "Junit4TestClassShouldBeFinal.java",
691 Matchers.is(false),
692 Matchers.containsString("JUnitTestClassShouldBeFinal")
693 ).validate();
694 }
695
696
697
698
699
700 @Test
701 void allowJunitFifthTestClassToBeFinal() throws Exception {
702 new PmdAssert(
703 "Junit5TestClassShouldBeFinal.java",
704 Matchers.is(false),
705 Matchers.containsString("JUnitTestClassShouldBeFinal")
706 ).validate();
707 }
708
709
710
711
712
713 @Test
714 void allowJunitTestClassToBeFinal() throws Exception {
715 new PmdAssert(
716 "JunitTestClassIsFinal.java",
717 Matchers.is(true),
718 Matchers.not(
719 Matchers.containsString("JUnitTestClassShouldBeFinal")
720 )
721 ).validate();
722 }
723
724
725
726
727
728 @Test
729 @EnabledForJreRange(min = JRE.JAVA_14, max = JRE.JAVA_21)
730 void allowRecordClasses() throws Exception {
731 new PmdAssert(
732 "RecordParsed.java",
733 Matchers.is(true),
734 Matchers.not(
735 Matchers.containsString(PmdValidatorTest.STATIC_METHODS)
736 )
737 ).validate();
738 }
739
740
741
742
743
744 @Test
745 void allowsSwaggerAnnotations() throws Exception {
746 new PmdAssert(
747 "SwaggerApi.java",
748 Matchers.is(true),
749 Matchers.not(
750 Matchers.containsString("RuleSetReferenceId")
751 )
752 ).validate();
753 }
754
755
756
757
758
759 @Test
760 void prohibitsUnicodeCharactersInMethodNames() throws Exception {
761 new PmdAssert(
762 "UnicodeCharactersInMethodNames.java",
763 Matchers.is(false),
764 Matchers.containsString("MethodNamingConventions")
765 ).validate();
766 }
767 }