mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 09:33:06 +02:00
323 lines
13 KiB
Java
323 lines
13 KiB
Java
/*
|
|
* Copyright 2012 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
* use this file except in compliance with the License. You may obtain a copy of
|
|
* the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations under
|
|
* the License.
|
|
*/
|
|
|
|
package de.dennisguse.opentracks.content;
|
|
|
|
import android.content.ContentUris;
|
|
import android.location.Location;
|
|
import android.net.Uri;
|
|
|
|
import androidx.test.platform.app.InstrumentationRegistry;
|
|
import androidx.test.rule.provider.ProviderTestRule;
|
|
|
|
import org.junit.After;
|
|
import org.junit.Before;
|
|
import org.junit.Rule;
|
|
import org.junit.Test;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.List;
|
|
|
|
import de.dennisguse.opentracks.content.SearchEngine.ScoredResult;
|
|
import de.dennisguse.opentracks.content.SearchEngine.SearchQuery;
|
|
import de.dennisguse.opentracks.content.data.Marker;
|
|
import de.dennisguse.opentracks.content.data.Track;
|
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
|
import de.dennisguse.opentracks.content.provider.CustomContentProvider;
|
|
import de.dennisguse.opentracks.content.provider.CustomSQLiteOpenHelper;
|
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertNotNull;
|
|
import static org.junit.Assert.assertNull;
|
|
|
|
/**
|
|
* 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 {
|
|
|
|
private static final String TAG = SearchEngineTest.class.getSimpleName();
|
|
|
|
private static final Location HERE = new Location("gps");
|
|
private static final long NOW = SearchEngine.OLDEST_ALLOWED_TIMESTAMP + 1000;
|
|
|
|
@Rule
|
|
public ProviderTestRule sqliteContentProviderRule = new ProviderTestRule.Builder(CustomContentProvider.class, ContentProviderUtils.AUTHORITY_PACKAGE).setPrefix(TAG).build();
|
|
|
|
private ContentProviderUtils providerUtils;
|
|
private SearchEngine engine;
|
|
|
|
@Before
|
|
public void setUp() {
|
|
providerUtils = new ContentProviderUtils(sqliteContentProviderRule.getResolver());
|
|
|
|
engine = new SearchEngine(providerUtils);
|
|
}
|
|
|
|
@After
|
|
public void tearDown() {
|
|
InstrumentationRegistry.getInstrumentation().getTargetContext().deleteDatabase(TAG + CustomSQLiteOpenHelper.DATABASE_NAME);
|
|
}
|
|
|
|
private Track.Id insertTrack(String title, String description, String category, long hoursAgo) {
|
|
Track track = new Track();
|
|
track.setName(title);
|
|
track.setDescription(description);
|
|
track.setCategory(category);
|
|
|
|
TrackStatistics stats = track.getTrackStatistics();
|
|
if (hoursAgo > 0) {
|
|
// Started twice hoursAgo, so the average time is hoursAgo.
|
|
stats.setStartTime_ms(NOW - hoursAgo * 1000L * 60L * 60L * 2);
|
|
stats.setStopTime_ms(NOW);
|
|
}
|
|
|
|
Uri uri = providerUtils.insertTrack(track);
|
|
return new Track.Id(ContentUris.parseId(uri));
|
|
}
|
|
|
|
private Track.Id insertTrack(String title, String description, String category) {
|
|
return insertTrack(title, description, category, -1);
|
|
}
|
|
|
|
private Track.Id insertTrack(String title, long hoursAgo) {
|
|
return insertTrack(title, "", "", hoursAgo);
|
|
}
|
|
|
|
private Marker.Id insertWaypoint(String title, String description, String category, double distance, long hoursAgo, Track.Id 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);
|
|
}
|
|
Marker waypoint = new Marker(location);
|
|
waypoint.setName(title);
|
|
waypoint.setDescription(description);
|
|
waypoint.setCategory(category);
|
|
waypoint.setTrackId(trackId);
|
|
|
|
Uri uri = providerUtils.insertMarker(waypoint);
|
|
return new Marker.Id(ContentUris.parseId(uri));
|
|
}
|
|
|
|
private Marker.Id insertWaypoint(String title, String description, String category) {
|
|
return insertWaypoint(title, description, category, 0.0, -1, null);
|
|
}
|
|
|
|
private Marker.Id insertWaypoint(String title, double distance) {
|
|
return insertWaypoint(title, "", "", distance, -1, null);
|
|
}
|
|
|
|
private Marker.Id insertWaypoint(String title, long hoursAgo) {
|
|
return insertWaypoint(title, "", "", 0.0, hoursAgo, null);
|
|
}
|
|
|
|
private Marker.Id insertWaypoint(String title, long hoursAgo, Track.Id trackId) {
|
|
return insertWaypoint(title, "", "", 0.0, hoursAgo, trackId);
|
|
}
|
|
|
|
@Test
|
|
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");
|
|
Track.Id descriptionMatchId = insertTrack("bb", "aa", "cc");
|
|
Track.Id categoryMatchId = insertTrack("bb", "cc", "aa");
|
|
Track.Id titleMatchId = insertTrack("aa", "bb", "cc");
|
|
Track.Id titleCategoryMatchId = insertTrack("aa", "bb", "ca");
|
|
Track.Id titleDescriptionMatchId = insertTrack("aa", "ba", "cc");
|
|
Track.Id allMatchId = insertTrack("aa", "ba", "ca");
|
|
|
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
|
|
|
// Title > Description > Category.
|
|
assertTrackResults(results, allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId, categoryMatchId);
|
|
}
|
|
|
|
@Test
|
|
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");
|
|
Marker.Id descriptionMatchId = insertWaypoint("bb", "aa", "cc");
|
|
Marker.Id categoryMatchId = insertWaypoint("bb", "cc", "aa");
|
|
Marker.Id titleMatchId = insertWaypoint("aa", "bb", "cc");
|
|
Marker.Id titleCategoryMatchId = insertWaypoint("aa", "bb", "ca");
|
|
Marker.Id titleDescriptionMatchId = insertWaypoint("aa", "ba", "cc");
|
|
Marker.Id allMatchId = insertWaypoint("aa", "ba", "ca");
|
|
|
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
|
|
|
// Title > Description > Category.
|
|
assertWaypointResults(results, allMatchId, titleDescriptionMatchId, titleCategoryMatchId, titleMatchId, descriptionMatchId, categoryMatchId);
|
|
}
|
|
|
|
@Test
|
|
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
|
|
Marker.Id descriptionWaypointId = insertWaypoint("bb", "aa", "cc");
|
|
insertWaypoint("bb", "cc", "dd");
|
|
Marker.Id titleWaypointId = insertWaypoint("aa", "bb", "cc");
|
|
insertTrack("bb", "cc", "dd");
|
|
Track.Id trackId = insertTrack("aa", "bb", "cc");
|
|
|
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
|
ArrayList<ScoredResult> 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));
|
|
}
|
|
|
|
@Test
|
|
public void testSearchWaypointDistance() {
|
|
// All results match text, but they're at difference distances from the user.
|
|
Marker.Id farFarAwayId = insertWaypoint("aa", 0.3);
|
|
Marker.Id nearId = insertWaypoint("ab", 0.1);
|
|
Marker.Id farId = insertWaypoint("ac", 0.2);
|
|
|
|
SearchQuery query = new SearchQuery("a", HERE, null, NOW);
|
|
ArrayList<ScoredResult> 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.
|
|
Track.Id oldestId = insertTrack("aa", 3);
|
|
Track.Id recentId = insertTrack("ab", 1);
|
|
Track.Id oldId = insertTrack("ac", 2);
|
|
|
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
|
|
|
// Reverse time order.
|
|
assertTrackResults(results, recentId, oldId, oldestId);
|
|
}
|
|
|
|
@Test
|
|
public void testSearchWaypointRecent() {
|
|
// All results match text, but they're were recorded at different times.
|
|
Marker.Id oldestId = insertWaypoint("aa", 2);
|
|
Marker.Id recentId = insertWaypoint("ab", 0);
|
|
Marker.Id oldId = insertWaypoint("ac", 1);
|
|
|
|
SearchQuery query = new SearchQuery("a", null, null, NOW);
|
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
|
|
|
// Reverse time order.
|
|
assertWaypointResults(results, recentId, oldId, oldestId);
|
|
}
|
|
|
|
@Test
|
|
public void testSearchCurrentTrack() {
|
|
// All results match text, but one of them is the current track.
|
|
Track.Id currentId = insertTrack("ab", 1);
|
|
Track.Id otherId = insertTrack("aa", 1);
|
|
|
|
SearchQuery query = new SearchQuery("a", null, currentId, NOW);
|
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
|
|
|
// Current track should be demoted.
|
|
assertTrackResults(results, otherId, currentId);
|
|
}
|
|
|
|
@Test
|
|
public void testSearchCurrentTrackWaypoint() {
|
|
// All results match text, but one of them is in the current track.
|
|
Marker.Id otherId = insertWaypoint("aa", 1, new Track.Id(456));
|
|
Marker.Id currentId = insertWaypoint("ab", 1, new Track.Id(123));
|
|
|
|
SearchQuery query = new SearchQuery("a", null, new Track.Id(123), NOW);
|
|
ArrayList<ScoredResult> results = new ArrayList<>(engine.search(query));
|
|
|
|
// Waypoint in current track should be promoted.
|
|
assertWaypointResults(results, currentId, otherId);
|
|
}
|
|
|
|
private void assertTrackResult(Track.Id trackId, ScoredResult result) {
|
|
assertNotNull("Not a track", result.track);
|
|
assertNull("Ambiguous result", result.marker);
|
|
assertEquals(trackId, result.track.getId());
|
|
}
|
|
|
|
private void assertTrackResults(List<ScoredResult> results, Track.Id... trackIds) {
|
|
long[] longTrackIds = new long[trackIds.length];
|
|
for (int i = 0; i < trackIds.length; i++) {
|
|
longTrackIds[i] = trackIds[i].getId();
|
|
}
|
|
|
|
String errMsg = "Expected IDs=" + Arrays.toString(longTrackIds) + "; 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.marker);
|
|
assertEquals(errMsg, trackIds[i], result.track.getId());
|
|
}
|
|
}
|
|
|
|
private void assertWaypointResult(Marker.Id waypointId, ScoredResult result) {
|
|
assertNotNull("Not a waypoint", result.marker);
|
|
assertNull("Ambiguous result", result.track);
|
|
assertEquals(waypointId, result.marker.getId());
|
|
}
|
|
|
|
private void assertWaypointResults(List<ScoredResult> results, Marker.Id... waypointIds) {
|
|
long[] longWaypointIds = new long[waypointIds.length];
|
|
for (int i = 0; i < waypointIds.length; i++) {
|
|
longWaypointIds[i] = waypointIds[i].getId();
|
|
}
|
|
|
|
String errMsg = "Expected IDs=" + Arrays.toString(longWaypointIds) + "; results=" + results;
|
|
assertEquals(results.size(), waypointIds.length);
|
|
for (int i = 0; i < results.size(); i++) {
|
|
ScoredResult result = results.get(i);
|
|
assertNotNull(errMsg, result.marker);
|
|
assertNull(errMsg, result.track);
|
|
assertEquals(errMsg, waypointIds[i], result.marker.getId());
|
|
}
|
|
}
|
|
}
|