View Javadoc
1   /*
2    * SPDX-FileCopyrightText: Copyright (c) 2011-2026 Yegor Bugayenko
3    * SPDX-License-Identifier: MIT
4    */
5   package com.qulice.pmd;
6   
7   import com.google.common.base.Joiner;
8   import com.jcabi.matchers.RegexMatchers;
9   import com.qulice.pmd.rules.ProhibitPlainJunitAssertionsRule;
10  import com.qulice.spi.Environment;
11  import com.qulice.spi.Violation;
12  import java.io.File;
13  import java.util.Collections;
14  import org.hamcrest.MatcherAssert;
15  import org.hamcrest.Matchers;
16  import org.hamcrest.core.IsEqual;
17  import org.hamcrest.core.IsNot;
18  import org.hamcrest.core.StringContains;
19  import org.junit.jupiter.api.Assertions;
20  import org.junit.jupiter.api.Test;
21  import org.junit.jupiter.api.condition.EnabledForJreRange;
22  import org.junit.jupiter.api.condition.JRE;
23  
24  /**
25   * Test case for {@link PmdValidator} class.
26   *
27   * @since 0.3
28   */
29  @SuppressWarnings("PMD.TooManyMethods")
30  final class PmdValidatorTest {
31      /**
32       * Error message for forbidding access to static fields other than with a
33       * static way.
34       *
35       * @checkstyle LineLengthCheck (40 lines)
36       */
37      private static final String STATIC_ACCESS =
38          "%s\\[\\d+-\\d+\\]: Static fields should be accessed in a static way \\[CLASS_NAME.FIELD_NAME\\]\\.";
39  
40      /**
41       * Error message for forbidding access to static members via instance
42       * reference using 'this' keyword.
43       */
44      private static final String STATIC_VIA_THIS =
45          "%s\\[\\d+-\\d+\\]: Static members should be accessed in a static way \\[CLASS_NAME.FIELD_NAME\\], not via instance reference.";
46  
47      /**
48       * Error message for forbidding instructions inside a constructor other than
49       * field initialization or call to other constructors.
50       */
51      private static final String CODE_IN_CON =
52          "%s\\[\\d+-\\d+\\]: Only field initialization or call to other constructors in a constructor";
53  
54      /**
55       * Pattern for non-constructor field initialization.
56       */
57      private static final String NO_CON_INIT =
58          "%s\\[\\d+-\\d+\\]: Avoid doing field initialization outside constructor.";
59  
60      /**
61       * Pattern multiple constructors field initialization.
62       */
63      private static final String MULT_CON_INIT =
64          "%s\\[\\d+-\\d+\\]: Avoid field initialization in several constructors.";
65  
66      /**
67       * Template for string inside brackets.
68       */
69      private static final String BRACKETS = "(%s)";
70  
71      /**
72       * Pattern using plain JUnit assertions.
73       */
74      private static final String PLAIN_ASSERTIONS =
75          "Avoid using Plain JUnit assertions";
76  
77      /**
78       * Error message used to inform about using public static method.
79       */
80      private static final String STATIC_METHODS =
81          "Public static methods are prohibited";
82  
83      /**
84       * Error text for Files.createFile.
85       */
86      private static final String FILES_CREATE_ERR =
87          "Files.createFile should not be used in tests, replace them with @Rule TemporaryFolder";
88  
89      /**
90       * PmdValidator can find violations in Java file(s).
91       *
92       * @throws Exception If something wrong happens inside.
93       */
94      @Test
95      void findsProblemsInJavaFiles() throws Exception {
96          final String file = "src/main/java/Main.java";
97          final Environment env = new Environment.Mock()
98              .withFile(file, "class Main { int x = 0; }");
99          MatcherAssert.assertThat(
100             "Violations should be found",
101             new PmdValidator(env).validate(
102                 Collections.singletonList(new File(env.basedir(), file))
103             ),
104             Matchers.not(Matchers.<Violation>empty())
105         );
106     }
107 
108     /**
109      * PmdValidator can understand method references.
110      *
111      * @throws Exception If something wrong happens inside.
112      */
113     @Test
114     void understandsMethodReferences() throws Exception {
115         final String file = "UnderstandsMethodReferences.java";
116         new PmdAssert(
117             file,
118             Matchers.is(true),
119             Matchers.not(
120                 Matchers.containsString("(UnusedPrivateMethod)")
121             )
122         ).validate();
123     }
124 
125     /**
126      * PmdValidator does not think that constant is unused when it is used just
127      * from the inner class.
128      *
129      * @throws Exception If something wrong happens inside.
130      */
131     @Test
132     @SuppressWarnings("PMD.AvoidDuplicateLiterals")
133     void doesNotComplainAboutConstantsInInnerClasses() throws Exception {
134         final String file = "src/main/java/foo/Foo.java";
135         final Environment env = new Environment.Mock().withFile(
136             file,
137             Joiner.on('\n').join(
138                 "package foo;",
139                 "interface Foo {",
140                 "  final class Bar implements Foo {",
141                 "    private static final Pattern TEST =",
142                 "      Pattern.compile(\"hey\");",
143                 "    public String doSomething() {",
144                 "      return Foo.Bar.TEST.toString();",
145                 "    }",
146                 "  }",
147                 "}"
148             )
149         );
150         MatcherAssert.assertThat(
151             "Private constant in inner class is not a violation",
152             new PmdValidator(env).validate(
153                 Collections.singletonList(new File(env.basedir(), file))
154             ),
155             Matchers.<Violation>empty()
156         );
157     }
158 
159     /**
160      * PmdValidator can allow field initialization when constructor is missing.
161      *
162      * @throws Exception If something wrong happens inside.
163      */
164     @Test
165     void allowsFieldInitializationWhenConstructorIsMissing()
166         throws Exception {
167         final String file = "FieldInitNoConstructor.java";
168         new PmdAssert(
169             file,
170             Matchers.is(true),
171             Matchers.not(
172                 RegexMatchers.containsPattern(
173                     String.format(
174                         PmdValidatorTest.NO_CON_INIT,
175                         file
176                     )
177                 )
178             )
179         ).validate();
180     }
181 
182     /**
183      * PmdValidator can forbid field initialization when constructor exists.
184      *
185      * @throws Exception If something wrong happens inside.
186      */
187     @Test
188     void forbidsFieldInitializationWhenConstructorExists()
189         throws Exception {
190         final String file = "FieldInitConstructor.java";
191         new PmdAssert(
192             file,
193             Matchers.is(false),
194             RegexMatchers.containsPattern(
195                 String.format(
196                     PmdValidatorTest.NO_CON_INIT,
197                     file
198                 )
199             )
200         ).validate();
201     }
202 
203     /**
204      * PmdValidator can allow static field initialization when constructor
205      * exists.
206      *
207      * @throws Exception If something wrong happens inside.
208      */
209     @Test
210     void allowsStaticFieldInitializationWhenConstructorExists()
211         throws Exception {
212         final String file = "StaticFieldInitConstructor.java";
213         new PmdAssert(
214             file,
215             Matchers.is(true),
216             Matchers.not(
217                 RegexMatchers.containsPattern(
218                     String.format(
219                         PmdValidatorTest.NO_CON_INIT,
220                         file
221                     )
222                 )
223             )
224         ).validate();
225     }
226 
227     /**
228      * PmdValidator can forbid field initialization in several constructors.
229      * Only one constructor should do real work. Others - delegate to it.
230      *
231      * @throws Exception If something wrong happens inside.
232      */
233     @Test
234     void forbidsFieldInitializationInSeveralConstructors()
235         throws Exception {
236         final String file = "FieldInitSeveralConstructors.java";
237         new PmdAssert(
238             file,
239             Matchers.is(false),
240             RegexMatchers.containsPattern(
241                 String.format(
242                     PmdValidatorTest.MULT_CON_INIT,
243                     file
244                 )
245             )
246         ).validate();
247     }
248 
249     /**
250      * PmdValidator can allow field initialization in one constructor. Only one
251      * constructor should do real work. Others - delegate to it.
252      *
253      * @throws Exception If something wrong happens inside.
254      */
255     @Test
256     void allowsFieldInitializationInOneConstructor()
257         throws Exception {
258         final String file = "FieldInitOneConstructor.java";
259         new PmdAssert(
260             file,
261             Matchers.is(true),
262             Matchers.not(
263                 RegexMatchers.containsPattern(
264                     String.format(
265                         PmdValidatorTest.MULT_CON_INIT,
266                         file
267                     )
268                 )
269             )
270         ).validate();
271     }
272 
273     /**
274      * PmdValidator forbids unnecessary final modifier for methods.
275      *
276      * @throws Exception If something wrong happens inside.
277      */
278     @Test
279     void forbidsUnnecessaryFinalModifier()
280         throws Exception {
281         final String file = "UnnecessaryFinalModifier.java";
282         new PmdAssert(
283             file,
284             Matchers.is(false),
285             Matchers.containsString("Unnecessary modifier 'final'")
286         ).validate();
287     }
288 
289     /**
290      * PmdValidator forbid useless parentheses.
291      *
292      * @throws Exception If something wrong happens inside.
293      */
294     @Test
295     void forbidsUselessParentheses()
296         throws Exception {
297         final String file = "UselessParentheses.java";
298         new PmdAssert(
299             file,
300             Matchers.is(false),
301             Matchers.containsString("Useless parentheses")
302         ).validate();
303     }
304 
305     /**
306      * PmdValidator forbids code in constructor other than field
307      * initialization.
308      *
309      * @throws Exception If something wrong happens inside.
310      */
311     @Test
312     void forbidsCodeInConstructor()
313         throws Exception {
314         final String file = "CodeInConstructor.java";
315         new PmdAssert(
316             file,
317             Matchers.is(false),
318             RegexMatchers.containsPattern(
319                 String.format(
320                     PmdValidatorTest.CODE_IN_CON,
321                     file
322                 )
323             )
324         ).validate();
325     }
326 
327     /**
328      * PmdValidator allows lambda in constructor.
329      *
330      * @throws Exception If something wrong happens inside.
331      */
332     @Test
333     void allowsLambdaInConstructor()
334         throws Exception {
335         final String file = "LambdaInConstructor.java";
336         new PmdAssert(
337             file,
338             new IsEqual<>(true),
339             new IsNot<>(
340                 RegexMatchers.containsPattern(
341                     String.format(
342                         PmdValidatorTest.CODE_IN_CON,
343                         file
344                     )
345                 )
346             )
347         ).validate();
348     }
349 
350     /**
351      * PmdValidator forbids usage of Files.createFile in tests.
352      *
353      * @throws Exception If something wrong happens inside.
354      */
355     @Test
356     void forbidsFilesCreateFileInTests() throws Exception {
357         new PmdAssert(
358             "FilesCreateFileTest.java",
359             Matchers.is(false),
360             Matchers.containsString(
361                 PmdValidatorTest.FILES_CREATE_ERR
362             )
363         ).validate();
364     }
365 
366     /**
367      * PmdValidator allows usage of Files.createFile outside of tests.
368      *
369      * @throws Exception If something wrong happens inside.
370      */
371     @Test
372     void forbidsFilesCreateFileOutsideOfTests() throws Exception {
373         new PmdAssert(
374             "FilesCreateFileOther.java",
375             Matchers.is(true),
376             Matchers.not(
377                 Matchers.containsString(
378                     PmdValidatorTest.FILES_CREATE_ERR
379                 )
380             )
381         ).validate();
382     }
383 
384     /**
385      * PmdValidator accepts calls to other constructors or call to super class
386      * constructor in constructors.
387      *
388      * @throws Exception If something wrong happens inside.
389      */
390     @Test
391     void acceptsCallToConstructorInConstructor()
392         throws Exception {
393         final String file = "CallToConstructorInConstructor.java";
394         new PmdAssert(
395             file,
396             Matchers.is(true),
397             Matchers.not(
398                 RegexMatchers.containsPattern(
399                     String.format(
400                         PmdValidatorTest.CODE_IN_CON,
401                         file
402                     )
403                 )
404             )
405         ).validate();
406     }
407 
408     /**
409      * PmdValidator accepts calls to static fields in a static way.
410      *
411      * @throws Exception If something wrong happens inside.
412      */
413     @Test
414     void acceptsCallToStaticFieldsInStaticWay()
415         throws Exception {
416         final String file = "StaticAccessToStaticFields.java";
417         new PmdAssert(
418             file,
419             Matchers.is(true),
420             Matchers.allOf(
421                 Matchers.not(
422                     RegexMatchers.containsPattern(
423                         String.format(
424                             PmdValidatorTest.STATIC_ACCESS,
425                             file
426                         )
427                     )
428                 ),
429                 Matchers.not(
430                     RegexMatchers.containsPattern(
431                         String.format(
432                             PmdValidatorTest.STATIC_VIA_THIS,
433                             file
434                         )
435                     )
436                 )
437             )
438         ).validate();
439     }
440 
441     /**
442      * PmdValidator forbids calls to static fields directly in a non static
443      * way.
444      *
445      * @throws Exception If something wrong happens inside.
446      */
447     @Test
448     void forbidsCallToStaticFieldsDirectly()
449         throws Exception {
450         final String file = "DirectAccessToStaticFields.java";
451         new PmdAssert(
452             file,
453             Matchers.is(false),
454             RegexMatchers.containsPattern(
455                 String.format(
456                     PmdValidatorTest.STATIC_ACCESS,
457                     file
458                 )
459             )
460         ).validate();
461     }
462 
463     /**
464      * PmdValidator forbids calls to static fields in a non static way via
465      * instance reference.
466      *
467      * @throws Exception If something wrong happens inside.
468      */
469     @Test
470     void forbidsCallToStaticFieldsViaThis()
471         throws Exception {
472         final String file = "AccessToStaticFieldsViaThis.java";
473         new PmdAssert(
474             file,
475             Matchers.is(false),
476             RegexMatchers.containsPattern(
477                 String.format(
478                     PmdValidatorTest.STATIC_VIA_THIS,
479                     file
480                 )
481             )
482         ).validate();
483     }
484 
485     /**
486      * PmdValidator forbids calls to static methods in a non static way via
487      * instance reference.
488      *
489      * @throws Exception If something wrong happens inside.
490      */
491     @Test
492     void forbidsCallToStaticMethodsViaThis()
493         throws Exception {
494         final String file = "AccessToStaticMethodsViaThis.java";
495         new PmdAssert(
496             file,
497             Matchers.is(false),
498             RegexMatchers.containsPattern(
499                 String.format(
500                     PmdValidatorTest.STATIC_VIA_THIS,
501                     file
502                 )
503             )
504         ).validate();
505     }
506 
507     /**
508      * PmdValidator forbids non public clone methods (PMD rule
509      * rulesets/java/clone.xml/CloneMethodMustBePublic).
510      *
511      * @throws Exception If something wrong happens inside.
512      */
513     @Test
514     void forbidsNonPublicCloneMethod() throws Exception {
515         new PmdAssert(
516             "CloneMethodMustBePublic.java",
517             Matchers.is(false),
518             Matchers.containsString(
519                 String.format(
520                     PmdValidatorTest.BRACKETS,
521                     "CloneMethodMustBePublic"
522                 )
523             )
524         ).validate();
525     }
526 
527     /**
528      * PmdValidator forbids clone methods with return type not matching class
529      * name (PMD rule
530      * rulesets/java/clone.xml/CloneMethodReturnTypeMustMatchClassName).
531      *
532      * @throws Exception If something wrong happens inside.
533      */
534     @Test
535     void forbidsCloneMethodReturnTypeNotMatchingClassName()
536         throws Exception {
537         new PmdAssert(
538             "CloneMethodReturnTypeMustMatchClassName.java",
539             Matchers.is(false),
540             Matchers.containsString(
541                 String.format(
542                     PmdValidatorTest.BRACKETS,
543                     "CloneMethodReturnTypeMustMatchClassName"
544                 )
545             )
546         ).validate();
547     }
548 
549     /**
550      * PmdValidator forbids ternary operators that can be simplified (PMD rule
551      * rulesets/java/basic.xml/SimplifiedTernary).
552      *
553      * @throws Exception If something wrong happens inside.
554      */
555     @Test
556     void forbidsNonSimplifiedTernaryOperators()
557         throws Exception {
558         new PmdAssert(
559             "SimplifiedTernary.java",
560             Matchers.is(false),
561             Matchers.containsString(
562                 String.format(
563                     PmdValidatorTest.BRACKETS,
564                     "SimplifiedTernary"
565                 )
566             )
567         ).validate();
568     }
569 
570     /**
571      * PmdValidator can prohibit plain JUnit assertion in import block like
572      * import static org.junit.Assert.assert* import static
573      * junit.framework.Assert.assert*.
574      * <p>
575      * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
576      *
577      * @throws Exception If something wrong happens inside.
578      */
579     @Test
580     void prohibitsStaticImportsPlainAssertionsInTests()
581         throws Exception {
582         final String file = "PlainJUnitAssertionStaticImportBlock.java";
583         new PmdAssert(
584             file,
585             Matchers.is(false),
586             Matchers.containsString(
587                 PmdValidatorTest.PLAIN_ASSERTIONS
588             )
589         ).validate();
590     }
591 
592     /**
593      * PmdValidator can prohibit plain JUnit assertion in test methods like
594      * Assert.assertEquals.
595      * <p>
596      * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
597      *
598      * @throws Exception If something wrong happens inside.
599      */
600     @Test
601     void prohibitsPlainJunitAssertionsInTestMethods()
602         throws Exception {
603         final String file = "PlainJUnitAssertionTestMethod.java";
604         new PmdAssert(
605             file,
606             Matchers.is(false),
607             Matchers.containsString(
608                 PmdValidatorTest.PLAIN_ASSERTIONS
609             )
610         ).validate();
611     }
612 
613     /**
614      * PmdValidator can allow Assert.fail().
615      * <p>
616      * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
617      *
618      * @throws Exception If something wrong happens inside.
619      */
620     @Test
621     void allowsAssertFail()
622         throws Exception {
623         final String file = "AllowAssertFail.java";
624         new PmdAssert(
625             file,
626             Matchers.is(false),
627             Matchers.allOf(
628                 Matchers.not(
629                     Matchers.containsString(
630                         PmdValidatorTest.PLAIN_ASSERTIONS
631                     )
632                 ),
633                 Matchers.containsString("UnitTestContainsTooManyAsserts")
634             )
635         ).validate();
636     }
637 
638     /**
639      * PmdValidator can allow non-static, non-transient fields.
640      *
641      * @throws Exception If something wrong happens inside.
642      */
643     @Test
644     void allowsNonTransientFields() throws Exception {
645         final String file = "AllowNonTransientFields.java";
646         new PmdAssert(
647             file,
648             Matchers.is(true),
649             Matchers.not(
650                 Matchers.containsString(
651                     "Found non-transient, non-static member."
652                 )
653             )
654         ).validate();
655     }
656 
657     /**
658      * PmdValidator can prohibit public static methods.
659      *
660      * @throws Exception If something wrong happens inside.
661      */
662     @Test
663     void prohibitsPublicStaticMethods() throws Exception {
664         new PmdAssert(
665             "StaticPublicMethod.java",
666             Matchers.is(false),
667             Matchers.containsString(PmdValidatorTest.STATIC_METHODS)
668         ).validate();
669     }
670 
671     /**
672      * PmdValidator can allow public static void main(String...args) method.
673      *
674      * @throws Exception If something wrong happens inside.
675      */
676     @Test
677     void allowsPublicStaticMainMethod() throws Exception {
678         new PmdAssert(
679             "StaticPublicVoidMainMethod.java",
680             Matchers.is(true),
681             Matchers.not(
682                 Matchers.containsString(PmdValidatorTest.STATIC_METHODS)
683             )
684         ).validate();
685     }
686 
687     /**
688      * PmdValidator can allow JUnit public static methods marked with:<br>
689      * BeforeClass annotation.<br> AfterClass annotation.<br>
690      * Parameterized.Parameters annotation.
691      *
692      * @throws Exception If something wrong happens inside.
693      */
694     @Test
695     void allowsJunitFrameworkPublicStaticMethods() throws Exception {
696         new PmdAssert(
697             "JunitStaticPublicMethods.java",
698             Matchers.is(false),
699             Matchers.allOf(
700                 Matchers.not(
701                     Matchers.containsString(PmdValidatorTest.STATIC_METHODS)
702                 ),
703                 Matchers.containsString("UnitTestShouldIncludeAssert")
704             )
705         ).validate();
706     }
707 
708     /**
709      * PmdValidator can allow duplicate literals in annotations.
710      *
711      * @throws Exception If something wrong happens inside.
712      */
713     @Test
714     void allowsDuplicateLiteralsInAnnotations() throws Exception {
715         new PmdAssert(
716             "AllowsDuplicateLiteralsInAnnotations.java",
717             Matchers.is(true),
718             Matchers.not(
719                 Matchers.containsString("AvoidDuplicateLiterals")
720             )
721         ).validate();
722     }
723 
724     /**
725      * PmdValidator can allow only package private methods, marked with: Test,
726      * RepeatedTest, TestFactory, TestTemplate or ParameterizedTest annotations.
727      * @throws Exception If something wrong happens inside.
728      */
729     @Test
730     void testShouldBePackagePrivate() throws Exception {
731         new PmdAssert(
732             "TestShouldBePackagePrivate.java",
733             Matchers.is(false),
734             Matchers.containsString("JUnit5TestShouldBePackagePrivate")
735         ).validate();
736     }
737 
738     /**
739      * PmdValidator can allow only final JUnit3 test classes.
740      *
741      * @throws Exception If something wrong happens inside.
742      */
743     @Test
744     void allowJunitThirdTestClassToBeFinal() throws Exception {
745         new PmdAssert(
746             "Junit3TestClassShouldBeFinal.java",
747             Matchers.is(false),
748             Matchers.containsString("JUnitTestClassShouldBeFinal")
749         ).validate();
750     }
751 
752     /**
753      * PmdValidator can allow only final JUnit4 test classes.
754      *
755      * @throws Exception If something wrong happens inside.
756      */
757     @Test
758     void allowJunitFourthTestClassToBeFinal() throws Exception {
759         new PmdAssert(
760             "Junit4TestClassShouldBeFinal.java",
761             Matchers.is(false),
762             Matchers.containsString("JUnitTestClassShouldBeFinal")
763         ).validate();
764     }
765 
766     /**
767      * PmdValidator can allow only final JUnit5 test classes.
768      *
769      * @throws Exception If something wrong happens inside.
770      */
771     @Test
772     void allowJunitFifthTestClassToBeFinal() throws Exception {
773         new PmdAssert(
774             "Junit5TestClassShouldBeFinal.java",
775             Matchers.is(false),
776             Matchers.containsString("JUnitTestClassShouldBeFinal")
777         ).validate();
778     }
779 
780     /**
781      * PmdValidator can allow only final Junit test classes.
782      *
783      * @throws Exception If something wrong happens inside.
784      */
785     @Test
786     void allowJunitTestClassToBeFinal() throws Exception {
787         new PmdAssert(
788             "JunitTestClassIsFinal.java",
789             Matchers.is(false),
790             Matchers.allOf(
791                 Matchers.not(
792                     Matchers.containsString("JUnitTestClassShouldBeFinal")
793                 ),
794                 Matchers.containsString("UnitTestShouldIncludeAssert")
795             )
796         ).validate();
797     }
798 
799     /**
800      * PmdValidator can allow record classes.
801      *
802      * @throws Exception If something wrong happens inside.
803      */
804     @Test
805     @EnabledForJreRange(min = JRE.JAVA_21, max = JRE.JAVA_25)
806     void allowRecordClasses() throws Exception {
807         new PmdAssert(
808             "RecordParsed.java",
809             Matchers.is(true),
810             Matchers.not(
811                 Matchers.containsString(PmdValidatorTest.STATIC_METHODS)
812             )
813         ).validate();
814     }
815 
816     /**
817      * PmdValidator checks swagger annotation.
818      *
819      * @throws Exception If something wrong happens inside.
820      */
821     @Test
822     void allowsSwaggerAnnotations() throws Exception {
823         new PmdAssert(
824             "SwaggerApi.java",
825             Matchers.is(true),
826             Matchers.not(
827                 Matchers.containsString("RuleSetReferenceId")
828             )
829         ).validate();
830     }
831 
832     /**
833      * PmdValidator can prohibit unicode characters in method names.
834      *
835      * @throws Exception If something wrong happens inside.
836      */
837     @Test
838     void prohibitsUnicodeCharactersInMethodNames() throws Exception {
839         new PmdAssert(
840             "UnicodeCharactersInMethodNames.java",
841             Matchers.is(false),
842             Matchers.containsString("MethodNamingConventions")
843         ).validate();
844     }
845 
846     /**
847      * Check if UseStringIsEmptyRule not throws an NullPointerException when
848      * found a pattern matching.
849      */
850     @Test
851     void notThrowsAnNullPointerExceptionOnPatternMatching() {
852         Assertions.assertDoesNotThrow(
853             () -> new PmdAssert(
854                 "UseStringIsEmptyRuleFailsOnPatternMatching.java",
855                 new IsEqual<>(false),
856                 new StringContains("UnusedLocalVariable")
857             ).validate()
858         );
859     }
860 }