package org.wikipedia.nearby;
import android.location.Location;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.wikipedia.R;
import org.wikipedia.test.TestRunner;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
/**
* Unit tests for Nearby related classes. Probably should refactor this into a model class.
*/
@SuppressWarnings("checkstyle:magicnumber") @RunWith(TestRunner.class)
public class NearbyUnitTest {
/** dist(origin, point a) */
private static final int A = 111_319;
private Location nextLocation;
private List<NearbyPage> nearbyPages;
@Before
public void setUp() throws Throwable {
nextLocation = new Location("current");
nextLocation.setLatitude(0.0d);
nextLocation.setLongitude(0.0d);
nearbyPages = new LinkedList<>();
nearbyPages.add(constructNearbyPage("c", 0.0, 3.0));
nearbyPages.add(constructNearbyPage("b", 0.0, 2.0));
nearbyPages.add(constructNearbyPage("a", 0.0, 1.0));
}
@Test public void testSort() throws Throwable {
calcDistances(nearbyPages);
Collections.sort(nearbyPages, new NearbyDistanceComparator());
assertThat("a", is(nearbyPages.get(0).getTitle()));
assertThat("b", is(nearbyPages.get(1).getTitle()));
assertThat("c", is(nearbyPages.get(2).getTitle()));
}
@Test public void testSortWithNullLocations() throws Throwable {
final Location location = null;
nearbyPages.add(new NearbyPage("d", location));
nearbyPages.add(new NearbyPage("e", location));
calcDistances(nearbyPages);
Collections.sort(nearbyPages, new NearbyDistanceComparator());
assertThat("a", is(nearbyPages.get(0).getTitle()));
assertThat("b", is(nearbyPages.get(1).getTitle()));
assertThat("c", is(nearbyPages.get(2).getTitle()));
// the two null location values come last but in the same order as from the original list:
assertThat("d", is(nearbyPages.get(3).getTitle()));
assertThat("e", is(nearbyPages.get(4).getTitle()));
}
@Test public void testCompare() throws Throwable {
final Location location = null;
NearbyPage nullLocPage = new NearbyPage("nowhere", location);
calcDistances(nearbyPages);
nullLocPage.setDistance(getDistance(nullLocPage.getLocation()));
assertThat(Integer.MAX_VALUE, is(nullLocPage.getDistance()));
NearbyDistanceComparator comp = new NearbyDistanceComparator();
assertThat(A, is(comp.compare(nearbyPages.get(1), nearbyPages.get(2))));
assertThat(-1 * A, is(comp.compare(nearbyPages.get(2), nearbyPages.get(1))));
assertThat(Integer.MAX_VALUE - A, is(comp.compare(nullLocPage, nearbyPages.get(2))));
assertThat((Integer.MIN_VALUE + 1) + A, is(comp.compare(nearbyPages.get(2), nullLocPage))); // - (max - a)
assertThat(0, is(comp.compare(nullLocPage, nullLocPage)));
}
@Test public void testGetDistanceLabelSameLocation() throws Throwable {
Location locationA = new Location("current");
locationA.setLatitude(0.0d);
locationA.setLongitude(0.0d);
assertThat("0 m", is(getDistanceLabel(locationA)));
}
@Test public void testGetDistanceLabelMeters() throws Throwable {
Location locationB = new Location("b");
locationB.setLatitude(0.0d);
locationB.setLongitude(0.001d);
assertThat("111 m", is(getDistanceLabel(locationB)));
}
@Test public void testGetDistanceLabelKilometers() throws Throwable {
Location locationB = new Location("b");
locationB.setLatitude(0.0d);
locationB.setLongitude(0.01d);
assertThat("1.11 km", is(getDistanceLabel(locationB)));
}
@Test public void testGetDistanceLabelNull() throws Throwable {
assertThat(" ", is(getDistanceLabel(null)));
}
private class NearbyDistanceComparator implements Comparator<NearbyPage> {
@Override
public int compare(NearbyPage a, NearbyPage b) {
return a.getDistance() - b.getDistance();
}
}
//
// UGLY: copy of production code
//
/**
* Calculates the distances from the origin to the given pages.
* This method should be called before sorting.
*/
private void calcDistances(List<NearbyPage> pages) {
for (NearbyPage page : pages) {
page.setDistance(getDistance(page.getLocation()));
}
}
private int getDistance(Location otherLocation) {
if (otherLocation == null) {
return Integer.MAX_VALUE;
} else {
return (int) nextLocation.distanceTo(otherLocation);
}
}
private static final int ONE_KM = 1000;
private static final double ONE_KM_D = 1000.0d;
private String getDistanceLabel(Location otherLocation) {
if (otherLocation == null) {
return " ";
}
final int distance = getDistance(otherLocation);
if (distance < ONE_KM) {
return getString(R.string.nearby_distance_in_meters, distance);
} else {
return getString(R.string.nearby_distance_in_kilometers, distance / ONE_KM_D);
}
}
private String getString(@StringRes int id, Object... formatArgs) {
return RuntimeEnvironment.application.getString(id, formatArgs);
}
private NearbyPage constructNearbyPage(@NonNull String title, double lat, double lon) {
Location location = new Location("");
location.setLatitude(lat);
location.setLongitude(lon);
return new NearbyPage(title, location);
}
}