package cgeo.geocaching;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
import java.util.GregorianCalendar;
import cgeo.CGeoTestCase;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.gc.GCLogin;
import cgeo.geocaching.connector.gc.GCMemberState;
import cgeo.geocaching.connector.gc.GCParser;
import cgeo.geocaching.connector.gc.MapTokens;
import cgeo.geocaching.connector.gc.Tile;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.log.LogEntry;
import cgeo.geocaching.log.LogType;
import cgeo.geocaching.maps.LivemapStrategy;
import cgeo.geocaching.models.Geocache;
import cgeo.geocaching.models.Trackable;
import cgeo.geocaching.settings.Credentials;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.TestSettings;
import cgeo.geocaching.storage.DataStore;
import cgeo.geocaching.test.mock.GC1ZXX2;
import cgeo.geocaching.test.mock.GC2JVEH;
import cgeo.geocaching.test.mock.GC3FJ5F;
import cgeo.geocaching.test.mock.MockedCache;
import cgeo.geocaching.utils.DisposableHandler;
import cgeo.geocaching.utils.Log;
import cgeo.test.Compare;
import static org.assertj.core.api.Java6Assertions.assertThat;
/**
* The c:geo application test. It can be used for tests that require an
* application and/or context.
*/
public class CgeoApplicationTest extends CGeoTestCase {
private static final MapTokens INVALID_TOKEN = null;
/**
* The name 'test preconditions' is a convention to signal that if this test
* doesn't pass, the test case was not set up properly and it might explain
* any and all failures in other tests. This is not guaranteed to run before
* other tests, as junit uses reflection to find the tests.
*/
@SmallTest
public void testPreconditions() {
assertThat(GCLogin.getInstance().login()).as("User and password must be provided").isEqualTo(StatusCode.NO_ERROR);
assertThat(Settings.isGCPremiumMember()).as("User must be premium member for some of the tests to succeed").isTrue();
}
/**
* Test {@link GCParser#searchTrackable(String, String, String)}
*/
@MediumTest
public static void testSearchTrackableNotExisting() {
final Trackable tb = GCParser.searchTrackable("123456", null, null);
assertThat(tb).isNull();
}
/**
* Test {@link GCParser#searchTrackable(String, String, String)}
*/
@MediumTest
public static void testSearchTrackable() {
final Trackable tb = GCParser.searchTrackable("TB2J1VZ", null, null);
assertThat(tb).isNotNull();
assert tb != null; // eclipse bug
// fix data
assertThat(tb.getGuid()).isEqualTo("aefffb86-099f-444f-b132-605436163aa8");
assertThat(tb.getGeocode()).isEqualTo("TB2J1VZ");
assertThat(tb.getIconUrl()).endsWith("://www.geocaching.com/images/wpttypes/21.gif");
assertThat(tb.getName()).isEqualTo("blafoo's Children Music CD");
assertThat(tb.getType()).isEqualTo("Travel Bug Dog Tag");
assertThat(tb.getReleased()).isEqualTo(new GregorianCalendar(2009, 8 - 1, 24).getTime());
assertThat(tb.getOrigin()).isEqualTo("Niedersachsen, Germany");
assertThat(tb.getOwner()).isEqualTo("blafoo");
assertThat(tb.getOwnerGuid()).isEqualTo("0564a940-8311-40ee-8e76-7e91b2cf6284");
assertThat(tb.getGoal()).isEqualTo("Kinder erfreuen.<br /><br />Make children happy.");
assertThat(tb.getDetails()).startsWith("Auf der CD sind");
// the host of the image can vary
assertThat(tb.getImage()).endsWith("geocaching.com/track/large/38382780-87a7-4393-8393-78841678ee8c.jpg");
// Following data can change over time
assertThat(tb.getDistance()).isGreaterThanOrEqualTo(10617.8f);
assertThat(tb.getLogs().size()).isGreaterThanOrEqualTo(10);
assertThat(tb.getSpottedType() == Trackable.SPOTTED_CACHE || tb.getSpottedType() == Trackable.SPOTTED_USER || tb.getSpottedType() == Trackable.SPOTTED_UNKNOWN).isTrue();
// no assumption possible: assertThat(tb.getSpottedGuid()).isEqualTo("faa2d47d-19ea-422f-bec8-318fc82c8063");
// no assumption possible: assertThat(tb.getSpottedName()).isEqualTo("Nice place for a break cache");
// we can't check specifics in the log entries since they change, but we can verify data was parsed
for (final LogEntry log : tb.getLogs()) {
assertThat(log.date).isGreaterThan(0);
assertThat(log.author).isNotEmpty();
if (log.getType() == LogType.PLACED_IT || log.getType() == LogType.RETRIEVED_IT) {
assertThat(log.cacheName).isNotEmpty();
assertThat(log.cacheGuid).isNotEmpty();
} else {
assertThat(log.getType()).isNotEqualTo(LogType.UNKNOWN);
}
}
}
/**
* Test {@link Geocache#searchByGeocode(String, String, boolean, DisposableHandler)}
*/
@MediumTest
public static Geocache testSearchByGeocode(final String geocode) {
final SearchResult search = Geocache.searchByGeocode(geocode, null, true, null);
assertThat(search).isNotNull();
if (Settings.isGCPremiumMember() || search.getError() == StatusCode.NO_ERROR) {
assertThat(search.getGeocodes()).containsExactly(geocode);
return DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
}
assertThat(search.getGeocodes()).isEmpty();
return null;
}
/**
* Test {@link Geocache#searchByGeocode(String, String, boolean, DisposableHandler)}
*/
@MediumTest
public static void testSearchByGeocodeNotExisting() {
final SearchResult search = Geocache.searchByGeocode("GC123456", null, true, null);
assertThat(search).isNotNull();
assertThat(search.getError()).isEqualTo(StatusCode.CACHE_NOT_FOUND);
}
/**
* Set the login data to the cgeo login, run the given Runnable, and restore the login.
*
*/
private static void withMockedLoginDo(final Runnable runnable) {
final Credentials credentials = Settings.getGcCredentials();
final GCMemberState memberStatus = Settings.getGCMemberStatus();
try {
runnable.run();
} finally {
// restore user and password
TestSettings.setLogin(credentials);
Settings.setGCMemberStatus(memberStatus);
GCLogin.getInstance().login();
}
}
/**
* Test {@link Geocache#searchByGeocode(String, String, boolean, DisposableHandler)}
*/
@MediumTest
public static void testSearchByGeocodeNotLoggedIn() {
withMockedLoginDo(new Runnable() {
@Override
public void run() {
// non premium cache
MockedCache cache = new GC3FJ5F();
deleteCacheFromDBAndLogout(cache.getGeocode());
SearchResult search = Geocache.searchByGeocode(cache.getGeocode(), null, true, null);
assertThat(search).isNotNull();
assertThat(search.getGeocodes()).containsExactly(cache.getGeocode());
final Geocache searchedCache = search.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
// coords must be null if the user is not logged in
assertThat(searchedCache).isNotNull();
assert searchedCache != null; // eclipse bug
assertThat(searchedCache.getCoords()).isNull();
// premium cache. Not visible to guests
cache = new GC2JVEH();
deleteCacheFromDBAndLogout(cache.getGeocode());
search = Geocache.searchByGeocode(cache.getGeocode(), null, true, null);
assertThat(search).isNotNull();
assertThat(search.getGeocodes()).isEmpty();
}
});
}
/**
* Test {@link Geocache#searchByGeocode(String, String, boolean, DisposableHandler)}
*/
@MediumTest
public static void testSearchErrorOccured() {
withMockedLoginDo(new Runnable() {
@Override
public void run() {
// non premium cache
final MockedCache cache = new GC1ZXX2();
deleteCacheFromDBAndLogout(cache.getGeocode());
final SearchResult search = Geocache.searchByGeocode(cache.getGeocode(), null, true, null);
assertThat(search).isNotNull();
assertThat(search.getGeocodes()).isEmpty();
}
});
}
/**
* mock the "exclude disabled caches" and "exclude my caches" options for the execution of the runnable
*
*/
private static void withMockedFilters(final Runnable runnable) {
// backup user settings
final boolean excludeMine = Settings.isExcludeMyCaches();
final boolean excludeDisabled = Settings.isExcludeDisabledCaches();
try {
// set up settings required for test
TestSettings.setExcludeMine(false);
TestSettings.setExcludeDisabledCaches(false);
runnable.run();
} finally {
// restore user settings
TestSettings.setExcludeMine(excludeMine);
TestSettings.setExcludeDisabledCaches(excludeDisabled);
}
}
/**
* Test {@link GCParser#searchByCoords(Geopoint, CacheType)}
*/
@MediumTest
public static void testSearchByCoords() {
withMockedFilters(new Runnable() {
@Override
public void run() {
final SearchResult search = GCParser.searchByCoords(new Geopoint("N 50° 06.654 E 008° 39.777"), CacheType.MYSTERY);
assertThat(search).isNotNull();
assertThat(search.getGeocodes().size()).isGreaterThanOrEqualTo(20);
assertThat(search.getGeocodes()).contains("GC1HBMY");
}
});
}
/**
* Test {@link GCParser#searchByOwner(String, CacheType)}
*/
@MediumTest
public static void testSearchByOwner() {
withMockedFilters(new Runnable() {
@Override
public void run() {
final SearchResult search = GCParser.searchByOwner("blafoo", CacheType.MYSTERY);
assertThat(search).isNotNull();
assertThat(search.getGeocodes()).hasSize(7);
assertThat(search.getGeocodes()).contains("GC36RT6");
}
});
}
/**
* Test {@link GCParser#searchByUsername(String, CacheType)}
*/
@MediumTest
public static void testSearchByUsername() {
withMockedFilters(new Runnable() {
@Override
public void run() {
final SearchResult search = GCParser.searchByUsername("blafoo", CacheType.WEBCAM);
assertThat(search).isNotNull();
assertThat(search.getTotalCountGC()).isEqualTo(5);
assertThat(search.getGeocodes()).contains("GCP0A9");
}
});
}
/**
* Test {@link ConnectorFactory#searchByViewport(Viewport, MapTokens)}
*/
@MediumTest
public static void testSearchByViewport() {
withMockedFilters(new Runnable() {
@Override
public void run() {
// backup user settings
final LivemapStrategy strategy = Settings.getLiveMapStrategy();
final CacheType cacheType = Settings.getCacheType();
try {
// set up settings required for test
TestSettings.setExcludeMine(false);
Settings.setCacheType(CacheType.ALL);
final GC3FJ5F mockedCache = new GC3FJ5F();
deleteCacheFromDB(mockedCache.getGeocode());
final MapTokens tokens = GCLogin.getInstance().getMapTokens();
final Viewport viewport = new Viewport(mockedCache, 0.003, 0.003);
// check coords for DETAILED
Settings.setLiveMapStrategy(LivemapStrategy.DETAILED);
SearchResult search = ConnectorFactory.searchByViewport(viewport, tokens);
assertThat(search).isNotNull();
assertThat(search.getGeocodes()).contains(mockedCache.getGeocode());
Geocache parsedCache = DataStore.loadCache(mockedCache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB);
assert parsedCache != null;
assertThat(parsedCache).isNotNull();
assertThat(mockedCache.getCoords().equals(parsedCache.getCoords())).isEqualTo(Settings.isGCPremiumMember());
assertThat(parsedCache.isReliableLatLon()).isEqualTo(Settings.isGCPremiumMember());
// check update after switch strategy to FAST
Settings.setLiveMapStrategy(LivemapStrategy.FAST);
Tile.cache.removeFromTileCache(mockedCache);
search = ConnectorFactory.searchByViewport(viewport, tokens);
assertThat(search).isNotNull();
assertThat(search.getGeocodes()).contains(mockedCache.getGeocode());
parsedCache = DataStore.loadCache(mockedCache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB);
assert parsedCache != null;
assertThat(parsedCache).isNotNull();
assertThat(mockedCache.getCoords().equals(parsedCache.getCoords())).isEqualTo(Settings.isGCPremiumMember());
assertThat(parsedCache.isReliableLatLon()).isEqualTo(Settings.isGCPremiumMember());
} finally {
// restore user settings
Settings.setLiveMapStrategy(strategy);
Settings.setCacheType(cacheType);
}
}
});
}
/**
* Test {@link ConnectorFactory#searchByViewport(Viewport, MapTokens)}
*/
@MediumTest
public static void testSearchByViewportNotLoggedIn() {
withMockedLoginDo(new Runnable() {
@Override
public void run() {
final LivemapStrategy strategy = Settings.getLiveMapStrategy();
final LivemapStrategy testStrategy = LivemapStrategy.FAST; // FASTEST, FAST or DETAILED for tests
Settings.setLiveMapStrategy(testStrategy);
final CacheType cacheType = Settings.getCacheType();
try {
{ // non premium cache
final MockedCache cache = new GC3FJ5F();
deleteCacheFromDBAndLogout(cache.getGeocode());
Tile.cache.removeFromTileCache(cache);
Settings.setCacheType(CacheType.ALL);
final Viewport viewport = new Viewport(cache, 0.003, 0.003);
final SearchResult search = ConnectorFactory.searchByViewport(viewport, INVALID_TOKEN);
assertThat(search).isNotNull();
assertThat(search.getGeocodes()).contains(cache.getGeocode());
// coords differ
final Geocache cacheFromViewport = DataStore.loadCache(cache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB);
assert cacheFromViewport != null;
assertThat(cacheFromViewport).isNotNull();
Log.d("cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords expected = " + cache.getCoords());
Log.d("cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords actual = " + cacheFromViewport.getCoords());
assertThat(cache.getCoords().distanceTo(cacheFromViewport.getCoords())).isGreaterThan(1e-4f);
// depending on the chosen strategy the coords can be reliable or not
// noinspection ConstantConditions
assertThat(cacheFromViewport.isReliableLatLon()).isEqualTo(testStrategy == LivemapStrategy.DETAILED);
}
{ // premium cache
final MockedCache cache = new MockedCache(new Geopoint(49.010183, 2.566117)) {
@Override
public String getGeocode() {
return "GC1K1W4";
}
};
deleteCacheFromDBAndLogout(cache.getGeocode());
Tile.cache.removeFromTileCache(cache);
Settings.setCacheType(CacheType.ALL);
final Viewport viewport = new Viewport(cache, 0.003, 0.003);
final SearchResult search = ConnectorFactory.searchByViewport(viewport, INVALID_TOKEN);
assertThat(search).isNotNull();
assertThat(search.getGeocodes()).contains(cache.getGeocode());
// coords differ
final Geocache cacheFromViewport = DataStore.loadCache(cache.getGeocode(), LoadFlags.LOAD_CACHE_OR_DB);
assert cacheFromViewport != null;
assertThat(cacheFromViewport).isNotNull();
Log.d("cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords expected = " + cache.getCoords());
Log.d("cgeoApplicationTest.testSearchByViewportNotLoggedIn: Coords actual = " + cacheFromViewport.getCoords());
assertThat(cache.getCoords().distanceTo(cacheFromViewport.getCoords()) <= 1e-3).isFalse();
// depending on the chosen strategy the coords can be reliable or not
// noinspection ConstantConditions
assertThat(cacheFromViewport.isReliableLatLon()).isEqualTo(testStrategy == LivemapStrategy.DETAILED);
}
} finally {
Settings.setLiveMapStrategy(strategy);
Settings.setCacheType(cacheType);
}
}
});
}
/**
* Test cache parsing. Esp. useful after a GC.com update
*/
public static void testSearchByGeocodeBasis() {
for (final MockedCache mockedCache : MockedCache.MOCKED_CACHES) {
final String oldUser = mockedCache.getMockedDataUser();
try {
mockedCache.setMockedDataUser(Settings.getUserName());
final Geocache parsedCache = CgeoApplicationTest.testSearchByGeocode(mockedCache.getGeocode());
Compare.assertCompareCaches(mockedCache, parsedCache, true);
} finally {
mockedCache.setMockedDataUser(oldUser);
}
}
}
/**
* Caches that are good test cases
*/
public static void testSearchByGeocodeSpecialties() {
final Geocache gcv2r9 = CgeoApplicationTest.testSearchByGeocode("GCV2R9");
assertThat(gcv2r9).isNotNull();
assertThat(gcv2r9.getLocation()).isEqualTo("California, United States");
final Geocache gc1zxez = CgeoApplicationTest.testSearchByGeocode("GC1ZXEZ");
assertThat(gc1zxez).isNotNull();
assertThat(gc1zxez.getOwnerUserId()).isEqualTo("Ms.Marple/Mr.Stringer");
}
/** Remove cache from DB and cache to ensure that the cache is not loaded from the database */
private static void deleteCacheFromDBAndLogout(final String geocode) {
deleteCacheFromDB(geocode);
GCLogin.getInstance().logout();
// Modify login data to avoid an automatic login again
TestSettings.setLogin(new Credentials("c:geo", "c:geo"));
Settings.setGCMemberStatus(GCMemberState.BASIC);
}
}