package com.tngtech.archunit.lang.syntax.elements;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.tngtech.archunit.ArchConfiguration;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.core.domain.JavaClasses;
import com.tngtech.archunit.core.importer.ClassFileImporter;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.FailureReport;
class ClassesShouldThatEvaluator {
private static String OPTIONAL_ARGS_REGEX = "(?:\\([^)]*\\))?";
private static String METHOD_OR_FIELD_REGEX = "\\.[\\w<>]+" + OPTIONAL_ARGS_REGEX;
private static String MEMBER_REFERENCE_REGEX = "<(.*)" + METHOD_OR_FIELD_REGEX + ">";
private static String SAME_CLASS_BACK_REFERENCE_REGEX = "<\\1" + METHOD_OR_FIELD_REGEX + ">";
private static String SELF_REFERENCE_REGEX = MEMBER_REFERENCE_REGEX + ".*" + SAME_CLASS_BACK_REFERENCE_REGEX;
private final ArchRule rule;
private ClassesShouldThatEvaluator(ArchRule rule) {
this.rule = rule;
}
static ClassesShouldThatEvaluator filterClassesAppearingInFailureReport(ClassesShouldConjunction classesShould) {
return new ClassesShouldThatEvaluator(classesShould);
}
List<JavaClass> on(Class<?>... toCheck) {
JavaClasses classes = importClasses(toCheck);
String report = getRelevantFailures(classes);
List<JavaClass> result = new ArrayList<>();
for (JavaClass clazz : classes) {
if (report.contains(clazz.getName())) {
result.add(clazz);
}
}
return result;
}
private String getRelevantFailures(JavaClasses classes) {
List<String> relevant = new ArrayList<>();
for (String line : linesIn(rule.evaluate(classes).getFailureReport())) {
if (!isDefaultConstructor(line) && !isSelfReference(line)) {
relevant.add(line);
}
}
return Joiner.on("#").join(relevant);
}
private boolean isDefaultConstructor(String line) {
return line.contains(Object.class.getName());
}
private boolean isSelfReference(String line) {
return line.matches(".*" + SELF_REFERENCE_REGEX + ".*");
}
private List<String> linesIn(FailureReport failureReport) {
List<String> result = new ArrayList<>();
for (String details : failureReport.getDetails()) {
result.addAll(Splitter.on(System.lineSeparator()).splitToList(details));
}
return result;
}
private JavaClasses importClasses(Class<?>... classes) {
try {
ArchConfiguration.get().setResolveMissingDependenciesFromClassPath(true);
return new ClassFileImporter().importClasses(ImmutableSet.copyOf(classes));
} finally {
ArchConfiguration.get().reset();
}
}
}