-
Notifications
You must be signed in to change notification settings - Fork 353
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #433 from rchargel/report-aggregate
Adding an additional report-aggregate mojo
- Loading branch information
Showing
24 changed files
with
1,369 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<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> | ||
<parent> | ||
<groupId>org.pitest</groupId> | ||
<artifactId>pitest-parent</artifactId> | ||
<version>1.3.2-SNAPSHOT</version> | ||
</parent> | ||
<artifactId>pitest-aggregator</artifactId> | ||
<description>Aggregates the output of report XML documents into a new combined HTML report</description> | ||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-checkstyle-plugin</artifactId> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.pitest</groupId> | ||
<artifactId>pitest-entry</artifactId> | ||
<version>${project.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.pitest</groupId> | ||
<artifactId>pitest-html-report</artifactId> | ||
<version>${project.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>${junit.version}</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.hamcrest</groupId> | ||
<artifactId>hamcrest-library</artifactId> | ||
<version>1.3</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
</project> |
40 changes: 40 additions & 0 deletions
40
pitest-aggregator/src/main/java/org/pitest/aggregate/BlockCoverageDataLoader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package org.pitest.aggregate; | ||
|
||
import java.io.File; | ||
import java.util.Collection; | ||
import java.util.Map; | ||
|
||
import org.pitest.classinfo.ClassName; | ||
import org.pitest.coverage.BlockCoverage; | ||
import org.pitest.coverage.BlockLocation; | ||
import org.pitest.mutationtest.engine.Location; | ||
import org.pitest.mutationtest.engine.MethodName; | ||
|
||
class BlockCoverageDataLoader extends DataLoader<BlockCoverage> { | ||
|
||
private static final String METHOD = "method"; | ||
private static final String CLASSNAME = "classname"; | ||
private static final String NUMBER = "number"; | ||
private static final String TESTS = "tests"; | ||
|
||
private static final String OPEN_PAREN = "("; | ||
|
||
public BlockCoverageDataLoader(final Collection<File> filesToLoad) { | ||
super(filesToLoad); | ||
} | ||
|
||
@Override | ||
protected BlockCoverage mapToData(final Map<String, Object> map) { | ||
final String method = (String) map.get(METHOD); | ||
final Location location = new Location(ClassName.fromString((String) map.get(CLASSNAME)), | ||
MethodName.fromString(method.substring(0, method.indexOf(OPEN_PAREN))), method.substring(method.indexOf(OPEN_PAREN))); | ||
|
||
final BlockLocation blockLocation = new BlockLocation(location, Integer.parseInt((String) map.get(NUMBER))); | ||
|
||
@SuppressWarnings("unchecked") | ||
final Collection<String> tests = (Collection<String>) map.get(TESTS); | ||
|
||
return new BlockCoverage(blockLocation, tests); | ||
} | ||
|
||
} |
60 changes: 60 additions & 0 deletions
60
pitest-aggregator/src/main/java/org/pitest/aggregate/CodeSourceAggregator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package org.pitest.aggregate; | ||
|
||
import java.io.File; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
|
||
import org.pitest.classinfo.ClassName; | ||
import org.pitest.classpath.ClassFilter; | ||
import org.pitest.classpath.ClassPath; | ||
import org.pitest.classpath.ClassPathRoot; | ||
import org.pitest.classpath.CodeSource; | ||
import org.pitest.classpath.DirectoryClassPathRoot; | ||
import org.pitest.classpath.PathFilter; | ||
import org.pitest.classpath.ProjectClassPaths; | ||
import org.pitest.functional.F; | ||
import org.pitest.functional.FCollection; | ||
import org.pitest.functional.predicate.Predicate; | ||
import org.pitest.functional.prelude.Prelude; | ||
import org.pitest.mutationtest.config.DefaultCodePathPredicate; | ||
import org.pitest.mutationtest.config.DefaultDependencyPathPredicate; | ||
import org.pitest.util.Glob; | ||
|
||
class CodeSourceAggregator { | ||
|
||
private final Collection<File> compiledCodeDirectories; | ||
|
||
public CodeSourceAggregator(final Collection<File> compiledCodeDirectories) { | ||
this.compiledCodeDirectories = Collections.unmodifiableCollection(compiledCodeDirectories); | ||
} | ||
|
||
public CodeSource createCodeSource() { | ||
return new CodeSource(createProjectClassPaths()); | ||
} | ||
|
||
private ProjectClassPaths createProjectClassPaths() { | ||
final ClassPath classPath = new ClassPath(compiledCodeDirectories); | ||
final Predicate<String> classPredicate = createClassPredicate(); | ||
final Predicate<ClassPathRoot> pathPredicate = new DefaultCodePathPredicate(); | ||
return new ProjectClassPaths(classPath, new ClassFilter(classPredicate, classPredicate), | ||
new PathFilter(pathPredicate, Prelude.not(new DefaultDependencyPathPredicate()))); | ||
} | ||
|
||
private Predicate<String> createClassPredicate() { | ||
final Collection<String> classes = new HashSet<String>(); | ||
for (final File buildOutputDirectory : compiledCodeDirectories) { | ||
if (buildOutputDirectory.exists()) { | ||
final DirectoryClassPathRoot dcRoot = new DirectoryClassPathRoot(buildOutputDirectory); | ||
classes.addAll(FCollection.map(dcRoot.classNames(), new F<String, String>() { | ||
@Override | ||
public String apply(final String a) { | ||
return ClassName.fromString(a).getPackage().asJavaName() + ".*"; | ||
} | ||
})); | ||
} | ||
} | ||
return Prelude.or(FCollection.map(classes, Glob.toGlobPredicate())); | ||
} | ||
|
||
} |
150 changes: 150 additions & 0 deletions
150
pitest-aggregator/src/main/java/org/pitest/aggregate/DataLoader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package org.pitest.aggregate; | ||
|
||
import java.io.BufferedInputStream; | ||
import java.io.File; | ||
import java.io.FileInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.util.ArrayList; | ||
import java.util.Collection; | ||
import java.util.Collections; | ||
import java.util.HashMap; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import javax.xml.parsers.DocumentBuilder; | ||
import javax.xml.parsers.DocumentBuilderFactory; | ||
import javax.xml.parsers.ParserConfigurationException; | ||
|
||
import org.w3c.dom.Document; | ||
import org.w3c.dom.NamedNodeMap; | ||
import org.w3c.dom.Node; | ||
import org.w3c.dom.NodeList; | ||
import org.xml.sax.SAXException; | ||
|
||
abstract class DataLoader<T> { | ||
|
||
private static final String CANNOT_CLOSE_ERR = "Unable to close input stream"; | ||
|
||
private final Set<File> filesToLoad; | ||
|
||
protected DataLoader(final Collection<File> filesToLoad) { | ||
if (filesToLoad == null || filesToLoad.isEmpty()) { | ||
throw new IllegalArgumentException("Null or empty filesToLoad"); | ||
} | ||
|
||
this.filesToLoad = Collections.unmodifiableSet(new HashSet<File>(filesToLoad)); | ||
} | ||
|
||
public Set<T> loadData() throws ReportAggregationException { | ||
final Set<T> data = new HashSet<T>(); | ||
|
||
for (final File file : filesToLoad) { | ||
data.addAll(loadData(file)); | ||
} | ||
return data; | ||
} | ||
|
||
protected abstract T mapToData(Map<String, Object> map); | ||
|
||
Set<T> loadData(final File dataLocation) throws ReportAggregationException { | ||
if (!dataLocation.exists() || !dataLocation.isFile()) { | ||
throw new ReportAggregationException(dataLocation.getAbsolutePath() + " does not exist or is not a file"); | ||
} | ||
final Set<T> data = new HashSet<T>(); | ||
try { | ||
final InputStream inputStream = new BufferedInputStream(new FileInputStream(dataLocation)); | ||
|
||
final Document doc = readDocument(inputStream); | ||
|
||
final Node docNode = doc.getFirstChild(); | ||
final NodeList nodeList = docNode.getChildNodes(); | ||
for (int i = 0; i < nodeList.getLength(); i++) { | ||
final Node itemNode = nodeList.item(i); | ||
if (itemNode.getNodeType() == Node.ELEMENT_NODE) { | ||
data.add(mapToData(nodeMap(itemNode))); | ||
} | ||
} | ||
return data; | ||
} catch (final IOException e) { | ||
throw new ReportAggregationException("Could not read file: " + dataLocation.getAbsolutePath(), e); | ||
} | ||
} | ||
|
||
/** | ||
* Reads the input stream into a document and closes the input stream when | ||
* finished. | ||
*/ | ||
static Document readDocument(final InputStream inputStream) throws ReportAggregationException { | ||
DocumentBuilder docBuilder; | ||
try { | ||
docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); | ||
return docBuilder.parse(inputStream); | ||
} catch (final IOException e) { | ||
throw new ReportAggregationException(e.getMessage(), e); | ||
} catch (final SAXException e) { | ||
throw new ReportAggregationException(e.getMessage(), e); | ||
} catch (final ParserConfigurationException e) { | ||
throw new ReportAggregationException(e.getMessage(), e); | ||
} finally { | ||
try { | ||
inputStream.close(); | ||
} catch (final IOException e) { | ||
throw new ReportAggregationException(CANNOT_CLOSE_ERR, e); | ||
} | ||
} | ||
} | ||
|
||
// converts the contents of a node into a map | ||
static Map<String, Object> nodeMap(final Node node) { | ||
final HashMap<String, Object> map = new HashMap<String, Object>(); | ||
|
||
final NamedNodeMap attrs = node.getAttributes(); | ||
for (int i = 0; i < attrs.getLength(); i++) { | ||
final Node attr = attrs.item(i); | ||
final String tc = attr.getTextContent().trim(); | ||
|
||
if (!tc.isEmpty()) { | ||
map.put(attr.getNodeName(), tc); | ||
} | ||
} | ||
|
||
final NodeList children = node.getChildNodes(); | ||
|
||
for (int i = 0; i < children.getLength(); i++) { | ||
final Node child = children.item(i); | ||
|
||
if (child.getNodeType() == Node.ELEMENT_NODE) { | ||
final String tc = child.getTextContent().trim(); | ||
if (!tc.isEmpty()) { | ||
map.put(child.getNodeName(), tc); | ||
} else { | ||
// may have test nodes | ||
final List<String> tests = new ArrayList<String>(); | ||
final NodeList testNodeList = child.getChildNodes(); | ||
for (int j = 0; j < testNodeList.getLength(); j++) { | ||
final Node testNode = testNodeList.item(j); | ||
if (testNode.getNodeType() == Node.ELEMENT_NODE) { | ||
final NamedNodeMap testAttrs = testNode.getAttributes(); | ||
for (int k = 0; k < testAttrs.getLength(); k++) { | ||
final Node attr = testAttrs.item(k); | ||
final String tn = attr.getTextContent().trim(); | ||
|
||
if (!tn.isEmpty()) { | ||
tests.add(tn); | ||
} | ||
} | ||
} | ||
} | ||
if (!tests.isEmpty()) { | ||
map.put(child.getNodeName(), tests); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return map; | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
pitest-aggregator/src/main/java/org/pitest/aggregate/MutationResultDataLoader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package org.pitest.aggregate; | ||
|
||
import java.io.File; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.Map; | ||
|
||
import org.pitest.classinfo.ClassName; | ||
import org.pitest.mutationtest.DetectionStatus; | ||
import org.pitest.mutationtest.MutationResult; | ||
import org.pitest.mutationtest.MutationStatusTestPair; | ||
import org.pitest.mutationtest.engine.Location; | ||
import org.pitest.mutationtest.engine.MethodName; | ||
import org.pitest.mutationtest.engine.MutationDetails; | ||
import org.pitest.mutationtest.engine.MutationIdentifier; | ||
|
||
class MutationResultDataLoader extends DataLoader<MutationResult> { | ||
|
||
private static final String MUTATED_CLASS = "mutatedClass"; | ||
private static final String MUTATED_METHOD = "mutatedMethod"; | ||
private static final String METHOD_DESCRIPTION = "methodDescription"; | ||
private static final String INDEX = "index"; | ||
private static final String MUTATOR = "mutator"; | ||
private static final String SOURCE_FILE = "sourceFile"; | ||
private static final String DESCRIPTION = "description"; | ||
private static final String LINE_NUMBER = "lineNumber"; | ||
private static final String BLOCK = "block"; | ||
private static final String NUMBER_OF_TESTS_RUN = "numberOfTestsRun"; | ||
private static final String STATUS = "status"; | ||
private static final String KILLING_TEST = "killingTest"; | ||
|
||
public MutationResultDataLoader(final Collection<File> filesToLoad) { | ||
super(filesToLoad); | ||
} | ||
|
||
@Override | ||
protected MutationResult mapToData(final Map<String, Object> map) { | ||
final Location location = new Location(ClassName.fromString((String) map.get(MUTATED_CLASS)), MethodName.fromString((String) map.get(MUTATED_METHOD)), | ||
(String) map.get(METHOD_DESCRIPTION)); | ||
|
||
final MutationIdentifier id = new MutationIdentifier(location, Arrays.asList(new Integer((String) map.get(INDEX))), (String) map.get(MUTATOR)); | ||
|
||
final MutationDetails md = new MutationDetails(id, (String) map.get(SOURCE_FILE), (String) map.get(DESCRIPTION), | ||
Integer.parseInt((String) map.get(LINE_NUMBER)), Integer.parseInt((String) map.get(BLOCK))); | ||
|
||
final MutationStatusTestPair status = new MutationStatusTestPair(Integer.parseInt((String) map.get(NUMBER_OF_TESTS_RUN)), | ||
DetectionStatus.valueOf((String) map.get(STATUS)), (String) map.get(KILLING_TEST)); | ||
|
||
return new MutationResult(md, status); | ||
} | ||
|
||
} |
29 changes: 29 additions & 0 deletions
29
pitest-aggregator/src/main/java/org/pitest/aggregate/MutatorUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package org.pitest.aggregate; | ||
|
||
import java.lang.reflect.Array; | ||
import java.lang.reflect.Method; | ||
import java.util.Map; | ||
import java.util.concurrent.ConcurrentHashMap; | ||
|
||
import org.pitest.mutationtest.engine.gregor.MethodMutatorFactory; | ||
|
||
final class MutatorUtil { | ||
|
||
private static Map<String, MethodMutatorFactory> factories = new ConcurrentHashMap<String, MethodMutatorFactory>(); | ||
|
||
@SuppressWarnings("unchecked") | ||
static MethodMutatorFactory loadMutator(final String className) { | ||
if (!factories.containsKey(className)) { | ||
try { | ||
final Class<MethodMutatorFactory> clazz = (Class<MethodMutatorFactory>) Class.forName(className); | ||
final Method values = clazz.getMethod("values"); | ||
final Object valuesArray = values.invoke(null); | ||
final MethodMutatorFactory mutator = (MethodMutatorFactory) Array.get(valuesArray, 0); | ||
factories.put(className, mutator); | ||
} catch (final Exception e) { | ||
throw new RuntimeException("Unable to load Mutator for class: " + className, e); | ||
} | ||
} | ||
return factories.get(className); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
pitest-aggregator/src/main/java/org/pitest/aggregate/ReportAggregationException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package org.pitest.aggregate; | ||
|
||
public class ReportAggregationException extends Exception { | ||
|
||
private static final long serialVersionUID = 1L; | ||
|
||
public ReportAggregationException(final String message) { | ||
super(message); | ||
} | ||
|
||
public ReportAggregationException(final String message, final Throwable cause) { | ||
super(message, cause); | ||
} | ||
|
||
} |
Oops, something went wrong.