diff --git a/.all-contributorsrc b/.all-contributorsrc index dcac68bf60..41116fe796 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3267,7 +3267,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/24591067?v=4", "profile": "https://github.com/jborgers", "contributions": [ - "bug" + "bug", + "code" ] }, { @@ -3384,7 +3385,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/242337?v=4", "profile": "https://github.com/jjlharrison", "contributions": [ - "bug" + "bug", + "code" ] }, { @@ -6639,6 +6641,123 @@ "contributions": [ "code" ] + }, + { + "login": "lukelukes", + "name": "lukelukes", + "avatar_url": "https://avatars.githubusercontent.com/u/45536418?v=4", + "profile": "https://github.com/lukelukes", + "contributions": [ + "code" + ] + }, + { + "login": "vibhory2j", + "name": "Vibhor Goyal", + "avatar_url": "https://avatars.githubusercontent.com/u/15845016?v=4", + "profile": "https://github.com/vibhory2j", + "contributions": [ + "bug" + ] + }, + { + "login": "Ramel0921", + "name": "Ramel0921", + "avatar_url": "https://avatars.githubusercontent.com/u/104978096?v=4", + "profile": "https://github.com/Ramel0921", + "contributions": [ + "bug" + ] + }, + { + "login": "flyhard", + "name": "Per Abich", + "avatar_url": "https://avatars.githubusercontent.com/u/409466?v=4", + "profile": "https://github.com/flyhard", + "contributions": [ + "code" + ] + }, + { + "login": "filipponova", + "name": "Filippo Nova", + "avatar_url": "https://avatars.githubusercontent.com/u/12506636?v=4", + "profile": "https://github.com/filipponova", + "contributions": [ + "bug" + ] + }, + { + "login": "dalizi007", + "name": "dalizi007", + "avatar_url": "https://avatars.githubusercontent.com/u/90743616?v=4", + "profile": "https://github.com/dalizi007", + "contributions": [ + "code" + ] + }, + { + "login": "shiomiyan", + "name": "shiomiyan", + "avatar_url": "https://avatars.githubusercontent.com/u/35842766?v=4", + "profile": "https://github.com/shiomiyan", + "contributions": [ + "doc" + ] + }, + { + "login": "lgemeinhardt", + "name": "lgemeinhardt", + "avatar_url": "https://avatars.githubusercontent.com/u/1395165?v=4", + "profile": "https://github.com/lgemeinhardt", + "contributions": [ + "bug" + ] + }, + { + "login": "HaelC", + "name": "Haoliang Chen", + "avatar_url": "https://avatars.githubusercontent.com/u/16898273?v=4", + "profile": "https://haelchan.me/", + "contributions": [ + "bug" + ] + }, + { + "login": "FSchliephacke", + "name": "FSchliephacke", + "avatar_url": "https://avatars.githubusercontent.com/u/10260493?v=4", + "profile": "https://github.com/FSchliephacke", + "contributions": [ + "bug" + ] + }, + { + "login": "stokpop", + "name": "Peter Paul Bakker", + "avatar_url": "https://avatars.githubusercontent.com/u/8797018?v=4", + "profile": "https://www.stokpop.nl/", + "contributions": [ + "code" + ] + }, + { + "login": "ASBrouwers", + "name": "ASBrouwers", + "avatar_url": "https://avatars.githubusercontent.com/u/23551289?v=4", + "profile": "https://github.com/ASBrouwers", + "contributions": [ + "code" + ] + }, + { + "login": "341816041", + "name": "่Œ…ๅปถๅฎ‰", + "avatar_url": "https://avatars.githubusercontent.com/u/100549608?v=4", + "profile": "https://github.com/341816041", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/.ci/build.sh b/.ci/build.sh index ebacd1cf0c..828fcb9bbf 100755 --- a/.ci/build.sh +++ b/.ci/build.sh @@ -245,12 +245,15 @@ ${rendered_release_notes}" # Runs the dogfood ruleset with the currently built pmd against itself # function pmd_ci_dogfood() { + local mpmdVersion=() ./mvnw versions:set -DnewVersion="${PMD_CI_MAVEN_PROJECT_VERSION}-dogfood" -DgenerateBackupPoms=false sed -i 's/[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}.*<\/version>\( *\)/'"${PMD_CI_MAVEN_PROJECT_VERSION}"'<\/version>\1/' pom.xml if [ "${PMD_CI_MAVEN_PROJECT_VERSION}" = "7.0.0-SNAPSHOT" ]; then sed -i 's/pmd-dogfood-config\.xml/pmd-dogfood-config7.xml/' pom.xml + mpmdVersion=(-Denforcer.skip=true -Dpmd.plugin.version=3.18.0-pmd7-SNAPSHOT) fi ./mvnw verify --show-version --errors --batch-mode --no-transfer-progress "${PMD_MAVEN_EXTRA_OPTS[@]}" \ + "${mpmdVersion[@]}" \ -DskipTests \ -Dmaven.javadoc.skip=true \ -Dmaven.source.skip=true \ diff --git a/.ci/files/project-list.xml b/.ci/files/project-list.xml index 3ecd924ece..ce357698bc 100644 --- a/.ci/files/project-list.xml +++ b/.ci/files/project-list.xml @@ -40,6 +40,11 @@ mvn dependency:build-classpath -DincludeScope=test -Dmdep.outputFile=classpath.t .*/build/generated-sources/.* classpath.txt ]]> diff --git a/.ci/git-repo-sync.sh b/.ci/git-repo-sync.sh index a32d6c9b03..af0635d9ba 100755 --- a/.ci/git-repo-sync.sh +++ b/.ci/git-repo-sync.sh @@ -27,7 +27,7 @@ function git_repo_sync() { pmd_ci_log_group_start "Git Sync" git remote add pmd-sf "${PMD_SF_USER}@git.code.sf.net:/p/pmd/code" if [ -n "${PMD_CI_BRANCH}" ]; then - git push pmd-sf "${PMD_CI_BRANCH}:${PMD_CI_BRANCH}" + retry 5 git push pmd-sf "${PMD_CI_BRANCH}:${PMD_CI_BRANCH}" pmd_ci_log_success "Successfully pushed ${PMD_CI_BRANCH} to sourceforge" elif [ -n "${PMD_CI_TAG}" ]; then git push pmd-sf tag "${PMD_CI_TAG}" @@ -39,6 +39,43 @@ function git_repo_sync() { pmd_ci_log_group_end } + +# +# From: https://gist.github.com/sj26/88e1c6584397bb7c13bd11108a579746 +# +# Retry a command up to a specific number of times until it exits successfully, +# with exponential back off. +# +# $ retry 5 echo Hello +# Hello +# +# $ retry 5 false +# Retry 1/5 exited 1, retrying in 1 seconds... +# Retry 2/5 exited 1, retrying in 2 seconds... +# Retry 3/5 exited 1, retrying in 4 seconds... +# Retry 4/5 exited 1, retrying in 8 seconds... +# Retry 5/5 exited 1, no more retries left. +# +function retry { + local retries=$1 + shift + + local count=0 + until "$@"; do + exit=$? + wait=$((2 ** $count)) + count=$(($count + 1)) + if [ $count -lt $retries ]; then + echo "Retry $count/$retries exited $exit, retrying in $wait seconds..." + sleep $wait + else + echo "Retry $count/$retries exited $exit, no more retries left." + return $exit + fi + done + return 0 +} + git_repo_sync exit 0 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d52aa82b5..01b91ce2d5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: run: | echo "LANG=en_US.UTF-8" >> $GITHUB_ENV echo "MAVEN_OPTS=-Dmaven.wagon.httpconnectionManager.ttlSeconds=180 -Dmaven.wagon.http.retryHandler.count=3 -DautoReleaseAfterClose=true -DstagingProgressTimeoutMinutes=30" >> $GITHUB_ENV - echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/17/scripts" >> $GITHUB_ENV + echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/18/scripts" >> $GITHUB_ENV - name: Check Environment shell: bash run: | diff --git a/.github/workflows/git-repo-sync.yml b/.github/workflows/git-repo-sync.yml index 250dd00933..a990a6726b 100644 --- a/.github/workflows/git-repo-sync.yml +++ b/.github/workflows/git-repo-sync.yml @@ -22,7 +22,7 @@ jobs: shell: bash run: | echo "LANG=en_US.UTF-8" >> $GITHUB_ENV - echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/17/scripts" >> $GITHUB_ENV + echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/18/scripts" >> $GITHUB_ENV - name: Sync run: .ci/git-repo-sync.sh shell: bash diff --git a/.github/workflows/troubleshooting.yml b/.github/workflows/troubleshooting.yml index 04ac1cd39c..ea4bd54fd9 100644 --- a/.github/workflows/troubleshooting.yml +++ b/.github/workflows/troubleshooting.yml @@ -36,7 +36,7 @@ jobs: run: | echo "LANG=en_US.UTF-8" >> $GITHUB_ENV echo "MAVEN_OPTS=-Dmaven.wagon.httpconnectionManager.ttlSeconds=180 -Dmaven.wagon.http.retryHandler.count=3 -DstagingProgressTimeoutMinutes=30" >> $GITHUB_ENV - echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/17/scripts" >> $GITHUB_ENV + echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/18/scripts" >> $GITHUB_ENV - name: Check Environment shell: bash run: | diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index db95c131dd..25a1876bb8 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.5/apache-maven-3.8.5-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar diff --git a/Gemfile.lock b/Gemfile.lock index f20255105a..b41e9645e9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -68,14 +68,14 @@ GEM multipart-post (2.1.1) nap (1.1.0) no_proxy_fix (0.1.2) - nokogiri (1.13.5) + nokogiri (1.13.6) mini_portile2 (~> 2.8.0) racc (~> 1.4) octokit (4.22.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) open4 (1.3.4) - pmdtester (1.5.0) + pmdtester (1.5.1) differ (~> 0.1) liquid (~> 5.2) logger-colors (~> 1.0) diff --git a/antlr4-wrapper.xml b/antlr4-wrapper.xml index 2e4b617e27..c2d3e224ff 100644 --- a/antlr4-wrapper.xml +++ b/antlr4-wrapper.xml @@ -8,7 +8,7 @@ - lang-name: matches the grammar name (eg "Swift") - lang-terse-name: uncapitalized package name (eg "swift") - node-prefix: prefix for generated AST nodes (eg "Sw") - - root-node-name: name of the root node (eg "TopLevel"), will be made to implement RootNode + - root-node-name: name of the root node without prefix (eg "TopLevel"), will be made to implement RootNode See AntlrGeneratedParserBase @@ -31,9 +31,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -45,7 +81,7 @@ - + diff --git a/do-release.sh b/do-release.sh index 5cd900bf32..3ddb331bbd 100755 --- a/do-release.sh +++ b/do-release.sh @@ -72,6 +72,14 @@ export RELEASE_VERSION export DEVELOPMENT_VERSION export CURRENT_BRANCH +# check for SNAPSHOT version of pmd.build-tools.version +BUILD_TOOLS_VERSION=$(./mvnw org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate -Dexpression=pmd.build-tools.version -q -DforceStdout) +BUILD_TOOLS_VERSION_RELEASE=${BUILD_TOOLS_VERSION%-SNAPSHOT} +if [ "${BUILD_TOOLS_VERSION}" != "${BUILD_TOOLS_VERSION_RELEASE}" ]; then + echo "Error: version pmd.build-tools.version is ${BUILD_TOOLS_VERSION} - snapshot is not allowed" + exit 1 +fi + RELEASE_RULESET="pmd-core/src/main/resources/rulesets/releases/${RELEASE_VERSION//\./}.xml" echo "* Update date info in **docs/_config.yml**." diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 020814c547..af044ad8d5 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.4.8) + activesupport (6.0.5) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -232,7 +232,7 @@ GEM jekyll-seo-tag (~> 2.1) minitest (5.15.0) multipart-post (2.1.1) - nokogiri (1.13.5) + nokogiri (1.13.6) mini_portile2 (~> 2.8.0) racc (~> 1.4) octokit (4.22.0) diff --git a/docs/_config.yml b/docs/_config.yml index 13469ef975..f89896c168 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -2,7 +2,7 @@ repository: pmd/pmd pmd: version: 7.0.0-SNAPSHOT - previous_version: 6.45.0 + previous_version: 6.47.0 date: ??-?????-2022 release_type: major diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml index 75aa7aeda3..8d72847030 100644 --- a/docs/_data/sidebars/pmd_sidebar.yml +++ b/docs/_data/sidebars/pmd_sidebar.yml @@ -244,6 +244,21 @@ entries: - title: Security output: web, pdf url: /pmd_rules_jsp_security.html + - title: null + output: web, pdf + subfolders: + - title: Kotlin Rules + output: web, pdf + subfolderitems: + - title: Index + output: web, pdf + url: /pmd_rules_kotlin.html + - title: Best Practices + output: web, pdf + url: /pmd_rules_kotlin_bestpractices.html + - title: Error Prone + output: web, pdf + url: /pmd_rules_kotlin_errorprone.html - title: null output: web, pdf subfolders: @@ -382,6 +397,9 @@ entries: - title: JSP url: /pmd_languages_jsp.html output: web, pdf + - title: Kotlin + url: /pmd_languages_kotlin.html + output: web, pdf - title: PLSQL url: /pmd_languages_plsql.html output: web, pdf @@ -394,6 +412,9 @@ entries: - title: HTML url: /pmd_languages_html.html output: web, pdf + - title: Gherkin + url: /pmd_languages_gherkin.html + output: web, pdf - title: Developer Documentation output: web, pdf folderitems: diff --git a/docs/pages/7_0_0_release_notes.md b/docs/pages/7_0_0_release_notes.md index cc3d9a0dc9..be94436737 100644 --- a/docs/pages/7_0_0_release_notes.md +++ b/docs/pages/7_0_0_release_notes.md @@ -49,6 +49,26 @@ Given the full Antlr support, PMD now fully supports Swift. We are pleased to an * {% rule "swift/bestpractices/UnavailableFunction" %} (`swift-bestpractices`) flags any function throwing a `fatalError` not marked as `@available(*, unavailable)` to ensure no calls are actually performed in the codebase. +Contributors: [@lsoncini](https://github.com/lsoncini), [@matifraga](https://github.com/matifraga), [@tomidelucca](https://github.com/tomidelucca) + +#### Kotlin support (experimental) + +PMD now supports Kotlin as an additional language for analyzing source code. It is based on +the official kotlin Antlr grammar. Java-based rules and XPath-based rules are supported. + +Kotlin support has **experimental** stability level, meaning no compatibility should +be expected between even incremental releases. Any functionality can be added, removed or changed without +warning. + +We are shipping the following rules: + +* {% rule kotlin/bestpractices/FunctionNameTooShort %} (`kotlin-bestpractices`) finds functions with a too short name. +* {% rule kotlin/errorprone/OverrideBothEqualsAndHashcode %} (`kotlin-errorprone`) finds classes with only either `equals` + or `hashCode` overridden, but not both. This leads to unexpected behavior once instances of such classes + are used in collections (Lists, HashMaps, ...). + +Contributors: [@jborgers](https://github.com/jborgers), [@stokpop](https://github.com/stokpop) + #### XPath 3.1 support Support for XPath versions 1.0, 1.0-compatibility was removed, support for XPath 2.0 is deprecated. The default (and only) supported XPath version is now XPath 3.1. This version of the XPath language is mostly identical to XPath 2.0. Notable changes: @@ -161,14 +181,14 @@ The following previously deprecated rules have been finally removed: ### Fixed Issues -* miscellaneous +* miscellaneous * [#896](https://github.com/pmd/pmd/issues/896): \[all] Use slf4j * [#1451](https://github.com/pmd/pmd/issues/1451): \[core] RulesetFactoryCompatibility stores the whole ruleset file in memory as a string -* cli +* cli * [#3828](https://github.com/pmd/pmd/issues/3828): \[core] Progress reporting -* apex-design +* apex-design * [#2667](https://github.com/pmd/pmd/issues/2667): \[apex] Integrate nawforce/ApexLink to build robust Unused rule -* java-bestpractices +* java-bestpractices * [#342](https://github.com/pmd/pmd/issues/342): \[java] AccessorMethodGeneration: Name clash with another public field not properly handled * [#755](https://github.com/pmd/pmd/issues/755): \[java] AccessorClassGeneration false positive for private constructors * [#770](https://github.com/pmd/pmd/issues/770): \[java] UnusedPrivateMethod yields false positive for counter-variant arguments @@ -243,6 +263,8 @@ The following previously deprecated rules have been finally removed: * java-performance * [#1224](https://github.com/pmd/pmd/issues/1224): \[java] InefficientEmptyStringCheck false negative in anonymous class * [#2712](https://github.com/pmd/pmd/issues/2712): \[java] SimplifyStartsWith false-positive with AssertJ +* kotlin + * [#419](https://github.com/pmd/pmd/issues/419): \[kotlin] Add support for Kotlin ### API Changes diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md index 0deeb1ba60..deccde46f6 100644 --- a/docs/pages/next_major_development.md +++ b/docs/pages/next_major_development.md @@ -246,6 +246,43 @@ the breaking API changes will be performed in 7.0.0. an API is tagged as `@Deprecated` or not in the latest minor release. During the development of 7.0.0, we may decide to remove some APIs that were not tagged as deprecated, though we'll try to avoid it." %} +#### 6.47.0 + +No changes. + +#### 6.46.0 + +##### Deprecated ruleset references + +Ruleset references with the following formats are now deprecated and will produce a warning +when used on the CLI or in a ruleset XML file: +- `-`, eg `java-basic`, which resolves to `rulesets/java/basic.xml` +- the internal release number, eg `600`, which resolves to `rulesets/releases/600.xml` + +Use the explicit forms of these references to be compatible with PMD 7. + +##### Deprecated API + +- {% jdoc core::RuleSetReferenceId#toString() %} is now deprecated. The format of this + method will remain the same until PMD 7. The deprecation is intended to steer users + away from relying on this format, as it may be changed in PMD 7. +- {% jdoc core::PMDConfiguration#getInputPaths() %} and + {% jdoc core::PMDConfiguration#setInputPaths(java.lang.String) %} are now deprecated. + A new set of methods have been added, which use lists and do not rely on comma splitting. + +##### Internal API + +Those APIs are not intended to be used by clients, and will be hidden or removed with PMD 7.0.0. +You can identify them with the `@InternalApi` annotation. You'll also get a deprecation warning. + +- {% jdoc core::cpd.CPDCommandLineInterface %} has been internalized. In order to execute CPD either + {% jdoc !!core::cpd.CPD#run(java.lang.String...) %} or {% jdoc !!core::cpd.CPD#main(java.lang.String[]) %} + should be used. +- Several members of {% jdoc test::cli.BaseCPDCLITest %} have been deprecated with replacements. +- The methods {% jdoc !!core::ant.Formatter#start(java.lang.String) %}, + {% jdoc !!core::ant.Formatter#end(net.sourceforge.pmd.Report) %}, {% jdoc !!core::ant.Formatter#getRenderer() %}, + and {% jdoc !!core::ant.Formatter#isNoOutputSupplied() %} have been internalized. + #### 6.45.0 ##### Experimental APIs @@ -1468,18 +1505,18 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see * The Java rules NcssConstructorCount (java-design), NcssMethodCount (java-design), and NcssTypeCount (java-design) have been deprecated. They will be replaced by the new rule {% rule java/design/NcssCount %} in the category `design`. -* The Java rule `LooseCoupling` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `bestpractices` instead. +* The Java rule `LooseCoupling` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `bestpractices` instead. -* The Java rule `CloneMethodMustImplementCloneable` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `errorprone` instead. +* The Java rule `CloneMethodMustImplementCloneable` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `errorprone` instead. -* The Java rule `UnusedImports` in ruleset `java-typeresolution` is deprecated. Use the rule with +* The Java rule `UnusedImports` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `bestpractices` instead. -* The Java rule `SignatureDeclareThrowsException` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `design` instead. +* The Java rule `SignatureDeclareThrowsException` in ruleset `java-typeresolution` is deprecated. Use the rule with the same name from category `design` instead. -* The Java rule `EmptyStaticInitializer` in ruleset `java-empty` is deprecated. Use the rule {% rule java/errorprone/EmptyInitializer %}, which covers both static and non-static empty initializers.` +* The Java rule `EmptyStaticInitializer` in ruleset `java-empty` is deprecated. Use the rule {% rule java/errorprone/EmptyInitializer %}, which covers both static and non-static empty initializers.` -* The Java rules `GuardDebugLogging` (ruleset `java-logging-jakarta-commons`) and `GuardLogStatementJavaUtil` +* The Java rules `GuardDebugLogging` (ruleset `java-logging-jakarta-commons`) and `GuardLogStatementJavaUtil` (ruleset `java-logging-java`) have been deprecated. Use the rule {% rule java/bestpractices/GuardLogStatement %}, which covers all cases regardless of the logging framework. * The Java rule "java/multithreading/UnsynchronizedStaticDateFormatter" has been deprecated and @@ -1490,20 +1527,20 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see and [`PositionLiteralsFirstInCaseInsensitiveComparisons`](https://pmd.github.io/pmd-6.29.0/pmd_rules_java_bestpractices.html#positionliteralsfirstincaseinsensitivecomparisons) (ruleset `java-bestpractices`) have been deprecated in favor of the new rule {% rule "java/bestpractices/LiteralsFirstInComparisons" %}. -* The Java rule [`AvoidFinalLocalVariable`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_codestyle.html#avoidfinallocalvariable) (`java-codestyle`) has been deprecated +* The Java rule [`AvoidFinalLocalVariable`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_codestyle.html#avoidfinallocalvariable) (`java-codestyle`) has been deprecated and will be removed with PMD 7.0.0. The rule is controversial and also contradicts other existing rules such as [`LocalVariableCouldBeFinal`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_codestyle.html#localvariablecouldbefinal). If the goal is to avoid defining constants in a scope smaller than the class, then the rule [`AvoidDuplicateLiterals`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_errorprone.html#avoidduplicateliterals) should be used instead. -* The Apex rule [`VariableNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#variablenamingconventions) (`apex-codestyle`) has been deprecated and +* The Apex rule [`VariableNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#variablenamingconventions) (`apex-codestyle`) has been deprecated and will be removed with PMD 7.0.0. The rule is replaced by the more general rules [`FieldNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#fieldnamingconventions), [`FormalParameterNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#formalparameternamingconventions), [`LocalVariableNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#localvariablenamingconventions), and [`PropertyNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#propertynamingconventions). -* The Java rule [`LoggerIsNotStaticFinal`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#loggerisnotstaticfinal) (`java-errorprone`) has been deprecated +* The Java rule [`LoggerIsNotStaticFinal`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#loggerisnotstaticfinal) (`java-errorprone`) has been deprecated and will be removed with PMD 7.0.0. The rule is replaced by [`ProperLogger`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#properlogger). * The Java rule [`DataflowAnomalyAnalysis`](https://pmd.github.io/pmd-6.27.0/pmd_rules_java_errorprone.html#dataflowanomalyanalysis) (`java-errorprone`) @@ -1516,7 +1553,7 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see * The Java rule `CloneThrowsCloneNotSupportedException` (java-errorprone) has been deprecated without replacement. -* The following Java rules are deprecated and removed from the quickstart ruleset, +* The following Java rules are deprecated and removed from the quickstart ruleset, as the new rule {% rule java/bestpractices/SimplifiableTestAssertion %} merges their functionality: * `UseAssertEqualsInsteadOfAssertTrue` (java-bestpractices) @@ -1529,7 +1566,7 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see the quickstart ruleset, as the new rule {% rule java/errorprone/ReturnEmptyCollectionRatherThanNull %} supersedes it. -* The following Java rules are deprecated and removed from the quickstart ruleset, +* The following Java rules are deprecated and removed from the quickstart ruleset, as the new rule {% rule java/bestpractices/PrimitiveWrapperInstantiation %} merges their functionality: * java/performance/BooleanInstantiation @@ -1543,3 +1580,17 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see as it finds only contrived cases of creating a primitive wrapper and unboxing it explicitly in the same expression. In PMD 7 this and more cases will be covered by a new rule `UnnecessaryBoxing`. + +* Since 6.46.0: The following Java rules are deprecated and removed from the quickstart ruleset, as the new rule + {% rule java/codestyle/EmptyControlStatement %} merges their functionality: + * {% rule java/errorprone/EmptyFinallyBlock %} + * {% rule java/errorprone/EmptyIfStmt %} + * {% rule java/errorprone/EmptyInitializer %} + * {% rule java/errorprone/EmptyStatementBlock %} + * {% rule java/errorprone/EmptySwitchStatements %} + * {% rule java/errorprone/EmptySynchronizedBlock %} + * {% rule java/errorprone/EmptyTryBlock %} + * {% rule java/errorprone/EmptyWhileStmt %} + +* Since 6.46.0: The Java rule {% rule java/errorprone/EmptyStatementNotInLoop %} is deprecated and removed from the quickstart + ruleset. Use the new rule {% rule java/codestyle/UnnecessarySemicolon %} instead. diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md index 7f156054d7..567db3d6c2 100644 --- a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md +++ b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md @@ -3,17 +3,54 @@ title: Adding PMD support for a new ANTLR grammar based language short_title: Adding a new language with ANTLR tags: [devdocs, extending] summary: "How to add a new language to PMD using ANTLR grammar." -last_updated: July 21, 2019 +last_updated: October 2021 sidebar: pmd_sidebar permalink: pmd_devdocs_major_adding_new_language_antlr.html folder: pmd/devdocs -# needs to be changed to branch master instead of pmd/7.0.x +# +# needs to be changed to branch master instead of pmd/7.0.x once pmd7 is released # https://github.com/pmd/pmd/blob/pmd/7.0.x -> https://github.com/pmd/pmd/blob/master +# --- +{% include callout.html type="warning" content=" -## 1. Start with a new sub-module. +**Before you start...**

+ +This is really a big contribution and can't be done with a drive by contribution. It requires dedicated passion +and long commitment to implement support for a new language.

+ +This step by step guide is just a small intro to get the basics started and it's also not necessarily up-to-date +or complete and you have to be able to fill in the blanks.

+ +Currently the Antlr integration has some basic limitations compared to JavaCC: The output of the +Antlr parser generator is not an abstract syntax tree (AST) but a parse tree. As such, a parse tree is +much more fine-grained than what a typical JavaCC grammar will produce. This means that the +parse tree is much deeper and contains nodes down to the different token types.

+ +The Antlr nodes themselves don't have any attributes because they are on the wrong abstraction level. +As they don't have attributes, there are no attributes that can be used in XPath based rules.

+ +In order to overcome these limitations, one would need to implement a post-processing step that transforms +a parse tree into an abstract syntax tree and introducing real nodes on a higher abstraction level. This +step is **not** described in this guide.

+ +After the basic support for a language is there, there are lots of missing features left. Typical features +that can greatly improve rule writing are: symbol table, type resolution, call/data flow analysis.

+ +Symbol table keeps track of variables and their usages. Type resolution tries to find the actual class type +of each used type, following along method calls (including overloaded and overwritten methods), allowing +to query sub types and type hierarchy. This requires additional configuration of an auxiliary classpath. +Call and data flow analysis keep track of the data as it is moving through different execution paths +a program has.

+ +These features are out of scope of this guide. Type resolution and data flow are features that +definitely don't come for free. It is much effort and requires perseverance to implement.

+ +" %} + +## 1. Start with a new sub-module * See pmd-swift for examples. ## 2. Implement an AST parser for your language @@ -24,7 +61,7 @@ folder: pmd/devdocs ## 3. Create AST node classes * The individual AST nodes are generated, but you need to define the common interface for them. -* You need a need to define the supertype interface for all nodes of the language. For that, we provide +* You need to define the supertype interface for all nodes of the language. For that, we provide [`AntlrNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNode.java). * See [`SwiftNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftNode.java) as an example. @@ -52,7 +89,7 @@ folder: pmd/devdocs ## 4. Generate your parser * Make sure, you have the property `true` in your `pom.xml` file. * This is just a matter of building the language module. ANTLR is called via ant, and this step is added - to the phase `generate-sources`. So you can just call e.g. `./mvnw generate-source -pl pmd-swift` to + to the phase `generate-sources`. So you can just call e.g. `./mvnw generate-sources -pl pmd-swift` to have the parser generated. * The generated code will be placed under `target/generated-sources/antlr4` and will not be committed to source control. diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md index c3b470247c..7e14a56a24 100644 --- a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md +++ b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md @@ -1,16 +1,40 @@ --- -title: Adding PMD support for a new JAVACC grammar based language -short_title: Adding a new language with JAVACC +title: Adding PMD support for a new JavaCC grammar based language +short_title: Adding a new language with JavaCC tags: [devdocs, extending] -summary: "How to add a new language to PMD using JAVACC grammar." -last_updated: October 5, 2019 +summary: "How to add a new language to PMD using JavaCC grammar." +last_updated: October 2021 sidebar: pmd_sidebar permalink: pmd_devdocs_major_adding_new_language_javacc.html folder: pmd/devdocs --- +{% include callout.html type="warning" content=" -## 1. Start with a new sub-module. +**Before you start...**

+ +This is really a big contribution and can't be done with a drive by contribution. It requires dedicated passion +and long commitment to implement support for a new language.

+ +This step by step guide is just a small intro to get the basics started and it's also not necessarily up-to-date +or complete and you have to be able to fill in the blanks.

+ +After the basic support for a language is there, there are lots of missing features left. Typical features +that can greatly improve rule writing are: symbol table, type resolution, call/data flow analysis.

+ +Symbol table keeps track of variables and their usages. Type resolution tries to find the actual class type +of each used type, following along method calls (including overloaded and overwritten methods), allowing +to query sub types and type hierarchy. This requires additional configuration of an auxiliary classpath. +Call and data flow analysis keep track of the data as it is moving through different execution paths +a program has.

+ +These features are out of scope of this guide. Type resolution and data flow are features that +definitely don't come for free. It is much effort and requires perseverance to implement.

+ +" %} + + +## 1. Start with a new sub-module * See pmd-java or pmd-vm for examples. ## 2. Implement an AST parser for your language diff --git a/docs/pages/pmd/languages/gherkin.md b/docs/pages/pmd/languages/gherkin.md new file mode 100644 index 0000000000..123bae7d49 --- /dev/null +++ b/docs/pages/pmd/languages/gherkin.md @@ -0,0 +1,16 @@ +--- +title: Gherkin +permalink: pmd_languages_gherkin.html +--- + +The [Gherkin](https://cucumber.io/docs/gherkin/) language is used to define test cases for the +[Cucumber](https://cucumber.io/) testing tool for behavior-driven development. +The Gherkin syntax is designed to be non-technical, making it human-readable for a wide audience. + +## Support in PMD +Starting from version 6.48.0, Gherkin support was added to CPD. + +### Limitations +- Support for Gherkin only extends to CPD to detect code duplication in Cucumber test cases. +- While Gherkin keywords have been translated into various +languages, CPD currently supports only the English version of the Gherkin language. diff --git a/docs/pages/pmd/languages/html.md b/docs/pages/pmd/languages/html.md index acb96fc416..9c905571e1 100644 --- a/docs/pages/pmd/languages/html.md +++ b/docs/pages/pmd/languages/html.md @@ -14,5 +14,11 @@ last_updated: April 2022 (6.45.0) The HTML language module uses [jsoup](https://jsoup.org/) for parsing. -XPath rules are supported, but the DOM is not a typical XML/XPath DOM. E.g. -text nodes are normal nodes. This might change in the future. +XPath 2.0 rules are supported, but the DOM is not always a typical XML/XPath DOM. +In the Designer, text nodes appear as nodes with name "#text", but they can +be selected as usual using `text()`. + +XML Namespaces are not supported. The local name of attributes include the prefix, +so that you have to select attributes by e.g. `//*[@*[local-name() = 'if:true']]`. + +Only XPath 1.0 rules are not supported. diff --git a/docs/pages/pmd/languages/java.md b/docs/pages/pmd/languages/java.md index cbe060e53b..a1e9d6c54d 100644 --- a/docs/pages/pmd/languages/java.md +++ b/docs/pages/pmd/languages/java.md @@ -9,7 +9,43 @@ summary: "Java-specific features and guidance" {% include warning.html content="WIP, todo for pmd 7" %} -### Type and symbol resolution +## Overview of supported Java language versions + +Usually the latest non-preview Java Version is the default version. + +| Java Version | Alias | Supported by PMD since | +|--------------|-------|------------------------| +| 19-preview | | 6.48.0 | +| 19 (default) | | 6.48.0 | +| 18-preview | | 6.44.0 | +| 18 | | 6.44.0 | +| 17 | | 6.37.0 | +| 16 | | 6.32.0 | +| 15 | | 6.27.0 | +| 14 | | 6.22.0 | +| 13 | | 6.18.0 | +| 12 | | 6.13.0 | +| 11 | | 6.6.0 | +| 10 | 1.10 | 6.4.0 | +| 9 | 1.9 | 6.0.0 | +| 8 | 1.8 | 5.1.0 | +| 7 | 1.7 | 5.0.0 | +| 6 | 1.6 | 3.9 | +| 5 | 1.5 | 3.0 | +| 1.4 | | 1.2.2 | +| 1.3 | | 1.0.0 | + +## Using Java preview features + +In order to analyze a project with PMD that uses preview language features, you'll need to enable +it via the environment variable `PMD_JAVA_OPTS` and select the new language version, e.g. `19-preview`: + + export PMD_JAVA_OPTS=--enable-preview + ./run.sh pmd -language java -version 19-preview ... + +Note: we only support preview language features for the latest two java versions. + +## Type and symbol resolution Java being a statically typed language, a Java program contains more information that just its syntax tree; for instance, every expression has a static type, and every method call is bound to a method overload statically (even if that overload is virtual). In PMD, much of this information is resolved from the AST by additional passes, which run after parsing, and before rules can inspect the tree. @@ -22,11 +58,11 @@ TODO describe * why we need auxclasspath * how disambiguation can fail -### Type and symbol APIs +## Type and symbol APIs TODO describe APIs -### Metrics framework +## Metrics framework In order to use code metrics in Java, use the metrics constants in {% jdoc java::lang.java.metrics.JavaMetrics %}, together with {% jdoc core::lang.metrics.MetricsUtil %}. For instance: diff --git a/docs/pages/pmd/languages/kotlin.md b/docs/pages/pmd/languages/kotlin.md new file mode 100644 index 0000000000..ad9297a248 --- /dev/null +++ b/docs/pages/pmd/languages/kotlin.md @@ -0,0 +1,14 @@ +--- +title: Kotlin Support +permalink: pmd_languages_kotlin.html +tags: [languages] +summary: "Kotlin-specific features and guidance" +--- + +Kotlin support in PMD is based on the official grammar from . + +Java-based rules and XPath-based rules are supported. + +{% include note.html content="Kotlin support has **experimental** stability level, meaning no compatibility should +be expected between even incremental releases. Any functionality can be added, removed or changed without +warning." %} diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index 392dce14e8..9238b38248 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -17,558 +17,567 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
0xflotus

๐Ÿ’ป ๐Ÿ›
1henni

๐Ÿ›
ALiNew

๐Ÿ› +
ASBrouwers

๐Ÿ’ป
Abhijit Sarkar

๐Ÿ›
Abhishek Kumar

๐Ÿ›
Adam

๐Ÿ› -
Adam Carroll

๐Ÿ› +
Adam Carroll

๐Ÿ›
Adam Obuchowicz

๐Ÿ›
Adrian Price

๐Ÿ›
Adrien Lecharpentier

๐Ÿ›
Aidan Harding

๐Ÿ›
Akshat Bahety

๐Ÿ’ป ๐Ÿ›
Akshay Thapa

๐Ÿ› -
Alan Buttars

๐Ÿ› +
Alan Buttars

๐Ÿ›
Alan Hohn

๐Ÿ›
Alberto Fernรกndez

๐Ÿ’ป ๐Ÿ›
Alex Rentz

๐Ÿ›
Alex Saveau

๐Ÿ›
Alex Shesterov

๐Ÿ’ป ๐Ÿ›
Alexey Markevich

๐Ÿ› -
Alexey Naumov

๐Ÿ› +
Alexey Naumov

๐Ÿ›
Alexey Yudichev

๐Ÿ›
Alix

๐Ÿ›
Alix

๐Ÿ›
Amish Shah

๐Ÿ›
Amit Prasad

๐Ÿ›
Amitosh Swain Mahapatra

๐Ÿ› -
Anand Subramanian

๐Ÿ’ป ๐Ÿ› +
Anand Subramanian

๐Ÿ’ป ๐Ÿ›
Anatoly Trosinenko

๐Ÿ’ป ๐Ÿ›
Andi Pabst

๐Ÿ’ป ๐Ÿ›
Andrea

๐Ÿ›
Andrea Aime

๐Ÿ›
Andreas Dangel

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› ๐Ÿšง
Andreas Markussen

๐Ÿ› -
Andreas Schmid

๐Ÿ› +
Andreas Schmid

๐Ÿ›
Andreas Turban

๐Ÿ›
Andrei Paikin

๐Ÿ›
Andrew

๐Ÿ›
Andrew Green

๐Ÿ›
Andrey Fomin

๐Ÿ›
Andrey Hitrin

๐Ÿ› -
Andrey Mochalov

๐Ÿ’ป ๐Ÿ› +
Andrey Mochalov

๐Ÿ’ป ๐Ÿ›
Andro72

๐Ÿ›
Andrwyw

๐Ÿ›
Andrรฉs Catalรกn

๐Ÿ›
Andy Pattenden

๐Ÿ›
Andy Ray

๐Ÿ›
Andy Robinson

๐Ÿ› -
Andy-2639

๐Ÿ› +
Andy-2639

๐Ÿ›
Ankush Somani

๐Ÿ›
Anmol Kumar

๐Ÿ›
Anthony Whitford

๐Ÿ›
AnthonyKot

๐Ÿ›
Aravind Hegde

๐Ÿ›
Arda Aslan

๐Ÿ› -
Ari Fogel

๐Ÿ› +
Ari Fogel

๐Ÿ›
Arnaud Jeansen

๐Ÿ’ป ๐Ÿ›
Arpit Koolwal

๐Ÿ›
Artem

๐Ÿ’ป ๐Ÿ›
Artem

๐Ÿ›
Artem Sheremet

๐Ÿ›
Artur

๐Ÿ› -
Artur Bosch

๐Ÿ› +
Artur Bosch

๐Ÿ›
Artur Dryomov

๐Ÿ›
Artur Ossowski

๐Ÿ›
AshTheMash

๐Ÿ›
Ashish Rana

๐Ÿ›
Atul Kaushal

๐Ÿ›
August Boland

๐Ÿ› -
Aurel Hudec

๐Ÿ› +
Aurel Hudec

๐Ÿ›
Austin Shalit

๐Ÿ›
Austin Tice

๐Ÿ›
Ayoub Kaanich

๐Ÿ›
BBG

๐Ÿ’ป ๐Ÿ“– ๐Ÿ›
Bailey Tjiong

๐Ÿ’ป
Barthรฉlemy L.

๐Ÿ› -
Basavaraj K N

๐Ÿ› +
Basavaraj K N

๐Ÿ›
Basil Peace

๐Ÿ›
Belle

๐Ÿ›
Ben Lerner

๐Ÿ›
Ben Manes

๐Ÿ›
Ben McCann

๐Ÿ›
Bendegรบz Nagy

๐Ÿ› -
Bennet S Yee

๐Ÿ› +
Bennet S Yee

๐Ÿ›
Benoit Lacelle

๐Ÿ›
Bernardo Macรชdo

๐Ÿ›
Bernd Farka

๐Ÿ›
Betina Cynthia Mamani

๐Ÿ›
Bhanu Prakash Pamidi

๐Ÿ’ป ๐Ÿ›
Bhargav Thanki

๐Ÿ› -
Binu R J

๐Ÿ› +
Binu R J

๐Ÿ›
Bjรถrn Kautler

๐Ÿ’ป ๐Ÿ›
Blightbuster

๐Ÿ›
Bo Zhang

๐Ÿ›
Bob "Wombat" Hogg

๐Ÿ›
Bobby Wertman

๐Ÿ›
Bolarinwa Saheed Olayemi

๐Ÿ’ป ๐Ÿ› -
Boris Petrov

๐Ÿ› +
Boris Petrov

๐Ÿ›
Brad Kent

๐Ÿ›
Brandon Mikeska

๐Ÿ›
Brian Batronis

๐Ÿ›
Brian Johnson

๐Ÿ›
Brice Dutheil

๐Ÿ’ป ๐Ÿ›
Bruno Ferreira

๐Ÿ› -
Bruno Ritz

๐Ÿ› +
Bruno Ritz

๐Ÿ›
Cameron Donaldson

๐Ÿ›
Carlos Macasaet

๐Ÿ›
Carsten Otto

๐Ÿ›
Charlie Housh

๐Ÿ›
Charlie Jonas

๐Ÿ›
Chas Honton

๐Ÿ› -
Chen Yang

๐Ÿ› +
Chen Yang

๐Ÿ›
Chotu

๐Ÿ›
Chris Smith

๐Ÿ›
Christian Hujer

๐Ÿ›
Christian Pontesegger

๐Ÿ›
ChristianWulf

๐Ÿ›
Christofer Dutz

๐Ÿ’ป -
Christoffer Anselm

๐Ÿ› +
Christoffer Anselm

๐Ÿ›
Christophe Vidal

๐Ÿ›
Christopher Dancy

๐Ÿ›
Clemens Prill

๐Ÿ›
Clint Chester

๐Ÿ’ป ๐Ÿ›
Clรฉment Fournier

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› ๐Ÿšง
Codacy Badger

๐Ÿ› -
Code-Nil

๐Ÿ› +
Code-Nil

๐Ÿ›
ColColonCleaner

๐Ÿ›
Colin Ingarfield

๐Ÿ›
Craig Andrews

๐Ÿ›
Craig Muchinsky

๐Ÿ›
Cyril

๐Ÿ’ป ๐Ÿ›
Dale

๐Ÿ’ป -
Damien Jiang

๐Ÿ› +
Damien Jiang

๐Ÿ›
Dan Berindei

๐Ÿ›
Dan Rollo

๐Ÿ›
Dan Ziemba

๐Ÿ›
Daniel Gredler

๐Ÿ’ป
Daniel Jipa

๐Ÿ›
Daniel Paul Searles

๐Ÿ’ป -
Daniel Reigada

๐Ÿ› +
Daniel Reigada

๐Ÿ›
Danilo Pianini

๐Ÿ›
Darko

๐Ÿ›
David

๐Ÿ›
David Atkinson

๐Ÿ›
David Burstrรถm

๐Ÿ’ป ๐Ÿ›
David Goatรฉ

๐Ÿ› -
David Golpira

๐Ÿ› +
David Golpira

๐Ÿ›
David Kovaล™รญk

๐Ÿ›
David M. Karr (fullname at gmail.com)

๐Ÿ›
David Renz

๐Ÿ’ป ๐Ÿ›
David Renz

๐Ÿ›
Deleted user

๐Ÿ›
Dell Green

๐Ÿ› -
Dem Pilafian

๐Ÿ› +
Dem Pilafian

๐Ÿ›
Den

๐Ÿ›
Denis Borovikov

๐Ÿ’ป ๐Ÿ›
Dennie Reniers

๐Ÿ’ป ๐Ÿ›
Dennis Kieselhorst

๐Ÿ›
Derek P. Moore

๐Ÿ›
Dichotomia

๐Ÿ› -
Dionisio Cortรฉs Fernรกndez

๐Ÿ’ป ๐Ÿ› +
Dionisio Cortรฉs Fernรกndez

๐Ÿ’ป ๐Ÿ›
Dmitri Bourlatchkov

๐Ÿ›
Dmitriy Kuzmin

๐Ÿ›
Dmytro Dashenkov

๐Ÿ›
Drew Hall

๐Ÿ›
Dumitru Postoronca

๐Ÿ›
Dylan Adams

๐Ÿ› -
Eden Hao

๐Ÿ› +
Eden Hao

๐Ÿ›
Egor Bredikhin

๐Ÿ›
Elan P. Kugelmass

๐Ÿ›
Elder S.

๐Ÿ›
Emile

๐Ÿ›
Eric

๐Ÿ›
Eric Kintzer

๐Ÿ› -
Eric Perret

๐Ÿ› +
Eric Perret

๐Ÿ›
Eric Squires

๐Ÿ›
Erich L Foster

๐Ÿ›
Erik Bleske

๐Ÿ›
Ernst Reissner

๐Ÿ›
F.W. Dekker

๐Ÿ› -
Facundo

๐Ÿ› -
Federico Giust

๐Ÿ› +
FSchliephacke

๐Ÿ› +
Facundo

๐Ÿ› +
Federico Giust

๐Ÿ›
Fedor Sherstobitov

๐Ÿ›
Felix Lampe

๐Ÿ›
Filip Golonka

๐Ÿ›
Filipe Esperandio

๐Ÿ’ป ๐Ÿ› +
Filippo Nova

๐Ÿ› + +
Francesco la Torre

๐Ÿ›
Francisco Duarte

๐Ÿ›
Frieder Bluemle

๐Ÿ› - -
Frits Jalvingh

๐Ÿ’ป ๐Ÿ›
G. Bazior

๐Ÿ›
Gabe Henkes

๐Ÿ›
Genoud Magloire

๐Ÿ› + +
Geoffrey555

๐Ÿ›
Georg Romstorfer

๐Ÿ›
Gio

๐Ÿ› - -
Gol

๐Ÿ›
Gonzalo Exequiel Ibars Ingman

๐Ÿ’ป ๐Ÿ›
GooDer

๐Ÿ›
Gregor Riegler

๐Ÿ› + +
Grzegorz Olszewski

๐Ÿ›
Gunther Schrijvers

๐Ÿ’ป ๐Ÿ›
Gustavo Krieger

๐Ÿ› - -
Guy Elsmore-Paddock

๐Ÿ›
Gรถrkem Mรผlayim

๐Ÿ›
Hanzel Godinez

๐Ÿ› +
Haoliang Chen

๐Ÿ› + +
Harsh Kukreja

๐Ÿ›
Heber

๐Ÿ›
Henning Schmiedehausen

๐Ÿ’ป ๐Ÿ›
Henning von Bargen

๐Ÿ’ป - -
Hervรฉ Boutemy

๐Ÿ›
Himanshu Pandey

๐Ÿ›
Hokwang Lee

๐Ÿ› + +
Hooperbloob

๐Ÿ’ป
Hung PHAN

๐Ÿ›
IDoCodingStuffs

๐Ÿ’ป ๐Ÿ›
Iccen Gan

๐Ÿ› - -
Ignacio Mariano Tirabasso

๐Ÿ›
Igor Melnichenko

๐Ÿ›
Igor Moreno

๐Ÿ› + +
Intelesis-MS

๐Ÿ›
Iroha_

๐Ÿ›
Ishan Srivastava

๐Ÿ›
Ivano Guerini

๐Ÿ› - -
Ivar Andreas Bonsaksen

๐Ÿ›
Ivo ล mรญd

๐Ÿ›
JJengility

๐Ÿ› -
Jake Hemmerle

๐Ÿ› -
James Harrison

๐Ÿ› -
Jan

๐Ÿ› -
Jan Aertgeerts

๐Ÿ’ป ๐Ÿ› +
Jake Hemmerle

๐Ÿ› +
James Harrison

๐Ÿ› ๐Ÿ’ป +
Jan

๐Ÿ› +
Jan Aertgeerts

๐Ÿ’ป ๐Ÿ›
Jan Brรผmmer

๐Ÿ›
Jan Tล™รญska

๐Ÿ›
Jan-Lukas Else

๐Ÿ› + +
Jason Qiu

๐Ÿ’ป ๐Ÿ“–
Jason Williams

๐Ÿ›
Jean-Paul Mayer

๐Ÿ›
Jean-Simon Larochelle

๐Ÿ› - -
Jeff Bartolotta

๐Ÿ’ป ๐Ÿ›
Jeff Hube

๐Ÿ’ป ๐Ÿ›
Jeff Jensen

๐Ÿ› -
Jeff May

๐Ÿ› -
Jens Gerdes

๐Ÿ› -
Jeroen Borgers

๐Ÿ› -
Jerome Russ

๐Ÿ› +
Jeff May

๐Ÿ› +
Jens Gerdes

๐Ÿ› +
Jeroen Borgers

๐Ÿ› ๐Ÿ’ป +
Jerome Russ

๐Ÿ›
JerritEic

๐Ÿ’ป ๐Ÿ“–
Jiri Pejchal

๐Ÿ›
Jithin Sunny

๐Ÿ› + +
Jiล™รญ ล korpil

๐Ÿ›
Joao Machado

๐Ÿ›
Jochen Krauss

๐Ÿ›
Johan Hammar

๐Ÿ› - -
John Karp

๐Ÿ›
John Zhang

๐Ÿ›
John-Teng

๐Ÿ’ป ๐Ÿ› + +
Jon Moroney

๐Ÿ’ป ๐Ÿ›
Jonas Geiregat

๐Ÿ›
Jonathan Wiesel

๐Ÿ’ป ๐Ÿ›
Jordan

๐Ÿ› - -
Jordi Llach

๐Ÿ›
Jorge Solรณrzano

๐Ÿ›
JorneVL

๐Ÿ› + +
Jose Palafox

๐Ÿ›
Jose Stovall

๐Ÿ›
Joseph

๐Ÿ’ป
Joseph Heenan

๐Ÿ› - -
Josh Feingold

๐Ÿ’ป ๐Ÿ›
Josh Holthaus

๐Ÿ›
Joshua S Arquilevich

๐Ÿ› + +
Joรฃo Ferreira

๐Ÿ’ป ๐Ÿ›
Joรฃo Pedro Schmitt

๐Ÿ›
Juan Martรญn Sotuyo Dodero

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› ๐Ÿšง
Juan Pablo Civile

๐Ÿ› - -
Julian Voronetsky

๐Ÿ›
Julien

๐Ÿ›
Julius

๐Ÿ› + +
JustPRV

๐Ÿ›
Jรถrn Huxhorn

๐Ÿ›
KThompso

๐Ÿ›
Kai Amundsen

๐Ÿ› - -
Karel Vervaeke

๐Ÿ›
Karl-Andero Mere

๐Ÿ›
Karl-Philipp Richter

๐Ÿ› + +
Karsten Silz

๐Ÿ›
Kazuma Watanabe

๐Ÿ›
Kev

๐Ÿ›
Keve Mรผller

๐Ÿ› - -
Kevin Guerra

๐Ÿ’ป
Kevin Jones

๐Ÿ›
Kevin Wayne

๐Ÿ› + +
Kieran Black

๐Ÿ›
Kirill Zubov

๐Ÿ›
Kirk Clemens

๐Ÿ’ป ๐Ÿ›
Klaus Hartl

๐Ÿ› - -
Koen Van Looveren

๐Ÿ›
Kris Scheibe

๐Ÿ’ป ๐Ÿ›
Kunal Thanki

๐Ÿ› + +
LaLucid

๐Ÿ’ป
Larry Diamond

๐Ÿ’ป ๐Ÿ›
Lars Knickrehm

๐Ÿ›
Leo Gutierrez

๐Ÿ› - -
LiGaOg

๐Ÿ’ป
Lintsi

๐Ÿ›
Linus Fernandes

๐Ÿ› + +
Lixon Lookose

๐Ÿ›
Logesh

๐Ÿ›
Lorenzo Gabriele

๐Ÿ›
Loรฏc Ledoyen

๐Ÿ› - -
Lucas Silva

๐Ÿ›
Lucas Soncini

๐Ÿ’ป ๐Ÿ›
Lukasz Slonina

๐Ÿ› + +
Lukebray

๐Ÿ›
Lyor Goldstein

๐Ÿ›
MCMicS

๐Ÿ›
Macarse

๐Ÿ› - -
Machine account for PMD

๐Ÿ’ป
Maciek Siemczyk

๐Ÿ›
Maikel Steneker

๐Ÿ’ป ๐Ÿ› + +
Maksim Moiseikin

๐Ÿ›
Manfred Koch

๐Ÿ›
Manuel Moya Ferrer

๐Ÿ’ป ๐Ÿ›
Manuel Ryan

๐Ÿ› - -
Marat Vyshegorodtsev

๐Ÿ›
Marcel Hรคrle

๐Ÿ›
Marcello Fialho

๐Ÿ› + +
Marcin Rataj

๐Ÿ›
Mark Adamcin

๐Ÿ›
Mark Hall

๐Ÿ’ป ๐Ÿ›
Mark Kolich

๐Ÿ› - -
Mark Pritchard

๐Ÿ›
Markus Rathgeb

๐Ÿ›
Marquis Wang

๐Ÿ› + +
Martin Feldsztejn

๐Ÿ›
Martin Lehmann

๐Ÿ›
Martin Spamer

๐Ÿ›
Martin Tarjรกnyi

๐Ÿ› - -
MatFl

๐Ÿ›
Mateusz Stefanski

๐Ÿ›
Mathieu Gouin

๐Ÿ› + +
MatiasComercio

๐Ÿ’ป ๐Ÿ›
Matt Benson

๐Ÿ›
Matt De Poorter

๐Ÿ›
Matt Harrah

๐Ÿ› - -
Matt Nelson

๐Ÿ›
Matthew Amos

๐Ÿ›
Matthew Duggan

๐Ÿ› + +
Matthew Hall

๐Ÿ›
Matรญas Fraga

๐Ÿ’ป ๐Ÿ›
Maxime Robert

๐Ÿ’ป ๐Ÿ›
MetaBF

๐Ÿ› - -
Michael

๐Ÿ›
Michael Bell

๐Ÿ›
Michael Bernstein

๐Ÿ› + +
Michael Clay

๐Ÿ›
Michael Dombrowski

๐Ÿ›
Michael Hausegger

๐Ÿ›
Michael Hoefer

๐Ÿ› - -
Michael Mรถbius

๐Ÿ›
Michael N. Lipp

๐Ÿ›
Michael Pellegrini

๐Ÿ› + +
Michal Kordas

๐Ÿ›
Michaล‚ Borek

๐Ÿ›
Michaล‚ Kuliล„ski

๐Ÿ›
Miguel Nรบรฑez Dรญaz-Montes

๐Ÿ› - -
Mihai Ionut

๐Ÿ›
Mirek Hankus

๐Ÿ›
Mladjan Gadzic

๐Ÿ› + +
MrAngry52

๐Ÿ›
Muminur Choudhury

๐Ÿ›
Mykhailo Palahuta

๐Ÿ’ป ๐Ÿ›
Nagendra Kumar Singh

๐Ÿ› - -
Nahuel Barrios

๐Ÿ›
Nathan Braun

๐Ÿ›
Nathan Reynolds

๐Ÿ› + +
Nathan Reynolds

๐Ÿ›
Nathanaรซl

๐Ÿ›
Naveen

๐Ÿ’ป
Nazdravi

๐Ÿ› - -
Neha-Dhonde

๐Ÿ›
Nicholas Doyle

๐Ÿ›
Nick Butcher

๐Ÿ› + +
Nico Gallinal

๐Ÿ›
Nicola Dal Maso

๐Ÿ›
Nicolas Filotto

๐Ÿ’ป
Nikita Chursin

๐Ÿ› - -
Niklas Baudy

๐Ÿ›
Nikolas Havrikov

๐Ÿ›
Nilesh Virkar

๐Ÿ› + +
Nimit Patel

๐Ÿ›
Niranjan Harpale

๐Ÿ›
Noah Sussman

๐Ÿ›
Noah0120

๐Ÿ› - -
Noam Tamim

๐Ÿ›
Noel Grandin

๐Ÿ›
Olaf Haalstra

๐Ÿ› + +
Oleg Pavlenko

๐Ÿ›
Oleksii Dykov

๐Ÿ’ป
Oliver Eikemeier

๐Ÿ›
Olivier Parent

๐Ÿ’ป ๐Ÿ› - -
Ollie Abbey

๐Ÿ’ป ๐Ÿ›
OverDrone

๐Ÿ›
Ozan Gulle

๐Ÿ’ป ๐Ÿ› + +
PUNEET JAIN

๐Ÿ›
Parbati Bose

๐Ÿ›
Paul Berg

๐Ÿ›
Pavel Bludov

๐Ÿ› - -
Pavel Miฤka

๐Ÿ›
Pedro Nuno Santos

๐Ÿ›
Pedro Rijo

๐Ÿ› + +
Pelisse Romain

๐Ÿ’ป ๐Ÿ“– ๐Ÿ› +
Per Abich

๐Ÿ’ป
Pete Davids

๐Ÿ›
Peter Bruin

๐Ÿ›
Peter Chittum

๐Ÿ’ป ๐Ÿ› - -
Peter Cudmore

๐Ÿ›
Peter Kasson

๐Ÿ› + +
Peter Kofler

๐Ÿ› +
Peter Paul Bakker

๐Ÿ’ป
Pham Hai Trung

๐Ÿ›
Philip Graf

๐Ÿ’ป ๐Ÿ›
Philip Hachey

๐Ÿ›
Philippe Ozil

๐Ÿ› +
Phinehas Artemix

๐Ÿ› -
Phinehas Artemix

๐Ÿ›
Phokham Nonava

๐Ÿ›
Piotr Szymaล„ski

๐Ÿ›
Piotrek ลปygieล‚o

๐Ÿ’ป ๐Ÿ›
Pranay Jaiswal

๐Ÿ›
Prasad Kamath

๐Ÿ›
Prasanna

๐Ÿ› +
Presh-AR

๐Ÿ› -
Presh-AR

๐Ÿ›
Puneet1726

๐Ÿ›
Rafael Cortรชs

๐Ÿ›
RaheemShaik999

๐Ÿ›
RajeshR

๐Ÿ’ป ๐Ÿ›
Ramachandra Mohan

๐Ÿ› +
Ramel0921

๐Ÿ›
Raquel Pau

๐Ÿ› @@ -685,266 +694,274 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Valentin Brandl

๐Ÿ›
Valeria

๐Ÿ›
Vasily Anisimov

๐Ÿ› +
Vibhor Goyal

๐Ÿ›
Vickenty Fesunov

๐Ÿ› -
Victor Noรซl

๐Ÿ› +
Victor Noรซl

๐Ÿ›
Vincent Galloy

๐Ÿ’ป
Vincent HUYNH

๐Ÿ›
Vincent Maurin

๐Ÿ›
Vincent Privat

๐Ÿ›
Vishhwas

๐Ÿ›
Vitaly

๐Ÿ› -
Vitaly Polonetsky

๐Ÿ› +
Vitaly Polonetsky

๐Ÿ›
Vojtech Polivka

๐Ÿ›
Vsevolod Zholobov

๐Ÿ›
Vyom Yadav

๐Ÿ’ป
Wang Shidong

๐Ÿ›
Waqas Ahmed

๐Ÿ›
Wayne J. Earl

๐Ÿ› -
Wchenghui

๐Ÿ› +
Wchenghui

๐Ÿ›
Will Winder

๐Ÿ›
William Brockhus

๐Ÿ’ป ๐Ÿ›
Wilson Kurniawan

๐Ÿ›
Wim Deblauwe

๐Ÿ›
Woongsik Choi

๐Ÿ›
XenoAmess

๐Ÿ’ป ๐Ÿ› -
Yang

๐Ÿ’ป +
Yang

๐Ÿ’ป
YaroslavTER

๐Ÿ›
Young Chan

๐Ÿ’ป ๐Ÿ›
YuJin Kim

๐Ÿ›
Yuri Dolzhenko

๐Ÿ›
Yurii Dubinka

๐Ÿ›
Zoltan Farkas

๐Ÿ› -
Zustin

๐Ÿ› +
Zustin

๐Ÿ›
aaronhurst-google

๐Ÿ›
alexmodis

๐Ÿ›
andreoss

๐Ÿ›
andrey81inmd

๐Ÿ’ป ๐Ÿ›
anicoara

๐Ÿ›
arunprasathav

๐Ÿ› -
asiercamara

๐Ÿ› +
asiercamara

๐Ÿ›
astillich-igniti

๐Ÿ’ป
avesolovksyy

๐Ÿ›
avishvat

๐Ÿ›
avivmu

๐Ÿ›
axelbarfod1

๐Ÿ›
b-3-n

๐Ÿ› -
balbhadra9

๐Ÿ› +
balbhadra9

๐Ÿ›
base23de

๐Ÿ›
bergander

๐Ÿ›
berkam

๐Ÿ’ป ๐Ÿ›
breizh31

๐Ÿ›
caesarkim

๐Ÿ›
carolyujing

๐Ÿ› -
cesares-basilico

๐Ÿ› +
cesares-basilico

๐Ÿ›
chrite

๐Ÿ›
cobratbq

๐Ÿ›
coladict

๐Ÿ›
cosmoJFH

๐Ÿ›
cristalp

๐Ÿ›
crunsk

๐Ÿ› -
cwholmes

๐Ÿ› +
cwholmes

๐Ÿ›
cyberjj999

๐Ÿ›
cyw3

๐Ÿ›
d1ss0nanz

๐Ÿ› +
dalizi007

๐Ÿ’ป
danbrycefairsailcom

๐Ÿ›
dariansanity

๐Ÿ› -
darrenmiliband

๐Ÿ› -
davidburstrom

๐Ÿ› +
darrenmiliband

๐Ÿ› +
davidburstrom

๐Ÿ›
dbirkman-paloalto

๐Ÿ›
deepak-patra

๐Ÿ›
dependabot[bot]

๐Ÿ’ป ๐Ÿ›
dinesh150

๐Ÿ›
diziaq

๐Ÿ› -
dreaminpast123

๐Ÿ› -
duanyanan

๐Ÿ› +
dreaminpast123

๐Ÿ› +
duanyanan

๐Ÿ›
dutt-sanjay

๐Ÿ›
dylanleung

๐Ÿ›
dzeigler

๐Ÿ›
ekkirala

๐Ÿ›
emersonmoura

๐Ÿ› -
fairy

๐Ÿ› -
filiprafalowicz

๐Ÿ’ป +
fairy

๐Ÿ› +
filiprafalowicz

๐Ÿ’ป
foxmason

๐Ÿ›
frankegabor

๐Ÿ›
frankl

๐Ÿ›
freafrea

๐Ÿ›
fsapatin

๐Ÿ› -
gracia19

๐Ÿ› -
guo fei

๐Ÿ› +
gracia19

๐Ÿ› +
guo fei

๐Ÿ›
gurmsc5

๐Ÿ›
gwilymatgearset

๐Ÿ’ป ๐Ÿ›
haigsn

๐Ÿ›
hemanshu070

๐Ÿ›
henrik242

๐Ÿ› -
hongpuwu

๐Ÿ› -
hvbtup

๐Ÿ’ป ๐Ÿ› +
hongpuwu

๐Ÿ› +
hvbtup

๐Ÿ’ป ๐Ÿ›
igniti GmbH

๐Ÿ›
ilovezfs

๐Ÿ›
itaigilo

๐Ÿ›
jakivey32

๐Ÿ›
jbennett2091

๐Ÿ› -
jcamerin

๐Ÿ› -
jkeener1

๐Ÿ› +
jcamerin

๐Ÿ› +
jkeener1

๐Ÿ›
jmetertea

๐Ÿ›
johnra2

๐Ÿ’ป
josemanuelrolon

๐Ÿ’ป ๐Ÿ›
kabroxiko

๐Ÿ’ป ๐Ÿ›
karwer

๐Ÿ› -
kaulonline

๐Ÿ› -
kdaemonv

๐Ÿ› +
kaulonline

๐Ÿ› +
kdaemonv

๐Ÿ›
kenji21

๐Ÿ’ป ๐Ÿ›
kfranic

๐Ÿ›
khalidkh

๐Ÿ›
krzyk

๐Ÿ›
lasselindqvist

๐Ÿ› -
lihuaib

๐Ÿ› -
lonelyma1021

๐Ÿ› +
lgemeinhardt

๐Ÿ› +
lihuaib

๐Ÿ› +
lonelyma1021

๐Ÿ›
lpeddy

๐Ÿ›
lujiefsi

๐Ÿ’ป +
lukelukes

๐Ÿ’ป
lyriccoder

๐Ÿ› + +
marcelmore

๐Ÿ›
matchbox

๐Ÿ›
matthiaskraaz

๐Ÿ›
meandonlyme

๐Ÿ› - -
mikesive

๐Ÿ›
milossesic

๐Ÿ›
mriddell95

๐Ÿ› + +
mrlzh

๐Ÿ›
msloan

๐Ÿ›
mucharlaravalika

๐Ÿ›
mvenneman

๐Ÿ› - -
nareshl119

๐Ÿ›
nicolas-harraudeau-sonarsource

๐Ÿ›
noerremark

๐Ÿ› + +
novsirion

๐Ÿ›
oggboy

๐Ÿ›
oinume

๐Ÿ›
orimarko

๐Ÿ’ป ๐Ÿ› - -
pallavi agarwal

๐Ÿ›
parksungrin

๐Ÿ›
patpatpat123

๐Ÿ› + +
patriksevallius

๐Ÿ›
pbrajesh1

๐Ÿ›
phoenix384

๐Ÿ›
piotrszymanski-sc

๐Ÿ’ป - -
plan3d

๐Ÿ›
poojasix

๐Ÿ›
prabhushrikant

๐Ÿ› + +
pujitha8783

๐Ÿ›
r-r-a-j

๐Ÿ›
raghujayjunk

๐Ÿ›
rajeshveera

๐Ÿ› - -
rajeswarreddy88

๐Ÿ›
recdevs

๐Ÿ›
reudismam

๐Ÿ’ป ๐Ÿ› + +
rijkt

๐Ÿ›
rillig-tk

๐Ÿ›
rmohan20

๐Ÿ’ป ๐Ÿ›
rxmicro

๐Ÿ› - -
ryan-gustafson

๐Ÿ’ป ๐Ÿ›
sabi0

๐Ÿ›
scais

๐Ÿ› + +
sebbASF

๐Ÿ›
sergeygorbaty

๐Ÿ’ป
shilko2013

๐Ÿ› +
shiomiyan

๐Ÿ“–
simeonKondr

๐Ÿ› - -
snajberk

๐Ÿ›
sniperrifle2004

๐Ÿ› + +
snuyanzin

๐Ÿ› ๐Ÿ’ป
sratz

๐Ÿ›
stonio

๐Ÿ›
sturton

๐Ÿ’ป ๐Ÿ›
sudharmohan

๐Ÿ› - -
suruchidawar

๐Ÿ›
svenfinitiv

๐Ÿ› + +
tashiscool

๐Ÿ›
test-git-hook

๐Ÿ›
testation21

๐Ÿ’ป ๐Ÿ›
thanosa

๐Ÿ›
tiandiyixian

๐Ÿ› - -
tobwoerk

๐Ÿ›
tprouvot

๐Ÿ› + +
trentchilders

๐Ÿ›
triandicAnt

๐Ÿ›
trishul14

๐Ÿ›
tsui

๐Ÿ›
winhkey

๐Ÿ› - -
witherspore

๐Ÿ›
wjljack

๐Ÿ› + +
wuchiuwong

๐Ÿ›
xingsong

๐Ÿ›
xioayuge

๐Ÿ›
xnYi9wRezm

๐Ÿ’ป ๐Ÿ›
xuanuy

๐Ÿ› - -
xyf0921

๐Ÿ›
yalechen-cyw3

๐Ÿ› + +
yasuharu-sato

๐Ÿ›
zenglian

๐Ÿ›
zgrzyt93

๐Ÿ’ป ๐Ÿ›
zh3ng

๐Ÿ›
zt_soft

๐Ÿ› - -
ztt79

๐Ÿ›
zzzzfeng

๐Ÿ› + +
รrpรกd Magosรกnyi

๐Ÿ›
ไปป่ดตๆฐ

๐Ÿ› +
่Œ…ๅปถๅฎ‰

๐Ÿ’ป diff --git a/docs/pages/pmd/userdocs/cli_reference.md b/docs/pages/pmd/userdocs/cli_reference.md index ce4214b9fa..8c1f59df60 100644 --- a/docs/pages/pmd/userdocs/cli_reference.md +++ b/docs/pages/pmd/userdocs/cli_reference.md @@ -76,14 +76,14 @@ The tool comes with a rather extensive help text, simply running with `--help`! %} {% include custom/cli_option_row.html options="--file-list" option_arg="filepath" - description="Path to file containing a comma delimited list of files to analyze. + description="Path to file containing a list of files to analyze, one path per line. If this is given, then you don't need to provide `--dir`." %} {% include custom/cli_option_row.html options="--force-language" option_arg="lang" description="Force a language to be used for all input files, irrespective of - filenames. When using this option, the automatic language selection - by extension is disabled and all files are tried to be parsed with + file names. When using this option, the automatic language selection + by extension is disabled and PMD tries to parse all files with the given language `<lang>`. Parsing errors are ignored and unparsable files are skipped. @@ -92,9 +92,9 @@ The tool comes with a rather extensive help text, simply running with `--help`! %} {% include custom/cli_option_row.html options="--ignore-list" option_arg="filepath" - description="Path to file containing a comma delimited list of files to ignore. + description="Path to file containing a list of files to ignore, one path per line. This option can be combined with `--dir` and `--file-list`. - This ignore list takes precedence over any files in the filelist." + This ignore list takes precedence over any files in the file-list." %} {% include custom/cli_option_row.html options="--help,-h,-H" description="Display help on usage." diff --git a/docs/pages/pmd/userdocs/cpd/cpd.md b/docs/pages/pmd/userdocs/cpd/cpd.md index dc4577e41d..d909eb4f2f 100644 --- a/docs/pages/pmd/userdocs/cpd/cpd.md +++ b/docs/pages/pmd/userdocs/cpd/cpd.md @@ -112,9 +112,9 @@ Novice as much as advanced readers may want to [read on on Refactoring Guru](htt languages="Java" %} {% include custom/cli_option_row.html options="--ignore-annotations" - description="Ignore language annotations when comparing text" + description="Ignore language annotations (Java) or attributes (C#) when comparing text" default="false" - languages="Java" + languages="C#, Java" %} {% include custom/cli_option_row.html options="--ignore-literal-sequences" description="Ignore sequences of literals (common e.g. in list initializers)" diff --git a/docs/pages/pmd/userdocs/tools/ant.md b/docs/pages/pmd/userdocs/tools/ant.md index eb7eae4367..9212ac552c 100644 --- a/docs/pages/pmd/userdocs/tools/ant.md +++ b/docs/pages/pmd/userdocs/tools/ant.md @@ -236,9 +236,10 @@ nested element. Possible values are: - - + + + diff --git a/docs/pages/pmd/userdocs/tools/tools.md b/docs/pages/pmd/userdocs/tools/tools.md index 78d7b7d316..c889ef0091 100644 --- a/docs/pages/pmd/userdocs/tools/tools.md +++ b/docs/pages/pmd/userdocs/tools/tools.md @@ -197,7 +197,7 @@ To install the PMD plugin for Eclipse: * Start Eclipse and open a project * Select "Help"->"Software Updates"->"Find and Install" * Click "Next", then click "New remote site" -* Enter "PMD" into the Name field and into the URL field +* Enter "PMD" into the Name field and into the URL field * Click through the rest of the dialog boxes to install the plugin Alternatively, you can download the latest zip file and follow the above procedures diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index a1be51b66c..b5ece35c0b 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -19,14 +19,65 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy -### Fixed Issues +#### Java 19 Support -* javascript - * [#3948](https://github.com/pmd/pmd/issues/3948): \[js] Invalid operator error for method property in object literal +This release of PMD brings support for Java 19. There are no new standard language features. + +PMD supports [JEP 427: Pattern Matching for switch (Third Preview)](https://openjdk.org/jeps/427) and +[JEP 405: Record Patterns (Preview)](https://openjdk.org/jeps/405) as preview language features. + +In order to analyze a project with PMD that uses these language features, +you'll need to enable it via the environment variable `PMD_JAVA_OPTS` and select the new language +version `19-preview`: + + export PMD_JAVA_OPTS=--enable-preview + ./run.sh pmd -language java -version 19-preview ... + +Note: Support for Java 17 preview language features have been removed. The version "17-preview" is no longer available. + +#### Gherkin support +Thanks to the contribution from [Anne Brouwers](https://github.com/ASBrouwers) PMD now has CPD support +for the [Gherkin](https://cucumber.io/docs/gherkin/) language. It is used to defined test cases for the +[Cucumber](https://cucumber.io/) testing tool for behavior-driven development. + +Being based on a proper Antlr grammar, CPD can: + +* ignore comments +* honor [comment-based suppressions](pmd_userdocs_cpd.html#suppression) + +### Fixed Issues +* java + * [#4015](https://github.com/pmd/pmd/issues/4015): \[java] Support JDK 19 +* java-bestpractices + * [#3455](https://github.com/pmd/pmd/issues/3455): \[java] WhileLoopWithLiteralBoolean - false negative with complex expressions +* java-design + * [#3729](https://github.com/pmd/pmd/issues/3729): \[java] TooManyMethods ignores "real" methods which are named like getters or setters + * [#3949](https://github.com/pmd/pmd/issues/3949): \[java] FinalFieldCouldBeStatic - false negative with unnecessary parenthesis +* java-performance + * [#3625](https://github.com/pmd/pmd/issues/3625): \[java] AddEmptyString - false negative with empty var ### API Changes +#### Deprecated API + +* The experimental Java AST class {% jdoc java::lang.java.ast.ASTGuardedPattern %} has been deprecated and + will be removed. It was introduced for Java 17 and Java 18 Preview as part of pattern matching for switch, + but it is no longer supported with Java 19 Preview. + +#### Experimental APIs + +* To support the Java preview language features "Pattern Matching for Switch" and "Record Patterns", the following + AST nodes have been introduced as experimental: + * {% jdoc java::lang.java.ast.ASTSwitchGuard %} + * {% jdoc java::lang.java.ast.ASTRecordPattern %} + * {% jdoc java::lang.java.ast.ASTComponentPatternList %} + ### External Contributions +* [#3984](https://github.com/pmd/pmd/pull/3984): \[java] Fix AddEmptyString false-negative issue - [@LiGaOg](https://github.com/LiGaOg) +* [#3988](https://github.com/pmd/pmd/pull/3988): \[java] Modify WhileLoopWithLiteralBoolean to meet the missing case #3455 - [@VoidxHoshi](https://github.com/VoidxHoshi) +* [#3992](https://github.com/pmd/pmd/pull/3992): \[java] FinalFieldCouldBeStatic - fix false negative with unnecessary parenthesis - [@dalizi007](https://github.com/dalizi007) +* [#3994](https://github.com/pmd/pmd/pull/3994): \[java] TooManyMethods - improve getter/setter detection (#3729) - [@341816041](https://github.com/341816041) +* [#4017](https://github.com/pmd/pmd/pull/4017): Add Gherkin support to CPD - [@ASBrouwers](https://github.com/ASBrouwers) {% endtocmaker %} diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 08788a3064..52432fe7c6 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -5,6 +5,220 @@ permalink: pmd_release_notes_old.html Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases +## 25-June-2022 - 6.47.0 + +The PMD team is pleased to announce PMD 6.47.0. + +This is a minor release. + +### Table Of Contents + +* [Fixed Issues](#fixed-issues) +* [API Changes](#api-changes) +* [External Contributions](#external-contributions) +* [Stats](#stats) + +### Fixed Issues +* core + * [#3999](https://github.com/pmd/pmd/issues/3999): \[cli] All files are analyzed despite parameter `--file-list` + * [#4009](https://github.com/pmd/pmd/issues/4009): \[core] Cannot build PMD with Temurin 17 +* java-bestpractices + * [#3824](https://github.com/pmd/pmd/issues/3824): \[java] UnusedPrivateField: Do not flag fields annotated with @Version + * [#3825](https://github.com/pmd/pmd/issues/3825): \[java] UnusedPrivateField: Do not flag fields annotated with @Id or @EmbeddedId +* java-design + * [#3823](https://github.com/pmd/pmd/issues/3823): \[java] ImmutableField: Do not flag fields in @Entity + * [#3981](https://github.com/pmd/pmd/issues/3981): \[java] ImmutableField reports fields annotated with @Value (Spring) + * [#3998](https://github.com/pmd/pmd/issues/3998): \[java] ImmutableField reports fields annotated with @Captor (Mockito) + * [#4004](https://github.com/pmd/pmd/issues/4004): \[java] ImmutableField reports fields annotated with @GwtMock (GwtMockito) and @Spy (Mockito) + * [#4008](https://github.com/pmd/pmd/issues/4008): \[java] ImmutableField not reporting fields that are only initialized in the declaration + * [#4011](https://github.com/pmd/pmd/issues/4011): \[java] ImmutableField: Do not flag fields annotated with @Inject + * [#4020](https://github.com/pmd/pmd/issues/4020): \[java] ImmutableField reports fields annotated with @FindBy and @FindBys (Selenium) +* java-errorprone + * [#3936](https://github.com/pmd/pmd/issues/3936): \[java] AvoidFieldNameMatchingMethodName should consider enum class + * [#3937](https://github.com/pmd/pmd/issues/3937): \[java] AvoidDuplicateLiterals - uncompilable test cases + +### API Changes + +No changes. + +### External Contributions +* [#3985](https://github.com/pmd/pmd/pull/3985): \[java] Fix false negative problem about Enum in AvoidFieldNameMatchingMethodName #3936 - [@Scrsloota](https://github.com/Scrsloota) +* [#3993](https://github.com/pmd/pmd/pull/3993): \[java] AvoidDuplicateLiterals - Add the method "buz" definition to test cases - [@dalizi007](https://github.com/dalizi007) +* [#4002](https://github.com/pmd/pmd/pull/4002): \[java] ImmutableField - Ignore fields annotated with @Value (Spring) or @Captor (Mockito) - [@jjlharrison](https://github.com/jjlharrison) +* [#4003](https://github.com/pmd/pmd/pull/4003): \[java] UnusedPrivateField - Ignore fields annotated with @Id/@EmbeddedId/@Version (JPA) or @Mock/@Spy/@MockBean (Mockito/Spring) - [@jjlharrison](https://github.com/jjlharrison) +* [#4006](https://github.com/pmd/pmd/pull/4006): \[doc] Fix eclipse plugin update site URL - [@shiomiyan](https://github.com/shiomiyan) +* [#4010](https://github.com/pmd/pmd/pull/4010): \[core] Bump kotlin to version 1.7.0 - [@maikelsteneker](https://github.com/maikelsteneker) + +### Stats +* 45 commits +* 23 closed tickets & PRs +* Days since last release: 27 + +## 28-May-2022 - 6.46.0 + +The PMD team is pleased to announce PMD 6.46.0. + +This is a minor release. + +### Table Of Contents + +* [New and noteworthy](#new-and-noteworthy) + * [CLI improvements](#cli-improvements) + * [C# Improvements](#c#-improvements) + * [New Rules](#new-rules) + * [Deprecated Rules](#deprecated-rules) +* [Fixed Issues](#fixed-issues) +* [API Changes](#api-changes) + * [Deprecated ruleset references](#deprecated-ruleset-references) + * [Deprecated API](#deprecated-api) + * [Internal API](#internal-api) +* [External Contributions](#external-contributions) +* [Stats](#stats) + +### New and noteworthy + +#### CLI improvements + +The PMD CLI now allows repeating the `--dir` (`-d`) and `--rulesets` (`-R`) options, + as well as providing several space-separated arguments to either of them. For instance: +```shell +pmd -d src/main/java src/test/java -R rset1.xml -R rset2.xml +``` +This also allows globs to be used on the CLI if your shell supports shell expansion. +For instance, the above can be written +```shell +pmd -d src/*/java -R rset*.xml +``` +Please use theses new forms instead of using comma-separated lists as argument to these options. + +#### C# Improvements + +When executing CPD on C# sources, the option `--ignore-annotations` is now supported as well. +It ignores C# attributes when detecting duplicated code. This option can also be enabled via +the CPD GUI. See [#3974](https://github.com/pmd/pmd/pull/3974) for details. + +#### New Rules + +This release ships with 2 new Java rules. + +* [`EmptyControlStatement`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_codestyle.html#emptycontrolstatement) reports many instances of empty things, e.g. control statements whose + body is empty, as well as empty initializers. + + EmptyControlStatement also works for empty `for` and `do` loops, while there were previously + no corresponding rules. + + This new rule replaces the rules EmptyFinallyBlock, EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, + EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, and EmptyWhileStmt. + +```xml + +``` + +The rule is part of the quickstart.xml ruleset. + +* [`UnnecessarySemicolon`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_codestyle.html#unnecessarysemicolon) reports semicolons that are unnecessary (so called "empty statements" + and "empty declarations"). + + This new rule replaces the rule EmptyStatementNotInLoop. + +```xml + +``` + +The rule is part of the quickstart.xml ruleset. + +#### Deprecated Rules + +* The following Java rules are deprecated and removed from the quickstart ruleset, as the new rule +[`EmptyControlStatement`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_codestyle.html#emptycontrolstatement) merges their functionality: + * [`EmptyFinallyBlock`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptyfinallyblock) + * [`EmptyIfStmt`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptyifstmt) + * [`EmptyInitializer`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptyinitializer) + * [`EmptyStatementBlock`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptystatementblock) + * [`EmptySwitchStatements`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptyswitchstatements) + * [`EmptySynchronizedBlock`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptysynchronizedblock) + * [`EmptyTryBlock`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptytryblock) + * [`EmptyWhileStmt`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptywhilestmt) +* The Java rule [`EmptyStatementNotInLoop`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_errorprone.html#emptystatementnotinloop) is deprecated and removed from the quickstart +ruleset. Use the new rule [`UnnecessarySemicolon`](https://pmd.github.io/pmd-6.46.0/pmd_rules_java_codestyle.html#unnecessarysemicolon) instead. + +### Fixed Issues + +* cli + * [#1445](https://github.com/pmd/pmd/issues/1445): \[core] Allow CLI to take globs as parameters +* core + * [#2352](https://github.com/pmd/pmd/issues/2352): \[core] Deprecate \-\ hyphen notation for ruleset references + * [#3787](https://github.com/pmd/pmd/issues/3787): \[core] Internalize some methods in Ant Formatter + * [#3835](https://github.com/pmd/pmd/issues/3835): \[core] Deprecate system properties of CPDCommandLineInterface + * [#3942](https://github.com/pmd/pmd/issues/3942): \[core] common-io path traversal vulnerability (CVE-2021-29425) +* cs (c#) + * [#3974](https://github.com/pmd/pmd/pull/3974): \[cs] Add option to ignore C# attributes (annotations) +* go + * [#2752](https://github.com/pmd/pmd/issues/2752): \[go] Error parsing unicode values +* html + * [#3955](https://github.com/pmd/pmd/pull/3955): \[html] Improvements for handling text and comment nodes + * [#3978](https://github.com/pmd/pmd/pull/3978): \[html] Add additional file extensions htm, xhtml, xht, shtml +* java + * [#3423](https://github.com/pmd/pmd/issues/3423): \[java] Error processing identifiers with Unicode +* java-bestpractices + * [#3954](https://github.com/pmd/pmd/issues/3954): \[java] NPE in UseCollectionIsEmptyRule when .size() is called in a record +* java-design + * [#3874](https://github.com/pmd/pmd/issues/3874): \[java] ImmutableField reports fields annotated with @Autowired (Spring) and @Mock (Mockito) +* java-errorprone + * [#3096](https://github.com/pmd/pmd/issues/3096): \[java] EmptyStatementNotInLoop FP in 6.30.0 with IfStatement +* java-performance + * [#3379](https://github.com/pmd/pmd/issues/3379): \[java] UseArraysAsList must ignore primitive arrays + * [#3965](https://github.com/pmd/pmd/issues/3965): \[java] UseArraysAsList false positive with non-trivial loops +* javascript + * [#2605](https://github.com/pmd/pmd/issues/2605): \[js] Support unicode characters + * [#3948](https://github.com/pmd/pmd/issues/3948): \[js] Invalid operator error for method property in object literal +* python + * [#2604](https://github.com/pmd/pmd/issues/2604): \[python] Support unicode identifiers + +### API Changes + +#### Deprecated ruleset references + +Ruleset references with the following formats are now deprecated and will produce a warning +when used on the CLI or in a ruleset XML file: +- `-`, eg `java-basic`, which resolves to `rulesets/java/basic.xml` +- the internal release number, eg `600`, which resolves to `rulesets/releases/600.xml` + +Use the explicit forms of these references to be compatible with PMD 7. + +#### Deprecated API + +- toString is now deprecated. The format of this + method will remain the same until PMD 7. The deprecation is intended to steer users + away from relying on this format, as it may be changed in PMD 7. +- getInputPaths and +setInputPaths are now deprecated. +A new set of methods have been added, which use lists and do not rely on comma splitting. + +#### Internal API + +Those APIs are not intended to be used by clients, and will be hidden or removed with PMD 7.0.0. +You can identify them with the `@InternalApi` annotation. You'll also get a deprecation warning. + +- CPDCommandLineInterface has been internalized. In order to execute CPD either +CPD#run or CPD#main +should be used. +- Several members of BaseCPDCLITest have been deprecated with replacements. +- The methods Formatter#start, +Formatter#end, Formatter#getRenderer, +and Formatter#isNoOutputSupplied have been internalized. + +### External Contributions + +* [#3961](https://github.com/pmd/pmd/pull/3961): \[java] Fix #3954 - NPE in UseCollectionIsEmptyRule with record - [@flyhard](https://github.com/flyhard) +* [#3964](https://github.com/pmd/pmd/pull/3964): \[java] Fix #3874 - ImmutableField: fix mockito/spring false positives - [@lukelukes](https://github.com/lukelukes) +* [#3974](https://github.com/pmd/pmd/pull/3974): \[cs] Add option to ignore C# attributes (annotations) - [@maikelsteneker](https://github.com/maikelsteneker) + +### Stats +* 92 commits +* 30 closed tickets & PRs +* Days since last release: 28 + ## 30-April-2022 - 6.45.0 The PMD team is pleased to announce PMD 6.45.0. diff --git a/pmd-apex-jorje/pom.xml b/pmd-apex-jorje/pom.xml index 56d5058b44..1e1c81fdce 100644 --- a/pmd-apex-jorje/pom.xml +++ b/pmd-apex-jorje/pom.xml @@ -9,7 +9,7 @@ net.sourceforge.pmd pmd 7.0.0-SNAPSHOT - ../ + ../pom.xml diff --git a/pmd-apex/pom.xml b/pmd-apex/pom.xml index 50ede2c0da..08f0ea8b2a 100644 --- a/pmd-apex/pom.xml +++ b/pmd-apex/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd 7.0.0-SNAPSHOT - ../ + ../pom.xml @@ -61,10 +61,6 @@ - - commons-io - commons-io - org.apache.commons commons-lang3 @@ -81,6 +77,11 @@ junit test + + org.junit.jupiter + junit-jupiter + test + com.github.stefanbirkner system-rules diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBlockStatement.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBlockStatement.java index bb93c0b88b..92b8ed7e82 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBlockStatement.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTBlockStatement.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.apex.ast; +import java.util.Objects; + import net.sourceforge.pmd.lang.document.TextDocument; import apex.jorje.semantic.ast.statement.BlockStatement; @@ -40,6 +42,6 @@ public final class ASTBlockStatement extends AbstractApexNode { @Override public boolean hasRealLoc() { - return super.hasRealLoc() && node.getLoc() != getParent().getNode().getLoc(); + return super.hasRealLoc() && !Objects.equals(node.getLoc(), getParent().getNode().getLoc()); } } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/cpd/ApexCpdTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/cpd/ApexCpdTest.java index 51ad07f5c8..412c4ea024 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/cpd/ApexCpdTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/cpd/ApexCpdTest.java @@ -11,18 +11,18 @@ import java.io.File; import java.io.IOException; import java.util.Iterator; -import org.apache.commons.io.FilenameUtils; import org.junit.Before; import org.junit.Test; import net.sourceforge.pmd.lang.apex.ApexLanguageModule; +import net.sourceforge.pmd.util.IOUtil; public class ApexCpdTest { private File testdir; @Before public void setUp() { - String path = FilenameUtils.normalize("src/test/resources/net/sourceforge/pmd/cpd/issue427"); + String path = IOUtil.normalizePath("src/test/resources/net/sourceforge/pmd/cpd/issue427"); testdir = new File(path); } diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java index ae6b37127d..5358e1beb5 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java @@ -17,13 +17,12 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Test; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.document.FileLocation; +import net.sourceforge.pmd.util.IOUtil; public class ApexParserTest extends ApexParserTestBase { @@ -158,7 +157,7 @@ public class ApexParserTest extends ApexParserTestBase { for (File file : fList) { if (file.isFile() && file.getName().endsWith(".cls")) { - String sourceCode = FileUtils.readFileToString(file, StandardCharsets.UTF_8); + String sourceCode = IOUtil.readFileToString(file, StandardCharsets.UTF_8); Assert.assertNotNull(parse(sourceCode)); } } @@ -170,7 +169,7 @@ public class ApexParserTest extends ApexParserTestBase { */ @Test public void parseInheritedSharingClass() throws IOException { - String source = IOUtils.toString(ApexParserTest.class.getResourceAsStream("InheritedSharing.cls"), + String source = IOUtil.readToString(ApexParserTest.class.getResourceAsStream("InheritedSharing.cls"), StandardCharsets.UTF_8); parse(source); } @@ -182,7 +181,7 @@ public class ApexParserTest extends ApexParserTestBase { */ @Test public void stackOverflowDuringClassParsing() throws Exception { - String source = IOUtils.toString(ApexParserTest.class.getResourceAsStream("StackOverflowClass.cls"), + String source = IOUtil.readToString(ApexParserTest.class.getResourceAsStream("StackOverflowClass.cls"), StandardCharsets.UTF_8); ASTUserClassOrInterface rootNode = parse(source); diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysisTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysisTest.java index 319f265ecf..7f3effa2b7 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysisTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/multifile/ApexMultifileAnalysisTest.java @@ -15,13 +15,14 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.Arrays; -import org.apache.commons.io.IOUtils; import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.SystemErrRule; import org.junit.rules.TemporaryFolder; +import net.sourceforge.pmd.util.IOUtil; + public class ApexMultifileAnalysisTest { @Rule @@ -67,7 +68,7 @@ public class ApexMultifileAnalysisTest { private void copyResource(String resourcePath, String relativePathInTempDir) throws IOException { File file = tempFolder.newFile(relativePathInTempDir); - String fileContents = IOUtils.toString(getClass().getResourceAsStream(resourcePath), StandardCharsets.UTF_8); + String fileContents = IOUtil.readToString(getClass().getResourceAsStream(resourcePath), StandardCharsets.UTF_8); Files.write(file.toPath(), Arrays.asList(fileContents.split("\\R").clone())); } diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index c77811a156..500a752818 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd 7.0.0-SNAPSHOT - ../ + ../pom.xml @@ -68,10 +68,6 @@ com.beust jcommander - - commons-io - commons-io - net.sf.saxon @@ -98,6 +94,11 @@ org.pcollections pcollections + + com.github.oowekyala.ooxml + nice-xml-messages + 3.1 + org.slf4j @@ -106,7 +107,7 @@ com.github.tomakehurst - wiremock + wiremock-jre8 test @@ -115,8 +116,13 @@ test - junit - junit + org.junit.jupiter + junit-jupiter + test + + + org.junit.platform + junit-platform-suite test @@ -124,11 +130,6 @@ JUnitParams test - - org.apache.ant - ant-testutil - test - org.mockito mockito-core @@ -139,6 +140,11 @@ system-rules test + + com.github.stefanbirkner + system-lambda + test + me.tongfei progressbar diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java index 4dd8f5f2b7..ad1d9508a8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java @@ -34,7 +34,6 @@ import net.sourceforge.pmd.internal.Slf4jSimpleConfiguration; import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.reporting.ReportStats; -import net.sourceforge.pmd.reporting.ReportStatsListener; import net.sourceforge.pmd.util.datasource.DataSource; import net.sourceforge.pmd.util.log.MessageReporter; import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter; @@ -74,34 +73,6 @@ public final class PMD { } - private static ReportStats runAndReturnStats(PmdAnalysis pmd) { - if (pmd.getRulesets().isEmpty()) { - return ReportStats.empty(); - } - - @SuppressWarnings("PMD.CloseResource") - ReportStatsListener listener = new ReportStatsListener(); - - pmd.addListener(listener); - - try { - pmd.performAnalysis(); - } catch (Exception e) { - pmd.getReporter().errorEx("Exception during processing", e); - ReportStats stats = listener.getResult(); - printErrorDetected(1 + stats.getNumErrors()); - return stats; // should have been closed - } - ReportStats stats = listener.getResult(); - - if (stats.getNumErrors() > 0) { - printErrorDetected(stats.getNumErrors()); - } - - return stats; - } - - static void encourageToUseIncrementalAnalysis(final PMDConfiguration configuration) { if (!configuration.isIgnoreIncrementalAnalysis() && configuration.getAnalysisCache() instanceof NoopAnalysisCache @@ -201,11 +172,6 @@ public final class PMD { return runPmd(configuration); } - private static void printErrorDetected(int errors) { - String msg = CliMessages.errorDetectedMessage(errors, "PMD"); - log.error(msg); - } - /** * Execute PMD from a configuration. Returns the status code without * exiting the VM. This is the main entry point to run a full PMD run @@ -232,8 +198,8 @@ public final class PMD { return StatusCode.ERROR; } try { - ReportStats stats; - stats = PMD.runAndReturnStats(pmd); + log.debug("Current classpath:\n{}", System.getProperty("java.class.path")); + ReportStats stats = pmd.runAndReturnStats(); if (pmdReporter.numErrors() > 0) { // processing errors are ignored return StatusCode.ERROR; @@ -248,7 +214,7 @@ public final class PMD { } catch (Exception e) { pmdReporter.errorEx("Exception while running PMD.", e); - printErrorDetected(1); + PmdAnalysis.printErrorDetected(pmdReporter, 1); return StatusCode.ERROR; } finally { finishBenchmarker(configuration); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java index 589f8b2241..314e4ce3ea 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java @@ -13,7 +13,6 @@ import java.util.List; import java.util.Objects; import java.util.Properties; -import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.LoggerFactory; @@ -464,7 +463,6 @@ public class PMDConfiguration extends AbstractConfiguration { * @deprecated Use {@link #getAllInputPaths()} */ @Deprecated - @DeprecatedUntil700 public @Nullable String getInputPaths() { return inputPaths.isEmpty() ? null : String.join(",", inputPaths); } @@ -479,20 +477,34 @@ public class PMDConfiguration extends AbstractConfiguration { /** * Set the comma separated list of input paths to process for source files. * - * @param inputPaths - * The comma separated list. + * @param inputPaths The comma separated list. + * + * @throws NullPointerException If the parameter is null + * @deprecated Use {@link #setInputPaths(List)} or {@link #addInputPath(String)} */ - public void setInputPaths(@NonNull String inputPaths) { + @Deprecated + public void setInputPaths(String inputPaths) { List paths = new ArrayList<>(); Collections.addAll(paths, inputPaths.split(",")); - paths.removeIf(StringUtils::isBlank); this.inputPaths = paths; } - public void setInputPaths(@NonNull List inputPaths) { - List paths = new ArrayList<>(inputPaths); - paths.removeIf(StringUtils::isBlank); - this.inputPaths = paths; + /** + * Set the input paths to the given list of paths. + * @throws NullPointerException If the parameter is null + */ + public void setInputPaths(List inputPaths) { + this.inputPaths = new ArrayList<>(inputPaths); + } + + /** + * Add an input path. It is not split on commas. + * + * @throws NullPointerException If the parameter is null + */ + public void addInputPath(String inputPath) { + Objects.requireNonNull(inputPath); + this.inputPaths.add(inputPath); } public String getInputFilePath() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java index 883c569f9c..4455b29fd8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java @@ -22,6 +22,7 @@ import net.sourceforge.pmd.benchmark.TimeTracker; import net.sourceforge.pmd.benchmark.TimedOperation; import net.sourceforge.pmd.benchmark.TimedOperationCategory; import net.sourceforge.pmd.cache.AnalysisCacheListener; +import net.sourceforge.pmd.cli.internal.CliMessages; import net.sourceforge.pmd.cli.internal.ProgressBarListener; import net.sourceforge.pmd.internal.util.AssertionUtil; import net.sourceforge.pmd.internal.util.FileCollectionUtil; @@ -33,8 +34,11 @@ import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.processor.AbstractPMDProcessor; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; +import net.sourceforge.pmd.reporting.ReportStats; +import net.sourceforge.pmd.reporting.ReportStatsListener; import net.sourceforge.pmd.util.ClasspathClassLoader; import net.sourceforge.pmd.util.IOUtil; +import net.sourceforge.pmd.util.StringUtil; import net.sourceforge.pmd.util.log.MessageReporter; /** @@ -364,7 +368,7 @@ public final class PmdAnalysis implements AutoCloseable { ruleSets.removeDysfunctionalRules(brokenRules); for (final Rule rule : brokenRules) { - reporter.warn("Removed misconfigured rule: {} cause: {}", + reporter.warn("Removed misconfigured rule: {0} cause: {1}", rule.getName(), rule.dysfunctionReason()); } @@ -397,4 +401,41 @@ public final class PmdAnalysis implements AutoCloseable { } } + ReportStats runAndReturnStats() { + if (getRulesets().isEmpty()) { + return ReportStats.empty(); + } + + @SuppressWarnings("PMD.CloseResource") + ReportStatsListener listener = new ReportStatsListener(); + + addListener(listener); + + try { + performAnalysis(); + } catch (Exception e) { + getReporter().errorEx("Exception during processing", e); + ReportStats stats = listener.getResult(); + printErrorDetected(1 + stats.getNumErrors()); + return stats; // should have been closed + } + ReportStats stats = listener.getResult(); + + if (stats.getNumErrors() > 0) { + printErrorDetected(stats.getNumErrors()); + } + + return stats; + } + + static void printErrorDetected(MessageReporter reporter, int errors) { + String msg = CliMessages.errorDetectedMessage(errors, "PMD"); + // note: using error level here increments the error count of the reporter, + // which we don't want. + reporter.info(StringUtil.quoteMessageFormat(msg)); + } + + void printErrorDetected(int errors) { + printErrorDetected(getReporter(), errors); + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RulePriority.java b/pmd-core/src/main/java/net/sourceforge/pmd/RulePriority.java index bdfd2c3882..4211ef881e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RulePriority.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RulePriority.java @@ -94,4 +94,35 @@ public enum RulePriority { return LOW; } } + + /** + * Returns the priority which corresponds to the given number as returned by + * {@link RulePriority#getPriority()}. If the number is an invalid value, + * then null will be returned. + * + * @param priority The numeric priority value. + */ + public static RulePriority valueOfNullable(int priority) { + try { + return RulePriority.values()[priority - 1]; + } catch (ArrayIndexOutOfBoundsException e) { + return null; + } + } + + /** + * Returns the priority which corresponds to the given number as returned by + * {@link RulePriority#getPriority()}. If the number is an invalid value, + * then null will be returned. + * + * @param priority The numeric priority value. + */ + public static RulePriority valueOfNullable(String priority) { + try { + int integer = Integer.parseInt(priority); + return RulePriority.values()[integer - 1]; + } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) { + return null; + } + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java index f2a178e71a..ccd56add3a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactory.java @@ -1,11 +1,23 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd; +import static net.sourceforge.pmd.util.CollectionUtil.setOf; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.DESCRIPTION; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.EXCLUDE; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.EXCLUDE_PATTERN; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.INCLUDE_PATTERN; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.NAME; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.PRIORITY; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.REF; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.RULE; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.RULESET; + import java.io.IOException; import java.io.InputStream; +import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -21,20 +33,38 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; -import org.xml.sax.SAXException; import net.sourceforge.pmd.RuleSet.RuleSetBuilder; -import net.sourceforge.pmd.internal.DOMUtils; import net.sourceforge.pmd.lang.rule.RuleReference; import net.sourceforge.pmd.rules.RuleFactory; import net.sourceforge.pmd.util.ResourceLoader; +import net.sourceforge.pmd.util.StringUtil; +import net.sourceforge.pmd.util.internal.xml.PmdXmlReporter; +import net.sourceforge.pmd.util.internal.xml.XmlErrorMessages; +import net.sourceforge.pmd.util.internal.xml.XmlUtil; +import net.sourceforge.pmd.util.log.MessageReporter; +import net.sourceforge.pmd.util.log.internal.NoopReporter; + +import com.github.oowekyala.ooxml.DomUtils; +import com.github.oowekyala.ooxml.messages.NiceXmlMessageSpec; +import com.github.oowekyala.ooxml.messages.OoxmlFacade; +import com.github.oowekyala.ooxml.messages.PositionedXmlDoc; +import com.github.oowekyala.ooxml.messages.XmlException; +import com.github.oowekyala.ooxml.messages.XmlMessageHandler; +import com.github.oowekyala.ooxml.messages.XmlMessageReporterBase; +import com.github.oowekyala.ooxml.messages.XmlPosition; +import com.github.oowekyala.ooxml.messages.XmlPositioner; +import com.github.oowekyala.ooxml.messages.XmlSeverity; /** * RuleSetFactory is responsible for creating RuleSet instances from XML @@ -45,14 +75,11 @@ final class RuleSetFactory { private static final Logger LOG = LoggerFactory.getLogger(RuleSetFactory.class); - private static final String DESCRIPTION = "description"; - private static final String UNEXPECTED_ELEMENT = "Unexpected element <"; - private static final String PRIORITY = "priority"; - private final ResourceLoader resourceLoader; private final RulePriority minimumPriority; private final boolean warnDeprecated; private final RuleSetFactoryCompatibility compatibilityFilter; + private final MessageReporter reporter; private final boolean includeDeprecatedRuleReferences; private final Map parsedRulesets = new HashMap<>(); @@ -61,13 +88,15 @@ final class RuleSetFactory { RulePriority minimumPriority, boolean warnDeprecated, RuleSetFactoryCompatibility compatFilter, - boolean includeDeprecatedRuleReferences) { + boolean includeDeprecatedRuleReferences, + MessageReporter reporter) { this.resourceLoader = resourceLoader; this.minimumPriority = minimumPriority; this.warnDeprecated = warnDeprecated; this.includeDeprecatedRuleReferences = includeDeprecatedRuleReferences; this.compatibilityFilter = compatFilter; + this.reporter = reporter; } @@ -75,17 +104,17 @@ final class RuleSetFactory { * Create a RuleSet from a RuleSetReferenceId. Priority filtering is ignored * when loading a single Rule. The currently configured ResourceLoader is used. * - * @param ruleSetReferenceId - * The RuleSetReferenceId of the RuleSet to create. + * @param ruleSetReferenceId The RuleSetReferenceId of the RuleSet to create. + * * @return A new RuleSet. */ - RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId) { + @NonNull RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId) { return createRuleSet(ruleSetReferenceId, includeDeprecatedRuleReferences); } - private RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId, boolean withDeprecatedRuleReferences) + private @NonNull RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId, boolean withDeprecatedRuleReferences) throws RuleSetLoadException { - return parseRuleSetNode(ruleSetReferenceId, withDeprecatedRuleReferences); + return readDocument(ruleSetReferenceId, withDeprecatedRuleReferences); } /** @@ -104,15 +133,14 @@ final class RuleSetFactory { * @return A new Rule. */ private Rule createRule(RuleSetReferenceId ruleSetReferenceId, boolean withDeprecatedRuleReferences) { - if (ruleSetReferenceId.isAllRules()) { + RuleSetReferenceId parentRuleset = ruleSetReferenceId.getParentRulesetIfThisIsARule(); + if (parentRuleset == null) { throw new IllegalArgumentException( "Cannot parse a single Rule from an all Rule RuleSet reference: <" + ruleSetReferenceId + ">."); } - RuleSet ruleSet; - // java8: computeIfAbsent - if (parsedRulesets.containsKey(ruleSetReferenceId)) { - ruleSet = parsedRulesets.get(ruleSetReferenceId); - } else { + // can't use computeIfAbsent as creating a ruleset may add more entries to the map. + RuleSet ruleSet = parsedRulesets.get(parentRuleset); + if (ruleSet == null) { ruleSet = createRuleSet(ruleSetReferenceId, withDeprecatedRuleReferences); parsedRulesets.put(ruleSetReferenceId, ruleSet); } @@ -127,80 +155,116 @@ final class RuleSetFactory { * or not * * @return The new RuleSet. + * + * @throws RuleSetLoadException If the ruleset cannot be parsed (eg IO exception, malformed XML, validation errors) */ - private RuleSet parseRuleSetNode(RuleSetReferenceId ruleSetReferenceId, boolean withDeprecatedRuleReferences) { - try (CheckedInputStream inputStream = new CheckedInputStream( - ruleSetReferenceId.getInputStream(resourceLoader), new Adler32());) { + private @NonNull RuleSet readDocument(RuleSetReferenceId ruleSetReferenceId, boolean withDeprecatedRuleReferences) { + + try (CheckedInputStream inputStream = new CheckedInputStream(ruleSetReferenceId.getInputStream(resourceLoader), new Adler32())) { if (!ruleSetReferenceId.isExternal()) { throw new IllegalArgumentException( "Cannot parse a RuleSet from a non-external reference: <" + ruleSetReferenceId + ">."); } + + XmlMessageHandler printer = getXmlMessagePrinter(); DocumentBuilder builder = createDocumentBuilder(); InputSource inputSource = new InputSource(inputStream); - Document document = builder.parse(inputSource); - Element ruleSetElement = document.getDocumentElement(); + inputSource.setSystemId(ruleSetReferenceId.getRuleSetFileName()); - RuleSetBuilder ruleSetBuilder = new RuleSetBuilder(inputStream.getChecksum().getValue()) - .withFileName(ruleSetReferenceId.getRuleSetFileName()); + OoxmlFacade ooxml = new OoxmlFacade() + .withPrinter(printer) + .withAnsiColors(false); + PositionedXmlDoc parsed = ooxml.parse(builder, inputSource); - if (ruleSetElement.hasAttribute("name")) { - ruleSetBuilder.withName(ruleSetElement.getAttribute("name")); - } else { - LOG.warn("RuleSet name is missing. Future versions of PMD will require it."); - ruleSetBuilder.withName("Missing RuleSet Name"); - } + @SuppressWarnings("PMD.CloseResource") + PmdXmlReporterImpl err = new PmdXmlReporterImpl(reporter, ooxml, parsed.getPositioner()); + try { + RuleSetBuilder ruleSetBuilder = new RuleSetBuilder(inputStream.getChecksum().getValue()).withFileName(ruleSetReferenceId.getRuleSetFileName()); - Set rulesetReferences = new HashSet<>(); - - NodeList nodeList = ruleSetElement.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node node = nodeList.item(i); - if (node.getNodeType() == Node.ELEMENT_NODE) { - String nodeName = node.getNodeName(); - String text = DOMUtils.parseTextNode(node); - if (DESCRIPTION.equals(nodeName)) { - ruleSetBuilder.withDescription(text); - } else if ("include-pattern".equals(nodeName)) { - final Pattern pattern = parseRegex(text); - if (pattern == null) { - continue; - } - ruleSetBuilder.withFileInclusions(pattern); - } else if ("exclude-pattern".equals(nodeName)) { - final Pattern pattern = parseRegex(text); - if (pattern == null) { - continue; - } - ruleSetBuilder.withFileExclusions(pattern); - } else if ("rule".equals(nodeName)) { - parseRuleNode(ruleSetReferenceId, ruleSetBuilder, node, withDeprecatedRuleReferences, rulesetReferences); + RuleSet ruleSet = parseRulesetNode(ruleSetReferenceId, withDeprecatedRuleReferences, parsed, ruleSetBuilder, err); + if (err.errCount > 0) { + // note this makes us jump to the catch branch + // these might have been non-fatal errors + String message; + if (err.errCount == 1) { + message = "An XML validation error occurred"; } else { - throw new IllegalArgumentException(UNEXPECTED_ELEMENT + node.getNodeName() - + "> encountered as child of element."); + message = err.errCount + " XML validation errors occurred"; } + throw new RuleSetLoadException(ruleSetReferenceId, message); } + return ruleSet; + } catch (Exception | Error e) { + throw e; } - - if (!ruleSetBuilder.hasDescription()) { - LOG.warn("RuleSet description is missing. Future versions of PMD will require it."); - ruleSetBuilder.withDescription("Missing description"); - } - - ruleSetBuilder.filterRulesByPriority(minimumPriority); - - return ruleSetBuilder.build(); - } catch (ParserConfigurationException | IOException | SAXException ex) { - ex.printStackTrace(); - throw new RuntimeException("Couldn't read the ruleset " + ruleSetReferenceId + ": " + ex.getMessage(), ex); + } catch (ParserConfigurationException | IOException ex) { + throw new RuleSetLoadException(ruleSetReferenceId, ex); } } - private Pattern parseRegex(String text) { + + private RuleSet parseRulesetNode(RuleSetReferenceId ruleSetReferenceId, + boolean withDeprecatedRuleReferences, + PositionedXmlDoc parsed, + RuleSetBuilder builder, + PmdXmlReporter err) { + Element ruleSetElement = parsed.getDocument().getDocumentElement(); + + if (ruleSetElement.hasAttribute("name")) { + builder.withName(ruleSetElement.getAttribute("name")); + } else { + err.at(ruleSetElement).warn("RuleSet name is missing. Future versions of PMD will require it."); + builder.withName("Missing RuleSet Name"); + } + + Set rulesetReferences = new HashSet<>(); + + for (Element node : DomUtils.children(ruleSetElement)) { + String text = XmlUtil.parseTextNode(node); + if (DESCRIPTION.matchesElt(node)) { + builder.withDescription(text); + } else if (INCLUDE_PATTERN.matchesElt(node)) { + final Pattern pattern = parseRegex(node, text, err); + if (pattern == null) { + continue; + } + builder.withFileInclusions(pattern); + } else if (EXCLUDE_PATTERN.matchesElt(node)) { + final Pattern pattern = parseRegex(node, text, err); + if (pattern == null) { + continue; + } + builder.withFileExclusions(pattern); + } else if (RULE.matchesElt(node)) { + try { + parseRuleNode(ruleSetReferenceId, builder, node, withDeprecatedRuleReferences, rulesetReferences, err); + } catch (XmlException ignored) { + // already reported (it's an XmlException), error count + // was incremented so parent method will throw RuleSetLoadException. + } + } else { + err.at(node).error(XmlErrorMessages.ERR__UNEXPECTED_ELEMENT_IN, + node.getTagName(), + RULESET); + } + } + + if (!builder.hasDescription()) { + err.at(ruleSetElement).warn("RuleSet description is missing. Future versions of PMD will require it."); + builder.withDescription("Missing description"); + } + + builder.filterRulesByPriority(minimumPriority); + + return builder.build(); + } + + private Pattern parseRegex(Element node, String text, PmdXmlReporter err) { final Pattern pattern; try { pattern = Pattern.compile(text); } catch (PatternSyntaxException pse) { - LOG.warn(pse.getMessage()); + err.at(node).error(pse); return null; } return pattern; @@ -247,32 +311,33 @@ final class RuleSetFactory { /** * Parse a rule node. * - * @param ruleSetReferenceId - * The RuleSetReferenceId of the RuleSet being parsed. - * @param ruleSetBuilder - * The RuleSet being constructed. - * @param ruleNode - * Must be a rule element node. - * @param withDeprecatedRuleReferences - * whether rule references that are deprecated should be ignored - * or not - * @param rulesetReferences keeps track of already processed complete ruleset references in order to log a warning + * @param ruleSetReferenceId The RuleSetReferenceId of the RuleSet being parsed. + * @param ruleSetBuilder The RuleSet being constructed. + * @param ruleNode Must be a rule element node. + * @param withDeprecatedRuleReferences whether rule references that are deprecated should be ignored + * or not + * @param rulesetReferences keeps track of already processed complete ruleset references in order to log + * a warning */ - private void parseRuleNode(RuleSetReferenceId ruleSetReferenceId, RuleSetBuilder ruleSetBuilder, Node ruleNode, - boolean withDeprecatedRuleReferences, Set rulesetReferences) { - Element ruleElement = (Element) ruleNode; - String ref = ruleElement.getAttribute("ref"); - ref = compatibilityFilter.applyRef(ref, this.warnDeprecated); - if (ref == null) { - return; // deleted rule - } - if (ref.endsWith("xml")) { - parseRuleSetReferenceNode(ruleSetBuilder, ruleElement, ref, rulesetReferences); - } else if (StringUtils.isBlank(ref)) { - parseSingleRuleNode(ruleSetReferenceId, ruleSetBuilder, ruleNode); - } else { - parseRuleReferenceNode(ruleSetReferenceId, ruleSetBuilder, ruleNode, ref, withDeprecatedRuleReferences); + private void parseRuleNode(RuleSetReferenceId ruleSetReferenceId, + RuleSetBuilder ruleSetBuilder, + Element ruleNode, + boolean withDeprecatedRuleReferences, + Set rulesetReferences, + PmdXmlReporter err) { + if (REF.hasAttribute(ruleNode)) { + String ref = REF.getAttributeOrThrow(ruleNode, err); + RuleSetReferenceId refId = parseReferenceAndWarn(ref, REF.getAttributeNode(ruleNode), err); + if (refId != null) { + if (refId.isAllRules()) { + parseRuleSetReferenceNode(ruleSetBuilder, ruleNode, ref, refId, rulesetReferences, err); + } else { + parseRuleReferenceNode(ruleSetReferenceId, ruleSetBuilder, ruleNode, ref, refId, withDeprecatedRuleReferences, err); + } + return; + } } + parseSingleRuleNode(ruleSetReferenceId, ruleSetBuilder, ruleNode, err); } /** @@ -289,29 +354,38 @@ final class RuleSetFactory { * The RuleSet reference. * @param rulesetReferences keeps track of already processed complete ruleset references in order to log a warning */ - private void parseRuleSetReferenceNode(RuleSetBuilder ruleSetBuilder, Element ruleElement, String ref, Set rulesetReferences) { - String priority = null; - NodeList childNodes = ruleElement.getChildNodes(); - Set excludedRulesCheck = new HashSet<>(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node child = childNodes.item(i); - if (isElementNode(child, "exclude")) { - Element excludeElement = (Element) child; - String excludedRuleName = excludeElement.getAttribute("name"); + private void parseRuleSetReferenceNode(RuleSetBuilder ruleSetBuilder, + Element ruleElement, + String ref, + RuleSetReferenceId ruleSetReferenceId, Set rulesetReferences, + PmdXmlReporter err) { + RulePriority priority = null; + Map excludedRulesCheck = new HashMap<>(); + for (Element child : XmlUtil.getElementChildrenList(ruleElement)) { + if (EXCLUDE.matchesElt(child)) { + String excludedRuleName; + try { + excludedRuleName = NAME.getAttributeOrThrow(child, err); + } catch (XmlException ignored) { + // has been reported + continue; + } excludedRuleName = compatibilityFilter.applyExclude(ref, excludedRuleName, this.warnDeprecated); if (excludedRuleName != null) { - excludedRulesCheck.add(excludedRuleName); + excludedRulesCheck.put(excludedRuleName, child); } - } else if (isElementNode(child, PRIORITY)) { - priority = DOMUtils.parseTextNode(child).trim(); + } else if (PRIORITY.matchesElt(child)) { + priority = RuleFactory.parsePriority(err, child); + } else { + XmlUtil.reportIgnoredUnexpectedElt(ruleElement, child, setOf(EXCLUDE, PRIORITY), err); } } - final RuleSetReference ruleSetReference = new RuleSetReference(ref, true, excludedRulesCheck); + final RuleSetReference ruleSetReference = new RuleSetReference(ref, true, excludedRulesCheck.keySet()); // load the ruleset with minimum priority low, so that we get all rules, to be able to exclude any rule // minimum priority will be applied again, before constructing the final ruleset RuleSetFactory ruleSetFactory = toLoader().filterAbovePriority(RulePriority.LOW).warnDeprecated(false).toFactory(); - RuleSet otherRuleSet = ruleSetFactory.createRuleSet(RuleSetReferenceId.parse(ref).get(0)); + RuleSet otherRuleSet = ruleSetFactory.createRuleSet(ruleSetReferenceId); List potentialRules = new ArrayList<>(); int countDeprecated = 0; for (Rule rule : otherRuleSet.getRules()) { @@ -320,7 +394,7 @@ final class RuleSetFactory { RuleReference ruleReference = new RuleReference(rule, ruleSetReference); // override the priority if (priority != null) { - ruleReference.setPriority(RulePriority.valueOf(Integer.parseInt(priority))); + ruleReference.setPriority(priority); } if (rule.isDeprecated()) { @@ -334,8 +408,9 @@ final class RuleSetFactory { if (!potentialRules.isEmpty() && potentialRules.size() == countDeprecated) { // all rules in the ruleset have been deprecated - the ruleset itself is considered to be deprecated rulesetDeprecated = true; - LOG.warn("The RuleSet {} has been deprecated and will be removed in PMD {}", - ref, PMDVersion.getNextMajorRelease()); + err.at(REF.getAttributeNode(ruleElement)) + .warn("The RuleSet {0} has been deprecated and will be removed in PMD {1}", + ref, PMDVersion.getNextMajorRelease()); } for (RuleReference r : potentialRules) { @@ -348,47 +423,68 @@ final class RuleSetFactory { } if (!excludedRulesCheck.isEmpty()) { - LOG.warn( - "Unable to exclude rules {} from ruleset reference {}" - + "; perhaps the rule name is misspelled or the rule doesn't exist anymore?", - excludedRulesCheck, ref); + excludedRulesCheck.forEach( + (name, elt) -> + err.at(elt).warn("Exclude pattern ''{0}'' did not match any rule in ruleset ''{1}''", name, ref)); } if (rulesetReferences.contains(ref)) { - LOG.warn("The ruleset {} is referenced multiple times in \"{}\".", ref, ruleSetBuilder.getName()); + err.at(ruleElement).warn("The ruleset {0} is referenced multiple times in ruleset ''{1}''", ref, ruleSetBuilder.getName()); } rulesetReferences.add(ref); } + private RuleSetReferenceId parseReferenceAndWarn(String ref, + Node xmlPlace, + PmdXmlReporter err) { + ref = compatibilityFilter.applyRef(ref, this.warnDeprecated); + if (ref == null) { + err.at(xmlPlace).warn("Rule reference references a deleted rule, ignoring"); + return null; // deleted rule + } + // only emit a warning if we check for deprecated syntax + MessageReporter subReporter = warnDeprecated ? err.at(xmlPlace) : new NoopReporter(); + + List references = RuleSetReferenceId.parse(ref, subReporter); + if (references.size() > 1 && warnDeprecated) { + err.at(xmlPlace).warn("Using a comma separated list as a ref attribute is deprecated. " + + "All references but the first are ignored."); + } else if (references.isEmpty()) { + err.at(xmlPlace).warn("Empty ref attribute"); + return null; + } + return references.get(0); + } + /** * Parse a rule node as a single Rule. The Rule has been fully defined * within the context of the current RuleSet. * - * @param ruleSetReferenceId - * The RuleSetReferenceId of the RuleSet being parsed. - * @param ruleSetBuilder - * The RuleSet being constructed. - * @param ruleNode - * Must be a rule element node. + * @param ruleSetReferenceId The RuleSetReferenceId of the RuleSet being parsed. + * @param ruleSetBuilder The RuleSet being constructed. + * @param ruleNode Must be a rule element node. + * @param err Error reporter */ - private void parseSingleRuleNode(RuleSetReferenceId ruleSetReferenceId, RuleSetBuilder ruleSetBuilder, - Node ruleNode) { - Element ruleElement = (Element) ruleNode; + private void parseSingleRuleNode(RuleSetReferenceId ruleSetReferenceId, + RuleSetBuilder ruleSetBuilder, + Element ruleNode, + PmdXmlReporter err) { // Stop if we're looking for a particular Rule, and this element is not // it. if (StringUtils.isNotBlank(ruleSetReferenceId.getRuleName()) - && !isRuleName(ruleElement, ruleSetReferenceId.getRuleName())) { + && !isRuleName(ruleNode, ruleSetReferenceId.getRuleName())) { return; } - Rule rule = new RuleFactory(resourceLoader).buildRule(ruleElement); + Rule rule = new RuleFactory(resourceLoader).buildRule(ruleNode, err); rule.setRuleSetName(ruleSetBuilder.getName()); - if (warnDeprecated && StringUtils.isBlank(ruleElement.getAttribute("language"))) { - LOG.warn("Rule {}/{} does not mention attribute language='{}'," - + " please mention it explicitly to be compatible with PMD 7", - ruleSetReferenceId.getRuleSetFileName(), rule.getName(), - rule.getLanguage().getTerseName()); + if (warnDeprecated && StringUtils.isBlank(ruleNode.getAttribute("language"))) { + err.at(ruleNode).warn( + "Rule {0}/{1} does not mention attribute language='{2}'," + + " please mention it explicitly to be compatible with PMD 7", + ruleSetReferenceId.getRuleSetFileName(), rule.getName(), + rule.getLanguage().getTerseName()); } ruleSetBuilder.addRule(rule); @@ -400,26 +496,25 @@ final class RuleSetFactory { * which comes from another RuleSet with some of it's attributes potentially * overridden. * - * @param ruleSetReferenceId - * The RuleSetReferenceId of the RuleSet being parsed. - * @param ruleSetBuilder - * The RuleSet being constructed. - * @param ruleNode - * Must be a rule element node. - * @param ref - * A reference to a Rule. - * @param withDeprecatedRuleReferences - * whether rule references that are deprecated should be ignored - * or not + * @param ruleSetReferenceId The RuleSetReferenceId of the RuleSet being parsed. + * @param ruleSetBuilder The RuleSet being constructed. + * @param ruleNode Must be a rule element node. + * @param ref A reference to a Rule. + * @param withDeprecatedRuleReferences whether rule references that are deprecated should be ignored + * @param err Error reporter */ - private void parseRuleReferenceNode(RuleSetReferenceId ruleSetReferenceId, RuleSetBuilder ruleSetBuilder, - Node ruleNode, String ref, boolean withDeprecatedRuleReferences) { - Element ruleElement = (Element) ruleNode; + private void parseRuleReferenceNode(RuleSetReferenceId ruleSetReferenceId, + RuleSetBuilder ruleSetBuilder, + Element ruleNode, + String ref, + RuleSetReferenceId otherRuleSetReferenceId, + boolean withDeprecatedRuleReferences, + PmdXmlReporter err) { // Stop if we're looking for a particular Rule, and this element is not // it. if (StringUtils.isNotBlank(ruleSetReferenceId.getRuleName()) - && !isRuleName(ruleElement, ruleSetReferenceId.getRuleName())) { + && !isRuleName(ruleNode, ruleSetReferenceId.getRuleName())) { return; } @@ -428,51 +523,60 @@ final class RuleSetFactory { RuleSetFactory ruleSetFactory = toLoader().filterAbovePriority(RulePriority.LOW).warnDeprecated(false).toFactory(); boolean isSameRuleSet = false; - RuleSetReferenceId otherRuleSetReferenceId = RuleSetReferenceId.parse(ref).get(0); if (!otherRuleSetReferenceId.isExternal() - && containsRule(ruleSetReferenceId, otherRuleSetReferenceId.getRuleName())) { - otherRuleSetReferenceId = new RuleSetReferenceId(ref, ruleSetReferenceId); + && containsRule(ruleSetReferenceId, otherRuleSetReferenceId.getRuleName())) { + otherRuleSetReferenceId = new RuleSetReferenceId(ref, ruleSetReferenceId, err.at(REF.getAttributeNode(ruleNode))); isSameRuleSet = true; } else if (otherRuleSetReferenceId.isExternal() - && otherRuleSetReferenceId.getRuleSetFileName().equals(ruleSetReferenceId.getRuleSetFileName())) { - otherRuleSetReferenceId = new RuleSetReferenceId(otherRuleSetReferenceId.getRuleName(), ruleSetReferenceId); + && otherRuleSetReferenceId.getRuleSetFileName().equals(ruleSetReferenceId.getRuleSetFileName())) { + otherRuleSetReferenceId = new RuleSetReferenceId(otherRuleSetReferenceId.getRuleName(), ruleSetReferenceId, err.at(REF.getAttributeNode(ruleNode))); isSameRuleSet = true; } // do not ignore deprecated rule references Rule referencedRule = ruleSetFactory.createRule(otherRuleSetReferenceId, true); if (referencedRule == null) { - throw new IllegalArgumentException("Unable to find referenced rule " + otherRuleSetReferenceId.getRuleName() - + "; perhaps the rule name is misspelled?"); + throw err.at(ruleNode).error( + "Unable to find referenced rule {0}" + + "; perhaps the rule name is misspelled?", + otherRuleSetReferenceId.getRuleName()); } if (warnDeprecated && referencedRule.isDeprecated()) { if (referencedRule instanceof RuleReference) { RuleReference ruleReference = (RuleReference) referencedRule; - LOG.warn("Use Rule name {}/{} instead of the deprecated Rule name {}. PMD {}" + err.at(ruleNode).warn( + "Use Rule name {0}/{1} instead of the deprecated Rule name {2}. PMD {3}" + " will remove support for this deprecated Rule name usage.", - ruleReference.getRuleSetReference().getRuleSetFileName(), - ruleReference.getOriginalName(), otherRuleSetReferenceId, - PMDVersion.getNextMajorRelease()); + ruleReference.getRuleSetReference().getRuleSetFileName(), + ruleReference.getOriginalName(), otherRuleSetReferenceId, + PMDVersion.getNextMajorRelease()); } else { - LOG.warn("Discontinue using Rule name {} as it is scheduled for removal from PMD." - + " PMD {} will remove support for this Rule.", - otherRuleSetReferenceId, PMDVersion.getNextMajorRelease()); + err.at(ruleNode).warn( + "Discontinue using Rule name {0} as it is scheduled for removal from PMD." + + " PMD {1} will remove support for this Rule.", + otherRuleSetReferenceId, PMDVersion.getNextMajorRelease()); } } RuleSetReference ruleSetReference = new RuleSetReference(otherRuleSetReferenceId.getRuleSetFileName(), false); - RuleReference ruleReference = new RuleFactory(resourceLoader).decorateRule(referencedRule, ruleSetReference, ruleElement); + RuleReference ruleReference; + try { + ruleReference = new RuleFactory(resourceLoader).decorateRule(referencedRule, ruleSetReference, ruleNode, err); + } catch (XmlException e) { + throw err.at(ruleNode).error(e, "Error while parsing rule reference"); + } if (warnDeprecated && ruleReference.isDeprecated() && !isSameRuleSet) { - LOG.warn("Use Rule name {}/{} instead of the deprecated Rule name {}/{}. PMD {}" + err.at(ruleNode).warn( + "Use Rule name {0}/{1} instead of the deprecated Rule name {2}/{3}. PMD {4}" + " will remove support for this deprecated Rule name usage.", - ruleReference.getRuleSetReference().getRuleSetFileName(), - ruleReference.getOriginalName(), - ruleSetReferenceId.getRuleSetFileName(), - ruleReference.getName(), - PMDVersion.getNextMajorRelease()); + ruleReference.getRuleSetReference().getRuleSetFileName(), + ruleReference.getOriginalName(), + ruleSetReferenceId.getRuleSetFileName(), + ruleReference.getName(), + PMDVersion.getNextMajorRelease()); } if (withDeprecatedRuleReferences || !isSameRuleSet || !ruleReference.isDeprecated()) { @@ -483,10 +587,11 @@ final class RuleSetFactory { // which means, it is a plain reference. And the new reference overrides. // for all other cases, we should log a warning if (existingRuleReference.hasOverriddenAttributes() || !ruleReference.hasOverriddenAttributes()) { - LOG.warn("The rule {} is referenced multiple times in \"{}\". " + err.at(ruleNode).warn( + "The rule {0} is referenced multiple times in ruleset ''{1}''. " + "Only the last rule configuration is used.", - ruleReference.getName(), - ruleSetBuilder.getName()); + ruleReference.getName(), + ruleSetBuilder.getName()); } } @@ -504,6 +609,7 @@ final class RuleSetFactory { * @return {@code true} if the ruleName exists */ private boolean containsRule(RuleSetReferenceId ruleSetReferenceId, String ruleName) { + // TODO: avoid reloading the ruleset once again boolean found = false; try (InputStream ruleSet = ruleSetReferenceId.getInputStream(resourceLoader)) { DocumentBuilder builder = createDocumentBuilder(); @@ -519,16 +625,12 @@ final class RuleSetFactory { } } } catch (Exception e) { - throw new RuleSetLoadException("Cannot load " + ruleSetReferenceId, e); + throw new RuleSetLoadException(ruleSetReferenceId, e); } return found; } - private static boolean isElementNode(Node node, String name) { - return node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(name); - } - /** * Determine if the specified rule element will represent a Rule with the * given name. @@ -562,5 +664,87 @@ final class RuleSetFactory { .includeDeprecatedRuleReferences(includeDeprecatedRuleReferences); } + private @NonNull XmlMessageHandler getXmlMessagePrinter() { + return entry -> { + Level level = entry.getSeverity() == XmlSeverity.WARNING ? Level.WARN : Level.ERROR; + String quotedText = StringUtil.quoteMessageFormat(entry.toString()); + reporter.logEx(level, quotedText, new Object[0], entry.getCause()); + }; + } + + private static final class PmdXmlReporterImpl + extends XmlMessageReporterBase + implements PmdXmlReporter { + + private final MessageReporter pmdReporter; + private int errCount; + + PmdXmlReporterImpl(MessageReporter pmdReporter, OoxmlFacade ooxml, XmlPositioner positioner) { + super(ooxml, positioner); + this.pmdReporter = pmdReporter; + } + + @Override + protected MessageReporter create2ndStage(XmlPosition position, XmlPositioner positioner) { + return new MessageReporter() { + @Override + public boolean isLoggable(Level level) { + return pmdReporter.isLoggable(level); + } + + + @Override + public void log(Level level, String message, Object... formatArgs) { + logEx(level, message, formatArgs, null); + } + + @Override + public void logEx(Level level, String message, Object[] formatArgs, @Nullable Throwable error) { + newException(level, error, message, formatArgs); + } + + @Override + public XmlException error(@Nullable Throwable cause, @Nullable String contextMessage, Object... formatArgs) { + return newException(Level.ERROR, cause, contextMessage, formatArgs); + } + + @Override + public XmlException newException(Level level, Throwable cause, String message, Object... formatArgs) { + XmlSeverity severity; + switch (level) { + case WARN: + severity = XmlSeverity.WARNING; + break; + case ERROR: + errCount++; + severity = XmlSeverity.ERROR; + break; + default: + throw new IllegalArgumentException("unexpected level " + level); + } + + if (message == null && formatArgs.length != 0) { + throw new IllegalArgumentException("Cannot pass format arguments for null message"); + } + + String actualMessage = message == null ? cause.getMessage() + : MessageFormat.format(message, formatArgs); + NiceXmlMessageSpec spec = + new NiceXmlMessageSpec(position, actualMessage) + .withSeverity(severity) + .withCause(cause); + String fullMessage = ooxml.getFormatter().formatSpec(ooxml, spec, positioner); + XmlException ex = new XmlException(spec, fullMessage); + ooxml.getPrinter().accept(ex); // spec of newException is also to log. + return ex; + } + + @Override + public int numErrors() { + return pmdReporter.numErrors(); + } + }; + } + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactoryCompatibility.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactoryCompatibility.java index d0a0716bd5..610676a92c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactoryCompatibility.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetFactoryCompatibility.java @@ -1,4 +1,4 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoadException.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoadException.java index 4fa14bcb62..b83355e1c6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoadException.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoadException.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd; +import org.checkerframework.checker.nullness.qual.NonNull; + import net.sourceforge.pmd.annotation.InternalApi; /** @@ -16,14 +18,14 @@ public final class RuleSetLoadException extends RuntimeException { /** Constructors are internal. */ @InternalApi - public RuleSetLoadException(String message, Throwable cause) { - super(message, cause); + public RuleSetLoadException(RuleSetReferenceId rsetId, @NonNull Throwable cause) { + super("Cannot load ruleset " + rsetId + ": " + cause.getMessage(), cause); } /** Constructors are internal. */ @InternalApi - public RuleSetLoadException(String message) { - super(message); + public RuleSetLoadException(RuleSetReferenceId rsetId, String message) { + super("Cannot load ruleset " + rsetId + ": " + message); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoader.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoader.java index 1a75e5d3a5..c3a5373dae 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoader.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoader.java @@ -16,6 +16,7 @@ import java.util.Properties; import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -139,10 +140,14 @@ public final class RuleSetLoader { this.minimumPriority, this.warnDeprecated, this.compatFilter, - this.includeDeprecatedRuleReferences + this.includeDeprecatedRuleReferences, + this.reporter ); } + private @Nullable MessageReporter filteredReporter() { + return warnDeprecated ? reporter : null; + } /** * Parses and returns a ruleset from its location. The location may @@ -153,7 +158,7 @@ public final class RuleSetLoader { * @throws RuleSetLoadException If any error occurs (eg, invalid syntax, or resource not found) */ public RuleSet loadFromResource(String rulesetPath) { - return loadFromResource(new RuleSetReferenceId(rulesetPath)); + return loadFromResource(new RuleSetReferenceId(rulesetPath, null, filteredReporter())); } /** @@ -165,7 +170,7 @@ public final class RuleSetLoader { * @throws RuleSetLoadException If any error occurs (eg, invalid syntax) */ public RuleSet loadFromString(String filename, final String rulesetXmlContent) { - return loadFromResource(new RuleSetReferenceId(filename) { + return loadFromResource(new RuleSetReferenceId(filename, null, filteredReporter()) { @Override public InputStream getInputStream(ResourceLoader rl) { return new ByteArrayInputStream(rulesetXmlContent.getBytes(StandardCharsets.UTF_8)); @@ -201,6 +206,7 @@ public final class RuleSetLoader { public List loadRuleSetsWithoutException(List rulesetPaths) { List ruleSets = new ArrayList<>(rulesetPaths.size()); boolean anyRules = false; + boolean error = false; for (String path : rulesetPaths) { try { RuleSet ruleset = this.loadFromResource(path); @@ -208,16 +214,12 @@ public final class RuleSetLoader { printRulesInDebug(path, ruleset); ruleSets.add(ruleset); } catch (RuleSetLoadException e) { - if (e.getCause() != null) { - // eg RuleSetNotFoundException - reporter.errorEx("Cannot load ruleset {0}", new Object[] { path }, e.getCause()); - } else { - reporter.errorEx("Cannot load ruleset {0}", new Object[] { path }, e); - } + error = true; + reporter.error(e); } } - if (!anyRules) { - reporter.warn("No rules found. Maybe you misspelled a rule name? ({})", + if (!anyRules && !error) { + reporter.warn("No rules found. Maybe you misspelled a rule name? ({0})", StringUtils.join(rulesetPaths, ',')); } return ruleSets; @@ -231,7 +233,7 @@ public final class RuleSetLoader { } } if (ruleset.getRules().isEmpty()) { - reporter.warn("No rules found in ruleset {}", path); + reporter.warn("No rules found in ruleset {0}", path); } } @@ -254,8 +256,10 @@ public final class RuleSetLoader { RuleSet loadFromResource(RuleSetReferenceId ruleSetReferenceId) { try { return toFactory().createRuleSet(ruleSetReferenceId); + } catch (RuleSetLoadException e) { + throw e; } catch (Exception e) { - throw new RuleSetLoadException("Cannot parse " + ruleSetReferenceId, e); + throw new RuleSetLoadException(ruleSetReferenceId, e); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java index 32387d4e3e..7afa4f78b2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetReferenceId.java @@ -12,11 +12,14 @@ import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.util.ResourceLoader; +import net.sourceforge.pmd.util.log.MessageReporter; /** * This class is used to parse a RuleSet reference value. Most commonly used for @@ -59,16 +62,6 @@ import net.sourceforge.pmd.util.ResourceLoader; * all * * - * java-basic - * rulesets/java/basic.xml - * all - * - * - * 50 - * rulesets/releases/50.xml - * all - * - * * rulesets/java/basic.xml/EmptyCatchBlock * rulesets/java/basic.xml * EmptyCatchBlock @@ -86,12 +79,18 @@ import net.sourceforge.pmd.util.ResourceLoader; @Deprecated @InternalApi public class RuleSetReferenceId { + + // todo this class has issues... What is even an "external" ruleset? + // terminology and API should be clarified. + private final boolean external; private final String ruleSetFileName; private final boolean allRules; private final String ruleName; private final RuleSetReferenceId externalRuleSetReferenceId; + private final String originalRef; + /** * Construct a RuleSetReferenceId for the given single ID string. * @@ -102,7 +101,16 @@ public class RuleSetReferenceId { */ public RuleSetReferenceId(final String id) { - this(id, null); + this(id, null, null); + } + + private RuleSetReferenceId(final String ruleSetFileName, boolean external, String ruleName, RuleSetReferenceId externalRuleSetReferenceId) { + this.ruleSetFileName = Objects.requireNonNull(ruleSetFileName); + this.originalRef = ruleName == null ? ruleSetFileName : ruleSetFileName + "/" + ruleName; + this.allRules = ruleName == null; + this.external = external; + this.ruleName = ruleName; + this.externalRuleSetReferenceId = externalRuleSetReferenceId; } /** @@ -111,19 +119,36 @@ public class RuleSetReferenceId { * Rule. The external RuleSetReferenceId will be responsible for producing * the InputStream containing the Rule. * - * @param id - * The id string. - * @param externalRuleSetReferenceId - * A RuleSetReferenceId to associate with this new instance. - * @throws IllegalArgumentException - * If the ID contains a comma character. - * @throws IllegalArgumentException - * If external RuleSetReferenceId is not external. - * @throws IllegalArgumentException - * If the ID is not Rule reference when there is an external - * RuleSetReferenceId. + * @param id The id string. + * @param externalRuleSetReferenceId A RuleSetReferenceId to associate with this new instance. + * + * @throws IllegalArgumentException If the ID contains a comma character. + * @throws IllegalArgumentException If external RuleSetReferenceId is not external. + * @throws IllegalArgumentException If the ID is not Rule reference when there is an external + * RuleSetReferenceId. */ public RuleSetReferenceId(final String id, final RuleSetReferenceId externalRuleSetReferenceId) { + this(id, externalRuleSetReferenceId, null); + } + + /** + * Construct a RuleSetReferenceId for the given single ID string. If an + * external RuleSetReferenceId is given, the ID must refer to a non-external + * Rule. The external RuleSetReferenceId will be responsible for producing + * the InputStream containing the Rule. + * + * @param id The id string. + * @param externalRuleSetReferenceId A RuleSetReferenceId to associate with this new instance. + * + * @throws IllegalArgumentException If the ID contains a comma character. + * @throws IllegalArgumentException If external RuleSetReferenceId is not external. + * @throws IllegalArgumentException If the ID is not Rule reference when there is an external + * RuleSetReferenceId. + */ + RuleSetReferenceId(final String id, + final RuleSetReferenceId externalRuleSetReferenceId, + final @Nullable MessageReporter err) { + this.originalRef = id; if (externalRuleSetReferenceId != null && !externalRuleSetReferenceId.isExternal()) { throw new IllegalArgumentException("Cannot pair with non-external <" + externalRuleSetReferenceId + ">."); @@ -152,7 +177,7 @@ public class RuleSetReferenceId { } else { String tempRuleName = getRuleName(id); String tempRuleSetFileName = tempRuleName != null && id != null - ? id.substring(0, id.length() - tempRuleName.length() - 1) : id; + ? id.substring(0, id.length() - tempRuleName.length() - 1) : id; if (isValidUrl(tempRuleSetFileName)) { // remaining part is a xml ruleset file, so the tempRuleName is @@ -178,8 +203,16 @@ public class RuleSetReferenceId { allRules = tempRuleName == null; } else { // resolve the ruleset name - it's maybe a built in ruleset - String builtinRuleSet = resolveBuiltInRuleset(tempRuleSetFileName); + String expandedRuleset = resolveDeprecatedBuiltInRulesetShorthand(tempRuleSetFileName); + String builtinRuleSet = expandedRuleset == null ? tempRuleSetFileName : expandedRuleset; if (checkRulesetExists(builtinRuleSet)) { + if (expandedRuleset != null && err != null) { + err.warn( + "Ruleset reference ''{0}'' uses a deprecated form, use ''{1}'' instead", + tempRuleSetFileName, builtinRuleSet + ); + } + external = true; ruleSetFileName = builtinRuleSet; ruleName = tempRuleName; @@ -221,6 +254,19 @@ public class RuleSetReferenceId { this.externalRuleSetReferenceId = externalRuleSetReferenceId; } + @Nullable RuleSetReferenceId getParentRulesetIfThisIsARule() { + if (ruleName == null) { + return null; + } + return new RuleSetReferenceId( + ruleSetFileName, + external, + null, + + null + ); + } + /** * Tries to load the given ruleset. * @@ -250,25 +296,22 @@ public class RuleSetReferenceId { * the ruleset name * @return the full classpath to the ruleset */ - private String resolveBuiltInRuleset(final String name) { - String result = null; - if (name != null) { - // Likely a simple RuleSet name - int index = name.indexOf('-'); - if (index >= 0) { - // Standard short name - result = "rulesets/" + name.substring(0, index) + '/' + name.substring(index + 1) + ".xml"; - } else { - // A release RuleSet? - if (name.matches("[0-9]+.*")) { - result = "rulesets/releases/" + name + ".xml"; - } else { - // Appears to be a non-standard RuleSet name - result = name; - } - } + private String resolveDeprecatedBuiltInRulesetShorthand(final String name) { + if (name == null) { + return null; } - return result; + // Likely a simple RuleSet name + int index = name.indexOf('-'); + if (index > 0) { + // Standard short name + return "rulesets/" + name.substring(0, index) + '/' + name.substring(index + 1) + ".xml"; + } + // A release RuleSet? + if (name.matches("[0-9]+.*")) { + return "rulesets/releases/" + name + ".xml"; + } + // Appears to be a non-standard RuleSet name + return null; } /** @@ -327,19 +370,25 @@ public class RuleSetReferenceId { * Parse a String comma separated list of RuleSet reference IDs into a List * of RuleReferenceId instances. * - * @param referenceString - * A comma separated list of RuleSet reference IDs. + * @param referenceString A comma separated list of RuleSet reference IDs. + * * @return The corresponding List of RuleSetReferenceId instances. */ + // TODO deprecate and remove public static List parse(String referenceString) { + return parse(referenceString, null); + } + + static List parse(String referenceString, + MessageReporter err) { List references = new ArrayList<>(); if (referenceString != null && referenceString.trim().length() > 0) { if (referenceString.indexOf(',') == -1) { - references.add(new RuleSetReferenceId(referenceString)); + references.add(new RuleSetReferenceId(referenceString, null, err)); } else { for (String name : referenceString.split(",")) { - references.add(new RuleSetReferenceId(name.trim())); + references.add(new RuleSetReferenceId(name.trim(), null, err)); } } } @@ -350,7 +399,7 @@ public class RuleSetReferenceId { * Is this an external RuleSet reference? * * @return true if this is an external reference, - * false otherwise. + * false otherwise. */ public boolean isExternal() { return external; @@ -411,10 +460,9 @@ public class RuleSetReferenceId { } private FileNotFoundException notFoundException() { - return new FileNotFoundException("Can't find resource '" + ruleSetFileName + "' for rule '" + ruleName - + "'" + ". Make sure the resource is a valid file or URL and is on the classpath. " - + "Here's the current classpath: " - + System.getProperty("java.class.path")); + return new FileNotFoundException("Cannot resolve rule/ruleset reference '" + originalRef + + "'" + ". Make sure the resource is a valid file or URL and is on the CLASSPATH. " + + "Use --debug (or a fine log level) to see the current classpath."); } /** @@ -424,8 +472,11 @@ public class RuleSetReferenceId { * ruleSetFileName for all Rule external references, * ruleSetFileName/ruleName, for a single Rule external * references, or ruleName otherwise. + * + * @deprecated Do not rely on the format of this method, it may be changed in PMD 7. */ @Override + @Deprecated public String toString() { if (ruleSetFileName != null) { if (allRules) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java index 522e5e9741..2d0a2a08c7 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/RuleSetWriter.java @@ -21,7 +21,6 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.CDATASection; @@ -37,6 +36,7 @@ import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyDescriptorField; import net.sourceforge.pmd.properties.PropertyTypeId; +import net.sourceforge.pmd.util.IOUtil; /** * This class represents a way to serialize a RuleSet to an XML configuration @@ -62,7 +62,7 @@ public class RuleSetWriter { } public void close() { - IOUtils.closeQuietly(outputStream); + IOUtil.closeQuietly(outputStream); } public void write(RuleSet ruleSet) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java b/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java index df35e7571d..043666ae98 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ant/Formatter.java @@ -18,7 +18,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.commons.lang3.reflect.MethodUtils; @@ -33,6 +32,7 @@ import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.renderers.RendererFactory; import net.sourceforge.pmd.reporting.FileAnalysisListener; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; +import net.sourceforge.pmd.util.IOUtil; @InternalApi public class Formatter { @@ -65,10 +65,14 @@ public class Formatter { this.parameters.add(parameter); } + @Deprecated + @InternalApi public Renderer getRenderer() { return renderer; } + @Deprecated + @InternalApi public void start(String baseDir) { Properties properties = createProperties(); @@ -115,6 +119,8 @@ public class Formatter { } } + @Deprecated + @InternalApi public void end(Report errorReport) { try { renderer.renderFileReport(errorReport); @@ -129,6 +135,8 @@ public class Formatter { } } + @Deprecated + @InternalApi public boolean isNoOutputSupplied() { return toFile == null && !toConsole; } @@ -190,8 +198,8 @@ public class Formatter { isOnError = false; } finally { if (isOnError) { - IOUtils.closeQuietly(output); - IOUtils.closeQuietly(writer); + IOUtil.closeQuietly(output); + IOUtil.closeQuietly(writer); } } return writer; @@ -236,6 +244,7 @@ public class Formatter { return null; } + @Deprecated @InternalApi public GlobalAnalysisListener newListener(Project project) throws IOException { start(project.getBaseDir().toString()); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java b/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java index 282efe1a33..3b1dd1fc4f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/ant/internal/PMDTaskImpl.java @@ -230,7 +230,7 @@ public class PMDTaskImpl { Slf4jSimpleConfiguration.installJulBridge(); // need to reload the logger with the new configuration Logger log = LoggerFactory.getLogger(PMDTaskImpl.class); - log.atLevel(level).log("Logging is at {}", level); + log.info("Logging is at {}", level); try { doTask(); } finally { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cache/AbstractAnalysisCache.java b/pmd-core/src/main/java/net/sourceforge/pmd/cache/AbstractAnalysisCache.java index e640d44d58..74af13c400 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cache/AbstractAnalysisCache.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cache/AbstractAnalysisCache.java @@ -21,7 +21,6 @@ import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +35,7 @@ import net.sourceforge.pmd.benchmark.TimedOperationCategory; import net.sourceforge.pmd.cache.internal.ClasspathFingerprinter; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.reporting.FileAnalysisListener; +import net.sourceforge.pmd.util.IOUtil; /** * Abstract implementation of the analysis cache. Handles all operations, except for persistence. @@ -180,7 +180,7 @@ public abstract class AbstractAnalysisCache implements AnalysisCache { @Override public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException { - String extension = FilenameUtils.getExtension(file.toString()); + String extension = IOUtil.getFilenameExtension(file.toString()); if ("jar".equalsIgnoreCase(extension)) { fileVisitor.visitFile(file, attrs); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cache/internal/RawFileFingerprinter.java b/pmd-core/src/main/java/net/sourceforge/pmd/cache/internal/RawFileFingerprinter.java index be93115f1d..29e6457efe 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cache/internal/RawFileFingerprinter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cache/internal/RawFileFingerprinter.java @@ -13,10 +13,11 @@ import java.util.Set; import java.util.zip.CheckedInputStream; import java.util.zip.Checksum; -import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import net.sourceforge.pmd.util.IOUtil; + /** * Base fingerprinter for raw files. */ @@ -41,7 +42,7 @@ public class RawFileFingerprinter implements ClasspathEntryFingerprinter { public void fingerprint(URL entry, Checksum checksum) throws IOException { try (CheckedInputStream inputStream = new CheckedInputStream(entry.openStream(), checksum)) { // Just read it, the CheckedInputStream will update the checksum on it's own - while (IOUtils.skip(inputStream, Long.MAX_VALUE) == Long.MAX_VALUE) { + while (IOUtil.skipFully(inputStream, Long.MAX_VALUE) == Long.MAX_VALUE) { // just loop } } catch (final FileNotFoundException ignored) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java index df10f008f7..ecbadad53e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java @@ -9,6 +9,7 @@ import java.util.Arrays; import java.util.List; import java.util.Properties; +import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.PMD; @@ -32,20 +33,44 @@ import com.beust.jcommander.validators.PositiveInteger; @InternalApi public class PMDParameters { - @Parameter(names = { "--rulesets", "-rulesets", "-R" }, description = "Comma separated list of ruleset names to use.", - required = true) - private String rulesets; + @Parameter(names = { "--rulesets", "-rulesets", "-R" }, + description = "Path to a ruleset xml file. " + + "The path may reference a resource on the classpath of the application, be a local file system path, or a URL. " + + "The option can be repeated, and multiple arguments can be provided to a single occurrence of the option.", + required = true, + variableArity = true) + private List rulesets; - @Parameter(names = { "--uri", "-uri", "-u" }, description = "Database URI for sources.") + @Parameter(names = { "--uri", "-uri", "-u" }, + description = "Database URI for sources. " + + "One of --dir, --file-list or --uri must be provided. " + ) private String uri; - @Parameter(names = { "--dir", "-dir", "-d" }, description = "Root directory for sources.") - private String sourceDir; + @Parameter(names = { "--dir", "-dir", "-d" }, + description = "Path to a source file, or directory containing source files to analyze. " + // About the following line: + // In PMD 6, this is only the case for files found in directories. If you + // specify a file directly, and it is unknown, then the Java parser is used. + + "Note that a file is only effectively added if it matches a language known by PMD. " + + "Zip and Jar files are also supported, if they are specified directly " + + "(archive files found while exploring a directory are not recursively expanded). " + + "This option can be repeated, and multiple arguments can be provided to a single occurrence of the option. " + + "One of --dir, --file-list or --uri must be provided. ", + variableArity = true) + private List inputPaths = new ArrayList<>(); - @Parameter(names = { "--file-list", "-filelist" }, description = "Path to a file containing a list of files to analyze.") + @Parameter(names = { "--file-list", "-filelist" }, + description = + "Path to a file containing a list of files to analyze, one path per line. " + + "One of --dir, --file-list or --uri must be provided. " + ) private String fileListPath; - @Parameter(names = { "--ignore-list", "-ignorelist" }, description = "Path to a file containing a list of files to ignore.") + @Parameter(names = { "--ignore-list", "-ignorelist" }, + description = "Path to a file containing a list of files to exclude from the analysis, one path per line. " + + "This option can be combined with --dir and --file-list. " + ) private String ignoreListPath; @Parameter(names = { "--format", "-format", "-f" }, description = "Report format type.") @@ -107,12 +132,17 @@ public class PMDParameters { @Parameter(names = { "-language", "-l" }, description = "Specify a language PMD should use.") private String language = null; - @Parameter(names = { "--force-language", "-force-language" }, description = "Force a language to be used for all input files, irrespective of filenames.") + @Parameter(names = { "--force-language", "-force-language" }, + description = "Force a language to be used for all input files, irrespective of file names. " + + "When using this option, the automatic language selection by extension is disabled, and PMD " + + "tries to parse all input files with the given language's parser. " + + "Parsing errors are ignored." + ) private String forceLanguage = null; @Parameter(names = { "--aux-classpath", "-auxclasspath" }, description = "Specifies the classpath for libraries used by the source code. " - + "This is used by the type resolution. The platform specific path delimiter " + + "This is used to resolve types in Java source files. The platform specific path delimiter " + "(\":\" on Linux, \";\" on Windows) is used to separate the entries. " + "Alternatively, a single 'file:' URL to a text file containing path elements on consecutive lines " + "can be specified.") @@ -199,12 +229,8 @@ public class PMDParameters { * @throws IllegalArgumentException if the parameters are inconsistent or incomplete */ public PMDConfiguration toConfiguration() { - if (null == this.getSourceDir() && null == this.getUri() && null == this.getFileListPath()) { - throw new IllegalArgumentException( - "Please provide a parameter for source root directory (-dir or -d), database URI (-uri or -u), or file list path (-filelist)."); - } PMDConfiguration configuration = new PMDConfiguration(); - configuration.setInputPaths(this.getSourceDir()); + configuration.setInputPaths(this.getInputPaths()); configuration.setInputFilePath(this.getFileListPath()); configuration.setIgnoreFilePath(this.getIgnoreListPath()); configuration.setInputUri(this.getUri()); @@ -348,12 +374,22 @@ public class PMDParameters { return auxclasspath; } + @Deprecated public String getRulesets() { + return StringUtils.join(rulesets, ","); + } + + public List getRulesetRefs() { return rulesets; } + public List getInputPaths() { + return inputPaths; + } + + @Deprecated public String getSourceDir() { - return sourceDir; + return StringUtils.join(inputPaths, ","); } public String getFileListPath() { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PmdParametersParseResult.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PmdParametersParseResult.java index 0ffc8465d0..2f863ba4d9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PmdParametersParseResult.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PmdParametersParseResult.java @@ -105,13 +105,29 @@ public final class PmdParametersParseResult { jcommander.setProgramName("pmd"); try { - jcommander.parse(args); + parseAndValidate(jcommander, result, args); return new PmdParametersParseResult(result, filterDeprecatedOptions(args)); } catch (ParameterException e) { return new PmdParametersParseResult(e, filterDeprecatedOptions(args)); } } + private static void parseAndValidate(JCommander jcommander, PMDParameters result, String[] args) { + jcommander.parse(args); + if (result.isHelp() || result.isVersion()) { + return; + } + // jcommander has no special support for global parameter validation like this + // For consistency we report this with a ParameterException + if (result.getInputPaths().isEmpty() + && null == result.getUri() + && null == result.getFileListPath()) { + throw new ParameterException( + "Please provide a parameter for source root directory (--dir or -d), database URI (--uri or -u), or file list path (--file-list)."); + } + + } + private static Map filterDeprecatedOptions(String... args) { Map argSet = new LinkedHashMap<>(SUGGESTED_REPLACEMENT); argSet.keySet().retainAll(new HashSet<>(Arrays.asList(args))); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPD.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPD.java index bcc83fb7b5..68acf184d0 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPD.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPD.java @@ -4,9 +4,11 @@ package net.sourceforge.pmd.cpd; +import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.OutputStreamWriter; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; @@ -15,13 +17,14 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; -import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sourceforge.pmd.annotation.Experimental; +import net.sourceforge.pmd.cli.internal.CliMessages; import net.sourceforge.pmd.lang.ast.TokenMgrError; import net.sourceforge.pmd.util.FileFinder; +import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.database.DBMSMetadata; import net.sourceforge.pmd.util.database.DBURI; import net.sourceforge.pmd.util.database.SourceObject; @@ -93,8 +96,7 @@ public class CPD { current.add(signature); } - if (!FilenameUtils.equalsNormalizedOnSystem(file.getAbsoluteFile().getCanonicalPath(), - file.getAbsolutePath())) { + if (!IOUtil.equalsNormalizedPaths(file.getAbsoluteFile().getCanonicalPath(), file.getAbsolutePath())) { System.err.println("Skipping " + file + " since it appears to be a symlink"); return; } @@ -174,7 +176,75 @@ public class CPD { return new ArrayList<>(source.values()); } + /** + * Entry to invoke CPD as command line tool. Note that this will + * invoke {@link System#exit(int)}. + * + * @param args command line arguments + */ public static void main(String[] args) { - CPDCommandLineInterface.main(args); + StatusCode statusCode = runCpd(args); + CPDCommandLineInterface.setStatusCodeOrExit(statusCode.toInt()); + } + + /** + * Parses the command line and executes CPD. Returns the status code + * without exiting the VM. + * + * @param args command line arguments + * + * @return the status code + */ + public static StatusCode runCpd(String... args) { + CPDConfiguration arguments = new CPDConfiguration(); + CPD.StatusCode statusCode = CPDCommandLineInterface.parseArgs(arguments, args); + if (statusCode != null) { + return statusCode; + } + + CPD cpd = new CPD(arguments); + + try { + CPDCommandLineInterface.addSourceFilesToCPD(cpd, arguments); + + cpd.go(); + if (arguments.getCPDRenderer() == null) { + // legacy writer + System.out.println(arguments.getRenderer().render(cpd.getMatches())); + } else { + arguments.getCPDRenderer().render(cpd.getMatches(), new BufferedWriter(new OutputStreamWriter(System.out))); + } + if (cpd.getMatches().hasNext()) { + if (arguments.isFailOnViolation()) { + statusCode = StatusCode.DUPLICATE_CODE_FOUND; + } else { + statusCode = StatusCode.OK; + } + } else { + statusCode = StatusCode.OK; + } + } catch (IOException | RuntimeException e) { + LOG.debug(e.toString(), e); + LOG.error(CliMessages.errorDetectedMessage(1, CPDCommandLineInterface.PROGRAM_NAME)); + statusCode = StatusCode.ERROR; + } + return statusCode; + } + + public enum StatusCode { + OK(0), + ERROR(1), + DUPLICATE_CODE_FOUND(4); + + private final int code; + + StatusCode(int code) { + this.code = code; + } + + /** Returns the exit code as used in CLI. */ + public int toInt() { + return this.code; + } } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java index fce76c1ae6..919d02cb45 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDCommandLineInterface.java @@ -4,11 +4,9 @@ package net.sourceforge.pmd.cpd; -import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.OutputStreamWriter; import java.net.URISyntaxException; import java.nio.file.Path; import java.util.ArrayList; @@ -26,27 +24,45 @@ import org.slf4j.LoggerFactory; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.PMDVersion; +import net.sourceforge.pmd.annotation.InternalApi; import net.sourceforge.pmd.cli.internal.CliMessages; +import net.sourceforge.pmd.cpd.CPD.StatusCode; import net.sourceforge.pmd.util.FileUtil; import net.sourceforge.pmd.util.database.DBURI; import com.beust.jcommander.JCommander; import com.beust.jcommander.ParameterException; +/** + * @deprecated Internal API. Use {@link CPD#runCpd(String...)} or {@link CPD#main(String[])} + * in order to execute CPD. + */ +@Deprecated +@InternalApi public final class CPDCommandLineInterface { private static final Logger LOG = LoggerFactory.getLogger(CPDCommandLineInterface.class); - private static final int NO_ERRORS_STATUS = 0; - private static final int ERROR_STATUS = 1; - private static final int DUPLICATE_CODE_FOUND = 4; - + /** + * @deprecated This is used for testing, but support for it will be removed in PMD 7. + * Use {@link CPD#runCpd(String...)} to avoid exiting the VM. In PMD 7, + * {@link CPD#main(String[])} will call {@link System#exit(int)} always. + */ + @Deprecated public static final String NO_EXIT_AFTER_RUN = "net.sourceforge.pmd.cli.noExit"; + + /** + * @deprecated This is used for testing, but support for it will be removed in PMD 7. + * Use {@link CPD#runCpd(String...)} to avoid exiting the VM. In PMD 7, + * {@link CPD#main(String[])} will call {@link System#exit(int)} always. + */ + @Deprecated public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status"; - private static final String PROGRAM_NAME = "cpd"; + static final String PROGRAM_NAME = "cpd"; private CPDCommandLineInterface() { } + @Deprecated public static void setStatusCodeOrExit(int status) { if (isExitAfterRunSet()) { System.exit(status); @@ -67,8 +83,7 @@ public final class CPDCommandLineInterface { System.setProperty(STATUS_CODE_PROPERTY, Integer.toString(statusCode)); } - public static void main(String[] args) { - CPDConfiguration arguments = new CPDConfiguration(); + static StatusCode parseArgs(CPDConfiguration arguments, String... args) { JCommander jcommander = new JCommander(arguments); jcommander.setProgramName(PROGRAM_NAME); @@ -77,14 +92,12 @@ public final class CPDCommandLineInterface { if (arguments.isHelp()) { jcommander.usage(); System.out.println(buildUsageText()); - setStatusCodeOrExit(NO_ERRORS_STATUS); - return; + return StatusCode.OK; } } catch (ParameterException e) { System.err.println(e.getMessage()); System.err.println(CliMessages.runWithHelpFlagMessage()); - setStatusCodeOrExit(ERROR_STATUS); - return; + return StatusCode.ERROR; } Map deprecatedOptions = filterDeprecatedOptions(args); @@ -98,33 +111,16 @@ public final class CPDCommandLineInterface { // Pass extra parameters as System properties to allow language // implementation to retrieve their associate values... CPDConfiguration.setSystemProperties(arguments); - CPD cpd = new CPD(arguments); - try { - addSourceFilesToCPD(cpd, arguments); + return null; + } - cpd.go(); - if (arguments.getCPDRenderer() == null) { - // legacy writer - System.out.println(arguments.getRenderer().render(cpd.getMatches())); - } else { - arguments.getCPDRenderer().render(cpd.getMatches(), new BufferedWriter(new OutputStreamWriter(System.out))); - } - if (cpd.getMatches().hasNext()) { - if (arguments.isFailOnViolation()) { - setStatusCodeOrExit(DUPLICATE_CODE_FOUND); - } else { - setStatusCodeOrExit(NO_ERRORS_STATUS); - } - } else { - setStatusCodeOrExit(NO_ERRORS_STATUS); - } - } catch (IOException | RuntimeException e) { - e.printStackTrace(); - LOG.debug(e.toString(), e); - LOG.error(CliMessages.errorDetectedMessage(1, "CPD")); - setStatusCodeOrExit(ERROR_STATUS); - } + /** + * @deprecated Use {@link CPD#main(String[])} + */ + @Deprecated + public static void main(String[] args) { + setStatusCodeOrExit(CPD.runCpd(args).toInt()); } private static Map filterDeprecatedOptions(String... args) { @@ -207,6 +203,8 @@ public final class CPDCommandLineInterface { } } + @Deprecated + @InternalApi public static String buildUsageText() { String helpText = " For example on Windows:" + PMD.EOL; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java index 91f8979744..9524fef9c2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/GUI.java @@ -147,7 +147,16 @@ public class GUI implements CPDListener { @Override public boolean canIgnoreAnnotations() { - return "java".equals(terseName); + if (terseName == null) { + return false; + } + switch (terseName) { + case "cs": + case "java": + return true; + default: + return false; + } } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SourceCode.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SourceCode.java index db7c88c22e..20529bdea6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SourceCode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/SourceCode.java @@ -14,8 +14,7 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; -import org.apache.commons.io.ByteOrderMark; -import org.apache.commons.io.input.BOMInputStream; +import net.sourceforge.pmd.util.IOUtil; public class SourceCode { @@ -112,11 +111,10 @@ public class SourceCode { @Override public Reader getReader() throws Exception { - BOMInputStream inputStream = new BOMInputStream(Files.newInputStream(file.toPath()), ByteOrderMark.UTF_8, - ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_16LE); + IOUtil.BomAwareInputStream inputStream = new IOUtil.BomAwareInputStream(Files.newInputStream(file.toPath())); - if (inputStream.hasBOM()) { - encoding = inputStream.getBOMCharsetName(); + if (inputStream.hasBom()) { + encoding = inputStream.getBomCharsetName(); } return new InputStreamReader(inputStream, encoding); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/internal/DOMUtils.java b/pmd-core/src/main/java/net/sourceforge/pmd/internal/DOMUtils.java deleted file mode 100644 index b28059f4d5..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/internal/DOMUtils.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.internal; - -import org.w3c.dom.Node; - -import net.sourceforge.pmd.annotation.InternalApi; - -@InternalApi -public final class DOMUtils { - private DOMUtils() { - // utility - } - - /** - * Parse a String from a textually type node. - * - * @param node The node. - * - * @return The String. - */ - public static String parseTextNode(Node node) { - final int nodeCount = node.getChildNodes().getLength(); - if (nodeCount == 0) { - return ""; - } - - StringBuilder buffer = new StringBuilder(); - - for (int i = 0; i < nodeCount; i++) { - Node childNode = node.getChildNodes().item(i); - if (childNode.getNodeType() == Node.CDATA_SECTION_NODE || childNode.getNodeType() == Node.TEXT_NODE) { - buffer.append(childNode.getNodeValue()); - } - } - return buffer.toString(); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/internal/Slf4jSimpleConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/internal/Slf4jSimpleConfiguration.java index eaa1b37581..44254440ad 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/internal/Slf4jSimpleConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/internal/Slf4jSimpleConfiguration.java @@ -5,20 +5,17 @@ package net.sourceforge.pmd.internal; import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.slf4j.LoggerFactoryFriend; +import org.slf4j.PmdLoggerFactoryFriend; import org.slf4j.bridge.SLF4JBridgeHandler; import org.slf4j.event.Level; public final class Slf4jSimpleConfiguration { - private static final String SIMPLE_LOGGER_FACTORY_CLASS = "org.slf4j.simple.SimpleLoggerFactory"; - private static final String SIMPLE_LOGGER_CLASS = "org.slf4j.simple.SimpleLogger"; + private static final String SIMPLE_LOGGER_FACTORY_CLASS = "org.slf4j.impl.SimpleLoggerFactory"; + private static final String SIMPLE_LOGGER_CLASS = "org.slf4j.impl.SimpleLogger"; private Slf4jSimpleConfiguration() { } @@ -43,22 +40,39 @@ public final class Slf4jSimpleConfiguration { Method initMethod = simpleLoggerClass.getDeclaredMethod("init"); initMethod.setAccessible(true); initMethod.invoke(null); + + // Call SimpleLoggerFactory.reset() by reflection. + Method resetMethod = loggerFactoryClass.getDeclaredMethod("reset"); + resetMethod.setAccessible(true); + resetMethod.invoke(loggerFactory); } catch (ReflectiveOperationException ex) { System.err.println("Error while initializing logging: " + ex); } - LoggerFactoryFriend.reset(); + PmdLoggerFactoryFriend.reset(); } public static Level getDefaultLogLevel() { Logger rootLogger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); - List enabledLogLevels = Arrays.asList(Level.values()).stream() - .filter(rootLogger::isEnabledForLevel).collect(Collectors.toList()); - if (enabledLogLevels.isEmpty()) { + + // check the lowest log level first + if (rootLogger.isTraceEnabled()) { + return Level.TRACE; + } + if (rootLogger.isDebugEnabled()) { + return Level.DEBUG; + } + if (rootLogger.isInfoEnabled()) { return Level.INFO; } - // return the lowest (last) level - return enabledLogLevels.get(enabledLogLevels.size() - 1); + if (rootLogger.isWarnEnabled()) { + return Level.WARN; + } + if (rootLogger.isErrorEnabled()) { + return Level.ERROR; + } + + return Level.INFO; } public static void disableLogging(Class clazz) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/FileCollectionUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/FileCollectionUtil.java index 488c55f0c1..e7d8618ff5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/FileCollectionUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/FileCollectionUtil.java @@ -15,7 +15,6 @@ import java.util.Arrays; import java.util.List; import java.util.Set; -import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,6 +22,7 @@ import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.document.FileCollector; import net.sourceforge.pmd.util.FileUtil; +import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.database.DBMSMetadata; import net.sourceforge.pmd.util.database.DBURI; import net.sourceforge.pmd.util.database.SourceObject; @@ -118,7 +118,7 @@ public final class FileCollectionUtil { private static void addRoot(FileCollector collector, String rootLocation) throws IOException { Path path = Paths.get(rootLocation); if (!Files.exists(path)) { - collector.getReporter().error("No such file {}", path); + collector.getReporter().error("No such file {0}", path); return; } @@ -156,7 +156,7 @@ public final class FileCollectionUtil { LOG.trace("Adding database source object {}", falseFilePath); try (Reader sourceCode = dbmsMetadata.getSourceCode(sourceObject)) { - String source = IOUtils.toString(sourceCode); + String source = IOUtil.readToString(sourceCode); collector.addSourceFile(source, falseFilePath); } catch (SQLException ex) { collector.getReporter().warnEx("Cannot get SourceCode for {} - skipping ...", diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/PlainTextLanguage.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/PlainTextLanguage.java new file mode 100644 index 0000000000..d1b46ce078 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/PlainTextLanguage.java @@ -0,0 +1,89 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang; + +import net.sourceforge.pmd.annotation.Experimental; +import net.sourceforge.pmd.lang.ast.AstInfo; +import net.sourceforge.pmd.lang.ast.Parser; +import net.sourceforge.pmd.lang.ast.Parser.ParserTask; +import net.sourceforge.pmd.lang.ast.RootNode; +import net.sourceforge.pmd.lang.ast.impl.AbstractNode; +import net.sourceforge.pmd.lang.document.TextRegion; + +/** + * A dummy language implementation whose parser produces a single node. + * This is provided for cases where a non-null language is required, but + * the parser is not useful. This is useful eg to mock rules when no other + * language is on the classpath. This language is not exposed by {@link LanguageRegistry} + * and can only be used explicitly with {@link #getInstance()}. + * + * @author Clรฉment Fournier + * @since 6.48.0 + */ +@Experimental +public final class PlainTextLanguage extends BaseLanguageModule { + + private static final Language INSTANCE = new PlainTextLanguage(); + + static final String TERSE_NAME = "text"; + + private PlainTextLanguage() { + super("Plain text", "Plain text", TERSE_NAME, "plain-text-file-goo-extension"); + addVersion("default", new TextLvh(), true); + } + + /** + * Returns the singleton instance of this language. + */ + public static Language getInstance() { + return INSTANCE; + } + + private static final class TextLvh implements LanguageVersionHandler { + @Override + public Parser getParser() { + return PlainTextFile::new; + } + } + + /** + * The only node produced by the parser of {@link PlainTextLanguage}. + */ + public static class PlainTextFile extends AbstractNode implements RootNode { + + private final AstInfo astInfo; + + + PlainTextFile(ParserTask task) { + this.astInfo = new AstInfo<>(task, this); + } + + @Override + public TextRegion getTextRegion() { + return getTextDocument().getEntireRegion(); + } + + @Override + public String getXPathNodeName() { + return "TextFile"; + } + + @Override + public String getImage() { + return null; + } + + @Override + public String toString() { + return "Plain text file (" + getEndLine() + " lines)"; + } + + @Override + public AstInfo getAstInfo() { + return astInfo; + } + } + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java index ba41117640..4f5c5b484c 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporter.java @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.ast; import java.text.MessageFormat; -import org.slf4j.Logger; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.event.Level; import net.sourceforge.pmd.util.StringUtil; @@ -20,21 +20,11 @@ public interface SemanticErrorReporter { // TODO use resource bundle keys instead of string messages. - /** - * Report an informational message at the given location. - * - * @param location Location where the message should be reported - * @param message Message (rendered using a {@link MessageFormat}) - * @param formatArgs Format arguments - */ - default void info(Node location, String message, Object... formatArgs) { - // noop - } - - /** * Report a warning at the given location. Warnings do not abort - * the analysis. + * the analysis. They are usually recoverable errors. They are used + * to warn the user that something wrong is going on, which may cause + * subsequent errors or inconsistent behavior. * * @param location Location where the warning should be reported * @param message Message (rendered using a {@link MessageFormat}) @@ -44,9 +34,9 @@ public interface SemanticErrorReporter { /** - * Report an error at the given location. Errors abort subsequent analysis. - * The produced error can be thrown by the caller if it cannot be recovered - * from. + * Report an error at the given location. Errors abort subsequent analysis + * and cause a processing error to be put in the report. The produced error + * can be thrown by the caller if it cannot be recovered from. * * @param location Location where the error should be reported * @param message Message (rendered using a {@link MessageFormat}) @@ -56,14 +46,17 @@ public interface SemanticErrorReporter { /** - * Returns true if at least one error has been reported. + * If {@link #error(Node, String, Object...)} has been called, return + * a semantic exception instance with the correct message. If it has been + * called more than once, return the first exception, possibly with suppressed + * exceptions for subsequent calls to {@link #error(Node, String, Object...)}. */ - boolean hasError(); + @Nullable SemanticException getFirstError(); static SemanticErrorReporter noop() { return new SemanticErrorReporter() { - private boolean hasError = false; + private SemanticException exception; @Override public void warning(Node location, String message, Object... formatArgs) { @@ -72,13 +65,18 @@ public interface SemanticErrorReporter { @Override public SemanticException error(Node location, String message, Object... formatArgs) { - hasError = true; - return new SemanticException(MessageFormat.format(message, formatArgs)); + SemanticException ex = new SemanticException(MessageFormat.format(message, formatArgs)); + if (this.exception == null) { + this.exception = ex; + } else { + this.exception.addSuppressed(ex); + } + return ex; } @Override - public boolean hasError() { - return hasError; + public @Nullable SemanticException getFirstError() { + return exception; } }; } @@ -88,9 +86,10 @@ public interface SemanticErrorReporter { * Forwards to a {@link MessageReporter}, except trace and debug * messages which are reported on a logger. */ - static SemanticErrorReporter reportToLogger(MessageReporter reporter, Logger logger) { + static SemanticErrorReporter reportToLogger(MessageReporter reporter) { return new SemanticErrorReporter() { - private boolean hasError = false; + + private SemanticException exception = null; private String locPrefix(Node loc) { return "at " + loc.getReportLocation() @@ -103,19 +102,10 @@ public interface SemanticErrorReporter { private String logMessage(Level level, Node location, String message, Object[] args) { String fullMessage = makeMessage(location, message, args); - if (level.compareTo(Level.INFO) > 0) { - logger.atLevel(level).log(fullMessage); - } else { - reporter.log(level, StringUtil.quoteMessageFormat(fullMessage)); // already formatted - } + reporter.log(level, StringUtil.quoteMessageFormat(fullMessage)); // already formatted return fullMessage; } - @Override - public void info(Node location, String message, Object... formatArgs) { - logMessage(Level.INFO, location, message, formatArgs); - } - @Override public void warning(Node location, String message, Object... args) { logMessage(Level.WARN, location, message, args); @@ -123,14 +113,19 @@ public interface SemanticErrorReporter { @Override public SemanticException error(Node location, String message, Object... args) { - hasError = true; String fullMessage = logMessage(Level.ERROR, location, message, args); - return new SemanticException(fullMessage); + SemanticException ex = new SemanticException(fullMessage); + if (this.exception == null) { + this.exception = ex; + } else { + this.exception.addSuppressed(ex); + } + return ex; } @Override - public boolean hasError() { - return hasError; + public @Nullable SemanticException getFirstError() { + return exception; } }; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java index 5833547776..03c37ca247 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java @@ -88,6 +88,12 @@ public abstract class BaseAntlrInnerNode> extends BaseAnt return pmdWrapper != null ? pmdWrapper.asAntlrNode() : null; } + protected List getTokens(int kind) { + return children(BaseAntlrTerminalNode.class) + .filter(it -> it.getTokenKind() == kind) + .toList(BaseAntlrTerminalNode::asAntlrNode); + } + protected void copyFrom(BaseAntlrInnerNode other) { asAntlrNode().copyFrom(other.asAntlrNode()); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java index ed05da3dd2..a50fb5dd58 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/Chars.java @@ -363,15 +363,9 @@ public final class Chars implements CharSequence { public boolean contentEquals(CharSequence cs, boolean ignoreCase) { if (cs instanceof Chars) { Chars chars2 = (Chars) cs; - if (len != chars2.len) { - return false; - } - return str.regionMatches(ignoreCase, start, chars2.str, chars2.start, len); + return len == chars2.len && str.regionMatches(ignoreCase, start, chars2.str, chars2.start, len); } else { - if (length() != cs.length()) { - return false; - } - return str.regionMatches(ignoreCase, start, cs.toString(), 0, len); + return length() == cs.length() && str.regionMatches(ignoreCase, start, cs.toString(), 0, len); } } @@ -490,13 +484,7 @@ public final class Chars implements CharSequence { @Override public boolean equals(Object o) { - if (this == o) { - return true; - } - if (!(o instanceof Chars)) { - return false; - } - return contentEquals((Chars) o); + return this == o || o instanceof Chars && contentEquals((Chars) o); } @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java index 5e481ca5cd..cfe574c851 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/FileCollector.java @@ -139,7 +139,7 @@ public final class FileCollector implements AutoCloseable { */ public boolean addFile(Path file) { if (!Files.isRegularFile(file)) { - reporter.error("Not a regular file {}", file); + reporter.error("Not a regular file: {0}", file); return false; } LanguageVersion languageVersion = discoverLanguage(file.toString()); @@ -165,7 +165,7 @@ public final class FileCollector implements AutoCloseable { public boolean addFile(Path file, Language language) { AssertionUtil.requireParamNotNull("language", language); if (!Files.isRegularFile(file)) { - reporter.error("Not a regular file {}", file); + reporter.error("Not a regular file: {0}", file); return false; } LanguageVersion lv = discoverer.getDefaultLanguageVersion(language); @@ -244,7 +244,7 @@ public final class FileCollector implements AutoCloseable { LanguageVersion contextVersion = discoverer.getDefaultLanguageVersion(language); if (!fileVersion.equals(contextVersion)) { reporter.error( - "Cannot add file {}: version ''{}'' does not match ''{}''", + "Cannot add file {0}: version ''{1}'' does not match ''{2}''", textFile.getPathId(), fileVersion, contextVersion @@ -287,7 +287,7 @@ public final class FileCollector implements AutoCloseable { */ public boolean addDirectory(Path dir) throws IOException { if (!Files.isDirectory(dir)) { - reporter.error("Not a directory {}", dir); + reporter.error("Not a directory {0}", dir); return false; } Files.walkFileTree(dir, new SimpleFileVisitor() { @@ -315,7 +315,7 @@ public final class FileCollector implements AutoCloseable { } else if (Files.isRegularFile(file)) { return addFile(file); } else { - reporter.error("Not a file or directory {}", file); + reporter.error("Not a file or directory {0}", file); return false; } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java index 95e7086818..ab23dd525a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/NioTextFile.java @@ -74,7 +74,7 @@ class NioTextFile extends BaseCloseable implements TextFile { throw new ReadOnlyFileException(this); } try (BufferedWriter bw = Files.newBufferedWriter(path, charset)) { - if (content.getLineTerminator().equals(TextFileContent.NORMALIZED_LINE_TERM)) { + if (TextFileContent.NORMALIZED_LINE_TERM.equals(content.getLineTerminator())) { content.getNormalizedText().writeFully(bw); } else { for (Chars line : content.getNormalizedText().lines()) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java index 7cf4967830..6e4a26b1f1 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFile.java @@ -14,7 +14,6 @@ import java.io.Reader; import java.nio.charset.Charset; import java.nio.file.Path; -import org.apache.commons.io.IOUtils; import org.checkerframework.checker.nullness.qual.NonNull; import net.sourceforge.pmd.PMDConfiguration; @@ -25,6 +24,7 @@ import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.document.TextFileBuilder.ForCharSeq; import net.sourceforge.pmd.lang.document.TextFileBuilder.ForNio; import net.sourceforge.pmd.lang.document.TextFileBuilder.ForReader; +import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.datasource.DataSource; /** @@ -283,7 +283,7 @@ public interface TextFile extends Closeable { ensureOpen(); try (InputStream is = ds.getInputStream(); Reader reader = new BufferedReader(new InputStreamReader(is, config.getSourceEncoding()))) { - String contents = IOUtils.toString(reader); + String contents = IOUtil.readToString(reader); return TextFileContent.fromCharSeq(contents); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java index cb77db852c..0219448387 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/document/TextFileContent.java @@ -20,11 +20,11 @@ import java.util.zip.Adler32; import java.util.zip.CheckedInputStream; import java.util.zip.Checksum; -import org.apache.commons.io.ByteOrderMark; -import org.apache.commons.io.IOUtils; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; +import net.sourceforge.pmd.util.IOUtil; + /** * Contents of a text file. */ @@ -161,7 +161,7 @@ public final class TextFileContent { static @NonNull TextFileContent normalizeCharSeq(CharSequence text, String fallBackLineSep) { long checksum = getCheckSum(text); // the checksum is computed on the original file - if (text.length() > 0 && text.charAt(0) == ByteOrderMark.UTF_BOM) { + if (text.length() > 0 && text.charAt(0) == IOUtil.UTF_BOM) { text = text.subSequence(1, text.length()); // skip the BOM } Matcher matcher = NEWLINE_PATTERN.matcher(text); @@ -208,11 +208,11 @@ public final class TextFileContent { int bufOffset = 0; int nextCharToCopy = 0; int n = input.read(cbuf); - if (n > 0 && cbuf[0] == ByteOrderMark.UTF_BOM) { + if (n > 0 && cbuf[0] == IOUtil.UTF_BOM) { nextCharToCopy = 1; } - while (n != IOUtils.EOF) { + while (n != IOUtil.EOF) { if (updateChecksum) { // if we use a checked input stream we dont need to update the checksum manually // note that this checksum operates on non-normalized characters diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java index 1a83310247..847b96175a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/AstElementNode.java @@ -52,7 +52,7 @@ public final class AstElementNode extends BaseNodeInfo implements SiblingCountin BaseNodeInfo parent, Node wrappedNode, Configuration configuration) { - super(Type.ELEMENT, configuration.getNamePool(), wrappedNode.getXPathNodeName(), parent); + super(determineType(wrappedNode), configuration.getNamePool(), wrappedNode.getXPathNodeName(), parent); this.treeInfo = document; this.wrappedNode = wrappedNode; @@ -65,6 +65,19 @@ public final class AstElementNode extends BaseNodeInfo implements SiblingCountin } } + private static int determineType(Node node) { + // As of PMD 6.48.0, only the experimental HTML module uses this naming + // convention to identify non-element nodes. + // TODO PMD 7: maybe generalize this to other languages + String name = node.getXPathNodeName(); + if ("#text".equals(name)) { + return Type.TEXT; + } else if ("#comment".equals(name)) { + return Type.COMMENT; + } + return Type.ELEMENT; + } + public Map makeAttributes(Node wrappedNode) { Map atts = new HashMap<>(); Iterator it = wrappedNode.getXPathAttributesIterator(); @@ -179,6 +192,10 @@ public final class AstElementNode extends BaseNodeInfo implements SiblingCountin @Override public CharSequence getStringValueCS() { + if (getNodeKind() == Type.TEXT || getNodeKind() == Type.COMMENT) { + return getUnderlyingNode().getImage(); + } + // https://www.w3.org/TR/xpath-datamodel-31/#ElementNode // The string-value property of an Element Node must be the // concatenation of the string-values of all its Text Node @@ -187,6 +204,7 @@ public final class AstElementNode extends BaseNodeInfo implements SiblingCountin // Since we represent all our Nodes as elements, there are no // text nodes + // TODO: for some languages like html we have text nodes return ""; } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdRunnable.java b/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdRunnable.java index 4680f484f8..3ae36944bd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdRunnable.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/processor/PmdRunnable.java @@ -24,6 +24,7 @@ import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; +import net.sourceforge.pmd.lang.ast.SemanticException; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.reporting.FileAnalysisListener; @@ -124,7 +125,7 @@ abstract class PmdRunnable implements Runnable { TextDocument textDocument, RuleSets ruleSets) throws FileAnalysisException { - SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(configuration.getReporter(), LOG); + SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(configuration.getReporter()); ParserTask task = new ParserTask( textDocument, reporter, @@ -142,9 +143,10 @@ abstract class PmdRunnable implements Runnable { RootNode rootNode = parse(parser, task); - if (reporter.hasError()) { - reporter.info(rootNode, "Errors occurred in file, skipping rule analysis"); - return; + SemanticException semanticError = reporter.getFirstError(); + if (semanticError != null) { + // cause a processing error to be reported and rule analysis to be skipped + throw semanticError; } ruleSets.apply(rootNode, listener); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractRenderer.java index 0627a50834..dabd3a99ae 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractRenderer.java @@ -7,8 +7,6 @@ package net.sourceforge.pmd.renderers; import java.io.IOException; import java.io.Writer; -import org.apache.commons.io.IOUtils; - import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.annotation.Experimental; import net.sourceforge.pmd.cli.PMDParameters; @@ -103,7 +101,7 @@ public abstract class AbstractRenderer extends AbstractPropertySource implements } catch (IOException e) { throw new IllegalStateException(e); } finally { - IOUtils.closeQuietly(writer); + IOUtil.closeQuietly(writer); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/XMLRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/XMLRenderer.java index 92d26e1adb..566ed812b9 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/XMLRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/XMLRenderer.java @@ -22,7 +22,6 @@ import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; -import org.apache.commons.io.output.WriterOutputStream; import org.apache.commons.lang3.StringUtils; import net.sourceforge.pmd.PMDVersion; @@ -30,6 +29,7 @@ import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; +import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.StringUtil; /** @@ -258,7 +258,7 @@ public class XMLRenderer extends AbstractIncrementingRenderer { public void setWriter(final Writer writer) { String encoding = getProperty(ENCODING); // for backwards compatibility, create a OutputStream that writes to the writer. - this.stream = new WriterOutputStream(writer, encoding); + this.stream = IOUtil.fromWriter(writer, encoding); XMLOutputFactory outputFactory = XMLOutputFactory.newFactory(); try { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/rules/RuleBuilder.java b/pmd-core/src/main/java/net/sourceforge/pmd/rules/RuleBuilder.java deleted file mode 100644 index beabbc6080..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/rules/RuleBuilder.java +++ /dev/null @@ -1,212 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.rules; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; -import org.w3c.dom.Element; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RulePriority; -import net.sourceforge.pmd.RuleSetReference; -import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.lang.Language; -import net.sourceforge.pmd.lang.LanguageRegistry; -import net.sourceforge.pmd.lang.LanguageVersion; -import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.util.ResourceLoader; - - -/** - * Builds a rule, validating its parameters throughout. The builder can define property descriptors, but not override - * them. For that, use {@link RuleFactory#decorateRule(Rule, RuleSetReference, Element)}. - * - * @author Clรฉment Fournier - * @since 6.0.0 - */ -@InternalApi -@Deprecated -public class RuleBuilder { - - private List> definedProperties = new ArrayList<>(); - private String name; - private ResourceLoader resourceLoader; - private String clazz; - private Language language; - private String minimumVersion; - private String maximumVersion; - private String since; - private String message; - private String externalInfoUrl; - private String description; - private List examples = new ArrayList<>(1); - private RulePriority priority; - private boolean isDeprecated; - - /** - * @deprecated Use {@link #RuleBuilder(String, ResourceLoader, String, String)} with the - * proper {@link ResourceLoader} instead. The resource loader is used to load the - * rule implementation class from the class path. - */ - @Deprecated - public RuleBuilder(String name, String clazz, String language) { - this(name, new ResourceLoader(), clazz, language); - } - - public RuleBuilder(String name, ResourceLoader resourceLoader, String clazz, String language) { - this.name = name; - this.resourceLoader = resourceLoader; - language(language); - className(clazz); - } - - private void language(String languageName) { - if (StringUtils.isBlank(languageName)) { - // Some languages don't need the attribute because the rule's - // constructor calls setLanguage, see e.g. AbstractJavaRule - return; - } - - Language lang = LanguageRegistry.findLanguageByTerseName(languageName); - if (lang == null) { - throw new IllegalArgumentException( - "Unknown Language '" + languageName + "' for rule " + name + ", supported Languages are " - + LanguageRegistry.getLanguages().stream().map(Language::getTerseName).collect(Collectors.joining(", ")) - ); - } - language = lang; - } - - private void className(String className) { - if (StringUtils.isBlank(className)) { - throw new IllegalArgumentException("The 'class' field of rule can't be null, nor empty."); - } - - this.clazz = className; - } - - public void minimumLanguageVersion(String minimum) { - minimumVersion = minimum; - } - - public void maximumLanguageVersion(String maximum) { - maximumVersion = maximum; - } - - private void checkLanguageVersionsAreOrdered(Rule rule) { - if (rule.getMinimumLanguageVersion() != null && rule.getMaximumLanguageVersion() != null - && rule.getMinimumLanguageVersion().compareTo(rule.getMaximumLanguageVersion()) > 0) { - throw new IllegalArgumentException( - "The minimum Language Version '" + rule.getMinimumLanguageVersion().getTerseName() - + "' must be prior to the maximum Language Version '" - + rule.getMaximumLanguageVersion().getTerseName() + "' for Rule '" + name - + "'; perhaps swap them around?"); - } - } - - public void since(String sinceStr) { - if (StringUtils.isNotBlank(sinceStr)) { - since = sinceStr; - } - } - - public void externalInfoUrl(String externalInfoUrl) { - this.externalInfoUrl = externalInfoUrl; - } - - public void message(String message) { - this.message = message; - } - - public void defineProperty(PropertyDescriptor descriptor) { - definedProperties.add(descriptor); - } - - - public void setDeprecated(boolean deprecated) { - isDeprecated = deprecated; - } - - - public void description(String description) { - this.description = description; - } - - - public void addExample(String example) { - examples.add(example); - } - - - public void priority(int priorityString) { - this.priority = RulePriority.valueOf(priorityString); - } - - // Must be loaded after rule construction to know the Language - private void loadLanguageMinMaxVersions(Rule rule) { - - if (minimumVersion != null) { - LanguageVersion minimumLanguageVersion = rule.getLanguage().getVersion(minimumVersion); - if (minimumLanguageVersion == null) { - throwUnknownLanguageVersionException("minimum", minimumVersion, rule.getLanguage()); - } else { - rule.setMinimumLanguageVersion(minimumLanguageVersion); - } - } - - if (maximumVersion != null) { - LanguageVersion maximumLanguageVersion = rule.getLanguage().getVersion(maximumVersion); - if (maximumLanguageVersion == null) { - throwUnknownLanguageVersionException("maximum", maximumVersion, rule.getLanguage()); - } else { - rule.setMaximumLanguageVersion(maximumLanguageVersion); - } - } - - checkLanguageVersionsAreOrdered(rule); - } - - private void throwUnknownLanguageVersionException(String minOrMax, String unknownVersion, Language lang) { - throw new IllegalArgumentException("Unknown " + minOrMax + " Language Version '" + unknownVersion - + "' for Language '" + lang.getTerseName() - + "' for Rule " + name - + "; supported Language Versions are: " - + lang.getVersions().stream().map(LanguageVersion::getVersion).collect(Collectors.joining(", "))); - } - - public Rule build() throws ClassNotFoundException, IllegalAccessException, InstantiationException { - Rule rule = resourceLoader.loadRuleFromClassPath(clazz); - - rule.setName(name); - rule.setRuleClass(clazz); - - if (rule.getLanguage() == null) { - rule.setLanguage(language); - } - - loadLanguageMinMaxVersions(rule); - rule.setSince(since); - rule.setMessage(message); - rule.setExternalInfoUrl(externalInfoUrl); - rule.setDeprecated(isDeprecated); - rule.setDescription(description); - rule.setPriority(priority == null ? RulePriority.LOW : priority); - - for (String example : examples) { - rule.addExample(example); - } - - for (PropertyDescriptor descriptor : definedProperties) { - if (!rule.getPropertyDescriptors().contains(descriptor)) { - rule.definePropertyDescriptor(descriptor); - } - } - - return rule; - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/rules/RuleFactory.java b/pmd-core/src/main/java/net/sourceforge/pmd/rules/RuleFactory.java index 28fcfb1005..a67cdfe4b8 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/rules/RuleFactory.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/rules/RuleFactory.java @@ -1,39 +1,54 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.rules; -import static net.sourceforge.pmd.properties.PropertyDescriptorField.DEFAULT_VALUE; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.MAXIMUM_LANGUAGE_VERSION; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.MINIMUM_LANGUAGE_VERSION; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.NAME; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.PROPERTY_TYPE; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.PROPERTY_VALUE; +import static net.sourceforge.pmd.util.internal.xml.XmlErrorMessages.ERR__INVALID_LANG_VERSION; +import static net.sourceforge.pmd.util.internal.xml.XmlErrorMessages.ERR__INVALID_LANG_VERSION_NO_NAMED_VERSION; +import static net.sourceforge.pmd.util.internal.xml.XmlErrorMessages.ERR__PROPERTY_DOES_NOT_EXIST; +import static net.sourceforge.pmd.util.internal.xml.XmlErrorMessages.IGNORED__DUPLICATE_PROPERTY_SETTER; -import java.util.AbstractMap.SimpleEntry; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.List; +import java.util.HashSet; import java.util.Map; -import java.util.Map.Entry; +import java.util.Set; +import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.w3c.dom.Attr; import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; -import org.w3c.dom.NodeList; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.RulePriority; import net.sourceforge.pmd.RuleSetReference; import net.sourceforge.pmd.annotation.InternalApi; -import net.sourceforge.pmd.internal.DOMUtils; +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.rule.RuleReference; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyDescriptorField; import net.sourceforge.pmd.properties.PropertyTypeId; +import net.sourceforge.pmd.properties.ValueParser; import net.sourceforge.pmd.properties.builders.PropertyDescriptorExternalBuilder; import net.sourceforge.pmd.util.ResourceLoader; +import net.sourceforge.pmd.util.StringUtil; +import net.sourceforge.pmd.util.internal.xml.PmdXmlReporter; +import net.sourceforge.pmd.util.internal.xml.SchemaConstant; +import net.sourceforge.pmd.util.internal.xml.SchemaConstants; +import net.sourceforge.pmd.util.internal.xml.XmlErrorMessages; +import net.sourceforge.pmd.util.internal.xml.XmlUtil; + +import com.github.oowekyala.ooxml.DomUtils; +import com.github.oowekyala.ooxml.messages.XmlException; /** @@ -46,34 +61,8 @@ import net.sourceforge.pmd.util.ResourceLoader; @Deprecated public class RuleFactory { - private static final Logger LOG = LoggerFactory.getLogger(RuleFactory.class); - - private static final String DEPRECATED = "deprecated"; - private static final String NAME = "name"; - private static final String MESSAGE = "message"; - private static final String EXTERNAL_INFO_URL = "externalInfoUrl"; - private static final String MINIMUM_LANGUAGE_VERSION = "minimumLanguageVersion"; - private static final String MAXIMUM_LANGUAGE_VERSION = "maximumLanguageVersion"; - private static final String SINCE = "since"; - private static final String PROPERTIES = "properties"; - private static final String PRIORITY = "priority"; - private static final String EXAMPLE = "example"; - private static final String DESCRIPTION = "description"; - private static final String PROPERTY = "property"; - private static final String CLASS = "class"; - - private static final List REQUIRED_ATTRIBUTES = Collections.unmodifiableList(Arrays.asList(NAME, CLASS)); - private final ResourceLoader resourceLoader; - /** - * @deprecated Use {@link #RuleFactory(ResourceLoader)} instead. - */ - @Deprecated - public RuleFactory() { - this(new ResourceLoader()); - } - /** * @param resourceLoader The resource loader to load the rule from jar */ @@ -87,49 +76,49 @@ public class RuleFactory { *

Declaring a property in the overriding element throws an exception (the property must exist in the referenced * rule). * - * @param referencedRule Referenced rule + * @param referencedRule Referenced rule * @param ruleSetReference the ruleset, where the referenced rule is defined - * @param ruleElement Element overriding some metadata about the rule + * @param ruleElement Element overriding some metadata about the rule + * @param err Error reporter * * @return A rule reference to the referenced rule */ - public RuleReference decorateRule(Rule referencedRule, RuleSetReference ruleSetReference, Element ruleElement) { + public RuleReference decorateRule(Rule referencedRule, RuleSetReference ruleSetReference, Element ruleElement, PmdXmlReporter err) { RuleReference ruleReference = new RuleReference(referencedRule, ruleSetReference); - if (ruleElement.hasAttribute(DEPRECATED)) { - ruleReference.setDeprecated(Boolean.parseBoolean(ruleElement.getAttribute(DEPRECATED))); - } - if (ruleElement.hasAttribute(NAME)) { - ruleReference.setName(ruleElement.getAttribute(NAME)); - } - if (ruleElement.hasAttribute(MESSAGE)) { - ruleReference.setMessage(ruleElement.getAttribute(MESSAGE)); - } - if (ruleElement.hasAttribute(EXTERNAL_INFO_URL)) { - ruleReference.setExternalInfoUrl(ruleElement.getAttribute(EXTERNAL_INFO_URL)); - } + SchemaConstants.DEPRECATED.getAttributeOpt(ruleElement).map(Boolean::parseBoolean).ifPresent(ruleReference::setDeprecated); + SchemaConstants.NAME.getAttributeOpt(ruleElement).ifPresent(ruleReference::setName); + SchemaConstants.MESSAGE.getAttributeOpt(ruleElement).ifPresent(ruleReference::setMessage); + SchemaConstants.EXTERNAL_INFO_URL.getAttributeOpt(ruleElement).ifPresent(ruleReference::setExternalInfoUrl); - for (int i = 0; i < ruleElement.getChildNodes().getLength(); i++) { - Node node = ruleElement.getChildNodes().item(i); - if (node.getNodeType() == Node.ELEMENT_NODE) { - switch (node.getNodeName()) { - case DESCRIPTION: - ruleReference.setDescription(DOMUtils.parseTextNode(node)); - break; - case EXAMPLE: - ruleReference.addExample(DOMUtils.parseTextNode(node)); - break; - case PRIORITY: - ruleReference.setPriority(RulePriority.valueOf(Integer.parseInt(DOMUtils.parseTextNode(node)))); - break; - case PROPERTIES: - setPropertyValues(ruleReference, (Element) node); - break; - default: - throw new IllegalArgumentException("Unexpected element <" + node.getNodeName() - + "> encountered as child of element for Rule " - + ruleReference.getName()); + for (Element node : DomUtils.children(ruleElement)) { + + if (SchemaConstants.DESCRIPTION.matchesElt(node)) { + + ruleReference.setDescription(XmlUtil.parseTextNode(node)); + + } else if (SchemaConstants.EXAMPLE.matchesElt(node)) { + + ruleReference.addExample(XmlUtil.parseTextNode(node)); + + } else if (SchemaConstants.PRIORITY.matchesElt(node)) { + + RulePriority priority = parsePriority(err, node); + if (priority == null) { + priority = RulePriority.MEDIUM; } + ruleReference.setPriority(priority); + + } else if (SchemaConstants.PROPERTIES.matchesElt(node)) { + + setPropertyValues(ruleReference, node, err); + + } else { + err.at(node).error( + XmlErrorMessages.ERR__UNEXPECTED_ELEMENT_IN, + node.getTagName(), + "rule " + ruleReference.getName() + ); } } @@ -145,162 +134,191 @@ public class RuleFactory { * @param ruleElement The rule element to parse * * @return A new instance of the rule described by this element + * * @throws IllegalArgumentException if the element doesn't describe a valid rule. */ - public Rule buildRule(Element ruleElement) { - checkRequiredAttributesArePresent(ruleElement); - - String name = ruleElement.getAttribute(NAME); - - RuleBuilder builder = new RuleBuilder(name, - resourceLoader, - ruleElement.getAttribute(CLASS), - ruleElement.getAttribute("language")); - - if (ruleElement.hasAttribute(MINIMUM_LANGUAGE_VERSION)) { - builder.minimumLanguageVersion(ruleElement.getAttribute(MINIMUM_LANGUAGE_VERSION)); - } - - if (ruleElement.hasAttribute(MAXIMUM_LANGUAGE_VERSION)) { - builder.maximumLanguageVersion(ruleElement.getAttribute(MAXIMUM_LANGUAGE_VERSION)); - } - - if (ruleElement.hasAttribute(SINCE)) { - builder.since(ruleElement.getAttribute(SINCE)); - } - - builder.message(ruleElement.getAttribute(MESSAGE)); - builder.externalInfoUrl(ruleElement.getAttribute(EXTERNAL_INFO_URL)); - builder.setDeprecated(hasAttributeSetTrue(ruleElement, DEPRECATED)); - - Element propertiesElement = null; - - final NodeList nodeList = ruleElement.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - Node node = nodeList.item(i); - if (node.getNodeType() != Node.ELEMENT_NODE) { - continue; - } - - switch (node.getNodeName()) { - case DESCRIPTION: - builder.description(DOMUtils.parseTextNode(node)); - break; - case EXAMPLE: - builder.addExample(DOMUtils.parseTextNode(node)); - break; - case PRIORITY: - builder.priority(Integer.parseInt(DOMUtils.parseTextNode(node).trim())); - break; - case PROPERTIES: - parsePropertiesForDefinitions(builder, node); - propertiesElement = (Element) node; - break; - default: - throw new IllegalArgumentException("Unexpected element <" + node.getNodeName() - + "> encountered as child of element for Rule " - + name); - } - } + public Rule buildRule(Element ruleElement, PmdXmlReporter err) { Rule rule; try { - rule = builder.build(); + String clazz = SchemaConstants.CLASS.getNonBlankAttribute(ruleElement, err); + rule = resourceLoader.loadRuleFromClassPath(clazz); } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { - LOG.error("Error instantiating a rule", e); - throw new RuntimeException(e); + Attr node = SchemaConstants.CLASS.getAttributeNode(ruleElement); + throw err.at(node).error(e); } - if (propertiesElement != null) { - setPropertyValues(rule, propertiesElement); + rule.setName(NAME.getNonBlankAttribute(ruleElement, err)); + if (rule.getLanguage() == null) { + setLanguage(ruleElement, err, rule); + } + Language language = rule.getLanguage(); + assert language != null; + + rule.setMinimumLanguageVersion(getLanguageVersion(ruleElement, err, language, MINIMUM_LANGUAGE_VERSION)); + rule.setMaximumLanguageVersion(getLanguageVersion(ruleElement, err, language, MAXIMUM_LANGUAGE_VERSION)); + checkVersionsAreOrdered(ruleElement, err, rule); + + SchemaConstants.SINCE.getAttributeOpt(ruleElement).ifPresent(rule::setSince); + SchemaConstants.MESSAGE.getAttributeOpt(ruleElement).ifPresent(rule::setMessage); + SchemaConstants.EXTERNAL_INFO_URL.getAttributeOpt(ruleElement).ifPresent(rule::setExternalInfoUrl); + rule.setDeprecated(SchemaConstants.DEPRECATED.getAsBooleanAttr(ruleElement, false)); + + for (Element node : DomUtils.children(ruleElement)) { + if (SchemaConstants.DESCRIPTION.matchesElt(node)) { + + rule.setDescription(XmlUtil.parseTextNode(node)); + + } else if (SchemaConstants.EXAMPLE.matchesElt(node)) { + + rule.addExample(XmlUtil.parseTextNode(node)); + + } else if (SchemaConstants.PRIORITY.matchesElt(node)) { + + RulePriority rp = parsePriority(err, node); + if (rp == null) { + rp = RulePriority.MEDIUM; + } + rule.setPriority(rp); + + } else if (SchemaConstants.PROPERTIES.matchesElt(node)) { + + parsePropertiesForDefinitions(rule, node, err); + setPropertyValues(rule, node, err); + + } else { + throw err.at(node).error( + XmlErrorMessages.ERR__UNEXPECTED_ELEMENT_IN, + "rule " + NAME.getAttributeOrNull(ruleElement)); + } } return rule; } - private void checkRequiredAttributesArePresent(Element ruleElement) { - // add an attribute name here to make it required - - for (String att : REQUIRED_ATTRIBUTES) { - if (!ruleElement.hasAttribute(att)) { - throw new IllegalArgumentException("Missing '" + att + "' attribute"); - } + private void checkVersionsAreOrdered(Element ruleElement, PmdXmlReporter err, Rule rule) { + if (rule.getMinimumLanguageVersion() != null && rule.getMaximumLanguageVersion() != null + && rule.getMinimumLanguageVersion().compareTo(rule.getMaximumLanguageVersion()) > 0) { + throw err.at(MINIMUM_LANGUAGE_VERSION.getAttributeNode(ruleElement)) + .error( + XmlErrorMessages.ERR__INVALID_VERSION_RANGE, + rule.getMinimumLanguageVersion(), + rule.getMaximumLanguageVersion() + ); } } + /** - * Parses a properties element looking only for the values of the properties defined or overridden. - * - * @param propertiesNode Node to parse - * - * @return A map of property names to their value + * Parse a priority. If invalid, report it and return null. */ - private Map getPropertyValuesFrom(Element propertiesNode) { - Map overriddenProperties = new HashMap<>(); - - for (int i = 0; i < propertiesNode.getChildNodes().getLength(); i++) { - Node node = propertiesNode.getChildNodes().item(i); - if (node.getNodeType() == Node.ELEMENT_NODE && PROPERTY.equals(node.getNodeName())) { - Entry overridden = getPropertyValue((Element) node); - overriddenProperties.put(overridden.getKey(), overridden.getValue()); - } + public static @Nullable RulePriority parsePriority(PmdXmlReporter err, Element node) { + String text = XmlUtil.parseTextNode(node); + RulePriority rp = RulePriority.valueOfNullable(text); + if (rp == null) { + err.at(node).error(XmlErrorMessages.ERR__INVALID_PRIORITY_VALUE, text); + return null; } + return rp; + } - return overriddenProperties; + private LanguageVersion getLanguageVersion(Element ruleElement, PmdXmlReporter err, Language language, SchemaConstant attrName) { + if (attrName.hasAttribute(ruleElement)) { + String attrValue = attrName.getAttributeOrThrow(ruleElement, err); + LanguageVersion version = language.getVersion(attrValue); + if (version == null) { + String supportedVersions = language.getVersions().stream() + .map(LanguageVersion::getVersion) + .filter(it -> !it.isEmpty()) + .map(StringUtil::inSingleQuotes) + .collect(Collectors.joining(", ")); + String message = supportedVersions.isEmpty() + ? ERR__INVALID_LANG_VERSION_NO_NAMED_VERSION + : ERR__INVALID_LANG_VERSION; + throw err.at(attrName.getAttributeNode(ruleElement)) + .error( + message, + attrValue, + language.getTerseName(), + supportedVersions + ); + } + return version; + } + return null; + } + + private void setLanguage(Element ruleElement, PmdXmlReporter err, Rule rule) { + String langId = SchemaConstants.LANGUAGE.getNonBlankAttribute(ruleElement, err); + Language lang = LanguageRegistry.findLanguageByTerseName(langId); + if (lang == null) { + Attr node = SchemaConstants.LANGUAGE.getAttributeNode(ruleElement); + throw err.at(node) + .error("Invalid language ''{0}'', possible values are {1}", langId, supportedLanguages()); + } + rule.setLanguage(lang); + } + + private @NonNull String supportedLanguages() { + return LanguageRegistry.getLanguages().stream().map(Language::getTerseName).map(StringUtil::inSingleQuotes).collect(Collectors.joining(", ")); } /** * Parses the properties node and adds property definitions to the builder. Doesn't care for value overriding, that * will be handled after the rule instantiation. * - * @param builder Rule builder + * @param rule Rule builder * @param propertiesNode Node to parse + * @param err Error reporter */ - private void parsePropertiesForDefinitions(RuleBuilder builder, Node propertiesNode) { - for (int i = 0; i < propertiesNode.getChildNodes().getLength(); i++) { - Node node = propertiesNode.getChildNodes().item(i); - if (node.getNodeType() == Node.ELEMENT_NODE && PROPERTY.equals(node.getNodeName()) - && isPropertyDefinition((Element) node)) { - PropertyDescriptor descriptor = parsePropertyDefinition((Element) node); - builder.defineProperty(descriptor); + private void parsePropertiesForDefinitions(Rule rule, Element propertiesNode, @NonNull PmdXmlReporter err) { + for (Element child : SchemaConstants.PROPERTY_ELT.getElementChildrenNamedReportOthers(propertiesNode, err)) { + if (isPropertyDefinition(child)) { + rule.definePropertyDescriptor(parsePropertyDefinition(child, err)); } } } - /** - * Gets a mapping of property name to its value from the given property element. - * - * @param propertyElement Property element - * - * @return An entry of property name to its value - */ - private Entry getPropertyValue(Element propertyElement) { - String name = propertyElement.getAttribute(PropertyDescriptorField.NAME.attributeName()); - return new SimpleEntry<>(name, valueFrom(propertyElement)); - } - /** * Overrides the rule's properties with the values defined in the element. * * @param rule The rule * @param propertiesElt The {@literal } element */ - private void setPropertyValues(Rule rule, Element propertiesElt) { - Map overridden = getPropertyValuesFrom(propertiesElt); + private void setPropertyValues(Rule rule, Element propertiesElt, PmdXmlReporter err) { + Set overridden = new HashSet<>(); - for (Entry e : overridden.entrySet()) { - PropertyDescriptor descriptor = rule.getPropertyDescriptor(e.getKey()); - if (descriptor == null) { - throw new IllegalArgumentException( - "Cannot set non-existent property '" + e.getKey() + "' on Rule " + rule.getName()); + XmlException exception = null; + for (Element element : SchemaConstants.PROPERTY_ELT.getElementChildrenNamedReportOthers(propertiesElt, err)) { + String name = SchemaConstants.NAME.getAttributeOrThrow(element, err); + if (!overridden.add(name)) { + err.at(element).warn(IGNORED__DUPLICATE_PROPERTY_SETTER, name); + continue; } - setRulePropertyCapture(rule, descriptor, e.getValue()); + PropertyDescriptor desc = rule.getPropertyDescriptor(name); + if (desc == null) { + // todo just warn and ignore + throw err.at(element).error(ERR__PROPERTY_DOES_NOT_EXIST, name, rule.getName()); + } + try { + setRulePropertyCapture(rule, desc, element, err); + } catch (XmlException e) { + if (exception == null) { + exception = e; + } else { + exception.addSuppressed(e); + } + } + } + if (exception != null) { + throw exception; } } - private void setRulePropertyCapture(Rule rule, PropertyDescriptor descriptor, String value) { - rule.setProperty(descriptor, descriptor.valueFrom(value)); + private void setRulePropertyCapture(Rule rule, PropertyDescriptor descriptor, Element propertyElt, PmdXmlReporter err) { + T value = parsePropertyValue(propertyElt, err, descriptor::valueFrom); + rule.setProperty(descriptor, value); } /** @@ -311,66 +329,90 @@ public class RuleFactory { * @return True if this element defines a new property, false if this is just stating a value */ private static boolean isPropertyDefinition(Element node) { - return node.hasAttribute(PropertyDescriptorField.TYPE.attributeName()); + return SchemaConstants.PROPERTY_TYPE.hasAttribute(node); } /** * Parses a property definition node and returns the defined property descriptor. * * @param propertyElement Property node to parse + * @param err Error reporter * * @return The property descriptor */ - private static PropertyDescriptor parsePropertyDefinition(Element propertyElement) { - String typeId = propertyElement.getAttribute(PropertyDescriptorField.TYPE.attributeName()); + private static PropertyDescriptor parsePropertyDefinition(Element propertyElement, PmdXmlReporter err) { + + String typeId = SchemaConstants.PROPERTY_TYPE.getAttributeOrThrow(propertyElement, err); PropertyDescriptorExternalBuilder pdFactory = PropertyTypeId.factoryFor(typeId); if (pdFactory == null) { - throw new IllegalArgumentException("No property descriptor factory for type: " + typeId); + throw err.at(PROPERTY_TYPE.getAttributeNode(propertyElement)) + .error( + XmlErrorMessages.ERR__UNSUPPORTED_PROPERTY_TYPE, + typeId + ); } + return propertyDefCapture(propertyElement, err, pdFactory); + } + + private static PropertyDescriptor propertyDefCapture(Element propertyElement, + PmdXmlReporter err, + PropertyDescriptorExternalBuilder factory) { + // TODO support constraints like numeric range + + String name = SchemaConstants.NAME.getNonBlankAttributeOrThrow(propertyElement, err); + String description = SchemaConstants.DESCRIPTION.getNonBlankAttributeOrThrow(propertyElement, err); + Map values = new HashMap<>(); - NamedNodeMap atts = propertyElement.getAttributes(); + values.put(PropertyDescriptorField.NAME, name); + values.put(PropertyDescriptorField.DESCRIPTION, description); + String defaultValue = parsePropertyValue(propertyElement, err, s -> s); + values.put(PropertyDescriptorField.DEFAULT_VALUE, defaultValue); - /// populate a map of values for an individual descriptor - for (int i = 0; i < atts.getLength(); i++) { - Attr a = (Attr) atts.item(i); - values.put(PropertyDescriptorField.getConstant(a.getName()), a.getValue()); - } - - if (StringUtils.isBlank(values.get(DEFAULT_VALUE))) { - NodeList children = propertyElement.getElementsByTagName(DEFAULT_VALUE.attributeName()); - if (children.getLength() == 1) { - values.put(DEFAULT_VALUE, children.item(0).getTextContent()); - } else { - throw new IllegalArgumentException("No value defined!"); + // populate remaining fields + for (Node attrNode : DomUtils.asList(propertyElement.getAttributes())) { + Attr attr = (Attr) attrNode; + PropertyDescriptorField field = PropertyDescriptorField.getConstant(attr.getName()); + if (field == PropertyDescriptorField.NAME + || field == PropertyDescriptorField.DEFAULT_VALUE + || field == PropertyDescriptorField.DESCRIPTION) { + continue; } + if (field == null) { + err.at(attr).warn(XmlErrorMessages.IGNORED__UNEXPECTED_ATTRIBUTE_IN, propertyElement.getLocalName()); + continue; + } + values.put(field, attr.getValue()); } - // casting is not pretty but prevents the interface from having this method - return pdFactory.build(values); + try { + return factory.build(values); + } catch (IllegalArgumentException e) { + // builder threw, rethrow with XML location + throw err.at(propertyElement).error(e); + } } - /** Gets the string value from a property node. */ - private static String valueFrom(Element propertyNode) { - String strValue = propertyNode.getAttribute(DEFAULT_VALUE.attributeName()); + private static T parsePropertyValue(Element propertyElt, PmdXmlReporter err, ValueParser parser) { + @Nullable String defaultAttr = PROPERTY_VALUE.getAttributeOrNull(propertyElt); + if (defaultAttr != null) { + Attr attrNode = PROPERTY_VALUE.getAttributeNode(propertyElt); - if (StringUtils.isNotBlank(strValue)) { - return strValue; - } + try { + return parser.valueOf(defaultAttr); + } catch (IllegalArgumentException e) { + throw err.at(attrNode).error(e); + } - final NodeList nodeList = propertyNode.getChildNodes(); - - for (int i = 0; i < nodeList.getLength(); i++) { - Node node = nodeList.item(i); - if (node.getNodeType() == Node.ELEMENT_NODE && "value".equals(node.getNodeName())) { - return DOMUtils.parseTextNode(node); + } else { + Element child = PROPERTY_VALUE.getSingleChildIn(propertyElt, err); + String text = XmlUtil.parseTextNode(child); + try { + return parser.valueOf(text); + } catch (IllegalArgumentException e) { + throw err.at(child).error(e); } } - return null; - } - - private static boolean hasAttributeSetTrue(Element element, String attributeId) { - return element.hasAttribute(attributeId) && "true".equalsIgnoreCase(element.getAttribute(attributeId)); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java index 3483a7f17d..b708538400 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/CollectionUtil.java @@ -17,6 +17,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -24,6 +25,7 @@ import java.util.Set; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.BinaryOperator; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collector; @@ -273,6 +275,22 @@ public final class CollectionUtil { return Collections.unmodifiableList(union); } + public static Map mapOf(K k0, V v0) { + return Collections.singletonMap(k0, v0); + } + + public static Map buildMap(Consumer> effect) { + Map map = new LinkedHashMap<>(); + effect.accept(map); + return Collections.unmodifiableMap(map); + } + + public static Map buildMap(Map initialMap, Consumer> effect) { + Map map = new LinkedHashMap<>(initialMap); + effect.accept(map); + return Collections.unmodifiableMap(map); + } + public static List<@NonNull R> mapNotNull(Iterable from, Function f) { Iterator it = from.iterator(); if (!it.hasNext()) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/FileFinder.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/FileFinder.java index 874a004bcf..c632997409 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/FileFinder.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/FileFinder.java @@ -8,10 +8,9 @@ import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Comparator; import java.util.List; -import org.apache.commons.io.comparator.PathFileComparator; - import net.sourceforge.pmd.annotation.InternalApi; /** @@ -49,7 +48,12 @@ public class FileFinder { return; } - Arrays.sort(candidates, PathFileComparator.PATH_INSENSITIVE_COMPARATOR); + Arrays.sort(candidates, new Comparator() { + @Override + public int compare(File o1, File o2) { + return o1.getPath().compareToIgnoreCase(o2.getPath()); + } + }); for (File tmp : candidates) { if (tmp.isDirectory()) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/IOUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/IOUtil.java index 1c9a64194e..2ee4a303af 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/IOUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/IOUtil.java @@ -6,22 +6,30 @@ package net.sourceforge.pmd.util; import java.io.Closeable; import java.io.File; +import java.io.FilterInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; import java.util.List; +import java.util.Objects; -import org.apache.commons.io.ByteOrderMark; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.checkerframework.checker.nullness.qual.Nullable; @@ -35,6 +43,13 @@ import net.sourceforge.pmd.annotation.InternalApi; @InternalApi @Deprecated public final class IOUtil { + /** + * Unicode BOM character. Replaces commons io ByteOrderMark. + */ + public static final char UTF_BOM = '\uFEFF'; + /** Conventional return value for readers. */ + public static final int EOF = -1; + private static final int BUFFER_SIZE = 8192; private IOUtil() { } @@ -104,36 +119,9 @@ public final class IOUtil { } } - public static Reader skipBOM(Reader source) throws IOException { - int firstCharacter = source.read(); - if (firstCharacter == ByteOrderMark.UTF_BOM) { - return source; // with one less char - } - return new Reader() { - boolean done; - - @Override - public int read(char[] cbuf, int off, int len) throws IOException { - if (done) { - return source.read(cbuf, off, len); - } else if (len > 0) { - done = true; - cbuf[off] = (char) firstCharacter; - return 1; - } - return 0; - } - - @Override - public void close() throws IOException { - source.close(); - } - }; - } - public static void tryCloseClassLoader(ClassLoader classLoader) { if (classLoader instanceof Closeable) { - IOUtils.closeQuietly((Closeable) classLoader); + closeQuietly((Closeable) classLoader); } } @@ -182,4 +170,315 @@ public final class IOUtil { throw pendingException; } } + + + // The following methods are taken from Apache Commons IO. + // The dependency was removed from PMD 6 because it had a security issue, + // and upgrading was not possible without upgrading to Java 8. + // See https://github.com/pmd/pmd/pull/3968 + // TODO PMD 7: consider bringing back commons-io and cleaning this class up. + + public static void closeQuietly(Closeable closeable) { + try { + closeable.close(); + } catch (IOException ignored) { + // ignored + } + } + + public static byte[] toByteArray(InputStream stream) throws IOException { + byte[] result = new byte[0]; + byte[] buffer = new byte[BUFFER_SIZE]; + int count = stream.read(buffer); + while (count > -1) { + byte[] newResult = new byte[result.length + count]; + System.arraycopy(result, 0, newResult, 0, result.length); + System.arraycopy(buffer, 0, newResult, result.length, count); + result = newResult; + count = stream.read(buffer); + } + return result; + } + + public static long skipFully(InputStream stream, long n) throws IOException { + if (n < 0) { + throw new IllegalArgumentException(); + } + + long bytesToSkip = n; + byte[] buffer = new byte[(int) Math.min(BUFFER_SIZE, bytesToSkip)]; + while (bytesToSkip > 0) { + int count = stream.read(buffer, 0, (int) Math.min(BUFFER_SIZE, bytesToSkip)); + if (count < 0) { + // reached eof + break; + } + bytesToSkip -= count; + } + return n - bytesToSkip; + } + + public static String normalizePath(String path) { + Path path1 = Paths.get(path); + path1.isAbsolute(); + String normalized = path1.normalize().toString(); + if (normalized.contains("." + File.separator) || normalized.contains(".." + File.separator) || "".equals(normalized)) { + return null; + } + return normalized; + } + + public static boolean equalsNormalizedPaths(String path1, String path2) { + return Objects.equals(normalizePath(path1), normalizePath(path2)); + } + + public static String getFilenameExtension(String name) { + String filename = Paths.get(name).getFileName().toString(); + int dot = filename.lastIndexOf('.'); + if (dot > -1) { + return filename.substring(dot + 1); + } + return ""; + } + + public static String getFilenameBase(String name) { + String filename = Paths.get(name).getFileName().toString(); + int dot = filename.lastIndexOf('.'); + if (dot > -1) { + return filename.substring(0, dot); + } + return filename; + } + + public static void copy(InputStream from, OutputStream to) throws IOException { + byte[] buffer = new byte[BUFFER_SIZE]; + int count = from.read(buffer); + while (count > -1) { + to.write(buffer, 0, count); + count = from.read(buffer); + } + } + + public static void copy(Reader from, Writer to) throws IOException { + char[] buffer = new char[BUFFER_SIZE]; + int count = from.read(buffer); + while (count > -1) { + to.write(buffer, 0, count); + count = from.read(buffer); + } + } + + public static String readFileToString(File file) throws IOException { + return readFileToString(file, Charset.defaultCharset()); + } + + public static String readFileToString(File file, Charset charset) throws IOException { + byte[] bytes = Files.readAllBytes(file.toPath()); + return charset.decode(ByteBuffer.wrap(bytes)).toString(); + } + + public static String readToString(Reader reader) throws IOException { + StringBuilder sb = new StringBuilder(BUFFER_SIZE); + char[] buffer = new char[BUFFER_SIZE]; + int count = reader.read(buffer); + while (count > -1) { + sb.append(buffer, 0, count); + count = reader.read(buffer); + } + return sb.toString(); + } + + public static String readToString(InputStream stream, Charset charset) throws IOException { + byte[] bytes = toByteArray(stream); + return charset.decode(ByteBuffer.wrap(bytes)).toString(); + } + + public static InputStream fromReader(Reader reader) throws IOException { + class ReaderInputStream extends InputStream { + private final Reader reader; + private final CharBuffer charBuffer = CharBuffer.allocate(BUFFER_SIZE); + private final ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); + private final CharsetEncoder encoder; + + private boolean eof; + + ReaderInputStream(Reader reader) { + this.reader = reader; + encoder = Charset.defaultCharset().newEncoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + charBuffer.clear(); + byteBuffer.clear(); + byteBuffer.flip(); // byte buffer is empty at the beginning, no bytes read yet + } + + @Override + public int read() throws IOException { + if (!byteBuffer.hasRemaining()) { + if (charBuffer.hasRemaining() && !eof) { + int count = reader.read(charBuffer); + eof = count == -1; + } + byteBuffer.clear(); + charBuffer.flip(); + encoder.encode(charBuffer, byteBuffer, eof); + byteBuffer.flip(); + charBuffer.compact(); + } + + if (byteBuffer.hasRemaining()) { + return byteBuffer.get(); + } + + return -1; + } + + @Override + public int available() throws IOException { + return byteBuffer.remaining(); + } + + @Override + public void close() throws IOException { + reader.close(); + } + } + + return new ReaderInputStream(reader); + } + + public static OutputStream fromWriter(Writer writer, String encoding) throws UnsupportedCharsetException { + class WriterOutputStream extends OutputStream { + private final Writer writer; + private final CharsetDecoder decoder; + private final ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFER_SIZE); + private final CharBuffer charBuffer = CharBuffer.allocate(BUFFER_SIZE); + + WriterOutputStream(Writer writer, String encoding) throws UnsupportedCharsetException { + this.writer = writer; + Charset charset = Charset.forName(encoding); + decoder = charset.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + byteBuffer.clear(); + charBuffer.clear(); + } + + @Override + public void write(int b) throws IOException { + if (!byteBuffer.hasRemaining()) { + decodeByteBuffer(false); + } + byteBuffer.put((byte) b); + } + + @Override + public void flush() throws IOException { + decodeByteBuffer(false); + } + + private void decodeByteBuffer(boolean isClosing) throws IOException { + byteBuffer.flip(); + charBuffer.clear(); + decoder.decode(byteBuffer, charBuffer, isClosing); + writer.write(charBuffer.array(), 0, charBuffer.position()); + writer.flush(); + byteBuffer.compact(); + } + + @Override + public void close() throws IOException { + flush(); + decodeByteBuffer(true); + writer.close(); + } + } + + return new WriterOutputStream(writer, encoding); + } + + /** + *

+ * Input stream that skips an optional byte order mark at the beginning + * of the stream. Whether the stream had a byte order mark (encoded in either UTF-8, + * UTF-16LE or UTF-16BE) can be checked with {@link #hasBom()}. The corresponding + * charset can be retrieved with {@link #getBomCharsetName()}. + *

+ * + *

+ * If the stream didn't had a BOM, then no bytes are skipped. + *

+ */ + public static class BomAwareInputStream extends FilterInputStream { + + private byte[] begin; + int beginIndex; + + private String charset; + + public BomAwareInputStream(InputStream in) { + super(in); + begin = determineBom(); + } + + private byte[] determineBom() { + byte[] bytes = new byte[3]; + try { + int count = in.read(bytes); + if (count == 3 && bytes[0] == (byte) 0xef && bytes[1] == (byte) 0xbb && bytes[2] == (byte) 0xbf) { + charset = StandardCharsets.UTF_8.name(); + return new byte[0]; // skip all 3 bytes + } else if (count >= 2 && bytes[0] == (byte) 0xfe && bytes[1] == (byte) 0xff) { + charset = StandardCharsets.UTF_16BE.name(); + return new byte[] { bytes[2] }; + } else if (count >= 2 && bytes[0] == (byte) 0xff && bytes[1] == (byte) 0xfe) { + charset = StandardCharsets.UTF_16LE.name(); + return new byte[] { bytes[2] }; + } else if (count == 3) { + return bytes; + } + + if (count < 0) { + return new byte[0]; + } + + byte[] read = new byte[count]; + for (int i = 0; i < count; i++) { + read[i] = bytes[i]; + } + return read; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public int read() throws IOException { + if (beginIndex < begin.length) { + return begin[beginIndex++]; + } + return super.read(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (beginIndex < begin.length) { + int count = 0; + for (; count < len && beginIndex < begin.length; beginIndex++) { + b[off + count] = begin[beginIndex]; + count++; + } + return count; + } + return super.read(b, off, len); + } + + public boolean hasBom() { + return charset != null; + } + + public String getBomCharsetName() { + return charset; + } + } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index 5e50749cb0..ba989da286 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -41,6 +41,13 @@ public final class StringUtil { private StringUtil() { } + public static String inSingleQuotes(String s) { + if (s == null) { + s = ""; + } + return "'" + s + "'"; + } + /** * Returns the (1-based) line number of the character at the given index. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/FileDataSource.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/FileDataSource.java index b0624e75b7..77ddb6c354 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/FileDataSource.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/FileDataSource.java @@ -17,6 +17,7 @@ import net.sourceforge.pmd.util.datasource.internal.AbstractDataSource; /** * DataSource implementation to read data from a file. */ +@Deprecated public class FileDataSource extends AbstractDataSource { private final File file; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/ReaderDataSource.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/ReaderDataSource.java index ec21c09f4b..6edb9e6553 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/ReaderDataSource.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/ReaderDataSource.java @@ -8,13 +8,13 @@ import java.io.IOException; import java.io.InputStream; import java.io.Reader; -import org.apache.commons.io.input.ReaderInputStream; - +import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.datasource.internal.AbstractDataSource; /** * DataSource implementation to read data from a Reader. */ +@Deprecated public class ReaderDataSource extends AbstractDataSource { /** * Reader @@ -50,7 +50,7 @@ public class ReaderDataSource extends AbstractDataSource { */ @Override public InputStream getInputStream() throws IOException { - return new ReaderInputStream(reader); + return IOUtil.fromReader(reader); } /** diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/ZipDataSource.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/ZipDataSource.java index 09ac322b5e..6cbfa9ce80 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/ZipDataSource.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/ZipDataSource.java @@ -14,6 +14,7 @@ import net.sourceforge.pmd.util.datasource.internal.AbstractDataSource; /** * DataSource implementation to read data from an entry in a zip or jar file. */ +@Deprecated public class ZipDataSource extends AbstractDataSource { private final ZipFile zipFile; private final ZipEntry zipEntry; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/internal/AbstractDataSource.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/internal/AbstractDataSource.java index 56c54547b3..81484cad5d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/internal/AbstractDataSource.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/datasource/internal/AbstractDataSource.java @@ -8,6 +8,7 @@ import java.io.IOException; import net.sourceforge.pmd.util.datasource.DataSource; +@Deprecated public abstract class AbstractDataSource implements DataSource { @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/PmdXmlReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/PmdXmlReporter.java new file mode 100644 index 0000000000..02464f545a --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/PmdXmlReporter.java @@ -0,0 +1,16 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.internal.xml; + +import net.sourceforge.pmd.util.log.MessageReporter; + +import com.github.oowekyala.ooxml.messages.XmlMessageReporter; + +/** + * @author Clรฉment Fournier + */ +public interface PmdXmlReporter extends XmlMessageReporter { + +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/SchemaConstant.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/SchemaConstant.java new file mode 100755 index 0000000000..0b47420e7e --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/SchemaConstant.java @@ -0,0 +1,145 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.internal.xml; + +import static net.sourceforge.pmd.util.CollectionUtil.setOf; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * Wraps the name of eg an attribute or element, and provides convenience + * methods to query the DOM. + */ +public class SchemaConstant { + + private final String name; + + + public SchemaConstant(String name) { + this.name = name; + } + + + public boolean getAsBooleanAttr(Element e, boolean defaultValue) { + String attr = e.getAttribute(name); + return e.hasAttribute(name) ? Boolean.parseBoolean(attr) : defaultValue; + } + + public @NonNull String getAttributeOrThrow(Element element, PmdXmlReporter err) { + String attribute = element.getAttribute(name); + if (!element.hasAttribute(name)) { + throw err.at(element).error(XmlErrorMessages.ERR__MISSING_REQUIRED_ATTRIBUTE, name); + } + + return attribute; + } + + public @NonNull String getNonBlankAttributeOrThrow(Element element, PmdXmlReporter err) { + String attribute = element.getAttribute(name); + if (!element.hasAttribute(name)) { + throw err.at(element).error(XmlErrorMessages.ERR__MISSING_REQUIRED_ATTRIBUTE, name); + } else if (StringUtils.isBlank(attribute)) { + throw err.at(element).error(XmlErrorMessages.ERR__BLANK_REQUIRED_ATTRIBUTE, name); + } + return attribute; + } + + public @Nullable String getAttributeOrNull(Element element) { + String attr = element.getAttribute(name); + return attr.isEmpty() ? null : attr; + } + + public Optional getAttributeOpt(Element element) { + Attr attr = element.getAttributeNode(name); + return Optional.ofNullable(attr).map(Attr::getValue); + } + + public @Nullable Attr getAttributeNode(Element element) { + return element.getAttributeNode(name); + } + + public boolean hasAttribute(Element element) { + return element.hasAttribute(name); + } + + public List getChildrenIn(Element elt) { + return XmlUtil.getElementChildrenNamed(elt, name) + .collect(Collectors.toList()); + } + + public List getElementChildrenNamedReportOthers(Element elt, PmdXmlReporter err) { + return XmlUtil.getElementChildrenNamedReportOthers(elt, setOf(this), err) + .collect(Collectors.toList()); + } + + public Element getSingleChildIn(Element elt, PmdXmlReporter err) { + return XmlUtil.getSingleChildIn(elt, true, err, setOf(this)); + } + + public Element getOptChildIn(Element elt, PmdXmlReporter err) { + return XmlUtil.getSingleChildIn(elt, false, err, setOf(this)); + } + + public void setOn(Element element, String value) { + element.setAttribute(name, value); + } + + /** + * Returns the String name of this attribute. + * + * @return The attribute's name + */ + public String xmlName() { + return name; + } + + + @Override + public String toString() { + return xmlName(); + } + + + public boolean matchesElt(Node node) { + return node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals(name); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + SchemaConstant that = (SchemaConstant) o; + return Objects.equals(name, that.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } + + public @NonNull String getNonBlankAttribute(Element ruleElement, PmdXmlReporter err) { + String clazz = getAttributeOrThrow(ruleElement, err); + if (StringUtils.isBlank(clazz)) { + Attr node = getAttributeNode(ruleElement); + throw err.at(node).error("Attribute {0} may not be blank", this); + } + return clazz; + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/SchemaConstants.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/SchemaConstants.java new file mode 100755 index 0000000000..d6e7c37c94 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/SchemaConstants.java @@ -0,0 +1,42 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.internal.xml; + + +/** + * Constants of the ruleset schema. + */ +public final class SchemaConstants { + + public static final SchemaConstant PROPERTY_TYPE = new SchemaConstant("type"); + public static final SchemaConstant NAME = new SchemaConstant("name"); + public static final SchemaConstant MESSAGE = new SchemaConstant("message"); + public static final SchemaConstant LANGUAGE = new SchemaConstant("language"); + public static final SchemaConstant CLASS = new SchemaConstant("class"); + public static final SchemaConstant DESCRIPTION = new SchemaConstant("description"); + public static final SchemaConstant PROPERTY_VALUE = new SchemaConstant("value"); + + public static final SchemaConstant PROPERTIES = new SchemaConstant("properties"); + public static final SchemaConstant PROPERTY_ELT = new SchemaConstant("property"); + public static final SchemaConstant DEPRECATED = new SchemaConstant("deprecated"); + + public static final SchemaConstant RULESET = new SchemaConstant("ruleset"); + public static final SchemaConstant EXCLUDE_PATTERN = new SchemaConstant("exclude-pattern"); + public static final SchemaConstant INCLUDE_PATTERN = new SchemaConstant("include-pattern"); + public static final SchemaConstant RULE = new SchemaConstant("rule"); + public static final SchemaConstant REF = new SchemaConstant("ref"); + public static final SchemaConstant EXCLUDE = new SchemaConstant("exclude"); + public static final SchemaConstant PRIORITY = new SchemaConstant("priority"); + public static final SchemaConstant MINIMUM_LANGUAGE_VERSION = new SchemaConstant("minimumLanguageVersion"); + public static final SchemaConstant MAXIMUM_LANGUAGE_VERSION = new SchemaConstant("maximumLanguageVersion"); + public static final SchemaConstant EXTERNAL_INFO_URL = new SchemaConstant("externalInfoUrl"); + public static final SchemaConstant EXAMPLE = new SchemaConstant("example"); + public static final SchemaConstant SINCE = new SchemaConstant("since"); + + + private SchemaConstants() { + // utility class + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/XmlErrorMessages.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/XmlErrorMessages.java new file mode 100644 index 0000000000..d397020dd8 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/XmlErrorMessages.java @@ -0,0 +1,45 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.internal.xml; + +// CHECKSTYLE:OFF +public final class XmlErrorMessages { + + private static final String THIS_WILL_BE_IGNORED = ", this will be ignored"; + + /** {0}: unexpected element name; {1}: parent node name; {2}: list of allowed elements in this context */ + public static final String ERR__UNEXPECTED_ELEMENT = "Unexpected element ''{0}'' in {1}, expecting {2}"; + /** {0}: unexpected element name; {1}: parent node name */ + public static final String ERR__UNEXPECTED_ELEMENT_IN = "Unexpected element ''{0}'' in {1}"; + /** {0}: unexpected attr name; {1}: parent node name */ + public static final String ERR__UNEXPECTED_ATTRIBUTE_IN = "Unexpected attribute ''{0}'' in {1}"; + public static final String ERR__MISSING_REQUIRED_ATTRIBUTE = "Required attribute ''{0}'' is missing"; + public static final String ERR__BLANK_REQUIRED_ATTRIBUTE = "Required attribute ''{0}'' is blank"; + public static final String ERR__MISSING_REQUIRED_ELEMENT = "Required child element named {0} is missing"; + + /** {0}: unexpected element name; {1}: parent node name; {2}: allowed elements in this context */ + public static final String IGNORED__UNEXPECTED_ELEMENT = ERR__UNEXPECTED_ELEMENT + THIS_WILL_BE_IGNORED; + /** {0}: unexpected element name; {1}: parent node name */ + public static final String IGNORED__UNEXPECTED_ELEMENT_IN = ERR__UNEXPECTED_ELEMENT_IN + THIS_WILL_BE_IGNORED; + public static final String IGNORED__UNEXPECTED_ATTRIBUTE_IN = ERR__UNEXPECTED_ATTRIBUTE_IN + THIS_WILL_BE_IGNORED; + public static final String IGNORED__DUPLICATE_CHILD_ELEMENT = "Duplicated child with name ''{0}''" + THIS_WILL_BE_IGNORED; + public static final String IGNORED__DUPLICATE_PROPERTY_SETTER = "Duplicate property tag with name ''{0}''" + THIS_WILL_BE_IGNORED; + + public static final String ERR__UNSUPPORTED_VALUE_ATTRIBUTE = "This property does not support the attribute syntax.\nUse a nested element, e.g. {1}"; + public static final String ERR__PROPERTY_DOES_NOT_EXIST = "Cannot set non-existent property ''{0}'' on rule {1}"; + public static final String ERR__CONSTRAINT_NOT_SATISFIED = "Property constraint(s) not satisfied: {0}"; + public static final String ERR__LIST_CONSTRAINT_NOT_SATISFIED = "Property constraint(s) not satisfied on items"; + public static final String ERR__INVALID_VERSION_RANGE = "Invalid language version range, minimum version ''{0}'' is greater than maximum version ''{1}''"; + public static final String ERR__INVALID_LANG_VERSION_NO_NAMED_VERSION = "Invalid language version ''{0}'' for language ''{1}'', the language has no named versions"; + public static final String ERR__INVALID_LANG_VERSION = "Invalid language version ''{0}'' for language ''{1}'', supported versions are {2}"; + + public static final String WARN__DEPRECATED_USE_OF_ATTRIBUTE = "The use of the ''{0}'' attribute is deprecated. Use a nested element, e.g. {1}"; + public static final String ERR__INVALID_PRIORITY_VALUE = "Not a valid priority: ''{0}'', expected a number in [1,5]"; + public static final String ERR__UNSUPPORTED_PROPERTY_TYPE = "Unsupported property type ''{0}''"; + + private XmlErrorMessages() { + // utility class + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/XmlUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/XmlUtil.java new file mode 100644 index 0000000000..5d66faab05 --- /dev/null +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/internal/xml/XmlUtil.java @@ -0,0 +1,140 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.util.internal.xml; + +import static net.sourceforge.pmd.util.internal.xml.XmlErrorMessages.ERR__MISSING_REQUIRED_ELEMENT; +import static net.sourceforge.pmd.util.internal.xml.XmlErrorMessages.IGNORED__DUPLICATE_CHILD_ELEMENT; +import static net.sourceforge.pmd.util.internal.xml.XmlErrorMessages.IGNORED__UNEXPECTED_ELEMENT; +import static net.sourceforge.pmd.util.internal.xml.XmlErrorMessages.IGNORED__UNEXPECTED_ELEMENT_IN; + +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import net.sourceforge.pmd.util.StringUtil; + +import com.github.oowekyala.ooxml.DomUtils; + +public final class XmlUtil { + + private XmlUtil() { + + } + + public static Stream getElementChildren(Element parent) { + return DomUtils.asList(parent.getChildNodes()).stream() + .filter(it -> it.getNodeType() == Node.ELEMENT_NODE) + .map(Element.class::cast); + } + + public static List getElementChildrenList(Element parent) { + return getElementChildren(parent).collect(Collectors.toList()); + } + + public static Stream getElementChildrenNamed(Element parent, Set names) { + return getElementChildren(parent).filter(e -> matchesName(e, names)); + } + + public static Stream getElementChildrenNamedReportOthers(Element parent, Set names, PmdXmlReporter err) { + return getElementChildren(parent) + .map(it -> { + if (matchesName(it, names)) { + return it; + } else { + err.at(it).warn(IGNORED__UNEXPECTED_ELEMENT_IN, it.getTagName(), formatPossibleNames(names)); + return null; + } + }).filter(Objects::nonNull); + } + + public static boolean matchesName(Element elt, Set names) { + return names.stream().anyMatch(it -> it.xmlName().equals(elt.getTagName())); + } + + public static void reportIgnoredUnexpectedElt(Element parent, + Element unexpectedChild, + Set names, + PmdXmlReporter err) { + err.at(unexpectedChild).warn(IGNORED__UNEXPECTED_ELEMENT, + unexpectedChild.getTagName(), + parent.getTagName(), + formatPossibleNames(names)); + } + + public static Stream getElementChildrenNamed(Element parent, String name) { + return getElementChildren(parent).filter(e -> name.equals(e.getTagName())); + } + + + public static List getChildrenExpectSingleName(Element elt, String name, PmdXmlReporter err) { + return XmlUtil.getElementChildren(elt).peek(it -> { + if (!it.getTagName().equals(name)) { + err.at(it).warn(IGNORED__UNEXPECTED_ELEMENT_IN, it.getTagName(), name); + } + }).collect(Collectors.toList()); + } + + public static Element getSingleChildIn(Element elt, boolean throwOnMissing, PmdXmlReporter err, Set names) { + List children = getElementChildrenNamed(elt, names).collect(Collectors.toList()); + if (children.size() == 1) { + return children.get(0); + } else if (children.isEmpty()) { + if (throwOnMissing) { + throw err.at(elt).error(ERR__MISSING_REQUIRED_ELEMENT, formatPossibleNames(names)); + } else { + return null; + } + } else { + for (int i = 1; i < children.size(); i++) { + Element child = children.get(i); + err.at(child).warn(IGNORED__DUPLICATE_CHILD_ELEMENT, child.getTagName()); + } + return children.get(0); + } + } + + public static @Nullable String formatPossibleNames(Set names) { + if (names.isEmpty()) { + return null; + } else if (names.size() == 1) { + return StringUtil.inSingleQuotes(names.iterator().next().xmlName()); + } else { + return "one of " + names.stream() + .map(SchemaConstant::xmlName) + .map(StringUtil::inSingleQuotes) + .collect(Collectors.joining(", ")); + } + } + + /** + * Parse a String from a textually type node. + * + * @param node The node. + * + * @return The String. + */ + public static String parseTextNode(Node node) { + final int nodeCount = node.getChildNodes().getLength(); + if (nodeCount == 0) { + return ""; + } + + StringBuilder buffer = new StringBuilder(); + + for (int i = 0; i < nodeCount; i++) { + Node childNode = node.getChildNodes().item(i); + if (childNode.getNodeType() == Node.CDATA_SECTION_NODE || childNode.getNodeType() == Node.TEXT_NODE) { + buffer.append(childNode.getNodeValue()); + } + } + return buffer.toString(); + } +} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/MessageReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/MessageReporter.java index 689e4f41c4..97756c86b2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/MessageReporter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/MessageReporter.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.util.log; import java.text.MessageFormat; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.event.Level; import net.sourceforge.pmd.annotation.InternalApi; @@ -24,11 +25,28 @@ import net.sourceforge.pmd.annotation.InternalApi; @InternalApi public interface MessageReporter { + // todo change String to MessageFormat in those arg lists, it's too confusing + // where to apply MessageFormat otherwise... + boolean isLoggable(Level level); - void log(Level level, String message, Object... formatArgs); + default void log(Level level, String message, Object... formatArgs) { + logEx(level, message, formatArgs, null); + } - void logEx(Level level, String message, Object[] formatArgs, Throwable error); + void logEx(Level level, @Nullable String message, Object[] formatArgs, @Nullable Throwable error); + + /** + * Logs and returns a new exception. + * Message and cause may not be null a the same time. + */ + default RuntimeException newException(Level level, @Nullable Throwable cause, @Nullable String message, Object... formatArgs) { + logEx(level, message, formatArgs, cause); + if (message == null) { + return new RuntimeException(cause); + } + return new RuntimeException(MessageFormat.format(message, formatArgs), cause); + } default void info(String message, Object... formatArgs) { log(Level.INFO, message, formatArgs); @@ -46,8 +64,19 @@ public interface MessageReporter { logEx(Level.WARN, message, formatArgs, error); } - default void error(String message, Object... formatArgs) { - log(Level.ERROR, message, formatArgs); + default RuntimeException error(String message, Object... formatArgs) { + return error(null, message, formatArgs); + } + + /** + * Only one of the cause or the message can be null. + */ + default RuntimeException error(@Nullable Throwable cause, @Nullable String contextMessage, Object... formatArgs) { + return newException(Level.ERROR, cause, contextMessage, formatArgs); + } + + default RuntimeException error(Throwable error) { + return error(error, null); } default void errorEx(String message, Throwable error) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/ErrorsAsWarningsReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/ErrorsAsWarningsReporter.java index 80270d9163..71b201e2cc 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/ErrorsAsWarningsReporter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/ErrorsAsWarningsReporter.java @@ -32,10 +32,10 @@ public final class ErrorsAsWarningsReporter extends MessageReporterBase { } @Override - protected void logImpl(Level level, String message, Object[] formatArgs) { + protected void logImpl(Level level, String message) { if (level == Level.ERROR) { level = Level.WARN; } - backend.log(level, message, formatArgs); + backend.log(level, message); } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/MessageReporterBase.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/MessageReporterBase.java index 64f045174d..643b22f92f 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/MessageReporterBase.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/MessageReporterBase.java @@ -4,12 +4,16 @@ package net.sourceforge.pmd.util.log.internal; +import static net.sourceforge.pmd.util.StringUtil.quoteMessageFormat; + import java.text.MessageFormat; +import java.util.Objects; import org.apache.commons.lang3.exception.ExceptionUtils; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; import org.slf4j.event.Level; -import net.sourceforge.pmd.util.StringUtil; import net.sourceforge.pmd.util.log.MessageReporter; /** @@ -20,12 +24,12 @@ import net.sourceforge.pmd.util.log.MessageReporter; abstract class MessageReporterBase implements MessageReporter { private int numErrors; - private Level minLevel = Level.TRACE; + private @Nullable Level minLevel = Level.TRACE; /** * null level means off. */ - public final void setLevel(Level minLevel) { + public final void setLevel(@Nullable Level minLevel) { this.minLevel = minLevel; } @@ -41,36 +45,51 @@ abstract class MessageReporterBase implements MessageReporter { } @Override - public void logEx(Level level, String message, Object[] formatArgs, Throwable error) { + public void logEx(Level level, @Nullable String message, Object[] formatArgs, @Nullable Throwable error) { if (isLoggable(level)) { - message = MessageFormat.format(message, formatArgs); - String errorMessage = error.getMessage(); - if (errorMessage == null) { - errorMessage = error.getClass().getSimpleName(); + if (error == null) { + Objects.requireNonNull(message, "cannot call this method with null message and error"); + log(level, message, formatArgs); + return; } - errorMessage = StringUtil.quoteMessageFormat(errorMessage); - log(level, message + ": " + errorMessage); + if (level == Level.ERROR) { + this.numErrors++; + } + String fullMessage = getErrorMessage(error); + if (message != null) { + message = MessageFormat.format(message, formatArgs); + fullMessage = message + ": " + fullMessage; + } + logImpl(level, fullMessage); if (isLoggable(Level.DEBUG)) { - String stackTrace = StringUtil.quoteMessageFormat(ExceptionUtils.getStackTrace(error)); + String stackTrace = quoteMessageFormat(ExceptionUtils.getStackTrace(error)); log(Level.DEBUG, stackTrace); } } } + private @NonNull String getErrorMessage(Throwable error) { + String errorMessage = error.getMessage(); + if (errorMessage == null) { + errorMessage = error.getClass().getSimpleName(); + } + return errorMessage; + } + @Override public final void log(Level level, String message, Object... formatArgs) { if (level == Level.ERROR) { this.numErrors++; } if (isLoggable(level)) { - logImpl(level, message, formatArgs); + logImpl(level, MessageFormat.format(message, formatArgs)); } } /** * Perform logging assuming {@link #isLoggable(Level)} is true. */ - protected abstract void logImpl(Level level, String message, Object[] formatArgs); + protected abstract void logImpl(Level level, String message); @Override diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/NoopReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/NoopReporter.java index 98eb4a72a3..2ddfbf6d64 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/NoopReporter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/NoopReporter.java @@ -25,7 +25,7 @@ public final class NoopReporter extends MessageReporterBase implements MessageRe } @Override - protected void logImpl(Level level, String message, Object[] formatArgs) { + protected void logImpl(Level level, String message) { // noop } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/SimpleMessageReporter.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/SimpleMessageReporter.java index 672e40df98..f7ce618fa6 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/SimpleMessageReporter.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/log/internal/SimpleMessageReporter.java @@ -26,11 +26,42 @@ public class SimpleMessageReporter extends MessageReporterBase implements Messag @Override protected boolean isLoggableImpl(Level level) { - return backend.isEnabledForLevel(level); + switch (level) { + case ERROR: + return backend.isErrorEnabled(); + case WARN: + return backend.isWarnEnabled(); + case INFO: + return backend.isInfoEnabled(); + case DEBUG: + return backend.isDebugEnabled(); + case TRACE: + return backend.isTraceEnabled(); + default: + return false; + } } @Override - protected void logImpl(Level level, String message, Object[] formatArgs) { - backend.atLevel(level).log(message, formatArgs); + protected void logImpl(Level level, String message) { + switch (level) { + case ERROR: + backend.error(message); + break; + case WARN: + backend.warn(message); + break; + case INFO: + backend.info(message); + break; + case DEBUG: + backend.debug(message); + break; + case TRACE: + backend.trace(message); + break; + default: + throw new AssertionError("Invalid log level: " + level); + } } } diff --git a/pmd-core/src/main/java/org/slf4j/PmdLoggerFactoryFriend.java b/pmd-core/src/main/java/org/slf4j/PmdLoggerFactoryFriend.java new file mode 100644 index 0000000000..9ea8426926 --- /dev/null +++ b/pmd-core/src/main/java/org/slf4j/PmdLoggerFactoryFriend.java @@ -0,0 +1,26 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package org.slf4j; + +import net.sourceforge.pmd.annotation.InternalApi; + +/** + * This class is for internal use only. + *

+ * It is needed to reinitialize the underlying logging in case the configuration is changed. + *

+ * @deprecated internal, do not use + */ +@Deprecated +@InternalApi +public final class PmdLoggerFactoryFriend { + private PmdLoggerFactoryFriend() { + // helper + } + + public static void reset() { + LoggerFactory.reset(); + } +} diff --git a/pmd-core/src/main/resources/rulesets/internal/all-java.xml b/pmd-core/src/main/resources/rulesets/internal/all-java.xml index a8f260812f..796a9964d8 100644 --- a/pmd-core/src/main/resources/rulesets/internal/all-java.xml +++ b/pmd-core/src/main/resources/rulesets/internal/all-java.xml @@ -26,6 +26,12 @@ .*/net/sourceforge/pmd/lang/java/ast/InfiniteLoopInLookahead.java + + .*/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/GuardedAndParenthesizedPatterns.java + .*/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java18p/RefiningPatternsInSwitch.java + diff --git a/pmd-core/src/main/resources/rulesets/releases/6460.xml b/pmd-core/src/main/resources/rulesets/releases/6460.xml new file mode 100644 index 0000000000..9601247606 --- /dev/null +++ b/pmd-core/src/main/resources/rulesets/releases/6460.xml @@ -0,0 +1,14 @@ + + + + +This ruleset contains links to rules that are new in PMD v6.46.0 + + + + + + diff --git a/pmd-core/src/main/resources/rulesets/releases/700.xml b/pmd-core/src/main/resources/rulesets/releases/700.xml index 75821d4a05..4646553133 100644 --- a/pmd-core/src/main/resources/rulesets/releases/700.xml +++ b/pmd-core/src/main/resources/rulesets/releases/700.xml @@ -12,5 +12,13 @@ This ruleset contains links to rules that are new in PMD v7.0.0 + + + + + + + +
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/AbstractRuleTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/AbstractRuleTest.java index b18c691ac2..acb88be6ef 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/AbstractRuleTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/AbstractRuleTest.java @@ -5,13 +5,13 @@ package net.sourceforge.pmd; import static net.sourceforge.pmd.properties.constraints.NumericConstraints.inRange; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import java.util.Collections; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.Report.SuppressedViolation; import net.sourceforge.pmd.lang.DummyLanguageModule; @@ -67,32 +67,32 @@ public class AbstractRuleTest { } @Test - public void testCreateRV() { + void testCreateRV() { MyRule r = new MyRule(); r.setRuleSetName("foo"); DummyRootNode s = DummyLanguageModule.parse("abc()", "filename"); RuleViolation rv = new ParametricRuleViolation(r, s, r.getMessage()); - assertEquals("Line number mismatch!", s.getBeginLine(), rv.getBeginLine()); - assertEquals("Filename mismatch!", s.getTextDocument().getDisplayName(), rv.getFilename()); - assertEquals("Rule object mismatch!", r, rv.getRule()); - assertEquals("Rule msg mismatch!", r.getMessage(), rv.getDescription()); - assertEquals("RuleSet name mismatch!", r.getRuleSetName(), rv.getRule().getRuleSetName()); + assertEquals(1, rv.getBeginLine(), "Line number mismatch!"); + assertEquals("filename", rv.getFilename(), "Filename mismatch!"); + assertEquals(r, rv.getRule(), "Rule object mismatch!"); + assertEquals("my rule msg", rv.getDescription(), "Rule msg mismatch!"); + assertEquals("foo", rv.getRule().getRuleSetName(), "RuleSet name mismatch!"); } @Test - public void testCreateRV2() { + void testCreateRV2() { MyRule r = new MyRule(); DummyRootNode s = DummyLanguageModule.parse("abc()", "filename"); RuleViolation rv = new ParametricRuleViolation(r, s, "specificdescription"); - assertEquals("Line number mismatch!", s.getBeginLine(), rv.getBeginLine()); - assertEquals("Filename mismatch!", "filename", rv.getFilename()); - assertEquals("Rule object mismatch!", r, rv.getRule()); - assertEquals("Rule description mismatch!", "specificdescription", rv.getDescription()); + assertEquals(1, rv.getBeginLine(), "Line number mismatch!"); + assertEquals("filename", rv.getFilename(), "Filename mismatch!"); + assertEquals(r, rv.getRule(), "Rule object mismatch!"); + assertEquals("specificdescription", rv.getDescription(), "Rule description mismatch!"); } @Test - public void testRuleWithVariableInMessage() throws Exception { + void testRuleWithVariableInMessage() { MyRule r = new MyRule() { @Override public void apply(Node target, RuleContext ctx) { @@ -109,7 +109,7 @@ public class AbstractRuleTest { } @Test - public void testRuleSuppress() { + void testRuleSuppress() { DummyRootNode n = DummyLanguageModule.parse("abc()", "filename") .withNoPmdComments(Collections.singletonMap(1, "ohio")); RuleViolation violation = DefaultRuleViolationFactory.defaultInstance().createViolation(new MyRule(), n, n.getReportLocation(), "specificdescription"); @@ -119,82 +119,82 @@ public class AbstractRuleTest { } @Test - public void testEquals1() { + void testEquals1() { MyRule r = new MyRule(); - assertFalse("A rule is never equals to null!", r.equals(null)); + assertFalse(r.equals(null), "A rule is never equals to null!"); } @Test - public void testEquals2() { + void testEquals2() { MyRule r = new MyRule(); - assertEquals("A rule must be equals to itself", r, r); + assertEquals(r, r, "A rule must be equals to itself"); } @Test - public void testEquals3() { + void testEquals3() { MyRule r1 = new MyRule(); MyRule r2 = new MyRule(); - assertEquals("Two instances of the same rule are equal", r1, r2); - assertEquals("Hashcode for two instances of the same rule must be equal", r1.hashCode(), r2.hashCode()); + assertEquals(r1, r2, "Two instances of the same rule are equal"); + assertEquals(r1.hashCode(), r2.hashCode(), "Hashcode for two instances of the same rule must be equal"); } @Test - public void testEquals4() { + void testEquals4() { MyRule myRule = new MyRule(); - assertFalse("A rule cannot be equal to an object of another class", myRule.equals("MyRule")); + assertFalse(myRule.equals("MyRule"), "A rule cannot be equal to an object of another class"); } @Test - public void testEquals5() { + void testEquals5() { MyRule myRule = new MyRule(); MyOtherRule myOtherRule = new MyOtherRule(); - assertFalse("Two rules from different classes cannot be equal", myRule.equals(myOtherRule)); + assertFalse(myRule.equals(myOtherRule), "Two rules from different classes cannot be equal"); } @Test - public void testEquals6() { + void testEquals6() { MyRule r1 = new MyRule(); MyRule r2 = new MyRule(); r2.setName("MyRule2"); - assertFalse("Rules with different names cannot be equal", r1.equals(r2)); + assertFalse(r1.equals(r2), "Rules with different names cannot be equal"); } @Test - public void testEquals7() { + void testEquals7() { MyRule r1 = new MyRule(); MyRule r2 = new MyRule(); r2.setPriority(RulePriority.HIGH); - assertFalse("Rules with different priority levels cannot be equal", r1.equals(r2)); + assertFalse(r1.equals(r2), "Rules with different priority levels cannot be equal"); } @Test - public void testEquals8() { + void testEquals8() { MyRule r1 = new MyRule(); r1.setProperty(MyRule.XPATH_PROPERTY, "something"); MyRule r2 = new MyRule(); r2.setProperty(MyRule.XPATH_PROPERTY, "something else"); - assertFalse("Rules with different properties values cannot be equal", r1.equals(r2)); + assertFalse(r1.equals(r2), "Rules with different properties values cannot be equal"); } @Test - public void testEquals9() { + void testEquals9() { MyRule r1 = new MyRule(); MyRule r2 = new MyRule(); r2.setProperty(MyRule.XPATH_PROPERTY, "something else"); - assertFalse("Rules with different properties cannot be equal", r1.equals(r2)); + assertFalse(r1.equals(r2), "Rules with different properties cannot be equal"); } @Test - public void testEquals10() { + void testEquals10() { MyRule r1 = new MyRule(); MyRule r2 = new MyRule(); r2.setMessage("another message"); - assertEquals("Rules with different messages are still equal", r1, r2); - assertEquals("Rules that are equal must have the an equal hashcode", r1.hashCode(), r2.hashCode()); + assertEquals(r1, r2, "Rules with different messages are still equal"); + assertEquals(r1.hashCode(), r2.hashCode(), "Rules that are equal must have the an equal hashcode"); } @Test - public void testDeepCopyRule() { + void testDeepCopyRule() { MyRule r1 = new MyRule(); MyRule r2 = (MyRule) r1.deepCopy(); assertEquals(r1.getDescription(), r2.getDescription()); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/FileSelectorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/FileSelectorTest.java index 5f5ec141f5..67bde85b0e 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/FileSelectorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/FileSelectorTest.java @@ -4,11 +4,11 @@ package net.sourceforge.pmd; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.File; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.LanguageFilenameFilter; @@ -19,47 +19,47 @@ import net.sourceforge.pmd.lang.LanguageRegistry; * * @author pieter_van_raemdonck - Application Engineers NV/SA - www.ae.be */ -public class FileSelectorTest { +class FileSelectorTest { /** * Test wanted selection of a source file. */ @Test - public void testWantedFile() { + void testWantedFile() { LanguageFilenameFilter fileSelector = new LanguageFilenameFilter( LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); File javaFile = new File("/path/to/myFile.dummy"); boolean selected = fileSelector.accept(javaFile.getParentFile(), javaFile.getName()); - assertEquals("This file should be selected !", true, selected); + assertEquals(true, selected, "This file should be selected !"); } /** * Test unwanted selection of a non source file. */ @Test - public void testUnwantedFile() { + void testUnwantedFile() { LanguageFilenameFilter fileSelector = new LanguageFilenameFilter( LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); File javaFile = new File("/path/to/myFile.txt"); boolean selected = fileSelector.accept(javaFile.getParentFile(), javaFile.getName()); - assertEquals("Not-source file must not be selected!", false, selected); + assertEquals(false, selected, "Not-source file must not be selected!"); } /** * Test unwanted selection of a java file. */ @Test - public void testUnwantedJavaFile() { + void testUnwantedJavaFile() { LanguageFilenameFilter fileSelector = new LanguageFilenameFilter( LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); File javaFile = new File("/path/to/MyClass.java"); boolean selected = fileSelector.accept(javaFile.getParentFile(), javaFile.getName()); - assertEquals("Unwanted java file must not be selected!", false, selected); + assertEquals(false, selected, "Unwanted java file must not be selected!"); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/PmdAnalysisTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/PmdAnalysisTest.java index 5c437fc1a9..f38250e95e 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/PmdAnalysisTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/PmdAnalysisTest.java @@ -8,6 +8,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; +import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -15,18 +16,21 @@ import static org.mockito.Mockito.verify; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.ArgumentMatchers; +import net.sourceforge.pmd.RuleSetTest.MockRule; +import net.sourceforge.pmd.processor.PmdRunnableTest; import net.sourceforge.pmd.renderers.Renderer; +import net.sourceforge.pmd.reporting.ReportStats; /** * @author Clรฉment Fournier */ -public class PmdAnalysisTest { +class PmdAnalysisTest { @Test - public void testPmdAnalysisWithEmptyConfig() { + void testPmdAnalysisWithEmptyConfig() { PMDConfiguration config = new PMDConfiguration(); try (PmdAnalysis pmd = PmdAnalysis.create(config)) { assertThat(pmd.files().getCollectedFiles(), empty()); @@ -36,7 +40,7 @@ public class PmdAnalysisTest { } @Test - public void testRendererInteractions() throws IOException { + void testRendererInteractions() throws IOException { PMDConfiguration config = new PMDConfiguration(); config.setInputPaths("sample-source/dummy"); Renderer renderer = spy(Renderer.class); @@ -53,7 +57,7 @@ public class PmdAnalysisTest { } @Test - public void testRulesetLoading() { + void testRulesetLoading() { PMDConfiguration config = new PMDConfiguration(); config.addRuleSet("rulesets/dummy/basic.xml"); try (PmdAnalysis pmd = PmdAnalysis.create(config)) { @@ -62,7 +66,7 @@ public class PmdAnalysisTest { } @Test - public void testRulesetWhenSomeoneHasAnError() { + void testRulesetWhenSomeoneHasAnError() { PMDConfiguration config = new PMDConfiguration(); config.addRuleSet("rulesets/dummy/basic.xml"); config.addRuleSet("rulesets/xxxe/notaruleset.xml"); @@ -72,4 +76,18 @@ public class PmdAnalysisTest { } } + @Test + public void testParseException() { + PMDConfiguration config = new PMDConfiguration(); + config.setThreads(1); + config.setForceLanguageVersion(PmdRunnableTest.getVersionWithParserThatThrowsSemanticError()); + try (PmdAnalysis pmd = PmdAnalysis.create(config)) { + pmd.addRuleSet(RuleSet.forSingleRule(new MockRule())); + pmd.files().addSourceFile("file", "some source"); + + ReportStats stats = pmd.runAndReturnStats(); + assertEquals("Errors", 1, stats.getNumErrors()); + assertEquals("Violations", 0, stats.getNumViolations()); + } + } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/PmdConfigurationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/PmdConfigurationTest.java index 99c321530f..8674a440b2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/PmdConfigurationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/PmdConfigurationTest.java @@ -7,12 +7,13 @@ package net.sourceforge.pmd; import static net.sourceforge.pmd.util.CollectionUtil.listOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.IOException; @@ -20,13 +21,12 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.Collections; import java.util.Properties; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import net.sourceforge.pmd.cache.FileAnalysisCache; import net.sourceforge.pmd.cache.NoopAnalysisCache; @@ -34,64 +34,61 @@ import net.sourceforge.pmd.renderers.CSVRenderer; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.util.ClasspathClassLoader; -public class PmdConfigurationTest { - - @Rule - public TemporaryFolder folder = new TemporaryFolder(); +class PmdConfigurationTest { @Test - public void testSuppressMarker() { + void testSuppressMarker() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default suppress marker", PMDConfiguration.DEFAULT_SUPPRESS_MARKER, configuration.getSuppressMarker()); + assertEquals(PMDConfiguration.DEFAULT_SUPPRESS_MARKER, configuration.getSuppressMarker(), "Default suppress marker"); configuration.setSuppressMarker("CUSTOM_MARKER"); - assertEquals("Changed suppress marker", "CUSTOM_MARKER", configuration.getSuppressMarker()); + assertEquals("CUSTOM_MARKER", configuration.getSuppressMarker(), "Changed suppress marker"); } @Test - public void testThreads() { + void testThreads() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default threads", Runtime.getRuntime().availableProcessors(), configuration.getThreads()); + assertEquals(Runtime.getRuntime().availableProcessors(), configuration.getThreads(), "Default threads"); configuration.setThreads(0); - assertEquals("Changed threads", 0, configuration.getThreads()); + assertEquals(0, configuration.getThreads(), "Changed threads"); } @Test - public void testClassLoader() { + void testClassLoader() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default ClassLoader", PMDConfiguration.class.getClassLoader(), configuration.getClassLoader()); + assertEquals(PMDConfiguration.class.getClassLoader(), configuration.getClassLoader(), "Default ClassLoader"); configuration.prependAuxClasspath("some.jar"); - assertEquals("Prepended ClassLoader class", ClasspathClassLoader.class, - configuration.getClassLoader().getClass()); + assertEquals(ClasspathClassLoader.class, configuration.getClassLoader().getClass(), + "Prepended ClassLoader class"); URL[] urls = ((ClasspathClassLoader) configuration.getClassLoader()).getURLs(); - assertEquals("urls length", 1, urls.length); - assertTrue("url[0]", urls[0].toString().endsWith("/some.jar")); - assertEquals("parent classLoader", PMDConfiguration.class.getClassLoader(), - configuration.getClassLoader().getParent()); + assertEquals(1, urls.length, "urls length"); + assertTrue(urls[0].toString().endsWith("/some.jar"), "url[0]"); + assertEquals(PMDConfiguration.class.getClassLoader(), configuration.getClassLoader().getParent(), + "parent classLoader"); configuration.setClassLoader(null); - assertEquals("Revert to default ClassLoader", PMDConfiguration.class.getClassLoader(), - configuration.getClassLoader()); + assertEquals(PMDConfiguration.class.getClassLoader(), configuration.getClassLoader(), + "Revert to default ClassLoader"); } @Test - public void auxClasspathWithRelativeFileEmpty() { + void auxClasspathWithRelativeFileEmpty() { String relativeFilePath = "src/test/resources/net/sourceforge/pmd/cli/auxclasspath-empty.cp"; PMDConfiguration configuration = new PMDConfiguration(); configuration.prependAuxClasspath("file:" + relativeFilePath); URL[] urls = ((ClasspathClassLoader) configuration.getClassLoader()).getURLs(); - Assert.assertEquals(0, urls.length); + assertEquals(0, urls.length); } @Test - public void auxClasspathWithRelativeFileEmpty2() { + void auxClasspathWithRelativeFileEmpty2() { String relativeFilePath = "./src/test/resources/net/sourceforge/pmd/cli/auxclasspath-empty.cp"; PMDConfiguration configuration = new PMDConfiguration(); configuration.prependAuxClasspath("file:" + relativeFilePath); URL[] urls = ((ClasspathClassLoader) configuration.getClassLoader()).getURLs(); - Assert.assertEquals(0, urls.length); + assertEquals(0, urls.length); } @Test - public void auxClasspathWithRelativeFile() throws URISyntaxException { + void auxClasspathWithRelativeFile() throws URISyntaxException { final String FILE_SCHEME = "file"; String currentWorkingDirectory = new File("").getAbsoluteFile().toURI().getPath(); @@ -113,21 +110,21 @@ public class PmdConfigurationTest { new URI(FILE_SCHEME, null, currentWorkingDirectory, null), new URI(FILE_SCHEME, null, currentWorkingDirectory + "relative source dir/bar", null), }; - Assert.assertArrayEquals(expectedUris, uris); + assertArrayEquals(expectedUris, uris); } @Test - public void testRuleSetsLegacy() { + void testRuleSetsLegacy() { PMDConfiguration configuration = new PMDConfiguration(); - assertNull("Default RuleSets", configuration.getRuleSets()); + assertNull(configuration.getRuleSets(), "Default RuleSets"); configuration.setRuleSets("/rulesets/basic.xml"); - assertEquals("Changed RuleSets", "/rulesets/basic.xml", configuration.getRuleSets()); + assertEquals("/rulesets/basic.xml", configuration.getRuleSets(), "Changed RuleSets"); configuration.setRuleSets((String) null); assertNull(configuration.getRuleSets()); } @Test - public void testRuleSets() { + void testRuleSets() { PMDConfiguration configuration = new PMDConfiguration(); assertThat(configuration.getRuleSetPaths(), empty()); configuration.setRuleSets(listOf("/rulesets/basic.xml")); @@ -142,151 +139,153 @@ public class PmdConfigurationTest { } @Test - public void testMinimumPriority() { + void testMinimumPriority() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default minimum priority", RulePriority.LOW, configuration.getMinimumPriority()); + assertEquals(RulePriority.LOW, configuration.getMinimumPriority(), "Default minimum priority"); configuration.setMinimumPriority(RulePriority.HIGH); - assertEquals("Changed minimum priority", RulePriority.HIGH, configuration.getMinimumPriority()); + assertEquals(RulePriority.HIGH, configuration.getMinimumPriority(), "Changed minimum priority"); } @Test - public void testSourceEncoding() { + void testSourceEncoding() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default source encoding", System.getProperty("file.encoding"), configuration.getSourceEncoding().name()); + assertEquals(System.getProperty("file.encoding"), configuration.getSourceEncoding().name(), "Default source encoding"); configuration.setSourceEncoding(StandardCharsets.UTF_16LE.name()); - assertEquals("Changed source encoding", StandardCharsets.UTF_16LE, configuration.getSourceEncoding()); + assertEquals(StandardCharsets.UTF_16LE, configuration.getSourceEncoding(), "Changed source encoding"); } @Test - public void testInputPaths() { + void testInputPaths() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default input paths", null, configuration.getInputPaths()); + assertEquals(null, configuration.getInputPaths(), "Default input paths"); configuration.setInputPaths("a,b,c"); - assertEquals("Changed input paths", "a,b,c", configuration.getInputPaths()); + assertEquals("a,b,c", configuration.getInputPaths(), "Changed input paths"); } @Test - public void testReportShortNames() { + void testReportShortNames() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default report short names", false, configuration.isReportShortNames()); + assertEquals(false, configuration.isReportShortNames(), "Default report short names"); configuration.setReportShortNames(true); - assertEquals("Changed report short names", true, configuration.isReportShortNames()); + assertEquals(true, configuration.isReportShortNames(), "Changed report short names"); } @Test - public void testReportFormat() { + void testReportFormat() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default report format", null, configuration.getReportFormat()); + assertEquals(null, configuration.getReportFormat(), "Default report format"); configuration.setReportFormat("csv"); - assertEquals("Changed report format", "csv", configuration.getReportFormat()); + assertEquals("csv", configuration.getReportFormat(), "Changed report format"); } @Test - public void testCreateRenderer() { + void testCreateRenderer() { PMDConfiguration configuration = new PMDConfiguration(); configuration.setReportFormat("csv"); Renderer renderer = configuration.createRenderer(); - assertEquals("Renderer class", CSVRenderer.class, renderer.getClass()); - assertEquals("Default renderer show suppressed violations", false, renderer.isShowSuppressedViolations()); + assertEquals(CSVRenderer.class, renderer.getClass(), "Renderer class"); + assertEquals(false, renderer.isShowSuppressedViolations(), "Default renderer show suppressed violations"); configuration.setShowSuppressedViolations(true); renderer = configuration.createRenderer(); - assertEquals("Renderer class", CSVRenderer.class, renderer.getClass()); - assertEquals("Changed renderer show suppressed violations", true, renderer.isShowSuppressedViolations()); + assertEquals(CSVRenderer.class, renderer.getClass(), "Renderer class"); + assertEquals(true, renderer.isShowSuppressedViolations(), "Changed renderer show suppressed violations"); } @Test - public void testReportFile() { + void testReportFile() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default report file", null, configuration.getReportFile()); + assertEquals(null, configuration.getReportFile(), "Default report file"); configuration.setReportFile("somefile"); - assertEquals("Changed report file", "somefile", configuration.getReportFile()); + assertEquals("somefile", configuration.getReportFile(), "Changed report file"); } @Test - public void testShowSuppressedViolations() { + void testShowSuppressedViolations() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default show suppressed violations", false, configuration.isShowSuppressedViolations()); + assertEquals(false, configuration.isShowSuppressedViolations(), "Default show suppressed violations"); configuration.setShowSuppressedViolations(true); - assertEquals("Changed show suppressed violations", true, configuration.isShowSuppressedViolations()); + assertEquals(true, configuration.isShowSuppressedViolations(), "Changed show suppressed violations"); } @Test - public void testReportProperties() { + void testReportProperties() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default report properties size", 0, configuration.getReportProperties().size()); + assertEquals(0, configuration.getReportProperties().size(), "Default report properties size"); configuration.getReportProperties().put("key", "value"); - assertEquals("Changed report properties size", 1, configuration.getReportProperties().size()); - assertEquals("Changed report properties value", "value", configuration.getReportProperties().get("key")); + assertEquals(1, configuration.getReportProperties().size(), "Changed report properties size"); + assertEquals("value", configuration.getReportProperties().get("key"), "Changed report properties value"); configuration.setReportProperties(new Properties()); - assertEquals("Replaced report properties size", 0, configuration.getReportProperties().size()); + assertEquals(0, configuration.getReportProperties().size(), "Replaced report properties size"); } @Test - public void testDebug() { + void testDebug() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default debug", false, configuration.isDebug()); + assertEquals(false, configuration.isDebug(), "Default debug"); configuration.setDebug(true); - assertEquals("Changed debug", true, configuration.isDebug()); + assertEquals(true, configuration.isDebug(), "Changed debug"); } @Test - public void testStressTest() { + void testStressTest() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default stress test", false, configuration.isStressTest()); + assertEquals(false, configuration.isStressTest(), "Default stress test"); configuration.setStressTest(true); - assertEquals("Changed stress test", true, configuration.isStressTest()); + assertEquals(true, configuration.isStressTest(), "Changed stress test"); } @Test - public void testBenchmark() { + void testBenchmark() { PMDConfiguration configuration = new PMDConfiguration(); - assertEquals("Default benchmark", false, configuration.isBenchmark()); + assertEquals(false, configuration.isBenchmark(), "Default benchmark"); configuration.setBenchmark(true); - assertEquals("Changed benchmark", true, configuration.isBenchmark()); + assertEquals(true, configuration.isBenchmark(), "Changed benchmark"); } @Test - public void testAnalysisCache() throws IOException { + void testAnalysisCache(@TempDir Path folder) throws IOException { final PMDConfiguration configuration = new PMDConfiguration(); - assertNotNull("Default cache is null", configuration.getAnalysisCache()); - assertTrue("Default cache is not a noop", configuration.getAnalysisCache() instanceof NoopAnalysisCache); + assertNotNull(configuration.getAnalysisCache(), "Default cache is null"); + assertTrue(configuration.getAnalysisCache() instanceof NoopAnalysisCache, "Default cache is not a noop"); configuration.setAnalysisCache(null); - assertNotNull("Default cache was set to null", configuration.getAnalysisCache()); + assertNotNull(configuration.getAnalysisCache(), "Default cache was set to null"); - final File cacheFile = folder.newFile(); + final File cacheFile = folder.resolve("pmd-cachefile").toFile(); + assertTrue(cacheFile.createNewFile()); final FileAnalysisCache analysisCache = new FileAnalysisCache(cacheFile); configuration.setAnalysisCache(analysisCache); - assertSame("Configured cache not stored", analysisCache, configuration.getAnalysisCache()); + assertSame(analysisCache, configuration.getAnalysisCache(), "Configured cache not stored"); } @Test - public void testAnalysisCacheLocation() { + void testAnalysisCacheLocation() { final PMDConfiguration configuration = new PMDConfiguration(); configuration.setAnalysisCacheLocation(null); - assertNotNull("Null cache location accepted", configuration.getAnalysisCache()); - assertTrue("Null cache location accepted", configuration.getAnalysisCache() instanceof NoopAnalysisCache); + assertNotNull(configuration.getAnalysisCache(), "Null cache location accepted"); + assertTrue(configuration.getAnalysisCache() instanceof NoopAnalysisCache, "Null cache location accepted"); configuration.setAnalysisCacheLocation("pmd.cache"); - assertNotNull("Not null cache location produces null cache", configuration.getAnalysisCache()); - assertTrue("File cache location doesn't produce a file cache", - configuration.getAnalysisCache() instanceof FileAnalysisCache); + assertNotNull(configuration.getAnalysisCache(), "Not null cache location produces null cache"); + assertTrue(configuration.getAnalysisCache() instanceof FileAnalysisCache, + "File cache location doesn't produce a file cache"); } @Test - public void testIgnoreIncrementalAnalysis() throws IOException { + void testIgnoreIncrementalAnalysis(@TempDir Path folder) throws IOException { final PMDConfiguration configuration = new PMDConfiguration(); // set dummy cache location - final File cacheFile = folder.newFile(); + final File cacheFile = folder.resolve("pmd-cachefile").toFile(); + assertTrue(cacheFile.createNewFile()); final FileAnalysisCache analysisCache = new FileAnalysisCache(cacheFile); configuration.setAnalysisCache(analysisCache); - assertNotNull("Null cache location accepted", configuration.getAnalysisCache()); - assertFalse("Non null cache location, cache should not be noop", configuration.getAnalysisCache() instanceof NoopAnalysisCache); + assertNotNull(configuration.getAnalysisCache(), "Null cache location accepted"); + assertFalse(configuration.getAnalysisCache() instanceof NoopAnalysisCache, "Non null cache location, cache should not be noop"); configuration.setIgnoreIncrementalAnalysis(true); - assertTrue("Ignoring incremental analysis should turn the cache into a noop", configuration.getAnalysisCache() instanceof NoopAnalysisCache); + assertTrue(configuration.getAnalysisCache() instanceof NoopAnalysisCache, "Ignoring incremental analysis should turn the cache into a noop"); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java index 37478a1e90..693736776b 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/ReportTest.java @@ -6,14 +6,14 @@ package net.sourceforge.pmd; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.StringWriter; import java.util.function.Consumer; import org.checkerframework.checker.nullness.qual.NonNull; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; @@ -31,7 +31,7 @@ public class ReportTest { // Files are grouped together now. @Test - public void testSortedReportFile() { + void testSortedReportFile() { Renderer rend = new XMLRenderer(); String result = render(rend, r -> { FileLocation s = getNode(10, 5, "foo"); @@ -43,11 +43,11 @@ public class ReportTest { }); assertThat(result, containsString("bar")); assertThat(result, containsString("foo")); - assertTrue("sort order wrong", result.indexOf("bar") < result.indexOf("foo")); + assertTrue(result.indexOf("bar") < result.indexOf("foo"), "sort order wrong"); } @Test - public void testSortedReportLine() { + void testSortedReportLine() { Renderer rend = new XMLRenderer(); String result = render(rend, r -> { FileLocation node1 = getNode(20, 5, "foo1"); // line 20: after rule2 violation @@ -58,11 +58,11 @@ public class ReportTest { Rule rule2 = new MockRule("rule2", "rule2", "msg", "rulesetname"); r.onRuleViolation(violation(rule2, node2)); // same file!! }); - assertTrue("sort order wrong", result.indexOf("rule2") < result.indexOf("rule1")); + assertTrue(result.indexOf("rule2") < result.indexOf("rule1"), "sort order wrong"); } @Test - public void testIterator() { + void testIterator() { Rule rule = new MockRule("name", "desc", "msg", "rulesetname"); FileLocation loc1 = getNode(5, 5, "file1"); FileLocation loc2 = getNode(5, 6, "file1"); @@ -75,7 +75,7 @@ public class ReportTest { } @Test - public void testFilterViolations() { + void testFilterViolations() { Rule rule = new MockRule("name", "desc", "msg", "rulesetname"); FileLocation loc1 = getNode(5, 5, "file1"); FileLocation loc2 = getNode(5, 6, "file1"); @@ -91,7 +91,7 @@ public class ReportTest { } @Test - public void testUnion() { + void testUnion() { Rule rule = new MockRule("name", "desc", "msg", "rulesetname"); FileLocation loc1 = getNode(1, 2, "file1"); Report report1 = Report.buildReport(it -> it.onRuleViolation(violation(rule, loc1))); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java index a24170661a..4ca4140edd 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleContextTest.java @@ -4,10 +4,11 @@ package net.sourceforge.pmd; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.util.function.BiConsumer; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; import net.sourceforge.pmd.lang.ast.Node; @@ -16,7 +17,7 @@ import net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil; public class RuleContextTest { - public static Report getReport(Rule rule, BiConsumer sideEffects) { + static Report getReport(Rule rule, BiConsumer sideEffects) { return Report.buildReport(listener -> sideEffects.accept(rule, RuleContext.create(listener, rule))); } @@ -24,29 +25,29 @@ public class RuleContextTest { return getReport(rule, (r, ctx) -> r.apply(node, ctx)); } - public static Report getReportForRuleSetApply(RuleSet ruleset, RootNode node) { + static Report getReportForRuleSetApply(RuleSet ruleset, RootNode node) { return Report.buildReport(listener -> new RuleSets(ruleset).apply(node, listener)); } @Test - public void testMessage() throws Exception { + void testMessage() throws Exception { Report report = getReport(new FooRule(), (r, ctx) -> ctx.addViolationWithMessage(DummyTreeUtil.tree(DummyTreeUtil::root), "message with \"'{'\"")); - Assert.assertEquals("message with \"{\"", report.getViolations().get(0).getDescription()); + assertEquals("message with \"{\"", report.getViolations().get(0).getDescription()); } @Test - public void testMessageEscaping() throws Exception { + void testMessageEscaping() throws Exception { RuleViolation violation = makeViolation("message with \"'{'\""); - Assert.assertEquals("message with \"{\"", violation.getDescription()); + assertEquals("message with \"{\"", violation.getDescription()); } @Test - public void testMessageEscaping2() throws Exception { + void testMessageEscaping2() throws Exception { RuleViolation violation = makeViolation("message with ${ohio}"); - Assert.assertEquals("message with ${ohio}", violation.getDescription()); + assertEquals("message with ${ohio}", violation.getDescription()); } private RuleViolation makeViolation(String unescapedMessage, Object... args) throws Exception { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleReferenceTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleReferenceTest.java index 93e61596e2..ea0255adac 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleReferenceTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleReferenceTest.java @@ -4,13 +4,13 @@ package net.sourceforge.pmd; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.Dummy2LanguageModule; import net.sourceforge.pmd.lang.DummyLanguageModule; @@ -21,18 +21,18 @@ import net.sourceforge.pmd.lang.rule.RuleReference; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; -public class RuleReferenceTest { +class RuleReferenceTest { @Test - public void testRuleSetReference() { + void testRuleSetReference() { RuleReference ruleReference = new RuleReference(); RuleSetReference ruleSetReference = new RuleSetReference("somename"); ruleReference.setRuleSetReference(ruleSetReference); - assertEquals("Not same rule set reference", ruleSetReference, ruleReference.getRuleSetReference()); + assertEquals(ruleSetReference, ruleReference.getRuleSetReference(), "Not same rule set reference"); } @Test - public void testOverride() { + void testOverride() { final PropertyDescriptor PROPERTY1_DESCRIPTOR = PropertyFactory.stringProperty("property1").desc("Test property").defaultValue("").build(); MockRule rule = new MockRule(); rule.definePropertyDescriptor(PROPERTY1_DESCRIPTOR); @@ -66,7 +66,7 @@ public class RuleReferenceTest { } @Test - public void testLanguageOverrideDisallowed() { + void testLanguageOverrideDisallowed() { MockRule rule = new MockRule(); Language dummyLang = LanguageRegistry.getLanguage(DummyLanguageModule.NAME); rule.setLanguage(dummyLang); @@ -74,16 +74,16 @@ public class RuleReferenceTest { RuleReference ruleReference = new RuleReference(); ruleReference.setRule(rule); - Assert.assertThrows(UnsupportedOperationException.class, () -> ruleReference.setLanguage(LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME))); - Assert.assertEquals(dummyLang, ruleReference.getLanguage()); - Assert.assertThrows(IllegalArgumentException.class, () -> ruleReference.setMaximumLanguageVersion(LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME).getVersion("1.0"))); - Assert.assertEquals(rule.getMaximumLanguageVersion(), ruleReference.getOverriddenMaximumLanguageVersion()); - Assert.assertThrows(IllegalArgumentException.class, () -> ruleReference.setMinimumLanguageVersion(LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME).getVersion("1.0"))); - Assert.assertEquals(rule.getMinimumLanguageVersion(), ruleReference.getMinimumLanguageVersion()); + assertThrows(UnsupportedOperationException.class, () -> ruleReference.setLanguage(LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME))); + assertEquals(dummyLang, ruleReference.getLanguage()); + assertThrows(IllegalArgumentException.class, () -> ruleReference.setMaximumLanguageVersion(LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME).getVersion("1.0"))); + assertEquals(rule.getMaximumLanguageVersion(), ruleReference.getOverriddenMaximumLanguageVersion()); + assertThrows(IllegalArgumentException.class, () -> ruleReference.setMinimumLanguageVersion(LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME).getVersion("1.0"))); + assertEquals(rule.getMinimumLanguageVersion(), ruleReference.getMinimumLanguageVersion()); } @Test - public void testDeepCopyOverride() { + void testDeepCopyOverride() { final PropertyDescriptor PROPERTY1_DESCRIPTOR = PropertyFactory.stringProperty("property1").desc("Test property").defaultValue("").build(); MockRule rule = new MockRule(); rule.definePropertyDescriptor(PROPERTY1_DESCRIPTOR); @@ -119,61 +119,61 @@ public class RuleReferenceTest { private void validateOverriddenValues(final PropertyDescriptor propertyDescriptor1, final PropertyDescriptor propertyDescriptor2, RuleReference ruleReference) { - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME), - ruleReference.getLanguage()); + assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME), ruleReference.getLanguage(), + "Override failed"); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), - ruleReference.getMinimumLanguageVersion()); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), - ruleReference.getOverriddenMinimumLanguageVersion()); + assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), ruleReference.getMinimumLanguageVersion(), + "Override failed"); + assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), ruleReference.getOverriddenMinimumLanguageVersion(), + "Override failed"); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), - ruleReference.getMaximumLanguageVersion()); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), - ruleReference.getOverriddenMaximumLanguageVersion()); + assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), ruleReference.getMaximumLanguageVersion(), + "Override failed"); + assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), ruleReference.getOverriddenMaximumLanguageVersion(), + "Override failed"); - assertEquals("Override failed", false, ruleReference.getRule().isDeprecated()); - assertEquals("Override failed", true, ruleReference.isDeprecated()); - assertEquals("Override failed", true, ruleReference.isOverriddenDeprecated()); + assertEquals(false, ruleReference.getRule().isDeprecated(), "Override failed"); + assertEquals(true, ruleReference.isDeprecated(), "Override failed"); + assertEquals(true, ruleReference.isOverriddenDeprecated(), "Override failed"); - assertEquals("Override failed", "name2", ruleReference.getName()); - assertEquals("Override failed", "name2", ruleReference.getOverriddenName()); + assertEquals("name2", ruleReference.getName(), "Override failed"); + assertEquals("name2", ruleReference.getOverriddenName(), "Override failed"); - assertEquals("Override failed", "value2", ruleReference.getProperty(propertyDescriptor1)); - assertEquals("Override failed", "value3", ruleReference.getProperty(propertyDescriptor2)); - assertTrue("Override failed", ruleReference.getPropertyDescriptors().contains(propertyDescriptor1)); - assertTrue("Override failed", ruleReference.getPropertyDescriptors().contains(propertyDescriptor2)); - assertFalse("Override failed", ruleReference.getOverriddenPropertyDescriptors().contains(propertyDescriptor1)); - assertTrue("Override failed", ruleReference.getOverriddenPropertyDescriptors().contains(propertyDescriptor2)); - assertTrue("Override failed", - ruleReference.getPropertiesByPropertyDescriptor().containsKey(propertyDescriptor1)); - assertTrue("Override failed", - ruleReference.getPropertiesByPropertyDescriptor().containsKey(propertyDescriptor2)); - assertTrue("Override failed", - ruleReference.getOverriddenPropertiesByPropertyDescriptor().containsKey(propertyDescriptor1)); - assertTrue("Override failed", - ruleReference.getOverriddenPropertiesByPropertyDescriptor().containsKey(propertyDescriptor2)); + assertEquals("value2", ruleReference.getProperty(propertyDescriptor1), "Override failed"); + assertEquals("value3", ruleReference.getProperty(propertyDescriptor2), "Override failed"); + assertTrue(ruleReference.getPropertyDescriptors().contains(propertyDescriptor1), "Override failed"); + assertTrue(ruleReference.getPropertyDescriptors().contains(propertyDescriptor2), "Override failed"); + assertFalse(ruleReference.getOverriddenPropertyDescriptors().contains(propertyDescriptor1), "Override failed"); + assertTrue(ruleReference.getOverriddenPropertyDescriptors().contains(propertyDescriptor2), "Override failed"); + assertTrue(ruleReference.getPropertiesByPropertyDescriptor().containsKey(propertyDescriptor1), + "Override failed"); + assertTrue(ruleReference.getPropertiesByPropertyDescriptor().containsKey(propertyDescriptor2), + "Override failed"); + assertTrue(ruleReference.getOverriddenPropertiesByPropertyDescriptor().containsKey(propertyDescriptor1), + "Override failed"); + assertTrue(ruleReference.getOverriddenPropertiesByPropertyDescriptor().containsKey(propertyDescriptor2), + "Override failed"); - assertEquals("Override failed", "message2", ruleReference.getMessage()); - assertEquals("Override failed", "message2", ruleReference.getOverriddenMessage()); + assertEquals("message2", ruleReference.getMessage(), "Override failed"); + assertEquals("message2", ruleReference.getOverriddenMessage(), "Override failed"); - assertEquals("Override failed", "description2", ruleReference.getDescription()); - assertEquals("Override failed", "description2", ruleReference.getOverriddenDescription()); + assertEquals("description2", ruleReference.getDescription(), "Override failed"); + assertEquals("description2", ruleReference.getOverriddenDescription(), "Override failed"); - assertEquals("Override failed", 2, ruleReference.getExamples().size()); - assertEquals("Override failed", "example1", ruleReference.getExamples().get(0)); - assertEquals("Override failed", "example2", ruleReference.getExamples().get(1)); - assertEquals("Override failed", "example2", ruleReference.getOverriddenExamples().get(0)); + assertEquals(2, ruleReference.getExamples().size(), "Override failed"); + assertEquals("example1", ruleReference.getExamples().get(0), "Override failed"); + assertEquals("example2", ruleReference.getExamples().get(1), "Override failed"); + assertEquals("example2", ruleReference.getOverriddenExamples().get(0), "Override failed"); - assertEquals("Override failed", "externalInfoUrl2", ruleReference.getExternalInfoUrl()); - assertEquals("Override failed", "externalInfoUrl2", ruleReference.getOverriddenExternalInfoUrl()); + assertEquals("externalInfoUrl2", ruleReference.getExternalInfoUrl(), "Override failed"); + assertEquals("externalInfoUrl2", ruleReference.getOverriddenExternalInfoUrl(), "Override failed"); - assertEquals("Override failed", RulePriority.MEDIUM_HIGH, ruleReference.getPriority()); - assertEquals("Override failed", RulePriority.MEDIUM_HIGH, ruleReference.getOverriddenPriority()); + assertEquals(RulePriority.MEDIUM_HIGH, ruleReference.getPriority(), "Override failed"); + assertEquals(RulePriority.MEDIUM_HIGH, ruleReference.getOverriddenPriority(), "Override failed"); } @Test - public void testNotOverride() { + void testNotOverride() { final PropertyDescriptor PROPERTY1_DESCRIPTOR = PropertyFactory.stringProperty("property1").desc("Test property").defaultValue("").build(); MockRule rule = new MockRule(); rule.definePropertyDescriptor(PROPERTY1_DESCRIPTOR); @@ -204,36 +204,36 @@ public class RuleReferenceTest { ruleReference.setPriority(RulePriority.HIGH); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), - ruleReference.getMinimumLanguageVersion()); - assertNull("Override failed", ruleReference.getOverriddenMinimumLanguageVersion()); + assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.3"), ruleReference.getMinimumLanguageVersion(), + "Override failed"); + assertNull(ruleReference.getOverriddenMinimumLanguageVersion(), "Override failed"); - assertEquals("Override failed", LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), - ruleReference.getMaximumLanguageVersion()); - assertNull("Override failed", ruleReference.getOverriddenMaximumLanguageVersion()); + assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), ruleReference.getMaximumLanguageVersion(), + "Override failed"); + assertNull(ruleReference.getOverriddenMaximumLanguageVersion(), "Override failed"); - assertEquals("Override failed", false, ruleReference.isDeprecated()); - assertNull("Override failed", ruleReference.isOverriddenDeprecated()); + assertEquals(false, ruleReference.isDeprecated(), "Override failed"); + assertNull(ruleReference.isOverriddenDeprecated(), "Override failed"); - assertEquals("Override failed", "name1", ruleReference.getName()); - assertNull("Override failed", ruleReference.getOverriddenName()); + assertEquals("name1", ruleReference.getName(), "Override failed"); + assertNull(ruleReference.getOverriddenName(), "Override failed"); - assertEquals("Override failed", "value1", ruleReference.getProperty(PROPERTY1_DESCRIPTOR)); + assertEquals("value1", ruleReference.getProperty(PROPERTY1_DESCRIPTOR), "Override failed"); - assertEquals("Override failed", "message1", ruleReference.getMessage()); - assertNull("Override failed", ruleReference.getOverriddenMessage()); + assertEquals("message1", ruleReference.getMessage(), "Override failed"); + assertNull(ruleReference.getOverriddenMessage(), "Override failed"); - assertEquals("Override failed", "description1", ruleReference.getDescription()); - assertNull("Override failed", ruleReference.getOverriddenDescription()); + assertEquals("description1", ruleReference.getDescription(), "Override failed"); + assertNull(ruleReference.getOverriddenDescription(), "Override failed"); - assertEquals("Override failed", 1, ruleReference.getExamples().size()); - assertEquals("Override failed", "example1", ruleReference.getExamples().get(0)); - assertNull("Override failed", ruleReference.getOverriddenExamples()); + assertEquals(1, ruleReference.getExamples().size(), "Override failed"); + assertEquals("example1", ruleReference.getExamples().get(0), "Override failed"); + assertNull(ruleReference.getOverriddenExamples(), "Override failed"); - assertEquals("Override failed", "externalInfoUrl1", ruleReference.getExternalInfoUrl()); - assertNull("Override failed", ruleReference.getOverriddenExternalInfoUrl()); + assertEquals("externalInfoUrl1", ruleReference.getExternalInfoUrl(), "Override failed"); + assertNull(ruleReference.getOverriddenExternalInfoUrl(), "Override failed"); - assertEquals("Override failed", RulePriority.HIGH, ruleReference.getPriority()); - assertNull("Override failed", ruleReference.getOverriddenPriority()); + assertEquals(RulePriority.HIGH, ruleReference.getPriority(), "Override failed"); + assertNull(ruleReference.getOverriddenPriority(), "Override failed"); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryCompatibilityTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryCompatibilityTest.java index c397dae645..f9e3c089bb 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryCompatibilityTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryCompatibilityTest.java @@ -1,16 +1,19 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; -public class RuleSetFactoryCompatibilityTest { +import org.junit.jupiter.api.Test; + +class RuleSetFactoryCompatibilityTest { @Test - public void testCorrectOldReference() throws Exception { + void testCorrectOldReference() throws Exception { final String ruleset = "\n" + "\n" + "\n" + "\n" + " { + RuleSet ruleset = loadRuleSetInDir(DIR, "duplicatedRuleReference.xml"); - assertEquals(1, ruleset.getRules().size()); - Rule mockRule = ruleset.getRuleByName("DummyBasicMockRule"); - assertNotNull(mockRule); - assertEquals(RulePriority.MEDIUM, mockRule.getPriority()); - assertTrue(systemErrRule.getLog().contains("The rule DummyBasicMockRule is referenced multiple times in \"Custom Rules\". " - + "Only the last rule configuration is used.")); + assertEquals(1, ruleset.getRules().size()); + Rule mockRule = ruleset.getRuleByName("DummyBasicMockRule"); + assertNotNull(mockRule); + assertEquals(RulePriority.MEDIUM, mockRule.getPriority()); + }); + assertThat(log, containsString( + "The rule DummyBasicMockRule is referenced multiple times in ruleset 'Custom Rules'. " + + "Only the last rule configuration is used")); } @Test - public void duplicatedRuleReferenceWithOverrideShouldNotWarn() { - RuleSet ruleset = loadRuleSet("duplicatedRuleReferenceWithOverride.xml"); + void duplicatedRuleReferenceWithOverrideShouldNotWarn() throws Exception { + String log = SystemLambda.tapSystemErr(() -> { + RuleSet ruleset = loadRuleSetInDir(DIR, "duplicatedRuleReferenceWithOverride.xml"); - assertEquals(2, ruleset.getRules().size()); - Rule mockRule = ruleset.getRuleByName("DummyBasicMockRule"); - assertNotNull(mockRule); - assertEquals(RulePriority.HIGH, mockRule.getPriority()); - assertNotNull(ruleset.getRuleByName("SampleXPathRule")); - assertTrue(systemErrRule.getLog().isEmpty()); + assertEquals(2, ruleset.getRules().size()); + Rule mockRule = ruleset.getRuleByName("DummyBasicMockRule"); + assertNotNull(mockRule); + assertEquals(RulePriority.HIGH, mockRule.getPriority()); + assertNotNull(ruleset.getRuleByName("SampleXPathRule")); + }); + assertTrue(log.isEmpty()); } @Test - public void duplicatedRuleReferenceWithOverrideBeforeShouldNotWarn() { - RuleSet ruleset = loadRuleSet("duplicatedRuleReferenceWithOverrideBefore.xml"); - - assertEquals(2, ruleset.getRules().size()); - Rule mockRule = ruleset.getRuleByName("DummyBasicMockRule"); - assertNotNull(mockRule); - assertEquals(RulePriority.HIGH, mockRule.getPriority()); - assertNotNull(ruleset.getRuleByName("SampleXPathRule")); - assertTrue(systemErrRule.getLog().isEmpty()); + void duplicatedRuleReferenceWithOverrideBeforeShouldNotWarn() throws Exception { + String log = SystemLambda.tapSystemErr(() -> { + RuleSet ruleset = loadRuleSetInDir(DIR, "duplicatedRuleReferenceWithOverrideBefore.xml"); + assertEquals(2, ruleset.getRules().size()); + Rule mockRule = ruleset.getRuleByName("DummyBasicMockRule"); + assertNotNull(mockRule); + assertEquals(RulePriority.HIGH, mockRule.getPriority()); + assertNotNull(ruleset.getRuleByName("SampleXPathRule")); + }); + assertTrue(log.isEmpty()); } @Test - public void multipleDuplicates() { - RuleSet ruleset = loadRuleSet("multipleDuplicates.xml"); + void multipleDuplicates() throws Exception { + String log = SystemLambda.tapSystemErr(() -> { + RuleSet ruleset = loadRuleSetInDir(DIR, "multipleDuplicates.xml"); - assertEquals(2, ruleset.getRules().size()); - Rule mockRule = ruleset.getRuleByName("DummyBasicMockRule"); - assertNotNull(mockRule); - assertEquals(RulePriority.MEDIUM_HIGH, mockRule.getPriority()); - assertNotNull(ruleset.getRuleByName("SampleXPathRule")); - assertTrue(systemErrRule.getLog().contains("The rule DummyBasicMockRule is referenced multiple times in \"Custom Rules\". " - + "Only the last rule configuration is used.")); - assertTrue(systemErrRule.getLog().contains("The ruleset rulesets/dummy/basic.xml is referenced multiple times in \"Custom Rules\".")); + assertEquals(2, ruleset.getRules().size()); + Rule mockRule = ruleset.getRuleByName("DummyBasicMockRule"); + assertNotNull(mockRule); + assertEquals(RulePriority.MEDIUM_HIGH, mockRule.getPriority()); + assertNotNull(ruleset.getRuleByName("SampleXPathRule")); + }); + assertThat(log, containsString("The rule DummyBasicMockRule is referenced multiple times in ruleset 'Custom Rules'. Only the last rule configuration is used.")); + assertThat(log, containsString("The ruleset rulesets/dummy/basic.xml is referenced multiple times in ruleset 'Custom Rules'")); } - private RuleSet loadRuleSet(String ruleSetFilename) { - return new RuleSetLoader().loadFromResource("net/sourceforge/pmd/rulesets/duplicatedRuleLoggingTest/" + ruleSetFilename); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryMessagesTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryMessagesTest.java new file mode 100644 index 0000000000..05538f6c2b --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryMessagesTest.java @@ -0,0 +1,36 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; + +import org.junit.jupiter.api.Test; + +import com.github.stefanbirkner.systemlambda.SystemLambda; + +public class RuleSetFactoryMessagesTest extends RulesetFactoryTestBase { + + @Test + public void testFullMessage() throws Exception { + String log = SystemLambda.tapSystemErr(() -> assertCannotParse( + rulesetXml( + dummyRule( + priority("not a priority") + ) + ) + )); + + assertThat(log, containsString( + "Error at dummyRuleset.xml:9:1\n" + + " 7| \n" + + " 8| \n" + + " 9| not a priority\n" + + " ^^^^^^^^^ Not a valid priority: 'not a priority', expected a number in [1,5]" + )); + } + + +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java index 21eb127a96..1bc73cc21e 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -1,64 +1,60 @@ -/** +/* * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.DEPRECATED; +import static net.sourceforge.pmd.util.internal.xml.SchemaConstants.NAME; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.InputStream; import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import org.apache.commons.lang3.StringUtils; -import org.junit.Assert; -import org.junit.Test; -import org.junit.contrib.java.lang.system.SystemErrRule; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; -import net.sourceforge.pmd.junit.LocaleRule; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.rule.MockRule; import net.sourceforge.pmd.lang.rule.RuleReference; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.util.ResourceLoader; +import net.sourceforge.pmd.util.internal.xml.SchemaConstants; -public class RuleSetFactoryTest { +import com.github.stefanbirkner.systemlambda.SystemLambda; - @org.junit.Rule - public LocaleRule localeRule = LocaleRule.en(); - - @org.junit.Rule - public final SystemErrRule systemErrRule = new SystemErrRule().muteForSuccessfulTests().enableLog(); +class RuleSetFactoryTest extends RulesetFactoryTestBase { @Test - public void testRuleSetFileName() { + void testRuleSetFileName() { RuleSet rs = new RuleSetLoader().loadFromString("dummyRuleset.xml", EMPTY_RULESET); assertEquals("dummyRuleset.xml", rs.getFileName()); rs = new RuleSetLoader().loadFromResource("net/sourceforge/pmd/TestRuleset1.xml"); - assertEquals("wrong RuleSet file name", rs.getFileName(), "net/sourceforge/pmd/TestRuleset1.xml"); + assertEquals(rs.getFileName(), "net/sourceforge/pmd/TestRuleset1.xml", "wrong RuleSet file name"); } @Test - public void testRefs() { + void testRefs() { RuleSet rs = new RuleSetLoader().loadFromResource("net/sourceforge/pmd/TestRuleset1.xml"); assertNotNull(rs.getRuleByName("TestRuleRef")); } @Test - public void testExtendedReferences() throws Exception { + void testExtendedReferences() throws Exception { InputStream in = new ResourceLoader().loadClassPathResourceAsStream("net/sourceforge/pmd/rulesets/reference-ruleset.xml"); - assertNotNull("Test ruleset not found - can't continue with test!", in); + assertNotNull(in, "Test ruleset not found - can't continue with test!"); in.close(); RuleSet rs = new RuleSetLoader().loadFromResource("net/sourceforge/pmd/rulesets/reference-ruleset.xml"); @@ -107,19 +103,19 @@ public class RuleSetFactoryTest { } @Test - public void testRuleSetNotFound() { + void testRuleSetNotFound() { assertThrows(RuleSetLoadException.class, () -> new RuleSetLoader().loadFromResource("fooooo")); } @Test - public void testCreateEmptyRuleSet() { + void testCreateEmptyRuleSet() { RuleSet rs = loadRuleSet(EMPTY_RULESET); - assertEquals("test", rs.getName()); + assertEquals("Custom ruleset", rs.getName()); assertEquals(0, rs.size()); } @Test - public void testSingleRule() { + void testSingleRule() { RuleSet rs = loadRuleSet(SINGLE_RULE); assertEquals(1, rs.size()); Rule r = rs.getRules().iterator().next(); @@ -129,8 +125,25 @@ public class RuleSetFactoryTest { } @Test - public void testMultipleRules() { - RuleSet rs = loadRuleSet(MULTIPLE_RULES); + void testSingleRuleEmptyRef() throws Exception { + String log = SystemLambda.tapSystemErr(() -> { + RuleSet rs = loadRuleSet(SINGLE_RULE_EMPTY_REF); + assertEquals(1, rs.size()); + + Rule r = rs.getRules().iterator().next(); + assertEquals("MockRuleName", r.getName()); + assertEquals("net.sourceforge.pmd.lang.rule.MockRule", r.getRuleClass()); + assertEquals("avoid the mock rule", r.getMessage()); + }); + assertThat(log, containsString("Empty ref attribute")); + } + + @Test + void testMultipleRules() { + RuleSet rs = loadRuleSet(rulesetXml( + dummyRule(attrs -> attrs.put(NAME, "MockRuleName1")), + dummyRule(attrs -> attrs.put(NAME, "MockRuleName2")) + )); assertEquals(2, rs.size()); Set expected = new HashSet<>(); expected.add("MockRuleName1"); @@ -141,12 +154,18 @@ public class RuleSetFactoryTest { } @Test - public void testSingleRuleWithPriority() { - assertEquals(RulePriority.MEDIUM, loadFirstRule(PRIORITY).getPriority()); + void testSingleRuleWithPriority() { + Rule rule = loadFirstRule(rulesetXml( + rule( + dummyRuleDefAttrs(), + priority("3") + ) + )); + assertEquals(RulePriority.MEDIUM, rule.getPriority()); } @Test - public void testProps() { + void testProps() { Rule r = loadFirstRule(PROPERTIES); assertEquals("bar", r.getProperty(r.getPropertyDescriptor("fooString"))); assertEquals(3, r.getProperty(r.getPropertyDescriptor("fooInt"))); @@ -157,7 +176,7 @@ public class RuleSetFactoryTest { } @Test - public void testStringMultiPropertyDefaultDelimiter() { + void testStringMultiPropertyDefaultDelimiter() { Rule r = loadFirstRule( "\n\n Desc\n" + " \n" + "\n " - + " ruleset desc\n " - + "\n" - + " Please move your class to the right folder(rest \nfolder)\n" - + " 2\n \n \n" - + " " + ""); + + " ruleset desc\n " + + "\n" + + " Please move your class to the right folder(rest \nfolder)\n" + + " 2\n \n \n" + + " " + ""); Object propValue = r.getProperty(r.getPropertyDescriptor("packageRegEx")); assertEquals(Arrays.asList("com.aptsssss", "com.abc"), propValue); } @Test - public void testRuleSetWithDeprecatedRule() { + void testRuleSetWithDeprecatedRule() { RuleSet rs = loadRuleSet("\n" + "\n" + " ruleset desc\n" + " " @@ -210,20 +229,22 @@ public class RuleSetFactoryTest { * */ @Test - public void testRuleSetWithDeprecatedButRenamedRule() { - RuleSet rs = loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " ruleset desc\n" - + " " - + " " - + " d\n" + " 2\n" + " " - + ""); - assertEquals(1, rs.getRules().size()); - Rule rule = rs.getRuleByName("NewName"); - assertNotNull(rule); - assertNull(rs.getRuleByName("OldName")); + void testRuleSetWithDeprecatedButRenamedRule() throws Exception { + SystemLambda.tapSystemErr(() -> { + RuleSet rs = loadRuleSetWithDeprecationWarnings( + "\n" + "\n" + + " ruleset desc\n" + + " " + + " " + + " d\n" + " 2\n" + " " + + ""); + assertEquals(1, rs.getRules().size()); + Rule rule = rs.getRuleByName("NewName"); + assertNotNull(rule); + assertNull(rs.getRuleByName("OldName")); + }); - assertTrue(systemErrRule.getLog().isEmpty()); + verifyNoWarnings(); } /** @@ -236,7 +257,7 @@ public class RuleSetFactoryTest { * */ @Test - public void testRuleSetWithDeprecatedRenamedRuleForDoc() { + void testRuleSetWithDeprecatedRenamedRuleForDoc() { RuleSetLoader loader = new RuleSetLoader().includeDeprecatedRuleReferences(true); RuleSet rs = loader.loadFromString("", "\n" + "\n" @@ -257,18 +278,21 @@ public class RuleSetFactoryTest { * The user should get a deprecation warning. */ @Test - public void testRuleSetReferencesADeprecatedRenamedRule() { - RuleSet rs = loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " ruleset desc\n" - + " " + ""); - assertEquals(1, rs.getRules().size()); - Rule rule = rs.getRuleByName("OldNameOfDummyBasicMockRule"); - assertNotNull(rule); + void testRuleSetReferencesADeprecatedRenamedRule() throws Exception { + SystemLambda.tapSystemErr(() -> { + RuleSet rs = loadRuleSetWithDeprecationWarnings( + "\n" + "\n" + + " ruleset desc\n" + + " " + ""); + assertEquals(1, rs.getRules().size()); + Rule rule = rs.getRuleByName("OldNameOfDummyBasicMockRule"); + assertNotNull(rule); + }); - assertEquals(1, - StringUtils.countMatches(systemErrRule.getLog(), - "WARN net.sourceforge.pmd.RuleSetFactory - Use Rule name rulesets/dummy/basic.xml/DummyBasicMockRule instead of the deprecated Rule name rulesets/dummy/basic.xml/OldNameOfDummyBasicMockRule.")); + verifyFoundAWarningWithMessage( + containing("Use Rule name rulesets/dummy/basic.xml/DummyBasicMockRule " + + "instead of the deprecated Rule name rulesets/dummy/basic.xml/OldNameOfDummyBasicMockRule") + ); } /** @@ -286,16 +310,18 @@ public class RuleSetFactoryTest { * */ @Test - public void testRuleSetReferencesRulesetWithADeprecatedRenamedRule() { - RuleSet rs = loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " ruleset desc\n" - + " " + ""); - assertEquals(2, rs.getRules().size()); - assertNotNull(rs.getRuleByName("DummyBasicMockRule")); - assertNotNull(rs.getRuleByName("SampleXPathRule")); + void testRuleSetReferencesRulesetWithADeprecatedRenamedRule() throws Exception { + SystemLambda.tapSystemErr(() -> { + RuleSet rs = loadRuleSetWithDeprecationWarnings( + "\n" + "\n" + + " ruleset desc\n" + + " " + ""); + assertEquals(2, rs.getRules().size()); + assertNotNull(rs.getRuleByName("DummyBasicMockRule")); + assertNotNull(rs.getRuleByName("SampleXPathRule")); + }); - assertTrue(systemErrRule.getLog().isEmpty()); + verifyNoWarnings(); } /** @@ -314,17 +340,19 @@ public class RuleSetFactoryTest { * */ @Test - public void testRuleSetReferencesRulesetWithAExcludedDeprecatedRule() { - RuleSet rs = loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " ruleset desc\n" - + " " - + ""); - assertEquals(2, rs.getRules().size()); - assertNotNull(rs.getRuleByName("DummyBasicMockRule")); - assertNotNull(rs.getRuleByName("SampleXPathRule")); + void testRuleSetReferencesRulesetWithAExcludedDeprecatedRule() throws Exception { + String log = SystemLambda.tapSystemErr(() -> { + RuleSet rs = loadRuleSetWithDeprecationWarnings( + "\n" + "\n" + + " ruleset desc\n" + + " " + + ""); + assertEquals(2, rs.getRules().size()); + assertNotNull(rs.getRuleByName("DummyBasicMockRule")); + assertNotNull(rs.getRuleByName("SampleXPathRule")); + }); - assertTrue(systemErrRule.getLog().isEmpty()); + assertTrue(log.isEmpty()); } /** @@ -339,22 +367,25 @@ public class RuleSetFactoryTest { * */ @Test - public void testRuleSetReferencesRulesetWithAExcludedNonExistingRule() { - RuleSet rs = loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " ruleset desc\n" - + " " - + ""); - assertEquals(2, rs.getRules().size()); - assertNotNull(rs.getRuleByName("DummyBasicMockRule")); - assertNotNull(rs.getRuleByName("SampleXPathRule")); + void testRuleSetReferencesRulesetWithAExcludedNonExistingRule() throws Exception { + SystemLambda.tapSystemErr(() -> { + RuleSet rs = loadRuleSetWithDeprecationWarnings( + rulesetXml( + rulesetRef("rulesets/dummy/basic.xml", + excludeRule("NonExistingRule")) - assertEquals(0, - StringUtils.countMatches(systemErrRule.getLog(), - "WARN net.sourceforge.pmd.RuleSetFactory - Discontinue using Rule rulesets/dummy/basic.xml/DeprecatedRule as it is scheduled for removal from PMD.")); - assertEquals(1, - StringUtils.countMatches(systemErrRule.getLog(), - "WARN net.sourceforge.pmd.RuleSetFactory - Unable to exclude rules [NonExistingRule] from ruleset reference rulesets/dummy/basic.xml; perhaps the rule name is misspelled or the rule doesn't exist anymore?")); + )); + assertEquals(2, rs.getRules().size()); + assertNotNull(rs.getRuleByName("DummyBasicMockRule")); + assertNotNull(rs.getRuleByName("SampleXPathRule")); + }); + verifyFoundWarningWithMessage( + Mockito.never(), + containing("Discontinue using Rule rulesets/dummy/basic.xml/DeprecatedRule") + ); + verifyFoundAWarningWithMessage(containing( + "Exclude pattern 'NonExistingRule' did not match any rule in ruleset" + )); } /** @@ -362,18 +393,20 @@ public class RuleSetFactoryTest { * considered deprecated and the user should get a deprecation warning for the ruleset. */ @Test - public void testRuleSetReferencesDeprecatedRuleset() { - RuleSet rs = loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " ruleset desc\n" - + " " + ""); - assertEquals(2, rs.getRules().size()); - assertNotNull(rs.getRuleByName("DummyBasicMockRule")); - assertNotNull(rs.getRuleByName("SampleXPathRule")); + void testRuleSetReferencesDeprecatedRuleset() throws Exception { + SystemLambda.tapSystemErr(() -> { + RuleSet rs = loadRuleSetWithDeprecationWarnings( + rulesetXml( + rulesetRef("rulesets/dummy/deprecated.xml") + )); + assertEquals(2, rs.getRules().size()); + assertNotNull(rs.getRuleByName("DummyBasicMockRule")); + assertNotNull(rs.getRuleByName("SampleXPathRule")); + }); - assertEquals(1, - StringUtils.countMatches(systemErrRule.getLog(), - "WARN net.sourceforge.pmd.RuleSetFactory - The RuleSet rulesets/dummy/deprecated.xml has been deprecated and will be removed in PMD")); + verifyFoundAWarningWithMessage(containing( + "The RuleSet rulesets/dummy/deprecated.xml has been deprecated and will be removed in PMD" + )); } /** @@ -382,154 +415,156 @@ public class RuleSetFactoryTest { * no warning about deprecation - since the deprecated rules are not used. */ @Test - public void testRuleSetReferencesRulesetWithAMovedRule() { - RuleSet rs = loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " ruleset desc\n" - + " " + ""); - assertEquals(1, rs.getRules().size()); - assertNotNull(rs.getRuleByName("DummyBasic2MockRule")); + void testRuleSetReferencesRulesetWithAMovedRule() throws Exception { + SystemLambda.tapSystemErr(() -> { + RuleSet rs = loadRuleSetWithDeprecationWarnings( + rulesetXml( + ruleRef("rulesets/dummy/basic2.xml") + ) + ); + assertEquals(1, rs.getRules().size()); + assertNotNull(rs.getRuleByName("DummyBasic2MockRule")); + }); - assertEquals(0, - StringUtils.countMatches(systemErrRule.getLog(), - "WARN net.sourceforge.pmd.RuleSetFactory - Use Rule name rulesets/dummy/basic.xml/DummyBasicMockRule instead of the deprecated Rule name rulesets/dummy/basic2.xml/DummyBasicMockRule. PMD")); + verifyFoundWarningWithMessage( + Mockito.never(), + containing("Use Rule name rulesets/dummy/basic.xml/DummyBasicMockRule instead of the deprecated Rule name rulesets/dummy/basic2.xml/DummyBasicMockRule") + ); } @Test @SuppressWarnings("unchecked") - public void testXPath() { + void testXPath() { Rule r = loadFirstRule(XPATH); PropertyDescriptor xpathProperty = (PropertyDescriptor) r.getPropertyDescriptor("xpath"); - assertNotNull("xpath property descriptor", xpathProperty); - assertNotSame(r.getProperty(xpathProperty).indexOf(" //Block "), -1); + assertNotNull(xpathProperty, "xpath property descriptor"); + assertNotSame(r.getProperty(xpathProperty).indexOf("//Block"), -1); } @Test - public void testExternalReferenceOverride() { + void testExternalReferenceOverride() { Rule r = loadFirstRule(REF_OVERRIDE); assertEquals("TestNameOverride", r.getName()); assertEquals("Test message override", r.getMessage()); assertEquals("Test description override", r.getDescription()); - assertEquals("Test that both example are stored", 2, r.getExamples().size()); + assertEquals(2, r.getExamples().size(), "Test that both example are stored"); assertEquals("Test example override", r.getExamples().get(1)); assertEquals(RulePriority.MEDIUM, r.getPriority()); PropertyDescriptor test2Descriptor = r.getPropertyDescriptor("test2"); - assertNotNull("test2 descriptor", test2Descriptor); + assertNotNull(test2Descriptor, "test2 descriptor"); assertEquals("override2", r.getProperty(test2Descriptor)); PropertyDescriptor test3Descriptor = r.getPropertyDescriptor("test3"); - assertNotNull("test3 descriptor", test3Descriptor); + assertNotNull(test3Descriptor, "test3 descriptor"); assertEquals("override3", r.getProperty(test3Descriptor)); } @Test - public void testExternalReferenceOverrideNonExistent() { - RuleSetLoadException ex = assertCannotParse(REF_OVERRIDE_NONEXISTENT); - - assertThat(ex.getCause().getMessage(), containsString("Cannot set non-existent property 'test4' on Rule TestNameOverride")); - } - - private RuleSetLoadException assertCannotParse(String xmlContent) { - return assertThrows(RuleSetLoadException.class, () -> loadFirstRule(xmlContent)); + void testExternalReferenceOverrideNonExistent() { + assertThrows(RuleSetLoadException.class, + () -> loadFirstRule(REF_OVERRIDE_NONEXISTENT)); + verifyFoundAnErrorWithMessage( + containing("Cannot set non-existent property 'test4' on rule TestNameOverride") + ); } @Test - public void testReferenceInternalToInternal() { + void testReferenceInternalToInternal() { RuleSet ruleSet = loadRuleSet(REF_INTERNAL_TO_INTERNAL); Rule rule = ruleSet.getRuleByName("MockRuleName"); - assertNotNull("Could not find Rule MockRuleName", rule); + assertNotNull(rule, "Could not find Rule MockRuleName"); Rule ruleRef = ruleSet.getRuleByName("MockRuleNameRef"); - assertNotNull("Could not find Rule MockRuleNameRef", ruleRef); + assertNotNull(ruleRef, "Could not find Rule MockRuleNameRef"); } @Test - public void testReferenceInternalToInternalChain() { + void testReferenceInternalToInternalChain() { RuleSet ruleSet = loadRuleSet(REF_INTERNAL_TO_INTERNAL_CHAIN); Rule rule = ruleSet.getRuleByName("MockRuleName"); - assertNotNull("Could not find Rule MockRuleName", rule); + assertNotNull(rule, "Could not find Rule MockRuleName"); Rule ruleRef = ruleSet.getRuleByName("MockRuleNameRef"); - assertNotNull("Could not find Rule MockRuleNameRef", ruleRef); + assertNotNull(ruleRef, "Could not find Rule MockRuleNameRef"); Rule ruleRefRef = ruleSet.getRuleByName("MockRuleNameRefRef"); - assertNotNull("Could not find Rule MockRuleNameRefRef", ruleRefRef); + assertNotNull(ruleRefRef, "Could not find Rule MockRuleNameRefRef"); } @Test - public void testReferenceInternalToExternal() { + void testReferenceInternalToExternal() { RuleSet ruleSet = loadRuleSet(REF_INTERNAL_TO_EXTERNAL); Rule rule = ruleSet.getRuleByName("ExternalRefRuleName"); - assertNotNull("Could not find Rule ExternalRefRuleName", rule); + assertNotNull(rule, "Could not find Rule ExternalRefRuleName"); Rule ruleRef = ruleSet.getRuleByName("ExternalRefRuleNameRef"); - assertNotNull("Could not find Rule ExternalRefRuleNameRef", ruleRef); + assertNotNull(ruleRef, "Could not find Rule ExternalRefRuleNameRef"); } @Test - public void testReferenceInternalToExternalChain() { + void testReferenceInternalToExternalChain() { RuleSet ruleSet = loadRuleSet(REF_INTERNAL_TO_EXTERNAL_CHAIN); Rule rule = ruleSet.getRuleByName("ExternalRefRuleName"); - assertNotNull("Could not find Rule ExternalRefRuleName", rule); + assertNotNull(rule, "Could not find Rule ExternalRefRuleName"); Rule ruleRef = ruleSet.getRuleByName("ExternalRefRuleNameRef"); - assertNotNull("Could not find Rule ExternalRefRuleNameRef", ruleRef); + assertNotNull(ruleRef, "Could not find Rule ExternalRefRuleNameRef"); Rule ruleRefRef = ruleSet.getRuleByName("ExternalRefRuleNameRefRef"); - assertNotNull("Could not find Rule ExternalRefRuleNameRefRef", ruleRefRef); + assertNotNull(ruleRefRef, "Could not find Rule ExternalRefRuleNameRefRef"); } @Test - public void testReferencePriority() { + void testReferencePriority() { RuleSetLoader config = new RuleSetLoader().warnDeprecated(false).enableCompatibility(true); RuleSetLoader rulesetLoader = config.filterAbovePriority(RulePriority.LOW); RuleSet ruleSet = rulesetLoader.loadFromString("", REF_INTERNAL_TO_INTERNAL_CHAIN); - assertEquals("Number of Rules", 3, ruleSet.getRules().size()); + assertEquals(3, ruleSet.getRules().size(), "Number of Rules"); assertNotNull(ruleSet.getRuleByName("MockRuleName")); assertNotNull(ruleSet.getRuleByName("MockRuleNameRef")); assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef")); rulesetLoader = config.filterAbovePriority(RulePriority.MEDIUM_HIGH); ruleSet = rulesetLoader.loadFromString("", REF_INTERNAL_TO_INTERNAL_CHAIN); - assertEquals("Number of Rules", 2, ruleSet.getRules().size()); + assertEquals(2, ruleSet.getRules().size(), "Number of Rules"); assertNotNull(ruleSet.getRuleByName("MockRuleNameRef")); assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef")); rulesetLoader = config.filterAbovePriority(RulePriority.HIGH); ruleSet = rulesetLoader.loadFromString("", REF_INTERNAL_TO_INTERNAL_CHAIN); - assertEquals("Number of Rules", 1, ruleSet.getRules().size()); + assertEquals(1, ruleSet.getRules().size(), "Number of Rules"); assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef")); rulesetLoader = config.filterAbovePriority(RulePriority.LOW); ruleSet = rulesetLoader.loadFromString("", REF_INTERNAL_TO_EXTERNAL_CHAIN); - assertEquals("Number of Rules", 3, ruleSet.getRules().size()); + assertEquals(3, ruleSet.getRules().size(), "Number of Rules"); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleName")); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRef")); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef")); rulesetLoader = config.filterAbovePriority(RulePriority.MEDIUM_HIGH); ruleSet = rulesetLoader.loadFromString("", REF_INTERNAL_TO_EXTERNAL_CHAIN); - assertEquals("Number of Rules", 2, ruleSet.getRules().size()); + assertEquals(2, ruleSet.getRules().size(), "Number of Rules"); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRef")); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef")); rulesetLoader = config.filterAbovePriority(RulePriority.HIGH); ruleSet = rulesetLoader.loadFromString("", REF_INTERNAL_TO_EXTERNAL_CHAIN); - assertEquals("Number of Rules", 1, ruleSet.getRules().size()); + assertEquals(1, ruleSet.getRules().size(), "Number of Rules"); assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef")); } @Test - public void testOverridePriorityLoadWithMinimum() { + void testOverridePriorityLoadWithMinimum() { RuleSetLoader rulesetLoader = new RuleSetLoader().filterAbovePriority(RulePriority.MEDIUM_LOW) .warnDeprecated(true).enableCompatibility(true); RuleSet ruleset = rulesetLoader.loadFromResource("net/sourceforge/pmd/rulesets/ruleset-minimum-priority.xml"); // only one rule should remain, since we filter out the other rule by minimum priority - assertEquals("Number of Rules", 1, ruleset.getRules().size()); + assertEquals(1, ruleset.getRules().size(), "Number of Rules"); // Priority is overridden and applied, rule is missing assertNull(ruleset.getRuleByName("DummyBasicMockRule")); @@ -540,24 +575,24 @@ public class RuleSetFactoryTest { // now, load with default minimum priority rulesetLoader = new RuleSetLoader(); ruleset = rulesetLoader.loadFromResource("net/sourceforge/pmd/rulesets/ruleset-minimum-priority.xml"); - assertEquals("Number of Rules", 2, ruleset.getRules().size()); + assertEquals(2, ruleset.getRules().size(), "Number of Rules"); Rule dummyBasicMockRule = ruleset.getRuleByName("DummyBasicMockRule"); - assertEquals("Wrong Priority", RulePriority.LOW, dummyBasicMockRule.getPriority()); + assertEquals(RulePriority.LOW, dummyBasicMockRule.getPriority(), "Wrong Priority"); } @Test - public void testExcludeWithMinimumPriority() { + void testExcludeWithMinimumPriority() { RuleSetLoader rulesetLoader = new RuleSetLoader().filterAbovePriority(RulePriority.HIGH); RuleSet ruleset = rulesetLoader .loadFromResource("net/sourceforge/pmd/rulesets/ruleset-minimum-priority-exclusion.xml"); // no rules should be loaded - assertEquals("Number of Rules", 0, ruleset.getRules().size()); + assertEquals(0, ruleset.getRules().size(), "Number of Rules"); // now, load with default minimum priority rulesetLoader = new RuleSetLoader().filterAbovePriority(RulePriority.LOW); ruleset = rulesetLoader.loadFromResource("net/sourceforge/pmd/rulesets/ruleset-minimum-priority-exclusion.xml"); // only one rule, we have excluded one... - assertEquals("Number of Rules", 1, ruleset.getRules().size()); + assertEquals(1, ruleset.getRules().size(), "Number of Rules"); // rule is excluded assertNull(ruleset.getRuleByName("DummyBasicMockRule")); // this is the remaining rule @@ -565,24 +600,24 @@ public class RuleSetFactoryTest { } @Test - public void testOverrideMessage() { + void testOverrideMessage() { Rule r = loadFirstRule(REF_OVERRIDE_ORIGINAL_NAME); assertEquals("TestMessageOverride", r.getMessage()); } @Test - public void testOverrideMessageOneElem() { + void testOverrideMessageOneElem() { Rule r = loadFirstRule(REF_OVERRIDE_ORIGINAL_NAME_ONE_ELEM); assertEquals("TestMessageOverride", r.getMessage()); } @Test - public void testIncorrectExternalRef() { + void testIncorrectExternalRef() { assertCannotParse(REF_MISSPELLED_XREF); } @Test - public void testSetPriority() { + void testSetPriority() { RuleSetLoader rulesetLoader = new RuleSetLoader().filterAbovePriority(RulePriority.MEDIUM_HIGH).warnDeprecated(false); assertEquals(0, rulesetLoader.loadFromString("", SINGLE_RULE).size()); rulesetLoader = new RuleSetLoader().filterAbovePriority(RulePriority.MEDIUM_LOW).warnDeprecated(false); @@ -590,33 +625,60 @@ public class RuleSetFactoryTest { } @Test - public void testLanguage() { - Rule r = loadFirstRule(LANGUAGE); + void testLanguage() { + Rule r = loadFirstRule(rulesetXml( + dummyRule( + attrs -> attrs.put(SchemaConstants.LANGUAGE, "dummy") + ) + )); assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME), r.getLanguage()); } @Test - public void testIncorrectLanguage() { - assertCannotParse(INCORRECT_LANGUAGE); + void testIncorrectLanguage() { + assertCannotParse(rulesetXml( + dummyRule( + attrs -> attrs.put(SchemaConstants.LANGUAGE, "bogus") + ) + )); } @Test - public void testMinimumLanguageVersion() { - Rule r = loadFirstRule(MINIMUM_LANGUAGE_VERSION); + void testIncorrectPriority() { + assertCannotParse(rulesetXml( + dummyRule( + priority("not a priority") + ) + )); + verifyFoundAnErrorWithMessage(containing("Not a valid priority: 'not a priority'")); + } + + @Test + void testMinimumLanguageVersion() { + Rule r = loadFirstRule(rulesetXml( + dummyRule( + attrs -> attrs.put(SchemaConstants.MINIMUM_LANGUAGE_VERSION, "1.4") + ) + )); assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.4"), r.getMinimumLanguageVersion()); } @Test - public void testIncorrectMinimumLanguageVersion() { - RuleSetLoadException ex = assertCannotParse(INCORRECT_MINIMUM_LANGUAGE_VERSION); - - assertThat(ex.getCause().getMessage(), containsString("1.0, 1.1, 1.2")); // and not "dummy 1.0, dummy 1.1, ..." - + void testIncorrectMinimumLanguageVersion() { + assertCannotParse(rulesetXml( + dummyRule( + attrs -> attrs.put(SchemaConstants.MINIMUM_LANGUAGE_VERSION, "bogus") + ) + )); + verifyFoundAnErrorWithMessage( + containing("valid language version") + .and(containing("'1.0', '1.1', '1.2'")) // and not "dummy 1.0, dummy 1.1, ..." + ); } @Test - public void testIncorrectMinimumLanguageVersionWithLanguageSetInJava() { + void testIncorrectMinimumLanguageVersionWithLanguageSetInJava() { assertCannotParse("\n" + "\n" + " TODO\n" @@ -628,87 +690,111 @@ public class RuleSetFactoryTest { + " TODO\n" + " 2\n" + " \n" - + "\n" - + ""); + + "\n" + + ""); + + verifyFoundAnErrorWithMessage( + containing("valid language version") + ); } @Test - public void testMaximumLanguageVersion() { - Rule r = loadFirstRule(MAXIMUM_LANGUAGE_VERSION); + void testMaximumLanguageVersion() { + Rule r = loadFirstRule(rulesetXml( + dummyRule(attrs -> attrs.put(SchemaConstants.MAXIMUM_LANGUAGE_VERSION, "1.7")) + )); assertEquals(LanguageRegistry.getLanguage(DummyLanguageModule.NAME).getVersion("1.7"), r.getMaximumLanguageVersion()); } @Test - public void testIncorrectMaximumLanguageVersion() { - RuleSetLoadException ex = assertCannotParse(INCORRECT_MAXIMUM_LANGUAGE_VERSION); - - assertThat(ex.getCause().getMessage(), containsString("1.0, 1.1, 1.2")); // and not "dummy 1.0, dummy 1.1, ..." + void testIncorrectMaximumLanguageVersion() { + assertCannotParse(rulesetXml( + dummyRule(attrs -> attrs.put(SchemaConstants.MAXIMUM_LANGUAGE_VERSION, "bogus")) + )); + verifyFoundAnErrorWithMessage( + containing("valid language version") + .and(containing("'1.0', '1.1', '1.2'")) + ); } @Test - public void testInvertedMinimumMaximumLanguageVersions() { - assertCannotParse(INCORRECT_MAXIMUM_LANGUAGE_VERSION); + void testInvertedMinimumMaximumLanguageVersions() { + assertCannotParse(rulesetXml( + dummyRule( + attrs -> { + attrs.put(SchemaConstants.MINIMUM_LANGUAGE_VERSION, "1.7"); + attrs.put(SchemaConstants.MAXIMUM_LANGUAGE_VERSION, "1.4"); + } + ) + )); + verifyFoundAnErrorWithMessage(containing("version range")); } @Test public void testDirectDeprecatedRule() { - Rule r = loadFirstRule(DIRECT_DEPRECATED_RULE); - assertNotNull("Direct Deprecated Rule", r); + Rule r = loadFirstRule(rulesetXml( + dummyRule(attrs -> attrs.put(DEPRECATED, "true")) + )); + assertNotNull(r, "Direct Deprecated Rule"); assertTrue(r.isDeprecated()); } @Test - public void testReferenceToDeprecatedRule() { + void testReferenceToDeprecatedRule() { Rule r = loadFirstRule(REFERENCE_TO_DEPRECATED_RULE); - assertNotNull("Reference to Deprecated Rule", r); - assertTrue("Rule Reference", r instanceof RuleReference); - assertFalse("Not deprecated", r.isDeprecated()); - assertTrue("Original Rule Deprecated", ((RuleReference) r).getRule().isDeprecated()); - assertEquals("Rule name", r.getName(), DEPRECATED_RULE_NAME); + assertNotNull(r, "Reference to Deprecated Rule"); + assertTrue(r instanceof RuleReference, "Rule Reference"); + assertFalse(r.isDeprecated(), "Not deprecated"); + assertTrue(((RuleReference) r).getRule().isDeprecated(), "Original Rule Deprecated"); + assertEquals(r.getName(), DEPRECATED_RULE_NAME, "Rule name"); } @Test - public void testRuleSetReferenceWithDeprecatedRule() { + void testRuleSetReferenceWithDeprecatedRule() { RuleSet ruleSet = loadRuleSet(REFERENCE_TO_RULESET_WITH_DEPRECATED_RULE); - assertNotNull("RuleSet", ruleSet); - assertFalse("RuleSet empty", ruleSet.getRules().isEmpty()); + assertNotNull(ruleSet, "RuleSet"); + assertFalse(ruleSet.getRules().isEmpty(), "RuleSet empty"); // No deprecated Rules should be loaded when loading an entire RuleSet // by reference - unless it contains only deprecated rules - then all rules would be added Rule r = ruleSet.getRuleByName(DEPRECATED_RULE_NAME); - assertNull("Deprecated Rule Reference", r); + assertNull(r, "Deprecated Rule Reference"); for (Rule rule : ruleSet.getRules()) { - assertFalse("Rule not deprecated", rule.isDeprecated()); + assertFalse(rule.isDeprecated(), "Rule not deprecated"); } } @Test - public void testDeprecatedRuleSetReference() { + void testDeprecatedRuleSetReference() { RuleSet ruleSet = new RuleSetLoader().loadFromResource("net/sourceforge/pmd/rulesets/ruleset-deprecated.xml"); assertEquals(2, ruleSet.getRules().size()); } @Test - public void testExternalReferences() { - RuleSet rs = loadRuleSet(EXTERNAL_REFERENCE_RULE_SET); + void testExternalReferences() { + RuleSet rs = loadRuleSet( + rulesetXml( + ruleRef("net/sourceforge/pmd/external-reference-ruleset.xml/MockRule") + ) + ); assertEquals(1, rs.size()); assertEquals(MockRule.class.getName(), rs.getRuleByName("MockRule").getRuleClass()); } @Test - public void testIncludeExcludePatterns() { + void testIncludeExcludePatterns() { RuleSet ruleSet = loadRuleSet(INCLUDE_EXCLUDE_RULESET); - assertNotNull("Include patterns", ruleSet.getFileInclusions()); - assertEquals("Include patterns size", 2, ruleSet.getFileInclusions().size()); - assertEquals("Include pattern #1", "include1", ruleSet.getFileInclusions().get(0).pattern()); - assertEquals("Include pattern #2", "include2", ruleSet.getFileInclusions().get(1).pattern()); + assertNotNull(ruleSet.getFileInclusions(), "Include patterns"); + assertEquals(2, ruleSet.getFileInclusions().size(), "Include patterns size"); + assertEquals("include1", ruleSet.getFileInclusions().get(0).pattern(), "Include pattern #1"); + assertEquals("include2", ruleSet.getFileInclusions().get(1).pattern(), "Include pattern #2"); - assertNotNull("Exclude patterns", ruleSet.getFileExclusions()); - assertEquals("Exclude patterns size", 3, ruleSet.getFileExclusions().size()); - assertEquals("Exclude pattern #1", "exclude1", ruleSet.getFileExclusions().get(0).pattern()); - assertEquals("Exclude pattern #2", "exclude2", ruleSet.getFileExclusions().get(1).pattern()); - assertEquals("Exclude pattern #3", "exclude3", ruleSet.getFileExclusions().get(2).pattern()); + assertNotNull(ruleSet.getFileExclusions(), "Exclude patterns"); + assertEquals(3, ruleSet.getFileExclusions().size(), "Exclude patterns size"); + assertEquals("exclude1", ruleSet.getFileExclusions().get(0).pattern(), "Exclude pattern #1"); + assertEquals("exclude2", ruleSet.getFileExclusions().get(1).pattern(), "Exclude pattern #2"); + assertEquals("exclude3", ruleSet.getFileExclusions().get(2).pattern(), "Exclude pattern #3"); } /** @@ -716,14 +802,18 @@ public class RuleSetFactoryTest { * class is old (pmd 4.3 and not pmd 5). */ @Test - public void testBug1202() { - Assert.assertThrows( - RuleSetLoadException.class, - () -> new RuleSetLoader().loadFromString("", "\n" + "\n" - + " \n" + " 1\n" - + " \n" + " \n" - + " \n" + " \n" + " \n" - + "\n") + void testBug1202() { + assertCannotParse( + rulesetXml( + ruleRef( + "net.sourceforge.pmd.rules.XPathRule", + priority("1"), + properties( + propertyWithValueAttr("xpath", "//TypeDeclaration"), + propertyWithValueAttr("message", "Foo") + ) + ) + ) ); } @@ -731,13 +821,11 @@ public class RuleSetFactoryTest { * See https://sourceforge.net/p/pmd/bugs/1225/ */ @Test - public void testEmptyRuleSetFile() { - RuleSet ruleset = new RuleSetLoader().loadFromString("", "\n" + "\n" - + "\n" - + " PMD Ruleset.\n" + "\n" - + " .*Test.*\n" + "\n" + "\n"); + void testEmptyRuleSetFile() { + RuleSet ruleset = loadRuleSet( + rulesetXml( + excludePattern(".*Test.*") + )); assertEquals(0, ruleset.getRules().size()); } @@ -746,40 +834,32 @@ public class RuleSetFactoryTest { * Empty ruleset should be interpreted as deprecated. */ @Test - public void testEmptyRuleSetReferencedShouldNotBeDeprecated() { - RuleSet ruleset = new RuleSetLoader().loadFromString("", "\n" + "\n" - + "\n" - + " Ruleset which references a empty ruleset\n" + "\n" - + " \n" - + "\n"); + void testEmptyRuleSetReferencedShouldNotBeDeprecated() { + RuleSet ruleset = loadRuleSet( + rulesetXml( + ruleRef("rulesets/dummy/empty-ruleset.xml") + ) + ); assertEquals(0, ruleset.getRules().size()); - assertTrue(systemErrRule.getLog().isEmpty()); + verifyNoWarnings(); } /** * See https://sourceforge.net/p/pmd/bugs/1231/ */ @Test - public void testWrongRuleNameReferenced() { - assertCannotParse("\n" - + "\n" - + " Custom ruleset for tests\n" - + " \n" - + "\n"); + void testWrongRuleNameReferenced() { + assertCannotParse(rulesetXml( + ruleRef("net/sourceforge/pmd/TestRuleset1.xml/ThisRuleDoesNotExist") + )); } /** * Unit test for #1312 see https://sourceforge.net/p/pmd/bugs/1312/ - * */ @Test - public void testRuleReferenceWithNameOverridden() { + void testRuleReferenceWithNameOverridden() { RuleSet rs = loadRuleSet("\n" + "\n" + " */ @Test - public void testExcludeAndImportTwice() { - RuleSet ruleset = loadRuleSet("\n" + "\n" - + " Custom ruleset for tests\n" - + " \n" - + " \n" - + " \n" + "\n"); + void testExcludeAndImportTwice() { + RuleSet ruleset = loadRuleSet( + rulesetXml( + rulesetRef("rulesets/dummy/basic.xml", + excludeRule("DummyBasicMockRule") + ) + ) + ); + assertNull(ruleset.getRuleByName("DummyBasicMockRule")); - RuleSet ruleset2 = loadRuleSet("\n" + "\n" - + " Custom ruleset for tests\n" - + " \n" - + " \n" - + " \n" + " \n" - + "\n"); + RuleSet ruleset2 = loadRuleSet( + rulesetXml( + rulesetRef("rulesets/dummy/basic.xml", + excludeRule("DummyBasicMockRule") + ), + rulesetRef("rulesets/dummy/basic.xml") + ) + ); assertNotNull(ruleset2.getRuleByName("DummyBasicMockRule")); - RuleSet ruleset3 = loadRuleSet("\n" + "\n" - + " Custom ruleset for tests\n" - + " \n" - + " \n" - + " \n" + " \n" - + "\n"); + RuleSet ruleset3 = loadRuleSet( + rulesetXml( + rulesetRef("rulesets/dummy/basic.xml"), + rulesetRef("rulesets/dummy/basic.xml", + excludeRule("DummyBasicMockRule") + ) + ) + ); assertNotNull(ruleset3.getRuleByName("DummyBasicMockRule")); } @Test - public void testMissingRuleSetNameIsWarning() { - loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " Custom ruleset for tests\n" - + " \n" - + " \n" - ); + void testMissingRuleSetNameIsWarning() throws Exception { + SystemLambda.tapSystemErr(() -> { + loadRuleSetWithDeprecationWarnings( + "\n" + "\n" + + " Custom ruleset for tests\n" + + " \n" + + " \n" + ); + }); - assertTrue(systemErrRule.getLog().contains("RuleSet name is missing.")); + verifyFoundAWarningWithMessage(containing("RuleSet name is missing.")); } @Test public void testMissingRuleSetDescriptionIsWarning() { loadRuleSetWithDeprecationWarnings( - "\n" + "\n" - + " \n" - + " \n" + "\n" + "\n" + + " \n" + + " \n" ); - assertTrue(systemErrRule.getLog().contains("RuleSet description is missing.")); + verifyFoundAWarningWithMessage(containing("RuleSet description is missing.")); + } + + @Test + void testDeprecatedRulesetReferenceProducesWarning() throws Exception { + String log = SystemLambda.tapSystemErr( + () -> loadRuleSetWithDeprecationWarnings( + rulesetXml( + ruleRef("dummy-basic") + ))); + System.out.println(log); + + verifyFoundAWarningWithMessage(containing( + "Ruleset reference 'dummy-basic' uses a deprecated form, use 'rulesets/dummy/basic.xml' instead" + )); } private static final String REF_OVERRIDE_ORIGINAL_NAME = "\n" @@ -1004,176 +1098,56 @@ public class RuleSetFactoryTest { + "\n" + ""; - private static final String EMPTY_RULESET = "\n\ntestdesc\n"; + private static final String EMPTY_RULESET = rulesetXml(); - private static final String SINGLE_RULE = "\n" + private static final String SINGLE_RULE = + rulesetXml( + rule( + dummyRuleDefAttrs(), + priority("3") + ) + ); + + private static final String SINGLE_RULE_EMPTY_REF = + "\n" + "\n" + "testdesc\n" + "\n" + "3\n" + ""; - private static final String MULTIPLE_RULES = "\n" - + "\n" - + "\n" - + "testdesc\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + ""; + private static final String PROPERTIES = + rulesetXml( + rule(dummyRuleDefAttrs(), + description("testdesc2"), + properties( + "\n", + "\n", + "", + "\n", + "\n" + )) + ); - private static final String PROPERTIES = "\n" - + "\n" - + "testdesc\n" - + "\n" - + "\n" - + "testdesc2\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + ""; - - private static final String XPATH = "\n" - + "\n" - + "testdesc\n" - + "\n" - + "3\n" - + "\n" - + "testdesc2\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + ""; - - private static final String PRIORITY = "\n" - + "\n" - + "testdesc\n" - + "\n" - + "3\n" - + ""; - - private static final String LANGUAGE = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; - - private static final String INCORRECT_LANGUAGE = "\n" - + "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; - - private static final String MINIMUM_LANGUAGE_VERSION = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; - - private static final String INCORRECT_MINIMUM_LANGUAGE_VERSION = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; - - private static final String MAXIMUM_LANGUAGE_VERSION = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; - - private static final String INCORRECT_MAXIMUM_LANGUAGE_VERSION = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; - - private static final String INVERTED_MINIMUM_MAXIMUM_LANGUAGE_VERSIONS = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; - - private static final String DIRECT_DEPRECATED_RULE = "\n" - + "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; + private static final String XPATH = + rulesetXml( + rule( + dummyRuleDefAttrs(), + description("testDesc"), + properties( + "\n" + + "\n" + + "\n" + + "" + + "" + ) + ) + ); // Note: Update this RuleSet name to a different RuleSet with deprecated // Rules when the Rules are finally removed. @@ -1183,58 +1157,24 @@ public class RuleSetFactoryTest { // listed here is finally removed. private static final String DEPRECATED_RULE_NAME = "MockRule3"; - private static final String REFERENCE_TO_DEPRECATED_RULE = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; + private static final String REFERENCE_TO_DEPRECATED_RULE = + rulesetXml( + ruleRef(DEPRECATED_RULE_RULESET_NAME + "/" + DEPRECATED_RULE_NAME) + ); - private static final String REFERENCE_TO_RULESET_WITH_DEPRECATED_RULE = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; + private static final String REFERENCE_TO_RULESET_WITH_DEPRECATED_RULE = + rulesetXml( + rulesetRef(DEPRECATED_RULE_RULESET_NAME) + ); - private static final String DFA = "\n" - + "\n" - + "testdesc\n" - + "3\n" - + ""; + private static final String INCLUDE_EXCLUDE_RULESET = + rulesetXml( + includePattern("include1"), + includePattern("include2"), + excludePattern("exclude1"), + excludePattern("exclude2"), + excludePattern("exclude3") + ); - private static final String INCLUDE_EXCLUDE_RULESET = "\n" - + "\n" - + "testdesc\n" - + "include1\n" - + "include2\n" - + "\n" - + "exclude1\n" - + "exclude2\n" - + "exclude3\n" - + "\n" - + ""; - - private static final String EXTERNAL_REFERENCE_RULE_SET = "\n" - + "\n" - + "testdesc\n" - + "\n" - + ""; - - private Rule loadFirstRule(String ruleSetXml) { - RuleSet rs = loadRuleSet(ruleSetXml); - return rs.getRules().iterator().next(); - } - - private RuleSet loadRuleSet(String ruleSetXml) { - return new RuleSetLoader().loadFromString("dummyRuleset.xml", ruleSetXml); - } - - private RuleSet loadRuleSetWithDeprecationWarnings(String ruleSetXml) { - return new RuleSetLoader().warnDeprecated(true).enableCompatibility(false).loadFromString("testRuleset.xml", ruleSetXml); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java index 0914045572..1e75e37584 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetReferenceIdTest.java @@ -14,68 +14,68 @@ import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static com.github.tomakehurst.wiremock.client.WireMock.verify; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.List; -import org.apache.commons.io.IOUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import net.sourceforge.pmd.util.IOUtil; import net.sourceforge.pmd.util.ResourceLoader; -import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.junit5.WireMockTest; -public class RuleSetReferenceIdTest { +@WireMockTest +class RuleSetReferenceIdTest { private static void assertRuleSetReferenceId(final boolean expectedExternal, final String expectedRuleSetFileName, final boolean expectedAllRules, final String expectedRuleName, final String expectedToString, final RuleSetReferenceId reference) { - assertEquals("Wrong external", expectedExternal, reference.isExternal()); - assertEquals("Wrong RuleSet file name", expectedRuleSetFileName, reference.getRuleSetFileName()); - assertEquals("Wrong all Rule reference", expectedAllRules, reference.isAllRules()); - assertEquals("Wrong Rule name", expectedRuleName, reference.getRuleName()); - assertEquals("Wrong toString()", expectedToString, reference.toString()); - } - - @Test(expected = IllegalArgumentException.class) - public void testCommaInSingleId() { - - new RuleSetReferenceId("bad,id"); - } - - @Test(expected = IllegalArgumentException.class) - public void testInternalWithInternal() { - - new RuleSetReferenceId("SomeRule", new RuleSetReferenceId("SomeOtherRule")); - } - - @Test(expected = IllegalArgumentException.class) - public void testExternalWithExternal() { - - new RuleSetReferenceId("someruleset.xml/SomeRule", new RuleSetReferenceId("someruleset.xml/SomeOtherRule")); - } - - @Test(expected = IllegalArgumentException.class) - public void testExternalWithInternal() { - - new RuleSetReferenceId("someruleset.xml/SomeRule", new RuleSetReferenceId("SomeOtherRule")); + assertEquals(expectedExternal, reference.isExternal(), "Wrong external"); + assertEquals(expectedRuleSetFileName, reference.getRuleSetFileName(), "Wrong RuleSet file name"); + assertEquals(expectedAllRules, reference.isAllRules(), "Wrong all Rule reference"); + assertEquals(expectedRuleName, reference.getRuleName(), "Wrong Rule name"); + assertEquals(expectedToString, reference.toString(), "Wrong toString()"); } @Test - public void testInteralWithExternal() { + void testCommaInSingleId() { + assertThrows(IllegalArgumentException.class, () -> new RuleSetReferenceId("bad,id")); + } + @Test + void testInternalWithInternal() { + assertThrows(IllegalArgumentException.class, () -> + new RuleSetReferenceId("SomeRule", new RuleSetReferenceId("SomeOtherRule"))); + } + + @Test + void testExternalWithExternal() { + assertThrows(IllegalArgumentException.class, () -> + new RuleSetReferenceId("someruleset.xml/SomeRule", new RuleSetReferenceId("someruleset.xml/SomeOtherRule"))); + } + + @Test + void testExternalWithInternal() { + assertThrows(IllegalArgumentException.class, () -> + new RuleSetReferenceId("someruleset.xml/SomeRule", new RuleSetReferenceId("SomeOtherRule"))); + } + + @Test + void testInteralWithExternal() { // This is okay new RuleSetReferenceId("SomeRule", new RuleSetReferenceId("someruleset.xml/SomeOtherRule")); } @Test - public void testEmptyRuleSet() { - + void testEmptyRuleSet() { // This is representative of how the Test framework creates // RuleSetReferenceId from static RuleSet XMLs RuleSetReferenceId reference = new RuleSetReferenceId(null); @@ -83,8 +83,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testInternalWithExternalRuleSet() { - + void testInternalWithExternalRuleSet() { // This is representative of how the RuleSetFactory temporarily pairs an // internal reference // with an external reference. @@ -100,7 +99,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testConstructorGivenHttpUrlIdSucceedsAndProcessesIdCorrectly() { + void testConstructorGivenHttpUrlIdSucceedsAndProcessesIdCorrectly() { final String sonarRulesetUrlId = "http://localhost:54321/profiles/export?format=pmd&language=java&name=Sonar%2520way"; @@ -108,13 +107,10 @@ public class RuleSetReferenceIdTest { assertRuleSetReferenceId(true, sonarRulesetUrlId, true, null, sonarRulesetUrlId, ruleSetReferenceId); } - @org.junit.Rule - public WireMockRule wireMockRule = new WireMockRule(0); - @Test - public void testConstructorGivenHttpUrlInputStream() throws Exception { + void testConstructorGivenHttpUrlInputStream(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { String path = "/profiles/export?format=pmd&language=java&name=Sonar%2520way"; - String rulesetUrl = "http://localhost:" + wireMockRule.port() + path; + String rulesetUrl = "http://localhost:" + wmRuntimeInfo.getHttpPort() + path; stubFor(head(urlEqualTo(path)).willReturn(aResponse().withStatus(200))); stubFor(get(urlEqualTo(path)) .willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml").withBody("xyz"))); @@ -123,7 +119,7 @@ public class RuleSetReferenceIdTest { assertRuleSetReferenceId(true, rulesetUrl, true, null, rulesetUrl, ruleSetReferenceId); try (InputStream inputStream = ruleSetReferenceId.getInputStream(new ResourceLoader())) { - String loaded = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + String loaded = IOUtil.readToString(inputStream, StandardCharsets.UTF_8); assertEquals("xyz", loaded); } @@ -135,12 +131,12 @@ public class RuleSetReferenceIdTest { } @Test - public void testConstructorGivenHttpUrlSingleRuleInputStream() throws Exception { + void testConstructorGivenHttpUrlSingleRuleInputStream(WireMockRuntimeInfo wmRuntimeInfo) throws Exception { String path = "/profiles/export?format=pmd&language=java&name=Sonar%2520way"; String completePath = path + "/DummyBasicMockRule"; - String hostpart = "http://localhost:" + wireMockRule.port(); - String basicRuleSet = IOUtils - .toString(RuleSetReferenceId.class.getResourceAsStream("/rulesets/dummy/basic.xml"), StandardCharsets.UTF_8); + String hostpart = "http://localhost:" + wmRuntimeInfo.getHttpPort(); + String basicRuleSet = IOUtil + .readToString(RuleSetReferenceId.class.getResourceAsStream("/rulesets/dummy/basic.xml"), StandardCharsets.UTF_8); stubFor(head(urlEqualTo(completePath)).willReturn(aResponse().withStatus(404))); stubFor(head(urlEqualTo(path)).willReturn(aResponse().withStatus(200).withHeader("Content-type", "text/xml"))); @@ -152,7 +148,7 @@ public class RuleSetReferenceIdTest { ruleSetReferenceId); try (InputStream inputStream = ruleSetReferenceId.getInputStream(new ResourceLoader())) { - String loaded = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + String loaded = IOUtil.readToString(inputStream, StandardCharsets.UTF_8); assertEquals(basicRuleSet, loaded); } @@ -165,7 +161,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testOneSimpleRuleSet() { + void testOneSimpleRuleSet() { List references = RuleSetReferenceId.parse("dummy-basic"); assertEquals(1, references.size()); @@ -174,7 +170,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testMultipleSimpleRuleSet() { + void testMultipleSimpleRuleSet() { List references = RuleSetReferenceId.parse("dummy-unusedcode,dummy-basic"); assertEquals(2, references.size()); assertRuleSetReferenceId(true, "rulesets/dummy/unusedcode.xml", true, null, "rulesets/dummy/unusedcode.xml", @@ -187,7 +183,7 @@ public class RuleSetReferenceIdTest { * See https://sourceforge.net/p/pmd/bugs/1201/ */ @Test - public void testMultipleRulesWithSpaces() { + void testMultipleRulesWithSpaces() { List references = RuleSetReferenceId.parse("dummy-basic, dummy-unusedcode, dummy2-basic"); assertEquals(3, references.size()); assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", @@ -199,7 +195,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testOneReleaseRuleSet() { + void testOneReleaseRuleSet() { List references = RuleSetReferenceId.parse("50"); assertEquals(1, references.size()); assertRuleSetReferenceId(true, "rulesets/releases/50.xml", true, null, "rulesets/releases/50.xml", @@ -207,7 +203,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testOneFullRuleSet() { + void testOneFullRuleSet() { List references = RuleSetReferenceId.parse("rulesets/java/unusedcode.xml"); assertEquals(1, references.size()); assertRuleSetReferenceId(true, "rulesets/java/unusedcode.xml", true, null, "rulesets/java/unusedcode.xml", @@ -215,7 +211,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testOneFullRuleSetURL() { + void testOneFullRuleSetURL() { List references = RuleSetReferenceId.parse("file://somepath/rulesets/java/unusedcode.xml"); assertEquals(1, references.size()); assertRuleSetReferenceId(true, "file://somepath/rulesets/java/unusedcode.xml", true, null, @@ -223,7 +219,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testMultipleFullRuleSet() { + void testMultipleFullRuleSet() { List references = RuleSetReferenceId .parse("rulesets/java/unusedcode.xml,rulesets/java/basic.xml"); assertEquals(2, references.size()); @@ -234,7 +230,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testMixRuleSet() { + void testMixRuleSet() { List references = RuleSetReferenceId.parse("rulesets/dummy/unusedcode.xml,dummy2-basic"); assertEquals(2, references.size()); assertRuleSetReferenceId(true, "rulesets/dummy/unusedcode.xml", true, null, "rulesets/dummy/unusedcode.xml", @@ -244,14 +240,14 @@ public class RuleSetReferenceIdTest { } @Test - public void testUnknownRuleSet() { + void testUnknownRuleSet() { List references = RuleSetReferenceId.parse("nonexistant.xml"); assertEquals(1, references.size()); assertRuleSetReferenceId(true, "nonexistant.xml", true, null, "nonexistant.xml", references.get(0)); } @Test - public void testUnknownAndSimpleRuleSet() { + void testUnknownAndSimpleRuleSet() { List references = RuleSetReferenceId.parse("dummy-basic,nonexistant.xml"); assertEquals(2, references.size()); assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", true, null, "rulesets/dummy/basic.xml", @@ -260,7 +256,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testSimpleRuleSetAndRule() { + void testSimpleRuleSetAndRule() { List references = RuleSetReferenceId.parse("dummy-basic/DummyBasicMockRule"); assertEquals(1, references.size()); assertRuleSetReferenceId(true, "rulesets/dummy/basic.xml", false, "DummyBasicMockRule", @@ -268,7 +264,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testFullRuleSetAndRule() { + void testFullRuleSetAndRule() { List references = RuleSetReferenceId.parse("rulesets/java/basic.xml/EmptyCatchBlock"); assertEquals(1, references.size()); assertRuleSetReferenceId(true, "rulesets/java/basic.xml", false, "EmptyCatchBlock", @@ -276,7 +272,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testFullRuleSetURLAndRule() { + void testFullRuleSetURLAndRule() { List references = RuleSetReferenceId .parse("file://somepath/rulesets/java/unusedcode.xml/EmptyCatchBlock"); assertEquals(1, references.size()); @@ -285,21 +281,21 @@ public class RuleSetReferenceIdTest { } @Test - public void testInternalRuleSetAndRule() { + void testInternalRuleSetAndRule() { List references = RuleSetReferenceId.parse("EmptyCatchBlock"); assertEquals(1, references.size()); assertRuleSetReferenceId(false, null, false, "EmptyCatchBlock", "EmptyCatchBlock", references.get(0)); } @Test - public void testRelativePathRuleSet() { + void testRelativePathRuleSet() { List references = RuleSetReferenceId.parse("pmd/pmd-ruleset.xml"); assertEquals(1, references.size()); assertRuleSetReferenceId(true, "pmd/pmd-ruleset.xml", true, null, "pmd/pmd-ruleset.xml", references.get(0)); } @Test - public void testAbsolutePathRuleSet() { + void testAbsolutePathRuleSet() { List references = RuleSetReferenceId.parse("/home/foo/pmd/pmd-ruleset.xml"); assertEquals(1, references.size()); assertRuleSetReferenceId(true, "/home/foo/pmd/pmd-ruleset.xml", true, null, "/home/foo/pmd/pmd-ruleset.xml", @@ -307,7 +303,7 @@ public class RuleSetReferenceIdTest { } @Test - public void testFooRules() throws Exception { + void testFooRules() throws Exception { String fooRulesFile = new File("./src/test/resources/net/sourceforge/pmd/rulesets/foo-project/foo-rules") .getCanonicalPath(); List references = RuleSetReferenceId.parse(fooRulesFile); @@ -316,12 +312,8 @@ public class RuleSetReferenceIdTest { } @Test - public void testNullRulesetString() throws Exception { + void testNullRulesetString() throws Exception { List references = RuleSetReferenceId.parse(null); assertTrue(references.isEmpty()); } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(RuleSetReferenceIdTest.class); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetSchemaTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetSchemaTest.java index a07b476176..3e95166f4d 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetSchemaTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetSchemaTest.java @@ -4,9 +4,9 @@ package net.sourceforge.pmd; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -24,8 +24,8 @@ import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; @@ -34,18 +34,18 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; -public class RuleSetSchemaTest { +class RuleSetSchemaTest { private CollectingErrorHandler errorHandler; - @Before - public void setUp() { + @BeforeEach + void setUp() { Locale.setDefault(Locale.ROOT); errorHandler = new CollectingErrorHandler(); } @Test - public void verifyVersion2() throws Exception { + void verifyVersion2() throws Exception { String ruleset = generateRuleSet("2.0.0"); Document doc = parseWithVersion2(ruleset); assertNotNull(doc); @@ -56,7 +56,7 @@ public class RuleSetSchemaTest { } @Test - public void validateOnly() throws Exception { + void validateOnly() throws Exception { Validator validator = PMDRuleSetEntityResolver.getSchemaVersion2().newValidator(); validator.setErrorHandler(errorHandler); validator.validate(new StreamSource(new ByteArrayInputStream(generateRuleSet("2.0.0").getBytes(StandardCharsets.UTF_8)))); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetTest.java index c896f00f3d..c3cfc2bf62 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetTest.java @@ -11,12 +11,13 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.nio.charset.Charset; import java.nio.file.Paths; @@ -31,9 +32,8 @@ import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.apache.commons.io.FilenameUtils; import org.checkerframework.checker.nullness.qual.NonNull; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.Report.ProcessingError; import net.sourceforge.pmd.RuleSet.RuleSetBuilder; @@ -47,68 +47,72 @@ import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.rule.RuleReference; import net.sourceforge.pmd.lang.rule.RuleTargetSelector; +import net.sourceforge.pmd.util.IOUtil; -public class RuleSetTest { +class RuleSetTest { - private final Language dummyLang = LanguageRegistry.getLanguage(DummyLanguageModule.NAME); + private final Language dummyLang = DummyLanguageModule.getInstance(); - @Test(expected = NullPointerException.class) - public void testRuleSetRequiresName() { - new RuleSetBuilder(new Random().nextLong()) - .withName(null); - } - - @Test(expected = NullPointerException.class) - public void testRuleSetRequiresDescription() { - new RuleSetBuilder(new Random().nextLong()) - .withName("some name") - .withDescription(null); - } - - @Test(expected = NullPointerException.class) - public void testRuleSetRequiresName2() { - new RuleSetBuilder(new Random().nextLong()).build(); + @Test + void testRuleSetRequiresName() { + assertThrows(NullPointerException.class, () -> + new RuleSetBuilder(new Random().nextLong()) + .withName(null)); } @Test - public void testAccessors() { + void testRuleSetRequiresDescription() { + assertThrows(NullPointerException.class, () -> + new RuleSetBuilder(new Random().nextLong()) + .withName("some name") + .withDescription(null)); + } + + @Test + void testRuleSetRequiresName2() { + assertThrows(NullPointerException.class, () -> + new RuleSetBuilder(new Random().nextLong()).build()); + } + + @Test + void testAccessors() { RuleSet rs = new RuleSetBuilder(new Random().nextLong()) - .withFileName("baz") - .withName("foo") - .withDescription("bar") - .build(); - assertEquals("file name mismatch", "baz", rs.getFileName()); - assertEquals("name mismatch", "foo", rs.getName()); - assertEquals("description mismatch", "bar", rs.getDescription()); + .withFileName("baz") + .withName("foo") + .withDescription("bar") + .build(); + assertEquals("baz", rs.getFileName(), "file name mismatch"); + assertEquals("foo", rs.getName(), "name mismatch"); + assertEquals("bar", rs.getDescription(), "description mismatch"); } @Test - public void testGetRuleByName() { + void testGetRuleByName() { MockRule mock = new MockRule("name", "desc", "msg", "rulesetname"); RuleSet rs = RuleSet.forSingleRule(mock); - assertEquals("unable to fetch rule by name", mock, rs.getRuleByName("name")); + assertEquals(mock, rs.getRuleByName("name"), "unable to fetch rule by name"); } @Test - public void testGetRuleByName2() { + void testGetRuleByName2() { MockRule mock = new MockRule("name", "desc", "msg", "rulesetname"); RuleSet rs = RuleSet.forSingleRule(mock); - assertNull("the rule FooRule must not be found!", rs.getRuleByName("FooRule")); + assertNull(rs.getRuleByName("FooRule"), "the rule FooRule must not be found!"); } @Test - public void testRuleList() { + void testRuleList() { MockRule rule = new MockRule("name", "desc", "msg", "rulesetname"); RuleSet ruleset = RuleSet.forSingleRule(rule); - assertEquals("Size of RuleSet isn't one.", 1, ruleset.size()); + assertEquals(1, ruleset.size(), "Size of RuleSet isn't one."); Collection rules = ruleset.getRules(); Iterator i = rules.iterator(); - assertTrue("Empty Set", i.hasNext()); - assertEquals("Returned set of wrong size.", 1, rules.size()); - assertEquals("Rule isn't in ruleset.", rule, i.next()); + assertTrue(i.hasNext(), "Empty Set"); + assertEquals(1, rules.size(), "Returned set of wrong size."); + assertEquals(rule, i.next(), "Rule isn't in ruleset."); } private RuleSetBuilder createRuleSetBuilder(String name) { @@ -118,97 +122,98 @@ public class RuleSetTest { } @Test - public void testAddRuleSet() { + void testAddRuleSet() { RuleSet set1 = createRuleSetBuilder("ruleset1") .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .build(); RuleSet set2 = createRuleSetBuilder("ruleset2") - .addRule(new MockRule("name2", "desc", "msg", "rulesetname")) - .addRuleSet(set1) - .build(); - assertEquals("ruleset size wrong", 2, set2.size()); + .addRule(new MockRule("name2", "desc", "msg", "rulesetname")) + .addRuleSet(set1) + .build(); + assertEquals(2, set2.size(), "ruleset size wrong"); } - @Test(expected = RuntimeException.class) - public void testAddRuleSetByReferenceBad() { + @Test + void testAddRuleSetByReferenceBad() { RuleSet set1 = createRuleSetBuilder("ruleset1") .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .build(); - createRuleSetBuilder("ruleset2") - .addRule(new MockRule("name2", "desc", "msg", "rulesetname")) - .addRuleSetByReference(set1, false) - .build(); + assertThrows(RuntimeException.class, () -> + createRuleSetBuilder("ruleset2") + .addRule(new MockRule("name2", "desc", "msg", "rulesetname")) + .addRuleSetByReference(set1, false) + .build()); } @Test - public void testAddRuleSetByReferenceAllRule() { + void testAddRuleSetByReferenceAllRule() { RuleSet set2 = createRuleSetBuilder("ruleset2") .withFileName("foo") .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .addRule(new MockRule("name2", "desc", "msg", "rulesetname")) .build(); RuleSet set1 = createRuleSetBuilder("ruleset1") - .addRuleSetByReference(set2, true) - .build(); - assertEquals("wrong rule size", 2, set1.getRules().size()); + .addRuleSetByReference(set2, true) + .build(); + assertEquals(2, set1.getRules().size(), "wrong rule size"); for (Rule rule : set1.getRules()) { - assertTrue("not a rule reference", rule instanceof RuleReference); + assertTrue(rule instanceof RuleReference, "not a rule reference"); RuleReference ruleReference = (RuleReference) rule; - assertEquals("wrong ruleset file name", "foo", ruleReference.getRuleSetReference().getRuleSetFileName()); - assertTrue("not all rule reference", ruleReference.getRuleSetReference().isAllRules()); + assertEquals("foo", ruleReference.getRuleSetReference().getRuleSetFileName(), "wrong ruleset file name"); + assertTrue(ruleReference.getRuleSetReference().isAllRules(), "not all rule reference"); } } @Test - public void testAddRuleSetByReferenceSingleRule() { + void testAddRuleSetByReferenceSingleRule() { RuleSet set2 = createRuleSetBuilder("ruleset2") .withFileName("foo") .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .addRule(new MockRule("name2", "desc", "msg", "rulesetname")) .build(); RuleSet set1 = createRuleSetBuilder("ruleset1") - .addRuleSetByReference(set2, false) - .build(); - assertEquals("wrong rule size", 2, set1.getRules().size()); + .addRuleSetByReference(set2, false) + .build(); + assertEquals(2, set1.getRules().size(), "wrong rule size"); for (Rule rule : set1.getRules()) { - assertTrue("not a rule reference", rule instanceof RuleReference); + assertTrue(rule instanceof RuleReference, "not a rule reference"); RuleReference ruleReference = (RuleReference) rule; - assertEquals("wrong ruleset file name", "foo", ruleReference.getRuleSetReference().getRuleSetFileName()); - assertFalse("should not be all rule reference", ruleReference.getRuleSetReference().isAllRules()); + assertEquals("foo", ruleReference.getRuleSetReference().getRuleSetFileName(), "wrong ruleset file name"); + assertFalse(ruleReference.getRuleSetReference().isAllRules(), "should not be all rule reference"); } } @Test - public void testApply0Rules() throws Exception { + void testApply0Rules() throws Exception { RuleSet ruleset = createRuleSetBuilder("ruleset").build(); verifyRuleSet(ruleset, new HashSet()); } @Test - public void testEquals1() { + void testEquals1() { RuleSet s = createRuleSetBuilder("ruleset").build(); - assertFalse("A ruleset cannot be equals to null", s.equals(null)); + assertFalse(s.equals(null), "A ruleset cannot be equals to null"); } @Test @SuppressWarnings("PMD.UseAssertEqualsInsteadOfAssertTrue") - public void testEquals2() { + void testEquals2() { RuleSet s = createRuleSetBuilder("ruleset").build(); - assertTrue("A rulset must be equals to itself", s.equals(s)); + assertTrue(s.equals(s), "A rulset must be equals to itself"); } @Test - public void testEquals3() { + void testEquals3() { RuleSet s = new RuleSetBuilder(new Random().nextLong()) - .withName("basic rules") - .withDescription("desc") - .build(); - assertFalse("A ruleset cannot be equals to another kind of object", s.equals("basic rules")); + .withName("basic rules") + .withDescription("desc") + .build(); + assertFalse(s.equals("basic rules"), "A ruleset cannot be equals to another kind of object"); } @Test - public void testEquals4() { + void testEquals4() { RuleSet s1 = createRuleSetBuilder("my ruleset") .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .build(); @@ -217,12 +222,12 @@ public class RuleSetTest { .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .build(); - assertEquals("2 rulesets with same name and rules must be equals", s1, s2); - assertEquals("Equals rulesets must have the same hashcode", s1.hashCode(), s2.hashCode()); + assertEquals(s1, s2, "2 rulesets with same name and rules must be equals"); + assertEquals(s1.hashCode(), s2.hashCode(), "Equals rulesets must have the same hashcode"); } @Test - public void testEquals5() { + void testEquals5() { RuleSet s1 = createRuleSetBuilder("my ruleset") .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .build(); @@ -231,11 +236,11 @@ public class RuleSetTest { .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .build(); - assertFalse("2 rulesets with different name but same rules must not be equals", s1.equals(s2)); + assertFalse(s1.equals(s2), "2 rulesets with different name but same rules must not be equals"); } @Test - public void testEquals6() { + void testEquals6() { RuleSet s1 = createRuleSetBuilder("my ruleset") .addRule(new MockRule("name", "desc", "msg", "rulesetname")) .build(); @@ -244,61 +249,61 @@ public class RuleSetTest { .addRule(new MockRule("other rule", "desc", "msg", "rulesetname")) .build(); - assertFalse("2 rulesets with same name but different rules must not be equals", s1.equals(s2)); + assertFalse(s1.equals(s2), "2 rulesets with same name but different rules must not be equals"); } @Test - public void testLanguageApplies() { + void testLanguageApplies() { Rule rule = new MockRule(); - assertFalse("Different languages should not apply", - RuleSet.applies(rule, LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME).getDefaultVersion())); + assertFalse(RuleSet.applies(rule, LanguageRegistry.getLanguage(Dummy2LanguageModule.NAME).getDefaultVersion()), + "Different languages should not apply"); - assertTrue("Same language with no min/max should apply", - RuleSet.applies(rule, dummyLang.getVersion("1.5"))); + assertTrue(RuleSet.applies(rule, dummyLang.getVersion("1.5")), + "Same language with no min/max should apply"); rule.setMinimumLanguageVersion(dummyLang.getVersion("1.5")); - assertTrue("Same language with valid min only should apply", - RuleSet.applies(rule, dummyLang.getVersion("1.5"))); + assertTrue(RuleSet.applies(rule, dummyLang.getVersion("1.5")), + "Same language with valid min only should apply"); rule.setMaximumLanguageVersion(dummyLang.getVersion("1.6")); - assertTrue("Same language with valid min and max should apply", - RuleSet.applies(rule, dummyLang.getVersion("1.5"))); - assertFalse("Same language with outside range of min/max should not apply", - RuleSet.applies(rule, dummyLang.getVersion("1.4"))); - assertFalse("Same language with outside range of min/max should not apply", - RuleSet.applies(rule, dummyLang.getVersion("1.7"))); + assertTrue(RuleSet.applies(rule, dummyLang.getVersion("1.5")), + "Same language with valid min and max should apply"); + assertFalse(RuleSet.applies(rule, dummyLang.getVersion("1.4")), + "Same language with outside range of min/max should not apply"); + assertFalse(RuleSet.applies(rule, dummyLang.getVersion("1.7")), + "Same language with outside range of min/max should not apply"); } @Test - public void testAddExcludePattern() { + void testAddExcludePattern() { RuleSet ruleSet = createRuleSetBuilder("ruleset1") .withFileExclusions(Pattern.compile(".*")) .build(); - assertNotNull("Exclude patterns", ruleSet.getFileExclusions()); - assertEquals("Invalid number of patterns", 1, ruleSet.getFileExclusions().size()); + assertNotNull(ruleSet.getFileExclusions(), "Exclude patterns"); + assertEquals(1, ruleSet.getFileExclusions().size(), "Invalid number of patterns"); } @Test - public void testExcludePatternAreOrdered() { + void testExcludePatternAreOrdered() { RuleSet ruleSet2 = createRuleSetBuilder("ruleset2") - .withFileExclusions(Pattern.compile(".*")) - .withFileExclusions(Pattern.compile(".*ha")) - .build(); - assertEquals("Exclude pattern", Arrays.asList(".*", ".*ha"), toStrings(ruleSet2.getFileExclusions())); + .withFileExclusions(Pattern.compile(".*")) + .withFileExclusions(Pattern.compile(".*ha")) + .build(); + assertEquals(Arrays.asList(".*", ".*ha"), toStrings(ruleSet2.getFileExclusions()), "Exclude pattern"); } @Test - public void testIncludePatternsAreOrdered() { + void testIncludePatternsAreOrdered() { RuleSet ruleSet2 = createRuleSetBuilder("ruleset2") .withFileInclusions(Pattern.compile(".*")) .withFileInclusions(Arrays.asList(Pattern.compile(".*ha"), Pattern.compile(".*hb"))) .build(); - assertEquals("Exclude pattern", Arrays.asList(".*", ".*ha", ".*hb"), toStrings(ruleSet2.getFileInclusions())); + assertEquals(Arrays.asList(".*", ".*ha", ".*hb"), toStrings(ruleSet2.getFileInclusions()), "Exclude pattern"); } private List toStrings(List strings) { @@ -306,65 +311,65 @@ public class RuleSetTest { } @Test - public void testAddExcludePatterns() { + void testAddExcludePatterns() { RuleSet ruleSet = createRuleSetBuilder("ruleset1") .withFileExclusions(Pattern.compile(".*")) .build(); - assertNotNull("Exclude patterns", ruleSet.getFileExclusions()); - assertEquals("Invalid number of patterns", 1, ruleSet.getFileExclusions().size()); + assertNotNull(ruleSet.getFileExclusions(), "Exclude patterns"); + assertEquals(1, ruleSet.getFileExclusions().size(), "Invalid number of patterns"); RuleSet ruleSet2 = createRuleSetBuilder("ruleset2") - .withFileExclusions(ruleSet.getFileExclusions()) - .build(); - assertNotNull("Exclude patterns", ruleSet2.getFileExclusions()); - assertEquals("Invalid number of patterns", 1, ruleSet2.getFileExclusions().size()); + .withFileExclusions(ruleSet.getFileExclusions()) + .build(); + assertNotNull(ruleSet2.getFileExclusions(), "Exclude patterns"); + assertEquals(1, ruleSet2.getFileExclusions().size(), "Invalid number of patterns"); } @Test - public void testSetExcludePatterns() { + void testSetExcludePatterns() { List excludePatterns = new ArrayList<>(); excludePatterns.add(Pattern.compile("ah*")); excludePatterns.add(Pattern.compile(".*")); RuleSet ruleSet = createRuleSetBuilder("ruleset").replaceFileExclusions(excludePatterns).build(); - assertNotNull("Exclude patterns", ruleSet.getFileExclusions()); - assertEquals("Invalid number of exclude patterns", 2, ruleSet.getFileExclusions().size()); - assertEquals("Exclude pattern", "ah*", ruleSet.getFileExclusions().get(0).pattern()); - assertEquals("Exclude pattern", ".*", ruleSet.getFileExclusions().get(1).pattern()); - assertNotNull("Include patterns", ruleSet.getFileInclusions()); - assertEquals("Invalid number of include patterns", 0, ruleSet.getFileInclusions().size()); + assertNotNull(ruleSet.getFileExclusions(), "Exclude patterns"); + assertEquals(2, ruleSet.getFileExclusions().size(), "Invalid number of exclude patterns"); + assertEquals("ah*", ruleSet.getFileExclusions().get(0).pattern(), "Exclude pattern"); + assertEquals(".*", ruleSet.getFileExclusions().get(1).pattern(), "Exclude pattern"); + assertNotNull(ruleSet.getFileInclusions(), "Include patterns"); + assertEquals(0, ruleSet.getFileInclusions().size(), "Invalid number of include patterns"); } @Test - public void testAddIncludePattern() { + void testAddIncludePattern() { RuleSet ruleSet = createRuleSetBuilder("ruleset") - .withFileInclusions(Pattern.compile(".*")) - .build(); - assertNotNull("Include patterns", ruleSet.getFileInclusions()); - assertEquals("Invalid number of patterns", 1, ruleSet.getFileInclusions().size()); - assertEquals("Include pattern", ".*", ruleSet.getFileInclusions().get(0).pattern()); - assertNotNull("Exclude patterns", ruleSet.getFileExclusions()); - assertEquals("Invalid number of exclude patterns", 0, ruleSet.getFileExclusions().size()); + .withFileInclusions(Pattern.compile(".*")) + .build(); + assertNotNull(ruleSet.getFileInclusions(), "Include patterns"); + assertEquals(1, ruleSet.getFileInclusions().size(), "Invalid number of patterns"); + assertEquals(".*", ruleSet.getFileInclusions().get(0).pattern(), "Include pattern"); + assertNotNull(ruleSet.getFileExclusions(), "Exclude patterns"); + assertEquals(0, ruleSet.getFileExclusions().size(), "Invalid number of exclude patterns"); } @Test - public void testAddIncludePatterns() { + void testAddIncludePatterns() { RuleSet ruleSet = createRuleSetBuilder("ruleset1") .withFileInclusions(Pattern.compile("ah*"), Pattern.compile(".*")) .build(); RuleSet ruleSet2 = createRuleSetBuilder("ruleset1") - .withFileInclusions(ruleSet.getFileInclusions()) - .build(); - assertNotNull("Include patterns", ruleSet2.getFileInclusions()); - assertEquals("Invalid number of patterns", 2, ruleSet2.getFileInclusions().size()); - assertEquals("Include pattern", "ah*", ruleSet2.getFileInclusions().get(0).pattern()); - assertEquals("Include pattern", ".*", ruleSet2.getFileInclusions().get(1).pattern()); - assertNotNull("Exclude patterns", ruleSet.getFileExclusions()); - assertEquals("Invalid number of exclude patterns", 0, ruleSet.getFileExclusions().size()); + .withFileInclusions(ruleSet.getFileInclusions()) + .build(); + assertNotNull(ruleSet2.getFileInclusions(), "Include patterns"); + assertEquals(2, ruleSet2.getFileInclusions().size(), "Invalid number of patterns"); + assertEquals("ah*", ruleSet2.getFileInclusions().get(0).pattern(), "Include pattern"); + assertEquals(".*", ruleSet2.getFileInclusions().get(1).pattern(), "Include pattern"); + assertNotNull(ruleSet.getFileExclusions(), "Exclude patterns"); + assertEquals(0, ruleSet.getFileExclusions().size(), "Invalid number of exclude patterns"); } @Test - public void testSetIncludePatterns() { + void testSetIncludePatterns() { List includePatterns = new ArrayList<>(); includePatterns.add(Pattern.compile("ah*")); includePatterns.add(Pattern.compile(".*")); @@ -372,46 +377,46 @@ public class RuleSetTest { .replaceFileInclusions(includePatterns) .build(); - assertEquals("Include patterns", includePatterns, ruleSet.getFileInclusions()); - assertNotNull("Exclude patterns", ruleSet.getFileInclusions()); - assertEquals("Invalid number of exclude patterns", 0, ruleSet.getFileExclusions().size()); + assertEquals(includePatterns, ruleSet.getFileInclusions(), "Include patterns"); + assertNotNull(ruleSet.getFileInclusions(), "Exclude patterns"); + assertEquals(0, ruleSet.getFileExclusions().size(), "Invalid number of exclude patterns"); } @Test - public void testIncludeExcludeApplies() { + void testIncludeExcludeApplies() { TextFile file = TextFile.forPath(Paths.get("C:\\myworkspace\\project\\some\\random\\package\\RandomClass.java"), Charset.defaultCharset(), dummyLang.getDefaultVersion()); RuleSet ruleSet = createRuleSetBuilder("ruleset").build(); - assertTrue("No patterns", ruleSet.applies(file)); + assertTrue(ruleSet.applies(file), "No patterns"); ruleSet = createRuleSetBuilder("ruleset") - .withFileExclusions(Pattern.compile("nomatch")) - .build(); - assertTrue("Non-matching exclude", ruleSet.applies(file)); + .withFileExclusions(Pattern.compile("nomatch")) + .build(); + assertTrue(ruleSet.applies(file), "Non-matching exclude"); ruleSet = createRuleSetBuilder("ruleset") - .withFileExclusions(Pattern.compile("nomatch"), Pattern.compile(".*/package/.*")) - .build(); - assertFalse("Matching exclude", ruleSet.applies(file)); + .withFileExclusions(Pattern.compile("nomatch"), Pattern.compile(".*/package/.*")) + .build(); + assertFalse(ruleSet.applies(file), "Matching exclude"); ruleSet = createRuleSetBuilder("ruleset") - .withFileExclusions(Pattern.compile("nomatch")) - .withFileExclusions(Pattern.compile(".*/package/.*")) - .withFileInclusions(Pattern.compile(".*/randomX/.*")) - .build(); - assertFalse("Non-matching include", ruleSet.applies(file)); + .withFileExclusions(Pattern.compile("nomatch")) + .withFileExclusions(Pattern.compile(".*/package/.*")) + .withFileInclusions(Pattern.compile(".*/randomX/.*")) + .build(); + assertFalse(ruleSet.applies(file), "Non-matching include"); ruleSet = createRuleSetBuilder("ruleset") - .withFileExclusions(Pattern.compile("nomatch")) - .withFileExclusions(Pattern.compile(".*/package/.*")) - .withFileInclusions(Pattern.compile(".*/randomX/.*")) - .withFileInclusions(Pattern.compile(".*/random/.*")) - .build(); - assertTrue("Matching include", ruleSet.applies(file)); + .withFileExclusions(Pattern.compile("nomatch")) + .withFileExclusions(Pattern.compile(".*/package/.*")) + .withFileInclusions(Pattern.compile(".*/randomX/.*")) + .withFileInclusions(Pattern.compile(".*/random/.*")) + .build(); + assertTrue(ruleSet.applies(file), "Matching include"); } @Test - public void testIncludeExcludeMultipleRuleSetWithRuleChainApplies() throws Exception { + void testIncludeExcludeMultipleRuleSetWithRuleChainApplies() throws Exception { Rule rule = new FooRule(); rule.setName("FooRule1"); rule.setLanguage(LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); @@ -424,7 +429,7 @@ public class RuleSetTest { // Two violations Report report = Report.buildReport(ctx1 -> ruleSets.apply(makeCompilationUnits(), ctx1)); - assertEquals("Violations", 2, report.getViolations().size()); + assertEquals(2, report.getViolations().size(), "Violations"); // One violation ruleSet1 = createRuleSetBuilder("RuleSet1") @@ -435,11 +440,11 @@ public class RuleSetTest { RuleSets ruleSets2 = new RuleSets(listOf(ruleSet1, ruleSet2)); report = Report.buildReport(ctx -> ruleSets2.apply(makeCompilationUnits("C:\\package\\RandomClass.java"), ctx)); - assertEquals("Violations", 1, report.getViolations().size()); + assertEquals(1, report.getViolations().size(), "Violations"); } @Test - public void copyConstructorDeepCopies() { + void copyConstructorDeepCopies() { Rule rule = new FooRule(); rule.setName("FooRule1"); RuleSet ruleSet1 = createRuleSetBuilder("RuleSet1") @@ -458,14 +463,14 @@ public class RuleSetTest { Report report = RuleContextTest.getReportForRuleSetApply(ruleset, makeCompilationUnits()); - assertEquals("Invalid number of Violations Reported", expected.size(), report.getViolations().size()); + assertEquals(expected.size(), report.getViolations().size(), "Invalid number of Violations Reported"); for (RuleViolation violation : report.getViolations()) { - assertTrue("Unexpected Violation Returned: " + violation, expected.contains(violation)); + assertTrue(expected.contains(violation), "Unexpected Violation Returned: " + violation); } for (RuleViolation violation : expected) { - assertTrue("Expected Violation not Returned: " + violation, report.getViolations().contains(violation)); + assertTrue(report.getViolations().contains(violation), "Expected Violation not Returned: " + violation); } } @@ -485,7 +490,7 @@ public class RuleSetTest { } @Test - public void ruleExceptionShouldBeReported() throws Exception { + void ruleExceptionShouldBeReported() throws Exception { RuleSet ruleset = createRuleSetBuilder("ruleExceptionShouldBeReported") .addRule(new MockRule() { @Override @@ -507,7 +512,7 @@ public class RuleSetTest { @Test - public void ruleExceptionShouldNotStopProcessingFile() throws Exception { + void ruleExceptionShouldNotStopProcessingFile() throws Exception { RuleSet ruleset = createRuleSetBuilder("ruleExceptionShouldBeReported").addRule(new MockRule() { @Override public void apply(Node target, RuleContext ctx) { @@ -528,13 +533,13 @@ public class RuleSetTest { assertThat(error.getMsg(), containsString("java.lang.IllegalStateException: Test exception while applying rule\n")); assertThat(error.getMsg(), containsString("Rule applied on node=dummyRootNode[@Image=Foo]")); assertThat(error.getError().getCause(), instanceOf(IllegalStateException.class)); - assertThat(FilenameUtils.normalize(error.getFile(), true), equalTo("samplefile.dummy")); + assertThat(IOUtil.normalizePath(error.getFile()), equalTo("samplefile.dummy")); assertThat(report.getViolations(), hasSize(1)); } @Test - public void ruleExceptionShouldNotStopProcessingFileWithRuleChain() throws Exception { + void ruleExceptionShouldNotStopProcessingFileWithRuleChain() throws Exception { RuleSet ruleset = createRuleSetBuilder("ruleExceptionShouldBeReported").addRule(new MockRule() { @Override @@ -572,21 +577,21 @@ public class RuleSetTest { } - class MockRule extends net.sourceforge.pmd.lang.rule.MockRule { + static class MockRule extends net.sourceforge.pmd.lang.rule.MockRule { MockRule() { super(); - setLanguage(dummyLang); + setLanguage(DummyLanguageModule.getInstance()); } MockRule(String name, String description, String message, String ruleSetName, RulePriority priority) { super(name, description, message, ruleSetName, priority); - setLanguage(dummyLang); + setLanguage(DummyLanguageModule.getInstance()); } MockRule(String name, String description, String message, String ruleSetName) { super(name, description, message, ruleSetName); - setLanguage(dummyLang); + setLanguage(DummyLanguageModule.getInstance()); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetWriterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetWriterTest.java index 63bc53a909..fd06150198 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetWriterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetWriterTest.java @@ -4,13 +4,14 @@ package net.sourceforge.pmd; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.ByteArrayOutputStream; import java.util.Random; -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.RuleSet.RuleSetBuilder; import net.sourceforge.pmd.lang.rule.RuleReference; @@ -19,7 +20,7 @@ import net.sourceforge.pmd.lang.rule.RuleReference; * Unit test for {@link RuleSetWriter}. * */ -public class RuleSetWriterTest { +class RuleSetWriterTest { private ByteArrayOutputStream out; private RuleSetWriter writer; @@ -27,8 +28,8 @@ public class RuleSetWriterTest { /** * Prepare the output stream. */ - @Before - public void setupOutputStream() { + @BeforeEach + void setupOutputStream() { out = new ByteArrayOutputStream(); writer = new RuleSetWriter(out); } @@ -36,8 +37,8 @@ public class RuleSetWriterTest { /** * Closes the output stream at the end. */ - @After - public void cleanupStream() { + @AfterEach + void cleanupStream() { if (writer != null) { writer.close(); } @@ -50,7 +51,7 @@ public class RuleSetWriterTest { * any error */ @Test - public void testWrite() throws Exception { + void testWrite() throws Exception { RuleSet braces = new RuleSetLoader().loadFromResource("net/sourceforge/pmd/TestRuleset1.xml"); RuleSet ruleSet = new RuleSetBuilder(new Random().nextLong()) .withName("ruleset") @@ -61,7 +62,7 @@ public class RuleSetWriterTest { writer.write(ruleSet); String written = out.toString("UTF-8"); - Assert.assertTrue(written.contains(" comp = RuleViolation.DEFAULT_COMPARATOR; DummyNode s = DummyLanguageModule.parse("(abc)", "filename1").getFirstChild(); @@ -58,7 +56,7 @@ public class RuleViolationTest { } @Test - public void testComparatorWithSameFileDifferentLines() { + void testComparatorWithSameFileDifferentLines() { Rule rule = new MockRule("name", "desc", "msg", "rulesetname"); Comparator comp = RuleViolation.DEFAULT_COMPARATOR; DummyRootNode root = DummyLanguageModule.parse("(abc) (def)"); @@ -71,7 +69,7 @@ public class RuleViolationTest { } @Test - public void testComparatorWithSameFileSameLines() { + void testComparatorWithSameFileSameLines() { Rule rule = new MockRule("name", "desc", "msg", "rulesetname"); Comparator comp = RuleViolation.DEFAULT_COMPARATOR; String filename = TextFile.UNKNOWN_FILENAME; @@ -84,8 +82,4 @@ public class RuleViolationTest { assertEquals(0, comp.compare(r1, r2)); assertEquals(0, comp.compare(r2, r1)); } - - public static junit.framework.Test suite() { - return new JUnit4TestAdapter(RuleViolationTest.class); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RulesetFactoryTestBase.java b/pmd-core/src/test/java/net/sourceforge/pmd/RulesetFactoryTestBase.java new file mode 100644 index 0000000000..bad9754ed2 --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RulesetFactoryTestBase.java @@ -0,0 +1,243 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd; + +import static net.sourceforge.pmd.util.CollectionUtil.buildMap; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.argThat; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import java.text.MessageFormat; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.verification.VerificationMode; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; + +import net.sourceforge.pmd.lang.DummyLanguageModule; +import net.sourceforge.pmd.util.internal.xml.SchemaConstant; +import net.sourceforge.pmd.util.internal.xml.SchemaConstants; +import net.sourceforge.pmd.util.log.MessageReporter; +import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter; + +public class RulesetFactoryTestBase { + + protected MessageReporter mockReporter; + + @BeforeEach + public void setup() { + SimpleMessageReporter reporter = new SimpleMessageReporter(LoggerFactory.getLogger(RulesetFactoryTestBase.class)); + mockReporter = spy(reporter); + } + + protected void verifyNoWarnings() { + verifyZeroInteractions(mockReporter); + } + + protected static Predicate containing(String part) { + return new Predicate() { + @Override + public boolean test(String it) { + String format = MessageFormat.format(it, new Object[0]); + return format.contains(part); + } + + @Override + public String toString() { + return "string containing: " + part; + } + }; + } + + /** + * @param messageTest This is a MessageFormat string! + */ + protected void verifyFoundAWarningWithMessage(Predicate messageTest) { + verifyFoundWarningWithMessage(times(1), messageTest); + } + + /** + * @param messageTest This is a MessageFormat string! + */ + protected void verifyFoundWarningWithMessage(VerificationMode mode, Predicate messageTest) { + verify(mockReporter, mode) + .logEx(eq(Level.WARN), argThat(messageTest::test), any(), any()); + } + + protected void verifyFoundAnErrorWithMessage(Predicate messageTest) { + verify(mockReporter, times(1)) + .logEx(eq(Level.ERROR), argThat(messageTest::test), any(), any()); + } + + + protected RuleSet loadRuleSetInDir(String resourceDir, String ruleSetFilename) { + RuleSetLoader loader = new RuleSetLoader(); + loader.setReporter(mockReporter); + return loader.loadFromResource(resourceDir + "/" + ruleSetFilename); + } + + + protected Rule loadFirstRule(String ruleSetXml) { + RuleSet rs = loadRuleSet(ruleSetXml); + return rs.getRules().iterator().next(); + } + + protected RuleSet loadRuleSet(String ruleSetXml) { + return loadRuleSet("dummyRuleset.xml", ruleSetXml); + } + + protected RuleSet loadRuleSet(String fileName, String ruleSetXml) { + RuleSetLoader loader = new RuleSetLoader(); + loader.setReporter(mockReporter); + return loader.loadFromString(fileName, ruleSetXml); + } + + protected RuleSet loadRuleSetWithDeprecationWarnings(String ruleSetXml) { + PMDConfiguration config = new PMDConfiguration(); + config.setReporter(mockReporter); + try (PmdAnalysis pmd = PmdAnalysis.create(config)) { + return pmd.newRuleSetLoader() + .warnDeprecated(true) + .enableCompatibility(false).loadFromString("dummyRuleset.xml", ruleSetXml); + } + } + + protected void assertCannotParse(String xmlContent) { + assertThrows(RuleSetLoadException.class, () -> loadFirstRule(xmlContent)); + } + /* + DSL to build a ruleset XML file with method calls. + */ + + + protected static @NonNull String rulesetXml(String... contents) { + return "\n" + "\n" + + "\n" + + " Ruleset which references a empty ruleset\n" + "\n" + + body(contents) + + "\n"; + } + + protected static @NonNull String ruleRef(String ref) { + return "\n"; + } + + protected static @NonNull String rule(Map attrs, String... body) { + return "\n" + + body(body) + + ""; + } + + protected static @NonNull String dummyRule(Consumer> attributes, String... body) { + return rule(buildMap(dummyRuleDefAttrs(), attributes), body); + } + + protected static @NonNull String dummyRule(String... body) { + return dummyRule(m -> { }, body); + } + + /** + * Default attributes used by {@link #dummyRule(Consumer, String...)}. + */ + protected static Map dummyRuleDefAttrs() { + return buildMap( + map -> { + map.put(SchemaConstants.NAME, "MockRuleName"); + map.put(SchemaConstants.LANGUAGE, DummyLanguageModule.TERSE_NAME); + map.put(SchemaConstants.CLASS, net.sourceforge.pmd.lang.rule.MockRule.class.getName()); + map.put(SchemaConstants.MESSAGE, "avoid the mock rule"); + } + ); + } + + private static @NonNull String attrs(Map str) { + return str.entrySet().stream() + .map(it -> it.getKey().xmlName() + "=\"" + it.getValue() + "\"") + .collect(Collectors.joining(" ")); + } + + + protected static @NonNull String rulesetRef(String ref, String... body) { + return ruleRef(ref, body); + } + + protected static @NonNull String ruleRef(String ref, String... body) { + return "\n" + + body(body) + + "\n"; + } + + protected static @NonNull String excludePattern(String pattern) { + return tagOneLine("exclude-pattern", pattern); + } + + protected static @NonNull String excludeRule(String name) { + return emptyTag("exclude", buildMap(map -> map.put(SchemaConstants.NAME, name))); + } + + protected static @NonNull String includePattern(String pattern) { + return tagOneLine("include-pattern", pattern); + } + + protected static @NonNull String priority(String prio) { + return tagOneLine("priority", prio); + } + + protected static @NonNull String description(String description) { + return tagOneLine("description", description); + } + + protected static @NonNull String body(String... lines) { + return String.join("\n", lines); + } + + protected static @NonNull String properties(String... body) { + return tag("properties", body); + } + + protected static @NonNull String propertyWithValueAttr(String name, String valueAttr) { + return ".", - buildRule.getLog()); + log.toString()); fail("This should throw an exception"); } catch (BuildException ex) { - Assert.assertEquals( + assertEquals( "The following language is not supported:.", ex.getMessage()); } } @Test - public void testWithShortFilenames() throws IOException { - buildRule.executeTarget("testWithShortFilenames"); + void testWithShortFilenames() throws IOException { + executeTarget("testWithShortFilenames"); try (InputStream in = new FileInputStream("target/pmd-ant-test.txt")) { - String actual = IOUtils.toString(in, StandardCharsets.UTF_8); + String actual = IOUtil.readToString(in, StandardCharsets.UTF_8); // remove any trailing newline actual = actual.trim(); assertThat(actual, containsString("sample.dummy:1:\tSampleXPathRule:\tTest Rule 2")); @@ -99,20 +80,20 @@ public class PMDTaskTest { } @Test - public void testXmlFormatter() throws IOException { - buildRule.executeTarget("testXmlFormatter"); + void testXmlFormatter() throws IOException { + executeTarget("testXmlFormatter"); try (InputStream in = new FileInputStream("target/pmd-ant-xml.xml"); InputStream expectedStream = PMDTaskTest.class.getResourceAsStream("xml/expected-pmd-ant-xml.xml")) { - String actual = IOUtils.toString(in, StandardCharsets.UTF_8); + String actual = IOUtil.readToString(in, StandardCharsets.UTF_8); actual = actual.replaceFirst("timestamp=\"[^\"]+\"", "timestamp=\"\""); actual = actual.replaceFirst("\\.xsd\" version=\"[^\"]+\"", ".xsd\" version=\"\""); - String expected = IOUtils.toString(expectedStream, StandardCharsets.UTF_8); + String expected = IOUtil.readToString(expectedStream, StandardCharsets.UTF_8); expected = expected.replaceFirst("timestamp=\"[^\"]+\"", "timestamp=\"\""); expected = expected.replaceFirst("\\.xsd\" version=\"[^\"]+\"", ".xsd\" version=\"\""); - Assert.assertEquals(expected, actual); + assertEquals(expected, actual); } } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cache/FileAnalysisCacheTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cache/FileAnalysisCacheTest.java index 3ca761e9b4..1328f7c765 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cache/FileAnalysisCacheTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cache/FileAnalysisCacheTest.java @@ -4,11 +4,13 @@ package net.sourceforge.pmd.cache; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static com.github.stefanbirkner.systemlambda.SystemLambda.restoreSystemProperties; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -20,16 +22,15 @@ import java.net.URLClassLoader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mockito; import net.sourceforge.pmd.RuleSets; @@ -43,14 +44,10 @@ import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.document.TextFileContent; import net.sourceforge.pmd.lang.document.TextRange2d; -@SuppressWarnings("deprecation") -public class FileAnalysisCacheTest { +class FileAnalysisCacheTest { - @Rule - public TemporaryFolder tempFolder = new TemporaryFolder(); - - @Rule - public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + @TempDir + private Path tempFolder; private File unexistingCacheFile; private File newCacheFile; @@ -62,55 +59,56 @@ public class FileAnalysisCacheTest { private final LanguageVersion dummyVersion = LanguageRegistry.getDefaultLanguage().getDefaultVersion(); - @Before + @BeforeEach public void setUp() throws IOException { - unexistingCacheFile = new File(tempFolder.getRoot(), "non-existing-file.cache"); - newCacheFile = new File(tempFolder.getRoot(), "pmd-analysis.cache"); - emptyCacheFile = tempFolder.newFile(); - File sourceFile = tempFolder.newFile("Source.java"); - this.sourceFileBackend = TextFile.forPath(sourceFile.toPath(), Charset.defaultCharset(), dummyVersion); + unexistingCacheFile = tempFolder.resolve("non-existing-file.cache").toFile(); + newCacheFile = tempFolder.resolve("pmd-analysis.cache").toFile(); + emptyCacheFile = Files.createTempFile(tempFolder, null, null).toFile(); + Path sourceFile = tempFolder.resolve("Source.java"); + Files.write(sourceFile, listOf("dummy text")); + this.sourceFileBackend = TextFile.forPath(sourceFile, Charset.defaultCharset(), dummyVersion); this.sourceFile = TextDocument.create(sourceFileBackend); } @Test - public void testLoadFromNonExistingFile() throws IOException { + void testLoadFromNonExistingFile() throws IOException { final FileAnalysisCache cache = new FileAnalysisCache(unexistingCacheFile); - assertNotNull("Cache creation from non existing file failed.", cache); + assertNotNull(cache, "Cache creation from non existing file failed."); } @Test - public void testLoadFromEmptyFile() throws IOException { + void testLoadFromEmptyFile() throws IOException { final FileAnalysisCache cache = new FileAnalysisCache(emptyCacheFile); - assertNotNull("Cache creation from empty file failed.", cache); + assertNotNull(cache, "Cache creation from empty file failed."); } @Test - public void testLoadFromDirectoryShouldntThrow() throws IOException { - new FileAnalysisCache(tempFolder.getRoot()); + void testLoadFromDirectoryShouldntThrow() throws IOException { + new FileAnalysisCache(tempFolder.toFile()); } @Test - public void testLoadFromUnreadableFileShouldntThrow() throws IOException { + void testLoadFromUnreadableFileShouldntThrow() throws IOException { emptyCacheFile.setReadable(false); new FileAnalysisCache(emptyCacheFile); } @Test - public void testStoreCreatesFile() throws Exception { + void testStoreCreatesFile() throws Exception { final FileAnalysisCache cache = new FileAnalysisCache(unexistingCacheFile); cache.persist(); - assertTrue("Cache file doesn't exist after store", unexistingCacheFile.exists()); + assertTrue(unexistingCacheFile.exists(), "Cache file doesn't exist after store"); } @Test - public void testStoreOnUnwritableFileShouldntThrow() throws IOException { + void testStoreOnUnwritableFileShouldntThrow() throws IOException { emptyCacheFile.setWritable(false); final FileAnalysisCache cache = new FileAnalysisCache(emptyCacheFile); cache.persist(); } @Test - public void testStorePersistsFilesWithViolations() throws IOException { + void testStorePersistsFilesWithViolations() throws IOException { final FileAnalysisCache cache = new FileAnalysisCache(newCacheFile); cache.checkValidity(mock(RuleSets.class), mock(ClassLoader.class)); cache.isUpToDate(sourceFile); @@ -127,15 +125,15 @@ public class FileAnalysisCacheTest { final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); reloadedCache.checkValidity(mock(RuleSets.class), mock(ClassLoader.class)); - assertTrue("Cache believes unmodified file with violations is not up to date", - reloadedCache.isUpToDate(sourceFile)); + assertTrue(reloadedCache.isUpToDate(sourceFile), + "Cache believes unmodified file with violations is not up to date"); final List cachedViolations = reloadedCache.getCachedViolations(sourceFile); - assertEquals("Cached rule violations count mismatch", 1, cachedViolations.size()); + assertEquals(1, cachedViolations.size(), "Cached rule violations count mismatch"); } @Test - public void testCacheValidityWithNoChanges() throws IOException { + void testCacheValidityWithNoChanges() throws IOException { final RuleSets rs = mock(RuleSets.class); final ClassLoader cl = mock(ClassLoader.class); @@ -143,29 +141,29 @@ public class FileAnalysisCacheTest { final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); reloadedCache.checkValidity(rs, cl); - assertTrue("Cache believes unmodified file is not up to date without ruleset / classpath changes", - reloadedCache.isUpToDate(sourceFile)); + assertTrue(reloadedCache.isUpToDate(sourceFile), + "Cache believes unmodified file is not up to date without ruleset / classpath changes"); } @Test - public void testCacheValidityWithIrrelevantChanges() throws IOException { + void testCacheValidityWithIrrelevantChanges() throws IOException { final RuleSets rs = mock(RuleSets.class); final URLClassLoader cl = mock(URLClassLoader.class); when(cl.getURLs()).thenReturn(new URL[] {}); setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); - final File classpathFile = tempFolder.newFile("foo.xml"); + final File classpathFile = Files.createTempFile(tempFolder, null, "foo.xml").toFile(); when(cl.getURLs()).thenReturn(new URL[] { classpathFile.toURI().toURL(), }); final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); reloadedCache.checkValidity(rs, cl); - assertTrue("Cache believes unmodified file is not up to date without ruleset / classpath changes", - reloadedCache.isUpToDate(sourceFile)); + assertTrue(reloadedCache.isUpToDate(sourceFile), + "Cache believes unmodified file is not up to date without ruleset / classpath changes"); } @Test - public void testRulesetChangeInvalidatesCache() throws IOException { + void testRulesetChangeInvalidatesCache() throws IOException { final RuleSets rs = mock(RuleSets.class); final ClassLoader cl = mock(ClassLoader.class); @@ -174,27 +172,27 @@ public class FileAnalysisCacheTest { final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); when(rs.getChecksum()).thenReturn(1L); reloadedCache.checkValidity(rs, cl); - assertFalse("Cache believes unmodified file is up to date after ruleset changed", - reloadedCache.isUpToDate(sourceFile)); + assertFalse(reloadedCache.isUpToDate(sourceFile), + "Cache believes unmodified file is up to date after ruleset changed"); } @Test - public void testAuxClasspathNonExistingAuxclasspathEntriesIgnored() throws MalformedURLException, IOException { + void testAuxClasspathNonExistingAuxclasspathEntriesIgnored() throws MalformedURLException, IOException { final RuleSets rs = mock(RuleSets.class); final URLClassLoader cl = mock(URLClassLoader.class); - when(cl.getURLs()).thenReturn(new URL[] { new File(tempFolder.getRoot(), "non-existing-dir").toURI().toURL(), }); + when(cl.getURLs()).thenReturn(new URL[] { tempFolder.resolve("non-existing-dir").toFile().toURI().toURL(), }); setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); final FileAnalysisCache analysisCache = new FileAnalysisCache(newCacheFile); when(cl.getURLs()).thenReturn(new URL[] {}); analysisCache.checkValidity(rs, cl); - assertTrue("Cache believes unmodified file is not up to date after non-existing auxclasspath entry removed", - analysisCache.isUpToDate(sourceFile)); + assertTrue(analysisCache.isUpToDate(sourceFile), + "Cache believes unmodified file is not up to date after non-existing auxclasspath entry removed"); } @Test - public void testAuxClasspathChangeWithoutDFAorTypeResolutionDoesNotInvalidatesCache() throws MalformedURLException, IOException { + void testAuxClasspathChangeWithoutDFAorTypeResolutionDoesNotInvalidatesCache() throws MalformedURLException, IOException { final RuleSets rs = mock(RuleSets.class); final URLClassLoader cl = mock(URLClassLoader.class); when(cl.getURLs()).thenReturn(new URL[] { }); @@ -202,14 +200,14 @@ public class FileAnalysisCacheTest { setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); - when(cl.getURLs()).thenReturn(new URL[] { tempFolder.newFile().toURI().toURL(), }); + when(cl.getURLs()).thenReturn(new URL[] { Files.createTempFile(tempFolder, null, null).toFile().toURI().toURL(), }); reloadedCache.checkValidity(rs, cl); - assertTrue("Cache believes unmodified file is not up to date after auxclasspath changed when no rule cares", - reloadedCache.isUpToDate(sourceFile)); + assertTrue(reloadedCache.isUpToDate(sourceFile), + "Cache believes unmodified file is not up to date after auxclasspath changed when no rule cares"); } @Test - public void testAuxClasspathChangeInvalidatesCache() throws MalformedURLException, IOException { + void testAuxClasspathChangeInvalidatesCache() throws MalformedURLException, IOException { final RuleSets rs = mock(RuleSets.class); final URLClassLoader cl = mock(URLClassLoader.class); when(cl.getURLs()).thenReturn(new URL[] { }); @@ -217,7 +215,7 @@ public class FileAnalysisCacheTest { setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); - final File classpathFile = tempFolder.newFile("foo.class"); + final File classpathFile = Files.createTempFile(tempFolder, null, "foo.class").toFile(); when(cl.getURLs()).thenReturn(new URL[] { classpathFile.toURI().toURL(), }); // Make sure the auxclasspath file is not empty @@ -227,16 +225,16 @@ public class FileAnalysisCacheTest { when(r.getLanguage()).thenReturn(mock(Language.class)); when(rs.getAllRules()).thenReturn(Collections.singleton(r)); reloadedCache.checkValidity(rs, cl); - assertFalse("Cache believes unmodified file is up to date after auxclasspath changed", - reloadedCache.isUpToDate(sourceFile)); + assertFalse(reloadedCache.isUpToDate(sourceFile), + "Cache believes unmodified file is up to date after auxclasspath changed"); } @Test - public void testAuxClasspathJarContentsChangeInvalidatesCache() throws MalformedURLException, IOException { + void testAuxClasspathJarContentsChangeInvalidatesCache() throws MalformedURLException, IOException { final RuleSets rs = mock(RuleSets.class); final URLClassLoader cl = mock(URLClassLoader.class); - final File classpathFile = tempFolder.newFile("foo.class"); + final File classpathFile = Files.createTempFile(tempFolder, null, "foo.class").toFile(); when(cl.getURLs()).thenReturn(new URL[] { classpathFile.toURI().toURL(), }); final net.sourceforge.pmd.Rule r = mock(net.sourceforge.pmd.Rule.class); @@ -250,127 +248,136 @@ public class FileAnalysisCacheTest { final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); reloadedCache.checkValidity(rs, cl); - assertFalse("Cache believes cache is up to date when a auxclasspath file changed", - reloadedCache.isUpToDate(sourceFile)); + assertFalse(reloadedCache.isUpToDate(sourceFile), + "Cache believes cache is up to date when a auxclasspath file changed"); } @Test - public void testClasspathNonExistingEntryIsIgnored() throws MalformedURLException, IOException { - final RuleSets rs = mock(RuleSets.class); - final ClassLoader cl = mock(ClassLoader.class); + void testClasspathNonExistingEntryIsIgnored() throws Exception { + restoreSystemProperties(() -> { + final RuleSets rs = mock(RuleSets.class); + final ClassLoader cl = mock(ClassLoader.class); - System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator - + tempFolder.getRoot().getAbsolutePath() + File.separator + "non-existing-dir"); + System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + + tempFolder.toFile().getAbsolutePath() + File.separator + "non-existing-dir"); - final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); - try { + final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); + try { + reloadedCache.checkValidity(rs, cl); + } catch (final Exception e) { + fail("Validity check failed when classpath includes non-existing directories"); + } + }); + } + + @Test + void testClasspathChangeInvalidatesCache() throws Exception { + restoreSystemProperties(() -> { + final RuleSets rs = mock(RuleSets.class); + final ClassLoader cl = mock(ClassLoader.class); + + final File classpathFile = Files.createTempFile(tempFolder, null, "foo.class").toFile(); + + setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); + + // Edit the classpath referenced file + Files.write(classpathFile.toPath(), "some text".getBytes()); + System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + classpathFile.getAbsolutePath()); + + final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); reloadedCache.checkValidity(rs, cl); - } catch (final Exception e) { - fail("Validity check failed when classpath includes non-existing directories"); - } + assertFalse(reloadedCache.isUpToDate(sourceFile), + "Cache believes cache is up to date when the classpath changed"); + }); } @Test - public void testClasspathChangeInvalidatesCache() throws MalformedURLException, IOException { - final RuleSets rs = mock(RuleSets.class); - final ClassLoader cl = mock(ClassLoader.class); + void testClasspathContentsChangeInvalidatesCache() throws Exception { + restoreSystemProperties(() -> { + final RuleSets rs = mock(RuleSets.class); + final ClassLoader cl = mock(ClassLoader.class); - final File classpathFile = tempFolder.newFile("foo.class"); + final File classpathFile = Files.createTempFile(tempFolder, null, "foo.class").toFile(); - setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); + // Add a file to classpath + Files.write(classpathFile.toPath(), "some text".getBytes()); + System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + classpathFile.getAbsolutePath()); - // Edit the classpath referenced file - Files.write(classpathFile.toPath(), "some text".getBytes()); - System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + classpathFile.getAbsolutePath()); + setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); - final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); - reloadedCache.checkValidity(rs, cl); - assertFalse("Cache believes cache is up to date when the classpath changed", - reloadedCache.isUpToDate(sourceFile)); + // Change the file's contents + Files.write(classpathFile.toPath(), "some other text".getBytes()); + + final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); + reloadedCache.checkValidity(rs, cl); + assertFalse(reloadedCache.isUpToDate(sourceFile), + "Cache believes cache is up to date when a classpath file changed"); + }); } @Test - public void testClasspathContentsChangeInvalidatesCache() throws MalformedURLException, IOException { - final RuleSets rs = mock(RuleSets.class); - final ClassLoader cl = mock(ClassLoader.class); + void testWildcardClasspath() throws Exception { + restoreSystemProperties(() -> { + final RuleSets rs = mock(RuleSets.class); + final ClassLoader cl = mock(ClassLoader.class); + setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); - final File classpathFile = tempFolder.newFile("foo.class"); + // Prepare two class files + createZipFile("mylib1.jar"); + createZipFile("mylib2.jar"); - // Add a file to classpath - Files.write(classpathFile.toPath(), "some text".getBytes()); - System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + classpathFile.getAbsolutePath()); + System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + tempFolder.toFile().getAbsolutePath() + "/*"); - setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); - - // Change the file's contents - Files.write(classpathFile.toPath(), "some other text".getBytes()); - - final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); - reloadedCache.checkValidity(rs, cl); - assertFalse("Cache believes cache is up to date when a classpath file changed", - reloadedCache.isUpToDate(sourceFile)); + final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); + assertFalse(reloadedCache.isUpToDate(sourceFile), + "Cache believes cache is up to date when the classpath changed"); + }); } @Test - public void testWildcardClasspath() throws MalformedURLException, IOException { - final RuleSets rs = mock(RuleSets.class); - final ClassLoader cl = mock(ClassLoader.class); - setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); + void testWildcardClasspathContentsChangeInvalidatesCache() throws Exception { + restoreSystemProperties(() -> { + final RuleSets rs = mock(RuleSets.class); + final ClassLoader cl = mock(ClassLoader.class); - // Prepare two class files - createZipFile("mylib1.jar"); - createZipFile("mylib2.jar"); + // Prepare two jar files + final File classpathJar1 = createZipFile("mylib1.jar"); + createZipFile("mylib2.jar"); - System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + tempFolder.getRoot().getAbsolutePath() + "/*"); + System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + tempFolder.toFile().getAbsolutePath() + "/*"); - final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); - reloadedCache.checkValidity(rs, cl); - assertFalse("Cache believes cache is up to date when the classpath changed", - reloadedCache.isUpToDate(sourceFile)); + setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); + + // Change one file's contents (ie: adding more entries) + classpathJar1.delete(); + createZipFile(classpathJar1.getName(), 2); + + final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); + reloadedCache.checkValidity(rs, cl); + assertFalse(reloadedCache.isUpToDate(sourceFile), + "Cache believes cache is up to date when the classpath changed"); + }); } @Test - public void testWildcardClasspathContentsChangeInvalidatesCache() throws MalformedURLException, IOException { - final RuleSets rs = mock(RuleSets.class); - final ClassLoader cl = mock(ClassLoader.class); - - // Prepare two jar files - final File classpathJar1 = createZipFile("mylib1.jar"); - createZipFile("mylib2.jar"); - - System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + tempFolder.getRoot().getAbsolutePath() + "/*"); - - setupCacheWithFiles(newCacheFile, rs, cl, sourceFile); - - // Change one file's contents (ie: adding more entries) - classpathJar1.delete(); - createZipFile(classpathJar1.getName(), 2); - - final FileAnalysisCache reloadedCache = new FileAnalysisCache(newCacheFile); - reloadedCache.checkValidity(rs, cl); - assertFalse("Cache believes cache is up to date when the classpath changed", - reloadedCache.isUpToDate(sourceFile)); - } - - @Test - public void testUnknownFileIsNotUpToDate() throws IOException { + void testUnknownFileIsNotUpToDate() throws IOException { final FileAnalysisCache cache = new FileAnalysisCache(newCacheFile); - assertFalse("Cache believes an unknown file is up to date", - cache.isUpToDate(sourceFile)); + assertFalse(cache.isUpToDate(sourceFile), + "Cache believes an unknown file is up to date"); } @Test - public void testFileIsUpToDate() throws IOException { + void testFileIsUpToDate() throws IOException { setupCacheWithFiles(newCacheFile, mock(RuleSets.class), mock(ClassLoader.class), sourceFile); final FileAnalysisCache cache = new FileAnalysisCache(newCacheFile); cache.checkValidity(mock(RuleSets.class), mock(ClassLoader.class)); - assertTrue("Cache believes a known, unchanged file is not up to date", - cache.isUpToDate(sourceFile)); + assertTrue(cache.isUpToDate(sourceFile), + "Cache believes a known, unchanged file is not up to date"); } @Test - public void testFileIsNotUpToDateWhenEdited() throws IOException { + void testFileIsNotUpToDateWhenEdited() throws IOException { setupCacheWithFiles(newCacheFile, mock(RuleSets.class), mock(ClassLoader.class), sourceFile); // Edit the file @@ -380,7 +387,8 @@ public class FileAnalysisCacheTest { sourceFile = TextDocument.create(sourceFileBackend); final FileAnalysisCache cache = new FileAnalysisCache(newCacheFile); - assertFalse("Cache believes a known, changed file is up to date", cache.isUpToDate(sourceFile)); + assertFalse(cache.isUpToDate(sourceFile), + "Cache believes a known, changed file is up to date"); } private void setupCacheWithFiles(final File cacheFile, @@ -402,7 +410,7 @@ public class FileAnalysisCacheTest { } private File createZipFile(String fileName, int numEntries) throws IOException { - final File zipFile = tempFolder.newFile(fileName); + final File zipFile = Files.createTempFile(tempFolder, null, fileName).toFile(); try (ZipOutputStream zipOS = new ZipOutputStream(Files.newOutputStream(zipFile.toPath()))) { for (int i = 0; i < numEntries; i++) { zipOS.putNextEntry(new ZipEntry("lib/foo" + i + ".class")); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/AbstractClasspathEntryFingerprinterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/AbstractClasspathEntryFingerprinterTest.java index cf7a04276b..4ba8418638 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/AbstractClasspathEntryFingerprinterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/AbstractClasspathEntryFingerprinterTest.java @@ -4,33 +4,36 @@ package net.sourceforge.pmd.cache.internal; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.File; import java.io.IOException; import java.net.MalformedURLException; +import java.nio.file.Path; import java.util.zip.Adler32; import java.util.zip.Checksum; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +abstract class AbstractClasspathEntryFingerprinterTest { -@RunWith(JUnitParamsRunner.class) -public abstract class AbstractClasspathEntryFingerprinterTest { - - @Rule - public TemporaryFolder tempFolder = new TemporaryFolder(); + @TempDir + Path tempDir; protected ClasspathEntryFingerprinter fingerprinter = newFingerPrinter(); protected Checksum checksum = new Adler32(); - @Before - public void setUp() { + @BeforeEach + void setUp() { checksum.reset(); } @@ -43,37 +46,37 @@ public abstract class AbstractClasspathEntryFingerprinterTest { protected abstract File createValidNonEmptyFile() throws IOException; @Test - public void appliesToNullIsSafe() { + void appliesToNullIsSafe() { fingerprinter.appliesTo(null); } - @Parameters(method = "getValidFileExtensions") - @Test - public void appliesToValidFile(final String extension) { - Assert.assertTrue(fingerprinter.appliesTo(extension)); + @ParameterizedTest + @MethodSource("getValidFileExtensions") + void appliesToValidFile(final String extension) { + assertTrue(fingerprinter.appliesTo(extension)); } - @Parameters(method = "getInvalidFileExtensions") - @Test - public void doesNotApplyToInvalidFile(final String extension) { - Assert.assertFalse(fingerprinter.appliesTo(extension)); + @ParameterizedTest + @MethodSource("getInvalidFileExtensions") + void doesNotApplyToInvalidFile(final String extension) { + assertFalse(fingerprinter.appliesTo(extension)); } @Test - public void fingerprintNonExistingFile() throws MalformedURLException, IOException { + void fingerprintNonExistingFile() throws MalformedURLException, IOException { final long prevValue = checksum.getValue(); fingerprinter.fingerprint(new File("non-existing").toURI().toURL(), checksum); - Assert.assertEquals(prevValue, checksum.getValue()); + assertEquals(prevValue, checksum.getValue()); } @Test - public void fingerprintExistingValidFile() throws IOException { + void fingerprintExistingValidFile() throws IOException { final long prevValue = checksum.getValue(); final File file = createValidNonEmptyFile(); - Assert.assertNotEquals(prevValue, updateFingerprint(file)); + assertNotEquals(prevValue, updateFingerprint(file)); } protected long updateFingerprint(final File file) throws MalformedURLException, IOException { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/RawFileFingerprinterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/RawFileFingerprinterTest.java index c494d5f4df..a7eefecada 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/RawFileFingerprinterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/RawFileFingerprinterTest.java @@ -10,7 +10,7 @@ import java.nio.charset.StandardCharsets; import com.google.common.io.Files; -public class RawFileFingerprinterTest extends AbstractClasspathEntryFingerprinterTest { +class RawFileFingerprinterTest extends AbstractClasspathEntryFingerprinterTest { @Override protected ClasspathEntryFingerprinter newFingerPrinter() { @@ -29,7 +29,7 @@ public class RawFileFingerprinterTest extends AbstractClasspathEntryFingerprinte @Override protected File createValidNonEmptyFile() throws IOException { - final File file = tempFolder.newFile("Foo.class"); + File file = tempDir.resolve("Foo.class").toFile(); Files.write("some content", file, StandardCharsets.UTF_8); return file; diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/ZipFileFingerprinterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/ZipFileFingerprinterTest.java index 9fc3a9a618..62017b3be3 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/ZipFileFingerprinterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cache/internal/ZipFileFingerprinterTest.java @@ -4,6 +4,9 @@ package net.sourceforge.pmd.cache.internal; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + import java.io.File; import java.io.IOException; import java.net.MalformedURLException; @@ -15,13 +18,12 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class ZipFileFingerprinterTest extends AbstractClasspathEntryFingerprinterTest { +class ZipFileFingerprinterTest extends AbstractClasspathEntryFingerprinterTest { @Test - public void zipEntryMetadataDoesNotAffectFingerprint() throws IOException { + void zipEntryMetadataDoesNotAffectFingerprint() throws IOException { final File file = createValidNonEmptyFile(); final long baselineFingerprint = getBaseLineFingerprint(file); final long originalFileSize = file.length(); @@ -35,8 +37,8 @@ public class ZipFileFingerprinterTest extends AbstractClasspathEntryFingerprinte overwriteZipFileContents(file, zipEntry); } - Assert.assertEquals(baselineFingerprint, updateFingerprint(file)); - Assert.assertNotEquals(originalFileSize, file.length()); + assertEquals(baselineFingerprint, updateFingerprint(file)); + assertNotEquals(originalFileSize, file.length()); } @Override @@ -56,7 +58,7 @@ public class ZipFileFingerprinterTest extends AbstractClasspathEntryFingerprinte @Override protected File createValidNonEmptyFile() throws IOException { - final File zipFile = tempFolder.newFile("foo.jar"); + final File zipFile = tempDir.resolve("foo.jar").toFile(); overwriteZipFileContents(zipFile, new ZipEntry("lib/Foo.class")); return zipFile; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cli/CoreCliTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cli/CoreCliTest.java index 47106eb626..9e584759c3 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cli/CoreCliTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cli/CoreCliTest.java @@ -8,10 +8,10 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsStringIgnoringCase; import static org.hamcrest.Matchers.not; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; @@ -20,49 +20,40 @@ import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; -import org.apache.commons.io.IOUtils; -import org.hamcrest.Matcher; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; -import org.junit.contrib.java.lang.system.SystemErrRule; -import org.junit.contrib.java.lang.system.SystemOutRule; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.PMD.StatusCode; import net.sourceforge.pmd.internal.Slf4jSimpleConfiguration; +import net.sourceforge.pmd.util.IOUtil; + +import com.github.stefanbirkner.systemlambda.SystemLambda; /** * */ -public class CoreCliTest { +class CoreCliTest { + + @TempDir + private Path tempDir; private static final String DUMMY_RULESET = "net/sourceforge/pmd/cli/FakeRuleset.xml"; private static final String STRING_TO_REPLACE = "__should_be_replaced__"; - @Rule - public TemporaryFolder tempDir = new TemporaryFolder(); - // restoring system properties: -debug might change logging properties - // See Slf4jSimpleConfigurationForAnt and resetLogging - @Rule - public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); - @Rule - public final SystemOutRule outStreamCaptor = new SystemOutRule().muteForSuccessfulTests().enableLog(); - @Rule - public final SystemErrRule errStreamCaptor = new SystemErrRule().muteForSuccessfulTests().enableLog(); + private Path srcDir; - @AfterClass - public static void resetLogging() { + @AfterAll + static void resetLogging() { + // reset logging in case "--debug" changed the logging properties + // See also Slf4jSimpleConfigurationForAnt Slf4jSimpleConfiguration.reconfigureDefaultLogLevel(null); } - private Path srcDir; - - @Before - public void setup() throws IOException { + @BeforeEach + void setup() throws IOException { // set current directory to wd Path root = tempRoot(); System.setProperty("user.dir", root.toString()); @@ -74,85 +65,88 @@ public class CoreCliTest { @Test - public void testPreExistingReportFile() throws IOException { + void testPreExistingReportFile() throws Exception { Path reportFile = tempRoot().resolve("out/reportFile.txt"); // now we create the file Files.createDirectories(reportFile.getParent()); writeString(reportFile, STRING_TO_REPLACE); - assertTrue("Report file should exist", Files.exists(reportFile)); + assertTrue(Files.exists(reportFile), "Report file should exist"); - runPmdSuccessfully("-no-cache", "-d", srcDir, "-R", DUMMY_RULESET, "-r", reportFile); + runPmdSuccessfully("--no-cache", "-d", srcDir, "-R", DUMMY_RULESET, "-r", reportFile); assertNotEquals(readString(reportFile), STRING_TO_REPLACE); } @Test - public void testPreExistingReportFileLongOption() throws IOException { + void testPreExistingReportFileLongOption() throws Exception { Path reportFile = tempRoot().resolve("out/reportFile.txt"); // now we create the file Files.createDirectories(reportFile.getParent()); writeString(reportFile, STRING_TO_REPLACE); - assertTrue("Report file should exist", Files.exists(reportFile)); + assertTrue(Files.exists(reportFile), "Report file should exist"); runPmdSuccessfully("--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET, "--report-file", reportFile); - assertNotEquals("Report file should have been overwritten", readString(reportFile), STRING_TO_REPLACE); + assertNotEquals(readString(reportFile), STRING_TO_REPLACE, "Report file should have been overwritten"); } @Test - public void testNonExistentReportFile() throws IOException { + void testNonExistentReportFile() throws Exception { Path reportFile = tempRoot().resolve("out/reportFile.txt"); - assertFalse("Report file should not exist", Files.exists(reportFile)); + assertFalse(Files.exists(reportFile), "Report file should not exist"); try { - runPmdSuccessfully("-no-cache", "-d", srcDir, "-R", DUMMY_RULESET, "-r", reportFile); - assertTrue("Report file should have been created", Files.exists(reportFile)); + runPmdSuccessfully("--no-cache", "-d", srcDir, "-R", DUMMY_RULESET, "-r", reportFile); + assertTrue(Files.exists(reportFile), "Report file should have been created"); } finally { Files.deleteIfExists(reportFile); } } @Test - public void testNonExistentReportFileLongOption() { + void testNonExistentReportFileLongOption() throws Exception { Path reportFile = tempRoot().resolve("out/reportFile.txt"); - assertFalse("Report file should not exist", Files.exists(reportFile)); + assertFalse(Files.exists(reportFile), "Report file should not exist"); runPmdSuccessfully("--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET, "--report-file", reportFile); - assertTrue("Report file should have been created", Files.exists(reportFile)); + assertTrue(Files.exists(reportFile), "Report file should have been created"); } @Test - public void testFileCollectionWithUnknownFiles() throws IOException { + void testFileCollectionWithUnknownFiles() throws Exception { Path reportFile = tempRoot().resolve("out/reportFile.txt"); Files.createFile(srcDir.resolve("foo.not_analysable")); - assertFalse("Report file should not exist", Files.exists(reportFile)); + assertFalse(Files.exists(reportFile), "Report file should not exist"); - runPmdSuccessfully("--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET, "--report-file", reportFile, "--debug"); + // restoring system properties: --debug might change logging properties + SystemLambda.restoreSystemProperties(() -> { + runPmdSuccessfully("--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET, "--report-file", reportFile, "--debug"); + }); - assertTrue("Report file should have been created", Files.exists(reportFile)); - String reportText = IOUtils.toString(Files.newBufferedReader(reportFile, StandardCharsets.UTF_8)); + assertTrue(Files.exists(reportFile), "Report file should have been created"); + String reportText = IOUtil.readToString(Files.newBufferedReader(reportFile, StandardCharsets.UTF_8)); assertThat(reportText, not(containsStringIgnoringCase("error"))); } @Test - public void testNonExistentReportFileDeprecatedOptions() { + void testNonExistentReportFileDeprecatedOptions() throws Exception { Path reportFile = tempRoot().resolve("out/reportFile.txt"); - assertFalse("Report file should not exist", Files.exists(reportFile)); + assertFalse(Files.exists(reportFile), "Report file should not exist"); - runPmdSuccessfully("-no-cache", "-dir", srcDir, "-rulesets", DUMMY_RULESET, "-reportfile", reportFile); + String log = runPmdSuccessfully("-no-cache", "-dir", srcDir, "-rulesets", DUMMY_RULESET, "-reportfile", reportFile); - assertTrue("Report file should have been created", Files.exists(reportFile)); - assertTrue(errStreamCaptor.getLog().contains("Some deprecated options were used on the command-line, including -rulesets")); - assertTrue(errStreamCaptor.getLog().contains("Consider replacing it with --rulesets (or -R)")); + assertTrue(Files.exists(reportFile), "Report file should have been created"); + assertTrue(log.contains("Some deprecated options were used on the command-line, including -rulesets")); + assertTrue(log.contains("Consider replacing it with --rulesets (or -R)")); // only one parameter is logged - assertFalse(errStreamCaptor.getLog().contains("Some deprecated options were used on the command-line, including -reportfile")); - assertFalse(errStreamCaptor.getLog().contains("Consider replacing it with --report-file")); + assertFalse(log.contains("Some deprecated options were used on the command-line, including -reportfile")); + assertFalse(log.contains("Consider replacing it with --report-file")); } /** @@ -163,73 +157,82 @@ public class CoreCliTest { * and makes sure to cleanup the file afterwards. */ @Test - public void testRelativeReportFile() throws IOException { + void testRelativeReportFile() throws Exception { String reportFile = "reportFile.txt"; Path absoluteReportFile = FileSystems.getDefault().getPath(reportFile).toAbsolutePath(); // verify the file doesn't exist yet - we will delete the file at the end! - assertFalse("Report file must not exist yet!", Files.exists(absoluteReportFile)); + assertFalse(Files.exists(absoluteReportFile), "Report file must not exist yet! " + absoluteReportFile); try { - runPmdSuccessfully("-no-cache", "-d", srcDir, "-R", DUMMY_RULESET, "-r", reportFile); - assertTrue("Report file should have been created", Files.exists(absoluteReportFile)); + runPmdSuccessfully("--no-cache", "-d", srcDir, "-R", DUMMY_RULESET, "-r", reportFile); + assertTrue(Files.exists(absoluteReportFile), "Report file should have been created"); } finally { Files.deleteIfExists(absoluteReportFile); } } @Test - public void testRelativeReportFileLongOption() throws IOException { + void testRelativeReportFileLongOption() throws Exception { String reportFile = "reportFile.txt"; Path absoluteReportFile = FileSystems.getDefault().getPath(reportFile).toAbsolutePath(); // verify the file doesn't exist yet - we will delete the file at the end! - assertFalse("Report file must not exist yet!", Files.exists(absoluteReportFile)); + assertFalse(Files.exists(absoluteReportFile), "Report file must not exist yet!"); try { runPmdSuccessfully("--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET, "--report-file", reportFile); - assertTrue("Report file should have been created", Files.exists(absoluteReportFile)); + assertTrue(Files.exists(absoluteReportFile), "Report file should have been created"); } finally { Files.deleteIfExists(absoluteReportFile); } } @Test - public void debugLogging() { - runPmdSuccessfully("--debug", "--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET); - assertThat(errStreamCaptor.getLog(), containsString("[main] INFO net.sourceforge.pmd.PMD - Log level is at TRACE")); + void debugLogging() throws Exception { + // restoring system properties: --debug might change logging properties + SystemLambda.restoreSystemProperties(() -> { + String log = runPmdSuccessfully("--debug", "--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET); + assertThat(log, containsString("[main] INFO net.sourceforge.pmd.PMD - Log level is at TRACE")); + }); } @Test - public void defaultLogging() { - runPmdSuccessfully("--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET); - assertThat(errStreamCaptor.getLog(), containsString("[main] INFO net.sourceforge.pmd.PMD - Log level is at INFO")); + void defaultLogging() throws Exception { + String log = runPmdSuccessfully("--no-cache", "--dir", srcDir, "--rulesets", DUMMY_RULESET); + assertThat(log, containsString("[main] INFO net.sourceforge.pmd.PMD - Log level is at INFO")); + } + + @Test + void testDeprecatedRulesetSyntaxOnCommandLine() throws Exception { + String log = SystemLambda.tapSystemErrAndOut(() -> { + runPmd(StatusCode.VIOLATIONS_FOUND, "--no-cache", "--dir", srcDir, "--rulesets", "dummy-basic"); + }); + assertThat(log, containsString("Ruleset reference 'dummy-basic' uses a deprecated form, use 'rulesets/dummy/basic.xml' instead")); } @Test - public void testWrongCliOptionsDoNotPrintUsage() { + void testWrongCliOptionsDoNotPrintUsage() throws Exception { String[] args = { "-invalid" }; PmdParametersParseResult params = PmdParametersParseResult.extractParameters(args); - assertTrue("Expected invalid args", params.isError()); + assertTrue(params.isError(), "Expected invalid args"); - StatusCode code = PMD.runPmd(args); - assertEquals(StatusCode.ERROR, code); - assertThatErrAndOut(not(containsStringIgnoringCase("Available report formats and"))); + String log = SystemLambda.tapSystemErrAndOut(() -> { + StatusCode code = PMD.runPmd(args); + assertEquals(StatusCode.ERROR, code); + }); + assertThat(log, not(containsStringIgnoringCase("Available report formats and"))); } // utilities - - private void assertThatErrAndOut(Matcher matcher) { - assertThat("stdout", outStreamCaptor.getLog(), matcher); - assertThat("stderr", errStreamCaptor.getLog(), matcher); - } - private Path tempRoot() { - return tempDir.getRoot().toPath(); + return tempDir; } - private static void runPmdSuccessfully(Object... args) { - runPmd(0, args); + private static String runPmdSuccessfully(Object... args) throws Exception { + return SystemLambda.tapSystemErrAndOut(() -> { + runPmd(StatusCode.OK, args); + }); } private static String[] argsToString(Object... args) { @@ -254,9 +257,9 @@ public class CoreCliTest { return StandardCharsets.UTF_8.decode(buf).toString(); } - private static void runPmd(int expectedExitCode, Object[] args) { + private static void runPmd(StatusCode expectedExitCode, Object... args) { StatusCode actualExitCode = PMD.runPmd(argsToString(args)); - assertEquals("Exit code", expectedExitCode, actualExitCode.toInt()); + assertEquals(expectedExitCode, actualExitCode, "Exit code"); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDCommandLineInterfaceTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDCommandLineInterfaceTest.java index 5923717395..83b16fe69f 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDCommandLineInterfaceTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDCommandLineInterfaceTest.java @@ -4,59 +4,55 @@ package net.sourceforge.pmd.cli; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.ExpectedSystemExit; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.cache.NoopAnalysisCache; +import com.github.stefanbirkner.systemlambda.SystemLambda; + /** * Unit test for {@link PMDCommandLineInterface} */ -public class PMDCommandLineInterfaceTest { - @Rule - public final ExpectedSystemExit exit = ExpectedSystemExit.none(); +class PMDCommandLineInterfaceTest { - @Rule // Restores system properties after test - public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); - - @Before - public void clearSystemProperties() { + @BeforeEach + void clearSystemProperties() { System.clearProperty(PMDCommandLineInterface.NO_EXIT_AFTER_RUN); System.clearProperty(PMDCommandLineInterface.STATUS_CODE_PROPERTY); } @Test - public void testProperties() { + void testProperties() { PMDParameters params = new PMDParameters(); String[] args = { "-d", "source_folder", "-f", "yahtml", "-P", "outputDir=output_folder", "-R", "java-empty", }; PMDCommandLineInterface.extractParameters(params, args, "PMD"); - Assert.assertEquals("output_folder", params.getProperties().getProperty("outputDir")); + assertEquals("output_folder", params.getProperties().getProperty("outputDir")); } @Test - public void testMultipleProperties() { + void testMultipleProperties() { PMDParameters params = new PMDParameters(); String[] args = { "-d", "source_folder", "-f", "ideaj", "-P", "sourcePath=/home/user/source/", "-P", "fileName=Foo.java", "-P", "classAndMethodName=Foo.method", "-R", "java-empty", }; PMDCommandLineInterface.extractParameters(params, args, "PMD"); - Assert.assertEquals("/home/user/source/", params.getProperties().getProperty("sourcePath")); - Assert.assertEquals("Foo.java", params.getProperties().getProperty("fileName")); - Assert.assertEquals("Foo.method", params.getProperties().getProperty("classAndMethodName")); + assertEquals("/home/user/source/", params.getProperties().getProperty("sourcePath")); + assertEquals("Foo.java", params.getProperties().getProperty("fileName")); + assertEquals("Foo.method", params.getProperties().getProperty("classAndMethodName")); } @Test - public void testNoCacheSwitch() { + void testNoCacheSwitch() { PMDParameters params = new PMDParameters(); String[] args = {"-d", "source_folder", "-f", "ideaj", "-R", "java-empty", "-cache", "/home/user/.pmd/cache", "-no-cache", }; PMDCommandLineInterface.extractParameters(params, args, "PMD"); @@ -68,7 +64,7 @@ public class PMDCommandLineInterfaceTest { } @Test - public void testNoCacheSwitchLongOption() { + void testNoCacheSwitchLongOption() { PMDParameters params = new PMDParameters(); String[] args = {"-d", "source_folder", "-f", "ideaj", "-R", "java-empty", "--cache", "/home/user/.pmd/cache", "--no-cache", }; PMDCommandLineInterface.extractParameters(params, args, "PMD"); @@ -80,24 +76,34 @@ public class PMDCommandLineInterfaceTest { } @Test - public void testSetStatusCodeOrExitDoExit() { - exit.expectSystemExitWithStatus(0); - - PMDCommandLineInterface.setStatusCodeOrExit(0); + void testSetStatusCodeOrExitDoExit() throws Exception { + int code = SystemLambda.catchSystemExit(() -> PMDCommandLineInterface.setStatusCodeOrExit(0)); + assertEquals(0, code); } @Test - public void testSetStatusCodeOrExitSetStatus() { + void testSetStatusCodeOrExitSetStatus() { System.setProperty(PMDCommandLineInterface.NO_EXIT_AFTER_RUN, "1"); PMDCommandLineInterface.setStatusCodeOrExit(0); - Assert.assertEquals(System.getProperty(PMDCommandLineInterface.STATUS_CODE_PROPERTY), "0"); + assertEquals(System.getProperty(PMDCommandLineInterface.STATUS_CODE_PROPERTY), "0"); } @Test - public void testBuildUsageText() { + void testBuildUsageText() { // no exception.. - Assert.assertNotNull(PMDCommandLineInterface.buildUsageText()); + assertNotNull(PMDCommandLineInterface.buildUsageText()); } + @Test + void testOnlyFileListOption() { + PMDParameters params = new PMDParameters(); + String[] args = {"--file-list", "pmd.filelist", "-f", "text", "-R", "rulesets/java/quickstart.xml", "--no-cache", }; + PMDCommandLineInterface.extractParameters(params, args, "PMD"); + + PMDConfiguration config = params.toConfiguration(); + assertEquals("pmd.filelist", config.getInputFilePath()); + assertTrue(config.getAllInputPaths().isEmpty()); // no additional input paths + assertNull(config.getInputPaths()); + } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDFilelistTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDFilelistTest.java index e0e5d2d8e6..eedfca8adb 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDFilelistTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDFilelistTest.java @@ -12,7 +12,7 @@ import java.io.IOException; import java.util.List; import org.checkerframework.checker.nullness.qual.NonNull; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.internal.util.FileCollectionUtil; @@ -21,14 +21,14 @@ import net.sourceforge.pmd.lang.document.FileCollector; import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.util.log.internal.NoopReporter; -public class PMDFilelistTest { +class PMDFilelistTest { private static @NonNull FileCollector newCollector() { return FileCollector.newCollector(new LanguageVersionDiscoverer(), new NoopReporter()); } @Test - public void testGetApplicableFiles() throws IOException { + void testGetApplicableFiles() throws IOException { FileCollector collector = newCollector(); FileCollectionUtil.collectFileList(collector, "src/test/resources/net/sourceforge/pmd/cli/filelist.txt"); @@ -40,7 +40,7 @@ public class PMDFilelistTest { } @Test - public void testGetApplicableFilesMultipleLines() throws IOException { + void testGetApplicableFilesMultipleLines() throws IOException { FileCollector collector = newCollector(); FileCollectionUtil.collectFileList(collector, "src/test/resources/net/sourceforge/pmd/cli/filelist2.txt"); @@ -53,7 +53,7 @@ public class PMDFilelistTest { } @Test - public void testGetApplicableFilesWithIgnores() throws IOException { + void testGetApplicableFilesWithIgnores() throws IOException { FileCollector collector = newCollector(); PMDConfiguration configuration = new PMDConfiguration(); @@ -68,7 +68,7 @@ public class PMDFilelistTest { } @Test - public void testGetApplicableFilesWithDirAndIgnores() throws IOException { + void testGetApplicableFilesWithDirAndIgnores() throws IOException { PMDConfiguration configuration = new PMDConfiguration(); configuration.setInputPaths("src/test/resources/net/sourceforge/pmd/cli/src"); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDParametersTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDParametersTest.java index 22ca614a06..58a2860538 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDParametersTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDParametersTest.java @@ -4,20 +4,82 @@ package net.sourceforge.pmd.cli; -import org.apache.commons.lang3.reflect.FieldUtils; -import org.junit.Assert; -import org.junit.Test; +import static net.sourceforge.pmd.util.CollectionUtil.listOf; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class PMDParametersTest { +import org.apache.commons.lang3.reflect.FieldUtils; +import org.junit.jupiter.api.Test; + +import net.sourceforge.pmd.PMDConfiguration; + +class PMDParametersTest { @Test - public void testVersion() throws Exception { + void testVersion() throws Exception { PMDParameters parameters = new PMDParameters(); // no language set, uses default language - Assert.assertEquals("1.7", parameters.getVersion()); + assertEquals("1.7", parameters.getVersion()); // now set language FieldUtils.writeDeclaredField(parameters, "language", "dummy2", true); - Assert.assertEquals("1.0", parameters.getVersion()); + assertEquals("1.0", parameters.getVersion()); } + + @Test + void testMultipleDirsAndRuleSets() { + PmdParametersParseResult result = PmdParametersParseResult.extractParameters( + "-d", "a", "b", "-R", "x.xml", "y.xml" + ); + assertMultipleDirsAndRulesets(result); + } + + @Test + void testMultipleDirsAndRuleSetsWithCommas() { + PmdParametersParseResult result = PmdParametersParseResult.extractParameters( + "-d", "a,b", "-R", "x.xml,y.xml" + ); + assertMultipleDirsAndRulesets(result); + } + + @Test + void testMultipleDirsAndRuleSetsWithRepeatedOption() { + PmdParametersParseResult result = PmdParametersParseResult.extractParameters( + "-d", "a", "-d", "b", "-R", "x.xml", "-R", "y.xml" + ); + assertMultipleDirsAndRulesets(result); + } + + @Test + void testNoPositionalParametersAllowed() { + assertError( + // vvvv + "-R", "x.xml", "-d", "a", "--", "-d", "b" + ); + } + + + private void assertMultipleDirsAndRulesets(PmdParametersParseResult result) { + assertFalse(result.isError()); + PMDConfiguration config = result.toConfiguration(); + assertEquals(config.getAllInputPaths(), listOf("a", "b")); + assertEquals(config.getRuleSetPaths(), listOf("x.xml", "y.xml")); + } + + @Test + void testEmptyDirOption() { + assertError("-d", "-R", "y.xml"); + } + + @Test + void testEmptyRulesetOption() { + assertError("-R", "-d", "something"); + } + + private void assertError(String... params) { + PmdParametersParseResult result = PmdParametersParseResult.extractParameters(params); + assertTrue(result.isError()); + } + } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/AnyTokenizerTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/AnyTokenizerTest.java index 64f05ef145..ba9654f2c4 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/AnyTokenizerTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/AnyTokenizerTest.java @@ -5,29 +5,29 @@ package net.sourceforge.pmd.cpd; import static net.sourceforge.pmd.util.CollectionUtil.listOf; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class AnyTokenizerTest { +class AnyTokenizerTest { @Test - public void testMultiLineMacros() { + void testMultiLineMacros() { AnyTokenizer tokenizer = new AnyTokenizer("//"); compareResult(tokenizer, TEST1, EXPECTED); } @Test - public void testStringEscape() { + void testStringEscape() { AnyTokenizer tokenizer = new AnyTokenizer("//"); compareResult(tokenizer, "a = \"oo\\n\"", listOf("a", "=", "\"oo\\n\"", "EOF")); } @Test - public void testMultilineString() { + void testMultilineString() { AnyTokenizer tokenizer = new AnyTokenizer("//"); Tokens tokens = compareResult(tokenizer, "a = \"oo\n\";", listOf("a", "=", "\"oo\n\"", ";", "EOF")); TokenEntry string = tokens.getTokens().get(2); @@ -47,7 +47,7 @@ public class AnyTokenizerTest { * Tests that [core][cpd] AnyTokenizer doesn't count columns correctly #2760 is actually fixed. */ @Test - public void testTokenPosition() { + void testTokenPosition() { AnyTokenizer tokenizer = new AnyTokenizer(); SourceCode code = new SourceCode(new SourceCode.StringCodeLoader("a;\nbbbb\n;")); Tokens tokens = new Tokens(); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDCommandLineInterfaceTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDCommandLineInterfaceTest.java index b611b2ccec..33a04c47ff 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDCommandLineInterfaceTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDCommandLineInterfaceTest.java @@ -4,64 +4,65 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; -import org.junit.contrib.java.lang.system.SystemErrRule; -import org.junit.contrib.java.lang.system.SystemOutRule; -import org.junit.rules.TemporaryFolder; -import org.junit.rules.TestRule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -public class CPDCommandLineInterfaceTest { +import com.github.stefanbirkner.systemlambda.SystemLambda; + +class CPDCommandLineInterfaceTest { private static final String SRC_DIR = "src/test/resources/net/sourceforge/pmd/cpd/files/"; - @Rule - public final TestRule restoreSystemProperties = new RestoreSystemProperties(); - @Rule - public final SystemOutRule log = new SystemOutRule().enableLog().muteForSuccessfulTests(); - @Rule - public final SystemErrRule systemErrRule = new SystemErrRule().muteForSuccessfulTests().enableLog(); - @Rule - public TemporaryFolder tempDir = new TemporaryFolder(); + @TempDir + private Path tempDir; - @Before - public void setup() { + @BeforeEach + void setup() { System.setProperty(CPDCommandLineInterface.NO_EXIT_AFTER_RUN, "true"); } @Test - public void testEmptyResultRendering() { - CPDCommandLineInterface.main(new String[] { "--minimum-tokens", "340", "--language", "java", "--files", - SRC_DIR, "--format", "xml", }); - Assert.assertEquals("" + "\n" + "", log.getLog().trim()); + void testEmptyResultRendering() throws Exception { + String stdout = SystemLambda.tapSystemOut(() -> { + SystemLambda.tapSystemErr(() -> { + CPD.StatusCode statusCode = CPD.runCpd("--minimum-tokens", "340", "--language", "java", "--files", + SRC_DIR, "--format", "xml"); + assertEquals(CPD.StatusCode.OK, statusCode); + }); + }); + assertEquals("" + "\n" + "", stdout.trim()); } @Test - public void testDeprecatedOptionsWarning() throws IOException { - File filelist = new File(tempDir.getRoot(), "cpd-test-file-list.txt"); + void testDeprecatedOptionsWarning() throws Exception { + File filelist = new File(tempDir.toFile(), "cpd-test-file-list.txt"); Files.write(filelist.toPath(), Arrays.asList( new File(SRC_DIR, "dup1.java").getAbsolutePath(), new File(SRC_DIR, "dup2.java").getAbsolutePath()), StandardCharsets.UTF_8); - CPDCommandLineInterface.main(new String[] { "--minimum-tokens", "340", "--language", "java", "--filelist", - filelist.getAbsolutePath(), "--format", "xml", "-failOnViolation", "true" }); - Assert.assertEquals("" + "\n" + "", log.getLog().trim()); - assertTrue(systemErrRule.getLog().contains("Some deprecated options were used on the command-line, including -failOnViolation")); - assertTrue(systemErrRule.getLog().contains("Consider replacing it with --fail-on-violation")); + String stderr = SystemLambda.tapSystemErr(() -> { + String stdout = SystemLambda.tapSystemOut(() -> { + CPD.StatusCode statusCode = CPD.runCpd("--minimum-tokens", "340", "--language", "java", "--filelist", + filelist.getAbsolutePath(), "--format", "xml", "-failOnViolation", "true"); + assertEquals(CPD.StatusCode.OK, statusCode); + }); + assertEquals("" + "\n" + "", stdout.trim()); + }); + assertTrue(stderr.contains("Some deprecated options were used on the command-line, including -failOnViolation")); + assertTrue(stderr.contains("Consider replacing it with --fail-on-violation")); // only one parameter is logged - assertFalse(systemErrRule.getLog().contains("Some deprecated options were used on the command-line, including --filelist")); - assertFalse(systemErrRule.getLog().contains("Consider replacing it with --file-list")); + assertFalse(stderr.contains("Some deprecated options were used on the command-line, including --filelist")); + assertFalse(stderr.contains("Consider replacing it with --file-list")); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDConfigurationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDConfigurationTest.java index 38912fba83..0051538b8f 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDConfigurationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDConfigurationTest.java @@ -4,18 +4,20 @@ package net.sourceforge.pmd.cpd; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; + import java.util.HashMap; import java.util.Map; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.cpd.renderer.CPDRenderer; -public class CPDConfigurationTest { +class CPDConfigurationTest { @Test - public void testRenderers() { + void testRenderers() { Map> renderersToTest = new HashMap<>(); renderersToTest.put("csv", CSVRenderer.class); renderersToTest.put("xml", XMLRenderer.class); @@ -25,13 +27,13 @@ public class CPDConfigurationTest { for (Map.Entry> entry : renderersToTest.entrySet()) { Renderer r = CPDConfiguration.getRendererFromString(entry.getKey(), "UTF-8"); - Assert.assertNotNull(r); - Assert.assertSame(entry.getValue(), r.getClass()); + assertNotNull(r); + assertSame(entry.getValue(), r.getClass()); } } @Test - public void testCPDRenderers() { + void testCPDRenderers() { Map> renderersToTest = new HashMap<>(); renderersToTest.put("csv", CSVRenderer.class); renderersToTest.put("xml", XMLRenderer.class); @@ -41,8 +43,8 @@ public class CPDConfigurationTest { for (Map.Entry> entry : renderersToTest.entrySet()) { CPDRenderer r = CPDConfiguration.getCPDRendererFromString(entry.getKey(), "UTF-8"); - Assert.assertNotNull(r); - Assert.assertSame(entry.getValue(), r.getClass()); + assertNotNull(r); + assertSame(entry.getValue(), r.getClass()); } } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDFilelistTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDFilelistTest.java index 5c21740f85..be3c4fa1c7 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDFilelistTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDFilelistTest.java @@ -4,20 +4,20 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.nio.file.Paths; import java.util.HashSet; import java.util.List; import java.util.Set; -import org.apache.commons.io.FilenameUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class CPDFilelistTest { +class CPDFilelistTest { @Test - public void testFilelist() { + void testFilelist() { CPDConfiguration arguments = new CPDConfiguration(); arguments.setLanguage(new CpddummyLanguage()); arguments.setFileListPath("src/test/resources/net/sourceforge/pmd/cpd/cli/filelist.txt"); @@ -28,14 +28,14 @@ public class CPDFilelistTest { assertEquals(2, paths.size()); Set simpleNames = new HashSet<>(); for (String path : paths) { - simpleNames.add(FilenameUtils.getName(path)); + simpleNames.add(Paths.get(path).getFileName().toString()); } assertTrue(simpleNames.contains("anotherfile.dummy")); assertTrue(simpleNames.contains("somefile.dummy")); } @Test - public void testFilelistMultipleLines() { + void testFilelistMultipleLines() { CPDConfiguration arguments = new CPDConfiguration(); arguments.setLanguage(new CpddummyLanguage()); arguments.setFileListPath("src/test/resources/net/sourceforge/pmd/cpd/cli/filelist2.txt"); @@ -46,7 +46,7 @@ public class CPDFilelistTest { assertEquals(2, paths.size()); Set simpleNames = new HashSet<>(); for (String path : paths) { - simpleNames.add(FilenameUtils.getName(path)); + simpleNames.add(Paths.get(path).getFileName().toString()); } assertTrue(simpleNames.contains("anotherfile.dummy")); assertTrue(simpleNames.contains("somefile.dummy")); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDTest.java index fdac78c5f5..a4f966ca1f 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CPDTest.java @@ -4,19 +4,22 @@ package net.sourceforge.pmd.cpd; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + import java.io.File; import java.util.Iterator; import org.apache.commons.lang3.SystemUtils; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * Unit test for {@link CPD} */ -public class CPDTest { +class CPDTest { private static final String BASE_TEST_RESOURCE_PATH = "src/test/resources/net/sourceforge/pmd/cpd/files/"; private static final String TARGET_TEST_RESOURCE_PATH = "target/classes/net/sourceforge/pmd/cpd/files/"; @@ -27,8 +30,8 @@ public class CPDTest { // simply executed only on linux. private boolean canTestSymLinks = SystemUtils.IS_OS_UNIX; - @Before - public void setup() throws Exception { + @BeforeEach + void setup() throws Exception { CPDConfiguration theConfiguration = new CPDConfiguration(); theConfiguration.setLanguage(new AnyLanguage("any")); theConfiguration.setMinimumTileSize(10); @@ -44,7 +47,7 @@ public class CPDTest { * any error */ private void prepareSymLinks() throws Exception { - Assume.assumeTrue("Skipping unit tests with symlinks.", canTestSymLinks); + assumeTrue(canTestSymLinks, "Skipping unit tests with symlinks."); Runtime runtime = Runtime.getRuntime(); if (!new File(TARGET_TEST_RESOURCE_PATH, "symlink-for-real-file.txt").exists()) { @@ -65,7 +68,7 @@ public class CPDTest { * any error */ @Test - public void testFileSectionWithBrokenSymlinks() throws Exception { + void testFileSectionWithBrokenSymlinks() throws Exception { prepareSymLinks(); NoFileAssertListener listener = new NoFileAssertListener(0); @@ -83,7 +86,7 @@ public class CPDTest { * any error */ @Test - public void testFileAddedAsSymlinkAndReal() throws Exception { + void testFileAddedAsSymlinkAndReal() throws Exception { prepareSymLinks(); NoFileAssertListener listener = new NoFileAssertListener(1); @@ -102,7 +105,7 @@ public class CPDTest { * any error */ @Test - public void testFileAddedWithRelativePath() throws Exception { + void testFileAddedWithRelativePath() throws Exception { NoFileAssertListener listener = new NoFileAssertListener(1); cpd.setCpdListener(listener); @@ -116,7 +119,7 @@ public class CPDTest { * @throws Exception */ @Test - public void testFileOrderRelevance() throws Exception { + void testFileOrderRelevance() throws Exception { cpd.add(new File("./" + BASE_TEST_RESOURCE_PATH, "dup2.java")); cpd.add(new File("./" + BASE_TEST_RESOURCE_PATH, "dup1.java")); cpd.go(); @@ -125,8 +128,8 @@ public class CPDTest { while (matches.hasNext()) { Match match = matches.next(); // the file added first was dup2. - Assert.assertTrue(match.getFirstMark().getFilename().endsWith("dup2.java")); - Assert.assertTrue(match.getSecondMark().getFilename().endsWith("dup1.java")); + assertTrue(match.getFirstMark().getFilename().endsWith("dup2.java")); + assertTrue(match.getSecondMark().getFilename().endsWith("dup1.java")); } } @@ -146,7 +149,7 @@ public class CPDTest { public void addedFile(int fileCount, File file) { files++; if (files > expectedFilesCount) { - Assert.fail("File was added! - " + file); + fail("File was added! - " + file); } } @@ -156,8 +159,8 @@ public class CPDTest { } public void verify() { - Assert.assertEquals("Expected " + expectedFilesCount + " files, but " + files + " have been added.", - expectedFilesCount, files); + assertEquals(expectedFilesCount, files, + "Expected " + expectedFilesCount + " files, but " + files + " have been added."); } } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CSVRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CSVRendererTest.java index af976c4445..d38af2cf3a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CSVRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CSVRendererTest.java @@ -4,21 +4,21 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.cpd.renderer.CPDRenderer; -public class CSVRendererTest { +class CSVRendererTest { @Test - public void testLineCountPerFile() throws IOException { + void testLineCountPerFile() throws IOException { CPDRenderer renderer = new CSVRenderer(true); List list = new ArrayList<>(); String codeFragment = "code\nfragment"; @@ -37,7 +37,7 @@ public class CSVRendererTest { } @Test - public void testFilenameEscapes() throws IOException { + void testFilenameEscapes() throws IOException { CPDRenderer renderer = new CSVRenderer(); List list = new ArrayList<>(); String codeFragment = "code\nfragment"; diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CpdXsltTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CpdXsltTest.java index 085475f8d0..ea2cffa619 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CpdXsltTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CpdXsltTest.java @@ -4,6 +4,9 @@ package net.sourceforge.pmd.cpd; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.File; import java.io.StringWriter; import java.nio.charset.StandardCharsets; @@ -17,12 +20,12 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; -import org.apache.commons.io.IOUtils; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import net.sourceforge.pmd.util.IOUtil; -public class CpdXsltTest { +class CpdXsltTest { /* Sample ant build.xml file. Run with "ant cpdxsl". @@ -33,7 +36,7 @@ public class CpdXsltTest { */ @Test - public void cpdhtml() throws Exception { + void cpdhtml() throws Exception { XSLTErrorListener errorListener = new XSLTErrorListener(); // note: using the default JDK factory, otherwise we would use Saxon from PMD's classpath @@ -49,9 +52,9 @@ public class CpdXsltTest { transformer.setErrorListener(errorListener); transformer.transform(cpdReport, result); - String expected = IOUtils.toString(CpdXsltTest.class.getResourceAsStream("ExpectedCpdHtmlReport.html"), StandardCharsets.UTF_8); - Assert.assertEquals(expected, result.getWriter().toString()); - Assert.assertTrue("XSLT errors occured: " + errorListener, errorListener.hasNoErrors()); + String expected = IOUtil.readToString(CpdXsltTest.class.getResourceAsStream("ExpectedCpdHtmlReport.html"), StandardCharsets.UTF_8); + assertEquals(expected, result.getWriter().toString()); + assertTrue(errorListener.hasNoErrors(), "XSLT errors occured: " + errorListener); } private static class XSLTErrorListener implements ErrorListener { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/FileReporterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/FileReporterTest.java index 69768f7ecb..72a90390b7 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/FileReporterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/FileReporterTest.java @@ -4,30 +4,32 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.Reader; -import org.apache.commons.io.IOUtils; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import net.sourceforge.pmd.util.IOUtil; /** * @author Philippe T'Seyen */ -public class FileReporterTest { +class FileReporterTest { @Test - public void testCreation() { + void testCreation() { new FileReporter((String) null); new FileReporter((File) null); } @Test - public void testEmptyReport() throws ReportException { + void testEmptyReport() throws ReportException { File reportFile = new File("report.tmp"); FileReporter fileReporter = new FileReporter(reportFile); fileReporter.report(""); @@ -37,7 +39,7 @@ public class FileReporterTest { } @Test - public void testReport() throws ReportException, IOException { + void testReport() throws ReportException, IOException { String testString = "first line\nsecond line"; File reportFile = new File("report.tmp"); FileReporter fileReporter = new FileReporter(reportFile); @@ -47,21 +49,17 @@ public class FileReporterTest { assertTrue(reportFile.delete()); } - @Test(expected = ReportException.class) - public void testInvalidFile() throws ReportException { + @Test + void testInvalidFile() throws ReportException { File reportFile = new File("/invalid_folder/report.tmp"); FileReporter fileReporter = new FileReporter(reportFile); - fileReporter.report(""); + assertThrows(ReportException.class, () -> fileReporter.report("")); } private String readFile(File file) throws IOException { try (Reader reader = new FileReader(file)) { - String text = IOUtils.toString(reader); + String text = IOUtil.readToString(reader); return text.replaceAll("\\R", "\n"); } } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(FileReporterTest.class); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/LanguageFactoryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/LanguageFactoryTest.java index da8b0f20f2..cb840b3aba 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/LanguageFactoryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/LanguageFactoryTest.java @@ -4,14 +4,14 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class LanguageFactoryTest { +class LanguageFactoryTest { @Test - public void testSimple() { + void testSimple() { assertTrue(LanguageFactory.createLanguage("Cpddummy") instanceof CpddummyLanguage); assertTrue(LanguageFactory.createLanguage("not_existing_language") instanceof AnyLanguage); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MarkTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MarkTest.java index 0afa0144b8..55cb82b7ba 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MarkTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MarkTest.java @@ -4,16 +4,16 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.cpd.SourceCode.StringCodeLoader; -public class MarkTest { +class MarkTest { @Test - public void testSimple() { + void testSimple() { String filename = "/var/Foo.java"; int beginLine = 1; TokenEntry token = new TokenEntry("public", "/var/Foo.java", 1); @@ -35,7 +35,7 @@ public class MarkTest { } @Test - public void testColumns() { + void testColumns() { final String filename = "/var/Foo.java"; final int beginLine = 1; final int beginColumn = 2; @@ -59,8 +59,4 @@ public class MarkTest { assertEquals(endColumn, mark.getEndColumn()); assertEquals(codeFragment, mark.getSourceCodeSlice()); } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(MarkTest.class); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MatchTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MatchTest.java index dd6a4084d8..bd77cbd2e3 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MatchTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/MatchTest.java @@ -4,18 +4,18 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Iterator; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class MatchTest { +class MatchTest { @Test - public void testSimple() { + void testSimple() { int lineCount1 = 10; String codeFragment1 = "code fragment"; Mark mark1 = createMark("public", "/var/Foo.java", 1, lineCount1, codeFragment1); @@ -46,7 +46,7 @@ public class MatchTest { } @Test - public void testCompareTo() { + void testCompareTo() { Match m1 = new Match(1, new TokenEntry("public", "/var/Foo.java", 1), new TokenEntry("class", "/var/Foo.java", 1)); Match m2 = new Match(2, new TokenEntry("Foo", "/var/Foo.java", 1), new TokenEntry("{", "/var/Foo.java", 1)); @@ -60,8 +60,4 @@ public class MatchTest { result.setSourceCode(new SourceCode(new SourceCode.StringCodeLoader(code))); return result; } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(MatchTest.class); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/SourceCodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/SourceCodeTest.java index c672da6ee9..714acaac7c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/SourceCodeTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/SourceCodeTest.java @@ -4,21 +4,21 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.File; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.cpd.SourceCode.FileCodeLoader; -public class SourceCodeTest { +class SourceCodeTest { private static final String BASE_RESOURCE_PATH = "src/test/resources/net/sourceforge/pmd/cpd/files/"; private static final String SAMPLE_CODE = "Line 1\n" + "Line 2\n" + "Line 3\n" + "Line 4\n"; @Test - public void testSlice() { + void testSlice() { SourceCode sourceCode = new SourceCode(new SourceCode.StringCodeLoader(SAMPLE_CODE, "Foo.java")); assertEquals("Foo.java", sourceCode.getFileName()); @@ -31,7 +31,7 @@ public class SourceCodeTest { } @Test - public void testEncodingDetectionFromBOM() throws Exception { + void testEncodingDetectionFromBOM() throws Exception { FileCodeLoader loader = new SourceCode.FileCodeLoader(new File(BASE_RESOURCE_PATH + "file_with_utf8_bom.java"), "ISO-8859-1"); @@ -41,7 +41,7 @@ public class SourceCodeTest { } @Test - public void testEncodingIsNotChangedWhenThereIsNoBOM() throws Exception { + void testEncodingIsNotChangedWhenThereIsNoBOM() throws Exception { FileCodeLoader loader = new SourceCode.FileCodeLoader( new File(BASE_RESOURCE_PATH + "file_with_ISO-8859-1_encoding.java"), "ISO-8859-1"); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/TokenEntryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/TokenEntryTest.java index e66a27fb1e..eb50dc973a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/TokenEntryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/TokenEntryTest.java @@ -4,14 +4,14 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class TokenEntryTest { +class TokenEntryTest { @Test - public void testSimple() { + void testSimple() { TokenEntry.clearImages(); TokenEntry mark = new TokenEntry("public", "/var/Foo.java", 1); assertEquals(1, mark.getBeginLine()); @@ -22,7 +22,7 @@ public class TokenEntryTest { } @Test - public void testColumns() { + void testColumns() { TokenEntry.clearImages(); TokenEntry mark = new TokenEntry("public", "/var/Foo.java", 1, 2, 3); assertEquals(1, mark.getBeginLine()); @@ -31,8 +31,4 @@ public class TokenEntryTest { assertEquals(2, mark.getBeginColumn()); assertEquals(3, mark.getEndColumn()); } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(TokenEntryTest.class); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/XMLRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/XMLRendererTest.java index 406c8183aa..d548e84f4b 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/XMLRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/XMLRendererTest.java @@ -4,10 +4,9 @@ package net.sourceforge.pmd.cpd; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -15,11 +14,13 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; import net.sourceforge.pmd.cpd.renderer.CPDRenderer; @@ -28,7 +29,7 @@ import net.sourceforge.pmd.cpd.renderer.CPDRenderer; * @author Romain Pelisse <belaran@gmail.com> * */ -public class XMLRendererTest { +class XMLRendererTest { private static final String ENCODING = (String) System.getProperties().get("file.encoding"); private static final String FORM_FEED = "\u000C"; // this character is invalid in XML 1.0 documents @@ -36,28 +37,23 @@ public class XMLRendererTest { @Test - public void testWithNoDuplication() throws IOException { - + void testWithNoDuplication() throws IOException, ParserConfigurationException, SAXException { CPDRenderer renderer = new XMLRenderer(); List list = new ArrayList<>(); StringWriter sw = new StringWriter(); renderer.render(list.iterator(), sw); String report = sw.toString(); - try { - Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() - .parse(new ByteArrayInputStream(report.getBytes(ENCODING))); - NodeList nodes = doc.getChildNodes(); - Node n = nodes.item(0); - assertEquals("pmd-cpd", n.getNodeName()); - assertEquals(0, doc.getElementsByTagName("duplication").getLength()); - } catch (Exception e) { - e.printStackTrace(); - fail(e.getMessage()); - } + + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() + .parse(new ByteArrayInputStream(report.getBytes(ENCODING))); + NodeList nodes = doc.getChildNodes(); + Node n = nodes.item(0); + assertEquals("pmd-cpd", n.getNodeName()); + assertEquals(0, doc.getElementsByTagName("duplication").getLength()); } @Test - public void testWithOneDuplication() throws IOException { + void testWithOneDuplication() throws Exception { CPDRenderer renderer = new XMLRenderer(); List list = new ArrayList<>(); int lineCount = 6; @@ -70,42 +66,38 @@ public class XMLRendererTest { StringWriter sw = new StringWriter(); renderer.render(list.iterator(), sw); String report = sw.toString(); - try { - Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() - .parse(new ByteArrayInputStream(report.getBytes(ENCODING))); - NodeList dupes = doc.getElementsByTagName("duplication"); - assertEquals(1, dupes.getLength()); - Node file = dupes.item(0).getFirstChild(); + + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() + .parse(new ByteArrayInputStream(report.getBytes(ENCODING))); + NodeList dupes = doc.getElementsByTagName("duplication"); + assertEquals(1, dupes.getLength()); + Node file = dupes.item(0).getFirstChild(); + while (file != null && file.getNodeType() != Node.ELEMENT_NODE) { + file = file.getNextSibling(); + } + if (file != null) { + assertEquals("1", file.getAttributes().getNamedItem("line").getNodeValue()); + assertEquals("/var/Foo.java", file.getAttributes().getNamedItem("path").getNodeValue()); + assertEquals("6", file.getAttributes().getNamedItem("endline").getNodeValue()); + assertEquals(null, file.getAttributes().getNamedItem("column")); + assertEquals(null, file.getAttributes().getNamedItem("endcolumn")); + file = file.getNextSibling(); while (file != null && file.getNodeType() != Node.ELEMENT_NODE) { file = file.getNextSibling(); } - if (file != null) { - assertEquals("1", file.getAttributes().getNamedItem("line").getNodeValue()); - assertEquals("/var/Foo.java", file.getAttributes().getNamedItem("path").getNodeValue()); - assertEquals("6", file.getAttributes().getNamedItem("endline").getNodeValue()); - assertEquals(null, file.getAttributes().getNamedItem("column")); - assertEquals(null, file.getAttributes().getNamedItem("endcolumn")); - file = file.getNextSibling(); - while (file != null && file.getNodeType() != Node.ELEMENT_NODE) { - file = file.getNextSibling(); - } - } - if (file != null) { - assertEquals("73", file.getAttributes().getNamedItem("line").getNodeValue()); - assertEquals("78", file.getAttributes().getNamedItem("endline").getNodeValue()); - assertEquals(null, file.getAttributes().getNamedItem("column")); - assertEquals(null, file.getAttributes().getNamedItem("endcolumn")); - } - assertEquals(1, doc.getElementsByTagName("codefragment").getLength()); - assertEquals(codeFragment, doc.getElementsByTagName("codefragment").item(0).getTextContent()); - } catch (Exception e) { - e.printStackTrace(); - fail(e.getMessage()); } + if (file != null) { + assertEquals("73", file.getAttributes().getNamedItem("line").getNodeValue()); + assertEquals("78", file.getAttributes().getNamedItem("endline").getNodeValue()); + assertEquals(null, file.getAttributes().getNamedItem("column")); + assertEquals(null, file.getAttributes().getNamedItem("endcolumn")); + } + assertEquals(1, doc.getElementsByTagName("codefragment").getLength()); + assertEquals(codeFragment, doc.getElementsByTagName("codefragment").item(0).getTextContent()); } @Test - public void testRenderWithMultipleMatch() throws IOException { + void testRenderWithMultipleMatch() throws Exception { CPDRenderer renderer = new XMLRenderer(); List list = new ArrayList<>(); int lineCount1 = 6; @@ -125,19 +117,15 @@ public class XMLRendererTest { StringWriter sw = new StringWriter(); renderer.render(list.iterator(), sw); String report = sw.toString(); - try { - Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() - .parse(new ByteArrayInputStream(report.getBytes(ENCODING))); - assertEquals(2, doc.getElementsByTagName("duplication").getLength()); - assertEquals(4, doc.getElementsByTagName("file").getLength()); - } catch (Exception e) { - e.printStackTrace(); - fail(e.getMessage()); - } + + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() + .parse(new ByteArrayInputStream(report.getBytes(ENCODING))); + assertEquals(2, doc.getElementsByTagName("duplication").getLength()); + assertEquals(4, doc.getElementsByTagName("file").getLength()); } @Test - public void testWithOneDuplicationWithColumns() throws IOException { + void testWithOneDuplicationWithColumns() throws Exception { CPDRenderer renderer = new XMLRenderer(); List list = new ArrayList<>(); int lineCount = 6; @@ -150,42 +138,38 @@ public class XMLRendererTest { StringWriter sw = new StringWriter(); renderer.render(list.iterator(), sw); String report = sw.toString(); - try { - Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() - .parse(new ByteArrayInputStream(report.getBytes(ENCODING))); - NodeList dupes = doc.getElementsByTagName("duplication"); - assertEquals(1, dupes.getLength()); - Node file = dupes.item(0).getFirstChild(); + + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() + .parse(new ByteArrayInputStream(report.getBytes(ENCODING))); + NodeList dupes = doc.getElementsByTagName("duplication"); + assertEquals(1, dupes.getLength()); + Node file = dupes.item(0).getFirstChild(); + while (file != null && file.getNodeType() != Node.ELEMENT_NODE) { + file = file.getNextSibling(); + } + if (file != null) { + assertEquals("1", file.getAttributes().getNamedItem("line").getNodeValue()); + assertEquals("/var/Foo.java", file.getAttributes().getNamedItem("path").getNodeValue()); + assertEquals("6", file.getAttributes().getNamedItem("endline").getNodeValue()); + assertEquals("2", file.getAttributes().getNamedItem("column").getNodeValue()); + assertEquals("3", file.getAttributes().getNamedItem("endcolumn").getNodeValue()); + file = file.getNextSibling(); while (file != null && file.getNodeType() != Node.ELEMENT_NODE) { file = file.getNextSibling(); } - if (file != null) { - assertEquals("1", file.getAttributes().getNamedItem("line").getNodeValue()); - assertEquals("/var/Foo.java", file.getAttributes().getNamedItem("path").getNodeValue()); - assertEquals("6", file.getAttributes().getNamedItem("endline").getNodeValue()); - assertEquals("2", file.getAttributes().getNamedItem("column").getNodeValue()); - assertEquals("3", file.getAttributes().getNamedItem("endcolumn").getNodeValue()); - file = file.getNextSibling(); - while (file != null && file.getNodeType() != Node.ELEMENT_NODE) { - file = file.getNextSibling(); - } - } - if (file != null) { - assertEquals("73", file.getAttributes().getNamedItem("line").getNodeValue()); - assertEquals("78", file.getAttributes().getNamedItem("endline").getNodeValue()); - assertEquals("4", file.getAttributes().getNamedItem("column").getNodeValue()); - assertEquals("5", file.getAttributes().getNamedItem("endcolumn").getNodeValue()); - } - assertEquals(1, doc.getElementsByTagName("codefragment").getLength()); - assertEquals(codeFragment, doc.getElementsByTagName("codefragment").item(0).getTextContent()); - } catch (Exception e) { - e.printStackTrace(); - fail(e.getMessage()); } + if (file != null) { + assertEquals("73", file.getAttributes().getNamedItem("line").getNodeValue()); + assertEquals("78", file.getAttributes().getNamedItem("endline").getNodeValue()); + assertEquals("4", file.getAttributes().getNamedItem("column").getNodeValue()); + assertEquals("5", file.getAttributes().getNamedItem("endcolumn").getNodeValue()); + } + assertEquals(1, doc.getElementsByTagName("codefragment").getLength()); + assertEquals(codeFragment, doc.getElementsByTagName("codefragment").item(0).getTextContent()); } @Test - public void testRendererEncodedPath() throws IOException { + void testRendererEncodedPath() throws IOException { CPDRenderer renderer = new XMLRenderer(); List list = new ArrayList<>(); final String espaceChar = "<"; @@ -203,7 +187,7 @@ public class XMLRendererTest { } @Test - public void testRendererXMLEscaping() throws IOException { + void testRendererXMLEscaping() throws IOException { String codefragment = "code fragment" + FORM_FEED + "\nline2\nline3\nno & escaping necessary in CDATA\nx=\"]]>\";"; CPDRenderer renderer = new XMLRenderer(); List list = new ArrayList<>(); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java index 36792e3860..114fd8ccc4 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilterTest.java @@ -4,9 +4,10 @@ package net.sourceforge.pmd.cpd.token.internal; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.Collections; @@ -14,7 +15,7 @@ import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.NoSuchElementException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.TokenManager; import net.sourceforge.pmd.lang.ast.GenericToken; @@ -23,7 +24,7 @@ import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.document.TextRange2d; import net.sourceforge.pmd.lang.document.TextRegion; -public class BaseTokenFilterTest { +class BaseTokenFilterTest { static class StringToken implements GenericToken { @@ -113,7 +114,7 @@ public class BaseTokenFilterTest { } @Test - public void testRemainingTokensFunctionality1() { + void testRemainingTokensFunctionality1() { final TokenManager tokenManager = new StringTokenManager(); final DummyTokenFilter tokenFilter = new DummyTokenFilter<>(tokenManager); final StringToken firstToken = tokenFilter.getNextToken(); @@ -139,7 +140,7 @@ public class BaseTokenFilterTest { } @Test - public void testRemainingTokensFunctionality2() { + void testRemainingTokensFunctionality2() { final TokenManager tokenManager = new StringTokenManager(); final DummyTokenFilter tokenFilter = new DummyTokenFilter<>(tokenManager); final StringToken firstToken = tokenFilter.getNextToken(); @@ -164,8 +165,8 @@ public class BaseTokenFilterTest { assertEquals("c", secondValSecondIt.getImage()); } - @Test(expected = NoSuchElementException.class) - public void testRemainingTokensFunctionality3() { + @Test + void testRemainingTokensFunctionality3() { final TokenManager tokenManager = new StringTokenManager(); final DummyTokenFilter tokenFilter = new DummyTokenFilter<>(tokenManager); final StringToken firstToken = tokenFilter.getNextToken(); @@ -177,11 +178,11 @@ public class BaseTokenFilterTest { it1.next(); it2.next(); it2.next(); - it1.next(); + assertThrows(NoSuchElementException.class, () -> it1.next()); } - @Test(expected = ConcurrentModificationException.class) - public void testRemainingTokensFunctionality4() { + @Test + void testRemainingTokensFunctionality4() { final TokenManager tokenManager = new StringTokenManager(); final DummyTokenFilter tokenFilter = new DummyTokenFilter<>(tokenManager); final StringToken firstToken = tokenFilter.getNextToken(); @@ -190,7 +191,7 @@ public class BaseTokenFilterTest { final Iterator it1 = iterable.iterator(); final StringToken secondToken = tokenFilter.getNextToken(); assertEquals("b", secondToken.getImage()); - it1.next(); + assertThrows(ConcurrentModificationException.class, () -> it1.next()); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/internal/util/IteratorUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/internal/util/IteratorUtilTest.java index aca14a1cfd..e306fcfc0c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/internal/util/IteratorUtilTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/internal/util/IteratorUtilTest.java @@ -9,10 +9,11 @@ import static java.util.Collections.emptyIterator; import static java.util.Collections.emptyList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.Arrays; @@ -24,18 +25,12 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; -public class IteratorUtilTest { - - @Rule - public ExpectedException exception = ExpectedException.none(); +class IteratorUtilTest { @Test - public void testAnyMatchPos() { + void testAnyMatchPos() { Iterator iter = iterOf("a", "b", "cd"); boolean match = IteratorUtil.anyMatch(iter, it -> it.length() > 1); @@ -44,7 +39,7 @@ public class IteratorUtilTest { } @Test - public void testAnyMatchNeg() { + void testAnyMatchNeg() { Iterator iter = iterOf("a", "b", ""); boolean match = IteratorUtil.anyMatch(iter, it -> it.length() > 1); @@ -53,7 +48,7 @@ public class IteratorUtilTest { } @Test - public void testAnyMatchEmpty() { + void testAnyMatchEmpty() { Iterator iter = emptyIterator(); boolean match = IteratorUtil.anyMatch(iter, it -> it.length() > 1); @@ -63,7 +58,7 @@ public class IteratorUtilTest { @Test - public void testAllMatchPos() { + void testAllMatchPos() { Iterator iter = iterOf("ap", "bcd", "cd"); boolean match = IteratorUtil.allMatch(iter, it -> it.length() > 1); @@ -72,7 +67,7 @@ public class IteratorUtilTest { } @Test - public void testAllMatchNeg() { + void testAllMatchNeg() { Iterator iter = iterOf("a", "bcd", ""); boolean match = IteratorUtil.allMatch(iter, it -> it.length() > 1); @@ -81,7 +76,7 @@ public class IteratorUtilTest { } @Test - public void testAllMatchEmpty() { + void testAllMatchEmpty() { Iterator iter = emptyIterator(); boolean match = IteratorUtil.allMatch(iter, it -> it.length() > 1); @@ -91,7 +86,7 @@ public class IteratorUtilTest { @Test - public void testNoneMatchPos() { + void testNoneMatchPos() { Iterator iter = iterOf("ap", "bcd", "cd"); boolean match = IteratorUtil.noneMatch(iter, it -> it.length() < 1); @@ -100,7 +95,7 @@ public class IteratorUtilTest { } @Test - public void testNoneMatchNeg() { + void testNoneMatchNeg() { Iterator iter = iterOf("a", "bcd", ""); boolean match = IteratorUtil.noneMatch(iter, it -> it.length() < 1); @@ -109,7 +104,7 @@ public class IteratorUtilTest { } @Test - public void testNoneMatchEmpty() { + void testNoneMatchEmpty() { Iterator iter = emptyIterator(); boolean match = IteratorUtil.noneMatch(iter, it -> it.length() < 1); @@ -118,7 +113,7 @@ public class IteratorUtilTest { } @Test - public void testFlatmap() { + void testFlatmap() { Iterator iter = iterOf("ab", "cd", "e", "", "f"); Function> fun = s -> s.chars().mapToObj(i -> (char) i).map(String::valueOf).iterator(); @@ -130,7 +125,7 @@ public class IteratorUtilTest { @Test - public void testFlatmapEmpty() { + void testFlatmapEmpty() { Iterator iter = emptyIterator(); Function> fun = s -> s.chars().mapToObj(i -> (char) i).map(String::valueOf).iterator(); @@ -141,7 +136,7 @@ public class IteratorUtilTest { } @Test - public void testFlatmapEmpty2() { + void testFlatmapEmpty2() { Iterator iter = iterOf("ab", "cd", "e", "", "f"); Function> fun = s -> emptyIterator(); @@ -151,7 +146,7 @@ public class IteratorUtilTest { } @Test - public void testFlatmapIsLazy() { + void testFlatmapIsLazy() { Iterator iter = iterOf("a", "b"); Function> fun = s -> { if (s.equals("a")) { @@ -166,14 +161,12 @@ public class IteratorUtilTest { assertTrue(mapped.hasNext()); assertEquals("a", mapped.next()); - exception.expect(AssertionError.class); - - assertTrue(mapped.hasNext()); + assertThrows(AssertionError.class, () -> mapped.hasNext()); } @Test - public void testFlatmapWithSelf() { + void testFlatmapWithSelf() { Iterator iter = iterOf("ab", "e", null, "f"); Function> fun = s -> s == null ? null // test null safety : iterOf(s + "1", s + "2"); @@ -184,7 +177,7 @@ public class IteratorUtilTest { } @Test - public void testMapNotNull() { + void testMapNotNull() { Iterator iter = iterOf("ab", "cdde", "e", "", "f", "fe"); Function fun = s -> s.length() < 2 ? null : s.length(); @@ -195,7 +188,7 @@ public class IteratorUtilTest { } @Test - public void testMapNotNullEmpty() { + void testMapNotNullEmpty() { Iterator iter = emptyIterator(); Function fun = s -> s.length() < 2 ? null : s.length(); @@ -206,7 +199,7 @@ public class IteratorUtilTest { } @Test - public void testMapNotNullEmpty2() { + void testMapNotNullEmpty2() { Iterator iter = iterOf("a", "b"); Function> fun = s -> null; @@ -217,7 +210,7 @@ public class IteratorUtilTest { } @Test - public void testFilterNotNull() { + void testFilterNotNull() { Iterator iter = iterOf("ab", null, "e", null, "", "fe"); Iterator mapped = IteratorUtil.filterNotNull(iter); @@ -229,7 +222,7 @@ public class IteratorUtilTest { @Test - public void testDistinct() { + void testDistinct() { Iterator iter = iterOf("ab", null, "e", null, "fe", "ab", "c"); Iterator mapped = IteratorUtil.distinct(iter); @@ -241,7 +234,7 @@ public class IteratorUtilTest { @Test - public void testTakeWhile() { + void testTakeWhile() { Iterator iter = iterOf("ab", "null", "e", null, "", "fe"); Predicate predicate = Objects::nonNull; @@ -252,7 +245,7 @@ public class IteratorUtilTest { } @Test - public void testTakeWhileWithEmpty() { + void testTakeWhileWithEmpty() { Iterator iter = iterOf(); Predicate predicate = Objects::nonNull; @@ -262,7 +255,7 @@ public class IteratorUtilTest { } @Test - public void testPeek() { + void testPeek() { Iterator iter = iterOf("ab", null, "c"); List seen = new ArrayList<>(); Consumer action = seen::add; @@ -282,15 +275,14 @@ public class IteratorUtilTest { } @Test - public void testTakeNegative() { + void testTakeNegative() { Iterator iter = iterOf("a", "b", "c"); - exception.expect(IllegalArgumentException.class); - IteratorUtil.take(iter, -5); + assertThrows(IllegalArgumentException.class, () -> IteratorUtil.take(iter, -5)); } @Test - public void testTake0() { + void testTake0() { Iterator iter = iterOf("a", "b", "c"); Iterator mapped = IteratorUtil.take(iter, 0); @@ -299,7 +291,7 @@ public class IteratorUtilTest { } @Test - public void testTake() { + void testTake() { Iterator iter = iterOf("a", "b", "c"); Iterator mapped = IteratorUtil.take(iter, 1); @@ -309,7 +301,7 @@ public class IteratorUtilTest { } @Test - public void testTakeOverflow() { + void testTakeOverflow() { Iterator iter = iterOf("a", "b", "c"); Iterator mapped = IteratorUtil.take(iter, 12); @@ -319,15 +311,14 @@ public class IteratorUtilTest { } @Test - public void testDropNegative() { + void testDropNegative() { Iterator iter = iterOf("a", "b", "c"); - exception.expect(IllegalArgumentException.class); - IteratorUtil.advance(iter, -5); + assertThrows(IllegalArgumentException.class, () -> IteratorUtil.advance(iter, -5)); } @Test - public void testDrop0() { + void testDrop0() { Iterator iter = iterOf("a", "b", "c"); Iterator mapped = IteratorUtil.drop(iter, 0); @@ -337,7 +328,7 @@ public class IteratorUtilTest { } @Test - public void testDrop() { + void testDrop() { Iterator iter = iterOf("a", "b", "c"); Iterator mapped = IteratorUtil.drop(iter, 1); @@ -347,7 +338,7 @@ public class IteratorUtilTest { } @Test - public void testDropOverflow() { + void testDropOverflow() { Iterator iter = iterOf("a", "b", "c"); Iterator mapped = IteratorUtil.drop(iter, 12); @@ -356,15 +347,14 @@ public class IteratorUtilTest { } @Test - public void testGetNegative() { + void testGetNegative() { Iterator iter = iterOf("a", "b", "c"); - exception.expect(IllegalArgumentException.class); - IteratorUtil.getNth(iter, -5); + assertThrows(IllegalArgumentException.class, () -> IteratorUtil.getNth(iter, -5)); } @Test - public void testGet0() { + void testGet0() { Iterator iter = iterOf("a", "b", "c"); @@ -374,7 +364,7 @@ public class IteratorUtilTest { } @Test - public void testGetNth() { + void testGetNth() { Iterator iter = iterOf("a", "b", "c"); String elt = IteratorUtil.getNth(iter, 1); @@ -383,7 +373,7 @@ public class IteratorUtilTest { } @Test - public void testGetOverflow() { + void testGetOverflow() { Iterator iter = iterOf("a", "b", "c"); String elt = IteratorUtil.getNth(iter, 12); @@ -393,7 +383,7 @@ public class IteratorUtilTest { @Test - public void testLast() { + void testLast() { Iterator iter = iterOf("a", "b", "c"); String elt = IteratorUtil.last(iter); @@ -403,7 +393,7 @@ public class IteratorUtilTest { } @Test - public void testLastEmpty() { + void testLastEmpty() { Iterator iter = emptyIterator(); String elt = IteratorUtil.last(iter); @@ -412,7 +402,7 @@ public class IteratorUtilTest { } @Test - public void testCount() { + void testCount() { Iterator iter = iterOf("a", "b", "c"); int size = IteratorUtil.count(iter); @@ -422,7 +412,7 @@ public class IteratorUtilTest { } @Test - public void testCountEmpty() { + void testCountEmpty() { Iterator iter = emptyIterator(); int size = IteratorUtil.count(iter); @@ -431,7 +421,7 @@ public class IteratorUtilTest { } @Test - public void testToList() { + void testToList() { Iterator iter = iterOf("a", "b", "c"); List lst = IteratorUtil.toList(iter); @@ -441,7 +431,7 @@ public class IteratorUtilTest { } @Test - public void testAsReversed() { + void testAsReversed() { List iter = listOf("a", "b", "c"); Iterable mapped = IteratorUtil.asReversed(iter); @@ -450,7 +440,7 @@ public class IteratorUtilTest { } @Test - public void testAsReversedIsRepeatable() { + void testAsReversedIsRepeatable() { List iter = listOf("a", "b", "c"); Iterable mapped = IteratorUtil.asReversed(iter); @@ -463,7 +453,7 @@ public class IteratorUtilTest { @Test - public void testDropLast() { + void testDropLast() { Iterator iter = iterOf("ab", "cdde", "e", "", "f", "fe"); Iterator dropped = IteratorUtil.dropLast(iter, 2); @@ -472,7 +462,7 @@ public class IteratorUtilTest { } @Test - public void testDropLastOne() { + void testDropLastOne() { Iterator iter = iterOf("ab", "cdde", "e", "", "f", "fe"); Iterator dropped = IteratorUtil.dropLast(iter, 1); @@ -481,7 +471,7 @@ public class IteratorUtilTest { } @Test - public void testDropMoreThanSize() { + void testDropMoreThanSize() { Iterator iter = iterOf("ab", "c"); Iterator dropped = IteratorUtil.dropLast(iter, 4); @@ -490,7 +480,7 @@ public class IteratorUtilTest { } @Test - public void testDropLastZero() { + void testDropLastZero() { Iterator iter = iterOf("ab", "c"); Iterator dropped = IteratorUtil.dropLast(iter, 0); @@ -499,16 +489,15 @@ public class IteratorUtilTest { } @Test - public void testDropLastNegative() { + void testDropLastNegative() { Iterator iter = iterOf("ab", "c"); - Assert.assertThrows(IllegalArgumentException.class, () -> IteratorUtil.dropLast(iter, -3)); + assertThrows(IllegalArgumentException.class, () -> IteratorUtil.dropLast(iter, -3)); } private void assertExhausted(Iterator mapped) { assertFalse(mapped.hasNext()); - exception.expect(NoSuchElementException.class); - mapped.next(); + assertThrows(NoSuchElementException.class, () -> mapped.next()); } static Iterator iterOf(T... ts) { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java index b3cb7cefa2..ee50a2f297 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/DummyLanguageModule.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang; +import java.util.Objects; + import org.checkerframework.checker.nullness.qual.NonNull; import net.sourceforge.pmd.Rule; @@ -14,7 +16,6 @@ import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.ast.ParseException; import net.sourceforge.pmd.lang.ast.Parser; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; -import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.ast.SemanticErrorReporter; import net.sourceforge.pmd.lang.document.Chars; import net.sourceforge.pmd.lang.document.FileLocation; @@ -23,6 +24,7 @@ import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; import net.sourceforge.pmd.lang.rule.impl.DefaultRuleViolationFactory; +import net.sourceforge.pmd.processor.PmdRunnableTest; /** * Dummy language used for testing PMD. @@ -43,8 +45,11 @@ public class DummyLanguageModule extends BaseLanguageModule { addVersion("1.6", new Handler(), "6"); addDefaultVersion("1.7", new Handler(), "7"); addVersion("1.8", new Handler(), "8"); - addVersion("1.9-throws", new HandlerWithParserThatThrows()); - addVersion("1.9-semantic_error", new HandlerWithParserThatReportsSemanticError()); + PmdRunnableTest.registerCustomVersions(this::addVersion); + } + + public static DummyLanguageModule getInstance() { + return (DummyLanguageModule) Objects.requireNonNull(LanguageRegistry.getLanguage(NAME)); } public static DummyRootNode parse(String code) { @@ -60,11 +65,6 @@ public class DummyLanguageModule extends BaseLanguageModule { return (DummyRootNode) version.getLanguageVersionHandler().getParser().parse(task); } - - public static DummyLanguageModule getInstance() { - return (DummyLanguageModule) LanguageRegistry.getLanguage(NAME); - } - public static class Handler extends AbstractPmdLanguageVersionHandler { @Override @@ -78,28 +78,6 @@ public class DummyLanguageModule extends BaseLanguageModule { } } - public static class HandlerWithParserThatThrows extends Handler { - - @Override - public Parser getParser() { - return task -> { - throw new AssertionError("test error while parsing"); - }; - } - } - - public static class HandlerWithParserThatReportsSemanticError extends Handler { - - @Override - public Parser getParser() { - return task -> { - RootNode root = super.getParser().parse(task); - task.getReporter().error(root, "An error occurred!"); - return root; - }; - } - } - /** * Creates a tree of nodes that corresponds to the nesting structures * of parentheses in the text. The image of each node is also populated. @@ -170,6 +148,5 @@ public class DummyLanguageModule extends BaseLanguageModule { } }; } - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageParameterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageParameterTest.java index 10702fd855..1033dc9242 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageParameterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageParameterTest.java @@ -4,23 +4,24 @@ package net.sourceforge.pmd.lang; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.cli.PMDCommandLineInterface; import net.sourceforge.pmd.cli.PMDParameters; -public class LanguageParameterTest { +class LanguageParameterTest { /** Test that language parameters from the CLI are correctly passed through to the PMDConfiguration. Although this is a * CLI test, it resides here to take advantage of {@link net.sourceforge.pmd.lang.DummyLanguageModule} */ @Test - public void testLanguageFromCliToConfiguration() { + void testLanguageFromCliToConfiguration() { PMDParameters params = new PMDParameters(); String[] args = { "-d", "source_folder", "-f", "ideaj", "-P", "sourcePath=/home/user/source/", "-R", "java-empty", "-force-language", "dummy"}; PMDCommandLineInterface.extractParameters(params, args, "PMD"); - Assert.assertEquals(DummyLanguageModule.getInstance().getDefaultVersion().getName(), params.toConfiguration().getForceLanguageVersion().getName()); + assertEquals(DummyLanguageModule.getInstance().getDefaultVersion().getName(), params.toConfiguration().getForceLanguageVersion().getName()); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageRegistryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageRegistryTest.java index f7fd11c0ce..6aac4f0d58 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageRegistryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageRegistryTest.java @@ -4,43 +4,47 @@ package net.sourceforge.pmd.lang; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; -public class LanguageRegistryTest { +import org.junit.jupiter.api.Test; + +class LanguageRegistryTest { @Test - public void getDefaultLanguageTest() { + void getDefaultLanguageTest() { Language defaultLanguage = LanguageRegistry.getDefaultLanguage(); - Assert.assertNotNull(defaultLanguage); + assertNotNull(defaultLanguage); // as we don't have java language in this test, we get the first // available language now -> DummyLanguage - Assert.assertSame(DummyLanguageModule.class, defaultLanguage.getClass()); + assertSame(DummyLanguageModule.class, defaultLanguage.getClass()); } @Test - public void getDefaultVersionLanguageTest() { + void getDefaultVersionLanguageTest() { Language dummy = LanguageRegistry.findLanguageByTerseName("dummy"); LanguageVersion dummy12 = dummy.getVersion("1.2"); - Assert.assertNotNull(dummy12); + assertNotNull(dummy12); LanguageVersion dummyDefault = dummy.getDefaultVersion(); - Assert.assertNotNull(dummyDefault); + assertNotNull(dummyDefault); - Assert.assertNotSame(dummy12, dummyDefault); + assertNotSame(dummy12, dummyDefault); } @Test - public void getLanguageVersionByAliasTest() { + void getLanguageVersionByAliasTest() { Language dummy = LanguageRegistry.findLanguageByTerseName("dummy"); LanguageVersion dummy17 = dummy.getVersion("1.7"); - Assert.assertNotNull(dummy17); - Assert.assertEquals("1.7", dummy17.getVersion()); + assertNotNull(dummy17); + assertEquals("1.7", dummy17.getVersion()); LanguageVersion dummy7 = dummy.getVersion("7"); - Assert.assertNotNull(dummy7); - Assert.assertEquals("1.7", dummy17.getVersion()); - Assert.assertSame(dummy17, dummy7); + assertNotNull(dummy7); + assertEquals("1.7", dummy17.getVersion()); + assertSame(dummy17, dummy7); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/BoundaryTraversalTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/BoundaryTraversalTest.java index b3d394903f..c9c29900d2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/BoundaryTraversalTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/BoundaryTraversalTest.java @@ -4,19 +4,19 @@ package net.sourceforge.pmd.lang.ast; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.List; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * Unit test for {@link Node} tree traversal methods */ -public class BoundaryTraversalTest { +class BoundaryTraversalTest { private DummyNode rootNode; @@ -29,13 +29,13 @@ public class BoundaryTraversalTest { return parent; } - @Before - public void setUpSampleNodeTree() { + @BeforeEach + void setUpSampleNodeTree() { rootNode = newDummyNode(false); } @Test - public void testBoundaryIsHonored() { + void testBoundaryIsHonored() { addChild(rootNode, addChild(newDummyNode(true), newDummyNode(false))); List descendantsOfType = rootNode.descendants(DummyNode.class).toList(); @@ -44,7 +44,7 @@ public class BoundaryTraversalTest { } @Test - public void testSearchFromBoundary() { + void testSearchFromBoundary() { addChild(rootNode, addChild(newDummyNode(true), newDummyNode(false))); List descendantsOfType = rootNode.descendants(DummyNode.class).first().descendants(DummyNode.class).toList(); @@ -53,7 +53,7 @@ public class BoundaryTraversalTest { } @Test - public void testSearchFromBoundaryFromNonOptimisedStream() { + void testSearchFromBoundaryFromNonOptimisedStream() { addChild(rootNode, addChild(newDummyNode(true), newDummyNode(false))); List descendantsOfType = rootNode.descendants(DummyNode.class).take(1).descendants(DummyNode.class).toList(); @@ -62,7 +62,7 @@ public class BoundaryTraversalTest { } @Test - public void testSearchIgnoringBoundary() { + void testSearchIgnoringBoundary() { addChild(rootNode, addChild(newDummyNode(true), newDummyNode(false))); List descendantsOfType = rootNode.findDescendantsOfType(DummyNode.class, true); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java index bf1931f9e9..9e6c794527 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/DummyNode.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import net.sourceforge.pmd.internal.util.AssertionUtil; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.ast.Parser.ParserTask; import net.sourceforge.pmd.lang.ast.impl.AbstractNode; @@ -93,8 +92,7 @@ public class DummyNode extends AbstractNode implements Gen public void setImage(String image) { this.image = image; if (image.startsWith("#")) { - xpathName = image.substring(1); - assert AssertionUtil.isJavaIdentifier(xpathName) : "need an ident after '#': " + image; + xpathName = image; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporterTest.java index f798a8e066..eb4ef73580 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporterTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/SemanticErrorReporterTest.java @@ -4,15 +4,18 @@ package net.sourceforge.pmd.lang.ast; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.contains; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.event.Level; import org.slf4j.helpers.NOPLogger; @@ -27,33 +30,38 @@ import net.sourceforge.pmd.util.log.MessageReporter; * Reports errors that occur after parsing. This may be used to implement * semantic checks in a language specific way. */ -public class SemanticErrorReporterTest { +class SemanticErrorReporterTest { private static final String MOCK_FILENAME = "dummy/file.txt"; MessageReporter mockReporter; Logger mockLogger; - @Before - public void setup() { + @BeforeEach + void setup() { mockReporter = mock(MessageReporter.class); + when(mockReporter.isLoggable(Level.ERROR)).thenReturn(true); mockLogger = spy(NOPLogger.class); } @Test - public void testErrorLogging() { - SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(mockReporter, mockLogger); + void testErrorLogging() { + SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(mockReporter); RootNode node = parseMockNode(reporter); + assertNull(reporter.getFirstError()); + String message = "an error occurred"; reporter.error(node, message); verify(mockReporter).log(eq(Level.ERROR), contains(message)); verifyNoMoreInteractions(mockLogger); + + assertNotNull(reporter.getFirstError()); } @Test - public void testEscaping() { - SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(mockReporter, mockLogger); + void testEscaping() { + SemanticErrorReporter reporter = SemanticErrorReporter.reportToLogger(mockReporter); RootNode node = parseMockNode(reporter); // this is a MessageFormat string diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/impl/AbstractNodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/impl/AbstractNodeTest.java index 5ef7195965..824086f38e 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/impl/AbstractNodeTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/impl/AbstractNodeTest.java @@ -7,40 +7,36 @@ package net.sourceforge.pmd.lang.ast.impl; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.node; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.root; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.tree; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.fail; import java.util.List; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; import net.sourceforge.pmd.lang.ast.Node; -import junitparams.JUnitParamsRunner; -import junitparams.Parameters; - - /** * Unit test for {@link AbstractNode}. */ -@RunWith(JUnitParamsRunner.class) -public class AbstractNodeTest { +class AbstractNodeTest { private static final int NUM_CHILDREN = 3; private static final int NUM_GRAND_CHILDREN = 3; // Note that in order to successfully run JUnitParams, we need to explicitly use `Integer` instead of `int` - private Integer[] childrenIndexes() { + static Integer[] childrenIndexes() { return getIntRange(NUM_CHILDREN); } - private Integer[] grandChildrenIndexes() { + static Integer[] grandChildrenIndexes() { return getIntRange(NUM_GRAND_CHILDREN); } @@ -52,7 +48,7 @@ public class AbstractNodeTest { return childIndexes; } - public Object childrenAndGrandChildrenIndexes() { + static Object childrenAndGrandChildrenIndexes() { final Integer[] childrenIndexes = childrenIndexes(); final Integer[] grandChildrenIndexes = grandChildrenIndexes(); final Object[] indexes = new Object[childrenIndexes.length * grandChildrenIndexes.length]; @@ -67,8 +63,8 @@ public class AbstractNodeTest { private DummyRootNode rootNode; - @Before - public void setUpSampleNodeTree() { + @BeforeEach + void setUpSampleNodeTree() { rootNode = tree( () -> { DummyRootNode root = root(); @@ -89,9 +85,9 @@ public class AbstractNodeTest { /** * Explicitly tests the {@code remove} method, and implicitly the {@code removeChildAtIndex} method */ - @Test - @Parameters(method = "childrenIndexes") - public void testRemoveChildOfRootNode(final int childIndex) { + @ParameterizedTest + @MethodSource("childrenIndexes") + void testRemoveChildOfRootNode(final int childIndex) { final DummyNode child = rootNode.getChild(childIndex); final List grandChildren = child.children().toList(); @@ -109,7 +105,7 @@ public class AbstractNodeTest { } @Test - public void testPrevNextSiblings() { + void testPrevNextSiblings() { DummyRootNode root = tree(() -> root(node(), node())); assertNull(root.getNextSibling()); @@ -129,7 +125,7 @@ public class AbstractNodeTest { * This is a border case as the root node does not have any parent. */ @Test - public void testRemoveRootNode() { + void testRemoveRootNode() { // Check that the root node has the expected properties final List children = rootNode.children().toList(); @@ -149,9 +145,9 @@ public class AbstractNodeTest { * Explicitly tests the {@code remove} method, and implicitly the {@code removeChildAtIndex} method. * These are border cases as grandchildren nodes do not have any child. */ - @Test - @Parameters(method = "childrenAndGrandChildrenIndexes") - public void testRemoveGrandChildNode(final int childIndex, final int grandChildIndex) { + @ParameterizedTest + @MethodSource("childrenAndGrandChildrenIndexes") + void testRemoveGrandChildNode(final int childIndex, final int grandChildIndex) { final DummyNode child = rootNode.getChild(childIndex); final DummyNode grandChild = child.getChild(grandChildIndex); @@ -167,9 +163,9 @@ public class AbstractNodeTest { /** * Explicitly tests the {@code removeChildAtIndex} method. */ - @Test - @Parameters(method = "childrenIndexes") - public void testRemoveRootNodeChildAtIndex(final int childIndex) { + @ParameterizedTest + @MethodSource("childrenIndexes") + void testRemoveRootNodeChildAtIndex(final int childIndex) { final List originalChildren = rootNode.children().toList(); // Do the actual removal @@ -195,7 +191,7 @@ public class AbstractNodeTest { * Test that invalid indexes cases are handled without exception. */ @Test - public void testRemoveChildAtIndexWithInvalidIndex() { + void testRemoveChildAtIndexWithInvalidIndex() { try { rootNode.removeChildAtIndex(-1); rootNode.removeChildAtIndex(rootNode.getNumChildren()); @@ -208,9 +204,9 @@ public class AbstractNodeTest { * Explicitly tests the {@code removeChildAtIndex} method. * This is a border case as the method invocation should do nothing. */ - @Test - @Parameters(method = "grandChildrenIndexes") - public void testRemoveChildAtIndexOnNodeWithNoChildren(final int grandChildIndex) { + @ParameterizedTest + @MethodSource("grandChildrenIndexes") + void testRemoveChildAtIndexOnNodeWithNoChildren(final int grandChildIndex) { // grandChild does not have any child final DummyNode grandChild = rootNode.getChild(grandChildIndex).getChild(grandChildIndex); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeStreamBlanketTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeStreamBlanketTest.java index 72fb54767e..d8a0f3a496 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeStreamBlanketTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeStreamBlanketTest.java @@ -4,12 +4,15 @@ package net.sourceforge.pmd.lang.ast.internal; -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertSame; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.node; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.nodeB; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.root; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.tree; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import java.util.ArrayList; import java.util.Arrays; @@ -19,13 +22,8 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.DummyNode.DummyNodeTypeB; @@ -36,8 +34,7 @@ import net.sourceforge.pmd.lang.ast.NodeStream; * Asserts invariants independent of the NodeStream implementation. Error * messages are not great but coverage is. */ -@RunWith(Parameterized.class) -public class NodeStreamBlanketTest { +class NodeStreamBlanketTest { private static final List ASTS = Arrays.asList( tree( @@ -70,17 +67,9 @@ public class NodeStreamBlanketTest { ) ); - @Rule - public ExpectedException expect = ExpectedException.none(); - - private final NodeStream stream; - - public NodeStreamBlanketTest(NodeStream stream) { - this.stream = stream; - } - - @Test - public void testToListConsistency() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testToListConsistency(NodeStream stream) { List toList = stream.toList(); List collected = stream.collect(Collectors.toList()); List fromStream = stream.toStream().collect(Collectors.toList()); @@ -91,16 +80,18 @@ public class NodeStreamBlanketTest { assertEquals(toList, cached); } - @Test - public void testToListSize() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testToListSize(NodeStream stream) { List toList = stream.toList(); assertEquals(toList.size(), stream.count()); } - @Test - public void testLast() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testLast(NodeStream stream) { assertImplication( stream, prop("nonEmpty", NodeStream::nonEmpty), @@ -108,8 +99,9 @@ public class NodeStreamBlanketTest { ); } - @Test - public void testFirst() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testFirst(NodeStream stream) { assertImplication( stream, prop("nonEmpty", NodeStream::nonEmpty), @@ -118,8 +110,9 @@ public class NodeStreamBlanketTest { } - @Test - public void testDrop() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testDrop(NodeStream stream) { assertImplication( stream, prop("nonEmpty", NodeStream::nonEmpty), @@ -129,8 +122,9 @@ public class NodeStreamBlanketTest { ); } - @Test - public void testDropLast() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testDropLast(NodeStream stream) { assertImplication( stream, prop("nonEmpty", NodeStream::nonEmpty), @@ -140,8 +134,9 @@ public class NodeStreamBlanketTest { ); } - @Test - public void testDropMoreThan1() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testDropMoreThan1(NodeStream stream) { assertImplication( stream, prop("count() > 1", it -> it.count() > 1), @@ -150,8 +145,9 @@ public class NodeStreamBlanketTest { ); } - @Test - public void testTake() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testTake(NodeStream stream) { assertImplication( stream, prop("nonEmpty", NodeStream::nonEmpty), @@ -161,33 +157,35 @@ public class NodeStreamBlanketTest { ); } - @Test - public void testGet() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testGet(NodeStream stream) { for (int i = 0; i < 100; i++) { - assertSame("stream.get(i) == stream.drop(i).first()", stream.get(i), stream.drop(i).first()); + assertSame(stream.get(i), stream.drop(i).first(), "stream.get(i) == stream.drop(i).first()"); } } - @Test - public void testGetNegative() { - expect.expect(IllegalArgumentException.class); - stream.get(-1); + @ParameterizedTest + @MethodSource("primeNumbers") + void testGetNegative(NodeStream stream) { + assertThrows(IllegalArgumentException.class, () -> stream.get(-1)); } - @Test - public void testDropNegative() { - expect.expect(IllegalArgumentException.class); - stream.drop(-1); + @ParameterizedTest + @MethodSource("primeNumbers") + void testDropNegative(NodeStream stream) { + assertThrows(IllegalArgumentException.class, () -> stream.drop(-1)); } - @Test - public void testTakeNegative() { - expect.expect(IllegalArgumentException.class); - stream.take(-1); + @ParameterizedTest + @MethodSource("primeNumbers") + void testTakeNegative(NodeStream stream) { + assertThrows(IllegalArgumentException.class, () -> stream.take(-1)); } - @Test - public void testEmpty() { + @ParameterizedTest + @MethodSource("primeNumbers") + void testEmpty(NodeStream stream) { assertEquivalence( stream, prop("isEmpty", NodeStream::isEmpty), @@ -203,8 +201,7 @@ public class NodeStreamBlanketTest { ); } - @Parameterized.Parameters(name = "{index} On {0}") - public static Collection primeNumbers() { + static Collection primeNumbers() { return ASTS.stream().flatMap( root -> Stream.of( root.asStream(), @@ -251,10 +248,10 @@ public class NodeStreamBlanketTest { for (Prop prop1 : properties) { for (Prop prop2 : properties) { boolean p1 = prop1.test(input); - Assert.assertEquals( + assertEquals( + p1, prop2.test(input), "Expected (" + prop1.description + ") === (" + prop2.description - + "), but the LHS was " + p1 + " and the RHS was " + !p1, - p1, prop2.test(input) + + "), but the LHS was " + p1 + " and the RHS was " + !p1 ); } } @@ -262,13 +259,13 @@ public class NodeStreamBlanketTest { @SafeVarargs private static void assertImplication(T input, Prop precond, Prop... properties) { - Assume.assumeTrue(precond.test(input)); + assumeTrue(precond.test(input)); for (Prop prop2 : properties) { - Assert.assertTrue( + assertTrue( + prop2.test(input), "Expected (" + precond.description + ") to entail (" + prop2.description - + "), but the latter was false", - prop2.test(input) + + "), but the latter was false" ); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeStreamTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeStreamTest.java index 0bc4b03a1c..f4a744f859 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeStreamTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/ast/internal/NodeStreamTest.java @@ -11,18 +11,18 @@ import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.pathsOf; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.root; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.tree; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.collection.IsIterableContainingInOrder.contains; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.Optional; import org.apache.commons.lang3.mutable.MutableInt; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.DummyNode.DummyNodeTypeB; @@ -34,7 +34,7 @@ import net.sourceforge.pmd.lang.ast.NodeStream.DescendantNodeStream; /** * @author Clรฉment Fournier */ -public class NodeStreamTest { +class NodeStreamTest { private final DummyNode tree1 = tree( @@ -70,7 +70,7 @@ public class NodeStreamTest { @Test - public void testStreamConstructionIsNullSafe() { + void testStreamConstructionIsNullSafe() { assertTrue(NodeStream.of((Node) null).isEmpty()); assertThat(NodeStream.of(null, null, tree1).count(), equalTo(1)); assertThat(NodeStream.fromIterable(Arrays.asList(tree1, null, null)).count(), equalTo(1)); @@ -79,26 +79,26 @@ public class NodeStreamTest { @Test - public void testMapIsNullSafe() { + void testMapIsNullSafe() { assertTrue(tree1.descendantsOrSelf().map(n -> null).isEmpty()); } @Test - public void testFlatMapIsNullSafe() { + void testFlatMapIsNullSafe() { assertTrue(tree1.descendantsOrSelf().flatMap(n -> null).isEmpty()); } @Test - public void testChildrenStream() { + void testChildrenStream() { assertThat(pathsOf(tree1.children()), contains("0", "1")); assertThat(pathsOf(tree1.asStream().children()), contains("0", "1")); } @Test - public void testChildrenEagerEvaluation() { + void testChildrenEagerEvaluation() { NodeStream children = tree1.children(); assertEquals(AxisStream.ChildrenStream.class, children.getClass()); NodeStream children1 = children.children(); @@ -108,27 +108,27 @@ public class NodeStreamTest { @Test - public void testDescendantStream() { + void testDescendantStream() { assertThat(pathsOf(tree1.descendants()), contains("0", "00", "01", "010", "011", "0110", "012", "013", "1")); assertThat(pathsOf(tree1.asStream().descendants()), contains("0", "00", "01", "010", "011", "0110", "012", "013", "1")); } @Test - public void testSingletonStream() { + void testSingletonStream() { assertThat(pathsOf(tree1.asStream()), contains("")); assertThat(pathsOf(NodeStream.of(tree1)), contains("")); } @Test - public void testDescendantOrSelfStream() { + void testDescendantOrSelfStream() { assertThat(pathsOf(tree1.descendantsOrSelf()), contains("", "0", "00", "01", "010", "011", "0110", "012", "013", "1")); assertThat(pathsOf(NodeStream.of(tree1).descendantsOrSelf()), contains("", "0", "00", "01", "010", "011", "0110", "012", "013", "1")); assertThat(pathsOf(followPath(tree1, "0110").descendantsOrSelf()), contains("0110")); // with a leaf node } @Test - public void testAncestors() { + void testAncestors() { // 010 Node node = tree1.children().children().children().first(); assertEquals("010", node.getImage()); @@ -142,7 +142,7 @@ public class NodeStreamTest { } @Test - public void testAncestorsFiltered() { + void testAncestorsFiltered() { // 0110 Node node = tree1.children().children().children().children().first(); assertEquals("0110", node.getImage()); @@ -152,7 +152,7 @@ public class NodeStreamTest { } @Test - public void testAncestorsFilteredDrop() { + void testAncestorsFilteredDrop() { // 0110 Node node = tree1.children().children().children().children().first(); assertEquals("0110", node.getImage()); @@ -163,7 +163,7 @@ public class NodeStreamTest { @Test - public void testFollowingSiblings() { + void testFollowingSiblings() { assertThat(pathsOf(followPath(tree2, "2").asStream().followingSiblings()), contains("3")); assertThat(pathsOf(followPath(tree2, "0").asStream().followingSiblings()), contains("1", "2", "3")); assertTrue(pathsOf(followPath(tree2, "3").asStream().followingSiblings()).isEmpty()); @@ -171,47 +171,47 @@ public class NodeStreamTest { @Test - public void testPrecedingSiblings() { + void testPrecedingSiblings() { assertThat(pathsOf(followPath(tree2, "2").asStream().precedingSiblings()), contains("0", "1")); assertThat(pathsOf(followPath(tree2, "3").asStream().precedingSiblings()), contains("0", "1", "2")); assertTrue(pathsOf(followPath(tree2, "0").asStream().precedingSiblings()).isEmpty()); } @Test - public void testRootSiblings() { + void testRootSiblings() { assertTrue(tree2.asStream().precedingSiblings().isEmpty()); assertTrue(tree2.asStream().followingSiblings().isEmpty()); } @Test - public void testAncestorStream() { + void testAncestorStream() { assertThat(pathsOf(followPath(tree1, "01").ancestors()), contains("0", "")); assertThat(pathsOf(followPath(tree1, "01").asStream().ancestors()), contains("0", "")); } @Test - public void testParentStream() { + void testParentStream() { assertThat(pathsOf(followPath(tree1, "01").asStream().parents()), contains("0")); } @Test - public void testAncestorStreamUnion() { + void testAncestorStreamUnion() { assertThat(pathsOf(NodeStream.union(followPath(tree1, "01").ancestors(), tree2.children().ancestors())), contains("0", "", "", "", "", "")); } @Test - public void testDistinct() { + void testDistinct() { assertThat(pathsOf(NodeStream.union(followPath(tree1, "01").ancestors(), tree2.children().ancestors()).distinct()), contains("0", "", "")); // roots of both trees } @Test - public void testGet() { + void testGet() { // ("0", "00", "01", "010", "011", "0110", "012", "013", "1") DescendantNodeStream stream = tree1.descendants(); @@ -224,7 +224,7 @@ public class NodeStreamTest { } @Test - public void testNodeStreamsCanBeIteratedSeveralTimes() { + void testNodeStreamsCanBeIteratedSeveralTimes() { DescendantNodeStream stream = tree1.descendants(); assertThat(stream.count(), equalTo(9)); @@ -237,7 +237,7 @@ public class NodeStreamTest { @Test - public void testNodeStreamPipelineIsLazy() { + void testNodeStreamPipelineIsLazy() { MutableInt numEvals = new MutableInt(); @@ -251,7 +251,7 @@ public class NodeStreamTest { @Test - public void testForkJoinUpstreamPipelineIsExecutedAtMostOnce() { + void testForkJoinUpstreamPipelineIsExecutedAtMostOnce() { MutableInt numEvals = new MutableInt(); NodeStream stream = @@ -275,7 +275,7 @@ public class NodeStreamTest { @Test - public void testCachedStreamUpstreamPipelineIsExecutedAtMostOnce() { + void testCachedStreamUpstreamPipelineIsExecutedAtMostOnce() { MutableInt upstreamEvals = new MutableInt(); MutableInt downstreamEvals = new MutableInt(); @@ -304,7 +304,7 @@ public class NodeStreamTest { @Test - public void testUnionIsLazy() { + void testUnionIsLazy() { MutableInt tree1Evals = new MutableInt(); MutableInt tree2Evals = new MutableInt(); @@ -323,7 +323,7 @@ public class NodeStreamTest { @Test - public void testSomeOperationsAreLazy() { + void testSomeOperationsAreLazy() { MutableInt tree1Evals = new MutableInt(); @@ -365,7 +365,7 @@ public class NodeStreamTest { @Test - public void testFollowingSiblingsNonEmpty() { + void testFollowingSiblingsNonEmpty() { DummyNode node = followPath(tree1, "012"); NodeStream nodes = node.asStream().followingSiblings(); @@ -375,7 +375,7 @@ public class NodeStreamTest { } @Test - public void testPrecedingSiblingsNonEmpty() { + void testPrecedingSiblingsNonEmpty() { DummyNode node = followPath(tree1, "011"); NodeStream nodes = node.asStream().precedingSiblings(); @@ -385,7 +385,7 @@ public class NodeStreamTest { } @Test - public void testPrecedingSiblingsDrop() { + void testPrecedingSiblingsDrop() { DummyNode node = followPath(tree1, "012"); NodeStream nodes = node.asStream().precedingSiblings().drop(1); @@ -394,7 +394,7 @@ public class NodeStreamTest { } @Test - public void testFollowingSiblingsDrop() { + void testFollowingSiblingsDrop() { DummyNode node = followPath(tree1, "011"); NodeStream nodes = node.asStream().followingSiblings().drop(1); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java index 64a0a0cbd8..67b7976579 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/CharsTest.java @@ -5,13 +5,13 @@ package net.sourceforge.pmd.lang.document; import static net.sourceforge.pmd.util.CollectionUtil.listOf; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.IOException; import java.io.Reader; @@ -19,7 +19,7 @@ import java.io.StringWriter; import java.util.List; import java.util.stream.Collectors; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.util.CollectionUtil; @@ -423,7 +423,7 @@ public class CharsTest { // ------------ try (Reader reader = bc.newReader()) { - assertTrue("markSupported", reader.markSupported()); + assertTrue(reader.markSupported(), "markSupported"); assertEquals('b', reader.read()); assertEquals('c', reader.read()); @@ -453,7 +453,7 @@ public class CharsTest { // ------------ try (Reader reader = bc.newReader()) { - assertTrue("markSupported", reader.markSupported()); + assertTrue(reader.markSupported(), "markSupported"); assertEquals('b', reader.read()); assertThrows(IOException.class, reader::reset); @@ -491,7 +491,7 @@ public class CharsTest { char[] cbuf = new char[4]; try (Reader reader = bc.newReader()) { - assertTrue("markSupported", reader.markSupported()); + assertTrue(reader.markSupported(), "markSupported"); assertEquals('b', reader.read()); assertThrows(NullPointerException.class, () -> reader.read(null, 0, 0)); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileCollectorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileCollectorTest.java index 191c004db0..a72fc194d1 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileCollectorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileCollectorTest.java @@ -5,9 +5,9 @@ package net.sourceforge.pmd.lang.document; import static net.sourceforge.pmd.util.CollectionUtil.listOf; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.IOException; @@ -19,9 +19,8 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageRegistry; @@ -31,53 +30,48 @@ import net.sourceforge.pmd.lang.LanguageVersionDiscoverer; /** * @author Clรฉment Fournier */ -public class FileCollectorTest { +class FileCollectorTest { - @Rule - public TemporaryFolder tempFolder = new TemporaryFolder(); + @TempDir + private Path tempFolder; @Test - public void testAddFile() throws IOException { - Path root = tempFolder.getRoot().toPath(); - Path foo = newFile(root, "foo.dummy"); - Path bar = newFile(root, "bar.unknown"); + void testAddFile() throws IOException { + Path foo = newFile(tempFolder, "foo.dummy"); + Path bar = newFile(tempFolder, "bar.unknown"); FileCollector collector = newCollector(); - assertTrue("should be dummy language", collector.addFile(foo)); - assertFalse("should be unknown language", collector.addFile(bar)); + assertTrue(collector.addFile(foo), "should be dummy language"); + assertFalse(collector.addFile(bar), "should be unknown language"); assertCollected(collector, listOf("foo.dummy")); } @Test - public void testAddFileForceLanguage() throws IOException { - Path root = tempFolder.getRoot().toPath(); - Path bar = newFile(root, "bar.unknown"); + void testAddFileForceLanguage() throws IOException { + Path bar = newFile(tempFolder, "bar.unknown"); Language dummy = LanguageRegistry.findLanguageByTerseName("dummy"); FileCollector collector = newCollector(dummy.getDefaultVersion()); - assertTrue("should be unknown language", collector.addFile(bar, dummy)); + assertTrue(collector.addFile(bar, dummy), "should be unknown language"); assertCollected(collector, listOf("bar.unknown")); assertNoErrors(collector); } @Test - public void testAddFileNotExists() { - Path root = tempFolder.getRoot().toPath(); - + void testAddFileNotExists() { FileCollector collector = newCollector(); - assertFalse(collector.addFile(root.resolve("does_not_exist.dummy"))); + assertFalse(collector.addFile(tempFolder.resolve("does_not_exist.dummy"))); assertEquals(1, collector.getReporter().numErrors()); } @Test - public void testAddFileNotAFile() throws IOException { - Path root = tempFolder.getRoot().toPath(); - Path dir = root.resolve("src"); + void testAddFileNotAFile() throws IOException { + Path dir = tempFolder.resolve("src"); Files.createDirectories(dir); FileCollector collector = newCollector(); @@ -86,8 +80,8 @@ public class FileCollectorTest { } @Test - public void testAddDirectory() throws IOException { - Path root = tempFolder.getRoot().toPath(); + void testAddDirectory() throws IOException { + Path root = tempFolder; newFile(root, "src/foo.dummy"); newFile(root, "src/bar.unknown"); newFile(root, "src/x/bar.dummy"); @@ -100,7 +94,7 @@ public class FileCollectorTest { } @Test - public void testRelativize() throws IOException { + void testRelativize() throws IOException { String displayName = FileCollector.getDisplayName(Paths.get("a", "b", "c"), listOf(Paths.get("a").toString())); assertEquals(displayName, Paths.get("b", "c").toString()); } @@ -128,7 +122,7 @@ public class FileCollectorTest { } private void assertNoErrors(FileCollector collector) { - assertEquals("No errors expected", 0, collector.getReporter().numErrors()); + assertEquals(0, collector.getReporter().numErrors(), "No errors expected"); } private FileCollector newCollector() { @@ -138,7 +132,7 @@ public class FileCollectorTest { private FileCollector newCollector(LanguageVersion forcedVersion) { LanguageVersionDiscoverer discoverer = new LanguageVersionDiscoverer(forcedVersion); FileCollector collector = FileCollector.newCollector(discoverer, new TestMessageReporter()); - collector.relativizeWith(tempFolder.getRoot().getAbsolutePath()); + collector.relativizeWith(tempFolder.toAbsolutePath().toString()); return collector; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java index d0fb1e31d2..a583a70adc 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/FileLocationTest.java @@ -5,10 +5,10 @@ package net.sourceforge.pmd.lang.document; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.hamcrest.MatcherAssert; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * @author Clรฉment Fournier diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java index 7aa7c89ab1..5b7c2dc7aa 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/SourceCodePositionerTest.java @@ -4,10 +4,10 @@ package net.sourceforge.pmd.lang.document; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * Unit test for {@link SourceCodePositioner}. diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TestMessageReporter.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TestMessageReporter.java index 8689530e30..a37e239d6c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TestMessageReporter.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TestMessageReporter.java @@ -18,6 +18,5 @@ public class TestMessageReporter extends SimpleMessageReporter { public TestMessageReporter() { super(LOG); - setLevel(null); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java index 0f7d2b9a91..1d15349d12 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextDocumentTest.java @@ -10,13 +10,13 @@ import static org.junit.Assert.assertThrows; import java.io.IOException; -import org.apache.commons.io.IOUtils; import org.junit.Test; import org.junit.runner.RunWith; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; +import net.sourceforge.pmd.util.IOUtil; import junitparams.JUnitParamsRunner; import junitparams.Parameters; @@ -198,7 +198,7 @@ public class TextDocumentTest { assertEquals("NewReader should read the text", doc.getText().toString(), - IOUtils.toString(doc.newReader()) + IOUtil.readToString(doc.newReader()) ); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java index 17cf18bfba..1aafb3404b 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/document/TextFilesTest.java @@ -18,7 +18,6 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import org.apache.commons.io.IOUtils; import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.Rule; import org.junit.Test; @@ -91,6 +90,7 @@ public class TextFilesTest { DataSource ds = new FileDataSource(file.toFile()); PMDConfiguration config = new PMDConfiguration(); + config.setForceLanguageVersion(dummyVersion); try (TextFile tf = TextFile.dataSourceCompat(ds, config)) { assertEquals(ds.getNiceFileName(false, null), tf.getPathId()); assertEquals(ds.getNiceFileName(false, null), tf.getDisplayName()); @@ -242,7 +242,7 @@ public class TextFilesTest { private @NonNull Path makeTmpFile(Charset charset, String content) throws IOException { Path file = tempDir.newFile().toPath(); try (BufferedWriter writer = Files.newBufferedWriter(file, charset)) { - IOUtils.write(content, writer); + writer.write(content); } return file; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKeyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKeyTest.java index 97dfc80ea6..ebe27c5ce8 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKeyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/metrics/ParameterizedMetricKeyTest.java @@ -4,25 +4,25 @@ package net.sourceforge.pmd.lang.metrics; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.ast.Node; -public class ParameterizedMetricKeyTest { +class ParameterizedMetricKeyTest { private static final MetricOptions DUMMY_VERSION_1 = MetricOptions.ofOptions(Options.DUMMY1, Options.DUMMY2); private static final MetricOptions DUMMY_VERSION_2 = MetricOptions.ofOptions(Options.DUMMY2); private static final Metric DUMMY_METRIC = Metric.of((n, opts) -> 0., t -> t, "dummy"); @Test - public void testIdentity() { + void testIdentity() { ParameterizedMetricKey key1 = ParameterizedMetricKey.getInstance(DUMMY_METRIC, DUMMY_VERSION_1); ParameterizedMetricKey key2 = ParameterizedMetricKey.getInstance(DUMMY_METRIC, DUMMY_VERSION_1); @@ -32,7 +32,7 @@ public class ParameterizedMetricKeyTest { @Test - public void testVersioning() { + void testVersioning() { ParameterizedMetricKey key1 = ParameterizedMetricKey.getInstance(DUMMY_METRIC, DUMMY_VERSION_1); ParameterizedMetricKey key2 = ParameterizedMetricKey.getInstance(DUMMY_METRIC, DUMMY_VERSION_2); @@ -42,7 +42,7 @@ public class ParameterizedMetricKeyTest { @Test - public void testToString() { + void testToString() { ParameterizedMetricKey key1 = ParameterizedMetricKey.getInstance(DUMMY_METRIC, DUMMY_VERSION_1); assertTrue(key1.toString().contains(key1.metric.displayName())); @@ -51,7 +51,7 @@ public class ParameterizedMetricKeyTest { @Test - public void testAdHocMetricKey() { + void testAdHocMetricKey() { ParameterizedMetricKey key1 = ParameterizedMetricKey.getInstance(DUMMY_METRIC, DUMMY_VERSION_1); ParameterizedMetricKey key2 = ParameterizedMetricKey.getInstance(DUMMY_METRIC, DUMMY_VERSION_1); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java index 4344559685..fa94fc20a2 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/XPathRuleTest.java @@ -6,12 +6,10 @@ package net.sourceforge.pmd.lang.rule; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import org.hamcrest.Matchers; -import org.junit.Rule; -import org.junit.Test; -import org.junit.contrib.java.lang.system.SystemErrRule; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.RuleContextTest; @@ -23,70 +21,63 @@ import net.sourceforge.pmd.lang.ast.DummyNodeWithDeprecatedAttribute; import net.sourceforge.pmd.lang.document.TextRegion; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; -public class XPathRuleTest { +import com.github.stefanbirkner.systemlambda.SystemLambda; - @Rule - public final SystemErrRule systemErrRule = new SystemErrRule().muteForSuccessfulTests().enableLog(); +class XPathRuleTest { @Test - public void testAttributeDeprecation10() throws Exception { + void testAttributeDeprecation10() throws Exception { testDeprecation(XPathVersion.XPATH_1_0); } @Test - public void testAttributeDeprecation20() throws Exception { + void testAttributeDeprecation20() throws Exception { testDeprecation(XPathVersion.XPATH_2_0); } - public void testDeprecation(XPathVersion version) throws Exception { + void testDeprecation(XPathVersion version) throws Exception { XPathRule xpr = makeRule(version, "SomeRule"); - systemErrRule.clearLog(); - DummyNode firstNode = newNode(); - // with another rule forked from the same one (in multithreaded processor) - Report report = RuleContextTest.getReportForRuleApply(xpr, firstNode); - assertEquals(1, report.getViolations().size()); - - String log = systemErrRule.getLog(); + String log = SystemLambda.tapSystemErrAndOut(() -> { + // with another rule forked from the same one (in multithreaded processor) + Report report = RuleContextTest.getReportForRuleApply(xpr, firstNode); + assertEquals(1, report.getViolations().size()); + }); assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Size' by XPath rule 'SomeRule'")); assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Name' by XPath rule 'SomeRule', please use @Image instead")); - systemErrRule.clearLog(); - - // with another node - report = RuleContextTest.getReportForRuleApply(xpr, newNode()); - - assertEquals(1, report.getViolations().size()); - - assertEquals("", systemErrRule.getLog()); // no additional warnings + log = SystemLambda.tapSystemErrAndOut(() -> { + // with another node + Report report = RuleContextTest.getReportForRuleApply(xpr, newNode()); + assertEquals(1, report.getViolations().size()); + }); + assertEquals("", log); // no additional warnings - // with another rule forked from the same one (in multithreaded processor) - report = RuleContextTest.getReportForRuleApply(xpr.deepCopy(), newNode()); - - assertEquals(1, report.getViolations().size()); - - assertEquals("", systemErrRule.getLog()); // no additional warnings + log = SystemLambda.tapSystemErrAndOut(() -> { + // with another rule forked from the same one (in multithreaded processor) + Report report = RuleContextTest.getReportForRuleApply(xpr.deepCopy(), newNode()); + assertEquals(1, report.getViolations().size()); + }); + assertEquals("", log); // no additional warnings // with another rule on the same node, new warnings XPathRule otherRule = makeRule(version, "OtherRule"); otherRule.setRuleSetName("rset.xml"); - report = RuleContextTest.getReportForRuleApply(otherRule, firstNode); - - assertEquals(1, report.getViolations().size()); - - log = systemErrRule.getLog(); + log = SystemLambda.tapSystemErrAndOut(() -> { + Report report = RuleContextTest.getReportForRuleApply(otherRule, firstNode); + assertEquals(1, report.getViolations().size()); + }); assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Size' by XPath rule 'OtherRule' (in ruleset 'rset.xml')")); assertThat(log, Matchers.containsString("Use of deprecated attribute 'dummyNode/@Name' by XPath rule 'OtherRule' (in ruleset 'rset.xml'), please use @Image instead")); - } - public XPathRule makeRule(XPathVersion version, String name) { + XPathRule makeRule(XPathVersion version, String name) { XPathRule xpr = new XPathRule(version, "//dummyNode[@Size >= 2 and @Name='foo']"); xpr.setName(name); xpr.setLanguage(LanguageRegistry.getLanguage("Dummy")); @@ -95,7 +86,7 @@ public class XPathRuleTest { } - public XPathRule makeXPath(String xpathExpr) { + XPathRule makeXPath(String xpathExpr) { XPathRule xpr = new XPathRule(XPathVersion.XPATH_2_0, xpathExpr); xpr.setLanguage(LanguageRegistry.getLanguage(DummyLanguageModule.NAME)); xpr.setName("name"); @@ -104,7 +95,7 @@ public class XPathRuleTest { } @Test - public void testFileNameInXpath() { + void testFileNameInXpath() { Report report = executeRule(makeXPath("//*[pmd:fileName() = 'Foo.cls']"), newRoot("src/Foo.cls")); @@ -112,7 +103,7 @@ public class XPathRuleTest { } @Test - public void testBeginLine() { + void testBeginLine() { Report report = executeRule(makeXPath("//*[pmd:startLine(.)=1]"), newRoot("src/Foo.cls")); @@ -120,7 +111,7 @@ public class XPathRuleTest { } @Test - public void testBeginCol() { + void testBeginCol() { Report report = executeRule(makeXPath("//*[pmd:startColumn(.)=1]"), newRoot("src/Foo.cls")); @@ -128,7 +119,7 @@ public class XPathRuleTest { } @Test - public void testEndLine() { + void testEndLine() { Report report = executeRule(makeXPath("//*[pmd:endLine(.)=1]"), newRoot("src/Foo.cls")); @@ -136,19 +127,19 @@ public class XPathRuleTest { } @Test - public void testEndColumn() { + void testEndColumn() { Report report = executeRule(makeXPath("//*[pmd:endColumn(.)>1]"), newRoot("src/Foo.cls")); assertThat(report.getViolations(), hasSize(1)); } - public Report executeRule(net.sourceforge.pmd.Rule rule, DummyNode node) { + Report executeRule(net.sourceforge.pmd.Rule rule, DummyNode node) { return RuleContextTest.getReportForRuleApply(rule, node); } - public DummyRootNode newNode() { + DummyRootNode newNode() { DummyRootNode root = new DummyRootNode(); DummyNode dummy = new DummyNodeWithDeprecatedAttribute(); root.addChild(dummy, 0); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/internal/LatticeRelationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/internal/LatticeRelationTest.java index 575e2fb6d2..642ad2c4f8 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/internal/LatticeRelationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/internal/LatticeRelationTest.java @@ -8,7 +8,8 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; import static net.sourceforge.pmd.util.CollectionUtil.setOf; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Arrays; import java.util.HashSet; @@ -19,21 +20,16 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import org.checkerframework.checker.nullness.qual.NonNull; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; import org.pcollections.HashTreePSet; import org.pcollections.PSet; import net.sourceforge.pmd.internal.util.PredicateUtil; -public class LatticeRelationTest { - - @Rule - public ExpectedException expect = ExpectedException.none(); +class LatticeRelationTest { @Test - public void testCustomTopo() { + void testCustomTopo() { LatticeRelation, String, Set> lattice = setLattice(PredicateUtil.always()); @@ -52,7 +48,7 @@ public class LatticeRelationTest { } @Test - public void testClearing() { + void testClearing() { LatticeRelation, String, Set> lattice = setLattice(PredicateUtil.always()); @@ -79,7 +75,7 @@ public class LatticeRelationTest { @Test - public void testTopoFilter() { + void testTopoFilter() { // filter out sets with size 2 // this cuts out one level of the graph @@ -114,7 +110,7 @@ public class LatticeRelationTest { @Test - public void testInitialSetFilter() { + void testInitialSetFilter() { LatticeRelation, String, Set> lattice = new LatticeRelation<>( @@ -146,7 +142,7 @@ public class LatticeRelationTest { @Test - public void testDiamond() { + void testDiamond() { LatticeRelation, String, Set> lattice = setLattice(PredicateUtil.always()); @@ -172,7 +168,7 @@ public class LatticeRelationTest { @Test - public void testFilterOnChainSetup() { + void testFilterOnChainSetup() { // setup for the next test (difference here is no filter) LatticeRelation> lattice = stringLattice(PredicateUtil.always()); @@ -189,7 +185,7 @@ public class LatticeRelationTest { } @Test - public void testFilterOnChain() { + void testFilterOnChain() { LatticeRelation> lattice = stringLattice(s -> s.length() != 2 && s.length() != 1); @@ -208,7 +204,7 @@ public class LatticeRelationTest { } @Test - public void testTransitiveSucc() { + void testTransitiveSucc() { LatticeRelation> lattice = stringLattice(s -> s.equals("c") || s.equals("bc")); @@ -235,7 +231,7 @@ public class LatticeRelationTest { } @Test - public void testTransitiveSuccWithHoleInTheMiddle() { + void testTransitiveSuccWithHoleInTheMiddle() { LatticeRelation> lattice = stringLattice(setOf("abc", "bbc", "c")::contains); @@ -269,7 +265,7 @@ public class LatticeRelationTest { @Test - public void testToString() { + void testToString() { LatticeRelation, String, Set> lattice = setLattice(set -> set.size() < 2); lattice.put(setOf(1, 2), "12"); @@ -296,7 +292,7 @@ public class LatticeRelationTest { } @Test - public void testCycleDetection() { + void testCycleDetection() { List cycle = Arrays.asList("a", "b", "c", "d"); TopoOrder cyclicOrder = str -> { @@ -307,10 +303,10 @@ public class LatticeRelationTest { LatticeRelation> lattice = new LatticeRelation<>(cyclicOrder, PredicateUtil.always(), Objects::toString, Collectors.toSet()); - expect.expect(IllegalStateException.class); - expect.expectMessage("a -> b -> c -> d -> a"); - - lattice.put("a", "1"); + IllegalStateException exception = assertThrows(IllegalStateException.class, () -> { + lattice.put("a", "1"); + }); + assertEquals("Cycle in graph: a -> b -> c -> d -> a", exception.getMessage()); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/NoAttributeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/NoAttributeTest.java index 50476e0979..3503618ba9 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/NoAttributeTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/NoAttributeTest.java @@ -8,13 +8,13 @@ package net.sourceforge.pmd.lang.rule.xpath; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Set; import java.util.stream.Collectors; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.internal.util.IteratorUtil; import net.sourceforge.pmd.lang.ast.DummyNode; @@ -24,11 +24,11 @@ import net.sourceforge.pmd.lang.rule.xpath.NoAttribute.NoAttrScope; /** * @author Clรฉment Fournier */ -public class NoAttributeTest { +class NoAttributeTest { @Test - public void testNoAttrInherited() { + void testNoAttrInherited() { Node child = new NodeNoInherited(); Set attrNames = IteratorUtil.toList(child.getXPathAttributesIterator()).stream().map(Attribute::getName).collect(Collectors.toSet()); @@ -45,7 +45,7 @@ public class NoAttributeTest { @Test - public void testNoAttrAll() { + void testNoAttrAll() { assertTrue(0 < IteratorUtil.count(new NodeAllAttr(12).getXPathAttributesIterator())); @@ -59,7 +59,7 @@ public class NoAttributeTest { } @Test - public void testNoAttrAllIsNotInherited() { + void testNoAttrAllIsNotInherited() { NodeNoAttrAllChild child = new NodeNoAttrAllChild(); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java index d970f8aeeb..5220ce621e 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/impl/AttributeAxisIteratorTest.java @@ -6,7 +6,7 @@ package net.sourceforge.pmd.lang.rule.xpath.impl; import static net.sourceforge.pmd.util.CollectionUtil.setOf; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Arrays; import java.util.Collections; @@ -15,7 +15,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.ast.DummyNode; import net.sourceforge.pmd.lang.ast.Node; @@ -26,7 +26,7 @@ import net.sourceforge.pmd.util.CollectionUtil; /** * Unit test for {@link AttributeAxisIterator} */ -public class AttributeAxisIteratorTest { +class AttributeAxisIteratorTest { private static final Set DEFAULT_ATTRS = setOf("BeginColumn", "BeginLine", "Image", "EndColumn", "EndLine"); @@ -34,7 +34,7 @@ public class AttributeAxisIteratorTest { * Test hasNext and next. */ @Test - public void testAttributeAxisIterator() { + void testAttributeAxisIterator() { DummyNode dummyNode = new DummyNode(); AttributeAxisIterator it = new AttributeAxisIterator(dummyNode); @@ -43,7 +43,7 @@ public class AttributeAxisIteratorTest { } @Test - public void testAttributeAxisIteratorWithEnum() { + void testAttributeAxisIteratorWithEnum() { DummyNodeWithEnum dummyNode = new DummyNodeWithEnum(); AttributeAxisIterator it = new AttributeAxisIterator(dummyNode); @@ -54,7 +54,7 @@ public class AttributeAxisIteratorTest { } @Test - public void testAttributeAxisIteratorWithList() { + void testAttributeAxisIteratorWithList() { // list attributes are not supported anymore DummyNodeWithList dummyNode = new DummyNodeWithList(); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java index 1d15739995..3cb4065cf9 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/ElementNodeTest.java @@ -5,8 +5,12 @@ package net.sourceforge.pmd.lang.rule.xpath.internal; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.DummyLanguageModule; import net.sourceforge.pmd.lang.ast.DummyNode; @@ -15,11 +19,11 @@ import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; import net.sf.saxon.Configuration; import net.sf.saxon.type.Type; -public class ElementNodeTest { +class ElementNodeTest { @Test - public void testCompareOrder() { + void testCompareOrder() { DummyRootNode root = DummyLanguageModule.parse( "(#foo)" + "(#foo)" @@ -31,28 +35,72 @@ public class ElementNodeTest { Configuration configuration = Configuration.newConfiguration(); AstTreeInfo treeInfo = new AstTreeInfo(root, configuration); - Assert.assertSame(root, treeInfo.getRootNode().getUnderlyingNode()); - Assert.assertEquals(Type.DOCUMENT, treeInfo.getRootNode().getNodeKind()); + assertSame(root, treeInfo.getRootNode().getUnderlyingNode()); + assertEquals(Type.DOCUMENT, treeInfo.getRootNode().getNodeKind()); AstElementNode rootElt = treeInfo.getRootNode().getRootElement(); - Assert.assertSame(root, rootElt.getUnderlyingNode()); - Assert.assertEquals(Type.ELEMENT, rootElt.getNodeKind()); - Assert.assertSame(rootElt, treeInfo.findWrapperFor(root)); + assertSame(root, rootElt.getUnderlyingNode()); + assertEquals(Type.ELEMENT, rootElt.getNodeKind()); + assertSame(rootElt, treeInfo.findWrapperFor(root)); AstElementNode elementFoo0 = rootElt.getChildren().get(0); - Assert.assertSame(c0, elementFoo0.getUnderlyingNode()); - Assert.assertSame(elementFoo0, treeInfo.findWrapperFor(c0)); + assertSame(c0, elementFoo0.getUnderlyingNode()); + assertSame(elementFoo0, treeInfo.findWrapperFor(c0)); AstElementNode elementFoo1 = rootElt.getChildren().get(1); - Assert.assertSame(c1, elementFoo1.getUnderlyingNode()); - Assert.assertSame(elementFoo1, treeInfo.findWrapperFor(c1)); + assertSame(c1, elementFoo1.getUnderlyingNode()); + assertSame(elementFoo1, treeInfo.findWrapperFor(c1)); - Assert.assertFalse(elementFoo0.isSameNodeInfo(elementFoo1)); - Assert.assertFalse(elementFoo1.isSameNodeInfo(elementFoo0)); - Assert.assertTrue(elementFoo0.compareOrder(elementFoo1) < 0); - Assert.assertTrue(elementFoo1.compareOrder(elementFoo0) > 0); - Assert.assertEquals(0, elementFoo0.compareOrder(elementFoo0)); - Assert.assertEquals(0, elementFoo1.compareOrder(elementFoo1)); + assertFalse(elementFoo0.isSameNodeInfo(elementFoo1)); + assertFalse(elementFoo1.isSameNodeInfo(elementFoo0)); + assertTrue(elementFoo0.compareOrder(elementFoo1) < 0); + assertTrue(elementFoo1.compareOrder(elementFoo0) > 0); + assertEquals(0, elementFoo0.compareOrder(elementFoo0)); + assertEquals(0, elementFoo1.compareOrder(elementFoo1)); } + + @Test + void verifyTextNodeType() { + DummyRootNode root = DummyLanguageModule.parse("(foo)(#text)"); + + DummyNode c0 = root.getChild(0); + DummyNode c1 = root.getChild(1); + + Configuration configuration = Configuration.newConfiguration(); + AstTreeInfo treeInfo = new AstTreeInfo(root, configuration); + + AstElementNode rootElt = treeInfo.getRootNode().getRootElement(); + assertSame(root, rootElt.getUnderlyingNode()); + assertEquals(Type.ELEMENT, rootElt.getNodeKind()); + assertSame(rootElt, treeInfo.findWrapperFor(root)); + + AstElementNode elementFoo0 = rootElt.getChildren().get(0); + assertEquals(Type.ELEMENT, elementFoo0.getNodeKind()); + assertSame(c0, elementFoo0.getUnderlyingNode()); + assertSame(elementFoo0, treeInfo.findWrapperFor(c0)); + + AstElementNode elementText1 = rootElt.getChildren().get(1); + assertEquals(Type.TEXT, elementText1.getNodeKind()); + assertSame(c1, elementText1.getUnderlyingNode()); + assertSame(elementText1, treeInfo.findWrapperFor(c1)); + } + + @Test + void verifyCommentNodeType() { + DummyRootNode root = DummyLanguageModule.parse("(#comment)"); + + DummyNode c1 = root.getChild(0); + + Configuration configuration = Configuration.newConfiguration(); + AstTreeInfo treeInfo = new AstTreeInfo(root, configuration); + AstElementNode rootElt = treeInfo.getRootNode().getRootElement(); + + AstElementNode elementComment = rootElt.getChildren().get(0); + assertEquals("#comment", c1.getXPathNodeName()); + assertEquals(Type.COMMENT, elementComment.getNodeKind()); + assertSame(c1, elementComment.getUnderlyingNode()); + assertSame(elementComment, treeInfo.findWrapperFor(c1)); + } + } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java index 7ea30935b7..8b616459f6 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java @@ -9,7 +9,10 @@ import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.node; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.nodeB; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.root; import static net.sourceforge.pmd.lang.ast.impl.DummyTreeUtil.tree; -import static org.junit.Assert.assertEquals; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.HashMap; import java.util.List; @@ -17,10 +20,7 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.NonNull; import org.hamcrest.CoreMatchers; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; import net.sourceforge.pmd.lang.ast.DummyNodeWithListAndEnum; @@ -41,14 +41,11 @@ import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.BooleanValue; import net.sf.saxon.value.SequenceType; -public class SaxonXPathRuleQueryTest { - - @Rule - public final ExpectedException expected = ExpectedException.none(); +class SaxonXPathRuleQueryTest { // Unsupported: https://github.com/pmd/pmd/issues/2451 // @Test - // public void testListAttribute() { + // void testListAttribute() { // RootNode dummy = new DummyNodeWithListAndEnum(); // // assertQuery(1, "//dummyNode[@List = \"A\"]", dummy); @@ -63,7 +60,7 @@ public class SaxonXPathRuleQueryTest { // } @Test - public void testHigherOrderFuns() { // XPath 3.1 + void testHigherOrderFuns() { // XPath 3.1 DummyRootNode tree = tree(() -> root( node() )); @@ -91,7 +88,7 @@ public class SaxonXPathRuleQueryTest { } @Test - public void testListProperty() { + void testListProperty() { RootNode dummy = new DummyNodeWithListAndEnum(); PropertyDescriptor> prop = PropertyFactory.stringListProperty("prop") @@ -103,51 +100,50 @@ public class SaxonXPathRuleQueryTest { } @Test - public void testInvalidReturn() { + void testInvalidReturn() { DummyNodeWithListAndEnum dummy = new DummyNodeWithListAndEnum(); - - expected.expect(PmdXPathException.class); - expected.expectMessage(CoreMatchers.containsString("XPath rule expression returned a non-node")); - expected.expectMessage(CoreMatchers.containsString("Int64Value")); - - createQuery("1+2").evaluate(dummy); + PmdXPathException exception = assertThrows(PmdXPathException.class, () -> { + createQuery("1+2").evaluate(dummy); + }); + assertThat(exception.getMessage(), CoreMatchers.containsString("XPath rule expression returned a non-node")); + assertThat(exception.getMessage(), CoreMatchers.containsString("Int64Value")); } @Test - public void testRootExpression() { + void testRootExpression() { DummyRootNode dummy = new DummyRootNode(); List result = assertQuery(1, "/", dummy); - Assert.assertEquals(dummy, result.get(0)); + assertEquals(dummy, result.get(0)); } @Test - public void testRootExpressionIsADocumentNode() { + void testRootExpressionIsADocumentNode() { DummyRootNode dummy = new DummyRootNode(); List result = assertQuery(1, "(/)[self::document-node()]", dummy); - Assert.assertEquals(dummy, result.get(0)); + assertEquals(dummy, result.get(0)); } @Test - public void testRootExpressionWithName() { + void testRootExpressionWithName() { DummyRootNode dummy = new DummyRootNode(); String xpathName = dummy.getXPathNodeName(); List result = assertQuery(1, "(/)[self::document-node(element(" + xpathName + "))]", dummy); - Assert.assertEquals(dummy, result.get(0)); + assertEquals(dummy, result.get(0)); assertQuery(0, "(/)[self::document-node(element(DummyNodeX))]", dummy); } @Test - public void ruleChainVisits() { + void ruleChainVisits() { SaxonXPathRuleQuery query = createQuery("//dummyNode[@Image='baz']/foo | //bar[@Public = 'true'] | //dummyNode[@Public = false()] | //dummyNode"); List ruleChainVisits = query.getRuleChainVisits(); assertEquals(2, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertTrue(ruleChainVisits.contains("bar")); + assertTrue(ruleChainVisits.contains("dummyNode")); + assertTrue(ruleChainVisits.contains("bar")); assertEquals(3, query.nodeNameToXPaths.size()); assertExpression("(self::node()[(string(data(@Image))) eq \"baz\"])/child::element(foo)", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); @@ -158,22 +154,22 @@ public class SaxonXPathRuleQueryTest { } @Test - public void ruleChainVisitsMultipleFilters() { + void ruleChainVisitsMultipleFilters() { SaxonXPathRuleQuery query = createQuery("//dummyNode[@Test1 = false()][@Test2 = true()]"); List ruleChainVisits = query.getRuleChainVisits(); assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertTrue(ruleChainVisits.contains("dummyNode")); assertEquals(2, query.nodeNameToXPaths.size()); assertExpression("(self::node()[(boolean(data(@Test1))) eq false()])[(boolean(data(@Test2))) eq true()]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); assertExpression("(((/)/descendant::element(dummyNode))[(boolean(data(@Test1))) eq false()])[(boolean(data(@Test2))) eq true()]", query.getFallbackExpr()); } @Test - public void ruleChainVisitsCustomFunctions() { + void ruleChainVisitsCustomFunctions() { SaxonXPathRuleQuery query = createQuery("//dummyNode[pmd-dummy:imageIs(@Image)]"); List ruleChainVisits = query.getRuleChainVisits(); assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertTrue(ruleChainVisits.contains("dummyNode")); assertEquals(2, query.nodeNameToXPaths.size()); assertExpression("self::node()[Q{http://pmd.sourceforge.net/pmd-dummy}imageIs(exactly-one(convertUntyped(data(@Image))))]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); assertExpression("((/)/descendant::element(Q{}dummyNode))[Q{http://pmd.sourceforge.net/pmd-dummy}imageIs(exactly-one(convertUntyped(data(@Image))))]", query.getFallbackExpr()); @@ -184,7 +180,7 @@ public class SaxonXPathRuleQueryTest { * excluded from rule chain execution. Saxon itself optimizes this quite good already. */ @Test - public void ruleChainVisitsUnboundedPathExpressions() { + void ruleChainVisitsUnboundedPathExpressions() { SaxonXPathRuleQuery query = createQuery("//dummyNode[//ClassOrInterfaceType]"); List ruleChainVisits = query.getRuleChainVisits(); assertEquals(0, ruleChainVisits.size()); @@ -207,29 +203,29 @@ public class SaxonXPathRuleQueryTest { } @Test - public void ruleChainVisitsNested() { + void ruleChainVisitsNested() { SaxonXPathRuleQuery query = createQuery("//dummyNode/foo/*/bar[@Test = 'false']"); List ruleChainVisits = query.getRuleChainVisits(); assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertTrue(ruleChainVisits.contains("dummyNode")); assertEquals(2, query.nodeNameToXPaths.size()); assertExpression("(((self::node()/child::element(foo))/child::element())/child::element(bar))[(string(data(@Test))) eq \"false\"]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); assertExpression("docOrder(((docOrder((((/)/descendant::element(dummyNode))/child::element(foo))/child::element()))/child::element(bar))[(string(data(@Test))) eq \"false\"])", query.getFallbackExpr()); } @Test - public void ruleChainVisitsNested2() { + void ruleChainVisitsNested2() { SaxonXPathRuleQuery query = createQuery("//dummyNode/foo[@Baz = 'a']/*/bar[@Test = 'false']"); List ruleChainVisits = query.getRuleChainVisits(); assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertTrue(ruleChainVisits.contains("dummyNode")); assertEquals(2, query.nodeNameToXPaths.size()); assertExpression("((((self::node()/child::element(foo))[(string(data(@Baz))) eq \"a\"])/child::element())/child::element(bar))[(string(data(@Test))) eq \"false\"]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); assertExpression("docOrder(((docOrder(((((/)/descendant::element(dummyNode))/child::element(foo))[(string(data(@Baz))) eq \"a\"])/child::element()))/child::element(bar))[(string(data(@Test))) eq \"false\"])", query.getFallbackExpr()); } @Test - public void unionBeforeSlash() { + void unionBeforeSlash() { SaxonXPathRuleQuery query = createQuery("(//dummyNode | //dummyNodeB)/dummyNode[@Image = '10']"); DummyRootNode tree = tree(() -> root( @@ -251,7 +247,7 @@ public class SaxonXPathRuleQueryTest { } @Test - public void unionBeforeSlashWithFilter() { + void unionBeforeSlashWithFilter() { SaxonXPathRuleQuery query = createQuery("(//dummyNode[@Image='0'] | //dummyNodeB[@Image='1'])/dummyNode[@Image = '10']"); DummyRootNode tree = tree(() -> root( @@ -274,7 +270,7 @@ public class SaxonXPathRuleQueryTest { } @Test - public void unionBeforeSlashDeeper() { + void unionBeforeSlashDeeper() { SaxonXPathRuleQuery query = createQuery("(//dummyNode | //dummyNodeB)/dummyNode/dummyNode"); DummyRootNode tree = tree(() -> root( @@ -299,77 +295,77 @@ public class SaxonXPathRuleQueryTest { } @Test - public void ruleChainVisitWithVariable() { + void ruleChainVisitWithVariable() { PropertyDescriptor testClassPattern = PropertyFactory.stringProperty("testClassPattern").desc("test").defaultValue("a").build(); SaxonXPathRuleQuery query = createQuery("//dummyNode[matches(@SimpleName, $testClassPattern)]", testClassPattern); List ruleChainVisits = query.getRuleChainVisits(); assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertTrue(ruleChainVisits.contains("dummyNode")); assertEquals(2, query.nodeNameToXPaths.size()); assertExpression("self::node()[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")]", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); assertExpression("((/)/descendant::element(Q{}dummyNode))[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")]", query.getFallbackExpr()); } @Test - public void ruleChainVisitWithVariable2() { + void ruleChainVisitWithVariable2() { PropertyDescriptor testClassPattern = PropertyFactory.stringProperty("testClassPattern").desc("test").defaultValue("a").build(); SaxonXPathRuleQuery query = createQuery("//dummyNode[matches(@SimpleName, $testClassPattern)]/foo", testClassPattern); List ruleChainVisits = query.getRuleChainVisits(); assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); + assertTrue(ruleChainVisits.contains("dummyNode")); assertEquals(2, query.nodeNameToXPaths.size()); assertExpression("(self::node()[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")])/child::element(Q{}foo)", query.getExpressionsForLocalNameOrDefault("dummyNode").get(0)); assertExpression("docOrder((((/)/descendant::element(Q{}dummyNode))[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")])/child::element(Q{}foo))", query.getFallbackExpr()); } @Test - public void ruleChainVisitWithTwoFunctions() { + void ruleChainVisitWithTwoFunctions() { SaxonXPathRuleQuery query = createQuery("//dummyNode[ends-with(@Image, 'foo')][pmd-dummy:imageIs('bar')]"); List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(1, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("dummyNode")); - Assert.assertEquals(2, query.nodeNameToXPaths.size()); + assertEquals(1, ruleChainVisits.size()); + assertTrue(ruleChainVisits.contains("dummyNode")); + assertEquals(2, query.nodeNameToXPaths.size()); assertExpression("let $v0 := imageIs(\"bar\") return ((self::node()[ends-with(convertUntyped(data(@Image)), \"foo\")])[$v0])", query.nodeNameToXPaths.get("dummyNode").get(0)); } @Test - public void ruleChainWithUnions() { + void ruleChainWithUnions() { SaxonXPathRuleQuery query = createQuery("(//ForStatement | //WhileStatement | //DoStatement)//AssignmentOperator"); List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); + assertEquals(0, ruleChainVisits.size()); } @Test - public void ruleChainWithUnionsAndFilter() { + void ruleChainWithUnionsAndFilter() { SaxonXPathRuleQuery query = createQuery("(//ForStatement | //WhileStatement | //DoStatement)//AssignmentOperator[@Image='foo']"); List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); + assertEquals(0, ruleChainVisits.size()); } @Test - public void ruleChainWithUnionsCustomFunctionsVariant1() { + void ruleChainWithUnionsCustomFunctionsVariant1() { SaxonXPathRuleQuery query = createQuery("(//ForStatement | //WhileStatement | //DoStatement)//dummyNode[pmd-dummy:imageIs(@Image)]"); List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); + assertEquals(0, ruleChainVisits.size()); } @Test - public void ruleChainWithUnionsCustomFunctionsVariant2() { + void ruleChainWithUnionsCustomFunctionsVariant2() { SaxonXPathRuleQuery query = createQuery("//(ForStatement | WhileStatement | DoStatement)//dummyNode[pmd-dummy:imageIs(@Image)]"); List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(0, ruleChainVisits.size()); + assertEquals(0, ruleChainVisits.size()); } @Test - public void ruleChainWithUnionsCustomFunctionsVariant3() { + void ruleChainWithUnionsCustomFunctionsVariant3() { SaxonXPathRuleQuery query = createQuery("//ForStatement//dummyNode[pmd-dummy:imageIs(@Image)]" + " | //WhileStatement//dummyNode[pmd-dummy:imageIs(@Image)]" + " | //DoStatement//dummyNode[pmd-dummy:imageIs(@Image)]"); List ruleChainVisits = query.getRuleChainVisits(); - Assert.assertEquals(3, ruleChainVisits.size()); - Assert.assertTrue(ruleChainVisits.contains("ForStatement")); - Assert.assertTrue(ruleChainVisits.contains("WhileStatement")); - Assert.assertTrue(ruleChainVisits.contains("DoStatement")); + assertEquals(3, ruleChainVisits.size()); + assertTrue(ruleChainVisits.contains("ForStatement")); + assertTrue(ruleChainVisits.contains("WhileStatement")); + assertTrue(ruleChainVisits.contains("DoStatement")); final String expectedSubexpression = "(self::node()/descendant::element(dummyNode))[imageIs(exactly-one(convertUntyped(data(@Image))))]"; assertExpression(expectedSubexpression, query.nodeNameToXPaths.get("ForStatement").get(0)); @@ -392,7 +388,7 @@ public class SaxonXPathRuleQueryTest { private static List assertQuery(int resultSize, String xpath, Node node, PropertyDescriptor... descriptors) { SaxonXPathRuleQuery query = createQuery(xpath, descriptors); List result = query.evaluate(node); - assertEquals("Wrong number of matched nodes", resultSize, result.size()); + assertEquals(resultSize, result.size(), "Wrong number of matched nodes"); return result; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/symboltable/ApplierTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/symboltable/ApplierTest.java index 934ab5edb0..4f27b55170 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/symboltable/ApplierTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/symboltable/ApplierTest.java @@ -4,15 +4,15 @@ package net.sourceforge.pmd.lang.symboltable; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; -import org.junit.Test; +import org.junit.jupiter.api.Test; -public class ApplierTest { +class ApplierTest { private static class MyFunction implements Predicate { private int numCallbacks = 0; @@ -34,7 +34,7 @@ public class ApplierTest { } @Test - public void testSimple() { + void testSimple() { MyFunction f = new MyFunction(Integer.MAX_VALUE); List l = new ArrayList<>(); l.add(new Object()); @@ -45,7 +45,7 @@ public class ApplierTest { } @Test - public void testLimit() { + void testLimit() { MyFunction f = new MyFunction(2); List l = new ArrayList<>(); l.add(new Object()); @@ -54,8 +54,4 @@ public class ApplierTest { Applier.apply(f, l.iterator()); assertEquals(2, f.getNumCallbacks()); } - - public static junit.framework.Test suite() { - return new junit.framework.JUnit4TestAdapter(ApplierTest.class); - } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/processor/GlobalListenerTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/processor/GlobalListenerTest.java index 6fb5310330..9fcebd99ed 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/processor/GlobalListenerTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/processor/GlobalListenerTest.java @@ -4,8 +4,8 @@ package net.sourceforge.pmd.processor; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThrows; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -13,7 +13,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.checkerframework.checker.nullness.qual.NonNull; -import org.junit.Test; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import net.sourceforge.pmd.FooRule; @@ -29,12 +29,12 @@ import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; import net.sourceforge.pmd.reporting.GlobalAnalysisListener.ViolationCounterListener; -public class GlobalListenerTest { +class GlobalListenerTest { static final int NUM_DATA_SOURCES = 3; @Test - public void testViolationCounter() throws Exception { + void testViolationCounter() throws Exception { PMDConfiguration config = newConfig(); @@ -49,7 +49,7 @@ public class GlobalListenerTest { } @Test - public void testViolationCounterOnMulti() throws Exception { + void testViolationCounterOnMulti() throws Exception { PMDConfiguration config = newConfig(); config.setThreads(2); @@ -67,7 +67,7 @@ public class GlobalListenerTest { } @Test - public void testAnalysisCache() throws Exception { + void testAnalysisCache() throws Exception { PMDConfiguration config = newConfig(); AnalysisCache mockCache = spy(NoopAnalysisCache.class); @@ -82,7 +82,7 @@ public class GlobalListenerTest { } @Test - public void testCacheWithFailure() throws Exception { + void testCacheWithFailure() throws Exception { PMDConfiguration config = newConfig(); AnalysisCache mockCache = spy(NoopAnalysisCache.class); @@ -98,7 +98,7 @@ public class GlobalListenerTest { } @Test - public void testCacheWithPropagatedException() throws Exception { + void testCacheWithPropagatedException() throws Exception { PMDConfiguration config = newConfig(); AnalysisCache mockCache = spy(NoopAnalysisCache.class); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java index 6ce9253ac8..4211a38698 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/processor/MultiThreadProcessorTest.java @@ -5,12 +5,12 @@ package net.sourceforge.pmd.processor; import static net.sourceforge.pmd.util.CollectionUtil.listOf; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.Report.GlobalReportBuilderListener; @@ -26,7 +26,7 @@ import net.sourceforge.pmd.lang.rule.AbstractRule; import net.sourceforge.pmd.reporting.FileAnalysisListener; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; -public class MultiThreadProcessorTest { +class MultiThreadProcessorTest { private GlobalAnalysisListener listener; @@ -34,7 +34,7 @@ public class MultiThreadProcessorTest { private SimpleReportListener reportListener; private PMDConfiguration configuration; - public RuleSets setUpForTest(final String ruleset) { + RuleSets setUpForTest(final String ruleset) { configuration = new PMDConfiguration(); configuration.setThreads(2); LanguageVersion lv = LanguageRegistry.getDefaultLanguage().getDefaultVersion(); @@ -55,7 +55,7 @@ public class MultiThreadProcessorTest { // Dysfunctional rules are pruned upstream of the processor. // // @Test - // public void testRulesDysnfunctionalLog() throws Exception { + // void testRulesDysnfunctionalLog() throws Exception { // RuleSets ruleSets = setUpForTest("rulesets/MultiThreadProcessorTest/dysfunctional.xml"); // final SimpleRenderer renderer = new SimpleRenderer(null, null); // renderer.start(); @@ -65,15 +65,15 @@ public class MultiThreadProcessorTest { // final Iterator configErrors = renderer.getReport().getConfigurationErrors().iterator(); // final ConfigurationError error = configErrors.next(); // - // Assert.assertEquals("Dysfunctional rule message not present", + // assertEquals("Dysfunctional rule message not present", // DysfunctionalRule.DYSFUNCTIONAL_RULE_REASON, error.issue()); - // Assert.assertEquals("Dysfunctional rule is wrong", + // assertEquals("Dysfunctional rule is wrong", // DysfunctionalRule.class, error.rule().getClass()); - // Assert.assertFalse("More configuration errors found than expected", configErrors.hasNext()); + // assertFalse("More configuration errors found than expected", configErrors.hasNext()); // } @Test - public void testRulesThreadSafety() throws Exception { + void testRulesThreadSafety() throws Exception { RuleSets ruleSets = setUpForTest("rulesets/MultiThreadProcessorTest/basic.xml"); try (AbstractPMDProcessor processor = AbstractPMDProcessor.newFileProcessor(configuration)) { processor.processFiles(ruleSets, files, listener); @@ -82,10 +82,10 @@ public class MultiThreadProcessorTest { // if the rule is not executed, then maybe a // ConcurrentModificationException happened - Assert.assertEquals("Test rule has not been executed", 2, NotThreadSafeRule.count.get()); + assertEquals(2, NotThreadSafeRule.count.get(), "Test rule has not been executed"); // if the violation is not reported, then the rule instances have been // shared between the threads - Assert.assertEquals("Missing violation", 1, reportListener.violations.get()); + assertEquals(1, reportListener.violations.get(), "Missing violation"); } public static class NotThreadSafeRule extends AbstractRule { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/processor/PmdRunnableTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/processor/PmdRunnableTest.java index 5847cd35ec..400a217104 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/processor/PmdRunnableTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/processor/PmdRunnableTest.java @@ -7,20 +7,21 @@ package net.sourceforge.pmd.processor; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.Mockito.contains; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.util.List; +import java.util.function.BiConsumer; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; -import org.junit.rules.TestRule; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mockito; import org.slf4j.event.Level; @@ -35,36 +36,35 @@ import net.sourceforge.pmd.RuleSets; import net.sourceforge.pmd.internal.SystemProps; import net.sourceforge.pmd.internal.util.ContextedAssertionError; import net.sourceforge.pmd.lang.DummyLanguageModule; +import net.sourceforge.pmd.lang.DummyLanguageModule.Handler; import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.ast.Parser; +import net.sourceforge.pmd.lang.ast.RootNode; import net.sourceforge.pmd.lang.document.TextFile; import net.sourceforge.pmd.lang.rule.AbstractRule; import net.sourceforge.pmd.processor.MonoThreadProcessor.MonothreadRunnable; import net.sourceforge.pmd.util.log.MessageReporter; +import com.github.stefanbirkner.systemlambda.SystemLambda; + public class PmdRunnableTest { - @org.junit.Rule - public TestRule restoreSystemProperties = new RestoreSystemProperties(); + public static final String TEST_MESSAGE_SEMANTIC_ERROR = "An error occurred!"; + private static final String PARSER_REPORTS_SEMANTIC_ERROR = "1.9-semantic_error"; + private static final String THROWS_SEMANTIC_ERROR = "1.9-throws_semantic_error"; + private static final String THROWS_ASSERTION_ERROR = "1.9-throws"; - private LanguageVersion dummyThrows; - private LanguageVersion dummyDefault; - private LanguageVersion dummySemanticError; private PMDConfiguration configuration; private PmdRunnable pmdRunnable; private MessageReporter reporter; private Rule rule; - @Before + @BeforeEach public void prepare() { - Language dummyLanguage = LanguageRegistry.findLanguageByTerseName(DummyLanguageModule.TERSE_NAME); - dummyDefault = dummyLanguage.getDefaultVersion(); - dummyThrows = dummyLanguage.getVersion("1.9-throws"); - dummySemanticError = dummyLanguage.getVersion("1.9-semantic_error"); - // reset data rule = spy(new RuleThatThrows()); configuration = new PMDConfiguration(); @@ -92,47 +92,84 @@ public class PmdRunnableTest { } @Test - public void inErrorRecoveryModeErrorsShouldBeLoggedByParser() { - System.setProperty(SystemProps.PMD_ERROR_RECOVERY, ""); + public void inErrorRecoveryModeErrorsShouldBeLoggedByParser() throws Exception { + SystemLambda.restoreSystemProperties(() -> { + System.setProperty(SystemProps.PMD_ERROR_RECOVERY, ""); - Report report = process(dummyThrows); + Report report = process(versionWithParserThatThrowsAssertionError()); - Assert.assertEquals(1, report.getProcessingErrors().size()); + assertEquals(1, report.getProcessingErrors().size()); + }); } @Test - public void inErrorRecoveryModeErrorsShouldBeLoggedByRule() { - System.setProperty(SystemProps.PMD_ERROR_RECOVERY, ""); + public void inErrorRecoveryModeErrorsShouldBeLoggedByRule() throws Exception { + SystemLambda.restoreSystemProperties(() -> { + System.setProperty(SystemProps.PMD_ERROR_RECOVERY, ""); - Report report = process(dummyDefault); + Report report = process(DummyLanguageModule.getInstance().getDefaultVersion()); + + List errors = report.getProcessingErrors(); + assertThat(errors, hasSize(1)); + assertThat(errors.get(0).getError(), instanceOf(ContextedAssertionError.class)); + }); - List errors = report.getProcessingErrors(); - assertThat(errors, hasSize(1)); - assertThat(errors.get(0).getError(), instanceOf(ContextedAssertionError.class)); } @Test - public void withoutErrorRecoveryModeProcessingShouldBeAbortedByParser() { - Assert.assertNull(System.getProperty(SystemProps.PMD_ERROR_RECOVERY)); - - Assert.assertThrows(AssertionError.class, () -> process(dummyThrows)); + public void withoutErrorRecoveryModeProcessingShouldBeAbortedByParser() throws Exception { + SystemLambda.restoreSystemProperties(() -> { + System.clearProperty(SystemProps.PMD_ERROR_RECOVERY); + assertThrows(AssertionError.class, () -> process(versionWithParserThatThrowsAssertionError())); + }); } @Test - public void withoutErrorRecoveryModeProcessingShouldBeAbortedByRule() { - Assert.assertNull(System.getProperty(SystemProps.PMD_ERROR_RECOVERY)); - - - Assert.assertThrows(AssertionError.class, () -> process(dummyDefault)); + public void withoutErrorRecoveryModeProcessingShouldBeAbortedByRule() throws Exception { + SystemLambda.restoreSystemProperties(() -> { + System.clearProperty(SystemProps.PMD_ERROR_RECOVERY); + assertThrows(AssertionError.class, () -> process(DummyLanguageModule.getInstance().getDefaultVersion())); + }); } @Test public void semanticErrorShouldAbortTheRun() { - process(dummySemanticError); + Report report = process(versionWithParserThatReportsSemanticError()); - verify(reporter).log(eq(Level.INFO), contains("skipping rule analysis")); + verify(reporter, times(1)) + .log(eq(Level.ERROR), eq("at !debug only! test.dummy:1:1: " + TEST_MESSAGE_SEMANTIC_ERROR)); verify(rule, never()).apply(Mockito.any(), Mockito.any()); + + assertEquals(1, report.getProcessingErrors().size()); + } + + @Test + public void semanticErrorThrownShouldAbortTheRun() { + Report report = process(getVersionWithParserThatThrowsSemanticError()); + + verify(reporter, times(1)).log(eq(Level.ERROR), contains(TEST_MESSAGE_SEMANTIC_ERROR)); + verify(rule, never()).apply(Mockito.any(), Mockito.any()); + + assertEquals(1, report.getProcessingErrors().size()); + } + + public static void registerCustomVersions(BiConsumer addVersion) { + addVersion.accept(THROWS_ASSERTION_ERROR, new HandlerWithParserThatThrows()); + addVersion.accept(PARSER_REPORTS_SEMANTIC_ERROR, new HandlerWithParserThatReportsSemanticError()); + addVersion.accept(THROWS_SEMANTIC_ERROR, new HandlerWithParserThatThrowsSemanticError()); + } + + public static LanguageVersion versionWithParserThatThrowsAssertionError() { + return DummyLanguageModule.getInstance().getVersion(THROWS_ASSERTION_ERROR); + } + + public static LanguageVersion getVersionWithParserThatThrowsSemanticError() { + return DummyLanguageModule.getInstance().getVersion(THROWS_SEMANTIC_ERROR); + } + + public static LanguageVersion versionWithParserThatReportsSemanticError() { + return DummyLanguageModule.getInstance().getVersion(PARSER_REPORTS_SEMANTIC_ERROR); } private static class RuleThatThrows extends AbstractRule { @@ -147,4 +184,37 @@ public class PmdRunnableTest { throw new AssertionError("test"); } } + + public static class HandlerWithParserThatThrowsSemanticError extends Handler { + + @Override + public Parser getParser() { + return task -> { + RootNode root = super.getParser().parse(task); + throw task.getReporter().error(root, TEST_MESSAGE_SEMANTIC_ERROR); + }; + } + } + + public static class HandlerWithParserThatThrows extends Handler { + + @Override + public Parser getParser() { + return task -> { + throw new AssertionError("test error while parsing"); + }; + } + } + + public static class HandlerWithParserThatReportsSemanticError extends Handler { + + @Override + public Parser getParser() { + return task -> { + RootNode root = super.getParser().parse(task); + task.getReporter().error(root, TEST_MESSAGE_SEMANTIC_ERROR); + return root; + }; + } + } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractNumericPropertyDescriptorTester.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractNumericPropertyDescriptorTester.java index c9a880f5dc..b2f20bdfa5 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractNumericPropertyDescriptorTester.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractNumericPropertyDescriptorTester.java @@ -4,11 +4,12 @@ package net.sourceforge.pmd.properties; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.properties.builders.MultiNumericPropertyBuilder; import net.sourceforge.pmd.properties.builders.SingleNumericPropertyBuilder; @@ -17,15 +18,15 @@ import net.sourceforge.pmd.properties.builders.SingleNumericPropertyBuilder; /** * @author Clรฉment Fournier */ -public abstract class AbstractNumericPropertyDescriptorTester extends AbstractPropertyDescriptorTester { +abstract class AbstractNumericPropertyDescriptorTester extends AbstractPropertyDescriptorTester { - public AbstractNumericPropertyDescriptorTester(String typeName) { + AbstractNumericPropertyDescriptorTester(String typeName) { super(typeName); } @Test - public void testLowerUpperLimit() { + void testLowerUpperLimit() { assertNotNull(((NumericPropertyDescriptor) createProperty()).lowerLimit()); assertNotNull(((NumericPropertyDescriptor) createProperty()).upperLimit()); assertNotNull(((NumericPropertyDescriptor) createMultiProperty()).lowerLimit()); @@ -33,11 +34,11 @@ public abstract class AbstractNumericPropertyDescriptorTester extends Abstrac } - @Test(expected = RuntimeException.class) - public void testMissingMinThreshold() { + @Test + void testMissingMinThreshold() { Map attributes = getPropertyDescriptorValues(); attributes.remove(PropertyDescriptorField.MIN); - getSingleFactory().build(attributes); + assertThrows(RuntimeException.class, () -> getSingleFactory().build(attributes)); } @@ -50,25 +51,24 @@ public abstract class AbstractNumericPropertyDescriptorTester extends Abstrac } - @Test(expected = RuntimeException.class) - public void testMissingMaxThreshold() { + @Test + void testMissingMaxThreshold() { Map attributes = getPropertyDescriptorValues(); attributes.remove(PropertyDescriptorField.MAX); - getSingleFactory().build(attributes); - + assertThrows(RuntimeException.class, () -> getSingleFactory().build(attributes)); } - @Test(expected = IllegalArgumentException.class) - public void testBadDefaultValue() { - singleBuilder().defaultValue(createBadValue()).build(); + @Test + void testBadDefaultValue() { + assertThrows(IllegalArgumentException.class, () -> singleBuilder().defaultValue(createBadValue()).build()); } - @Test(expected = IllegalArgumentException.class) + @Test @SuppressWarnings("unchecked") - public void testMultiBadDefaultValue() { - multiBuilder().defaultValues(createValue(), createBadValue()).build(); + void testMultiBadDefaultValue() { + assertThrows(IllegalArgumentException.class, () -> multiBuilder().defaultValues(createValue(), createBadValue()).build()); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPackagedPropertyDescriptorTester.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPackagedPropertyDescriptorTester.java index 7190685b38..31a97b0f34 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPackagedPropertyDescriptorTester.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPackagedPropertyDescriptorTester.java @@ -6,12 +6,12 @@ package net.sourceforge.pmd.properties; import java.util.Map; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * @author Clรฉment Fournier */ -public abstract class AbstractPackagedPropertyDescriptorTester extends AbstractPropertyDescriptorTester { +abstract class AbstractPackagedPropertyDescriptorTester extends AbstractPropertyDescriptorTester { /* default */ AbstractPackagedPropertyDescriptorTester(String typeName) { super(typeName); @@ -19,7 +19,7 @@ public abstract class AbstractPackagedPropertyDescriptorTester extends Abstra @Test - public void testMissingPackageNames() { + void testMissingPackageNames() { Map attributes = getPropertyDescriptorValues(); attributes.remove(PropertyDescriptorField.LEGAL_PACKAGES); getMultiFactory().build(attributes); // no exception, null is ok diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPropertyDescriptorTester.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPropertyDescriptorTester.java index b80e16d8e5..ea7fe49b7c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPropertyDescriptorTester.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/AbstractPropertyDescriptorTester.java @@ -4,12 +4,12 @@ package net.sourceforge.pmd.properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.ArrayList; import java.util.HashMap; @@ -18,7 +18,7 @@ import java.util.Map; import java.util.Random; import java.util.regex.Pattern; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.properties.builders.PropertyDescriptorExternalBuilder; @@ -29,7 +29,7 @@ import net.sourceforge.pmd.properties.builders.PropertyDescriptorExternalBuilder * * @author Brian Remedios */ -public abstract class AbstractPropertyDescriptorTester { +abstract class AbstractPropertyDescriptorTester { public static final String PUNCTUATION_CHARS = "!@#$%^&*()_-+=[]{}\\|;:'\",.<>/?`~"; public static final String WHITESPACE_CHARS = " \t\n"; @@ -44,7 +44,7 @@ public abstract class AbstractPropertyDescriptorTester { protected final String typeName; - public AbstractPropertyDescriptorTester(String typeName) { + AbstractPropertyDescriptorTester(String typeName) { this.typeName = typeName; } @@ -53,7 +53,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testFactorySingleValue() { + void testFactorySingleValue() { PropertyDescriptor prop = getSingleFactory().build(getPropertyDescriptorValues()); T originalValue = createValue(); T value = prop.valueFrom(originalValue instanceof Class ? ((Class) originalValue).getName() : String.valueOf(originalValue)); @@ -92,7 +92,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testFactoryMultiValueDefaultDelimiter() { + void testFactoryMultiValueDefaultDelimiter() { PropertyDescriptorExternalBuilder> multiFactory = getMultiFactory(); PropertyDescriptor> prop = multiFactory.build(getPropertyDescriptorValues()); List originalValue = createMultipleValues(MULTI_VALUE_COUNT); @@ -119,7 +119,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testFactoryMultiValueCustomDelimiter() { + void testFactoryMultiValueCustomDelimiter() { PropertyDescriptorExternalBuilder> multiFactory = getMultiFactory(); Map valuesById = getPropertyDescriptorValues(); String customDelimiter = "รค"; @@ -135,18 +135,10 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testConstructors() { - + void testConstructors() { PropertyDescriptor desc = createProperty(); assertNotNull(desc); - - try { - createBadProperty(); - } catch (Exception ex) { - return; // caught ok - } - - fail("uncaught constructor exception"); + assertThrows(Exception.class, () -> createBadProperty()); } @@ -168,7 +160,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testAsDelimitedString() { + void testAsDelimitedString() { List testValue = createMultipleValues(MULTI_VALUE_COUNT); PropertyDescriptor> pmdProp = createMultiProperty(); @@ -184,7 +176,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testValueFrom() { + void testValueFrom() { T testValue = createValue(); PropertyDescriptor pmdProp = createProperty(); @@ -204,7 +196,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testErrorForCorrectSingle() { + void testErrorForCorrectSingle() { T testValue = createValue(); PropertyDescriptor pmdProp = createProperty(); // plain vanilla // property & valid test value @@ -214,7 +206,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testErrorForCorrectMulti() { + void testErrorForCorrectMulti() { List testMultiValues = createMultipleValues(MULTI_VALUE_COUNT); // multi-value property, all // valid test values PropertyDescriptor> multiProperty = createMultiProperty(); @@ -225,7 +217,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testErrorForBadSingle() { + void testErrorForBadSingle() { T testValue = createBadValue(); PropertyDescriptor pmdProp = createProperty(); // plain vanilla // property & valid test value @@ -243,12 +235,12 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testErrorForBadMulti() { + void testErrorForBadMulti() { List testMultiValues = createMultipleBadValues(MULTI_VALUE_COUNT); // multi-value property, all // valid test values PropertyDescriptor> multiProperty = createMultiProperty(); String errorMsg = multiProperty.errorFor(testMultiValues); - assertNotNull("uncaught bad value in: " + testMultiValues, errorMsg); + assertNotNull(errorMsg, "uncaught bad value in: " + testMultiValues); } @@ -263,18 +255,18 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testIsMultiValue() { + void testIsMultiValue() { assertFalse(createProperty().isMultiValue()); } @Test - public void testIsMultiValueMulti() { + void testIsMultiValueMulti() { assertTrue(createMultiProperty().isMultiValue()); } @Test - public void testAddAttributes() { + void testAddAttributes() { Map atts = createProperty().attributeValuesById(); assertTrue(atts.containsKey(PropertyDescriptorField.NAME)); assertTrue(atts.containsKey(PropertyDescriptorField.DESCRIPTION)); @@ -283,7 +275,7 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testAddAttributesMulti() { + void testAddAttributesMulti() { Map multiAtts = createMultiProperty().attributeValuesById(); assertTrue(multiAtts.containsKey(PropertyDescriptorField.DELIMITER)); assertTrue(multiAtts.containsKey(PropertyDescriptorField.NAME)); @@ -293,13 +285,13 @@ public abstract class AbstractPropertyDescriptorTester { @Test - public void testType() { + void testType() { assertNotNull(createProperty().type()); } @Test - public void testTypeMulti() { + void testTypeMulti() { assertNotNull(createMultiProperty().type()); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/BooleanPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/BooleanPropertyTest.java index 2e5cda931b..20ed012c7a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/BooleanPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/BooleanPropertyTest.java @@ -6,14 +6,14 @@ package net.sourceforge.pmd.properties; import java.util.List; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * @author Brian Remedios */ -public class BooleanPropertyTest extends AbstractPropertyDescriptorTester { +class BooleanPropertyTest extends AbstractPropertyDescriptorTester { - public BooleanPropertyTest() { + BooleanPropertyTest() { super("Boolean"); } @@ -26,14 +26,14 @@ public class BooleanPropertyTest extends AbstractPropertyDescriptorTester { +class CharacterPropertyTest extends AbstractPropertyDescriptorTester { private static final char DELIMITER = '|'; private static final char[] CHARSET = filter(ALL_CHARS.toCharArray(), DELIMITER); - public CharacterPropertyTest() { + CharacterPropertyTest() { super("Character"); } @Override @Test - public void testErrorForBadSingle() { + void testErrorForBadSingle() { } // not until char properties use illegal chars @Override @Test - public void testErrorForBadMulti() { + void testErrorForBadMulti() { } // not until char properties use illegal chars diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/DoublePropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/DoublePropertyTest.java index 9b24dc2d0b..038298d2a4 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/DoublePropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/DoublePropertyTest.java @@ -15,14 +15,14 @@ import java.util.List; * @author Brian Remedios */ @Deprecated -public class DoublePropertyTest extends AbstractNumericPropertyDescriptorTester { +class DoublePropertyTest extends AbstractNumericPropertyDescriptorTester { private static final double MIN = -10.0; private static final double MAX = 100.0; private static final double SHIFT = 5.0; - public DoublePropertyTest() { + DoublePropertyTest() { super("Double"); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/FloatPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/FloatPropertyTest.java index 4ebe325a7d..fdd922dce7 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/FloatPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/FloatPropertyTest.java @@ -15,14 +15,14 @@ import java.util.List; * * @author Brian Remedios */ -public class FloatPropertyTest extends AbstractNumericPropertyDescriptorTester { +class FloatPropertyTest extends AbstractNumericPropertyDescriptorTester { private static final float MIN = 1.0f; private static final float MAX = 11.0f; private static final float SHIFT = 3.0f; - public FloatPropertyTest() { + FloatPropertyTest() { super("Float"); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/IntegerPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/IntegerPropertyTest.java index 437bcfc422..b4c5dbf44f 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/IntegerPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/IntegerPropertyTest.java @@ -16,29 +16,18 @@ import java.util.List; * @author Brian Remedios */ @Deprecated -public class IntegerPropertyTest extends AbstractNumericPropertyDescriptorTester { +class IntegerPropertyTest extends AbstractNumericPropertyDescriptorTester { private static final int MIN = 1; private static final int MAX = 12; private static final int SHIFT = 4; - public IntegerPropertyTest() { + IntegerPropertyTest() { super("Integer"); } - /* @Override - @Test - public void testErrorForBadSingle() { - } // not until int properties get ranges - - @Override - @Test - public void testErrorForBadMulti() { - } // not until int properties get ranges - - */ @Override protected Integer createValue() { return randomInt(MIN, MAX); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/LongPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/LongPropertyTest.java index 878ec3f4c8..ad243c38c3 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/LongPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/LongPropertyTest.java @@ -11,14 +11,14 @@ import java.util.List; * @author Clรฉment Fournier */ @Deprecated -public class LongPropertyTest extends AbstractNumericPropertyDescriptorTester { +class LongPropertyTest extends AbstractNumericPropertyDescriptorTester { private static final long MIN = 10L; private static final long MAX = 11000L; private static final long SHIFT = 300L; - public LongPropertyTest() { + LongPropertyTest() { super("Long"); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java index e45799026d..e1e72f92fb 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/PropertyDescriptorTest.java @@ -9,8 +9,10 @@ import static net.sourceforge.pmd.properties.constraints.NumericConstraints.inRa import static net.sourceforge.pmd.util.CollectionUtil.listOf; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItem; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.ArrayList; import java.util.Arrays; @@ -26,8 +28,7 @@ import org.apache.commons.lang3.StringUtils; import org.hamcrest.Matcher; import org.hamcrest.Matchers; import org.hamcrest.core.SubstringMatcher; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.FooRule; import net.sourceforge.pmd.Rule; @@ -41,14 +42,10 @@ import net.sourceforge.pmd.properties.constraints.PropertyConstraint; * @author Clรฉment Fournier * @since 7.0.0 */ -public class PropertyDescriptorTest { - - @org.junit.Rule - public ExpectedException thrown = ExpectedException.none(); - +class PropertyDescriptorTest { @Test - public void testConstraintViolationCausesDysfunctionalRule() { + void testConstraintViolationCausesDysfunctionalRule() { PropertyDescriptor intProperty = PropertyFactory.intProperty("fooProp") .desc("hello") .defaultValue(4) @@ -69,7 +66,7 @@ public class PropertyDescriptorTest { @Test - public void testConstraintViolationCausesDysfunctionalRuleMulti() { + void testConstraintViolationCausesDysfunctionalRuleMulti() { PropertyDescriptor> descriptor = PropertyFactory.doubleListProperty("fooProp") .desc("hello") .defaultValues(2., 11.) // 11. is in range @@ -89,39 +86,37 @@ public class PropertyDescriptorTest { } @Test - public void testDefaultValueConstraintViolationCausesFailure() { + void testDefaultValueConstraintViolationCausesFailure() { PropertyConstraint constraint = inRange(1, 10); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(allOf(containsIgnoreCase("Constraint violat"/*-ed or -ion*/), - containsIgnoreCase(constraint.getConstraintDescription()))); - - PropertyFactory.intProperty("fooProp") - .desc("hello") - .defaultValue(1000) - .require(constraint) - .build(); + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + PropertyFactory.intProperty("fooProp") + .desc("hello") + .defaultValue(1000) + .require(constraint) + .build()); + assertThat(thrown.getMessage(), allOf(containsIgnoreCase("Constraint violat"/*-ed or -ion*/), + containsIgnoreCase(constraint.getConstraintDescription()))); } @Test - public void testDefaultValueConstraintViolationCausesFailureMulti() { + void testDefaultValueConstraintViolationCausesFailureMulti() { PropertyConstraint constraint = inRange(1d, 10d); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(allOf(containsIgnoreCase("Constraint violat"/*-ed or -ion*/), - containsIgnoreCase(constraint.getConstraintDescription()))); - - PropertyFactory.doubleListProperty("fooProp") - .desc("hello") - .defaultValues(2., 11.) // 11. is out of range - .requireEach(constraint) - .build(); + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + PropertyFactory.doubleListProperty("fooProp") + .desc("hello") + .defaultValues(2., 11.) // 11. is out of range + .requireEach(constraint) + .build()); + assertThat(thrown.getMessage(), allOf(containsIgnoreCase("Constraint violat"/*-ed or -ion*/), + containsIgnoreCase(constraint.getConstraintDescription()))); } @Test - public void testNoConstraintViolationCausesIsOkMulti() { + void testNoConstraintViolationCausesIsOkMulti() { PropertyDescriptor> descriptor = PropertyFactory.doubleListProperty("fooProp") .desc("hello") @@ -137,7 +132,7 @@ public class PropertyDescriptorTest { @Test - public void testNoConstraintViolationCausesIsOk() { + void testNoConstraintViolationCausesIsOk() { PropertyDescriptor descriptor = PropertyFactory.stringProperty("fooProp") .desc("hello") @@ -150,7 +145,7 @@ public class PropertyDescriptorTest { } @Test - public void testIntProperty() { + void testIntProperty() { PropertyDescriptor descriptor = PropertyFactory.intProperty("intProp") .desc("hello") .defaultValue(1) @@ -173,18 +168,19 @@ public class PropertyDescriptorTest { } @Test - public void testIntPropertyInvalidValue() { + void testIntPropertyInvalidValue() { PropertyDescriptor descriptor = PropertyFactory.intProperty("intProp") .desc("hello") .defaultValue(1) .build(); - thrown.expect(NumberFormatException.class); - thrown.expectMessage("not a number"); - descriptor.valueFrom("not a number"); + + NumberFormatException thrown = assertThrows(NumberFormatException.class, () -> + descriptor.valueFrom("not a number")); + assertThat(thrown.getMessage(), containsString("not a number")); } @Test - public void testDoubleProperty() { + void testDoubleProperty() { PropertyDescriptor descriptor = PropertyFactory.doubleProperty("doubleProp") .desc("hello") .defaultValue(1.0) @@ -207,18 +203,18 @@ public class PropertyDescriptorTest { } @Test - public void testDoublePropertyInvalidValue() { + void testDoublePropertyInvalidValue() { PropertyDescriptor descriptor = PropertyFactory.doubleProperty("doubleProp") .desc("hello") .defaultValue(1.0) .build(); - thrown.expect(NumberFormatException.class); - thrown.expectMessage("this is not a number"); - descriptor.valueFrom("this is not a number"); + NumberFormatException thrown = assertThrows(NumberFormatException.class, () -> + descriptor.valueFrom("this is not a number")); + assertThat(thrown.getMessage(), containsString("this is not a number")); } @Test - public void testStringProperty() { + void testStringProperty() { PropertyDescriptor descriptor = PropertyFactory.stringProperty("stringProp") .desc("hello") .defaultValue("default value") @@ -251,7 +247,7 @@ public class PropertyDescriptorTest { } @Test - public void testEnumProperty() { + void testEnumProperty() { PropertyDescriptor descriptor = PropertyFactory.enumProperty("enumProp", nameMap) .desc("hello") .defaultValue(SampleEnum.B) @@ -273,42 +269,41 @@ public class PropertyDescriptorTest { @Test - public void testEnumPropertyNullValueFailsBuild() { + void testEnumPropertyNullValueFailsBuild() { Map map = new HashMap<>(nameMap); map.put("TEST_NULL", null); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(containsIgnoreCase("null value")); - - PropertyFactory.enumProperty("enumProp", map); + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + PropertyFactory.enumProperty("enumProp", map)); + assertThat(thrown.getMessage(), containsIgnoreCase("null value")); } @Test - public void testEnumListPropertyNullValueFailsBuild() { + void testEnumListPropertyNullValueFailsBuild() { Map map = new HashMap<>(nameMap); map.put("TEST_NULL", null); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(containsIgnoreCase("null value")); - - PropertyFactory.enumListProperty("enumProp", map); + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + PropertyFactory.enumListProperty("enumProp", map)); + assertThat(thrown.getMessage(), containsIgnoreCase("null value")); } @Test - public void testEnumPropertyInvalidValue() { + void testEnumPropertyInvalidValue() { PropertyDescriptor descriptor = PropertyFactory.enumProperty("enumProp", nameMap) .desc("hello") .defaultValue(SampleEnum.B) .build(); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Value was not in the set [TEST_A, TEST_B, TEST_C]"); - descriptor.valueFrom("InvalidEnumValue"); + + IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, () -> + descriptor.valueFrom("InvalidEnumValue")); + assertThat(thrown.getMessage(), containsString("Value was not in the set [TEST_A, TEST_B, TEST_C]")); } @Test - public void testRegexProperty() { + void testRegexProperty() { PropertyDescriptor descriptor = PropertyFactory.regexProperty("regexProp") .desc("hello") .defaultValue("^[A-Z].*$") @@ -320,24 +315,25 @@ public class PropertyDescriptorTest { } @Test - public void testRegexPropertyInvalidValue() { + void testRegexPropertyInvalidValue() { PropertyDescriptor descriptor = PropertyFactory.regexProperty("regexProp") .desc("hello") .defaultValue("^[A-Z].*$") .build(); - thrown.expect(PatternSyntaxException.class); - thrown.expectMessage("Unclosed character class"); - descriptor.valueFrom("[open class"); + + PatternSyntaxException thrown = assertThrows(PatternSyntaxException.class, () -> + descriptor.valueFrom("[open class")); + assertThat(thrown.getMessage(), containsString("Unclosed character class")); } @Test - public void testRegexPropertyInvalidDefaultValue() { - thrown.expect(PatternSyntaxException.class); - thrown.expectMessage("Unclosed character class"); - PropertyDescriptor descriptor = PropertyFactory.regexProperty("regexProp") - .desc("hello") - .defaultValue("[open class") - .build(); + void testRegexPropertyInvalidDefaultValue() { + PatternSyntaxException thrown = assertThrows(PatternSyntaxException.class, () -> + PropertyFactory.regexProperty("regexProp") + .desc("hello") + .defaultValue("[open class") + .build()); + assertThat(thrown.getMessage(), containsString("Unclosed character class")); } @@ -346,37 +342,37 @@ public class PropertyDescriptorTest { } @Test - public void testStringParserEmptyString() { + void testStringParserEmptyString() { assertEquals(emptyList(), parseEscaped("", ',')); } @Test - public void testStringParserSimple() { + void testStringParserSimple() { assertEquals(listOf("a", "b", "c"), parseEscaped("a,b,c", ',')); } @Test - public void testStringParserEscapedChar() { + void testStringParserEscapedChar() { assertEquals(listOf("a", "b,c"), parseEscaped("a,b\\,c", ',')); } @Test - public void testStringParserEscapedEscapedChar() { + void testStringParserEscapedEscapedChar() { assertEquals(listOf("a", "b\\", "c"), parseEscaped("a,b\\\\,c", ',')); } @Test - public void testStringParserDelimIsBackslash() { + void testStringParserDelimIsBackslash() { assertEquals(listOf("a,b", "", ",c"), parseEscaped("a,b\\\\,c", '\\')); } @Test - public void testStringParserTrailingBackslash() { + void testStringParserTrailingBackslash() { assertEquals(listOf("a", "b\\"), parseEscaped("a,b\\", ',')); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/RegexPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/RegexPropertyTest.java index 09d9442eff..b57f5403ea 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/RegexPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/RegexPropertyTest.java @@ -16,8 +16,8 @@ import java.util.regex.Pattern; * @since 6.2.0 */ @Deprecated -public class RegexPropertyTest extends AbstractPropertyDescriptorTester { - public RegexPropertyTest() { +class RegexPropertyTest extends AbstractPropertyDescriptorTester { + RegexPropertyTest() { super("Regex"); } @@ -60,42 +60,42 @@ public class RegexPropertyTest extends AbstractPropertyDescriptorTester } @Override - public void testAddAttributesMulti() { + void testAddAttributesMulti() { } @Override - public void testAsDelimitedString() { + void testAsDelimitedString() { } @Override - public void testErrorForBadMulti() { + void testErrorForBadMulti() { } @Override - public void testErrorForCorrectMulti() { + void testErrorForCorrectMulti() { } @Override - public void testFactoryMultiValueDefaultDelimiter() { + void testFactoryMultiValueDefaultDelimiter() { } @Override - public void testFactoryMultiValueCustomDelimiter() { + void testFactoryMultiValueCustomDelimiter() { } @Override - public void testTypeMulti() { + void testTypeMulti() { } @Override - public void testIsMultiValueMulti() { + void testIsMultiValueMulti() { } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/SimpleEnumeratedPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/SimpleEnumeratedPropertyTest.java index b890cc89ea..6b5d3fe335 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/SimpleEnumeratedPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/SimpleEnumeratedPropertyTest.java @@ -4,16 +4,17 @@ package net.sourceforge.pmd.properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import org.junit.Assume; -import org.junit.Test; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.properties.SimpleEnumeratedPropertyTest.Foo; @@ -25,7 +26,7 @@ import net.sourceforge.pmd.properties.SimpleEnumeratedPropertyTest.Foo; * @author Brian Remedios */ @Deprecated -public class SimpleEnumeratedPropertyTest extends AbstractPropertyDescriptorTester { +class SimpleEnumeratedPropertyTest extends AbstractPropertyDescriptorTester { private static final String[] KEYS = {"bar", "na", "bee", "coo"}; private static final Foo[] VALUES = {Foo.BAR, Foo.NA, Foo.BEE, Foo.COO}; @@ -42,13 +43,13 @@ public class SimpleEnumeratedPropertyTest extends AbstractPropertyDescriptorTest } - public SimpleEnumeratedPropertyTest() { + SimpleEnumeratedPropertyTest() { super("Enum"); } @Test - public void testMappings() { + void testMappings() { EnumeratedPropertyDescriptor prop = (EnumeratedPropertyDescriptor) createProperty(); EnumeratedPropertyDescriptor> multi @@ -79,23 +80,24 @@ public class SimpleEnumeratedPropertyTest extends AbstractPropertyDescriptorTest } - @Test(expected = IllegalArgumentException.class) - public void testDefaultIndexOutOfBounds() { - new EnumeratedMultiProperty<>("testEnumerations", "Test enumerations with simple type", - KEYS, VALUES, new int[] {99}, Foo.class, 1.0f); - } - - - @Test(expected = IllegalArgumentException.class) - public void testNoMappingForDefault() { - new EnumeratedMultiProperty<>("testEnumerations", "Test enumerations with simple type", - MAPPINGS, Collections.singletonList(Foo.IGNORED), Foo.class, 1.0f); - + @Test + void testDefaultIndexOutOfBounds() { + assertThrows(IllegalArgumentException.class, () -> + new EnumeratedMultiProperty<>("testEnumerations", "Test enumerations with simple type", + KEYS, VALUES, new int[] {99}, Foo.class, 1.0f)); } @Test - public void creationTest() { + void testNoMappingForDefault() { + assertThrows(IllegalArgumentException.class, () -> + new EnumeratedMultiProperty<>("testEnumerations", "Test enumerations with simple type", + MAPPINGS, Collections.singletonList(Foo.IGNORED), Foo.class, 1.0f)); + } + + + @Test + void creationTest() { PropertyDescriptor prop = createProperty(); PropertyDescriptor> multi = createMultiProperty(); @@ -134,22 +136,22 @@ public class SimpleEnumeratedPropertyTest extends AbstractPropertyDescriptorTest @Override @Test - public void testFactorySingleValue() { - Assume.assumeTrue("The EnumeratedProperty factory is not implemented yet", false); + @Disabled("The EnumeratedProperty factory is not implemented yet") + void testFactorySingleValue() { } @Override @Test - public void testFactoryMultiValueCustomDelimiter() { - Assume.assumeTrue("The EnumeratedProperty factory is not implemented yet", false); + @Disabled("The EnumeratedProperty factory is not implemented yet") + void testFactoryMultiValueCustomDelimiter() { } @Override @Test - public void testFactoryMultiValueDefaultDelimiter() { - Assume.assumeTrue("The EnumeratedProperty factory is not implemented yet", false); + @Disabled("The EnumeratedProperty factory is not implemented yet") + void testFactoryMultiValueDefaultDelimiter() { } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/StringPropertyTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/StringPropertyTest.java index 8385f22a19..1ece5cc174 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/StringPropertyTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/StringPropertyTest.java @@ -14,14 +14,14 @@ import java.util.List; * * @author Brian Remedios */ -public class StringPropertyTest extends AbstractPropertyDescriptorTester { +class StringPropertyTest extends AbstractPropertyDescriptorTester { private static final int MAX_STRING_LENGTH = 52; private static final char DELIMITER = '|'; private static final char[] CHARSET = filter(ALL_CHARS.toCharArray(), DELIMITER); - public StringPropertyTest() { + StringPropertyTest() { super("String"); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/properties/constraints/NumericConstraintsTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/properties/constraints/NumericConstraintsTest.java index a891a2c91a..638d21c6ae 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/properties/constraints/NumericConstraintsTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/properties/constraints/NumericConstraintsTest.java @@ -4,48 +4,50 @@ package net.sourceforge.pmd.properties.constraints; -import org.junit.Assert; -import org.junit.Test; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; -public class NumericConstraintsTest { +import org.junit.jupiter.api.Test; + +class NumericConstraintsTest { @Test - public void testInRangeInteger() { + void testInRangeInteger() { PropertyConstraint constraint = NumericConstraints.inRange(1, 10); - Assert.assertTrue(constraint.test(1)); - Assert.assertTrue(constraint.test(5)); - Assert.assertTrue(constraint.test(10)); - Assert.assertFalse(constraint.test(0)); - Assert.assertFalse(constraint.test(-1)); - Assert.assertFalse(constraint.test(11)); - Assert.assertFalse(constraint.test(100)); + assertTrue(constraint.test(1)); + assertTrue(constraint.test(5)); + assertTrue(constraint.test(10)); + assertFalse(constraint.test(0)); + assertFalse(constraint.test(-1)); + assertFalse(constraint.test(11)); + assertFalse(constraint.test(100)); } @Test - public void testInRangeDouble() { + void testInRangeDouble() { PropertyConstraint constraint = NumericConstraints.inRange(1.0, 10.0); - Assert.assertTrue(constraint.test(1.0)); - Assert.assertTrue(constraint.test(5.5)); - Assert.assertTrue(constraint.test(10.0)); - Assert.assertFalse(constraint.test(0.0)); - Assert.assertFalse(constraint.test(-1.0)); - Assert.assertFalse(constraint.test(11.1)); - Assert.assertFalse(constraint.test(100.0)); + assertTrue(constraint.test(1.0)); + assertTrue(constraint.test(5.5)); + assertTrue(constraint.test(10.0)); + assertFalse(constraint.test(0.0)); + assertFalse(constraint.test(-1.0)); + assertFalse(constraint.test(11.1)); + assertFalse(constraint.test(100.0)); } @Test - public void testPositive() { + void testPositive() { PropertyConstraint constraint = NumericConstraints.positive(); - Assert.assertTrue(constraint.test(1)); - Assert.assertTrue(constraint.test(1.5f)); - Assert.assertTrue(constraint.test(1.5d)); - Assert.assertTrue(constraint.test(100)); - Assert.assertFalse(constraint.test(0)); - Assert.assertFalse(constraint.test(0.1f)); - Assert.assertFalse(constraint.test(0.9d)); - Assert.assertFalse(constraint.test(-1)); - Assert.assertFalse(constraint.test(-100)); - Assert.assertFalse(constraint.test(-0.1f)); - Assert.assertFalse(constraint.test(-0.1d)); + assertTrue(constraint.test(1)); + assertTrue(constraint.test(1.5f)); + assertTrue(constraint.test(1.5d)); + assertTrue(constraint.test(100)); + assertFalse(constraint.test(0)); + assertFalse(constraint.test(0.1f)); + assertFalse(constraint.test(0.9d)); + assertFalse(constraint.test(-1)); + assertFalse(constraint.test(-100)); + assertFalse(constraint.test(-0.1f)); + assertFalse(constraint.test(-0.1d)); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java index a61b2c0066..bbb524284b 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/AbstractRendererTest.java @@ -4,19 +4,19 @@ package net.sourceforge.pmd.renderers; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.Path; import java.util.function.Consumer; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import net.sourceforge.pmd.FooRule; import net.sourceforge.pmd.Report; @@ -34,47 +34,49 @@ import net.sourceforge.pmd.lang.document.TextRange2d; import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; import net.sourceforge.pmd.reporting.FileAnalysisListener; import net.sourceforge.pmd.reporting.GlobalAnalysisListener; +import net.sourceforge.pmd.util.IOUtil; -public abstract class AbstractRendererTest { +abstract class AbstractRendererTest { - @org.junit.Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @TempDir + private Path tempDir; - public abstract Renderer getRenderer(); + abstract Renderer getRenderer(); - public abstract String getExpected(); + abstract String getExpected(); - public String getExpectedWithProperties() { + String getExpectedWithProperties() { return getExpected(); } - public abstract String getExpectedEmpty(); + abstract String getExpectedEmpty(); - public abstract String getExpectedMultiple(); + abstract String getExpectedMultiple(); - public String getExpectedError(ProcessingError error) { + String getExpectedError(ProcessingError error) { return ""; } - public String getExpectedErrorWithoutMessage(ProcessingError error) { + String getExpectedErrorWithoutMessage(ProcessingError error) { return getExpectedError(error); } - public String getExpectedError(ConfigurationError error) { + String getExpectedError(ConfigurationError error) { return ""; } - public String filter(String expected) { + String filter(String expected) { return expected; } - protected String getSourceCodeFilename() { + String getSourceCodeFilename() { return "notAvailable.ext"; } - @Test(expected = NullPointerException.class) - public void testNullPassedIn() throws Exception { - getRenderer().renderFileReport(null); + @Test + void testNullPassedIn() throws Exception { + assertThrows(NullPointerException.class, () -> + getRenderer().renderFileReport(null)); } protected Consumer reportOneViolation() { @@ -126,14 +128,14 @@ public abstract class AbstractRendererTest { */ protected String readFile(String relativePath) { try (InputStream in = getClass().getResourceAsStream(relativePath)) { - return IOUtils.toString(in, StandardCharsets.UTF_8); + return IOUtil.readToString(in, StandardCharsets.UTF_8); } catch (IOException e) { throw new RuntimeException(e); } } @Test - public void testRuleWithProperties() throws Exception { + void testRuleWithProperties() throws Exception { RuleWithProperties theRule = new RuleWithProperties(); theRule.setProperty(RuleWithProperties.STRING_PROPERTY_DESCRIPTOR, "the string value\nsecond line with \"quotes\""); @@ -143,7 +145,7 @@ public abstract class AbstractRendererTest { } @Test - public void testRenderer() throws Exception { + void testRenderer() throws Exception { testRenderer(Charset.defaultCharset()); } @@ -153,26 +155,26 @@ public abstract class AbstractRendererTest { } @Test - public void testRendererEmpty() throws Exception { + void testRendererEmpty() throws Exception { String actual = render(it -> {}); assertEquals(filter(getExpectedEmpty()), filter(actual)); } @Test - public void testRendererMultiple() throws Exception { + void testRendererMultiple() throws Exception { String actual = render(reportTwoViolations()); assertEquals(filter(getExpectedMultiple()), filter(actual)); } @Test - public void testError() throws Exception { + void testError() throws Exception { Report.ProcessingError err = new Report.ProcessingError(new RuntimeException("Error"), "file"); String actual = render(it -> it.onError(err)); assertEquals(filter(getExpectedError(err)), filter(actual)); } @Test - public void testErrorWithoutMessage() throws Exception { + void testErrorWithoutMessage() throws Exception { Report.ProcessingError err = new Report.ProcessingError(new NullPointerException(), "file"); String actual = render(it -> it.onError(err)); assertEquals(filter(getExpectedErrorWithoutMessage(err)), filter(actual)); @@ -183,7 +185,7 @@ public abstract class AbstractRendererTest { } @Test - public void testConfigError() throws Exception { + void testConfigError() throws Exception { Report.ConfigurationError err = new Report.ConfigurationError(new FooRule(), "a configuration error"); String actual = renderGlobal(getRenderer(), it -> it.onConfigError(err)); assertEquals(filter(getExpectedError(err)), filter(actual)); @@ -213,7 +215,7 @@ public abstract class AbstractRendererTest { private String renderGlobal(Renderer renderer, Consumer listenerEffects, Charset expectedEncoding) throws IOException { - File file = temporaryFolder.newFile(); + File file = tempDir.resolve("report.out").toFile(); renderer.setReportFile(file.getAbsolutePath()); try (GlobalAnalysisListener listener = renderer.newListener()) { @@ -222,7 +224,7 @@ public abstract class AbstractRendererTest { throw new AssertionError(e); } - return FileUtils.readFileToString(file, expectedEncoding); + return IOUtil.readFileToString(file, expectedEncoding); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CSVRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CSVRendererTest.java index 4b0fdf3024..b38f6e163a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CSVRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CSVRendererTest.java @@ -8,38 +8,38 @@ import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.Report.ConfigurationError; import net.sourceforge.pmd.Report.ProcessingError; -public class CSVRendererTest extends AbstractRendererTest { +class CSVRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new CSVRenderer(); } @Override - public String getExpected() { + String getExpected() { return getHeader() + "\"1\",\"\",\"" + getSourceCodeFilename() + "\",\"5\",\"1\",\"blah\",\"RuleSet\",\"Foo\"" + PMD.EOL; } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return getHeader(); } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return getHeader() + "\"1\",\"\",\"" + getSourceCodeFilename() + "\",\"5\",\"1\",\"blah\",\"RuleSet\",\"Foo\"" + PMD.EOL + "\"2\",\"\",\"" + getSourceCodeFilename() + "\",\"1\",\"1\",\"blah\",\"RuleSet\",\"Boo\"" + PMD.EOL; } @Override - public String getExpectedError(ProcessingError error) { + String getExpectedError(ProcessingError error) { return getHeader(); } @Override - public String getExpectedError(ConfigurationError error) { + String getExpectedError(ConfigurationError error) { return getHeader(); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java index 5bc52da837..64f8ed897f 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/CodeClimateRendererTest.java @@ -4,9 +4,9 @@ package net.sourceforge.pmd.renderers; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.lang.document.FileLocation; @@ -14,15 +14,15 @@ import net.sourceforge.pmd.lang.rule.ParametricRuleViolation; import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.lang.rule.xpath.XPathVersion; -public class CodeClimateRendererTest extends AbstractRendererTest { +class CodeClimateRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new CodeClimateRenderer(); } @Override - public String getExpected() { + String getExpected() { return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\"," + "\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: Low\\n\\n" + "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n" @@ -37,7 +37,7 @@ public class CodeClimateRendererTest extends AbstractRendererTest { } @Override - public String getExpectedWithProperties() { + String getExpectedWithProperties() { return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\"," + "\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: Low\\n\\n" + "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n" @@ -54,12 +54,12 @@ public class CodeClimateRendererTest extends AbstractRendererTest { } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return ""; } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\"," + "\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: Low\\n\\n" + "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n" @@ -84,7 +84,7 @@ public class CodeClimateRendererTest extends AbstractRendererTest { } @Test - public void testXPathRule() throws Exception { + void testXPathRule() throws Exception { FileLocation node = createLocation(1, 1, 1, 1); XPathRule theRule = new XPathRule(XPathVersion.XPATH_3_1, "//dummyNode"); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/EmacsRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/EmacsRendererTest.java index bf39ff9df4..01ac684c61 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/EmacsRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/EmacsRendererTest.java @@ -6,25 +6,25 @@ package net.sourceforge.pmd.renderers; import net.sourceforge.pmd.PMD; -public class EmacsRendererTest extends AbstractRendererTest { +class EmacsRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new EmacsRenderer(); } @Override - public String getExpected() { + String getExpected() { return getSourceCodeFilename() + ":1: blah" + PMD.EOL; } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return ""; } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return getSourceCodeFilename() + ":1: blah" + PMD.EOL + getSourceCodeFilename() + ":1: blah" + PMD.EOL; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/EmptyRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/EmptyRendererTest.java index db6c11942e..778c070b4a 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/EmptyRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/EmptyRendererTest.java @@ -4,34 +4,31 @@ package net.sourceforge.pmd.renderers; -import org.junit.Test; - -public class EmptyRendererTest extends AbstractRendererTest { +class EmptyRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new EmptyRenderer(); } - // Overriding the annotation from the super class, this renderer doesn't care, so no NPE. - @Test @Override - public void testNullPassedIn() throws Exception { - super.testNullPassedIn(); + void testNullPassedIn() throws Exception { + // Overriding test from the super class, this renderer doesn't care, so no NPE. + getRenderer().renderFileReport(null); } @Override - public String getExpected() { + String getExpected() { return ""; } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return ""; } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return ""; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/HTMLRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/HTMLRendererTest.java index c51cdcc3f9..58509f153d 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/HTMLRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/HTMLRendererTest.java @@ -4,17 +4,17 @@ package net.sourceforge.pmd.renderers; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.Report.ConfigurationError; import net.sourceforge.pmd.Report.ProcessingError; -public class HTMLRendererTest extends AbstractRendererTest { +class HTMLRendererTest extends AbstractRendererTest { @Override protected String getSourceCodeFilename() { @@ -26,12 +26,12 @@ public class HTMLRendererTest extends AbstractRendererTest { } @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new HTMLRenderer(); } @Override - public String getExpected() { + String getExpected() { return getExpected(null, null); } @@ -48,13 +48,13 @@ public class HTMLRendererTest extends AbstractRendererTest { } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return getHeader() + "" + PMD.EOL; } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return getHeader() + " " + PMD.EOL + "1" + PMD.EOL + "" + getEscapedFilename() + "" + PMD.EOL + "1" + PMD.EOL @@ -65,7 +65,7 @@ public class HTMLRendererTest extends AbstractRendererTest { } @Override - public String getExpectedError(ProcessingError error) { + String getExpectedError(ProcessingError error) { return getHeader() + "

Processing errors

" + PMD.EOL + "" + PMD.EOL + " " + PMD.EOL @@ -74,7 +74,7 @@ public class HTMLRendererTest extends AbstractRendererTest { } @Override - public String getExpectedError(ConfigurationError error) { + String getExpectedError(ConfigurationError error) { return getHeader() + "
FileProblem

Configuration errors

" + PMD.EOL + "" + PMD.EOL + " " + PMD.EOL @@ -89,7 +89,7 @@ public class HTMLRendererTest extends AbstractRendererTest { } @Test - public void testLinkPrefix() throws IOException { + void testLinkPrefix() throws IOException { final HTMLRenderer renderer = new HTMLRenderer(); final String linkPrefix = "https://github.com/pmd/pmd/blob/master/"; final String linePrefix = "L"; @@ -102,7 +102,7 @@ public class HTMLRendererTest extends AbstractRendererTest { } @Test - public void testLinePrefixNotSet() throws IOException { + void testLinePrefixNotSet() throws IOException { final HTMLRenderer renderer = new HTMLRenderer(); final String linkPrefix = "https://github.com/pmd/pmd/blob/master/"; renderer.setProperty(HTMLRenderer.LINK_PREFIX, linkPrefix); @@ -114,7 +114,7 @@ public class HTMLRendererTest extends AbstractRendererTest { } @Test - public void testEmptyLinePrefix() throws IOException { + void testEmptyLinePrefix() throws IOException { final HTMLRenderer renderer = new HTMLRenderer(); final String linkPrefix = "https://github.com/pmd/pmd/blob/master/"; renderer.setProperty(HTMLRenderer.LINK_PREFIX, linkPrefix); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/IDEAJRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/IDEAJRendererTest.java index 8b824b1363..bfc1d0ef57 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/IDEAJRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/IDEAJRendererTest.java @@ -6,10 +6,10 @@ package net.sourceforge.pmd.renderers; import net.sourceforge.pmd.PMD; -public class IDEAJRendererTest extends AbstractRendererTest { +class IDEAJRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { Renderer result = new IDEAJRenderer(); result.setProperty(IDEAJRenderer.SOURCE_PATH, ""); result.setProperty(IDEAJRenderer.CLASS_AND_METHOD_NAME, "Foo "); @@ -18,17 +18,17 @@ public class IDEAJRendererTest extends AbstractRendererTest { } @Override - public String getExpected() { + String getExpected() { return "blah" + PMD.EOL + " at Foo (Foo.java:1)" + PMD.EOL; } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return ""; } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return "blah" + PMD.EOL + " at Foo (Foo.java:1)" + PMD.EOL + "blah" + PMD.EOL + " at Foo (Foo.java:1)" + PMD.EOL; } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java index f5f1c31709..26a8a379e7 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/JsonRendererTest.java @@ -5,10 +5,11 @@ package net.sourceforge.pmd.renderers; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.io.IOException; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.FooRule; import net.sourceforge.pmd.Report.ConfigurationError; @@ -16,30 +17,30 @@ import net.sourceforge.pmd.Report.ProcessingError; import net.sourceforge.pmd.Report.SuppressedViolation; import net.sourceforge.pmd.ViolationSuppressor; -public class JsonRendererTest extends AbstractRendererTest { +class JsonRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new JsonRenderer(); } @Override - public String getExpected() { + String getExpected() { return readFile("expected.json"); } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return readFile("empty.json"); } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return readFile("expected-multiple.json"); } @Override - public String getExpectedError(ProcessingError error) { + String getExpectedError(ProcessingError error) { String expected = readFile("expected-processingerror.json"); expected = expected.replace("###REPLACE_ME###", error.getDetail() .replaceAll("\r", "\\\\r") @@ -49,12 +50,12 @@ public class JsonRendererTest extends AbstractRendererTest { } @Override - public String getExpectedError(ConfigurationError error) { + String getExpectedError(ConfigurationError error) { return readFile("expected-configurationerror.json"); } @Override - public String getExpectedErrorWithoutMessage(ProcessingError error) { + String getExpectedErrorWithoutMessage(ProcessingError error) { String expected = readFile("expected-processingerror-no-message.json"); expected = expected.replace("###REPLACE_ME###", error.getDetail() .replaceAll("\r", "\\\\r") @@ -69,7 +70,7 @@ public class JsonRendererTest extends AbstractRendererTest { } @Override - public String filter(String expected) { + String filter(String expected) { return expected .replaceAll("\"timestamp\":\\s*\"[^\"]+\"", "\"timestamp\": \"--replaced--\"") .replaceAll("\"pmdVersion\":\\s*\"[^\"]+\"", "\"pmdVersion\": \"unknown\"") @@ -77,7 +78,7 @@ public class JsonRendererTest extends AbstractRendererTest { } @Test - public void suppressedViolations() throws IOException { + void suppressedViolations() throws IOException { SuppressedViolation suppressed = new SuppressedViolation( newRuleViolation(1, 1, 1, 1, new FooRule()), ViolationSuppressor.NOPMD_COMMENT_SUPPRESSOR, @@ -85,6 +86,6 @@ public class JsonRendererTest extends AbstractRendererTest { ); String actual = renderReport(getRenderer(), it -> it.onSuppressedRuleViolation(suppressed)); String expected = readFile("expected-suppressed.json"); - Assert.assertEquals(filter(expected), filter(actual)); + assertEquals(filter(expected), filter(actual)); } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/PapariTextRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/PapariTextRendererTest.java index 69c7f384a1..504e38b62b 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/PapariTextRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/PapariTextRendererTest.java @@ -12,10 +12,10 @@ import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.Report.ConfigurationError; import net.sourceforge.pmd.Report.ProcessingError; -public class PapariTextRendererTest extends AbstractRendererTest { +class PapariTextRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { TextColorRenderer result = new TextColorRenderer() { @Override protected Reader getReader(String sourceFile) throws FileNotFoundException { @@ -27,19 +27,19 @@ public class PapariTextRendererTest extends AbstractRendererTest { } @Override - public String getExpected() { + String getExpected() { return "* file: " + getSourceCodeFilename() + PMD.EOL + " src: " + getSourceCodeFilename() + ":1:1" + PMD.EOL + " rule: Foo" + PMD.EOL + " msg: blah" + PMD.EOL + " code: public class Foo {}" + PMD.EOL + PMD.EOL + PMD.EOL + PMD.EOL + "Summary:" + PMD.EOL + PMD.EOL + "* warnings: 1" + PMD.EOL; } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return PMD.EOL + PMD.EOL + "Summary:" + PMD.EOL + PMD.EOL + "* warnings: 0" + PMD.EOL; } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return "* file: " + getSourceCodeFilename() + PMD.EOL + " src: " + getSourceCodeFilename() + ":1:1" + PMD.EOL + " rule: Foo" + PMD.EOL + " msg: blah" + PMD.EOL + " code: public class Foo {}" + PMD.EOL + PMD.EOL + " src: " + getSourceCodeFilename() + ":1:1" + PMD.EOL + " rule: Boo" + PMD.EOL + " msg: blah" + PMD.EOL @@ -48,21 +48,21 @@ public class PapariTextRendererTest extends AbstractRendererTest { } @Override - public String getExpectedError(ProcessingError error) { + String getExpectedError(ProcessingError error) { return PMD.EOL + PMD.EOL + "Summary:" + PMD.EOL + PMD.EOL + "* file: file" + PMD.EOL + " err: RuntimeException: Error" + PMD.EOL + error.getDetail() + PMD.EOL + PMD.EOL + "* errors: 1" + PMD.EOL + "* warnings: 0" + PMD.EOL; } @Override - public String getExpectedErrorWithoutMessage(ProcessingError error) { + String getExpectedErrorWithoutMessage(ProcessingError error) { return PMD.EOL + PMD.EOL + "Summary:" + PMD.EOL + PMD.EOL + "* file: file" + PMD.EOL + " err: NullPointerException: null" + PMD.EOL + error.getDetail() + PMD.EOL + PMD.EOL + "* errors: 1" + PMD.EOL + "* warnings: 0" + PMD.EOL; } @Override - public String getExpectedError(ConfigurationError error) { + String getExpectedError(ConfigurationError error) { return PMD.EOL + PMD.EOL + "Summary:" + PMD.EOL + PMD.EOL + "* rule: Foo" + PMD.EOL + " err: a configuration error" + PMD.EOL + PMD.EOL + "* errors: 1" + PMD.EOL + "* warnings: 0" + PMD.EOL; diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/RenderersTests.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/RenderersTests.java index ce0ae361f7..071dcef8ee 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/RenderersTests.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/RenderersTests.java @@ -4,17 +4,16 @@ package net.sourceforge.pmd.renderers; -import org.junit.runner.RunWith; -import org.junit.runners.Suite; -import org.junit.runners.Suite.SuiteClasses; +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; /** * tests for the net.sourceforge.pmd.renderers package * * @author Boris Gruschko ( boris at gruschko.org ) */ -@RunWith(Suite.class) -@SuiteClasses({ +@Suite +@SelectClasses({ CodeClimateRendererTest.class, CSVRendererTest.class, EmacsRendererTest.class, @@ -31,5 +30,5 @@ import org.junit.runners.Suite.SuiteClasses; XSLTRendererTest.class, YAHTMLRendererTest.class }) -public class RenderersTests { +class RenderersTests { } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/SarifRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/SarifRendererTest.java index 9faefb055f..a3b786f8a0 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/SarifRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/SarifRendererTest.java @@ -4,54 +4,54 @@ package net.sourceforge.pmd.renderers; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.nio.charset.StandardCharsets; import java.util.function.Consumer; -import org.json.JSONArray; -import org.json.JSONObject; -import org.junit.Test; -import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.Report; import net.sourceforge.pmd.Rule; import net.sourceforge.pmd.reporting.FileAnalysisListener; +import com.github.stefanbirkner.systemlambda.SystemLambda; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; -public class SarifRendererTest extends AbstractRendererTest { - - @org.junit.Rule - public RestoreSystemProperties systemProperties = new RestoreSystemProperties(); +class SarifRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new SarifRenderer(); } @Test - public void testRendererWithASCII() throws Exception { - System.setProperty("file.encoding", StandardCharsets.US_ASCII.name()); - testRenderer(StandardCharsets.UTF_8); + void testRendererWithASCII() throws Exception { + SystemLambda.restoreSystemProperties(() -> { + System.setProperty("file.encoding", StandardCharsets.US_ASCII.name()); + testRenderer(StandardCharsets.UTF_8); + }); } @Override - public String getExpected() { + String getExpected() { return readFile("expected.sarif.json"); } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return readFile("empty.sarif.json"); } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return readFile("expected-multiple.sarif.json"); } @Override - public String getExpectedError(Report.ProcessingError error) { + String getExpectedError(Report.ProcessingError error) { String expected = readFile("expected-error.sarif.json"); expected = expected.replace("###REPLACE_ME###", error.getDetail() .replaceAll("\r", "\\\\r") @@ -61,12 +61,12 @@ public class SarifRendererTest extends AbstractRendererTest { } @Override - public String getExpectedError(Report.ConfigurationError error) { + String getExpectedError(Report.ConfigurationError error) { return readFile("expected-configerror.sarif.json"); } @Override - public String getExpectedErrorWithoutMessage(Report.ProcessingError error) { + String getExpectedErrorWithoutMessage(Report.ProcessingError error) { String expected = readFile("expected-error-nomessage.sarif.json"); expected = expected.replace("###REPLACE_ME###", error.getDetail() .replaceAll("\r", "\\\\r") @@ -76,7 +76,7 @@ public class SarifRendererTest extends AbstractRendererTest { } @Override - public String filter(String expected) { + String filter(String expected) { return expected.replaceAll("\r\n", "\n") // make the test run on Windows, too .replaceAll("\"version\": \".+\",", "\"version\": \"unknown\","); } @@ -88,12 +88,13 @@ public class SarifRendererTest extends AbstractRendererTest { * when it should report multiple results #3768 */ @Test - public void testRendererMultipleLocations() throws Exception { + void testRendererMultipleLocations() throws Exception { String actual = renderReport(getRenderer(), reportThreeViolationsTwoRules()); - JSONObject json = new JSONObject(actual); - JSONArray results = json.getJSONArray("runs").getJSONObject(0).getJSONArray("results"); - assertEquals(3, results.length()); + Gson gson = new Gson(); + JsonObject json = gson.fromJson(actual, JsonObject.class); + JsonArray results = json.getAsJsonArray("runs").get(0).getAsJsonObject().getAsJsonArray("results"); + assertEquals(3, results.size()); assertEquals(filter(readFile("expected-multiple-locations.sarif.json")), filter(actual)); } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/SummaryHTMLRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/SummaryHTMLRendererTest.java index 6d89825c4c..5ed067de6b 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/SummaryHTMLRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/SummaryHTMLRendererTest.java @@ -4,12 +4,12 @@ package net.sourceforge.pmd.renderers; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.Collections; import java.util.function.Consumer; -import org.junit.Test; +import org.junit.jupiter.api.Test; import net.sourceforge.pmd.FooRule; import net.sourceforge.pmd.PMD; @@ -21,10 +21,10 @@ import net.sourceforge.pmd.lang.ast.DummyNode.DummyRootNode; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.reporting.FileAnalysisListener; -public class SummaryHTMLRendererTest extends AbstractRendererTest { +class SummaryHTMLRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { Renderer result = new SummaryHTMLRenderer(); result.setProperty(HTMLRenderer.LINK_PREFIX, "link_prefix"); result.setProperty(HTMLRenderer.LINE_PREFIX, "line_prefix"); @@ -38,7 +38,7 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest { } @Override - public String getExpected() { + String getExpected() { return "PMD" + PMD.EOL + "

Summary

" + PMD.EOL + "
RuleProblem
" + PMD.EOL + "" + PMD.EOL @@ -55,7 +55,7 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest { } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return "PMD" + PMD.EOL + "

Summary

" + PMD.EOL + "
Rule nameNumber of violations
" + PMD.EOL + "" + PMD.EOL + "
Rule nameNumber of violations
" + PMD.EOL @@ -67,7 +67,7 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest { } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return "PMD" + PMD.EOL + "

Summary

" + PMD.EOL + "" + PMD.EOL + "" + PMD.EOL @@ -87,7 +87,7 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest { } @Override - public String getExpectedError(ProcessingError error) { + String getExpectedError(ProcessingError error) { return "PMD" + PMD.EOL + "

Summary

" + PMD.EOL + "
Rule nameNumber of violations
" + PMD.EOL + "" + PMD.EOL + "
Rule nameNumber of violations
" + PMD.EOL @@ -102,7 +102,7 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest { } @Override - public String getExpectedError(ConfigurationError error) { + String getExpectedError(ConfigurationError error) { return "PMD" + PMD.EOL + "

Summary

" + PMD.EOL + "" + PMD.EOL + "" + PMD.EOL + "
Rule nameNumber of violations
" + PMD.EOL @@ -117,7 +117,7 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest { } @Test - public void testShowSuppressions() throws Exception { + void testShowSuppressions() throws Exception { Renderer renderer = getRenderer(); renderer.setShowSuppressedViolations(true); String actual = renderReport(renderer, createEmptyReportWithSuppression()); @@ -138,7 +138,7 @@ public class SummaryHTMLRendererTest extends AbstractRendererTest { } @Test - public void testHideSuppressions() throws Exception { + void testHideSuppressions() throws Exception { Renderer renderer = getRenderer(); renderer.setShowSuppressedViolations(false); String actual = renderReport(renderer, createEmptyReportWithSuppression()); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/TextPadRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/TextPadRendererTest.java index ac45b8a55b..7a4cdecb54 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/TextPadRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/TextPadRendererTest.java @@ -6,25 +6,25 @@ package net.sourceforge.pmd.renderers; import net.sourceforge.pmd.PMD; -public class TextPadRendererTest extends AbstractRendererTest { +class TextPadRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new TextPadRenderer(); } @Override - public String getExpected() { + String getExpected() { return getSourceCodeFilename() + "(1, Foo): blah" + PMD.EOL; } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return ""; } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return getSourceCodeFilename() + "(1, Foo): blah" + PMD.EOL + getSourceCodeFilename() + "(1, Boo): blah" + PMD.EOL; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/TextRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/TextRendererTest.java index 2e85785db2..fc2f008def 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/TextRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/TextRendererTest.java @@ -8,41 +8,41 @@ import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.Report.ConfigurationError; import net.sourceforge.pmd.Report.ProcessingError; -public class TextRendererTest extends AbstractRendererTest { +class TextRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new TextRenderer(); } @Override - public String getExpected() { + String getExpected() { return getSourceCodeFilename() + ":1:\tFoo:\tblah" + PMD.EOL; } @Override - public String getExpectedEmpty() { + String getExpectedEmpty() { return ""; } @Override - public String getExpectedMultiple() { + String getExpectedMultiple() { return getSourceCodeFilename() + ":1:\tFoo:\tblah" + PMD.EOL + getSourceCodeFilename() + ":1:\tBoo:\tblah" + PMD.EOL; } @Override - public String getExpectedError(ProcessingError error) { + String getExpectedError(ProcessingError error) { return "file\t-\tRuntimeException: Error" + PMD.EOL; } @Override - public String getExpectedErrorWithoutMessage(ProcessingError error) { + String getExpectedErrorWithoutMessage(ProcessingError error) { return "file\t-\tNullPointerException: null" + PMD.EOL; } @Override - public String getExpectedError(ConfigurationError error) { + String getExpectedError(ConfigurationError error) { return "Foo\t-\ta configuration error" + PMD.EOL; } } diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/VBHTMLRendererTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/VBHTMLRendererTest.java index 7bc7118adb..2c7b6c61c3 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/renderers/VBHTMLRendererTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/renderers/VBHTMLRendererTest.java @@ -8,15 +8,15 @@ import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.Report.ConfigurationError; import net.sourceforge.pmd.Report.ProcessingError; -public class VBHTMLRendererTest extends AbstractRendererTest { +class VBHTMLRendererTest extends AbstractRendererTest { @Override - public Renderer getRenderer() { + Renderer getRenderer() { return new VBHTMLRenderer(); } @Override - public String getExpected() { + String getExpected() { return "PMD