View Javadoc
1   /*
2    * Copyright (c) 2011-2025 Yegor Bugayenko
3    *
4    * All rights reserved.
5    *
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions
8    * are met: 1) Redistributions of source code must retain the above
9    * copyright notice, this list of conditions and the following
10   * disclaimer. 2) Redistributions in binary form must reproduce the above
11   * copyright notice, this list of conditions and the following
12   * disclaimer in the documentation and/or other materials provided
13   * with the distribution. 3) Neither the name of the Qulice.com nor
14   * the names of its contributors may be used to endorse or promote
15   * products derived from this software without specific prior written
16   * permission.
17   *
18   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
20   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22   * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29   * OF THE POSSIBILITY OF SUCH DAMAGE.
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   * Test case for {@link PmdValidator} class.
50   * @since 0.3
51   */
52  @SuppressWarnings("PMD.TooManyMethods")
53  final class PmdValidatorTest {
54  
55      /**
56       * Error message for forbidding access to static fields
57       * other than with a static way.
58       * @checkstyle LineLengthCheck (40 lines)
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       * Error message for forbidding access to static members
65       * via instance reference using 'this' keyword.
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       * Error message for forbidding instructions inside a constructor
72       * other than field initialization or call to other constructors.
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       * Pattern for non-constructor field initialization.
79       */
80      private static final String NO_CON_INIT =
81          "%s\\[\\d+-\\d+\\]: Avoid doing field initialization outside constructor.";
82  
83      /**
84       * Pattern multiple constructors field initialization.
85       */
86      private static final String MULT_CON_INIT =
87          "%s\\[\\d+-\\d+\\]: Avoid field initialization in several constructors.";
88  
89      /**
90       * Template for string inside brackets.
91       */
92      private static final String BRACKETS = "(%s)";
93  
94      /**
95       * Pattern using plain JUnit assertions.
96       */
97      private static final String PLAIN_ASSERTIONS =
98          "Avoid using Plain JUnit assertions";
99  
100     /**
101      * Error message used to inform about using public static method.
102      */
103     private static final String STATIC_METHODS =
104         "Public static methods are prohibited";
105 
106     /**
107      * Error text for Files.createFile.
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      * PmdValidator can find violations in Java file(s).
114      * @throws Exception If something wrong happens inside.
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      * PmdValidator can understand method references.
132      * @throws Exception If something wrong happens inside.
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      * PmdValidator does not think that constant is unused when it is used
148      * just from the inner class.
149      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow field initialization when constructor is missing.
181      * @throws Exception If something wrong happens inside.
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      * PmdValidator can forbid field initialization when constructor exists.
199      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow static field initialization when constructor
215      * exists.
216      * @throws Exception If something wrong happens inside.
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      * PmdValidator can forbid field initialization in several constructors.
234      * Only one constructor should do real work. Others - delegate to it.
235      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow field initialization in one constructor.
251      * Only one constructor should do real work. Others - delegate to it.
252      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids unnecessary final modifier for methods.
270      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbid useless parentheses.
284      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids code in constructor
298      * other than field initialization.
299      * @throws Exception If something wrong happens inside.
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      * PmdValidator allows lambda in constructor.
315      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids usage of Files.createFile in tests.
333      * @throws Exception If something wrong happens inside.
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      * PmdValidator allows usage of Files.createFile outside of tests.
348      * @throws Exception If something wrong happens inside.
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      * PmdValidator accepts calls to other constructors
365      * or call to super class constructor in constructors.
366      * @throws Exception If something wrong happens inside.
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      * PmdValidator accepts calls to static fields
384      * in a static way.
385      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids calls to static fields directly
410      * in a non static way.
411      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids calls to static fields
427      * in a non static way via instance reference.
428      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids calls to static methods
444      * in a non static way via instance reference.
445      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids non public clone methods (PMD rule
461      * rulesets/java/clone.xml/CloneMethodMustBePublic).
462      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids clone methods with return type not matching class
480      * name (PMD rule
481      * rulesets/java/clone.xml/CloneMethodReturnTypeMustMatchClassName).
482      * @throws Exception If something wrong happens inside.
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      * PmdValidator forbids ternary operators that can be simplified (PMD rule
501      * rulesets/java/basic.xml/SimplifiedTernary).
502      * @throws Exception If something wrong happens inside.
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      * PmdValidator can prohibit plain JUnit assertion in import block like
521      * import static org.junit.Assert.assert*
522      * import static junit.framework.Assert.assert*.
523      *
524      * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
525      * @throws Exception If something wrong happens inside.
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      * PmdValidator can prohibit plain JUnit assertion in test methods like
541      * Assert.assertEquals.
542      *
543      * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
544      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow Assert.fail().
560      *
561      * Custom Rule {@link ProhibitPlainJunitAssertionsRule}
562      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow non-static, non-transient fields.
580      * @throws Exception If something wrong happens inside.
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      * PmdValidator can prohibit public static methods.
597      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow public static void main(String...args) method.
610      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow JUnit public static methods marked with:<br>
625      * BeforeClass annotation.<br>
626      * AfterClass annotation.<br>
627      * Parameterized.Parameters annotation.
628      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow duplicate literals in annotations.
643      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow only package private methods,
658      * annotated by @Test, @RepeatedTest, @TestFactory, @TestTemplate or @ParameterizedTest.
659      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow only final JUnit3 test classes.
672      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow only final JUnit4 test classes.
685      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow only final JUnit5 test classes.
698      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow only final Junit test classes.
711      * @throws Exception If something wrong happens inside.
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      * PmdValidator can allow record classes.
726      * @throws Exception If something wrong happens inside.
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      * PmdValidator checks swagger annotation.
742      * @throws Exception If something wrong happens inside.
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      * PmdValidator can prohibit unicode characters in method names.
757      * @throws Exception If something wrong happens inside.
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 }