package io.jenkins.plugins.analysis.warnings.steps; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; import org.junit.Test; import edu.hm.hafner.analysis.Issue; import hudson.model.FreeStyleProject; import hudson.model.Result; import io.jenkins.plugins.analysis.core.filter.ExcludeCategory; import io.jenkins.plugins.analysis.core.filter.ExcludeFile; import io.jenkins.plugins.analysis.core.filter.ExcludeModule; import io.jenkins.plugins.analysis.core.filter.ExcludePackage; import io.jenkins.plugins.analysis.core.filter.ExcludeType; import io.jenkins.plugins.analysis.core.filter.IncludeCategory; import io.jenkins.plugins.analysis.core.filter.IncludeFile; import io.jenkins.plugins.analysis.core.filter.IncludeModule; import io.jenkins.plugins.analysis.core.filter.IncludePackage; import io.jenkins.plugins.analysis.core.filter.IncludeType; import io.jenkins.plugins.analysis.core.filter.RegexpFilter; import io.jenkins.plugins.analysis.core.model.AnalysisResult; import io.jenkins.plugins.analysis.core.testutil.IntegrationTestWithJenkinsPerSuite; import io.jenkins.plugins.analysis.warnings.Pmd; import io.jenkins.plugins.analysis.warnings.checkstyle.CheckStyle; import static org.assertj.core.api.Assertions.*; /** * Integration tests of the regex property filters. * * @author Manuel Hampp */ @SuppressWarnings("ClassDataAbstractionCoupling") public class FiltersITest extends IntegrationTestWithJenkinsPerSuite { private static final String MODULE_FILTER = "module-filter/"; /** * Tests the module expression filter: provides a pom.xml in the workspace so that modules are correctly assigned. */ @Test public void shouldFilterPmdIssuesByModule() { Map<RegexpFilter, Integer[]> expectedLinesByFilter = setupModuleFilterForPmd(); for (Entry<RegexpFilter, Integer[]> entry : expectedLinesByFilter.entrySet()) { FreeStyleProject project = createFreeStyleProject(); copyDirectoryToWorkspace(project, MODULE_FILTER); enableWarnings(project, recorder -> recorder.setFilters(toFilter(entry)), createTool(new Pmd(), "**/pmd.xml")); buildAndVerifyResults(project, entry.getValue()); } } /** * Provides a map, that contains the filters and the line numbers that are expected to remain after filtering. * * @return the mapping */ private Map<RegexpFilter, Integer[]> setupModuleFilterForPmd() { /* CopyToClipboard.java:54 com.avaloq.adt.env.internal.ui.actions Basic CollapsibleIfStatements Normal 1 ChangeSelectionAction.java:14 com.avaloq.adt.env.internal.ui.actions.change Import Statement Rules UnusedImports Normal 1 */ Map<RegexpFilter, Integer[]> filterResultMap = new HashMap<>(); filterResultMap.put(new ExcludeModule("m1"), new Integer[] {14}); filterResultMap.put(new IncludeModule("m1"), new Integer[] {54}); return filterResultMap; } /** * Tests the category and file expression filter by comparing the result with expected. */ @Test public void shouldFilterCheckStyleIssuesByCategoryAndFile() { Map<RegexpFilter, Integer[]> expectedLinesByFilter = setupCategoryFilterForCheckStyle(); for (Entry<RegexpFilter, Integer[]> entry : expectedLinesByFilter.entrySet()) { FreeStyleProject project = createFreeStyleProjectWithWorkspaceFiles("checkstyle-filtering.xml"); enableGenericWarnings(project, recorder -> recorder.setFilters(toFilter(entry)), new CheckStyle()); buildAndVerifyResults(project, entry.getValue()); } } /** * Provides a map, that contains the filters and the line numbers that are expected to remain after filtering. * * @return the mapping */ private Map<RegexpFilter, Integer[]> setupCategoryFilterForCheckStyle() { /* CsharpNamespaceDetector.java:30 -Blocks RightCurlyCheck High 1 CsharpNamespaceDetector.java:37 -Blocks RightCurlyCheck High 1 CsharpNamespaceDetector.java:17 -Design DesignForExtensionCheck High 1 CsharpNamespaceDetector.java:22 -Design DesignForExtensionCheck High 1 CsharpNamespaceDetector.java:42 -Sizes LineLengthCheck High 1 CsharpNamespaceDetector.java:29 -Sizes LineLengthCheck High 1 FileFinder.java:99 -Blocks RightCurlyCheck High 1 */ Map<RegexpFilter, Integer[]> filterResultMap = new HashMap<>(); filterResultMap.put(new IncludeCategory("Blocks"), new Integer[] {30, 37, 99}); filterResultMap.put(new ExcludeCategory("Blocks"), new Integer[] {17, 22, 42, 29}); filterResultMap.put(new ExcludeCategory("(Blocks|Design)"), new Integer[] {42, 29}); filterResultMap.put(new IncludeCategory("(Blocks|Design)"), new Integer[] {30, 37, 17, 22, 99}); filterResultMap.put(new ExcludeFile(".*Csharp.*"), new Integer[] {99}); filterResultMap.put(new IncludeFile(".*Csharp.*"), new Integer[] {30, 37, 17, 22, 42, 29}); return filterResultMap; } /** * Tests the package and type expression filter by comparing the result with expected. */ @Test public void shouldFilterPmdIssuesByPackageAndType() { Map<RegexpFilter, Integer[]> typeFiltersWithResult = setupCategoryFilterForPmd(); for (Entry<RegexpFilter, Integer[]> entry : typeFiltersWithResult.entrySet()) { FreeStyleProject project = createFreeStyleProjectWithWorkspaceFiles("pmd-warnings.xml"); enableGenericWarnings(project, recorder -> recorder.setFilters(toFilter(entry)), new Pmd()); buildAndVerifyResults(project, entry.getValue()); } } /** * Provides a map, that contains the filters and the line numbers that are expected to remain after filtering. * * @return the mapping */ private Map<RegexpFilter, Integer[]> setupCategoryFilterForPmd() { /* CopyToClipboard.java:54 com.avaloq.adt.env.internal.ui.actions Basic CollapsibleIfStatements Normal 1 ChangeSelectionAction.java:14 com.avaloq.adt.env.internal.ui.actions.change Import Statement Rules UnusedImports Normal 1 SelectSourceDialog.java:938 com.avaloq.adt.env.internal.ui.dialogs Basic Rules EmptyCatchBlock Low 1 SelectSourceDialog.java:980 com.avaloq.adt.env.internal.ui.dialogs Basic Rules EmptyCatchBlock High 1 */ HashMap<RegexpFilter, Integer[]> filterResultMap = new HashMap<>(); filterResultMap.put(new IncludePackage(".*actions"), new Integer[] {54, 14}); filterResultMap.put(new IncludePackage(".*actions.*"), new Integer[] {54, 14}); filterResultMap.put(new ExcludePackage(".*actions.*"), new Integer[] {938, 980}); filterResultMap.put(new ExcludePackage(".*actions"), new Integer[] {938, 980}); filterResultMap.put(new IncludeType(".*EmptyCatchBlock"), new Integer[] {938, 980}); filterResultMap.put(new ExcludeType(".*EmptyCatchBlock"), new Integer[] {54, 14}); return filterResultMap; } /** * Validates the filtered issues in the projects. Asserts that only issues with the specified lines are retained. * * @param project * project that contains the issues to compare * @param expectedLines * issue line numbers that are expected */ private void buildAndVerifyResults(final FreeStyleProject project, final Integer... expectedLines) { AnalysisResult result = scheduleBuildAndAssertStatus(project, Result.SUCCESS); assertThat(getLines(result)).containsOnly(expectedLines); } private List<Integer> getLines(final AnalysisResult result) { return result.getIssues() .stream() .map(Issue::getLineStart) .collect(Collectors.toList()); } private List<RegexpFilter> toFilter(final Entry<RegexpFilter, Integer[]> entry) { return Collections.singletonList(entry.getKey()); } }