From 2a98d5cd4c701f8391c8f4f7161323ed2143ac7a Mon Sep 17 00:00:00 2001 From: pbludov Date: Sun, 14 Nov 2021 18:25:11 +0300 Subject: [PATCH] Issue #10932: remove dependency on Powermock from tests --- .ci/pitest.sh | 35 +-- config/import-control-test.xml | 10 - pom.xml | 23 +- .../tools/checkstyle/utils/CommonUtil.java | 14 +- .../AuditEventDefaultFormatterTest.java | 45 ++++ .../checkstyle/ConfigurationLoaderTest.java | 27 ++ .../checkstyle/PackageObjectFactoryTest.java | 52 ++++ .../checkstyle/PropertyCacheFileTest.java | 139 ++++++++++ .../tools/checkstyle/TreeWalkerTest.java | 93 +++++++ .../checks/header/HeaderCheckTest.java | 184 +++++++------ .../imports/ImportControlLoaderTest.java | 32 +++ .../AuditEventDefaultFormatterPowerTest.java | 72 ----- .../powermock/CommonUtilPowerTest.java | 66 ----- .../ConfigurationLoaderPowerTest.java | 82 ------ .../powermock/HeaderCheckPowerTest.java | 71 ----- .../ImportControlLoaderPowerTest.java | 68 ----- .../PackageObjectFactoryPowerTest.java | 86 ------ .../powermock/PropertyCacheFilePowerTest.java | 247 ------------------ .../powermock/TreeWalkerPowerTest.java | 105 -------- .../checkstyle/utils/CommonUtilTest.java | 101 ++++--- .../treewalker/InputTreeWalkerJavadoc.java | 5 + .../extensions/configuration.properties | 1 - 22 files changed, 581 insertions(+), 977 deletions(-) delete mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/AuditEventDefaultFormatterPowerTest.java delete mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/CommonUtilPowerTest.java delete mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/ConfigurationLoaderPowerTest.java delete mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/HeaderCheckPowerTest.java delete mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/ImportControlLoaderPowerTest.java delete mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/PackageObjectFactoryPowerTest.java delete mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/PropertyCacheFilePowerTest.java delete mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/TreeWalkerPowerTest.java create mode 100644 src/test/resources/com/puppycrawl/tools/checkstyle/treewalker/InputTreeWalkerJavadoc.java delete mode 100644 src/test/resources/org/powermock/extensions/configuration.properties diff --git a/.ci/pitest.sh b/.ci/pitest.sh index 948a9ed1517..c9d8769cbdf 100755 --- a/.ci/pitest.sh +++ b/.ci/pitest.sh @@ -41,6 +41,8 @@ pitest-annotation|pitest-design \ |pitest-coding \ |pitest-regexp \ |pitest-meta \ +|pitest-tree-walker \ +|pitest-utils \ |pitest-java-ast-visitor) mvn --no-transfer-progress -e -P$1 clean test org.pitest:pitest-maven:mutationCoverage; declare -a ignoredItems=(); @@ -59,8 +61,6 @@ pitest-main) pitest-header) mvn --no-transfer-progress -e -P$1 clean test org.pitest:pitest-maven:mutationCoverage; declare -a ignoredItems=( - "AbstractHeaderCheck.java.html:
            catch (final IOException ex) {
" - "AbstractHeaderCheck.java.html:
                throw new IllegalArgumentException("unable to load header", ex);
" "RegexpHeaderCheck.java.html:
                    isMatch = headerLineNo == headerSize
" "RegexpHeaderCheck.java.html:
                            || isMatch(line, headerLineNo);
" ); @@ -81,27 +81,15 @@ pitest-common) mvn --no-transfer-progress -e -P$1 clean test org.pitest:pitest-maven:mutationCoverage; declare -a ignoredItems=( "AuditEventDefaultFormatter.java.html:
        if (lastDotIndex == -1) {
" - "AuditEventDefaultFormatter.java.html:
                checkShortName = checkFullName.substring(0, checkFullName.lastIndexOf(SUFFIX));
" - "AuditEventDefaultFormatter.java.html:
                checkShortName = checkFullName;
" - "AuditEventDefaultFormatter.java.html:
            if (checkFullName.endsWith(SUFFIX)) {
" "Checker.java.html:
                if (cacheFile != null && cacheFile.isInCache(fileName, timestamp)
" "DefaultLogger.java.html:
        closeError = errorStreamOptions == OutputStreamOptions.CLOSE;
" "DefaultLogger.java.html:
        closeInfo = infoStreamOptions == OutputStreamOptions.CLOSE;
" "DefaultLogger.java.html:
        if (closeError) {
" "DefaultLogger.java.html:
        if (closeInfo) {
" "DefaultLogger.java.html:
        if (severityLevel != SeverityLevel.IGNORE) {
" - "ConfigurationLoader.java.html:
                    catch (final CheckstyleException ex) {
" - "ConfigurationLoader.java.html:
                                        + recentModule.getName(), ex);
" - "ConfigurationLoader.java.html:
                        throw new SAXException(
" "PackageObjectFactory.java.html:
        if (instance == null
" "PackageObjectFactory.java.html:
        if (!name.contains(PACKAGE_SEPARATOR)) {
" "PackageObjectFactory.java.html:
                if (thirdPartyNameToFullModuleNames == null) {
" - "PackageObjectFactory.java.html:
            returnValue = Collections.emptyMap();
" - "PackageObjectFactory.java.html:
        catch (IOException ignore) {
" - "PropertyCacheFile.java.html:
                if (!cachedHashSum.equals(contentHashSum)) {
" - "PropertyCacheFile.java.html:
                    changed = true;
" - "PropertyCacheFile.java.html:
        catch (final IOException | NoSuchAlgorithmException ex) {
" - "PropertyCacheFile.java.html:
            throw new IllegalStateException("Unable to calculate hashcode.", ex);
" ); checkPitestReport "${ignoredItems[@]}" ;; @@ -159,25 +147,6 @@ pitest-javadoc) checkPitestReport "${ignoredItems[@]}" ;; -pitest-tree-walker) - mvn --no-transfer-progress -e -P$1 clean test org.pitest:pitest-maven:mutationCoverage; - declare -a ignoredItems=( - "TreeWalker.java.html:
            if (!commentChecks.isEmpty()) {
" - "TreeWalker.java.html:
            if (!ordinaryChecks.isEmpty()) {
" - "TreeWalker.java.html:
            if (filters.isEmpty()) {
" - ); - checkPitestReport "${ignoredItems[@]}" - ;; - -pitest-utils) - mvn --no-transfer-progress -e -P$1 clean test org.pitest:pitest-maven:mutationCoverage; - declare -a ignoredItems=( - "CommonUtil.java.html:
                catch (final URISyntaxException ex) {
" - "CommonUtil.java.html:
                    throw new CheckstyleException(UNABLE_TO_FIND_EXCEPTION_PREFIX + filename, ex);
" - ); - checkPitestReport "${ignoredItems[@]}" - ;; - # pitesttyle-gui) # mvn -e -P$1 clean test org.pitest:pitest-maven:mutationCoverage; # # post validation is skipped, we do not test gui throughly diff --git a/config/import-control-test.xml b/config/import-control-test.xml index 7175d138cb8..a3e307ef080 100644 --- a/config/import-control-test.xml +++ b/config/import-control-test.xml @@ -17,11 +17,6 @@ - - - - @@ -35,11 +30,6 @@ - - - - - diff --git a/pom.xml b/pom.xml index b7b8d87e9cd..332b013d865 100644 --- a/pom.xml +++ b/pom.xml @@ -205,7 +205,7 @@ 3.15.0 6.41.0 0.8.7 - 2.0.9 + 4.1.0 10.6 3.1.2 1.40.0 @@ -316,24 +316,9 @@ test - org.powermock - powermock-api-mockito2 - ${powermock.version} - test - - - - org.javassist - javassist - 3.28.0-GA - test - - - - org.powermock - powermock-module-junit4 - ${powermock.version} - test + org.mockito + mockito-inline + ${mockito.version} commons-io diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/utils/CommonUtil.java b/src/main/java/com/puppycrawl/tools/checkstyle/utils/CommonUtil.java index 65844acda0b..4cffbca1755 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/utils/CommonUtil.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/utils/CommonUtil.java @@ -447,7 +447,7 @@ private static URI getFilepathOrClasspathUri(String filename) throws CheckstyleE public static URI getResourceFromClassPath(String filename) throws CheckstyleException { final URL configUrl; if (filename.charAt(0) == '/') { - configUrl = CommonUtil.class.getResource(filename); + configUrl = getCheckstyleResource(filename); } else { configUrl = ClassLoader.getSystemResource(filename); @@ -468,6 +468,18 @@ public static URI getResourceFromClassPath(String filename) throws CheckstyleExc return uri; } + /** + * Finds a resource with a given name in the Checkstyle resource bundle. + * This method is intended only for internal use in Checkstyle tests for + * easy mocking to gain 100% coverage. + * + * @param name name of the desired resource + * @return URI of the resource + */ + public static URL getCheckstyleResource(String name) { + return CommonUtil.class.getResource(name); + } + /** * Puts part of line, which matches regexp into given template * on positions $n where 'n' is number of matched part in line. diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/AuditEventDefaultFormatterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/AuditEventDefaultFormatterTest.java index ac6e1a0d97f..7dac8140c8f 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/AuditEventDefaultFormatterTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/AuditEventDefaultFormatterTest.java @@ -19,7 +19,10 @@ package com.puppycrawl.tools.checkstyle; +import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import org.junit.jupiter.api.Test; @@ -80,6 +83,48 @@ public void testCalculateBufferLength() throws Exception { assertEquals(54, result, "Buffer length is not expected"); } + /** + * This test mocks {@code AuditEvent} to emulate an event from a top level class + * to gain 100% coverage. + */ + @Test + public void testFormatTopLevelModuleNameContainsCheckSuffix() { + final AuditEvent mock = mock(AuditEvent.class); + when(mock.getSourceName()).thenReturn("TestModuleCheck"); + when(mock.getSeverityLevel()).thenReturn(SeverityLevel.WARNING); + when(mock.getLine()).thenReturn(1); + when(mock.getColumn()).thenReturn(1); + when(mock.getMessage()).thenReturn("Mocked message."); + when(mock.getFileName()).thenReturn("InputMockFile.java"); + final AuditEventFormatter formatter = new AuditEventDefaultFormatter(); + + final String expected = "[WARN] InputMockFile.java:1:1: Mocked message. [TestModule]"; + assertWithMessage("Invalid format") + .that(formatter.format(mock)) + .isEqualTo(expected); + } + + /** + * This test mocks {@code AuditEvent} to emulate an event from a top level class + * to gain 100% coverage. + */ + @Test + public void testFormatTopLevelModuleNameDoesNotContainCheckSuffix() { + final AuditEvent mock = mock(AuditEvent.class); + when(mock.getSourceName()).thenReturn("TestModule"); + when(mock.getSeverityLevel()).thenReturn(SeverityLevel.WARNING); + when(mock.getLine()).thenReturn(1); + when(mock.getColumn()).thenReturn(1); + when(mock.getMessage()).thenReturn("Mocked message."); + when(mock.getFileName()).thenReturn("InputMockFile.java"); + final AuditEventFormatter formatter = new AuditEventDefaultFormatter(); + + final String expected = "[WARN] InputMockFile.java:1:1: Mocked message. [TestModule]"; + assertWithMessage("Invalid format") + .that(formatter.format(mock)) + .isEqualTo(expected); + } + private static class TestModuleCheck { // no code diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/ConfigurationLoaderTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/ConfigurationLoaderTest.java index 3ca13eec930..7834ba7d0aa 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/ConfigurationLoaderTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/ConfigurationLoaderTest.java @@ -22,8 +22,11 @@ import static com.google.common.truth.Truth.assertWithMessage; 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.Assertions.fail; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.when; import java.io.File; import java.lang.reflect.Constructor; @@ -36,6 +39,7 @@ import java.util.Properties; import org.junit.jupiter.api.Test; +import org.mockito.MockedConstruction; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -618,4 +622,27 @@ public void testConstructors() throws Exception { assertEquals(1, length, "Unexpected children size"); } + @Test + public void testConfigWithIgnoreExceptionalAttributes() { + try (MockedConstruction mocked = mockConstruction( + DefaultConfiguration.class, (mock, context) -> { + when(mock.getPropertyNames()).thenReturn(new String[] {"severity"}); + when(mock.getName()).thenReturn("MemberName"); + when(mock.getProperty("severity")).thenThrow(CheckstyleException.class); + })) { + final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> { + ConfigurationLoader.loadConfiguration( + getPath("InputConfigurationLoaderModuleIgnoreSeverity.xml"), + new PropertiesExpander(new Properties()), IgnoredModulesOptions.OMIT); + }); + final String expectedMessage = + "Problem during accessing 'severity' attribute for MemberName"; + assertWithMessage("Invalid exception cause message") + .that(ex) + .hasCauseThat() + .hasMessageThat() + .isEqualTo(expectedMessage); + } + } + } diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java index fb88473a628..7d9424740be 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/PackageObjectFactoryTest.java @@ -19,6 +19,7 @@ package com.puppycrawl.tools.checkstyle; +import static com.google.common.truth.Truth.assertWithMessage; import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.AMBIGUOUS_MODULE_NAME_EXCEPTION_MESSAGE; import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.BASE_PACKAGE; import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.CHECK_SUFFIX; @@ -31,8 +32,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.mockStatic; import java.io.File; +import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; @@ -45,6 +48,8 @@ import java.util.Set; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; @@ -52,6 +57,8 @@ import com.puppycrawl.tools.checkstyle.api.Violation; import com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationLocationCheck; import com.puppycrawl.tools.checkstyle.internal.utils.CheckUtil; +import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil; +import com.puppycrawl.tools.checkstyle.utils.ModuleReflectionUtil; /** * Enter a description of class PackageObjectFactoryTest.java. @@ -393,6 +400,51 @@ public void testGetShortFromFullModuleNamesThirdParty() { "Invalid simple check name"); } + /** + * This method is for testing the case of an exception caught inside + * {@code PackageObjectFactory.generateThirdPartyNameToFullModuleName}, a private method used + * to initialize private field {@code PackageObjectFactory.thirdPartyNameToFullModuleNames}. + * Since the method and the field both are private, the {@link TestUtil} is required to ensure + * that the field is changed. Also, the expected exception should be thrown from the static + * method {@link ModuleReflectionUtil#getCheckstyleModules}, so {@link Mockito#mockStatic} + * is required to mock this exception. + * + * @throws Exception when the code tested throws an exception + */ + @Test + public void testGenerateThirdPartyNameToFullModuleNameWithException() throws Exception { + final String name = "String"; + final String packageName = "java.lang"; + final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + final Set packages = Collections.singleton(packageName); + final PackageObjectFactory objectFactory = new PackageObjectFactory(packages, classLoader, + TRY_IN_ALL_REGISTERED_PACKAGES); + + try (MockedStatic utilities = + mockStatic(ModuleReflectionUtil.class)) { + utilities.when(() -> ModuleReflectionUtil.getCheckstyleModules(packages, classLoader)) + .thenThrow(new IOException("mock exception")); + + final String internalFieldName = "thirdPartyNameToFullModuleNames"; + final Map nullMap = TestUtil.getInternalState(objectFactory, + internalFieldName); + assertWithMessage("Expected uninitialized field") + .that(nullMap) + .isNull(); + + final Object instance = objectFactory.createModule(name); + assertWithMessage("Expected empty string") + .that(instance) + .isEqualTo(""); + + final Map emptyMap = TestUtil.getInternalState(objectFactory, + internalFieldName); + assertWithMessage("Expected empty map") + .that(emptyMap) + .isEmpty(); + } + } + private static final class FailConstructorFileSet extends AbstractFileSetCheck { private FailConstructorFileSet() { diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/PropertyCacheFileTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/PropertyCacheFileTest.java index 04c1f7407cd..73a962b3c0e 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/PropertyCacheFileTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/PropertyCacheFileTest.java @@ -19,12 +19,16 @@ package com.puppycrawl.tools.checkstyle; +import static com.google.common.truth.Truth.assertWithMessage; 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 static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mockStatic; import java.io.BufferedInputStream; import java.io.BufferedReader; @@ -32,10 +36,12 @@ import java.io.File; import java.io.IOException; import java.io.ObjectOutputStream; +import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.nio.file.Files; import java.nio.file.Paths; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.HashSet; import java.util.Locale; import java.util.Properties; @@ -43,10 +49,15 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.MockedStatic; import com.google.common.io.BaseEncoding; import com.google.common.io.ByteStreams; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil; import com.puppycrawl.tools.checkstyle.utils.CommonUtil; public class PropertyCacheFileTest extends AbstractPathTestSupport { @@ -284,4 +295,132 @@ public void testChangeInConfig() throws Exception { assertEquals(1, detailsAfterChangeInConfig.size(), "Invalid cache size"); } + @Test + public void testNonExistentResource() throws IOException { + final Configuration config = new DefaultConfiguration("myName"); + final String filePath = File.createTempFile("junit", null, temporaryFolder).getPath(); + final PropertyCacheFile cache = new PropertyCacheFile(config, filePath); + + // create cache with one file + cache.load(); + final String myFile = "myFile"; + cache.put(myFile, 1); + + final String hash = cache.get(PropertyCacheFile.CONFIG_HASH_KEY); + assertWithMessage("Config hash key should not be null") + .that(hash) + .isNotNull(); + + try (MockedStatic byteStream = mockStatic(ByteStreams.class)) { + byteStream.when(() -> ByteStreams.toByteArray(any(BufferedInputStream.class))) + .thenThrow(IOException.class); + + // apply new external resource to clear cache + final Set resources = new HashSet<>(); + final String resource = getPath("InputPropertyCacheFile.header"); + resources.add(resource); + cache.putExternalResources(resources); + + assertWithMessage("Should return false in file is not in cache") + .that(cache.isInCache(myFile, 1)) + .isFalse(); + + assertWithMessage("Should return false in file is not in cache") + .that(cache.isInCache(resource, 1)) + .isFalse(); + } + } + + @Test + public void testExceptionNoSuchAlgorithmException() throws Exception { + final Configuration config = new DefaultConfiguration("myName"); + final String filePath = File.createTempFile("junit", null, temporaryFolder).getPath(); + final PropertyCacheFile cache = new PropertyCacheFile(config, filePath); + cache.put("myFile", 1); + + try (MockedStatic messageDigest = mockStatic(MessageDigest.class)) { + messageDigest.when(() -> MessageDigest.getInstance("SHA-1")) + .thenThrow(NoSuchAlgorithmException.class); + + final InvocationTargetException ex = + assertThrows(InvocationTargetException.class, () -> { + TestUtil.invokeStaticMethod(PropertyCacheFile.class, + "getHashCodeBasedOnObjectContent", config); + }); + assertWithMessage("Invalid exception cause") + .that(ex) + .hasCauseThat() + .hasCauseThat() + .isInstanceOf(NoSuchAlgorithmException.class); + assertWithMessage("Invalid exception message") + .that(ex) + .hasCauseThat() + .hasMessageThat() + .isEqualTo("Unable to calculate hashcode."); + } + } + + /** + * This test invokes {@code putExternalResources} twice to invalidate cache. + * And asserts that two different exceptions produces different content, + * but two exceptions with same message produces one shared content. + * + * @param rawMessages exception messages separated by ';' + */ + @ParameterizedTest + @ValueSource(strings = {"Same;Same", "First;Second"}) + public void testPutNonExistentExternalResource(String rawMessages) throws Exception { + final File cacheFile = File.createTempFile("junit", null, temporaryFolder); + final String[] messages = rawMessages.split(";"); + // We mock getUriByFilename method of CommonUtil to guarantee that it will + // throw CheckstyleException with the specific content. + try (MockedStatic commonUtil = mockStatic(CommonUtil.class)) { + final int numberOfRuns = messages.length; + final String[] configHashes = new String[numberOfRuns]; + final String[] externalResourceHashes = new String[numberOfRuns]; + for (int i = 0; i < numberOfRuns; i++) { + commonUtil.when(() -> CommonUtil.getUriByFilename(any(String.class))) + .thenThrow(new CheckstyleException(messages[i])); + final Configuration config = new DefaultConfiguration("myConfig"); + final PropertyCacheFile cache = new PropertyCacheFile(config, cacheFile.getPath()); + cache.load(); + + configHashes[i] = cache.get(PropertyCacheFile.CONFIG_HASH_KEY); + assertWithMessage("Config hash key should not be null") + .that(configHashes[i]) + .isNotNull(); + + final Set nonExistentExternalResources = new HashSet<>(); + final String externalResourceFileName = "non_existent_file.xml"; + nonExistentExternalResources.add(externalResourceFileName); + cache.putExternalResources(nonExistentExternalResources); + + externalResourceHashes[i] = cache.get(PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX + + externalResourceFileName); + assertWithMessage("External resource hashes should not be null") + .that(externalResourceHashes[i]) + .isNotNull(); + + cache.persist(); + + final Properties cacheDetails = new Properties(); + try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) { + cacheDetails.load(reader); + } + + assertWithMessage("Unexpected number of objects in cache") + .that(cacheDetails) + .hasSize(2); + } + + assertWithMessage("Invalid config hash") + .that(configHashes[0]) + .isEqualTo(configHashes[1]); + final boolean sameException = messages[0].equals(messages[1]); + assertWithMessage("Invalid external resource hashes") + .that(externalResourceHashes[0].equals(externalResourceHashes[1])) + .isEqualTo(sameException); + } + } + } diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/TreeWalkerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/TreeWalkerTest.java index 6394e70d54b..df0f2c76594 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/TreeWalkerTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/TreeWalkerTest.java @@ -23,6 +23,10 @@ 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.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; import java.io.File; import java.io.Writer; @@ -39,18 +43,23 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.mockito.MockedConstruction; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.internal.util.Checks; import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.Context; +import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.FileText; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck; import com.puppycrawl.tools.checkstyle.checks.coding.EmptyStatementCheck; import com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck; +import com.puppycrawl.tools.checkstyle.checks.design.OneTopLevelClassCheck; import com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck; import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck; import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocParagraphCheck; @@ -96,6 +105,90 @@ public void testProperFileExtension() throws Exception { verify(checkConfig, file.getPath(), expected1); } + /** + * This test is needed for 100% coverage. + * The Pitest reports some conditions as redundant, for example: + *
+     *     if (!collection.isEmpty()) { // This may me omitted.
+     *         Object value = doSomeHardJob();
+     *         for (Item item : collection) {
+     *             item.accept(value);
+     *         }
+     *     }
+     * 
+ * But we really want to avoid calls to {@code doSomeHardJob} method. + * To make this condition mandatory, we need to broke one branch. + * In this case, mocking {@code TreeWalkerAuditEvent} will cause + * {@code getFilteredViolations} to fail. This prevents the condition + *
+     *     if (filters.isEmpty())
+     * 
+ * in {@link TreeWalker#processFiltered(File, FileText)} to survive with Pitest mutations. + * + * @throws Exception if an error occurs + */ + @Test + public void testNoAuditEventsWithoutFilters() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(OneTopLevelClassCheck.class); + final String[] expected = { + "5:1: " + getCheckMessage(OneTopLevelClassCheck.class, + OneTopLevelClassCheck.MSG_KEY, "InputTreeWalkerInner"), + }; + try (MockedConstruction mocked = + Mockito.mockConstruction(TreeWalkerAuditEvent.class, (mock, context) -> { + throw new CheckstyleException("No audit events expected"); + })) { + verify(checkConfig, getPath("InputTreeWalker.java"), expected); + } + } + + /** + * This test is needed for 100% coverage. The method {@link Mockito#mockStatic} is used to + * ensure that the {@code if (!ordinaryChecks.isEmpty())} condition cannot be removed. + */ + @Test + public void testConditionRequiredWithoutOrdinaryChecks() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(JavadocParagraphCheck.class); + final String[] expected = { + "3: " + getCheckMessage(JavadocParagraphCheck.class, + JavadocParagraphCheck.MSG_REDUNDANT_PARAGRAPH), + }; + final String path = getPath("InputTreeWalkerJavadoc.java"); + final DetailAST mockAst = mock(DetailAST.class); + final DetailAST realAst = JavaParser.parseFile(new File(path), + JavaParser.Options.WITH_COMMENTS); + // Ensure that there is no calls to walk(..., AstState.ORDINARY) + doThrow(IllegalStateException.class).when(mockAst).getFirstChild(); + try (MockedStatic parser = Mockito.mockStatic(JavaParser.class)) { + parser.when(() -> JavaParser.parse(any(FileContents.class))).thenReturn(mockAst); + // This will re-enable walk(..., AstState.WITH_COMMENTS) + parser.when(() -> JavaParser.appendHiddenCommentNodes(mockAst)).thenReturn(realAst); + + verify(checkConfig, path, expected); + } + } + + /** + * This test is needed for 100% coverage. The method {@link Mockito#mockStatic} is used to + * ensure that the {@code if (!commentChecks.isEmpty())} condition cannot be removed. + */ + @Test + public void testConditionRequiredWithoutCommentChecks() throws Exception { + final DefaultConfiguration checkConfig = createModuleConfig(OneTopLevelClassCheck.class); + final String[] expected = { + "5:1: " + getCheckMessage(OneTopLevelClassCheck.class, + OneTopLevelClassCheck.MSG_KEY, "InputTreeWalkerInner"), + }; + try (MockedStatic parser = + Mockito.mockStatic(JavaParser.class, CALLS_REAL_METHODS)) { + // Ensure that there is no calls to walk(..., AstState.WITH_COMMENTS) + parser.when(() -> JavaParser.appendHiddenCommentNodes(any(DetailAST.class))) + .thenThrow(IllegalStateException.class); + + verify(checkConfig, getPath("InputTreeWalker.java"), expected); + } + } + @Test public void testImproperFileExtension() throws Exception { final DefaultConfiguration checkConfig = diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/header/HeaderCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/header/HeaderCheckTest.java index 9e0cbc5cbf6..9b086b11e9c 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/header/HeaderCheckTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/header/HeaderCheckTest.java @@ -23,16 +23,20 @@ import static com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck.MSG_MISMATCH; import static com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck.MSG_MISSING; 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.Assertions.assertThrows; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.when; import java.io.File; +import java.io.IOException; +import java.io.LineNumberReader; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.Set; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.mockito.MockedConstruction; import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.DefaultConfiguration; @@ -84,22 +88,22 @@ public void testWhitespaceHeader() throws Exception { public void testNonExistentHeaderFile() throws Exception { final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class); checkConfig.addProperty("headerFile", getPath("nonExistent.file")); - try { + final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> { createChecker(checkConfig); - fail("CheckstyleException is expected"); - } - catch (CheckstyleException ex) { - final String messageStart = "cannot initialize module" - + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" - + " - illegal value "; - final String causeMessageStart = "Unable to find: "; - - assertTrue(ex.getMessage().startsWith(messageStart), - "Invalid exception message, should start with: " + messageStart); - assertTrue( - ex.getCause().getCause().getCause().getMessage().startsWith(causeMessageStart), - "Invalid exception message, should start with: " + causeMessageStart); - } + }); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .startsWith("cannot initialize module" + + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" + + " - illegal value "); + assertWithMessage("Invalid cause exception message") + .that(ex) + .hasCauseThat() + .hasCauseThat() + .hasCauseThat() + .hasMessageThat() + .startsWith("Unable to find: "); } @Test @@ -107,53 +111,60 @@ public void testInvalidCharset() throws Exception { final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class); checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header")); checkConfig.addProperty("charset", "XSO-8859-1"); - try { + final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> { createChecker(checkConfig); - fail("CheckstyleException is expected"); - } - catch (CheckstyleException ex) { - assertEquals("cannot initialize module" - + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" - + " - Cannot set property 'charset' to 'XSO-8859-1'", - ex.getMessage(), "Invalid exception message"); - assertEquals("unsupported charset: 'XSO-8859-1'", - ex.getCause().getCause().getCause().getMessage(), "Invalid exception message"); - } + }); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("cannot initialize module" + + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" + + " - Cannot set property 'charset' to 'XSO-8859-1'"); + assertWithMessage("Invalid cause exception message") + .that(ex) + .hasCauseThat() + .hasCauseThat() + .hasCauseThat() + .hasMessageThat() + .startsWith("unsupported charset: 'XSO-8859-1'"); } @Test - public void testEmptyFilename() throws Exception { + public void testEmptyFilename() { final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class); checkConfig.addProperty("headerFile", ""); - try { + final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> { createChecker(checkConfig); - fail("Checker creation should not succeed with invalid headerFile"); - } - catch (CheckstyleException ex) { - assertEquals("cannot initialize module" - + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" - + " - Cannot set property 'headerFile' to ''", - ex.getMessage(), "Invalid exception message"); - assertEquals("property 'headerFile' is missing or invalid in module" - + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck", - ex.getCause().getCause().getCause().getMessage(), "Invalid exception message"); - } + }); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("cannot initialize module" + + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" + + " - Cannot set property 'headerFile' to ''"); + assertWithMessage("Invalid cause exception message") + .that(ex) + .hasCauseThat() + .hasCauseThat() + .hasCauseThat() + .hasMessageThat() + .isEqualTo("property 'headerFile' is missing or invalid in module" + + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"); } @Test - public void testNullFilename() throws Exception { + public void testNullFilename() { final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class); checkConfig.addProperty("headerFile", null); - try { + final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> { createChecker(checkConfig); - fail("Checker creation should not succeed with null headerFile"); - } - catch (CheckstyleException ex) { - assertEquals("cannot initialize module" - + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" - + " - Cannot set property 'headerFile' to 'null'", - ex.getMessage(), "Invalid exception message"); - } + }); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("cannot initialize module" + + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck" + + " - Cannot set property 'headerFile' to 'null'"); } @Test @@ -181,15 +192,14 @@ public void testIgnore() throws Exception { public void testSetHeaderTwice() { final HeaderCheck check = new HeaderCheck(); check.setHeader("Header"); - try { + final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { check.setHeader("Header2"); - fail("ConversionException is expected"); - } - catch (IllegalArgumentException ex) { - assertEquals("header has already been set - " - + "set either header or headerFile, not both", ex.getMessage(), - "Invalid exception message"); - } + }); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("header has already been set - " + + "set either header or headerFile, not both"); } @Test @@ -197,17 +207,14 @@ public void testIoExceptionWhenLoadingHeaderFile() throws Exception { final HeaderCheck check = new HeaderCheck(); check.setHeaderFile(new URI("test://bad")); - try { + final InvocationTargetException ex = assertThrows(InvocationTargetException.class, () -> { TestUtil.invokeMethod(check, "loadHeaderFile"); - fail("InvocationTargetException expected"); - } - catch (InvocationTargetException ex) { - assertWithMessage("Invalid exception cause message") - .that(ex) - .hasCauseThat() - .hasMessageThat() - .startsWith("unable to load header file "); - } + }); + assertWithMessage("Invalid exception cause message") + .that(ex) + .hasCauseThat() + .hasMessageThat() + .startsWith("unable to load header file "); } @Test @@ -254,21 +261,18 @@ public void testIgnoreLinesSorted() throws Exception { } @Test - public void testLoadHeaderFileTwice() throws Exception { + public void testLoadHeaderFileTwice() { final HeaderCheck check = new HeaderCheck(); check.setHeader("Header"); - try { + final InvocationTargetException ex = assertThrows(InvocationTargetException.class, () -> { TestUtil.invokeMethod(check, "loadHeaderFile"); - fail("InvocationTargetException is expected"); - } - catch (InvocationTargetException ex) { - assertWithMessage("Invalid exception cause message") + }); + assertWithMessage("Invalid exception cause message") .that(ex) - .hasCauseThat() + .hasCauseThat() .hasMessageThat() - .isEqualTo("header has already been set - " - + "set either header or headerFile, not both"); - } + .isEqualTo("header has already been set - " + + "set either header or headerFile, not both"); } @Test @@ -294,4 +298,26 @@ public void testExternalResource() throws Exception { assertEquals(1, results.size(), "Invalid result size"); assertEquals(uri.toString(), results.iterator().next(), "Invalid resource location"); } + + @Test + public void testIoExceptionWhenLoadingHeader() { + final HeaderCheck check = new HeaderCheck(); + try (MockedConstruction mocked = mockConstruction( + LineNumberReader.class, (mock, context) -> { + when(mock.readLine()).thenThrow(IOException.class); + })) { + final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { + check.setHeader("header"); + }); + assertWithMessage("Invalid exception cause") + .that(ex) + .hasCauseThat() + .isInstanceOf(IOException.class); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("unable to load header"); + } + } + } diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoaderTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoaderTest.java index 18dc98b04c3..b5620dc9e9b 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoaderTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoaderTest.java @@ -19,22 +19,31 @@ package com.puppycrawl.tools.checkstyle.checks.imports; +import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; 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.Assertions.fail; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URI; +import java.net.URL; import org.junit.jupiter.api.Test; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; import org.xml.sax.helpers.AttributesImpl; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; @@ -124,4 +133,27 @@ public void testLoadThrowsException() throws Exception { } } + @Test + public void testInputStreamFailsOnRead() throws Exception { + try (InputStream inputStream = mock(InputStream.class)) { + final int available = doThrow(IOException.class).when(inputStream).available(); + final URL url = mock(URL.class); + when(url.openStream()).thenReturn(inputStream); + final URI uri = mock(URI.class); + when(uri.toURL()).thenReturn(url); + + final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> { + ImportControlLoader.load(uri); + }); + assertWithMessage("Invalid exception class") + .that(ex) + .hasCauseThat() + .isInstanceOf(SAXParseException.class); + // Workaround for warning "Result of InputStream.available() is ignored" + assertWithMessage("") + .that(available) + .isEqualTo(0); + } + } + } diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/AuditEventDefaultFormatterPowerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/AuditEventDefaultFormatterPowerTest.java deleted file mode 100644 index b76e6e5c392..00000000000 --- a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/AuditEventDefaultFormatterPowerTest.java +++ /dev/null @@ -1,72 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2021 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.internal.powermock; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.when; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.puppycrawl.tools.checkstyle.AuditEventDefaultFormatter; -import com.puppycrawl.tools.checkstyle.AuditEventFormatter; -import com.puppycrawl.tools.checkstyle.api.AuditEvent; -import com.puppycrawl.tools.checkstyle.api.SeverityLevel; - -@RunWith(PowerMockRunner.class) -@PrepareForTest(AuditEvent.class) -public class AuditEventDefaultFormatterPowerTest { - - @Test - public void testFormatModuleNameContainsCheckSuffix() { - final AuditEvent mock = PowerMockito.mock(AuditEvent.class); - when(mock.getSourceName()).thenReturn("TestModuleCheck"); - when(mock.getSeverityLevel()).thenReturn(SeverityLevel.WARNING); - when(mock.getLine()).thenReturn(1); - when(mock.getColumn()).thenReturn(1); - when(mock.getMessage()).thenReturn("Mocked message."); - when(mock.getFileName()).thenReturn("InputMockFile.java"); - final AuditEventFormatter formatter = new AuditEventDefaultFormatter(); - - final String expected = "[WARN] InputMockFile.java:1:1: Mocked message. [TestModule]"; - - assertEquals("Invalid format", expected, formatter.format(mock)); - } - - @Test - public void testFormatModuleNameDoesNotContainCheckSuffix() { - final AuditEvent mock = PowerMockito.mock(AuditEvent.class); - when(mock.getSourceName()).thenReturn("TestModule"); - when(mock.getSeverityLevel()).thenReturn(SeverityLevel.WARNING); - when(mock.getLine()).thenReturn(1); - when(mock.getColumn()).thenReturn(1); - when(mock.getMessage()).thenReturn("Mocked message."); - when(mock.getFileName()).thenReturn("InputMockFile.java"); - final AuditEventFormatter formatter = new AuditEventDefaultFormatter(); - - final String expected = "[WARN] InputMockFile.java:1:1: Mocked message. [TestModule]"; - - assertEquals("Invalid format", expected, formatter.format(mock)); - } - -} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/CommonUtilPowerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/CommonUtilPowerTest.java deleted file mode 100644 index 9a8f0e581bb..00000000000 --- a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/CommonUtilPowerTest.java +++ /dev/null @@ -1,66 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2021 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.internal.powermock; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; - -import java.net.URISyntaxException; -import java.net.URL; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; -import com.puppycrawl.tools.checkstyle.utils.CommonUtil; -import com.puppycrawl.tools.checkstyle.utils.CommonUtilTest; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({ CommonUtil.class, CommonUtilTest.class }) -public class CommonUtilPowerTest { - - @Test - public void testLoadSuppressionsUriSyntaxException() throws Exception { - final URL configUrl = mock(URL.class); - - when(configUrl.toURI()).thenThrow(URISyntaxException.class); - mockStatic(CommonUtil.class, Mockito.CALLS_REAL_METHODS); - final String fileName = "/suppressions_none.xml"; - when(CommonUtil.class.getResource(fileName)).thenReturn(configUrl); - - try { - CommonUtil.getUriByFilename(fileName); - fail("Exception is expected"); - } - catch (CheckstyleException ex) { - assertTrue("Invalid exception cause", ex.getCause() instanceof URISyntaxException); - assertEquals("Invalid exception message", - "Unable to find: " + fileName, ex.getMessage()); - } - } - -} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/ConfigurationLoaderPowerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/ConfigurationLoaderPowerTest.java deleted file mode 100644 index fc5e4d01f09..00000000000 --- a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/ConfigurationLoaderPowerTest.java +++ /dev/null @@ -1,82 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2021 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.internal.powermock; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.powermock.api.mockito.PowerMockito.when; - -import java.util.Properties; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport; -import com.puppycrawl.tools.checkstyle.ConfigurationLoader; -import com.puppycrawl.tools.checkstyle.ConfigurationLoader.IgnoredModulesOptions; -import com.puppycrawl.tools.checkstyle.DefaultConfiguration; -import com.puppycrawl.tools.checkstyle.PropertiesExpander; -import com.puppycrawl.tools.checkstyle.ThreadModeSettings; -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({DefaultConfiguration.class, ConfigurationLoader.class}) -public class ConfigurationLoaderPowerTest extends AbstractPathTestSupport { - - @Override - protected String getPackageLocation() { - return "com/puppycrawl/tools/checkstyle/configurationloader"; - } - - @Test - public void testConfigWithIgnoreExceptionalAttributes() throws Exception { - // emulate exception from unrelated code, but that is same try-catch - final DefaultConfiguration tested = PowerMockito.mock(DefaultConfiguration.class); - when(tested.getPropertyNames()).thenReturn(new String[] {"severity"}); - when(tested.getName()).thenReturn("MemberName"); - when(tested.getProperty("severity")).thenThrow(CheckstyleException.class); - // to void creation of 2 other mocks for now reason, only one moc is used for all cases - PowerMockito.whenNew(DefaultConfiguration.class) - .withArguments("MemberName", ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE) - .thenReturn(tested); - PowerMockito.whenNew(DefaultConfiguration.class) - .withArguments("Checker", ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE) - .thenReturn(tested); - PowerMockito.whenNew(DefaultConfiguration.class) - .withArguments("TreeWalker", ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE) - .thenReturn(tested); - - try { - ConfigurationLoader.loadConfiguration( - getPath("InputConfigurationLoaderModuleIgnoreSeverity.xml"), - new PropertiesExpander(new Properties()), IgnoredModulesOptions.OMIT); - fail("Exception is expected"); - } - catch (CheckstyleException expected) { - assertEquals("Invalid exception cause message", - "Problem during accessing 'severity' attribute for MemberName", - expected.getCause().getMessage()); - } - } - -} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/HeaderCheckPowerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/HeaderCheckPowerTest.java deleted file mode 100644 index 4ec1aa6710b..00000000000 --- a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/HeaderCheckPowerTest.java +++ /dev/null @@ -1,71 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2021 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.internal.powermock; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; - -import java.io.IOException; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport; -import com.puppycrawl.tools.checkstyle.checks.header.AbstractHeaderCheck; -import com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck; -import com.puppycrawl.tools.checkstyle.checks.header.HeaderCheckTest; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({ HeaderCheck.class, HeaderCheckTest.class, AbstractHeaderCheck.class }) -public class HeaderCheckPowerTest extends AbstractModuleTestSupport { - - @Override - protected String getPackageLocation() { - return "com/puppycrawl/tools/checkstyle/checks/header/header"; - } - - /** - * This test needs powermock because {@code StringReader} can't throw an exception to trigger - * the catch otherwise unless the reader is mishandled. - * - * @throws Exception if there is an error. - */ - @Test - public void testIoExceptionWhenLoadingHeader() throws Exception { - final HeaderCheck check = PowerMockito.spy(new HeaderCheck()); - PowerMockito.doThrow(new IOException("expected exception")).when(check, "loadHeader", - any()); - - try { - check.setHeader("header"); - fail("Exception expected"); - } - catch (IllegalArgumentException ex) { - assertTrue("Invalid exception cause", ex.getCause() instanceof IOException); - assertEquals("Invalid exception message", "unable to load header", ex.getMessage()); - } - } - -} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/ImportControlLoaderPowerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/ImportControlLoaderPowerTest.java deleted file mode 100644 index 800cbb8cf03..00000000000 --- a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/ImportControlLoaderPowerTest.java +++ /dev/null @@ -1,68 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2021 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.internal.powermock; - -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URL; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.BDDMockito; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.xml.sax.SAXParseException; - -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; -import com.puppycrawl.tools.checkstyle.checks.imports.ImportControlLoader; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({ImportControlLoader.class, URI.class}) -public class ImportControlLoaderPowerTest { - - @Test - public void testInputStreamFailsOnRead() throws Exception { - final InputStream inputStream = PowerMockito.mock(InputStream.class); - final int available = Mockito.doThrow(IOException.class).when(inputStream).available(); - - final URL url = PowerMockito.mock(URL.class); - BDDMockito.given(url.openStream()).willReturn(inputStream); - - final URI uri = PowerMockito.mock(URI.class); - BDDMockito.given(uri.toURL()).willReturn(url); - - try { - ImportControlLoader.load(uri); - // Using available to bypass 'ignored result' warning - fail("exception expected " + available); - } - catch (CheckstyleException ex) { - assertSame("Invalid exception class", - SAXParseException.class, ex.getCause().getClass()); - } - } - -} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/PackageObjectFactoryPowerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/PackageObjectFactoryPowerTest.java deleted file mode 100644 index 1e17ba4e528..00000000000 --- a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/PackageObjectFactoryPowerTest.java +++ /dev/null @@ -1,86 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2021 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.internal.powermock; - -import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.ModuleLoadOption.TRY_IN_ALL_REGISTERED_PACKAGES; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.powermock.api.mockito.PowerMockito.doThrow; -import static org.powermock.api.mockito.PowerMockito.mockStatic; - -import java.io.IOException; -import java.util.Collections; -import java.util.Map; -import java.util.Set; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.puppycrawl.tools.checkstyle.PackageObjectFactory; -import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil; -import com.puppycrawl.tools.checkstyle.utils.ModuleReflectionUtil; - -@RunWith(PowerMockRunner.class) -@PowerMockIgnore(value = "com.puppycrawl.tools.checkstyle.api.*", globalIgnore = false) -@PrepareForTest(ModuleReflectionUtil.class) -public class PackageObjectFactoryPowerTest { - - /** - * This method is for testing the case of an exception caught inside - * {@code PackageObjectFactory.generateThirdPartyNameToFullModuleName}, a private method used - * to initialize private field {@code PackageObjectFactory.thirdPartyNameToFullModuleNames}. - * Since the method and the field both are private, the {@link TestUtil#getInternalState} is - * required to ensure that the field is changed. Also, the expected exception should be thrown - * from the static method {@link ModuleReflectionUtil#getCheckstyleModules}, so - * {@link PowerMockito#mockStatic} is required to mock this exception. - * - * @throws Exception when the code tested throws an exception - */ - @Test - public void testGenerateThirdPartyNameToFullModuleNameWithException() throws Exception { - final String name = "String"; - final String packageName = "java.lang"; - final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - final Set packages = Collections.singleton(packageName); - final PackageObjectFactory objectFactory = new PackageObjectFactory(packages, classLoader, - TRY_IN_ALL_REGISTERED_PACKAGES); - - mockStatic(ModuleReflectionUtil.class); - doThrow(new IOException("mock exception")).when(ModuleReflectionUtil.class); - ModuleReflectionUtil.getCheckstyleModules(packages, classLoader); - - final String internalFieldName = "thirdPartyNameToFullModuleNames"; - final Map nullMap = TestUtil.getInternalState(objectFactory, - internalFieldName); - assertNull("Expected uninitialized field", nullMap); - - final Object instance = objectFactory.createModule(name); - assertEquals("Expected empty string", "", instance); - - final Map emptyMap = TestUtil.getInternalState(objectFactory, - internalFieldName); - assertEquals("Expected empty map", Collections.emptyMap(), emptyMap); - } - -} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/PropertyCacheFilePowerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/PropertyCacheFilePowerTest.java deleted file mode 100644 index 36603b1438e..00000000000 --- a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/PropertyCacheFilePowerTest.java +++ /dev/null @@ -1,247 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2021 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.internal.powermock; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.any; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.file.Files; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.google.common.io.ByteStreams; -import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport; -import com.puppycrawl.tools.checkstyle.DefaultConfiguration; -import com.puppycrawl.tools.checkstyle.PropertyCacheFile; -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; -import com.puppycrawl.tools.checkstyle.api.Configuration; -import com.puppycrawl.tools.checkstyle.utils.CommonUtil; - -@RunWith(PowerMockRunner.class) -@PrepareForTest({ PropertyCacheFile.class, ByteStreams.class, - CommonUtil.class}) -public class PropertyCacheFilePowerTest extends AbstractPathTestSupport { - - @Rule - public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Override - protected String getPackageLocation() { - return "com/puppycrawl/tools/checkstyle/propertycachefile"; - } - - /** - * This SuppressWarning("unchecked") required to suppress - * "Unchecked generics array creation for varargs parameter" during mock. - * - * @throws IOException when smth wrong with file creation or cache.load - */ - @Test - public void testNonExistentResource() throws IOException { - final Configuration config = new DefaultConfiguration("myName"); - final String filePath = temporaryFolder.newFile().getPath(); - final PropertyCacheFile cache = new PropertyCacheFile(config, filePath); - - // create cache with one file - cache.load(); - final String myFile = "myFile"; - cache.put(myFile, 1); - - final String hash = cache.get(PropertyCacheFile.CONFIG_HASH_KEY); - assertNotNull("Config hash key should not be null", hash); - - mockStatic(ByteStreams.class); - - when(ByteStreams.toByteArray(any(BufferedInputStream.class))) - .thenThrow(IOException.class); - - // apply new external resource to clear cache - final Set resources = new HashSet<>(); - final String resource = getPath("InputPropertyCacheFile.header"); - resources.add(resource); - cache.putExternalResources(resources); - - assertFalse("Should return false in file is not in cache", - cache.isInCache(myFile, 1)); - assertFalse("Should return false in file is not in cache", - cache.isInCache(resource, 1)); - } - - @Test - public void testExceptionNoSuchAlgorithmException() throws Exception { - final Configuration config = new DefaultConfiguration("myName"); - final String filePath = temporaryFolder.newFile().getPath(); - final PropertyCacheFile cache = new PropertyCacheFile(config, filePath); - cache.put("myFile", 1); - mockStatic(MessageDigest.class); - - when(MessageDigest.getInstance("SHA-1")) - .thenThrow(NoSuchAlgorithmException.class); - - final Class[] param = new Class[1]; - param[0] = Serializable.class; - final Method method = - PropertyCacheFile.class.getDeclaredMethod("getHashCodeBasedOnObjectContent", param); - method.setAccessible(true); - try { - method.invoke(cache, config); - fail("InvocationTargetException is expected"); - } - catch (InvocationTargetException ex) { - assertTrue("Invalid exception cause", - ex.getCause().getCause() instanceof NoSuchAlgorithmException); - assertEquals("Invalid exception message", - "Unable to calculate hashcode.", ex.getCause().getMessage()); - } - } - - @Test - public void testPutNonExistentExternalResourceSameExceptionBetweenRuns() throws Exception { - final File cacheFile = temporaryFolder.newFile(); - - // We mock getUriByFilename method of CommonUtil to guarantee that it will - // throw CheckstyleException with the specific content. - mockStatic(CommonUtil.class); - final CheckstyleException mockException = - new CheckstyleException("Cannot get URL for cache file " + cacheFile.getAbsolutePath()); - when(CommonUtil.getUriByFilename(any(String.class))) - .thenThrow(mockException); - - // We invoke 'putExternalResources' twice to invalidate cache - // and have two identical exceptions which the equal content - final int numberOfRuns = 2; - final String[] configHashes = new String[numberOfRuns]; - final String[] externalResourceHashes = new String[numberOfRuns]; - for (int i = 0; i < numberOfRuns; i++) { - final Configuration config = new DefaultConfiguration("myConfig"); - final PropertyCacheFile cache = new PropertyCacheFile(config, cacheFile.getPath()); - cache.load(); - - configHashes[i] = cache.get(PropertyCacheFile.CONFIG_HASH_KEY); - assertNotNull("Config hash key should not be null", configHashes[i]); - - final Set nonExistentExternalResources = new HashSet<>(); - final String externalResourceFileName = "non_existent_file.xml"; - nonExistentExternalResources.add(externalResourceFileName); - cache.putExternalResources(nonExistentExternalResources); - - externalResourceHashes[i] = cache.get(PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX - + externalResourceFileName); - assertNotNull("External resource hashes should not be null", - externalResourceHashes[i]); - - cache.persist(); - - final Properties cacheDetails = new Properties(); - try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) { - cacheDetails.load(reader); - } - - final int expectedNumberOfObjectsInCacheFile = 2; - assertEquals("Unexpected number of objects in cache", - expectedNumberOfObjectsInCacheFile, cacheDetails.size()); - } - - assertEquals("Invalid config hash", configHashes[0], configHashes[1]); - assertEquals("Invalid external resource hashes", - externalResourceHashes[0], externalResourceHashes[1]); - } - - /** - * It is OK to have long test method name here as it describes the test purpose. - */ - @Test - public void testPutNonExistentExternalResourceDifferentExceptionsBetweenRuns() - throws Exception { - final File cacheFile = temporaryFolder.newFile(); - - // We invoke 'putExternalResources' twice to invalidate cache - // and have two different exceptions with different content. - final int numberOfRuns = 2; - final String[] configHashes = new String[numberOfRuns]; - final String[] externalResourceHashes = new String[numberOfRuns]; - for (int i = 0; i < numberOfRuns; i++) { - final Configuration config = new DefaultConfiguration("myConfig"); - final PropertyCacheFile cache = new PropertyCacheFile(config, cacheFile.getPath()); - - // We mock getUriByFilename method of CommonUtil to guarantee that it will - // throw CheckstyleException with the specific content. - mockStatic(CommonUtil.class); - final CheckstyleException mockException = new CheckstyleException("Exception #" + i); - when(CommonUtil.getUriByFilename(any(String.class))) - .thenThrow(mockException); - - cache.load(); - - configHashes[i] = cache.get(PropertyCacheFile.CONFIG_HASH_KEY); - assertNotNull("Config hash key should not be null", configHashes[i]); - - final Set nonExistentExternalResources = new HashSet<>(); - final String externalResourceFileName = "non_existent_file.xml"; - nonExistentExternalResources.add(externalResourceFileName); - cache.putExternalResources(nonExistentExternalResources); - - externalResourceHashes[i] = cache.get(PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX - + externalResourceFileName); - assertNotNull("External resource hashes should not be null", - externalResourceHashes[i]); - - cache.persist(); - - final Properties cacheDetails = new Properties(); - try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) { - cacheDetails.load(reader); - } - - final int expectedNumberOfObjectsInCacheFile = 2; - assertEquals("Unexpected number of objects in cache", - expectedNumberOfObjectsInCacheFile, cacheDetails.size()); - } - - assertEquals("Invalid config hash", configHashes[0], configHashes[1]); - assertNotEquals("Invalid external resource hashes", - externalResourceHashes[0], externalResourceHashes[1]); - } - -} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/TreeWalkerPowerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/TreeWalkerPowerTest.java deleted file mode 100644 index 0a24cc6dad7..00000000000 --- a/src/test/java/com/puppycrawl/tools/checkstyle/internal/powermock/TreeWalkerPowerTest.java +++ /dev/null @@ -1,105 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2021 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.internal.powermock; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; -import static org.powermock.api.mockito.PowerMockito.spy; -import static org.powermock.api.mockito.PowerMockito.verifyPrivate; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport; -import com.puppycrawl.tools.checkstyle.PackageObjectFactory; -import com.puppycrawl.tools.checkstyle.TreeWalker; -import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.FileContents; -import com.puppycrawl.tools.checkstyle.api.FileText; -import com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck; -import com.puppycrawl.tools.checkstyle.checks.naming.TypeNameCheck; -import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil; - -@RunWith(PowerMockRunner.class) -@PrepareForTest(TreeWalker.class) -public class TreeWalkerPowerTest extends AbstractModuleTestSupport { - - @Rule - public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Override - protected String getPackageLocation() { - return "com/puppycrawl/tools/checkstyle/treewalker"; - } - - @Test - public void testBehaviourWithOnlyOrdinaryChecks() throws Exception { - final TreeWalker treeWalkerSpy = spy(new TreeWalker()); - final Class classAstState = - Class.forName("com.puppycrawl.tools.checkstyle.TreeWalker$AstState"); - final PackageObjectFactory factory = new PackageObjectFactory( - new HashSet<>(), Thread.currentThread().getContextClassLoader()); - treeWalkerSpy.configure(createModuleConfig(TypeNameCheck.class)); - treeWalkerSpy.setModuleFactory(factory); - treeWalkerSpy.setupChild(createModuleConfig(TypeNameCheck.class)); - final File file = temporaryFolder.newFile("file.java"); - final List lines = new ArrayList<>(); - lines.add("class Test {}"); - final FileText fileText = new FileText(file, lines); - treeWalkerSpy.setFileContents(new FileContents(fileText)); - TestUtil.invokeMethod(treeWalkerSpy, "processFiltered", file, fileText); - verifyPrivate(treeWalkerSpy, times(1)).invoke("walk", - any(DetailAST.class), any(FileContents.class), any(classAstState)); - verifyPrivate(treeWalkerSpy, times(0)).invoke("getFilteredViolations", - any(String.class), any(FileContents.class), any(DetailAST.class)); - } - - @Test - public void testBehaviourWithOnlyCommentChecks() throws Exception { - final TreeWalker treeWalkerSpy = spy(new TreeWalker()); - final Class classAstState = - Class.forName("com.puppycrawl.tools.checkstyle.TreeWalker$AstState"); - final PackageObjectFactory factory = new PackageObjectFactory( - new HashSet<>(), Thread.currentThread().getContextClassLoader()); - treeWalkerSpy.configure(createModuleConfig(CommentsIndentationCheck.class)); - treeWalkerSpy.setModuleFactory(factory); - treeWalkerSpy.setupChild(createModuleConfig(CommentsIndentationCheck.class)); - final File file = temporaryFolder.newFile("file.java"); - final List lines = new ArrayList<>(); - lines.add("class Test {}"); - final FileText fileText = new FileText(file, lines); - treeWalkerSpy.setFileContents(new FileContents(fileText)); - TestUtil.invokeMethod(treeWalkerSpy, "processFiltered", file, fileText); - verifyPrivate(treeWalkerSpy, times(1)).invoke("walk", - any(DetailAST.class), any(FileContents.class), any(classAstState)); - verifyPrivate(treeWalkerSpy, times(0)).invoke("getFilteredViolations", - any(String.class), any(FileContents.class), any(DetailAST.class)); - } - -} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/utils/CommonUtilTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/utils/CommonUtilTest.java index b726d9d2a8d..9e3f0565cfa 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/utils/CommonUtilTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/utils/CommonUtilTest.java @@ -20,6 +20,7 @@ package com.puppycrawl.tools.checkstyle.utils; import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; @@ -29,15 +30,20 @@ import static org.hamcrest.MatcherAssert.assertThat; 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.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.CALLS_REAL_METHODS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.util.Dictionary; import java.util.Properties; @@ -45,10 +51,12 @@ import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport; import com.puppycrawl.tools.checkstyle.ConfigurationLoader; import com.puppycrawl.tools.checkstyle.PropertiesExpander; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; public class CommonUtilTest extends AbstractPathTestSupport { @@ -107,26 +115,24 @@ public void testCreatePattern() { @Test public void testBadRegex() { - try { + final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { CommonUtil.createPattern("["); - fail("exception expected"); - } - catch (IllegalArgumentException ex) { - assertEquals("Failed to initialise regular expression [", ex.getMessage(), - "Invalid exception message"); - } + }); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("Failed to initialise regular expression ["); } @Test public void testBadRegex2() { - try { + final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> { CommonUtil.createPattern("[", Pattern.MULTILINE); - fail("exception expected"); - } - catch (IllegalArgumentException ex) { - assertEquals("Failed to initialise regular expression [", ex.getMessage(), - "Invalid exception message"); - } + }); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("Failed to initialise regular expression ["); } @Test @@ -212,14 +218,13 @@ public void testGetExistingConstructor() throws NoSuchMethodException { @Test public void testGetNonExistentConstructor() { - try { + final IllegalStateException ex = assertThrows(IllegalStateException.class, () -> { CommonUtil.getConstructor(Math.class); - fail("IllegalStateException is expected"); - } - catch (IllegalStateException expected) { - assertSame(NoSuchMethodException.class, expected.getCause().getClass(), - "Invalid exception cause"); - } + }); + assertWithMessage("Invalid exception cause") + .that(ex) + .hasCauseThat() + .isInstanceOf(NoSuchMethodException.class); } @Test @@ -235,15 +240,13 @@ public void testInvokeConstructor() throws NoSuchMethodException { @Test public void testInvokeConstructorThatFails() throws NoSuchMethodException { final Constructor constructor = Dictionary.class.getConstructor(); - - try { + final IllegalStateException ex = assertThrows(IllegalStateException.class, () -> { CommonUtil.invokeConstructor(constructor); - fail("IllegalStateException is expected"); - } - catch (IllegalStateException expected) { - assertSame(InstantiationException.class, - expected.getCause().getClass(), "Invalid exception cause"); - } + }); + assertWithMessage("Invalid exception cause") + .that(ex) + .hasCauseThat() + .isInstanceOf(InstantiationException.class); } @Test @@ -258,15 +261,15 @@ public void testClose() { @Test public void testCloseWithException() { - try { + final IllegalStateException ex = assertThrows(IllegalStateException.class, () -> { CommonUtil.close(() -> { throw new IOException("Test IOException"); }); - fail("exception expected"); - } - catch (IllegalStateException ex) { - assertEquals("Cannot close the stream", ex.getMessage(), "Invalid exception message"); - } + }); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("Cannot close the stream"); } @Test @@ -499,6 +502,30 @@ public void testIsCodePointWhitespace() { .isFalse(); } + @Test + public void testLoadSuppressionsUriSyntaxException() throws Exception { + final URL configUrl = mock(URL.class); + when(configUrl.toURI()).thenThrow(URISyntaxException.class); + try (MockedStatic utilities = + mockStatic(CommonUtil.class, CALLS_REAL_METHODS)) { + final String fileName = "/suppressions_none.xml"; + utilities.when(() -> CommonUtil.getCheckstyleResource(fileName)) + .thenReturn(configUrl); + + final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> { + CommonUtil.getUriByFilename(fileName); + }); + assertWithMessage("Invalid exception cause") + .that(ex) + .hasCauseThat() + .isInstanceOf(URISyntaxException.class); + assertWithMessage("Invalid exception message") + .that(ex) + .hasMessageThat() + .isEqualTo("Unable to find: " + fileName); + } + } + private static class TestCloseable implements Closeable { private boolean closed; diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/treewalker/InputTreeWalkerJavadoc.java b/src/test/resources/com/puppycrawl/tools/checkstyle/treewalker/InputTreeWalkerJavadoc.java new file mode 100644 index 00000000000..b04ad091866 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/treewalker/InputTreeWalkerJavadoc.java @@ -0,0 +1,5 @@ +package com.puppycrawl.tools.checkstyle.treewalker; + +/**

Javadoc comment. */ // violation +public class InputTreeWalkerJavadoc { +} diff --git a/src/test/resources/org/powermock/extensions/configuration.properties b/src/test/resources/org/powermock/extensions/configuration.properties deleted file mode 100644 index ce04b51fd08..00000000000 --- a/src/test/resources/org/powermock/extensions/configuration.properties +++ /dev/null @@ -1 +0,0 @@ -powermock.global-ignore=com.sun.org.apache.xerces.*,javax.xml.parsers.*,org.w3c.dom.*,org.xml.sax.*