package controller;
import controller.effectiveoutlierness.Calculation;
import controller.effectiveoutlierness.Min;
import controller.effectiveoutlierness.Average;
import controller.effectiveoutlierness.Max;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import db.Database;
import db.DatabaseAccessException;
import db.DatabaseConfiguration;
import db.IncompatibleVersionException;
import db.InvalidDriverException;
/**
* The class is used to test all subspace functionalities, including the class {@link Subspace} and {@link Feature}
*/
public class SubspaceControllerTest {
private final String path = System.getProperty("java.io.tmpdir") + "/bsv_controller_tests";
private final String dbFile = this.path + "/database-junit-group.bsv";
private Database database = null;
private SubspaceController subspaceController;
/**
* Set up a clean database before we do the testing on it and init the group controller
*/
@Before
public void setup() {
// create working directory
(new File(this.path)).mkdirs();
// make sure the old file is deleted
(new File(this.dbFile)).delete();
try {
// create a new database with two features
this.database = new Database(this.dbFile);
String[] features = { "Feature 1", "Feature 2", "Outlierness 1", "Outlierness 2", "Outlierness 3" };
boolean[] outlier = { false, false, true, true, true };
this.database.initFeatures(features, outlier);
// create some subspaces
int[] ids1 = { 1, 2, 3 };
this.database.pushSubspace(1, ids1, "Subspace 1");
int[] ids2 = { 1, 4 };
this.database.pushSubspace(2, ids2, "Subspace 2");
int[] ids3 = { 2, 5 };
this.database.pushSubspace(3, ids3, "Subspace 3");
// create some objects
float[][] objects = { { 0.0f, 0.2f, 0.1f, 0.3f, 0.5f }, { 1.0f, 0.8f, 0.9f, 0.7f, 0.5f } };
this.database.pushObject(objects);
this.database.updateFeaturesMinMax();
this.subspaceController = new SubspaceController(this.database);
} catch (InvalidDriverException e) {
Assert.fail(e.getMessage());
} catch (IncompatibleVersionException e) {
Assert.fail(e.getMessage());
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
}
/**
* Clean up, after testing.
*/
@After
public void tearDown() {
// shutdown
try {
this.database.shutdown();
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
// clean up database
if (this.database != null) {
assertEquals(true, (new File(this.dbFile)).delete());
}
}
/**
* Test the {@link SubspaceController} and its methods
*/
@Test
public void subspaceControllerTest() {
try {
// check initial state and get subspace
assertEquals("Incorrect name for initial subspace", "All Features", this.subspaceController
.getActiveSubspace().getName());
assertEquals("Incorrect numbers of features in initial All Features subspace", 6, this.subspaceController
.getActiveSubspace().getFeatures().length);
assertEquals("Incorrect number of subspaces", 4, this.subspaceController.getSubspaces().length);
assertEquals("Incorrect name for all features", "All Features",
this.subspaceController.getSubspaces()[0].getName());
assertEquals("Incorrect name for subspace 1", "Subspace 1 - (Feature 1,Feature 2,Outlierness 1)",
this.subspaceController.getSubspaces()[1].getName());
assertEquals("Incorrect name for subspace 2", "Subspace 2 - (Feature 1,Outlierness 2)",
this.subspaceController.getSubspaces()[2].getName());
assertEquals("Incorrect name for subspace 3", "Subspace 3 - (Feature 2,Outlierness 3)",
this.subspaceController.getSubspaces()[3].getName());
// change active subspace
this.subspaceController.setActiveSubspace(this.subspaceController.getSubspaces()[3]);
assertEquals("Incorrect name for active subspace", "Subspace 3 - (Feature 2,Outlierness 3)",
this.subspaceController.getActiveSubspace().getName());
assertEquals("Incorrect numbers of features in active subspace", 3, this.subspaceController
.getActiveSubspace().getFeatures().length);
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
}
/**
* Test the constructor and the setter for illegal argument exception
*/
@Test
public void subspaceControllerArgumentTest() {
try {
new SubspaceController(null);
Assert.fail("Database was null");
} catch (IllegalArgumentException e) {
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
try {
this.subspaceController.setActiveSubspace(null);
Assert.fail("New active subspace was null");
} catch (IllegalArgumentException e) {
}
try {
this.subspaceController.setCalculateEffectiveOutliernessBy(null);
Assert.fail("New effective outlierness calculation was null");
} catch (IllegalArgumentException e) {
}
}
/**
* Test the effective outlierness handling in subspace controller
*/
@Test
public void effectiveOutliernessTest() {
assertEquals("Incorrect number of effective outlierness calculations", 3,
this.subspaceController.getAllCalculations().length);
assertEquals("Incorrect name for initial calculation", "Average", this.subspaceController
.getCalculateEffectiveOutliernessBy().getName());
this.subspaceController.setCalculateEffectiveOutliernessBy(this.subspaceController.getAllCalculations()[1]);
assertEquals("Incorrect name for outlierness calculation", "Max", this.subspaceController
.getCalculateEffectiveOutliernessBy().getName());
assertEquals("Incorrect name for outlierness calculation", "Max", this.subspaceController
.getCalculateEffectiveOutliernessBy().toString());
}
/**
* Test the class {@link Subspace} and its methods
*/
@Test
public void subspaceTest() {
Subspace subspace = this.subspaceController.getActiveSubspace();
try {
assertEquals("Incorrect id of subspace", 0, subspace.getId());
assertEquals("Incorrect name of subspace", "All Features", subspace.getName());
assertEquals("Incorrect name of subspace", "All Features", subspace.toString());
assertEquals("Incorrect number of features", 6, subspace.getFeatures().length);
assertTrue("Subspaces are not equal", subspace.equals(this.subspaceController.getActiveSubspace()));
assertFalse("The subspaces are equal", subspace.equals(this.subspaceController.getSubspaces()[3]));
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
}
/**
* Test the constructor of a subspace for illegal argument exception
*/
@Test
public void subspaceArgumentTest() {
Integer[] features = { 1, 2 };
try {
new Subspace(null, this.database, 1, "Subspace", features);
Assert.fail("Subspace controller was null");
} catch (IllegalArgumentException e) {
}
try {
new Subspace(this.subspaceController, null, 1, "Subspace", features);
Assert.fail("Database was null");
} catch (IllegalArgumentException e) {
}
try {
new Subspace(this.subspaceController, this.database, -1, "Subspace", features);
Assert.fail("Id was negative");
} catch (IllegalArgumentException e) {
}
try {
new Subspace(this.subspaceController, this.database, 1, null, features);
Assert.fail("Name was null");
} catch (IllegalArgumentException e) {
}
try {
new Subspace(this.subspaceController, this.database, 1, "Subspace", null);
Assert.fail("Features was null");
} catch (IllegalArgumentException e) {
}
}
/**
* Test the equal method of class {@link Subspace}
*/
@Test
public void subspaceEqualTest() {
Integer[] ids = { 1, 2, 3, 4 };
Subspace subspace1 = new Subspace(this.subspaceController, this.database, 1, "Subspace 1", ids);
Subspace subspace2 = new Subspace(this.subspaceController, this.database, 1, "Subspace 1", ids);
Subspace subspace3 = new Subspace(this.subspaceController, this.database, 2, "Subspace 2", ids);
assertTrue("Subpsaces are the same", subspace1.equals(subspace1));
assertTrue("Subspaces are equal", subspace1.equals(subspace2));
assertFalse("Subspaces are not equal", subspace1.equals(subspace3));
assertFalse("Object was no subspace", subspace1.equals(new Object()));
}
/**
* Test the class {@link Feature} and its methods
*/
@Test
public void featureTest() {
try {
Feature feature = this.subspaceController.getActiveSubspace().getFeatures()[1];
assertEquals("Incorrect id", 1, feature.getId());
assertEquals("Incorrect Name", "Feature 1", feature.getName());
assertEquals("Incorrect Name", "Feature 1", feature.toString());
assertFalse("Incorrect outlier flag", feature.isOutlier());
assertFalse("Incorrect virtual flag,", feature.isVirtual());
assertEquals("Incorrect max string length", DatabaseConfiguration.VARCHARLENGTH, feature.maxStringLength());
assertEquals("Incorrect min value for feature 1", 0.0f, feature.getMinValue(), 0.000000001f);
assertEquals("Incorrect max value for feature 1", 1.0f, feature.getMaxValue(), 0.000000001f);
assertEquals(feature.getId(), this.subspaceController.getActiveSubspace().getFeatures()[1].getId());
// test setter
feature.setName("new Feature 1");
assertEquals("Incorrect new name", "new Feature 1", feature.getName());
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
}
/**
* Test the class {@link Feature} and its methods
*/
@Test
public void effectiveOutliernessFeatureTest() {
try {
// calculate the effective outlierness to check the getMin and getMax methods
calculateEffectiveOutlierness(this.subspaceController.getCalculateEffectiveOutliernessBy());
Feature feature = this.subspaceController.getActiveSubspace().getFeatures()[0];
assertEquals("Incorrect id", -1, feature.getId());
assertEquals("Incorrect Name", "Effect. Outlierness", feature.getName());
assertEquals("Incorrect Name", "Effect. Outlierness", feature.toString());
assertFalse("Incorrect outlier flag", feature.isOutlier());
assertTrue("Incorrect virtual flag,", feature.isVirtual());
assertEquals("Incorrect max string length", DatabaseConfiguration.VARCHARLENGTH, feature.maxStringLength());
assertEquals("Incorrect min value for feature 1", 0.3f, feature.getMinValue(), 0.000001f);
assertEquals("Incorrect max value for feature 1", 0.7f, feature.getMaxValue(), 0.000001f);
assertEquals(feature.getId(), this.subspaceController.getActiveSubspace().getFeatures()[0].getId());
// test setter
feature.setName("new Name");
assertEquals("Incorrect new name", "new Name", feature.getName());
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
}
/**
* Test the constructor and setters in class {@link Feature} for illegal argument exceptions
*/
@Test
public void featureArgumentTest() {
// test constructor
try {
new Feature(null, this.database, 1, "Feature 1", false, false, 0, 1);
Assert.fail("Subspace controller was null");
} catch (IllegalArgumentException e) {
}
try {
new Feature(this.subspaceController, null, 1, "Feature 1", false, false, 0, 1);
Assert.fail("Database was null");
} catch (IllegalArgumentException e) {
}
try {
new Feature(this.subspaceController, this.database, 1, null, false, false, 0, 1);
Assert.fail("Name was null");
} catch (IllegalArgumentException e) {
}
try {
new Feature(this.subspaceController, this.database, 1, "aaaaaaaaaaaaaaaaaaaaaaaaa", false, false, 0, 1);
Assert.fail("Name was to long");
} catch (IllegalArgumentException e) {
}
// test the setters
Feature feature = null;
try {
feature = this.subspaceController.getActiveSubspace().getFeatures()[1];
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
try {
feature.setName(null);
Assert.fail("Name was null");
} catch (IllegalArgumentException e) {
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
try {
feature.setName("aaaaaaaaaaaaaaaaaaaaaaaa");
Assert.fail("Name was to long");
} catch (IllegalArgumentException e) {
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
}
/**
* Test the equal method of class {@link Feature}
*/
@Test
public void featureEqualTest() {
Feature feature1 = new Feature(this.subspaceController, this.database, 1, "Feature 1", false, false, 0, 1);
Feature feature2 = new Feature(this.subspaceController, this.database, 2, "Feature 2", false, false, 0, 1);
Feature feature3 = new Feature(this.subspaceController, this.database, 1, "Feature 3", false, false, 0, 1);
Feature feature4 = new Feature(this.subspaceController, this.database, 1, "Feature 1", true, false, 0, 1);
assertTrue("Objects are the same", feature1.equals(feature1));
assertFalse("Second feature was null", feature1.equals(null));
assertFalse("Second feature has other id", feature1.equals(feature2));
assertFalse("Second feature has other name", feature1.equals(feature3));
assertFalse("Second feature has other outlier flag", feature1.equals(feature4));
assertFalse("Second feature was no feature object", feature1.equals(new Object()));
}
/**
* Calculates the effective outlierness for two test elements, according to the given strategy
*
* @param effOut
* the strategy to calculate the effective outlierness by
* @return the calculated effective outlierness
*/
private float[] calculateEffectiveOutlierness(Calculation effOut) {
// the result vector for both calculations
float[] result = new float[2];
Feature[] features = null;
try {
features = this.subspaceController.getActiveSubspace().getFeatures();
} catch (DatabaseAccessException e) {
Assert.fail(e.getMessage());
}
// init an element for calculation
int[] featureIds = new int[features.length - 1];
for (int i = 1; i < features.length; i++) {
featureIds[i - 1] = features[i].getId();
}
// first element
float[] values1 = { 0.0f, 0.2f, 0.1f, 0.3f, 0.5f };
Group[] groups = new Group[0];
ElementData element1 = new ElementData(1, featureIds, values1, groups);
// calculate the effective outlierness
effOut.calculate(features, element1);
result[0] = element1.getValue(new Feature(this.subspaceController, this.database, -1, "Eff. Out.", false, true,
0, 1));
// second element
float[] values2 = { 1.0f, 0.8f, 0.9f, 0.7f, 0.5f };
groups = new Group[0];
ElementData element2 = new ElementData(1, featureIds, values2, groups);
// calculate the effective outlierness
effOut.calculate(features, element2);
result[1] = element2.getValue(new Feature(this.subspaceController, this.database, -1, "Eff. Out.", false, true,
0, 1));
return result;
}
/**
* Test the class {@link EffectiveOutliernessAverage}
*/
@Test
public void effectiveOutliernessAverageTest() {
Average effOut = new Average();
assertEquals("Incorrect average calculation", 0.3f, calculateEffectiveOutlierness(effOut)[0], 0.000001f);
assertEquals("Incorrect average calculation", 0.7f, calculateEffectiveOutlierness(effOut)[1], 0.000001f);
// test the min / max methods
assertEquals("Incorrect min outlierness", 0.3f, effOut.getMinValue(), 0.000001f);
assertEquals("Incorrect min outlierness", 0.7f, effOut.getMaxValue(), 0.000001f);
assertEquals("Incorrect name", "Average", effOut.getName());
}
/**
* Test the class {@link EffectiveOutliernessMax}
*/
@Test
public void effectiveOutliernessMaxTest() {
Max effOut = new Max();
assertEquals("Incorrect average calculation", 0.5f, calculateEffectiveOutlierness(effOut)[0], 0.000001f);
assertEquals("Incorrect average calculation", 0.9f, calculateEffectiveOutlierness(effOut)[1], 0.000001f);
// test the min / max methods
assertEquals("Incorrect min outlierness", 0.5f, effOut.getMinValue(), 0.000001f);
assertEquals("Incorrect min outlierness", 0.9f, effOut.getMaxValue(), 0.000001f);
assertEquals("Incorrect name", "Max", effOut.getName());
}
/**
* Test the class {@link EffectiveOutliernessMin}
*/
@Test
public void effectiveOutliernessMinTest() {
Min effOut = new Min();
assertEquals("Incorrect average calculation", 0.1f, calculateEffectiveOutlierness(effOut)[0], 0.000001f);
assertEquals("Incorrect average calculation", 0.5f, calculateEffectiveOutlierness(effOut)[1], 0.000001f);
// test the min / max methods
assertEquals("Incorrect min outlierness", 0.1f, effOut.getMinValue(), 0.000001f);
assertEquals("Incorrect min outlierness", 0.5f, effOut.getMaxValue(), 0.000001f);
assertEquals("Incorrect name", "Min", effOut.getName());
}
}