From 2ac6d5d07b349b9fa8210e55f1755beb03184d04 Mon Sep 17 00:00:00 2001 From: Rodrigo Damazio Date: Wed, 25 Jan 2012 20:42:49 -0200 Subject: [PATCH] Adding tests for the search functionality. --- .../mytracks/content/SearchEngineTest.java | 313 ++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 MyTracksTest/src/com/google/android/apps/mytracks/content/SearchEngineTest.java diff --git a/MyTracksTest/src/com/google/android/apps/mytracks/content/SearchEngineTest.java b/MyTracksTest/src/com/google/android/apps/mytracks/content/SearchEngineTest.java new file mode 100644 index 000000000..3fef63c1d --- /dev/null +++ b/MyTracksTest/src/com/google/android/apps/mytracks/content/SearchEngineTest.java @@ -0,0 +1,313 @@ +/** + * + */ +package com.google.android.apps.mytracks.content; + +import com.google.android.apps.mytracks.content.SearchEngine.ScoredResult; +import com.google.android.apps.mytracks.content.SearchEngine.SearchQuery; +import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext; +import com.google.android.apps.mytracks.stats.TripStatistics; + +import android.content.ContentUris; +import android.location.Location; +import android.net.Uri; +import android.test.AndroidTestCase; +import android.test.RenamingDelegatingContext; +import android.test.mock.MockContentResolver; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Tests for {@link SearchEngine}. + * These are not meant to be quality tests, but instead feature-by-feature tests + * (in other words, they don't test the mixing of different score boostings, just + * each boosting separately) + * + * @author Rodrigo Damazio + */ +public class SearchEngineTest extends AndroidTestCase { + + private static final Location HERE = new Location("gps"); + private static final long NOW = 1234567890000L; // After OLDEST_ALLOWED_TIMESTAMP + private MyTracksProviderUtils providerUtils; + private SearchEngine engine; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + MockContentResolver mockContentResolver = new MockContentResolver(); + RenamingDelegatingContext targetContext = new RenamingDelegatingContext( + getContext(), getContext(), "test."); + MockContext context = new MockContext(mockContentResolver, targetContext); + MyTracksProvider provider = new MyTracksProvider(); + provider.attachInfo(context, null); + mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider); + setContext(context); + + providerUtils = MyTracksProviderUtils.Factory.get(context); + engine = new SearchEngine(providerUtils); + } + + @Override + protected void tearDown() throws Exception { + providerUtils.deleteAllTracks(); + + super.tearDown(); + } + + private long insertTrack(String title, String description, String category, double distance, long hoursAgo) { + Track track = new Track(); + track.setName(title); + track.setDescription(description); + track.setCategory(category); + + TripStatistics stats = track.getStatistics(); + if (hoursAgo > 0) { + // Started twice hoursAgo, so the average time is hoursAgo. + stats.setStartTime(NOW - hoursAgo * 1000L * 60L * 60L * 2); + stats.setStopTime(NOW); + } + + int latitude = (int) ((HERE.getLatitude() + distance) * 1E6); + int longitude = (int) ((HERE.getLongitude() + distance) * 1E6); + stats.setBounds(latitude, longitude, latitude, longitude); + + Uri uri = providerUtils.insertTrack(track); + return ContentUris.parseId(uri); + } + + private long insertTrack(String title, String description, String category) { + return insertTrack(title, description, category, 0, -1); + } + + private long insertTrack(String title, double distance) { + return insertTrack(title, "", "", distance, -1); + } + + private long insertTrack(String title, long hoursAgo) { + return insertTrack(title, "", "", 0.0, hoursAgo); + } + + private long insertWaypoint(String title, String description, String category, double distance, long hoursAgo, long trackId) { + Waypoint waypoint = new Waypoint(); + waypoint.setName(title); + waypoint.setDescription(description); + waypoint.setCategory(category); + waypoint.setTrackId(trackId); + + Location location = new Location(HERE); + location.setLatitude(location.getLatitude() + distance); + location.setLongitude(location.getLongitude() + distance); + if (hoursAgo >= 0) { + location.setTime(NOW - hoursAgo * 1000L * 60L * 60L); + } + waypoint.setLocation(location); + + Uri uri = providerUtils.insertWaypoint(waypoint); + return ContentUris.parseId(uri); + } + + private long insertWaypoint(String title, String description, String category) { + return insertWaypoint(title, description, category, 0.0, -1, -1); + } + + private long insertWaypoint(String title, double distance) { + return insertWaypoint(title, "", "", distance, -1, -1); + } + + private long insertWaypoint(String title, long hoursAgo) { + return insertWaypoint(title, "", "", 0.0, hoursAgo, -1); + } + + private long insertWaypoint(String title, long hoursAgo, long trackId) { + return insertWaypoint(title, "", "", 0.0, hoursAgo, trackId); + } + + public void testSearchText() { + // Insert 7 tracks (purposefully out of result order): + // - one which won't match + // - one which will match the description + // - one which will match the category + // - one which will match the title + // - one which will match in title and category + // - one which will match in title and description + // - one which will match in all fields + insertTrack("bb", "cc", "dd"); + long descriptionMatchId = insertTrack("bb", "aa", "cc"); + long categoryMatchId = insertTrack("bb", "cc", "aa"); + long titleMatchId = insertTrack("aa", "bb", "cc"); + long titleCategoryMatchId = insertTrack("aa", "bb", "ca"); + long titleDescriptionMatchId = insertTrack("aa", "ba", "cc"); + long allMatchId = insertTrack("aa", "ba", "ca"); + + SearchQuery query = new SearchQuery("a", null, -1, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Title > Description > Category. + assertTrackResults(results, + allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId, + categoryMatchId); + } + + public void testSearchWaypointText() { + // Insert 7 waypoints (purposefully out of result order): + // - one which won't match + // - one which will match the description + // - one which will match the category + // - one which will match the title + // - one which will match in title and category + // - one which will match in title and description + // - one which will match in all fields + insertWaypoint("bb", "cc", "dd"); + long descriptionMatchId = insertWaypoint("bb", "aa", "cc"); + long categoryMatchId = insertWaypoint("bb", "cc", "aa"); + long titleMatchId = insertWaypoint("aa", "bb", "cc"); + long titleCategoryMatchId = insertWaypoint("aa", "bb", "ca"); + long titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc"); + long allMatchId = insertWaypoint("aa", "ba", "ca"); + + SearchQuery query = new SearchQuery("a", null, -1, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Title > Description > Category. + assertWaypointResults(results, + allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId, + categoryMatchId); + } + + public void testSearchMixedText() { + // Insert 5 entries (purposefully out of result order): + // - one waypoint which will match by description + // - one waypoint which won't match + // - one waypoint which will match by title + // - one track which won't match + // - one track which will match by title + long descriptionWaypointId = insertWaypoint("bb", "aa", "cc"); + insertWaypoint("bb", "cc", "dd"); + long titleWaypointId = insertWaypoint("aa", "bb", "cc"); + insertTrack("bb", "cc", "dd"); + long trackId = insertTrack("aa", "bb", "cc"); + + SearchQuery query = new SearchQuery("a", null, -1, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Title > Description > Category. + assertEquals(results.toString(), 3, results.size()); + assertTrackResult(trackId, results.get(0)); + assertWaypointResult(titleWaypointId, results.get(1)); + assertWaypointResult(descriptionWaypointId, results.get(2)); + } + + public void testSearchTrackDistance() { + // All results match text, but they're at difference distances from the user. + long farFarAwayId = insertTrack("aa", 0.3); + long nearId = insertTrack("ab", 0.1); + long farId = insertTrack("ac", 0.2); + + SearchQuery query = new SearchQuery("a", HERE, -1, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Distance order. + assertTrackResults(results, nearId, farId, farFarAwayId); + } + + public void testSearchWaypointDistance() { + // All results match text, but they're at difference distances from the user. + long farFarAwayId = insertWaypoint("aa", 0.3); + long nearId = insertWaypoint("ab", 0.1); + long farId = insertWaypoint("ac", 0.2); + + SearchQuery query = new SearchQuery("a", HERE, -1, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Distance order. + assertWaypointResults(results, nearId, farId, farFarAwayId); + } + + public void testSearchTrackRecent() { + // All results match text, but they're were recorded at different times. + long oldestId = insertTrack("aa", 3); + long recentId = insertTrack("ab", 1); + long oldId = insertTrack("ac", 2); + + SearchQuery query = new SearchQuery("a", null, -1, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Reverse time order. + assertTrackResults(results, recentId, oldId, oldestId); + } + + public void testSearchWaypointRecent() { + // All results match text, but they're were recorded at different times. + long oldestId = insertWaypoint("aa", 2); + long recentId = insertWaypoint("ab", 0); + long oldId = insertWaypoint("ac", 1); + + SearchQuery query = new SearchQuery("a", null, -1, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Reverse time order. + assertWaypointResults(results, recentId, oldId, oldestId); + } + + public void testSearchCurrentTrack() { + // All results match text, but one of them is the current track. + long currentId = insertTrack("ab", 1); + long otherId = insertTrack("aa", 1); + + SearchQuery query = new SearchQuery("a", null, currentId, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Current track should be demoted. + assertTrackResults(results, otherId, currentId); + } + + public void testSearchCurrentTrackWaypoint() { + // All results match text, but one of them is in the current track. + long otherId = insertWaypoint("aa", 1, 456); + long currentId = insertWaypoint("ab", 1, 123); + + SearchQuery query = new SearchQuery("a", null, 123, NOW); + ArrayList results = new ArrayList(engine.search(query)); + + // Waypoint in current track should be promoted. + assertWaypointResults(results, currentId, otherId); + } + + private void assertTrackResult(long trackId, ScoredResult result) { + assertNotNull("Not a track", result.track); + assertNull("Ambiguous result", result.waypoint); + assertEquals(trackId, result.track.getId()); + } + + private void assertTrackResults(List results, long... trackIds) { + String errMsg = "Expected IDs=" + Arrays.toString(trackIds) + "; results=" + results; + assertEquals(results.size(), trackIds.length); + for (int i = 0; i < results.size(); i++) { + ScoredResult result = results.get(i); + assertNotNull(errMsg, result.track); + assertNull(errMsg, result.waypoint); + assertEquals(errMsg, trackIds[i], result.track.getId()); + } + } + + private void assertWaypointResult(long waypointId, ScoredResult result) { + assertNotNull("Not a waypoint", result.waypoint); + assertNull("Ambiguous result", result.track); + assertEquals(waypointId, result.waypoint.getId()); + } + + private void assertWaypointResults(List results, long... waypointIds) { + String errMsg = "Expected IDs=" + Arrays.toString(waypointIds) + "; results=" + results; + assertEquals(results.size(), waypointIds.length); + for (int i = 0; i < results.size(); i++) { + ScoredResult result = results.get(i); + assertNotNull(errMsg, result.waypoint); + assertNull(errMsg, result.track); + assertEquals(errMsg, waypointIds[i], result.waypoint.getId()); + } + } +}