Execute PMD and verify output

Uses apache commons-compress to extract the ZIP file.
This commit is contained in:
Andreas Dangel
2017-02-20 17:51:19 +01:00
committed by Juan Martín Sotuyo Dodero
parent 9351f13cf2
commit d2665bd870
6 changed files with 215 additions and 2 deletions

View File

@ -163,6 +163,12 @@
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>1.13</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>

View File

@ -8,12 +8,15 @@ import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import net.sourceforge.pmd.PMD;
@ -24,10 +27,14 @@ public class BinaryDistTest {
return new File(".", "target/pmd-bin-" + PMD.VERSION + ".zip");
}
private File getSourceDistribution() {
return new File(".", "target/pmd-src-" + PMD.VERSION + ".zip");
}
@Test
public void testFileExistence() {
File file = getBinaryDistribution();
assertTrue(file.exists());
assertTrue(getBinaryDistribution().exists());
assertTrue(getSourceDistribution().exists());
}
private Set<String> getExpectedFileNames() {
@ -58,4 +65,22 @@ public class BinaryDistTest {
assertTrue(expectedFileNames.isEmpty());
}
@Test
public void runPMD() throws Exception {
Path tempDir = Files.createTempDirectory("pmd-it-test-");
String srcDir = new File(".", "src/test/resources/sample-source/").getAbsolutePath();
try {
ZipFileExtractor.extractZipFile(getBinaryDistribution().toPath(), tempDir);
PMDExecutionResult result = PMDExecutor.runPMD(tempDir, srcDir, "java-basic");
result.assertPMDExecutionResult(4, "JumbledIncrementer.java:8:");
result = PMDExecutor.runPMD(tempDir, srcDir, "java-design");
result.assertPMDExecutionResult(0, "");
} finally {
FileUtils.forceDelete(tempDir.toFile());
}
}
}

View File

@ -0,0 +1,39 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.it;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
/**
* Collects the result of a PMD execution in order to verify it.
*
* @author Andreas Dangel
*/
public class PMDExecutionResult {
private final int exitCode;
private final String output;
PMDExecutionResult(int theExitCode, String theOutput) {
this.exitCode = theExitCode;
this.output = theOutput;
}
/**
* Asserts that PMD exited with the expected exit code and that the given expected
* output is contained in the actual PMD output.
*
* @param expectedExitCode the exit code, e.g. 0 if no rule violations are expected, or 4 if violations are found
* @param expectedOutput the output to search for
*/
public void assertPMDExecutionResult(int expectedExitCode, String expectedOutput) {
assertEquals("PMD exited with wrong code", expectedExitCode, exitCode);
assertNotNull("No output found", output);
if (!output.contains(expectedOutput)) {
fail("Expected output '" + expectedOutput + "' not present.\nComplete output:\n\n" + output);
}
}
}

View File

@ -0,0 +1,68 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.it;
import java.nio.file.Path;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.SystemUtils;
import net.sourceforge.pmd.PMD;
/**
* Executes PMD from command line. Deals with the differences, when PMD is run on Windows or on Linux.
*
* @author Andreas Dangel
*/
public class PMDExecutor {
private static final String PMD_BIN_PREFIX = "pmd-bin-";
private static final String SOURCE_DIRECTORY_FLAG = "-d";
private static final String RULESET_FLAG = "-R";
private static final String FORMAT_FLAG = "-f";
private static final String FORMATTER = "text";
private PMDExecutor() {
// this is a helper class only
}
private static PMDExecutionResult runPMDUnix(Path tempDir, String sourceDirectory, String ruleset) throws Exception {
String cmd = tempDir.resolve(PMD_BIN_PREFIX + PMD.VERSION + "/bin/run.sh").toAbsolutePath().toString();
ProcessBuilder pb = new ProcessBuilder(cmd, "pmd", SOURCE_DIRECTORY_FLAG, sourceDirectory, RULESET_FLAG, ruleset, FORMAT_FLAG, FORMATTER);
pb.redirectErrorStream(true);
Process process = pb.start();
String output = IOUtils.toString(process.getInputStream());
int result = process.waitFor();
return new PMDExecutionResult(result, output);
}
private static PMDExecutionResult runPMDWindows(Path tempDir, String sourceDirectory, String ruleset) throws Exception {
String cmd = tempDir.resolve(PMD_BIN_PREFIX + PMD.VERSION + "/bin/pmd.bat").toAbsolutePath().toString();
ProcessBuilder pb = new ProcessBuilder(cmd, SOURCE_DIRECTORY_FLAG, sourceDirectory, RULESET_FLAG, ruleset, FORMAT_FLAG, FORMATTER);
pb.redirectErrorStream(true);
Process process = pb.start();
String output = IOUtils.toString(process.getInputStream());
int result = process.waitFor();
return new PMDExecutionResult(result, output);
}
/**
* Executes the PMD found in tempDir against the given sourceDirectory path with the given ruleset.
*
* @param tempDir the directory, to which the binary distribution has been extracted
* @param sourceDirectory the source directory, that PMD should analyze
* @param ruleset the ruleset, that PMD should execute
* @return collected result of the execution
* @throws Exception if the execution fails for any reason (executable not found, ...)
*/
public static PMDExecutionResult runPMD(Path tempDir, String sourceDirectory, String ruleset) throws Exception {
if (SystemUtils.IS_OS_WINDOWS) {
return runPMDWindows(tempDir, sourceDirectory, ruleset);
} else {
return runPMDUnix(tempDir, sourceDirectory, ruleset);
}
}
}

View File

@ -0,0 +1,62 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.it;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.util.Enumeration;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.IOUtils;
/**
* Extracts a zip file with preserving the unix file permissions.
*
* @author Andreas Dangel
*/
public class ZipFileExtractor {
// unix file permission for executable flag by owner
private static final int OWNER_EXECUTABLE = 0x40;
private ZipFileExtractor() {
// Helper class
}
/**
* Extracts the given zip file into the tempDir.
* @param zipPath the zip file to extract
* @param tempDir the target directory
* @throws Exception if any error happens during extraction
*/
public static void extractZipFile(Path zipPath, Path tempDir) throws Exception {
ZipFile zip = new ZipFile(zipPath.toFile());
try {
Enumeration<ZipArchiveEntry> entries = zip.getEntries();
while (entries.hasMoreElements()) {
ZipArchiveEntry entry = entries.nextElement();
File file = tempDir.resolve(entry.getName()).toFile();
if (entry.isDirectory()) {
assertTrue(file.mkdirs());
} else {
try (InputStream data = zip.getInputStream(entry);
OutputStream fileOut = new FileOutputStream(file);) {
IOUtils.copy(data, fileOut);
}
if ((entry.getUnixMode() & OWNER_EXECUTABLE) == OWNER_EXECUTABLE) {
file.setExecutable(true);
}
}
}
} finally {
zip.close();
}
}
}

View File

@ -0,0 +1,13 @@
/**
* Sample file which triggers the JumbledIncrementerRule on line 8.
* Used in the integration tests.
*/
public class JumbledIncrementer {
public void foo() {
for (int i = 0; i < 10; i++) { // only references 'i'
for (int k = 0; k < 20; i++) { // references both 'i' and 'k'
System.out.println("Hello");
}
}
}
}