org.pitest.dependency.DependencyExtractor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pitest Show documentation
Show all versions of pitest Show documentation
Mutation testing system for Java.
/*
* Copyright 2010 Henry Coles
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package org.pitest.dependency;
import static org.pitest.functional.prelude.Prelude.and;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.BiFunction;
import java.util.function.Predicate;
import java.util.logging.Logger;
import org.objectweb.asm.ClassReader;
import org.pitest.bytecode.NullVisitor;
import org.pitest.classinfo.ClassByteArraySource;
import org.pitest.functional.FCollection;
import java.util.Optional;
import org.pitest.functional.SideEffect1;
import org.pitest.util.Functions;
import org.pitest.util.Log;
public class DependencyExtractor {
private static final Logger LOG = Log.getLogger();
private final int depth;
private final ClassByteArraySource classToBytes;
public DependencyExtractor(final ClassByteArraySource classToBytes,
final int depth) {
this.depth = depth;
this.classToBytes = classToBytes;
}
public Collection extractCallDependenciesForPackages(
final String clazz, final Predicate targetPackages)
throws IOException {
final Set allDependencies = extractCallDependencies(clazz,
new IgnoreCoreClasses());
return FCollection.filter(allDependencies,
and(asJVMNamePredicate(targetPackages), notSuppliedClass(clazz)));
}
private static Predicate notSuppliedClass(final String clazz) {
return a -> !Functions.jvmClassToClassName().apply(a).equals(clazz);
}
private static Predicate asJVMNamePredicate(
final Predicate predicate) {
return a -> predicate.test(Functions.jvmClassToClassName().apply(a));
}
public Collection extractCallDependenciesForPackages(
final String clazz, final Predicate targetPackages,
final Predicate doNotTraverse) throws IOException {
final Set allDependencies = extractCallDependencies(clazz,
doNotTraverse);
return FCollection.filter(allDependencies, targetPackages);
}
Set extractCallDependencies(final String clazz,
final Predicate filter) throws IOException {
return this
.extractCallDependencies(clazz, new TreeSet(), filter, 0);
}
public int getMaxDistance() {
return this.depth;
}
private Set extractCallDependencies(final String clazz,
final TreeSet visited, final Predicate filter,
final int currentDepth) throws IOException {
final Map> classesToAccesses = groupDependenciesByClass(extractRelevantDependencies(
clazz, filter));
final Set dependencies = new HashSet<>(
classesToAccesses.keySet());
dependencies.removeAll(visited);
visited.addAll(dependencies);
if ((currentDepth < (this.depth - 1)) || (this.depth == 0)) {
dependencies.addAll(examineChildDependencies(currentDepth, dependencies,
visited, filter));
}
return dependencies;
}
private Set examineChildDependencies(final int currentDepth,
final Set classes, final TreeSet visited,
final Predicate filter) throws IOException {
final Set deps = new HashSet<>();
for (final String each : classes) {
final Set childDependencies = extractCallDependencies(each,
visited, filter, currentDepth + 1);
deps.addAll(childDependencies);
}
return deps;
}
private Set extractRelevantDependencies(final String clazz,
final Predicate filter) throws IOException {
final List dependencies = extract(clazz, filter);
final Set relevantDependencies = new TreeSet<>(
equalDestinationComparator());
FCollection.filter(dependencies, filter, relevantDependencies);
return relevantDependencies;
}
private static Comparator equalDestinationComparator() {
return (o1, o2) -> o1.getDest().compareTo(o2.getDest());
}
private List extract(final String clazz,
final Predicate filter) throws IOException {
final Optional bytes = this.classToBytes.getBytes(clazz);
if (!bytes.isPresent()) {
LOG.warning("No bytes found for " + clazz);
return Collections.emptyList();
}
final ClassReader reader = new ClassReader(bytes.get());
final List dependencies = new ArrayList<>();
final SideEffect1 se = constructCollectingSideEffectForVisitor(
dependencies, and(nameIsEqual(clazz).negate(), filter));
final DependencyClassVisitor dcv = new DependencyClassVisitor(
new NullVisitor(), se);
reader.accept(dcv, ClassReader.EXPAND_FRAMES);
return dependencies;
}
private Map> groupDependenciesByClass(
final Set relevantDependencies) {
final List sortedByClass = new ArrayList<>(
relevantDependencies.size());
Collections.sort(sortedByClass, classNameComparator());
return FCollection.fold(addDependenciesToMap(),
new HashMap>(), relevantDependencies);
}
private static BiFunction