package com.ikokoon.serenity.process;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.junit.Before;
import org.junit.Test;
import com.ikokoon.serenity.ATest;
import com.ikokoon.serenity.Collector;
import com.ikokoon.serenity.Configuration;
import com.ikokoon.serenity.IConstants;
import com.ikokoon.serenity.instrumentation.dependency.DependencyClassAdapter;
import com.ikokoon.serenity.model.Class;
import com.ikokoon.serenity.model.Line;
import com.ikokoon.serenity.model.Method;
import com.ikokoon.serenity.model.Package;
import com.ikokoon.serenity.model.Project;
import com.ikokoon.serenity.persistence.DataBaseOdb;
import com.ikokoon.serenity.persistence.DataBaseRam;
import com.ikokoon.serenity.persistence.DataBaseToolkit;
import com.ikokoon.serenity.persistence.IDataBase;
import com.ikokoon.serenity.process.aggregator.MethodAggregator;
import com.ikokoon.serenity.process.aggregator.PackageAggregator;
import com.ikokoon.target.discovery.Discovery;
import com.ikokoon.target.discovery.IDiscovery;
import com.ikokoon.toolkit.Executer;
import com.ikokoon.toolkit.Toolkit;
/**
* This is the test for the aggregator. The aggregator takes the collected data on the methods, classes and packages and calculates the metrics like
* the abstractness the stability and so on.
*
* @author Michael Couck
* @since 02.08.09
* @version 01.00
*/
public class AggregatorTest extends ATest implements IConstants {
@Before
public void clear() {
Configuration.getConfiguration().includedPackages.clear();
Configuration.getConfiguration().includedPackages.add(Discovery.class.getPackage().getName());
Configuration.getConfiguration().includedPackages.add("edu.umd.cs.findbugs");
DataBaseToolkit.clear(dataBase);
Collector.initialize(dataBase);
}
@Test
public void aggregate() {
// D:/Eclipse/workspace/serenity/work/jobs/Discovery/builds/2010-02-27_19-28-14/serenity
double aggregationDuration = Executer.execute(new Executer.IPerform() {
public void execute() {
File odbDataBaseFile = new File("./src/test/resources/findbugs/serenity.odb");
IDataBase odbDataBase = IDataBase.DataBaseManager.getDataBase(DataBaseOdb.class, odbDataBaseFile.getAbsolutePath(), null);
IDataBase ramDataBase = IDataBase.DataBaseManager.getDataBase(DataBaseRam.class, "ramDatabase.ram", odbDataBase);
new Aggregator(null, ramDataBase).execute();
Project<?, ?> project = (Project<?, ?>) ramDataBase.find(Project.class, Toolkit.hash(Project.class.getName()));
if (project != null) {
logger.warn(ToStringBuilder.reflectionToString(project));
} else {
logger.warn("Project : " + project);
}
ramDataBase.close();
odbDataBase = IDataBase.DataBaseManager.getDataBase(DataBaseOdb.class, odbDataBaseFile.getAbsolutePath(), mockInternalDataBase);
project = (Project<?, ?>) odbDataBase.find(Project.class, Toolkit.hash(Project.class.getName()));
logger.warn(ToStringBuilder.reflectionToString(project));
odbDataBase.close();
}
}, "AggregatorTest : ", 1);
logger.warn("Aggregation took : " + aggregationDuration);
}
@Test
@SuppressWarnings("unchecked")
public void innerClasses() {
visitClass(DependencyClassAdapter.class, IDiscovery.class.getName());
visitClass(DependencyClassAdapter.class, Discovery.class.getName());
Project project = new Project();
project.setTimestamp(new Date());
dataBase.persist(project);
Package<?, ?> pakkage = dataBase.find(Package.class, Toolkit.hash(Discovery.class.getPackage().getName()));
assertNotNull(pakkage);
Class<?, ?> klass = dataBase.find(Class.class, Toolkit.hash(Discovery.class.getName()));
assertNotNull(klass);
Method<?, ?> method = dataBase.find(Method.class, Toolkit.hash(klass.getName(), "getAnonymousInnerClass", "()V"));
assertNotNull(method);
Aggregator aggregator = new Aggregator(null, dataBase);
aggregator.execute();
assertEquals(0d, method.getCoverage());
assertEquals(3, method.getChildren().size());
// Check the class
assertEquals(4, klass.getChildren().size()); // 10 + 15
// Sigma n=1, n, (method lines / class lines) * method complexity
// ((10 / 15) * 10) + ((5 / 15) * 20) = 6.666r + 6.6666r = 13.3333r
assertEquals(1d, klass.getComplexity());
// ((10 / 15) * 20) + ((5 / 15) * 40) = 13.33r + 13.333r =
assertEquals(0d, klass.getCoverage());
// e / e + a = 2 / 2 + 1 = 0.666r
assertEquals(1d, klass.getStability());
assertEquals(0d, klass.getEfference());
assertEquals(0d, klass.getAfference());
assertEquals(false, klass.getInterfaze());
// assertEquals(22d, pakkage.getLines());
// Sigma : (class lines / package lines) * class complexity
// ((15 / 65) * 13.333333333333332) + ((50 / 65) * 25) = 3.07692 + 19.2307 = 22.30692307692308
assertEquals(1d, pakkage.getComplexity());
// ((15 / 65) * 26.666666666666664) + ((50 / 65) * 7.996) = 6.1538 + 6.5107 = 12.298461538461538
assertEquals(0d, pakkage.getCoverage());
// i / (i + im) = 1 / 2 = 0.5
assertEquals(0d, pakkage.getAbstractness());
// e / (e + a) = 3 / 5 = 0.6666666666666666
assertEquals(1d, pakkage.getStability());
// d=|-stability + -abstractness + 1|/sqrt(-1²+-1²) = |-0.6666666666666666 + -0.5 + 1|sqrt(-1sq + -1sq) =
assertEquals(0.0d, pakkage.getDistance());
assertEquals(1d, pakkage.getInterfaces());
assertEquals(5d, pakkage.getImplementations());
assertEquals(0d, pakkage.getEfference());
assertEquals(0d, pakkage.getAfference());
assertEquals(6, pakkage.getChildren().size());
}
@Test
public void aggregateMethods() throws Exception {
visitClass(DependencyClassAdapter.class, IDiscovery.class.getName());
visitClass(DependencyClassAdapter.class, Discovery.class.getName());
Package<?, ?> pakkage = dataBase.find(Package.class, Toolkit.hash(Discovery.class.getPackage().getName()));
Set<Class<?, ?>> classes = new TreeSet<Class<?, ?>>();
Set<Method<?, ?>> methods = new TreeSet<Method<?, ?>>();
Set<Line<?, ?>> lines = new TreeSet<Line<?, ?>>();
getClassesMethodsAndLines(pakkage, classes, methods, lines);
for (Method<?, ?> method : methods) {
new MethodAggregator(dataBase, method).aggregate();
double executed = getExecuted(method);
double coverage = (executed / (double) method.getChildren().size()) * 100d;
assertEquals(Math.round(coverage), Math.round(method.getCoverage()));
}
}
@Test
public void aggregateClass() throws Exception {
visitClass(DependencyClassAdapter.class, IDiscovery.class.getName());
visitClass(DependencyClassAdapter.class, Discovery.class.getName());
Class<?, ?> klass = dataBase.find(Class.class, Toolkit.hash(Discovery.class.getName()));
assertEquals(getComplexity(klass), klass.getComplexity());
assertEquals(getCoverage(klass), klass.getCoverage());
assertEquals(getStability(klass), klass.getStability());
}
@Test
public void aggregatePackage() throws Exception {
visitClass(DependencyClassAdapter.class, IDiscovery.class.getName());
visitClass(DependencyClassAdapter.class, Discovery.class.getName());
Package<?, ?> pakkage = dataBase.find(Package.class, Toolkit.hash(Discovery.class.getPackage().getName()));
new PackageAggregator(dataBase, pakkage).aggregate();
assertEquals(getAbstractness(pakkage), pakkage.getAbstractness());
assertEquals(getComplexity(pakkage), pakkage.getComplexity());
assertEquals(getCoverage(pakkage), pakkage.getCoverage());
assertEquals(getDistance(pakkage), pakkage.getDistance());
assertEquals(getStability(pakkage), pakkage.getStability());
}
@Test
@SuppressWarnings("unchecked")
public void aggregateProject() throws Exception {
File odbDataBaseFile = new File("./src/test/resources/isearch/serenity.odb");
IDataBase dataBase = IDataBase.DataBaseManager.getDataBase(DataBaseOdb.class, odbDataBaseFile.getAbsolutePath(), null);
try {
Project<?, ?> project = dataBase.find(Project.class, Toolkit.hash(Project.class.getName()));
project.setAbstractness(0);
project.setClasses(0);
project.setComplexity(0);
project.setCoverage(0);
project.setDistance(0);
project.setLines(0);
project.setMethods(0);
project.setPackages(0);
project.setStability(0);
dataBase.persist(project);
DataBaseToolkit.execute(dataBase, new Package(), new DataBaseToolkit.Executer() {
public void execute(Object object) {
Package pakkage = (Package) object;
pakkage.setAbstractness(0);
pakkage.setAfference(0);
pakkage.setComplexity(0);
pakkage.setCoverage(0);
pakkage.setDistance(0);
pakkage.setEfference(0);
pakkage.setExecuted(0);
pakkage.setImplementations(0);
pakkage.setInterfaces(0);
pakkage.setLines(0);
pakkage.setStability(0);
}
});
DataBaseToolkit.execute(dataBase, new Class(), new DataBaseToolkit.Executer() {
public void execute(Object object) {
Class klass = (Class) object;
klass.setAfference(0);
klass.setComplexity(0);
klass.setCoverage(0);
klass.setEfference(0);
klass.setStability(0);
}
});
new Aggregator(null, dataBase).execute();
project = dataBase.find(Project.class, Toolkit.hash(Project.class.getName()));
assertTrue(project.getAbstractness() != 0);
assertTrue(project.getClasses() != 0);
assertTrue(project.getComplexity() != 0);
// assertTrue(project.getCoverage() != 0);
assertTrue(project.getDistance() != 0);
assertTrue(project.getLines() != 0);
assertTrue(project.getMethods() != 0);
assertTrue(project.getPackages() != 0);
assertTrue(project.getStability() != 0);
} finally {
dataBase.close();
}
}
@SuppressWarnings( { "unused", "unchecked" })
private double getComplexity(List<Package> pakkages) {
return 0d;
}
@SuppressWarnings( { "unchecked", "unused" })
private double getAbstractness(List<Package> pakkages) {
double interfaces = 0d;
double implementations = 0d;
for (Package<?, ?> pakkage : pakkages) {
interfaces += pakkage.getInterfaces();
implementations += pakkage.getImplementations();
}
return interfaces / implementations > 0 ? implementations : 0;
}
protected double getStability(Package<?, ?> pakkage) {
double efferent = 0d;
double afferent = 0d;
for (Class<?, ?> klass : pakkage.getChildren()) {
efferent += klass.getEfferent().size();
afferent = klass.getAfferent().size();
}
double denominator = efferent + afferent;
return denominator > 0 ? efferent / denominator : 1d;
}
protected double getDistance(Package<?, ?> pakkage) {
// TODO - validate this test - A + I = 1
double a = -1, b = -1;
double distance = Math.abs(-pakkage.getStability() + -pakkage.getAbstractness() + 1) / Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
return distance;
}
protected double getCoverage(Package<?, ?> pakkage) {
double coverage = 0d;
for (Class<?, ?> klass : pakkage.getChildren()) {
coverage += klass.getCoverage();
}
return coverage / pakkage.getChildren().size();
}
protected double getComplexity(Package<?, ?> pakkage) {
double complexity = 0d;
for (Class<?, ?> klass : pakkage.getChildren()) {
complexity += klass.getComplexity();
}
complexity = complexity / pakkage.getChildren().size();
return complexity;
}
protected double getAbstractness(Package<?, ?> pakkage) {
return pakkage.getInterfaces() / pakkage.getImplementations();
}
protected double getStability(Class<?, ?> klass) {
double numerator = klass.getEfferent().size();
double denominator = klass.getEfferent().size() + klass.getAfferent().size();
return denominator > 0 ? numerator / denominator : 0d;
}
protected double getCoverage(Class<?, ?> klass) {
double coverage = 0d;
for (Method<?, ?> method : klass.getChildren()) {
coverage += method.getCoverage();
}
coverage = coverage / (double) klass.getChildren().size() * 100d;
return coverage;
}
protected double getComplexity(Class<?, ?> klass) {
double complexity = 0d;
for (Method<?, ?> method : klass.getChildren()) {
complexity += method.getComplexity();
}
complexity = complexity / klass.getChildren().size();
return Math.max(1, complexity);
}
private void getClassesMethodsAndLines(Package<?, ?> pakkage, Set<Class<?, ?>> classes, Set<Method<?, ?>> methods, Set<Line<?, ?>> lines) {
for (Class<?, ?> klass : pakkage.getChildren()) {
classes.add(klass);
for (Method<?, ?> method : klass.getChildren()) {
methods.add(method);
for (Line<?, ?> line : method.getChildren()) {
lines.add(line);
}
}
}
}
private double getExecuted(Method<?, ?> method) {
double executed = 0d;
for (Line<?, ?> line : method.getChildren()) {
if (line.getCounter() > 0d) {
executed++;
}
}
return executed;
}
}