Extract test framework into own sub-module

This commit is contained in:
Andreas Dangel
2014-10-04 17:37:09 +02:00
parent ad88b4784d
commit c859a05718
9 changed files with 30 additions and 0 deletions

24
pmd-test/pom.xml Normal file
View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>pmd-test</artifactId>
<name>PMD Test Framework</name>
<parent>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-aggregate</artifactId>
<version>5.1.4-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,37 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.testframework;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.util.List;
import net.sourceforge.pmd.cpd.SourceCode;
import net.sourceforge.pmd.cpd.TokenEntry;
import net.sourceforge.pmd.cpd.Tokenizer;
import net.sourceforge.pmd.cpd.Tokens;
/**
* @author Romain PELISSE, belaran@gmail.com
*
*/
public abstract class AbstractTokenizerTest {
protected int expectedTokenCount;
protected Tokenizer tokenizer;
protected SourceCode sourceCode;
public abstract void buildTokenizer();
public abstract String getSampleCode();
protected void tokenizeTest() throws IOException {
Tokens tokens = new Tokens();
tokenizer.tokenize(sourceCode, tokens);
List<TokenEntry> entries = tokens.getTokens();
assertEquals(expectedTokenCount,entries.size());
}
}

View File

@@ -0,0 +1,180 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.testframework;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import net.sourceforge.pmd.Rule;
import org.junit.Test;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.Filterable;
import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.TestClass;
/**
* A test runner for rule tests. Unlike {@link SimpleAggregatorTst.CustomXmlTestClassMethodsRunner}
* it also reports the successful executed tests and allows to selectively execute single test cases
* (it is {@link Filterable}).
* <p>
* In order to use it, you'll need to subclass {@link SimpleAggregatorTst} and annotate your test
* class with RunWith:
* <pre>
* {@code @}RunWith(PMDTestRunner.class)
* public class MyRuleSetTest extends SimpleAggregatorTst {
* ...
* }
* </pre>
* </p>
*/
public class PMDTestRunner extends Runner implements Filterable {
private final Description desc;
private final Class<? extends SimpleAggregatorTst> klass;
private final List<TestDescriptor> allTests = new ArrayList<TestDescriptor>();
private BlockJUnit4ClassRunner chainedRunner;
/**
* Creates a new {@link PMDTestRunner} for the given test class.
* @param klass the test class that is under test
* @throws InitializationError any error
*/
public PMDTestRunner(final Class<? extends SimpleAggregatorTst> klass) throws InitializationError {
this.klass = klass;
desc = Description.createSuiteDescription(klass);
configureRuleTests();
configureUnitTests();
}
private void configureRuleTests() throws InitializationError {
Description root = Description.createSuiteDescription("Rule Tests");
try {
SimpleAggregatorTst test = createTestClass();
test.setUp();
List<Rule> rules = new ArrayList<Rule>(test.getRules());
Collections.sort(rules, new Comparator<Rule>() {
@Override
public int compare(Rule o1, Rule o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (Rule r : rules) {
Description ruleDescription = Description.createSuiteDescription(r.getName());
root.addChild(ruleDescription);
TestDescriptor[] ruleTests = test.extractTestsFromXml(r);
for (TestDescriptor t : ruleTests) {
Description d = createTestDescription(t);
ruleDescription.addChild(d);
allTests.add(t);
}
}
if (!root.getChildren().isEmpty()) {
desc.addChild(root);
}
} catch (Exception e) {
throw new InitializationError(e);
}
}
private SimpleAggregatorTst createTestClass() {
try {
return klass.getConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void configureUnitTests() throws InitializationError {
TestClass tclass = new TestClass(klass);
if (!tclass.getAnnotatedMethods(Test.class).isEmpty()) {
Description unitTests = Description.createSuiteDescription("Unit tests");
chainedRunner = new BlockJUnit4ClassRunner(klass);
for (Description d : chainedRunner.getDescription().getChildren()) {
unitTests.addChild(d);
}
desc.addChild(unitTests);
}
}
@Override
public Description getDescription() {
return desc;
}
@Override
public void run(RunNotifier notifier) {
SimpleAggregatorTst test = createTestClass();
boolean regressionTestMode = TestDescriptor.inRegressionTestMode();
for (TestDescriptor t : allTests) {
Description d = createTestDescription(t);
notifier.fireTestStarted(d);
try {
if (!regressionTestMode || t.isRegressionTest()) {
test.runTest(t);
} else {
notifier.fireTestIgnored(d);
}
} catch (Throwable e) {
notifier.fireTestFailure(new Failure(d, e));
} finally {
notifier.fireTestFinished(d);
}
}
if (chainedRunner != null) {
chainedRunner.run(notifier);
}
}
private Description createTestDescription(TestDescriptor t) {
String d = t.getDescription().replaceAll("\n|\r", " ");
return Description.createTestDescription(klass, t.getRule().getName() + "::" + t.getNumberInDocument() + " " + d);
}
@Override
public void filter(Filter filter) throws NoTestsRemainException {
Iterator<TestDescriptor> it = allTests.iterator();
while (it.hasNext()) {
TestDescriptor t = it.next();
Description testDesc = createTestDescription(t);
if (filter.shouldRun(testDesc)) {
try {
filter.apply(t);
} catch (NoTestsRemainException e) {
it.remove();
}
} else {
it.remove();
}
}
boolean chainIsEmpty = false;
try {
if (chainedRunner != null) {
chainedRunner.filter(filter);
} else {
chainIsEmpty = true;
}
} catch (NoTestsRemainException e) {
chainIsEmpty = true;
}
if (allTests.isEmpty() && chainIsEmpty) {
throw new NoTestsRemainException();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,74 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.testframework;
import java.util.ArrayList;
import java.util.List;
import net.sourceforge.pmd.Rule;
import org.junit.runner.RunWith;
/**
* Standard methods for (simple) testcases.
*/
@RunWith(PMDTestRunner.class)
public abstract class SimpleAggregatorTst extends RuleTst {
/**
* Configure the rule tests to be executed. Implement this method in
* subclasses by calling adRule.
*
* @see #addRule(String, String)
*/
protected void setUp() {
// empty, to be overridden
}
/**
* Run a set of tests defined in an XML test-data file for a rule. The file
* should be ./xml/RuleName.xml relative to the test-class. The format is
* defined in test-data.xsd.
*/
public void runTests(Rule rule) {
runTests(extractTestsFromXml(rule));
}
/**
* Run a set of tests defined in a XML test-data file. The file should be
* ./xml/[testsFileName].xml relative to the test-class. The format is
* defined in test-data.xsd.
*/
public void runTests(Rule rule, String testsFileName) {
runTests(extractTestsFromXml(rule, testsFileName));
}
/**
* Run a set of tests of a certain sourceType.
*/
public void runTests(TestDescriptor[] tests) {
for (int i = 0; i < tests.length; i++) {
runTest(tests[i]);
}
}
private List<Rule> rules = new ArrayList<Rule>();
/**
* Add new XML tests associated with the rule to the test suite. This should
* be called from the setup method.
*/
protected void addRule(String ruleSet, String ruleName) {
rules.add(findRule(ruleSet, ruleName));
}
/**
* Gets all configured rules.
*
* @return all configured rules.
*/
protected List<Rule> getRules() {
return rules;
}
}

View File

@@ -0,0 +1,33 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.testframework;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
public class StreamUtil {
public static String toString(InputStream in) {
if (in == null) {
throw new NullPointerException("no input stream given");
}
StringBuilder sb = new StringBuilder();
int c;
try {
while ((c = in.read()) != -1) {
sb.append((char) c);
}
} catch (IOException e) {
// ignored
} finally {
IOUtils.closeQuietly(in);
}
return sb.toString();
}
}

View File

@@ -0,0 +1,139 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.testframework;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.lang.LanguageVersion;
import org.junit.Ignore;
/**
* Stores the information required to run a complete test.
*/
@Ignore("this is not a unit test")
public class TestDescriptor {
private Rule rule;
private Properties properties;
private String description;
private int numberOfProblemsExpected;
private List<String> expectedMessages = new ArrayList<String>();
private List<Integer> expectedLineNumbers = new ArrayList<Integer>();
private String code;
private LanguageVersion languageVersion;
private boolean reinitializeRule = true; //default, avoids unintentional mixing of state between test cases
private boolean isRegressionTest = true;
private int numberInDocument = -1;
// Empty descriptor added to please mvn surefire plugin
public TestDescriptor() {
}
public TestDescriptor(String code, String description, int numberOfProblemsExpected, Rule rule) {
this(code, description, numberOfProblemsExpected, rule, RuleTst.DEFAULT_LANGUAGE_VERSION);
}
public TestDescriptor(String code, String description, int numberOfProblemsExpected, Rule rule, LanguageVersion languageVersion) {
this.rule = rule;
this.code = code;
this.description = description;
this.numberOfProblemsExpected = numberOfProblemsExpected;
this.languageVersion = languageVersion;
}
public int getNumberInDocument() {
return numberInDocument;
}
public void setNumberInDocument(int numberInDocument) {
this.numberInDocument = numberInDocument;
}
public void setExpectedMessages(List<String> messages) {
expectedMessages.clear();
expectedMessages.addAll(messages);
}
public List<String> getExpectedMessages() {
return expectedMessages;
}
public void setExpectedLineNumbers(List<Integer> expectedLineNumbers) {
this.expectedLineNumbers.clear();
this.expectedLineNumbers.addAll(expectedLineNumbers);
}
public List<Integer> getExpectedLineNumbers() {
return expectedLineNumbers;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public Properties getProperties() {
return properties;
}
public String getCode() {
return code;
}
public LanguageVersion getLanguageVersion() {
return languageVersion;
}
public String getDescription() {
return description;
}
public int getNumberOfProblemsExpected() {
return numberOfProblemsExpected;
}
public Rule getRule() {
return rule;
}
public boolean getReinitializeRule() {
return reinitializeRule;
}
public void setReinitializeRule(boolean reinitializeRule) {
this.reinitializeRule = reinitializeRule;
}
/**
* Checks whether we are testing for regression problems only.
* Return value is based on the system property "pmd.regress".
*
* @return <code>false</code> if system property "pmd.regress" is set to <code>false</code>, <code>true</code> otherwise
*/
public static boolean inRegressionTestMode() {
boolean inRegressionMode = true; // default
try {
//get the "pmd.regress" System property
String property = System.getProperty("pmd.regress");
if (property != null) {
inRegressionMode = Boolean.parseBoolean(property);
}
} catch (IllegalArgumentException e) {
} catch (NullPointerException e) {
}
return inRegressionMode;
}
public boolean isRegressionTest() {
return isRegressionTest;
}
public void setRegressionTest(boolean isRegressionTest) {
this.isRegressionTest = isRegressionTest;
}
}