package freenet.node;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import junit.framework.TestCase;
public class PeerLocationTest extends TestCase {
private static final double EPSILON = 1e-15;
private static final double[][] PEER_LOCATIONS = new double[][] {
// Must be sorted!
{ 0.1 },
{ 0.0 },
{ 0.9 },
{ 0.1, 0.3 },
{ 0.1, 0.3, 0.4 },
{ 0.0, 0.1, 0.2, 0.3, 0.3, 0.35, 0.5, 0.5, 0.99 },
{ 0.1, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24 },
{ 0.0000001, 0.0000003, 0.0001, 0.0002, 0.4, 0.5, 0.999, 0.999999, 0.9999995 },
{ 0, 0.1, 0.11, 0.9, 0.99, 1 }
};
private static final double[] TARGET_LOCATIONS = new double[] {
0.0, 1e-12, 0.01, 0.05, 0.09, 0.1, 0.11, 0.29, 0.3, 0.31,
0.35, 0.4, 0.45, 0.5, 0.51, 0.9, 0.91, 0.9999, 1 - 1e-12
};
public void testFindClosestLocation() {
for (double[] peers : PEER_LOCATIONS) {
for (double target : TARGET_LOCATIONS) {
int closest = PeerLocation.findClosestLocation(peers, target);
double ref = trivialFindClosestDistance(peers, target);
assertEquals(ref, Location.distance(peers[closest], target), EPSILON);
}
}
}
public void testGetClosestPeerLocation() {
for (double[] peers : PEER_LOCATIONS) {
PeerLocation pl = new PeerLocation("0.0");
assertTrue(pl.updateLocation(0.0, peers));
for (double target : TARGET_LOCATIONS) {
for (Set<Double> exclude : omit(peers)) {
double closest = pl.getClosestPeerLocation(target, exclude);
assertFalse(exclude.contains(closest));
double ref = trivialFindClosestDistance(peers, target, exclude);
if (!Double.isInfinite(ref)) {
assertFalse(Double.isNaN(closest));
boolean isPeer = false;
for (double peer : peers) {
if (closest == peer) {
isPeer = true;
break;
}
}
assertTrue(isPeer);
assertEquals(ref, Location.distance(closest, target), EPSILON);
} else {
assertTrue(Double.isNaN(closest));
}
}
}
}
}
// Generate sets of sequential omitted values of half the length, plus the empty set
@SuppressWarnings("unchecked")
private Set<Double>[] omit(double[] locs) {
Set<Double>[] result = (Set<Double>[]) new Set<?>[locs.length + 1];
result[locs.length] = new HashSet<Double>();
int n = locs.length / 2 + 1;
for (int i = 0; i < locs.length; i++) {
Set<Double> s = new HashSet<Double>();
for (int j = 0; j < n; j++) {
s.add(locs[(i + j) % locs.length]);
}
result[i] = s;
assertFalse(result[i].isEmpty());
}
return result;
}
// Trivial reference implementation that finds the distance to the closest location
private double trivialFindClosestDistance(double[] locs, double l) {
double minDist = Double.POSITIVE_INFINITY;
for (int i = 0; i < locs.length; i++) {
final double d = Location.distance(locs[i], l);
if (d < minDist) {
minDist = d;
}
}
return minDist;
}
// Trivial reference implementation that finds the distance to the closest location, with some
// locations excluded from consideration
private double trivialFindClosestDistance(double[] locs, double l, Set<Double> exclude) {
double minDist = Double.POSITIVE_INFINITY;
for (int i = 0; i < locs.length; i++) {
if (exclude.contains(locs[i])) {
continue;
}
final double d = Location.distance(locs[i], l);
if (d < minDist) {
minDist = d;
}
}
return minDist;
}
}