com.oneandone.iocunit.analyzer.Phase2Matcher Maven / Gradle / Ivy
package com.oneandone.iocunit.analyzer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author aschoerk
*/
class Phase2Matcher extends PhasesBase {
static AtomicInteger instance = new AtomicInteger(0);
static Logger logger = LoggerFactory.getLogger(Phase2Matcher.class);
HashMap matching = new HashMap<>();
HashMultiMap ambiguus = new HashMultiMap<>();
Set empty = new HashSet<>();
public Phase2Matcher(Configuration configuration) {
super(configuration);
}
public void matchInject(QualifiedType inject) {
logger.trace("matchingInject: {}", inject);
Set matchingProducers = configuration.getProducerMap().findMatchingProducersRegardingAlternatives(inject);
if(matchingProducers.size() == 0) {
logger.trace("No match found for inject {}", inject);
empty.add(inject);
}
else if(matchingProducers.size() > 1) {
for (QualifiedType x : matchingProducers) {
logger.trace("Ambiguus match: {} for inject", x, inject);
}
ambiguus.put(inject, matchingProducers);
}
else {
final QualifiedType theMatch = matchingProducers.iterator().next();
matching.put(inject, theMatch);
logger.trace("Unambiguus match: {}", theMatch);
}
}
public List> evaluateMatches() {
Set> newToBeStarted = new HashSet();
for (QualifiedType inject : empty) {
// search for producers and inner classes
}
Set chosenTypes = new HashSet<>();
for (QualifiedType inject : matching.keySet()) {
final QualifiedType producingType = matching.get(inject);
if(!configuration.isToBeStarted(producingType.getDeclaringClass())) {
if(producingType.isFake()) {
logger.trace("Fake Unambiguus Producer for Inject {}", inject, producingType);
}
else {
logger.trace("Unambiguus Producer for Inject {}", inject);
logger.trace("--- {}", producingType);
newToBeStarted.add(producingType.getDeclaringClass());
chosenTypes.add(producingType);
}
}
configuration.injectHandled(inject, producingType);
}
for (QualifiedType inject : ambiguus.keySet()) {
Map, QualifiedType> testClasses = new HashMap<>();
Map, QualifiedType> sutClasses = new HashMap<>();
Set producingTypes = ambiguus.get(inject);
if (!inject.isInstance()){
logger.debug("Ambiguus resolved inject: {}", inject);
for (QualifiedType producing : producingTypes) {
logger.debug("--- Producing: {}", producing);
}
}
Set alreadyChosen = producingTypes.stream()
.filter(p -> chosenTypes.contains(p))
.collect(Collectors.toSet());
if(alreadyChosen.size() > 0) {
if(alreadyChosen.size() > 1) {
logger.error("Two producing types should only resolve to one chosen for inject {}", inject);
}
for (QualifiedType q : alreadyChosen) {
logger.info("Already chosen: {}", q);
}
continue;
}
boolean alreadyProduced = false;
for (QualifiedType q : producingTypes) {
Class declaringClass = q.getDeclaringClass();
assert declaringClass != null;
assert !configuration.getExcludedClasses().contains(declaringClass);
if(configuration.isToBeStarted(declaringClass) || newToBeStarted.contains(declaringClass)) {
alreadyProduced = true;
if (!inject.isInstance())
logger.trace("{} Already produced by declaring class: {}", inject, declaringClass.getName());
configuration.injectHandled(inject, q);
}
else if(configuration.isTestClass(declaringClass)) {
testClasses.put(declaringClass, q);
}
else {
sutClasses.put(declaringClass, q);
}
}
if(alreadyProduced) {
; // inject handled by producer in already used class.
}
else if(testClasses.size() != 0) {
if(testClasses.size() > 1) {
logger.error("Handling Inject: {} Testclass(es) {} clashing",
inject, testClasses);
}
else {
if(sutClasses.size() > 0) {
logger.error("Handling Inject: {} Testclasses clashing with sutClasses",
inject);
for (Class> c : sutClasses.keySet()) {
Set injects = configuration.getInjectsForClass(c);
if(injects.size() == 0) {
logger.error("SutClass {} excluded because of clashing with Testclass {}"
, c, testClasses.keySet().iterator().next());
configuration.excluded(c);
sutClasses.remove(c);
}
else {
logger.error("Tried to exclude SutClass {} excluded because of clashing "
+ "with Testclass {} not possible because of other injects"
, c, testClasses.keySet().iterator().next());
}
}
}
final Class> testClass = testClasses.keySet().iterator().next();
if(!configuration.isToBeStarted(testClass)) {
newToBeStarted.add(testClass);
logger.info("Selected producing test class {}", testClass.getName());
} else {
logger.info("Already selected producing test class {}", testClass.getName());
}
configuration.injectHandled(inject, testClasses.values().iterator().next());
}
}
else if(sutClasses.size() > 0) {
if(sutClasses.size() > 1) {
logger.error("Handling Inject: {} too many SutClass(es) {}",
inject, sutClasses);
}
else {
final Class> sutClass = sutClasses.keySet().iterator().next();
if(!configuration.isToBeStarted(sutClass)) {
logger.info("Selected producing sut class {}", sutClass.getName());
newToBeStarted.add(sutClass);
} else {
logger.info("Already selected producing sut class {}", sutClass.getName());
}
configuration.injectHandled(inject, sutClasses.values().iterator().next());
}
}
}
List> result = new ArrayList<>(newToBeStarted);
return result;
}
public void work() {
configuration.setPhase(Configuration.Phase.MATCHING);
logger.trace("Phase2Matcher starting");
for (QualifiedType i : configuration.getInjects()) {
matchInject(i);
}
evaluateMatches();
for (QualifiedType i : configuration.getInstanceInjects()) {
matchInstanceInjects(i);
}
logger.trace("Phase2Matcher ready");
}
private void matchInstanceInjects(final QualifiedType inject) {
Set matchingProducers = configuration
.getAvailableProducerMap()
.findMatchingProducersRegardingAlternatives(inject);
for (QualifiedType producer: matchingProducers) {
if (!configuration.isToBeStarted(producer.getDeclaringClass()))
configuration.candidate(producer.getDeclaringClass());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy